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日}的价格");
}
}
}