using Newtonsoft.Json;
using YLErp.DBModels;
using YLErp.DBModels.Enums;
namespace YLErp.Modules.SwapModule
{
///
/// 互换利息计算单元测试 - T+0场景
/// ================================================================
/// T+0定义:起息日(StartDate) = 成交日(TradeDate),不额外加1天
/// TradeDate=2026-04-27, StartDate=2026-04-27
/// ----------------------------------------------------------------
/// 测试口径:
/// "10" = 算头不算尾(含起息日,不含操作日)
/// "11" = 算头算尾(含起息日和操作日)
/// ----------------------------------------------------------------
/// 与T+1的关键差异:
/// T+1: StartDate=4/28, 4/29平仓(算头不算尾)→1天
/// T+0: StartDate=4/27, 4/28平仓(算头不算尾)→1天 (所有天数+1)
/// ----------------------------------------------------------------
/// Excel覆盖的T+0算头不算尾场景:
/// 固定利率:T+0固定正利率、T+0固定负利率
/// 浮动利率:T+0浮动加点(当前营业日/前一营业日/单利)
/// 每个场景 × 4业务场景(浮动×3)
/// ================================================================
///
[TestClass]
public class GetInterestsUnitTest_T0
{
#region 内部类:浮动利率模拟服务
private sealed class StubSwapDealService : SwapDealService
{
private readonly IReadOnlyDictionary _floatRates;
public StubSwapDealService(OptUserInfo optUser, IReadOnlyDictionary floatRates) : base(optUser)
{
_floatRates = floatRates;
}
protected override bool TryGetFloatRate(DateTime valueDate, string underlyingCode, out double rate)
{
if (!string.Equals(underlyingCode, "FR007", StringComparison.OrdinalIgnoreCase))
{
rate = 0;
return false;
}
if (_floatRates.TryGetValue(valueDate.Date, out rate)) return true;
rate = 0;
return false;
}
}
#endregion
#region 测试常量
private const decimal Principal = 1000m;
private const decimal FixedRate = 0.01m;
private const decimal FixedRatePositive = 0.0075m;
private const decimal FixedRateNegative = -0.0105m;
private const decimal FloatMinusRate = -0.021m;
private const decimal FloatPlusRate = 0.0025m;
private const int AnnualDays = 365;
private const int ResetPeriod = 3;
private const int ResetPeriodFixed = 1;
private const int InterestRule_Pre = -1;
private const int InterestRule_Cur = 0;
// T+0: StartDate = TradeDate(不额外加1天)
private static readonly DateTime TradeDate = new(2026, 4, 27);
private static readonly DateTime StartDate = new(2026, 4, 27); // = TradeDate
private static readonly DateTime ExerciseDate = new(2027, 4, 27);
private SwapDealService _service;
private IReadOnlyDictionary _floatRates;
[TestInitialize]
public void Init()
{
_floatRates = new Dictionary
{
[new DateTime(2026, 4, 24)] = 0.001, // InterestRule_Pre: GetNonHolidayDefore(4/26日)→4/24
[new DateTime(2026, 4, 26)] = 0.001, // 新增:T+0前一营业日场景需要
[new DateTime(2026, 4, 27)] = 0.001,
[new DateTime(2026, 4, 28)] = 0.001,
[new DateTime(2026, 4, 29)] = 0.001,
[new DateTime(2026, 4, 30)] = 0.002,
[new DateTime(2026, 5, 1)] = 0.002, // 复利从头算需要完整日期范围
[new DateTime(2026, 5, 3)] = 0.002, // 复利重置日取FR007
[new DateTime(2026, 5, 5)] = 0.002, // InterestRule_Pre取率日
[new DateTime(2026, 5, 6)] = 0.002,
[new DateTime(2027, 4, 23)] = 0.001,
[new DateTime(2027, 4, 24)] = 0.001,
[new DateTime(2027, 4, 25)] = 0.001,
[new DateTime(2027, 4, 26)] = 0.001,
[new DateTime(2027, 4, 27)] = 0.001
};
_service = new StubSwapDealService(
new OptUserInfo(0, nameof(GetInterestsUnitTest_T0), OptUserFrom.UnitTest),
_floatRates);
}
#endregion
#region 测试数据构建器
private static trade CreateTrade(string interestCalcMode, int interestRule = InterestRule_Pre)
{
var extend = new trade_extend
{
TradeId = 1,
ExtendJson = JsonConvert.SerializeObject(new TradeExtendJson
{
AnnualDays = AnnualDays,
InterestCalcMode = interestCalcMode,
SettlementRules = interestRule
})
};
return new trade
{
id = 1, TradeNumber = "UT-SWAP-INT-T0-001", ClientId = 999998,
TradeType = "收益互换", TradeDate = TradeDate, StartDate = StartDate,
ExerciseDate = ExerciseDate, TradeStatus = "确认成交", ValidState = "Valid",
trade_extend = extend
};
}
private static swap_position CreateFloatInterestPosition(
int interestRule = InterestRule_Cur, InterestTypeEnum interestType = InterestTypeEnum.单利,
decimal fixedRate = 0.01m, SwapDirectionEnum direction = SwapDirectionEnum.收取)
{
var intervalModels = new List
{
new IntervalModel { Date = ExerciseDate, Rate = fixedRate, Settlement = 0 }
};
return new swap_position
{
id = 1001, SwapTradeId = 1, PositionType = (int)PositionTypeFlag.Unknown,
InterestDirection = (int)direction, InterestMode = (int)InterestModeEnum.标的期初全价,
InterestRateDefault = fixedRate, InterestPrincipalFix = Principal,
PosiStartDate = StartDate, PosiMatuirityDate = ExerciseDate,
IsInitial = true, Invalid = false, InterestType = (int)interestType,
IsAnnualized = true, interest_rest_days = ResetPeriod,
interest_rule = interestRule, FloatRateUnderlyingCode = "FR007",
InterestSwapInterval = JsonConvert.SerializeObject(intervalModels)
};
}
private static swap_position CreateFixedInterestPosition(
decimal fixedRate = 0.0075m, int interestRule = InterestRule_Cur,
SwapDirectionEnum direction = SwapDirectionEnum.收取)
{
var intervalModels = new List
{
new IntervalModel { Date = ExerciseDate, Rate = fixedRate, Settlement = 0 }
};
return new swap_position
{
id = 1001, SwapTradeId = 1, PositionType = (int)PositionTypeFlag.Unknown,
InterestDirection = (int)direction, InterestMode = (int)InterestModeEnum.合约名义本金规模,
InterestRateDefault = fixedRate, InterestPrincipalFix = Principal,
PosiStartDate = StartDate, PosiMatuirityDate = ExerciseDate,
IsInitial = true, Invalid = false, InterestType = (int)InterestTypeEnum.单利,
IsAnnualized = true, interest_rest_days = ResetPeriodFixed,
interest_rule = interestRule, FloatRateUnderlyingCode = null,
InterestSwapInterval = JsonConvert.SerializeObject(intervalModels)
};
}
private static eod_swap_position CreateEodPosition(DateTime valueDate, decimal tdPrincipal, decimal floatRate, decimal interestSum)
{
return new eod_swap_position
{
id = 1, SwapTradeId = 1, PositionId = 1001, ValueDate = valueDate,
ClientId = 999998, FloatRate = floatRate, TdInterestPrincipal = tdPrincipal,
PosiNotionalValue = tdPrincipal, InterestIncomeSum = interestSum,
InterestProfitSum = interestSum
};
}
///
/// 计算含预EOD利息的总期望利息(匹配生产代码中间舍入行为)
/// ---------------------------------------------------------------
/// 生产代码先取 preEod.InterestProfitSum(已舍入到11位的DB值),
/// 再加上新期间日度原始利息,最后再舍入一次
///
private static decimal ExpectedInterestWithPreEod(
int newDays, decimal fixedRate, decimal floatRate, decimal principal,
decimal preEodInterestSum, decimal closePercent)
{
var yearlyRate = fixedRate + floatRate;
var newRawInterest = principal * yearlyRate * newDays / AnnualDays;
return Math.Round(preEodInterestSum * closePercent + newRawInterest * closePercent,
ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
}
///
/// 容忍末位差异的利息比较(允许相差2位)
///
private static void AssertInterestEqual(decimal expected, decimal actual)
{
var tolerance = 1m / (decimal)Math.Pow(10, ConsGlobal.PriceRound - 2);
Assert.IsTrue(Math.Abs(expected - actual) <= tolerance,
string.Format("Expected: {0}, Actual: {1}, Diff: {2}", expected, actual, expected - actual));
}
private static decimal ExpectedInterest(int days, decimal fixedRate, decimal floatRate, decimal principal)
{
var yearlyRate = fixedRate + floatRate;
var interest = principal * yearlyRate * days / AnnualDays;
return Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
}
#endregion
#region 通用调用方法
// --- 浮动利率 ---
private swap_flow_event CalcFloatUnwind(string calcMode, DateTime valueDate, DateTime unwindDate,
decimal closePercent, int interestRule, decimal fixedRate, InterestTypeEnum interestType,
List eodPositions = null,
decimal posiNotional = Principal, List closeList = null,
bool newCalcLast = false)
{
eodPositions ??= new List();
var td = CreateTrade(calcMode, interestRule);
var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate);
var interests = _service.GetInterests(td, td.trade_extend, valueDate, unwindDate,
eodPositions, new List { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.平仓,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
private swap_flow_event CalcFloatEod(string calcMode, DateTime valueDate,
int interestRule, decimal fixedRate, InterestTypeEnum interestType,
List eodPositions = null, List closeList = null)
{
eodPositions ??= new List();
var td = CreateTrade(calcMode, interestRule);
var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate);
var interests = _service.GetInterests(td, td.trade_extend, valueDate, valueDate,
eodPositions, new List { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.平仓,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
// --- 固定利率 ---
private swap_flow_event CalcFixedUnwind(string calcMode, DateTime valueDate, DateTime unwindDate,
decimal closePercent, int interestRule, decimal fixedRate,
List eodPositions = null,
decimal posiNotional = Principal, List closeList = null,
bool newCalcLast = false)
{
eodPositions ??= new List();
var td = CreateTrade(calcMode, interestRule);
var position = CreateFixedInterestPosition(fixedRate, interestRule);
var interests = _service.GetInterests(td, td.trade_extend, valueDate, unwindDate,
eodPositions, new List { position },
posiNotional, posiNotional, posiNotional, posiNotional, closePercent,
(int)SwapEventTypeEnum.平仓,
false, false, 0, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
private swap_flow_event CalcFixedEod(string calcMode, DateTime valueDate,
int interestRule, decimal fixedRate, List eodPositions = null,
List closeList = null)
{
eodPositions ??= new List();
var td = CreateTrade(calcMode, interestRule);
var position = CreateFixedInterestPosition(fixedRate, interestRule);
var interests = _service.GetInterests(td, td.trade_extend, valueDate, valueDate,
eodPositions, new List { position },
Principal, Principal, Principal, Principal, 1m,
(int)SwapEventTypeEnum.平仓,
false, false, 0, Principal, false, settment: true, newCalcLast: false, closeList: closeList);
AssertInterestEqual(1, interests.Count);
return interests[0];
}
#endregion
// ================================================================
// T+0场景:StartDate = TradeDate = 2026-04-27
// 算头不算尾("10"):4/27平仓→0天, 4/28平仓→1天, 4/29平仓→2天
// 算头算尾("11"):4/27平仓→1天, 4/28平仓→2天, 4/29平仓→3天
// ================================================================
#region 1. T+0固定正利率 算头不算尾("10") - interest_rule=0
///
/// [UT_T0_FIX_POS_001] T+0固定正利率算头不算尾-未收盘平仓
/// ---------------------------------------------------------------
/// StartDate=4/27, 4/28平仓, 算头不算尾→S=4/27,E=4/27→1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_001()
{
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRatePositive);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FIX_POS_002] T+0固定正利率算头不算尾-收盘后次日全部平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→1+1=2天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(1, FixedRatePositive, 0m, Principal))
};
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRatePositive, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FIX_POS_003] T+0固定正利率算头不算尾-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头不算尾→1天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(1, FixedRatePositive, 0m, Principal))
};
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRatePositive, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal * 0.5m), interest.InterestAmount);
}
///
/// [UT_T0_FIX_POS_004] T+0固定正利率算头不算尾-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平50%→1天×50%; 5/6全平剩余→EOD=4/28, newCalcLast=true
/// 算头不算尾,newCalcLast强制算尾: 4/29~5/6=8天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_004()
{
// 4/28部分平仓50%(算头不算尾→S=4/27,E=4/27→1天)
var u1 = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRatePositive);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal * 0.5m), u1.InterestAmount);
// 5/6全平剩余50%(EOD=4/28, newCalcLast=true强制算尾: 4/29~5/6=8天)
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0m,
ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m))
};
var u2 = CalcFixedUnwind("10", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Cur, FixedRatePositive, eod, Principal * 0.5m, newCalcLast: true);
var expected = ExpectedInterestWithPreEod(8, FixedRatePositive, 0m, Principal * 0.5m,
ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m), 1m);
AssertInterestEqual(expected, u2.InterestAmount);
}
#endregion
#region 2. T+0固定负利率 算头不算尾("10") - interest_rule=0
///
/// [UT_T0_FIX_NEG_001] T+0固定负利率算头不算尾-未收盘平仓
/// ---------------------------------------------------------------
/// StartDate=4/27, 4/28平仓, 算头不算尾→1天, 负利率-1.05%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_NEG_001()
{
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRateNegative);
AssertInterestEqual(ExpectedInterest(1, FixedRateNegative, 0m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FIX_NEG_002] T+0固定负利率算头不算尾-收盘后次日全部平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→2天, 负利率-1.05%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_NEG_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(1, FixedRateNegative, 0m, Principal))
};
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRateNegative, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRateNegative, 0m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FIX_NEG_003] T+0固定负利率算头不算尾-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头不算尾→1天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_NEG_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(2, FixedRateNegative, 0m, Principal * 0.5m))
};
var interest = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRateNegative, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRateNegative, 0m, Principal)*0.5m, interest.InterestAmount);
}
///
/// [UT_T0_FIX_NEG_004] T+0固定负利率算头不算尾-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平50%→1天×50%; 5/6全平剩余→newCalcLast=true, 8天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_NEG_004()
{
var u1 = CalcFixedUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRateNegative);
AssertInterestEqual(ExpectedInterest(1, FixedRateNegative, 0m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0m,
ExpectedInterest(2, FixedRateNegative, 0m, Principal * 0.5m))
};
var u2 = CalcFixedUnwind("10", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Cur, FixedRateNegative, eod, Principal * 0.5m, newCalcLast: true);
var expected = ExpectedInterestWithPreEod(8, FixedRateNegative, 0m, Principal * 0.5m,
ExpectedInterest(2, FixedRateNegative, 0m, Principal * 0.5m), 1m);
AssertInterestEqual(expected, u2.InterestAmount);
}
#endregion
#region 3. T+0浮动加点(当前营业日,复利)算头不算尾("10")
///
/// [UT_T0_FLT_PLUS_CUR_002] T+0浮动加点(当前营业日,复利)算头不算尾-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→2天, FR007+0.25%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_CUR_003] T+0浮动加点(当前营业日,复利)算头不算尾-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头不算尾→2天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal*0.5m), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_CUR_004] T+0浮动加点(当前营业日,复利)算头不算尾-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平50%→1天; 5/6全平剩余→复利从头算9天[27-29][30-2][3-5]
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_004()
{
var u1 = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List();
var u2 = CalcFloatUnwind("10", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod, Principal * 0.5m);
// 复利从头算:9天, 每3天重置, [27-29]@0.35%, [30-2,3-5]@0.45%
var principal = Principal * 0.5m;
var rate1 = FloatPlusRate + 0.001m;
var rate2 = FloatPlusRate + 0.002m;
decimal interest = 0m, dynomic = principal;
for (int d = 0; d < 9; d++)
{
if (d % 3 == 0) dynomic = principal + interest;
interest += dynomic * (d < 3 ? rate1 : rate2) / AnnualDays;
}
var expected = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected, u2.InterestAmount);
}
#endregion
#region 4. T+0浮动加点(前一营业日,复利)算头不算尾("10")
///
/// [UT_T0_FLT_PLUS_PRE_002] T+0浮动加点(前一营业日,复利)算头不算尾-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_PRE_003] T+0浮动加点(前一营业日,复利)算头不算尾-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头不算尾→1天, 复利从头算
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal * 0.5m), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_PRE_004] T+0浮动加点(前一营业日,复利)算头不算尾-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→1天@0.10%; 5/6全平→复利从头算9天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_004()
{
var u1 = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var u2 = CalcFloatUnwind("10", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod, Principal * 0.5m);
// 复利从头算:9天, 每3天重置, [27-29]@0.001, [30-2]@0.001, [3-5]@0.002 → 6@0.35%+3@0.45%
var principal = Principal * 0.5m;
var rate1 = FloatPlusRate + 0.001m;
var rate2 = FloatPlusRate + 0.002m;
decimal interest2 = 0m, dynomic = principal;
for (int d = 0; d < 9; d++)
{
if (d % 3 == 0) dynomic = principal + interest2;
interest2 += dynomic * (d < 6 ? rate1 : rate2) / AnnualDays;
}
var expected = Math.Round(interest2, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected, u2.InterestAmount);
}
#endregion
#region 5. T+0浮动加点(单利)算头不算尾("10")
///
/// [UT_T0_FLT_PLUS_SI_002] T+0浮动加点(单利)算头不算尾-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→2天, 单利
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_SI_003] T+0浮动加点(单利)算头不算尾-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头不算尾→1天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var interest = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal*0.5m), interest.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_SI_004] T+0浮动加点(单利)算头不算尾-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→1天; 5/6全平→9天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_004()
{
var u1 = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var u2 = CalcFloatUnwind("10", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod, Principal * 0.5m);
// 单利: 9天, [27,28,29]@0.001 +[30,1,2]@0.001 + [3,4,5]@0.002
var raw = Principal * 0.5m * (FloatPlusRate + 0.001m) * 6 / AnnualDays
+ Principal * 0.5m * (FloatPlusRate + 0.002m) * 3 / AnnualDays;
var expected = Math.Round(raw, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected, u2.InterestAmount);
}
#endregion
#region 6. T+0固定正利率 算头算尾("11") - interest_rule=0
///
/// [UT_T0_FIX_POS_11_001] 算头算尾 T+0固定正利率-未收盘平仓
/// ---------------------------------------------------------------
/// StartDate=4/27, 4/28平仓, 算头算尾→S=4/27,E=4/28→2天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_11_001()
{
var i = CalcFixedUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRatePositive);
AssertInterestEqual(ExpectedInterest(2, FixedRatePositive, 0m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FIX_POS_11_002] 算头算尾 T+0固定正利率-收盘后次日全部平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头算尾→1+1=2天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_11_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(1, FixedRatePositive, 0m, Principal))
};
var i = CalcFixedUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRatePositive, eod);
AssertInterestEqual(ExpectedInterest(2, FixedRatePositive, 0m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FIX_POS_11_003] 算头算尾 T+0固定正利率-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头算尾→2天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_11_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m,
ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m))
};
var i = CalcFixedUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRatePositive, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FIX_POS_11_004] 算头算尾 T+0固定正利率-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→2天×50%; 5/6全平→EOD=4/28, 算头算尾(newCalcLast=true无影响)
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_POS_11_004()
{
var u1 = CalcFixedUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FixedRatePositive);
AssertInterestEqual(ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0m,
ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m))
};
var u2 = CalcFixedUnwind("11", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Cur, FixedRatePositive, eod, Principal * 0.5m, newCalcLast: true);
AssertInterestEqual(ExpectedInterestWithPreEod(8, FixedRatePositive, 0m, Principal * 0.5m,
ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m), 1m), u2.InterestAmount);
}
#endregion
#region 7. T+0浮动加点(当前营业日)算头算尾("11")
///
/// [UT_T0_FLT_PLUS_CUR_11_002] 算头算尾 T+0浮动加点(当前营业日,复利)-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头算尾→2天, 复利从头算
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_11_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_CUR_11_003] 算头算尾 T+0浮动加点(当前营业日,复利)-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头算尾→2天, 复利从头算
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_11_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_CUR_11_004] 算头算尾 T+0浮动加点(当前营业日,复利)-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→2天; 5/6全平→复利从头算10天 [27-29] [30-2] [3-5] [6]
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_CUR_11_004()
{
var u1 = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var u2 = CalcFloatUnwind("11", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Cur, FloatPlusRate, InterestTypeEnum.复利, eod, Principal * 0.5m, newCalcLast: false);
// 复利从头算:10天, 每3天重置, [27-29]@0.35%, [30-2,3-5,6]@0.45%
var principal = Principal * 0.5m;
var rate1 = FloatPlusRate + 0.001m;
var rate2 = FloatPlusRate + 0.002m;
decimal interest = 0m, dynomic = principal;
for (int d = 0; d < 10; d++)
{
if (d % 3 == 0) dynomic = principal + interest;
interest += dynomic * (d < 3 ? rate1 : rate2) / AnnualDays;
}
var expected1 = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected1, u2.InterestAmount);
}
#endregion
#region 8. T+0浮动加点(前一营业日)算头算尾("11")
///
/// [UT_T0_FLT_PLUS_PRE_11_002] 算头算尾 T+0浮动加点(前一营业日,复利)-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头算尾→2天, 复利从头算
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_11_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_PRE_11_003] 算头算尾 T+0浮动加点(前一营业日,复利)-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头算尾→2天, 复利从头算
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_11_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_PRE_11_004] 算头算尾 T+0浮动加点(前一营业日,复利)-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→2天@0.10%; 5/6全平→复利从头算10天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_PRE_11_004()
{
var u1 = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var u2 = CalcFloatUnwind("11", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.复利, eod, Principal * 0.5m);
// 复利从头算:10天, 每3天重置, [27-29,30-2]@0.001, [3-5,6]@0.002 → 6@0.35%+4@0.45%
var principal = Principal * 0.5m;
var rate1 = FloatPlusRate + 0.001m;
var rate2 = FloatPlusRate + 0.002m;
decimal interest = 0m, dynomic = principal;
for (int d = 0; d < 10; d++)
{
if (d % 3 == 0) dynomic = principal + interest;
interest += dynomic * (d < 6 ? rate1 : rate2) / AnnualDays;
}
var expected1 = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected1, u2.InterestAmount);
}
#endregion
#region 9. T+0浮动加点(单利)算头算尾("11")
///
/// [UT_T0_FLT_PLUS_SI_11_002] 算头算尾 T+0浮动加点(单利)-收盘后次日全平
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头算尾→2天, 单利
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_11_002()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FloatPlusRate, 0.001m, Principal))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_SI_11_003] 算头算尾 T+0浮动加点(单利)-部分平仓
/// ---------------------------------------------------------------
/// 4/27收盘+4/28半平50%, 算头算尾→2天×50%
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_11_003()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var i = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod);
AssertInterestEqual(ExpectedInterest(1, FloatPlusRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_PLUS_SI_11_004] 算头算尾 T+0浮动加点(单利)-部分平仓后全平
/// ---------------------------------------------------------------
/// 4/28半平→2天; 5/6全平→算头算尾
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_PLUS_SI_11_004()
{
var u1 = CalcFloatUnwind("11", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 0.5m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利);
AssertInterestEqual(ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m), u1.InterestAmount);
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 28), Principal * 0.5m, 0.001m,
ExpectedInterest(2, FloatPlusRate, 0.001m, Principal * 0.5m))
};
var u2 = CalcFloatUnwind("11", new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m,
InterestRule_Pre, FloatPlusRate, InterestTypeEnum.单利, eod, Principal * 0.5m);
// 单利: 10天, [27,28,29]@0.001 + [30,1,2]@0.001 + [3,4,5,6]@0.002 → 3@0.35% + 3@0.35% + 3@0.45%
var raw1 = Principal * 0.5m * (FloatPlusRate + 0.001m) * 6 / AnnualDays
+ Principal * 0.5m * (FloatPlusRate + 0.002m) * 4 / AnnualDays;
var expected1 = Math.Round(raw1, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero);
AssertInterestEqual(expected1, u2.InterestAmount);
}
#endregion
#region 10. T+0固定利率 - 收盘归档
///
/// [UT_T0_FIX_EOD_001] T+0固定利率算头不算尾-首日收盘归档
/// ---------------------------------------------------------------
/// 4/27(起息日)执行收盘, 算头不算尾→1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_EOD_001()
{
var i = CalcFixedEod("10", new DateTime(2026, 4, 27), InterestRule_Cur, FixedRatePositive);
AssertInterestEqual(ExpectedInterest(1, FixedRatePositive, 0m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FIX_EOD_002] T+0固定利率算头不算尾-连续收盘
/// ---------------------------------------------------------------
/// 4/27收盘+4/28收盘, 算头不算尾→各1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FIX_EOD_002()
{
var e1 = CalcFixedEod("10", new DateTime(2026, 4, 27), InterestRule_Cur, FixedRatePositive);
var expected1 = ExpectedInterest(1, FixedRatePositive, 0m, Principal);
AssertInterestEqual(expected1, e1.InterestAmount);
var e2 = CalcFixedEod("10", new DateTime(2026, 4, 28), InterestRule_Cur, FixedRatePositive,
new List { CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0m, expected1) });
AssertInterestEqual(expected1*2, e2.InterestAmount);
}
#endregion
#region 11. T+0浮动利率 - 基础场景
///
/// [UT_T0_FLT_BASE_001] T+0浮动利率基础-起息日平仓→0天
/// ---------------------------------------------------------------
/// StartDate=4/27, 4/27平仓, 算头不算尾→0天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_BASE_001()
{
var i = CalcFloatUnwind("10", new DateTime(2026, 4, 27), new DateTime(2026, 4, 27), 1m,
InterestRule_Cur, FixedRate, InterestTypeEnum.单利);
AssertInterestEqual(0m, i.InterestAmount);
}
///
/// [UT_T0_FLT_BASE_002] T+0浮动利率基础-第2天全平→1天
/// ---------------------------------------------------------------
/// StartDate=4/27, 4/28平仓, 算头不算尾→1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_BASE_002()
{
var i = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRate, InterestTypeEnum.单利);
AssertInterestEqual(ExpectedInterest(1, FixedRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_BASE_003] T+0浮动利率基础-首日收盘→1天
/// ---------------------------------------------------------------
/// 4/27执行收盘, 算头不算尾→1天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_BASE_003()
{
var i = CalcFloatEod("10", new DateTime(2026, 4, 27), InterestRule_Cur, FixedRate, InterestTypeEnum.单利);
AssertInterestEqual(ExpectedInterest(1, FixedRate, 0.001m, Principal), i.InterestAmount);
}
///
/// [UT_T0_FLT_BASE_004] T+0浮动利率基础-首日收盘+次日全平→2天
/// ---------------------------------------------------------------
/// 4/27收盘+4/28全平, 算头不算尾→2天
/// ---------------------------------------------------------------
///
[TestMethod]
public void UT_T0_FLT_BASE_004()
{
var eod = new List
{
CreateEodPosition(new DateTime(2026, 4, 27), Principal, 0.001m,
ExpectedInterest(1, FixedRate, 0.001m, Principal))
};
var i = CalcFloatUnwind("10", new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m,
InterestRule_Cur, FixedRate, InterestTypeEnum.单利, eod);
AssertInterestEqual(ExpectedInterest(1, FixedRate, 0.001m, Principal), i.InterestAmount);
}
#endregion
}
}