diff --git a/YLErpDAL/Modules/SwapModule/Accrual/FundingLegAccrual.cs b/YLErpDAL/Modules/SwapModule/Accrual/FundingLegAccrual.cs index 8c5902ca..a621e489 100644 --- a/YLErpDAL/Modules/SwapModule/Accrual/FundingLegAccrual.cs +++ b/YLErpDAL/Modules/SwapModule/Accrual/FundingLegAccrual.cs @@ -4,60 +4,17 @@ using YLErp.Derivatives.Interest; namespace YLErp.Modules.SwapModule.Accrual; /// -/// 融资腿计息编排层(NEW,替换 SwapDealService 内 CalcDaily* 家族的"纯数学"部分)。 +/// 融资腿计息编排层——纯数学部分(替换 SwapDealService 内 CalcDaily* 家族的纯计算)。 /// /// 职责边界(与 SwapInterest 原语、SwapDealService 适配器三者正交): /// - /// 本类:持有跨日 ,逐日循环,经 IIndexFixer 取当日率并封装为 , - /// 调用 SwapInterest 原子原语算账,处理平仓缩放 / 已实现扣除,replay 求 Δ。 +/// 本类:持有已解析的 ,执行单利日终计息纯函数。 /// SwapInterest:原子 "本金×利率×天数/年化" 纯函数,无状态。 -/// SwapDealService.GetInterests:仅做 DB 读、swap_flow_event 构造与落库(IO)。 +/// SwapDealService:负责 DB 读、取率、swap_flow_event 构造与落库(IO)。 /// -/// -/// 命名规范:本文件内所有概念一律使用自描述英文名。旧代码 typo 一律不出现: -/// -/// closePrecent 的 closeRatio(且语义固定为"占剩余持仓比例") -/// orginPv→ OriginalPv(原始名义本金,用于保证金腿差分基数) -/// floateRate→ FloatRate(FR007 浮动利率,拼写修正) -/// dynomicPrincipal→ AccrualPrincipal(逐日滚动计息本金) -/// -/// -/// 重要——以下 当前为"结构骨架": -/// 精确的跨日不变量(T+1 本金缩到剩余、重置日本金保留、consumedInterest 扣除、保证金腿差分公式) -/// 依 branch-merge-analysis §7 的 DI_* 不变量,必须在把 _0808(人工已过)的利息核心并入后, -/// 从 CalcDaily* 迁移而来并以 Excel oracle 验收。骨架故意只跑"朴素逐日累加", -/// 不等价于已验证口径——切勿在未迁移前接入生产。 /// public static class FundingLegAccrual { - // 中性锚点日期:AccrueDay 只需"同日起止 → 1 天"的语义,不依赖真实时钟,保持纯函数。 - private static readonly DateTime Epoch = new(2000, 1, 1); - - // 资金腿计息精度(生产口径)。与 SwapDealService.InterestCalculationPrecision 一致。 - // 注意:SwapInterest.Precision=11 仅服务于保证金腿(MarginAccount),与资金腿 12 不一致属已知 TODO; - // 资金腿所有落库/对账均以 12 为准,此处显式锁定,避免静默引入尾差。 - private const int ProductionPrecision = 12; - - /// - /// 单日原子计息("AccrueDay")。委托 SwapInterest.AccrueSimple(同一天、Convention 边界 → 1 天), - /// 直接复用 SwapInterest 已有的 (Accrued/AccruedToday)作为返回, - /// 不再另立结果类型。编排层按日把"当天本金 + 当天率"喂入此入口,使浮动利率逐日不同也能正确累积。 - /// 复利时收盘本金 = 当日本金 + 当日利息(利滚利),该推导在 内完成, - /// 不塞进返回结构,保持与 SwapInterest 单一结果类型的契约一致。 - /// - /// 当日计息本金(来自 )。 - /// 当日生效年利率(由调用方经 IIndexFixer + 合约利差构造后传入,已含 spread)。 - /// 计息政策(含算头算尾 / 年化天数 / 单复利)。 - public static InterestResult AccrueDay( - decimal accrualPrincipal, - decimal dailyRate, - AccrualPolicy policy, - int precision = SwapInterest.Precision) - { - // 单日计息:start == end,按 policy.Convention 决定首日是否计;Both 时恰 1 天。 - return SwapInterest.AccrueSimple(accrualPrincipal, dailyRate, Epoch, Epoch, policy.Convention, policy.AnnualDays, precision); - } - /// /// 单利日终计息(纯函数,替换 SwapDealService.CalcDailySimpleInterestByEod 的"纯数学"部分)。 /// @@ -65,7 +22,7 @@ public static class FundingLegAccrual /// /// 计息基数 baseTdInterestPrincipal = priorAccrualPrincipal + positionPrincipal − originalPv; /// 当日利息 = baseTdInterestPrincipal × closeRatio × rate.AllInRate,年化则再 ÷ AnnualDays; - /// 累计未实现 = priorUnrealized + 当日利息;末位按资金腿精度 12 舍入。 + /// 累计未实现 = priorUnrealized + 当日利息;末位按资金腿精度 舍入。 /// /// /// 取率与重置日重取浮动利率由适配器(CalcDailySimpleInterestByEod)负责,并封装为 传入; @@ -102,83 +59,7 @@ public static class FundingLegAccrual var totalUnrealized = priorUnrealized + dayInterest; return new InterestResult( - Math.Round(totalUnrealized, ProductionPrecision, MidpointRounding.AwayFromZero), - Math.Round(tdInterest, ProductionPrecision, MidpointRounding.AwayFromZero)); - } - - /// - /// 逐日计息编排(骨架)。从 逐日循环, - /// 推进 ,并返回期末状态。 - /// - /// 期初状态(通常来自上一日日终,见 )。 - /// 计息区间起点。 - /// 计息区间终点。 - /// 取计息日生效年利率的委托(适配器处由 IIndexFixer + 合约利差构造;测试可传 day => 0.0134m)。 - /// 计息政策。 - /// 可选平仓比例(占剩余,0~1)。非空则在期末应用平仓缩放。 - public static AccrualState AccruePeriod( - AccrualState opening, - DateTime startDate, - DateTime endDate, - Func dailyRate, - AccrualPolicy policy, - decimal? closeRatio = null) - { - var state = opening; - - for (var day = startDate.Date; day <= endDate.Date; day = day.AddDays(1)) - { - var rate = dailyRate(day); - var dayResult = AccrueDay(state.AccrualPrincipal, rate, policy); - - // 收盘本金:复利时并入当日利息(利滚利),单利时维持原基数。 - var nextPrincipal = state.AccrualPrincipal + (policy.IsCompound ? dayResult.AccruedToday : 0m); - var nextUnrealized = state.UnrealizedInterest + dayResult.AccruedToday; - state = new AccrualState(nextPrincipal, nextUnrealized, state.RealizedInterest); - - // ── PORT(合并 _0808 后从 CalcDaily* 迁移,受 DI_* 不变量 + Excel oracle 验收)── - // 1. 重置日(距 StartDate 每 resetPeriodDays 天):复利时累计利息并入本金(已在 ClosingAccrualPrincipal 体现); - // 但"重置日部分平仓后 EOD 本金必须保留计算出的复利本金、不得被 closeRatio 二次缩放"。 - // 2. 部分平仓次日(T+1):AccrualPrincipal 必须缩到剩余(× (1-closeRatio)); - // 重置日 / 算尾日不得二次缩放,否则剩余本金被打折。 - // 3. consumedInterest(历史已实现)在平仓日经 SwapInterest.ApplyUnwind 扣除。 - // 4. 保证金腿差分基数 OriginalPv:dynomicPrincipal = AccrualPrincipal + PositionPrincipal - OriginalPv,此处分支处理。 - // 5. replay 求 Δ:本 EOD 状态 − 上一 EOD 状态,由调用方(适配器层)负责,不在纯数学内。 - } - - if (closeRatio.HasValue) - { - state = ApplyPartialClose(state, closeRatio.Value, state.RealizedInterest, policy); - } - - return state; - } - - /// - /// 部分 / 全部平仓缩放:把剩余待实现按 (1-closeRatio) 保留,并扣除历史已实现; - /// 计息本金同步缩到剩余持仓。委托 SwapInterest.ApplyUnwind / AccrueUnrealized(与 Margin 共用同一纯函数)。 - /// - /// 平仓前状态(未实现部分)。 - /// 平仓比例(占剩余持仓,0~1;1=全平)。 - /// 历史已实现利息累计,从剩余未实现中扣除。 - /// 计息政策(精度取 SwapInterest.Precision)。 - public static AccrualState ApplyPartialClose( - AccrualState state, - decimal closeRatio, - decimal realizedInterest, - AccrualPolicy policy) - { - // 待实现利息缩放:unrealized × (1-closeRatio) − realizedInterest - var scaled = SwapInterest.ApplyUnwind( - new InterestResult(state.UnrealizedInterest, state.UnrealizedInterest), - closeRatio, realizedInterest, SwapInterest.Precision); - - // 计息本金按剩余持仓缩放(全平 closeRatio=1 → 归零) - var principalRemaining = Math.Round( - state.AccrualPrincipal * (1m - closeRatio), - SwapInterest.Precision, - MidpointRounding.AwayFromZero); - - return new AccrualState(principalRemaining, scaled.Accrued, realizedInterest); + Math.Round(totalUnrealized, SwapInterest.FundingLegPrecision, MidpointRounding.AwayFromZero), + Math.Round(tdInterest, SwapInterest.FundingLegPrecision, MidpointRounding.AwayFromZero)); } }