Files
zszq-trs/UnitTestProject/Modules/SwapModule/InterestLegs/InterestLegStrategyTest.cs
T
hjhan 79e9304114 refactor(interest): 新增利息腿策略接口 + 3个活跃mode实现
为拆三类腿做准备,按 Strategy 模式封装 CalcNotionalByMode 的 switch。
本次零生产代码改动,全部为新增小文件,每个类单一职责<50行。

新增(策略接口+值对象):
- InterestLegs/IInterestLegStrategy.cs
  NotionalResult 值对象(closePrincipal/posiPrincipal/closePercent)
  + IInterestLegStrategy 接口(每个mode一个实现)

新增(3个活跃利息腿mode):
- InterestLegs/FixedNotionalLeg.cs        mode 1 固定值
  计息基数恒=InterestPrincipalFix, 不随平仓比例变化(合同写死的固定值)
- InterestLegs/ContractNotionalLeg.cs     mode 2 合约名义本金规模
  平仓本金=posiNotional×closePercent, 按比例线性缩放
- InterestLegs/UnderlyingFullPriceLeg.cs  mode 9 标的期初全价
  主路径公式同mode2, 差异在衡泰路径grossPrice折算+EOD复利反推

确认现状:
- 界面实际只有3个活跃利息腿mode(1/2/9), TradeView.cshtml:330-349
- mode 3(持仓名义本金)/4(持仓市值) 零引用=死代码, 本次不实现
- mode 7/8(多空存续) 界面已注释掉, 本次不实现
- mode 5/6(预付金) 属保证金维度, 后续单独做PrepayLeg

新增测试(8个,全过):
- InterestLegStrategyTest.cs 覆盖各mode的部分平仓/全平/零平仓场景
  验证策略行为与现有CalcNotionalByMode switch完全一致
2026-08-10 18:32:17 +08:00

115 lines
4.3 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using YLErp.DBModels.Enums;
using YLErp.Modules.SwapModule.InterestLegs;
namespace UnitTestProject.Modules.SwapModule.InterestLegs
{
/// <summary>
/// 利息腿策略单测。验证每个策略的 CalcNotional 与现有 CalcNotionalByMode switch 完全一致。
/// 这组测试是后续"迁移调用点"的安全网——迁移前后行为必须不变。
/// </summary>
[TestClass]
public class InterestLegStrategyTest
{
private const decimal Fix = 2_000_000m; // 合约固定本金
private const decimal Notional = 100_000_000m; // 剩余名义本金 1 亿
private const decimal LongNotional = 60_000_000m;
private const decimal ShortNotional = 40_000_000m;
#region 固定值(mode 1):恒=Fix,不随比例变
[TestMethod]
public void 固定值_部分平仓_计息基数恒等于Fix()
{
var leg = new FixedNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0.5m);
Assert.AreEqual(Fix, r.ClosePrincipal, "平仓本金恒=Fix");
Assert.AreEqual(Fix, r.PosiPrincipal, "持仓本金恒=Fix");
Assert.AreEqual(1m, r.ClosePercent, "有效比例恒=1(固定值不随比例缩放)");
}
[TestMethod]
public void 固定值_全平_计息基数仍等于Fix()
{
var leg = new FixedNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
Assert.AreEqual(Fix, r.ClosePrincipal, "全平本金仍=Fix");
}
#endregion
#region 合约名义本金规模(mode 2):按比例线性缩放
[TestMethod]
public void 合约名义本金_部分平仓_本金按比例缩放()
{
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0.5m);
Assert.AreEqual(50_000_000m, r.ClosePrincipal, "平仓本金=Notional×50%");
Assert.AreEqual(Notional, r.PosiPrincipal, "持仓本金=Notional全额");
Assert.AreEqual(0.5m, r.ClosePercent, "有效比例=入参");
}
[TestMethod]
public void 合约名义本金_全平_本金等于全额()
{
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
Assert.AreEqual(Notional, r.ClosePrincipal, "全平本金=Notional");
}
[TestMethod]
public void 合约名义本金_零平仓_本金为零()
{
var leg = new ContractNotionalLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0m);
Assert.AreEqual(0m, r.ClosePrincipal, "零平仓本金=0");
Assert.AreEqual(Notional, r.PosiPrincipal, "持仓本金仍=Notional");
}
#endregion
#region 标的期初全价(mode 9):主路径公式与mode2相同
[TestMethod]
public void 标的期初全价_部分平仓_主路径公式同mode2()
{
var leg = new UnderlyingFullPriceLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 0.5m);
Assert.AreEqual(50_000_000m, r.ClosePrincipal, "平仓本金=Notional×50%(与mode2主路径一致)");
Assert.AreEqual(Notional, r.PosiPrincipal);
Assert.AreEqual(0.5m, r.ClosePercent);
}
[TestMethod]
public void 标的期初全价_全平_本金等于全额()
{
var leg = new UnderlyingFullPriceLeg();
var r = leg.CalcNotional(Fix, Notional, LongNotional, ShortNotional, 1m);
Assert.AreEqual(Notional, r.ClosePrincipal);
}
#endregion
#region 守卫:三个策略对应不同mode
[TestMethod]
public void 三个策略对应不同枚举值()
{
Assert.AreEqual(InterestModeEnum.固定值, new FixedNotionalLeg().Mode);
Assert.AreEqual(InterestModeEnum.合约名义本金规模, new ContractNotionalLeg().Mode);
Assert.AreEqual(InterestModeEnum.标的期初全价, new UnderlyingFullPriceLeg().Mode);
}
#endregion
}
}