using Newtonsoft.Json; using YLErp.DBModels; using YLErp.DBModels.Enums; namespace YLErp.Modules.SwapModule { /// /// 诊断测试:验证「浮动腿 fpositions 仍用 origPositions(orig 100M)」对本 deal 的 /// 预付金/返回预付金结果是否产生影响。结论预期:本 deal 利息腿只有 mode 9(标的期初全价) /// 与 mode 5(初始预付金),CalcNotionalByMode 中 posiLong/posiShort 仅在「多头/空头存续名义本金」 /// 分支被消费(L709-716),故本 deal 即便 fpositions 用 orig 100M,预付金腿结果也不受其影响。 /// 本测试仅做诊断/验证,不改动任何生产代码;用反射调用 private CalcNotionalByMode 以直接证明 /// “mode 9 / mode 5 的 closePrincipal 不依赖 posiLong/posiShort”。 /// [TestClass] public class SwapUnwindFloatingLegDiagnosticTdd { private sealed class StubSwapDealService : SwapDealService { public StubSwapDealService(OptUserInfo optUser) : base(optUser) { } protected override bool TryGetFloatRate(DateTime valueDate, string underlyingCode, out double rate) { rate = 0; return false; } } private const decimal OrigFix = 99_000m; // 期初预付金腿初始本金 private const decimal RealFix = 66_813.12m; // 实时预付金腿剩余本金(4 次平仓后) private const decimal OrigLong = 100_000_000m; // 期初标的(多头)名义本金 private const decimal RealLong = 68_947_200m; // 实时标的(多头)剩余名义本金 private const decimal ClosePct = 0.1m; // 本次平仓比例 10% private static readonly DateTime D0 = new(2026, 7, 1); private static readonly DateTime D1 = new(2026, 7, 16); private SwapDealService _svc; [TestInitialize] public void Init() => _svc = new StubSwapDealService(new OptUserInfo(0, nameof(SwapUnwindFloatingLegDiagnosticTdd), OptUserFrom.UnitTest)); // ---- GLMS 双轨持仓构造 ---- private static swap_position OrigPrepay(decimal fix = OrigFix) => new swap_position { id = 35798, SwapTradeId = 1993, PosiDirection = 0, InterestMode = (int)InterestModeEnum.初始预付金, InterestPrincipalFix = fix, IsInitial = true, Invalid = false, InterestType = (int)InterestTypeEnum.单利, interest_rest_days = 1, InterestDirection = (int)SwapDirectionEnum.收取, InterestSwapInterval = "[]" }; private static swap_position RealPrepay(decimal fix = RealFix) => new swap_position { id = 35871, SwapTradeId = 1993, PositionId = 35798, PosiDirection = 0, InterestMode = (int)InterestModeEnum.初始预付金, InterestPrincipalFix = fix, IsInitial = false, Invalid = false, InterestType = (int)InterestTypeEnum.单利, interest_rest_days = 1, InterestDirection = (int)SwapDirectionEnum.收取, InterestSwapInterval = "[]" }; private static swap_position OrigBasePrice() => new swap_position { id = 35797, SwapTradeId = 1993, PosiDirection = 0, InterestMode = (int)InterestModeEnum.标的期初全价, InterestPrincipalFix = 0, IsInitial = true, Invalid = false, InterestType = (int)InterestTypeEnum.单利, interest_rest_days = 1, InterestSwapInterval = "[]" }; private static swap_position RealBasePrice() => new swap_position { id = 35870, SwapTradeId = 1993, PositionId = 35797, PosiDirection = 0, InterestMode = (int)InterestModeEnum.标的期初全价, InterestPrincipalFix = 0, IsInitial = false, Invalid = false, InterestType = (int)InterestTypeEnum.单利, interest_rest_days = 1, InterestSwapInterval = "[]" }; private static swap_position OrigLongLeg() => new swap_position { id = 35799, SwapTradeId = 1993, PosiDirection = 2, PositionType = (int)PositionTypeFlag.Long, InterestMode = 0, PosiNotionalValue = OrigLong, IsInitial = true, Invalid = false }; private static swap_position RealLongLeg() => new swap_position { id = 35872, SwapTradeId = 1993, PositionId = 35799, PosiDirection = 2, PositionType = (int)PositionTypeFlag.Long, InterestMode = 0, PosiNotionalValue = RealLong, IsInitial = false, Invalid = false }; private static trade MakeTrade() { var extend = new trade_extend { TradeId = 1993, ExtendJson = JsonConvert.SerializeObject(new TradeExtendJson { AnnualDays = 365, InterestCalcMode = "10", SettlementRules = 0 }) }; return new trade { id = 1993, TradeNumber = "GLMS-20260701-0008", ClientId = 999998, TradeType = "收益互换", TradeDate = D0, StartDate = D0, ExerciseDate = D1, TradeStatus = "确认成交", ValidState = "Valid", StockEqvNotional = (double)RealLong, Notional = (double)RealLong, trade_extend = extend }; } } }