refactor(interest): SwapDealService 6处取价收敛到 IIndexFixer
修正上次尝试的失败: 静态 Fr007IndexFixer.Instance 绕过了 TryGetFloatRate(virtual)接缝, 导致测试 stub 失效(CI_007/CI_008失败)。 本次方案: 新增 SwapDealIndexFixer(实例级, 委托 TryGetFloatRate): - SwapDealService.IndexFixer 属性 lazy 初始化, 包 SwapDealIndexFixer - 6处 GetNonHolidayDefore+TryGetFloatRate 全部替换为 IndexFixerBase+IndexFixer - TryGetFloatRate(protected virtual)保留不动, 测试 stub 机制完全不受影响 验证: CI_007/CI_008 从失败转为通过, 全量480测试7失败(与基线一致,零回归)。 SwapDealService 内 GetNonHolidayDefore 出现次数: 6 → 0(全部收敛到 IndexFixerBase)。
This commit is contained in:
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using YLErp.Derivatives.Interest;
|
||||
|
||||
namespace YLErp.Modules.SwapModule;
|
||||
|
||||
/// <summary>
|
||||
/// SwapDealService 专用取价器:通过实例方法委托给 TryGetFloatRate(virtual),
|
||||
/// 而非 Fr007IndexFixer.Instance 那样直接调 EodPriceQueryService。
|
||||
///
|
||||
/// 为什么不用静态 Instance:SwapDealService.TryGetFloatRate 是 protected virtual,
|
||||
/// 测试通过 override 它注入 stub 利率。静态 Instance 绕过这个接缝会让 45 个测试失败。
|
||||
/// 本类把 TryGetFloatRate 包成 IIndexFixer,既保留 virtual 接缝,又用上 IndexFixerBase。
|
||||
/// </summary>
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
/// <summary>FR007 取价器,委托 TryGetFloatRate(保留 virtual 接缝供测试 stub)。</summary>
|
||||
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日}的价格");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user