refactor(accrual): 提取BuildLegRate/BuildEodPolicy消除EOD wrapper构造重复

EOD CompoundEod + SimpleEod 各有一份相同的FundingLegRate构造(3行)
和AccrualPolicy构造(5行), 共16行重复。

提取为:
- BuildLegRate(position, spread, effectiveFloat): 固定腿→Fixed, 浮动腿→Floating
- BuildEodPolicy(position, annualDays, isCompound): 算头算尾+重置周期

每个EOD wrapper从10行构造代码→2行调用, 净减12行
SwapModule零回归(7基线/510通过)
This commit is contained in:
hjhan
2026-08-12 14:01:24 +08:00
parent 9d321378ac
commit bfa230381b
+15 -22
View File
@@ -1339,6 +1339,16 @@ namespace YLErp.Modules.SwapModule
throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格");
}
/// <summary>构造利率值对象:固定腿→Fixed(spread),浮动腿→Floating(spread+fixing)。</summary>
private static FundingLegRate BuildLegRate(swap_position position, decimal spread, decimal effectiveFloat)
=> string.IsNullOrEmpty(position.FloatRateUnderlyingCode)
? FundingLegRate.Fixed(spread)
: FundingLegRate.Floating(spread, effectiveFloat);
/// <summary>构造 EOD 计息政策(算头算尾,重置周期取 position.interest_rest_days)。</summary>
private static AccrualPolicy BuildEodPolicy(swap_position position, int annualDays, bool isCompound)
=> new AccrualPolicy(AccrualBoundary.Both, isCompound, position.interest_rest_days ?? 1, annualDays, position.IsAnnualized);
/// <summary>
/// 按重置周期切分利率段,每段记录 all-in 利率(spread+fixing)。返回 (分段列表, 末段浮动利率)。
/// fetchAfterDate: 仅该日期之后的重置日才取 FR007(单利传 ValueDate,复利传 null 全程取)。
@@ -1478,16 +1488,8 @@ namespace YLErp.Modules.SwapModule
: 1m;
// 纯数学下沉至 CompoundInterestAccrual.AccrueEodDDD 命名 + 末位生产精度 12 舍入)。
var isFixedLeg = string.IsNullOrEmpty(position.FloatRateUnderlyingCode);
var legRate = isFixedLeg
? FundingLegRate.Fixed(flowEvent.InterestRate)
: FundingLegRate.Floating(flowEvent.InterestRate, effectiveFloat);
var accrualPolicy = new AccrualPolicy(
convention: AccrualBoundary.Both,
isCompound: true,
resetPeriodDays: interestPeriod,
annualDays: annualDays,
isAnnualized: position.IsAnnualized);
var legRate = BuildLegRate(position, flowEvent.InterestRate, effectiveFloat);
var accrualPolicy = BuildEodPolicy(position, annualDays, isCompound: true);
// 完整计息 trace:前后日期/基数/利率/重置标志全过程,经 SwapCalcTrace 常驻落盘(关键路径日志)。
var interestTrace = new AccrualTrace();
@@ -1533,18 +1535,9 @@ namespace YLErp.Modules.SwapModule
flowEvent.FloatRate = effectiveFloat;
// 纯数学下沉至 SimpleInterestAccrualDDD 命名 + 末位生产精度 12 舍入),行为与上版逐字对齐
// 利率构成按腿型封装:固定腿 → FixedRate;浮动腿 → Spread + IndexFixing(沿用旧实现 InterestRate+浮动利率 的口径)。
var isFixedLeg = string.IsNullOrEmpty(position.FloatRateUnderlyingCode);
var legRate = isFixedLeg
? FundingLegRate.Fixed(flowEvent.InterestRate)
: FundingLegRate.Floating(flowEvent.InterestRate, effectiveFloat);
var accrualPolicy = new AccrualPolicy(
convention: AccrualBoundary.Both,
isCompound: false,
resetPeriodDays: position.interest_rest_days ?? 1,
annualDays: annualDays,
isAnnualized: position.IsAnnualized);
// 纯数学下沉至 SimpleInterestAccrual(末位生产精度 12 舍入)。
var legRate = BuildLegRate(position, flowEvent.InterestRate, effectiveFloat);
var accrualPolicy = BuildEodPolicy(position, annualDays, isCompound: false);
// 完整计息 trace:收集器由适配器创建,随后经 SwapCalcTrace 常驻落盘(关键路径日志,无条件)。
var interestTrace = new AccrualTrace();
var result = SimpleInterestAccrual.AccrueEod(