diff --git a/YLErpDAL/Modules/SwapModule/SwapDealIndexFixer.cs b/YLErpDAL/Modules/SwapModule/SwapDealIndexFixer.cs new file mode 100644 index 00000000..0ba1acc9 --- /dev/null +++ b/YLErpDAL/Modules/SwapModule/SwapDealIndexFixer.cs @@ -0,0 +1,25 @@ +using System; +using YLErp.Derivatives.Interest; + +namespace YLErp.Modules.SwapModule; + +/// +/// SwapDealService 专用取价器:通过实例方法委托给 TryGetFloatRate(virtual), +/// 而非 Fr007IndexFixer.Instance 那样直接调 EodPriceQueryService。 +/// +/// 为什么不用静态 Instance:SwapDealService.TryGetFloatRate 是 protected virtual, +/// 测试通过 override 它注入 stub 利率。静态 Instance 绕过这个接缝会让 45 个测试失败。 +/// 本类把 TryGetFloatRate 包成 IIndexFixer,既保留 virtual 接缝,又用上 IndexFixerBase。 +/// +internal sealed class SwapDealIndexFixer : IndexFixerBase, IIndexFixer +{ + private readonly SwapDealService _owner; + internal SwapDealIndexFixer(SwapDealService owner) => _owner = owner; + + public bool TryGetFixing(DateTime fixingDate, string underlyingCode, out decimal rate) + { + bool ok = _owner.TryGetFloatRate(fixingDate, underlyingCode, out double r); + rate = Convert.ToDecimal(r); + return ok; + } +} diff --git a/YLErpDAL/Modules/SwapModule/SwapDealService.cs b/YLErpDAL/Modules/SwapModule/SwapDealService.cs index 4183bece..c2a74be4 100644 --- a/YLErpDAL/Modules/SwapModule/SwapDealService.cs +++ b/YLErpDAL/Modules/SwapModule/SwapDealService.cs @@ -5,6 +5,7 @@ using System.Linq.Expressions; using YLErp.BLL; using YLErp.BLL.Eod; using YLErp.DBModels.Enums; +using YLErp.Derivatives.Interest; using YLErp.Helpers; using YLErp.Modules.DataProviderModule; using YLErp.Modules.EodModule; @@ -23,6 +24,10 @@ namespace YLErp.Modules.SwapModule return EodPriceQueryService.TryGetPrice(valueDate, underlyingCode, out rate); } + private IIndexFixer _indexFixer; + /// FR007 取价器,委托 TryGetFloatRate(保留 virtual 接缝供测试 stub)。 + protected virtual IIndexFixer IndexFixer => _indexFixer ??= new SwapDealIndexFixer(this); + #region 可测试化接缝(Seams)——override 这些虚方法可在测试中替换 DB/外部调用,生产代码行为不变 // FindTrade 已上提到基类 SwapTradeBaseService(三子类实现一致,消除重复) @@ -1037,9 +1042,8 @@ namespace YLErp.Modules.SwapModule if (string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) return position.FloatRate; int days = (endDate - startDate).Days; - DateTime rateDate = days % period == 0 - ? QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(position.interest_rule ?? 0)) - : QdpCalendarHelper.GetNonHolidayDefore(startDate.AddDays(position.interest_rule ?? 0)); + DateTime rateDate = IndexFixerBase.GetFixingDate( + days % period == 0 ? endDate : startDate, position.interest_rule); if (preEod.id != 0 && days % period != 0) { @@ -1047,9 +1051,9 @@ namespace YLErp.Modules.SwapModule return preEod.FloatRate; } - if (TryGetFloatRate(rateDate, position.FloatRateUnderlyingCode, out double rate)) + if (IndexFixer.TryGetFixing(rateDate, position.FloatRateUnderlyingCode, out decimal rate)) { - position.FloatRate = positionClone.FloatRate = Convert.ToDecimal(rate); + position.FloatRate = positionClone.FloatRate = rate; return position.FloatRate; } if (!swap) throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{rateDate:yyyy年MM月dd日}的价格"); @@ -1352,14 +1356,14 @@ namespace YLErp.Modules.SwapModule if (accrueDate >= startDate && i % interestPeriod == 0 && !string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0)); - if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1)) + var fixingDate = IndexFixerBase.GetFixingDate(accrueDate, position.interest_rule); + if (IndexFixer.TryGetFixing(fixingDate, position.FloatRateUnderlyingCode, out decimal fixing)) { - if (floatRate1 != 0) floatRate = floatRate1; + if (fixing != 0m) floatRate = Convert.ToDouble(fixing); } else { - throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格"); + throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格"); } } if (accrueDate >= startDate) @@ -1443,14 +1447,14 @@ namespace YLErp.Modules.SwapModule // tdDynomicPrincipal = flowEvent.InterestPrincipal 使本金累积乘 closePercent^N)。 if (i % interestPeriod == 0 && !string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(accrueDate.AddDays(position.interest_rule ?? 0)); - if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1)) + var fixingDate = IndexFixerBase.GetFixingDate(accrueDate, position.interest_rule); + if (IndexFixer.TryGetFixing(fixingDate, position.FloatRateUnderlyingCode, out decimal fixing)) { - if (floatRate1 != 0) floatRate = floatRate1; + if (fixing != 0m) floatRate = Convert.ToDouble(fixing); } else { - throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格"); + throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格"); } } @@ -1507,18 +1511,14 @@ namespace YLErp.Modules.SwapModule tdDynomicPrincipal = tdDynomicPrincipal + interestProfitSum * remainingPercent; if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - // 获取合适的 rateDate - var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(position.interest_rule ?? 0)); // 获取前一工作日; - if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double floatRate1)) + var fixingDate = IndexFixerBase.GetFixingDate(endDate, position.interest_rule); + if (IndexFixer.TryGetFixing(fixingDate, position.FloatRateUnderlyingCode, out decimal fixing)) { - if (floatRate1 != 0) - { - floatRate = floatRate1; - } + if (fixing != 0m) floatRate = Convert.ToDouble(fixing); } else { - throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格"); + throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格"); } } @@ -1572,17 +1572,14 @@ namespace YLErp.Modules.SwapModule // 获取新的浮动利率 if (!string.IsNullOrEmpty(position.FloatRateUnderlyingCode)) { - var fr007RateDate = QdpCalendarHelper.GetNonHolidayDefore(endDate.AddDays(position.interest_rule ?? 0)); - if (TryGetFloatRate(fr007RateDate, position.FloatRateUnderlyingCode, out double newFloatRate)) + var fixingDate = IndexFixerBase.GetFixingDate(endDate, position.interest_rule); + if (IndexFixer.TryGetFixing(fixingDate, position.FloatRateUnderlyingCode, out decimal fixing)) { - if (newFloatRate != 0) - { - floatRate = newFloatRate; - } + if (fixing != 0m) floatRate = Convert.ToDouble(fixing); } else { - throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fr007RateDate:yyyy年MM月dd日}的价格"); + throw new Exception($"获取不到{position.FloatRateUnderlyingCode}在{fixingDate:yyyy年MM月dd日}的价格"); } } }