using Newtonsoft.Json; using System.Security.Principal; using YLErp.DBModels; using YLErp.DBModels.Enums; namespace YLErp.Modules.SwapModule { /// /// 互换利息计算单元测试 - T+1场景 /// ================================================================ /// T+1定义:起息日(StartDate) = 成交日(TradeDate) + 1天 /// TradeDate=2026-04-27, StartDate=2026-04-28 /// ---------------------------------------------------------------- /// 测试口径: /// "10" = 算头不算尾(含起息日,不含操作日) /// "11" = 算头算尾(含起息日和操作日) /// ---------------------------------------------------------------- /// 计息逻辑说明(算头不算尾): /// calcFirst=true(算头), calcLast=false(不算尾) /// 计息区间:从StartDate到valueDate-1天 /// 例如:StartDate=4/28, valueDate=4/29 → 计息区间=4/28(1天) /// ---------------------------------------------------------------- /// 统一测试数据: /// - Principal=1000, AnnualDays=365 /// - ResetPeriod=3天(浮动利率)/ 1天(固定利率) /// - InterestRule=-1(前一营业日), 0(当前营业日) /// - FR007@2026-04-27=0.10%, FR007@2026-04-30=0.20% /// ---------------------------------------------------------------- /// Excel覆盖的T+1场景: /// 固定利率:T+1固定正利率、T+1固定负利率 /// 浮动利率:T+1浮动减点(前一/当前营业日,单/复利) /// 每个场景 × 4业务场景(浮动×3) /// ================================================================ /// [TestClass] public class GetInterestsUnitTest_T1 { #region 内部类:浮动利率模拟服务 /// /// StubSwapDealService - 模拟浮动利率获取 /// 用于单元测试中预置FR007价格,避免依赖外部数据源 /// 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; // 本金:1000 private const decimal FixedRate = 0.01m; // 固定利率:1.00% private const decimal FixedRatePositive = 0.0075m; // 固定正利率:0.75%(Excel场景) private const decimal FixedRateNegative = -0.0105m; // 固定负利率:-1.05%(Excel场景) private const int AnnualDays = 365; // 年化天数 private const int ResetPeriod = 3; // 重置周期:3天(浮动利率) private const int ResetPeriodFixed = 1; // 重置周期:1天(固定利率) private const int InterestRule_Pre = -1; // 前一营业日规则 private const int InterestRule_Cur = 0; // 当前营业日规则 private static readonly DateTime TradeDate = new(2026, 4, 27); // 成交日 private static readonly DateTime StartDate = new(2026, 4, 28); // 起息日(开始计息日) private static readonly DateTime ExerciseDate = new(2027, 4, 27); // 到期日 private SwapDealService _service; private IReadOnlyDictionary _floatRates; [TestInitialize] public void Init() { // 预置FR007价格数据 _floatRates = new Dictionary { [new DateTime(2026, 4, 27)] = 0.001, // FR007@2026-04-27 = 0.10% [new DateTime(2026, 4, 28)] = 0.001, // FR007@2026-04-28 = 0.10% [new DateTime(2026, 4, 29)] = 0.001, // FR007@2026-04-29 = 0.10% [new DateTime(2026, 4, 30)] = 0.002, // FR007@2026-04-30 = 0.20% [new DateTime(2026, 5, 1)] = 0.002, // 复利从头算需要完整日期范围 [new DateTime(2026, 5, 3)] = 0.002, // 复利重置日取FR007 [new DateTime(2026, 5, 4)] = 0.002, // 复利重置日取FR007 [new DateTime(2026, 5, 6)] = 0.002, // FR007@2026-05-06 = 0.20% // 到期日测试用例需要的利率数据(2027年) [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_T1), OptUserFrom.UnitTest), _floatRates); } #endregion #region 测试数据构建器 /// /// 创建测试用交易对象 /// /// 计息口径:"10"=算头不算尾 /// 取率规则:-1=前一营业日,0=当前营业日 private static trade CreateTrade(string interestCalcMode = "10", 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-001", ClientId = 999998, TradeType = "收益互换", TradeDate = TradeDate, StartDate = StartDate, ExerciseDate = ExerciseDate, TradeStatus = "确认成交", ValidState = "Valid", trade_extend = extend }; } /// /// 创建浮动利率测试用持仓对象(Excel场景:FR007+固定利率) /// private static swap_position CreateFloatInterestPosition( int interestRule = InterestRule_Pre, 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) }; } /// /// 创建固定利率测试用持仓对象(无浮动利率标的,纯固定利率) /// 对应Excel中的固定利率场景 /// private static swap_position CreateFixedInterestPosition( decimal fixedRate = 0.0075m, int interestRule = InterestRule_Pre, 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) }; } /// /// 创建日终持仓记录(EOD归档数据) /// 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 }; } /// /// 计算期望利息金额(先累加原始值,最后一次性舍入,比较时比生产少2位容错) /// /// /// 容忍末位差异的利息比较(允许相差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); } /// /// 计算含预EOD利息的总期望利息(比生产少2位精度容错) /// 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); } #endregion #region 通用的GetInterests调用方法 /// /// 通用浮动利率平仓计算(不含eodPositions) /// private swap_flow_event CalcFloatUnwind(DateTime valueDate, DateTime unwindDate, decimal closePercent, int interestRule = InterestRule_Pre, decimal fixedRate = 0.01m, InterestTypeEnum interestType = InterestTypeEnum.单利, List closeList = null, bool newCalcLast = false) { return CalcFloatUnwind(valueDate, unwindDate, closePercent, new List(), interestRule, fixedRate, interestType, closeList: closeList, newCalcLast: newCalcLast); } /// /// 通用浮动利率平仓计算(含eodPositions) /// private swap_flow_event CalcFloatUnwind(DateTime valueDate, DateTime unwindDate, decimal closePercent, List eodPositions, int interestRule = InterestRule_Pre, decimal fixedRate = 0.01m, InterestTypeEnum interestType = InterestTypeEnum.单利, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { var td = CreateTrade("10", interestRule); var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate); var interests = _service.GetInterests( td, td.trade_extend, valueDate, unwindDate, eodPositions, new List { position }, posiNotional, posiNotional, closePercent, (int)SwapEventTypeEnum.平仓, false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } /// /// 通用浮动利率收盘计算 /// private swap_flow_event CalcFloatEod(DateTime valueDate, List eodPositions, int interestRule = InterestRule_Pre, decimal fixedRate = 0.01m, InterestTypeEnum interestType = InterestTypeEnum.单利, List closeList = null) { var td = CreateTrade("10", interestRule); var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate); var interests = _service.GetInterests( td, td.trade_extend, valueDate, valueDate, eodPositions, new List { position }, Principal, Principal, 1m, (int)SwapEventTypeEnum.平仓, false, Principal, false, settment: true, newCalcLast: false, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } /// /// 通用浮动利率自动互换计算 /// private swap_flow_event CalcFloatAutoSwap(DateTime valueDate, List eodPositions, decimal closePercent = 1m, int interestRule = InterestRule_Pre, decimal fixedRate = 0.01m, InterestTypeEnum interestType = InterestTypeEnum.单利, List closeList = null) { var td = CreateTrade("10", interestRule); var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate); var interests = _service.GetInterests( td, td.trade_extend, valueDate, valueDate, eodPositions, new List { position }, Principal, Principal, closePercent, (int)SwapEventTypeEnum.自动互换, false, Principal, false, settment: false, newCalcLast: false, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } /// /// 通用固定利率平仓计算 /// private swap_flow_event CalcFixedUnwind(DateTime valueDate, DateTime unwindDate, decimal closePercent, int interestRule = InterestRule_Pre, decimal fixedRate = 0.0075m, List closeList = null, bool newCalcLast = false) { return CalcFixedUnwind(valueDate, unwindDate, closePercent, new List(), interestRule, fixedRate, closeList: closeList, newCalcLast: newCalcLast); } /// /// 通用固定利率平仓计算(含eodPositions) /// private swap_flow_event CalcFixedUnwind(DateTime valueDate, DateTime unwindDate, decimal closePercent, List eodPositions, int interestRule = InterestRule_Pre, decimal fixedRate = 0.0075m, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { var td = CreateTrade("10", interestRule); var position = CreateFixedInterestPosition(fixedRate, interestRule); var interests = _service.GetInterests( td, td.trade_extend, valueDate, unwindDate, eodPositions, new List { position }, posiNotional, posiNotional, closePercent, (int)SwapEventTypeEnum.平仓, false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } /// /// 通用固定利率收盘计算 /// private swap_flow_event CalcFixedEod(DateTime valueDate, List eodPositions, int interestRule = InterestRule_Pre, decimal fixedRate = 0.0075m, List closeList = null) { var td = CreateTrade("10", interestRule); var position = CreateFixedInterestPosition(fixedRate, interestRule); var interests = _service.GetInterests( td, td.trade_extend, valueDate, valueDate, eodPositions, new List { position }, Principal, Principal, 1m, (int)SwapEventTypeEnum.平仓, false, Principal, false, settment: true, newCalcLast: false, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } #endregion // ================================================================ // 所有测试均使用 InterestCalcMode="10"(算头不算尾) // ================================================================ #region 场景1:浮动利率算头不算尾 - 盘中平仓场景 /// /// [FLOAT_UNWIND_001] 算头不算尾 - 首日起息日平仓 /// --------------------------------------------------------------- /// 场景:StartDate=4/28盘中执行全平 /// 口径:算头不算尾 /// - 算头:S=4/28 /// - 不算尾:E=4/27(操作日前一日) /// - 计息天数 = 0天 /// 期望:利息=0 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_001() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 28), new DateTime(2026, 4, 28), 1m); AssertInterestEqual(0m, interest.InterestAmount); } /// /// [FLOAT_UNWIND_002] 算头不算尾 - 次日全平(基准场景) /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/29盘中全平 /// 口径:算头不算尾 → 计息区间:4/28(1天) /// 期望:计息天数=1天,利息=1*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_002() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_003] 算头不算尾 - 次日平仓50% /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/29盘中平仓一半 /// 口径:算头不算尾,计息天数=1天 /// 期望:利息=0.5*1*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_003() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m); var expected = ExpectedInterestWithPreEod(0, FixedRate, 0.001m, Principal, ExpectedInterest(1, FixedRate, 0.001m, Principal), 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_004] 算头不算尾 - 第3日全平(跨周末) /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/30盘中全平 /// 口径:算头不算尾 → 计息区间:4/28~4/29(2天) /// 期望:计息天数=2天,利息=2*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_004() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 30), new DateTime(2026, 4, 30), 1m); var expected = ExpectedInterest(2, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_005] 算头不算尾 - 第3日平仓50%(跨周末) /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/30盘中平仓一半 /// 口径:算头不算尾,计息天数=2天 /// 期望:利息=0.5*2*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_005() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 30), new DateTime(2026, 4, 30), 0.5m); var expected = ExpectedInterest(2, FixedRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_006] 算头不算尾 - 次日半平 + 第3日收盘 /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/29盘中平仓一半;4/30收盘 /// 期望: /// - 4/29平仓利息=0.5*1*(1.00%+0.10%)*1000/365 /// - 4/30收盘利息=剩余50%*1天利息 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_006() { // 第一步:4月29日平仓50% var unwindInterest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m); var expectedUnwind = ExpectedInterest(1, FixedRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind, unwindInterest.InterestAmount); // 第二步:4月30日收盘(剩余50%持仓计息1天) var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(1, FixedRate, 0.001m, Principal * 0.5m)) }; var eodInterest = CalcFloatEod(new DateTime(2026, 4, 30), eodPositions); var expectedEod = ExpectedInterest(2, FixedRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedEod, eodInterest.InterestAmount); } /// /// [FLOAT_UNWIND_007] 算头不算尾 - 第3日直接收盘(已有前日EOD) /// --------------------------------------------------------------- /// 场景:4/28未平仓;4/29已收盘归档;4/30收盘 /// 期望:4/30收盘待实现利息=3天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_007() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal, 0.001m, ExpectedInterest(2, FixedRate, 0.001m, Principal)) }; var eodInterest = CalcFloatEod(new DateTime(2026, 4, 30), eodPositions); var expectedEod = ExpectedInterest(3, FixedRate, 0.001m, Principal * 1m); AssertInterestEqual(expectedEod, eodInterest.InterestAmount); } /// /// [FLOAT_UNWIND_008] 算头不算尾 - 次日自动互换 /// --------------------------------------------------------------- /// 场景:4/29执行"自动互换" /// 期望:计息天数=1天,利息=1*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_008() { var interest = CalcFloatAutoSwap(new DateTime(2026, 4, 29), new List()); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_009] 算头不算尾 - 自动互换后次日平仓 /// --------------------------------------------------------------- /// 场景:4/29已自动互换;4/30执行"全平" /// 期望:计息天数=0天,利息=0 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_009() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal, 0.001m, 0m) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 30), new DateTime(2026, 4, 30), 1m, eodPositions); AssertInterestEqual(0m, interest.InterestAmount); } /// /// [FLOAT_UNWIND_010] 算头不算尾 - 跨重置周期全平(中间有收盘) /// --------------------------------------------------------------- /// 场景:4/29收盘归档;5/6全平(跨周期) /// 期望:分段计息,累计利息=4/29收盘+4/30持仓+5/1~5/5持仓 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_010() { var oneDay = ExpectedInterest(1, FixedRate, 0.001m, Principal); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal, 0.001m, oneDay) }; var interest = CalcFloatUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions); var secondPeriod = ExpectedInterest(5, FixedRate, 0.002m, Principal); var expected = Math.Round(oneDay * 2 + secondPeriod, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_UNWIND_010A] 已有前次结算时,浮动利率重置起点应按当前计息段起点计算 /// --------------------------------------------------------------- /// 场景:5/3已有EOD;5/6全平;重置周期=3天,取率规则=当前营业日 /// 期望:应按 5/3~5/6 这一段判断重置,取到 5/6 的 0.20% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_010A() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 5, 3), Principal, 0.001m, 0m) }; var interest = CalcFloatUnwind( new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Cur); Assert.AreEqual(0.002m, interest.FloatRate); } /// /// [FLOAT_UNWIND_011] 算头不算尾 - 跨重置周期全平(中间无收盘) /// --------------------------------------------------------------- /// 场景:4/28起息;5/6全平(4/29未收盘) /// 期望:3天@0.10% + 5天@0.20% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_UNWIND_011() { var eodPositions = new List(); var interest = CalcFloatUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions); var firstPeriod = ExpectedInterest(3, FixedRate, 0.001m, Principal); var secondPeriod = ExpectedInterest(5, FixedRate, 0.002m, Principal); var expected = Math.Round(firstPeriod + secondPeriod, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expected, interest.InterestAmount); } #endregion #region 场景2:浮动利率算头不算尾 - 收盘归档场景 /// /// [FLOAT_EOD_001] 算头不算尾 - 首日收盘归档 /// --------------------------------------------------------------- /// 场景:4/28执行收盘EOD归档(首次收盘) /// 期望:当日收盘利息=1天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_001() { var interest = CalcFloatEod(new DateTime(2026, 4, 28), new List()); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_EOD_002] 算头不算尾 - 首日收盘,次日全平 /// --------------------------------------------------------------- /// 场景:4/28已收盘;4/29盘中全平 /// 期望:总利息=历史1天+当期0天=1天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FixedRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_EOD_003] 算头不算尾 - 首日收盘,次日平仓50% /// --------------------------------------------------------------- /// 场景:4/28已收盘;4/29盘中平仓一半 /// 期望:总利息=(历史1天+当期0天)*50%=0.5天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FixedRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions); var expected = ExpectedInterestWithPreEod(0, FixedRate, 0.001m, Principal, ExpectedInterest(1, FixedRate, 0.001m, Principal), 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_EOD_004] 算头不算尾 - 连续收盘(4/28、4/29) /// --------------------------------------------------------------- /// 场景:4/28和4/29连续两个工作日收盘归档 /// 期望:4/29收盘累计利息=2天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_004() { var eod1 = CalcFloatEod(new DateTime(2026, 4, 28), new List()); var expected1 = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected1, eod1.InterestAmount); var eod2 = CalcFloatEod(new DateTime(2026, 4, 29), new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, expected1) }); var expected2 = ExpectedInterest(2, FixedRate, 0.001m, Principal); AssertInterestEqual(expected2, eod2.InterestAmount); } /// /// [FLOAT_EOD_005] 算头不算尾 - 首日收盘后第3日收盘 /// --------------------------------------------------------------- /// 场景:4/28已收盘;4/30执行收盘(4/29未收盘) /// 期望:4/29收盘利息=1天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_005() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, 0m) }; var interest = CalcFloatEod(new DateTime(2026, 4, 30), eodPositions); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_EOD_006] 算头不算尾 - 到期日收盘不算尾 /// --------------------------------------------------------------- /// 场景:4/28起息,2027-04-27到期 /// 操作:2027-04-27执行收盘归档 /// 期望:到期日收盘利息=0(不算尾) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_EOD_006() { var eodPositions = new List { CreateEodPosition(new DateTime(2027, 4, 26), Principal, 0.001m, 10m) }; var interest = CalcFloatEod(new DateTime(2027, 4, 27), eodPositions); AssertInterestEqual(0m, interest.InterestAmount); } #endregion #region 场景3:浮动利率算头不算尾 - 当前营业日规则(interest_rule=0) /// /// [FLOAT_CUR_001] 算头不算尾 + 当前营业日规则 - 次日全平 /// --------------------------------------------------------------- /// 场景:interest_rule=0(当前营业日),4/29盘中全平 /// 期望:计息天数=1天,利息=1*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_CUR_001() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, InterestRule_Cur); var expected = ExpectedInterest(1, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLOAT_CUR_002] 算头不算尾 + 当前营业日规则 - 第3日全平 /// --------------------------------------------------------------- /// 场景:interest_rule=0(当前营业日),4/30盘中全平 /// 期望:计息天数=2天,利息=2*(1.00%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLOAT_CUR_002() { var interest = CalcFloatUnwind(new DateTime(2026, 4, 30), new DateTime(2026, 4, 30), 1m, InterestRule_Cur); var expected = ExpectedInterest(2, FixedRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } #endregion // ================================================================ // Excel测试文件场景:固定利率算头不算尾 // 维度:T+1/T+0 × 正利率/负利率 × 4业务场景 // ================================================================ #region 场景4:固定利率算头不算尾 - T+1固定正利率(前一营业日,正利率0.75%) /// /// [FIX_POS_T1_001] T+1固定正利率算头不算尾 - 未收盘平仓 /// --------------------------------------------------------------- /// 业务场景1:固定利率未收盘平仓 /// 参数:interest_rule=-1, FixedRate=0.75% /// 操作:4/28起息,4/29盘中全平 /// 期望:计息天数=1天,利息=1*0.75%*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_001() { var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(1, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_002] T+1固定正利率算头不算尾 - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 业务场景2:收盘后次日全部平仓 /// 参数:interest_rule=-1, FixedRate=0.75% /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:总利息=历史1天+当期0天=1天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, ExpectedInterest(1, FixedRatePositive, 0m, Principal)) }; var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(1, FixedRatePositive, 0m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_003] T+1固定正利率算头不算尾 - 部分平仓 /// --------------------------------------------------------------- /// 业务场景3:部分平仓 /// 参数:interest_rule=-1, FixedRate=0.75% /// 操作:4/28收盘归档;4/29盘中平仓50% /// 期望:利息=0.5*1*0.75%*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, ExpectedInterest(1, FixedRatePositive, 0m, Principal)) }; var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterestWithPreEod(0, FixedRatePositive, 0m, Principal, ExpectedInterest(1, FixedRatePositive, 0m, Principal), 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_004] T+1固定正利率算头不算尾 - 部分平仓后经过数日再全部平仓 /// --------------------------------------------------------------- /// 业务场景4:部分平仓一次后,经过数日再全部平仓 /// 参数:interest_rule=-1, FixedRate=0.75% /// 操作:4/29部分平仓50%;经过4/29收盘、4/30收盘;5/6全部平仓剩余50% /// 期望:4/29平仓=0.5天+5/6平仓=剩余×累计天数 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_004() { // 第一步:4/29部分平仓50% var unwind1 = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FixedRatePositive); var expectedUnwind1 = ExpectedInterest(1, FixedRatePositive, 0m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); // 第二步:5/6全平剩余50%(经过4/29收盘和4/30收盘) // newCalcLast=true: 4/30~5/6=7天 var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0m, ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m)) }; var unwind2 = CalcFixedUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FixedRatePositive, Principal * 0.5m, newCalcLast: true); // newCalcLast=true强制算尾: 4/30~5/6=7天 var expectedTotal = ExpectedInterestWithPreEod(7, FixedRatePositive, 0m, Principal * 0.5m, ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m), 1m); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景6:固定利率算头不算尾 - T+1固定负利率(前一营业日,负利率-1.05%) /// /// [FIX_NEG_T1_001] T+1固定负利率算头不算尾 - 未收盘平仓 /// --------------------------------------------------------------- /// 业务场景1:固定利率未收盘平仓 /// 参数:interest_rule=-1, FixedRate=-1.05% /// 操作:4/28起息,4/29盘中全平 /// 期望:计息天数=1天,利息=1*(-1.05%)*1000/365(负利息) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_NEG_T1_001() { var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, InterestRule_Pre, FixedRateNegative); var expected = ExpectedInterest(1, FixedRateNegative, 0m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_NEG_T1_002] T+1固定负利率算头不算尾 - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 业务场景2:收盘后次日全部平仓 /// 参数:interest_rule=-1, FixedRate=-1.05% /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:总利息=1天(负利息) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_NEG_T1_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, ExpectedInterest(1, FixedRateNegative, 0m, Principal)) }; var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FixedRateNegative); var expected = ExpectedInterest(1, FixedRateNegative, 0m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_NEG_T1_003] T+1固定负利率算头不算尾 - 部分平仓 /// --------------------------------------------------------------- /// 业务场景3:部分平仓 /// 参数:interest_rule=-1, FixedRate=-1.05% /// 操作:4/28收盘归档;4/29盘中平仓50% /// 期望:利息=0.5*1*(-1.05%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_NEG_T1_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, ExpectedInterest(1, FixedRateNegative, 0m, Principal)) }; var interest = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FixedRateNegative); var expected = ExpectedInterestWithPreEod(0, FixedRateNegative, 0m, Principal, ExpectedInterest(1, FixedRateNegative, 0m, Principal), 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_NEG_T1_004] T+1固定负利率算头不算尾 - 部分平仓后经过数日再全部平仓 /// --------------------------------------------------------------- /// 业务场景4:部分平仓一次后,经过数日再全部平仓 /// 参数:interest_rule=-1, FixedRate=-1.05% /// 操作:4/29部分平仓50%;经过4/29收盘;5/6全部平仓剩余50% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_NEG_T1_004() { // 第一步:4/29部分平仓50% var unwind1 = CalcFixedUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FixedRateNegative); var expectedUnwind1 = ExpectedInterest(1, FixedRateNegative, 0m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); // 第二步:5/6全平剩余50%,newCalcLast=true var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0m, ExpectedInterest(2, FixedRateNegative, 0m, Principal * 0.5m)) }; var unwind2 = CalcFixedUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FixedRateNegative, Principal * 0.5m, newCalcLast: true); var expectedTotal = ExpectedInterestWithPreEod(7, FixedRateNegative, 0m, Principal * 0.5m, ExpectedInterest(2, FixedRateNegative, 0m, Principal * 0.5m), 1m); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion // ================================================================ // Excel测试文件场景:浮动利率算头不算尾 - 扩展维度 // 维度:T+1/T+0 × 加减点 × 前一/当前营业日 × 单/复利 // ================================================================ #region 场景8:浮动利率算头不算尾 - T+1浮动减点(当前营业日,复利) private const decimal FloatMinusRate = -0.021m; // 浮动减点固定端-2.10%(Excel场景) private const decimal FloatPlusRate = 0.0025m; // 浮动加点固定端+0.25%(Excel场景) /// /// [FLT_MINUS_T1_CUR_002] T+1浮动减点算头不算尾(当前营业日) - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 业务场景2:收盘后次日全部平仓 /// 参数:interest_rule=0, FixedRate=-2.10%, InterestType=复利 /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:总利息=1天(固定-2.10%+浮动0.10%=-2.00%) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_CUR_003] T+1浮动减点算头不算尾(当前营业日) - 部分平仓 /// --------------------------------------------------------------- /// 业务场景3:部分平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_CUR_004] T+1浮动减点算头不算尾(当前营业日) - 部分平仓后全平 /// --------------------------------------------------------------- /// 复利从头算:8天 [28-30]@-2.0% + [1-5]@-1.9% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_004() { // 第一步:4/29部分平仓50% var unwind1 = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expectedUnwind1 = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); // 第二步:5/6全平剩余50%,复利从头算 var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利, Principal * 0.5m, newCalcLast: false); // 复利从头算:8天, 每3天重置, [28-30]@-2.0%, [1-5]@-1.9% var principal = Principal * 0.5m; var rate1 = FloatMinusRate + 0.001m; var rate2 = FloatMinusRate + 0.002m; decimal interest = 0m, dynomic = principal; for (int d = 0; d < 8; d++) { if (d % 3 == 0) dynomic = principal + interest; interest += dynomic * (d < 3 ? rate1 : rate2) / AnnualDays; } var expectedTotal = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景10:浮动利率算头不算尾 - T+1浮动减点(前一营业日,复利) /// /// [FLT_MINUS_T1_PRE_002] T+1浮动减点算头不算尾(前一营业日) - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 业务场景2:收盘后次日全部平仓 /// 参数:interest_rule=-1, FixedRate=-2.10%, InterestType=复利 /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:总利息=1天(-2.10%+0.10%=-2.00%) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_003] T+1浮动减点算头不算尾(前一营业日) - 部分平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_004] T+1浮动减点算头不算尾(前一营业日) - 部分平仓后全平 /// --------------------------------------------------------------- /// 复利从头算:8天 [28-30]@-2.0% + [1-5]@-1.9% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_004() { var unwind1 = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expectedUnwind1 = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利, Principal * 0.5m, newCalcLast: false); // 复利从头算:8天, 每3天重置, [28-30]@-2.0%, [1-5]@-1.9% var principal = Principal * 0.5m; var rate1 = FloatMinusRate + 0.001m; var rate2 = FloatMinusRate + 0.002m; decimal interest = 0m, dynomic = principal; for (int d = 0; d < 8; d++) { if (d % 3 == 0) dynomic = principal + interest; interest += dynomic * (d < 3 ? rate1 : rate2) / AnnualDays; } var expectedTotal = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景12:浮动利率算头不算尾 - T+1浮动减点(前一营业日,单利) /// /// [FLT_MINUS_T1_PRE_SI_002] T+1浮动减点算头不算尾(前一营业日,单利) - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 业务场景2:收盘后次日全部平仓 /// 参数:interest_rule=-1, FixedRate=-2.10%, InterestType=单利 /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:总利息=1天(-2.10%+0.10%=-2.00%) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expected = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 1m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_SI_003] T+1浮动减点算头不算尾(前一营业日,单利) - 部分平仓 /// --------------------------------------------------------------- /// 业务场景3:部分平仓 /// 参数:interest_rule=-1, FixedRate=-2.10%, InterestType=单利 /// 操作:4/28收盘归档;4/29盘中平仓50% /// 期望:利息=0.5*1*(-2.10%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expected = ExpectedInterestWithPreEod(0, FloatMinusRate, 0.001m, Principal, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal), 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_SI_004] T+1浮动减点算头不算尾(前一营业日,单利) - 部分平仓后全平 /// --------------------------------------------------------------- /// 业务场景4:部分平仓一次后,经过数日再全部平仓 /// 参数:interest_rule=-1, FixedRate=-2.10%, InterestType=单利 /// 操作:4/29部分平仓50%;经过4/29收盘;5/6全部平仓剩余50% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_004() { var unwind1 = CalcFloatUnwind(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expectedUnwind1 = ExpectedInterest(1, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利, Principal * 0.5m); // 单利: 6天(EOD后), [30]@0.001 + [1-5]@0.002 → 1@-2.0% + 5@-1.9% var raw = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m) + Principal * 0.5m * (FloatMinusRate + 0.001m) * 1 / AnnualDays + Principal * 0.5m * (FloatMinusRate + 0.002m) * 5 / AnnualDays; var expectedTotal = Math.Round(raw, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景14:固定利率算头不算尾 - 收盘归档场景 /// /// [FIX_EOD_001] 固定利率算头不算尾 - 首日收盘归档 /// --------------------------------------------------------------- /// 场景:4/28执行收盘EOD归档(首次收盘) /// 参数:FixedRate=0.75%, interest_rule=-1 /// 期望:当日收盘利息=1天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_EOD_001() { var interest = CalcFixedEod(new DateTime(2026, 4, 28), new List(), InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(1, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_EOD_002] 固定利率算头不算尾 - 连续收盘 /// --------------------------------------------------------------- /// 场景:4/28和4/29连续两个工作日收盘归档 /// 参数:FixedRate=0.75%, interest_rule=-1 /// 期望:4/28和4/29收盘利息=2天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_EOD_002() { var eod1 = CalcFixedEod(new DateTime(2026, 4, 28), new List(), InterestRule_Pre, FixedRatePositive); var expected1 = ExpectedInterest(1, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected1, eod1.InterestAmount); var eod2 = CalcFixedEod(new DateTime(2026, 4, 29), new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, expected1) }, InterestRule_Pre, FixedRatePositive); var expected2 = ExpectedInterest(1, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected1+expected2, eod2.InterestAmount); } /// /// [FIX_EOD_003] 固定利率算头不算尾 - 到期日收盘不算尾 /// --------------------------------------------------------------- /// 场景:4/28起息,2027-04-27到期 /// 参数:FixedRate=0.75%, interest_rule=-1 /// 操作:2027-04-27执行收盘归档 /// 期望:到期日收盘利息=0(不算尾) /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_EOD_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2027, 4, 26), Principal, 0m, 10m) }; var interest = CalcFixedEod(new DateTime(2027, 4, 27), eodPositions, InterestRule_Pre, FixedRatePositive); AssertInterestEqual(0m, interest.InterestAmount); } #endregion // ================================================================ // Excel测试文件场景:算头算尾(InterestCalcMode="11") // 这些场景在Excel中标记为"通过",同样需要单元测试覆盖 // 口径说明:"11"=算头算尾(含起息日和到期日/操作日) // 与算头不算尾("10")的关键区别: // - "10":计息区间 S=startDate, E=valueDate-1 → days天 // - "11":计息区间 S=startDate, E=valueDate → days+1天 // ================================================================ #region 场景A:固定利率算头算尾 - T+1固定正利率(前一营业日,正利率0.75%) /// /// [FIX_POS_T1_11_001] 算头算尾 T+1固定正利率 - 未收盘平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=0.75% /// 操作:4/28起息,4/29盘中全平 /// 算头算尾:S=4/28, E=4/29 → 2天 /// 期望:利息=2*0.75%*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_11_001() { var interest = CalcFixedUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(2, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_11_002] 算头算尾 T+1固定正利率 - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=0.75% /// 操作:4/28收盘归档;4/29盘中全平 /// 算头算尾:历史1天+当期1天=2天 /// 期望:总利息=2天 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_11_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m, ExpectedInterest(1, FixedRatePositive, 0m, Principal)) }; var interest = CalcFixedUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(2, FixedRatePositive, 0m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_11_003] 算头算尾 T+1固定正利率 - 部分平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=0.75% /// 操作:4/28收盘归档;4/29盘中平仓50% /// 算头算尾:历史1天+当期1天=2天×50% /// 期望:利息=0.5*2*0.75%*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_11_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0m,ExpectedInterest(1, FixedRatePositive, 0m, Principal)) }; var interest = CalcFixedUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FixedRatePositive); var expected = ExpectedInterest(2, FixedRatePositive, 0m, Principal*0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FIX_POS_T1_11_004] 算头算尾 T+1固定正利率 - 部分平仓后经过数日再全部平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=0.75% /// 操作:4/29部分平仓50%;经过4/29收盘;5/6全部平仓剩余50% /// 算头算尾:4/29半平=2天×50%;5/6全平剩余=8天×50% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FIX_POS_T1_11_004() { // 4/29部分平仓50%(算头算尾→2天) var unwind1 = CalcFixedUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FixedRatePositive); var expectedUnwind1 = ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); // 5/6全平剩余50%(EOD=4/29, 算头算尾→4/29~5/6=8天) var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0m, ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m)) }; var unwind2 = CalcFixedUnwind11(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FixedRatePositive, Principal * 0.5m, newCalcLast: true); // 算头算尾: 4/29~5/6(算尾)=8天(newCalcLast=true无影响) var expectedTotal = ExpectedInterestWithPreEod(7, FixedRatePositive, 0m, Principal * 0.5m, ExpectedInterest(2, FixedRatePositive, 0m, Principal * 0.5m), 1m); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景C:浮动利率算头算尾 - T+1浮动减点(当前营业日,复利) /// /// [FLT_MINUS_T1_CUR_11_002] 算头算尾 T+1浮动减点(当前营业日) - 收盘后次日全部平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_11_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_CUR_11_003] 算头算尾 T+1浮动减点(当前营业日) - 部分平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_11_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterestWithPreEod(0, FloatMinusRate, 0.001m, Principal, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal), 0.5m)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_CUR_11_004] 算头算尾 T+1浮动减点(当前营业日) - 部分平仓后全平, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_CUR_11_004() { var unwind1 = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利); var expectedUnwind1 = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind11(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Cur, FloatMinusRate, InterestTypeEnum.复利, Principal * 0.5m, newCalcLast: false); // 复利从头算:9天, 每3天重置, [28-30]@-2.0%, [1-3,4-6]@-1.9% var principal = Principal * 0.5m; var rate1 = FloatMinusRate + 0.001m; var rate2 = FloatMinusRate + 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 expectedTotal = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景E:浮动利率算头算尾 - T+1浮动减点(前一营业日,复利) /// /// [FLT_MINUS_T1_PRE_11_002] 算头算尾 T+1浮动减点(前一营业日) - 收盘后次日全部平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_11_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_11_003] 算头算尾 T+1浮动减点(前一营业日) - 部分平仓, 复利从头算 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_11_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterestWithPreEod(0, FloatMinusRate, 0.001m, Principal, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal), 0.5m)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_11_004] 算头算尾 T+1浮动减点(前一营业日) - 部分平仓后全平 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=-2.10%, 复利 /// 操作:4/29部分平仓50%;经过4/29收盘;5/6全部平仓剩余50% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_11_004() { var unwind1 = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利); var expectedUnwind1 = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind11(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.复利, Principal * 0.5m, newCalcLast: false); // 复利从头算:9天, 每3天重置, [28-30]@-2.0%, [1-3,4-6]@-1.9% var principal = Principal * 0.5m; var rate1 = FloatMinusRate + 0.001m; var rate2 = FloatMinusRate + 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 expectedTotal = Math.Round(interest, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion #region 场景G:浮动利率算头算尾 - T+1浮动减点(单利) /// /// [FLT_MINUS_T1_PRE_SI_11_002] 算头算尾 T+1浮动减点(单利) - 收盘后次日全部平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=-2.10%, 单利 /// 操作:4/28收盘归档;4/29盘中全平 /// 期望:利息=2*(-2.10%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_11_002() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_SI_11_003] 算头算尾 T+1浮动减点(单利) - 部分平仓 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=-2.10%, 单利 /// 操作:4/28收盘归档;4/29盘中平仓50% /// 期望:利息=0.5*2*(-2.10%+0.10%)*1000/365 /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_11_003() { var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 28), Principal, 0.001m, ExpectedInterestWithPreEod(0, FloatMinusRate, 0.001m, Principal, ExpectedInterest(1, FloatMinusRate, 0.001m, Principal), 1m)) }; var interest = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expected = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal*0.5m); AssertInterestEqual(expected, interest.InterestAmount); } /// /// [FLT_MINUS_T1_PRE_SI_11_004] 算头算尾 T+1浮动减点(单利) - 部分平仓后全平 /// --------------------------------------------------------------- /// 参数:InterestCalcMode="11", interest_rule=-1, FixedRate=-2.10%, 单利 /// 操作:4/29部分平仓50%;经过4/29收盘;5/6全部平仓剩余50% /// --------------------------------------------------------------- /// [TestMethod] public void UT_SWAP_INT_FLT_MINUS_T1_PRE_SI_11_004() { var unwind1 = CalcFloatUnwind11(new DateTime(2026, 4, 29), new DateTime(2026, 4, 29), 0.5m, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利); var expectedUnwind1 = ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m); AssertInterestEqual(expectedUnwind1, unwind1.InterestAmount); var eodPositions = new List { CreateEodPosition(new DateTime(2026, 4, 29), Principal * 0.5m, 0.001m, ExpectedInterest(2, FloatMinusRate, 0.001m, Principal * 0.5m)) }; var unwind2 = CalcFloatUnwind11(new DateTime(2026, 5, 6), new DateTime(2026, 5, 6), 1m, eodPositions, InterestRule_Pre, FloatMinusRate, InterestTypeEnum.单利, Principal * 0.5m); // 单利: 9天, [28,29,30]@0.001 + [1-6]@0.002 → 1@-2.0% + 6@-1.9% var raw = Principal * 0.5m * (FloatMinusRate + 0.001m) * 3 / AnnualDays + Principal * 0.5m * (FloatMinusRate + 0.002m) * 6 / AnnualDays; var expectedTotal = Math.Round(raw, ConsGlobal.PriceRound, MidpointRounding.AwayFromZero); AssertInterestEqual(expectedTotal, unwind2.InterestAmount); } #endregion // ================================================================ // 算头算尾("11")通用调用方法 // ================================================================ #region 算头算尾("11")辅助方法 private swap_flow_event CalcFixedUnwind11(DateTime valueDate, DateTime unwindDate, decimal closePercent, int interestRule, decimal fixedRate, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { return CalcFixedUnwind11(valueDate, unwindDate, closePercent, new List(), interestRule, fixedRate, posiNotional, closeList, newCalcLast); } private swap_flow_event CalcFixedUnwind11(DateTime valueDate, DateTime unwindDate, decimal closePercent, List eodPositions, int interestRule, decimal fixedRate, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { var td = CreateTrade("11", interestRule); var position = CreateFixedInterestPosition(fixedRate, interestRule); var interests = _service.GetInterests( td, td.trade_extend, valueDate, unwindDate, eodPositions, new List { position }, posiNotional, posiNotional, closePercent, (int)SwapEventTypeEnum.平仓, false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } private swap_flow_event CalcFloatUnwind11(DateTime valueDate, DateTime unwindDate, decimal closePercent, int interestRule, decimal fixedRate, InterestTypeEnum interestType, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { return CalcFloatUnwind11(valueDate, unwindDate, closePercent, new List(), interestRule, fixedRate, interestType, posiNotional, closeList: closeList, newCalcLast: newCalcLast); } private swap_flow_event CalcFloatUnwind11(DateTime valueDate, DateTime unwindDate, decimal closePercent, List eodPositions, int interestRule, decimal fixedRate, InterestTypeEnum interestType, decimal posiNotional = Principal, List closeList = null, bool newCalcLast = false) { var td = CreateTrade("11", interestRule); var position = CreateFloatInterestPosition(interestRule, interestType, fixedRate); var interests = _service.GetInterests( td, td.trade_extend, valueDate, unwindDate, eodPositions, new List { position }, posiNotional, posiNotional, closePercent, (int)SwapEventTypeEnum.平仓, false, posiNotional, false, settment: false, newCalcLast: newCalcLast, closeList: closeList); AssertInterestEqual(1, interests.Count); return interests[0]; } #endregion } }