test(swap): 契约参考实现落地,引擎主力族盘中重放首次对齐确认书公式 oracle
ContractReferenceCalc 独立实现 §8a 确认书公式(∏/重置期切分/末段收口/ 利率确定日=重置日上一营业日),禁止引用生产计息类防同源;4 例手算锚点 自验证(真实规模 5000万/2.05%/90天=75999.04 与玩具锚点)。 引擎对照首批 3 例全绿:mode9/mode2 × 复利 × "10" × T+0 部分平仓30%, 盘中重放与契约 oracle 容差 0.01 元内逐分吻合——盘中口径=确认书公式 自此有机器强制,后续补格直接复用 oracle 供给(TEST-MATRIX §7.5 已登记)。 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
namespace UnitTestProject.Modules.SwapModule.Accrual
|
||||
{
|
||||
/// <summary>
|
||||
/// 契约参考实现(确认书公式,TEST-MATRIX §8a)——全矩阵统一 oracle 供给。
|
||||
///
|
||||
/// 【独立性约束·勿破坏】本类只实现确认书公式原文,禁止引用任何生产计息引擎类
|
||||
/// (YLErp.Modules.SwapModule.Accrual.* / SwapDealService),否则 oracle 与被测对象同源,
|
||||
/// 失去"独立参考"资格(oracle 分级第一级,见 TEST-MATRIX §7.4)。
|
||||
///
|
||||
/// 确认书公式(国联民生收益互换确认书-现券/ETF 四份一致):
|
||||
/// 参考利率(绝对) = ∏[i=1..k] ( 1 + (FR007i + 利差) × di / 365 ) − 1
|
||||
/// 结息额(平仓部分) = 实际平掉额 × 参考利率(绝对)
|
||||
/// - k = 计息期包含的重置期个数;完整重置期 di = 重置频率(生产 7 天),末段不足按实际日历日
|
||||
/// - 重置期自计息期首日按重置频率依次推算;首个重置期始于计息期首日;末段收口到计息期最后一日
|
||||
/// - 利率确定日 = 每个重置期首日(重置日)的上一个营业日,取该日 FR007
|
||||
/// - 计息期 = 自起始日(含)至到期日(不含)——即算头不算尾 "10"(生产主力条款)
|
||||
/// - 计息基准 A/365
|
||||
///
|
||||
/// 营业日准则:本参考实现按周末近似(周六/周日非营业日);法定节假日历由调用方通过
|
||||
/// 取价委托自行吸收(如按确定日提供同一利率)。测试与生产参数对齐(§8):重置 7 天 / 365。
|
||||
/// </summary>
|
||||
public static class ContractReferenceCalc
|
||||
{
|
||||
/// <summary>
|
||||
/// 参考利率(绝对) = ∏(1 + (FR007i+利差)×di/annualDays) − 1。
|
||||
/// </summary>
|
||||
/// <param name="startDate">计息期首日(含)</param>
|
||||
/// <param name="endDate">计息期末日("10"不含/"11"含,由 calcLast 决定)</param>
|
||||
/// <param name="resetDays">重置频率天数(生产 7)</param>
|
||||
/// <param name="spread">利差(InterestRateDefault,如 +0.25% = 0.0025)</param>
|
||||
/// <param name="fixing">取价委托:入参=利率确定日(重置日上一营业日),返回该日 FR007</param>
|
||||
/// <param name="calcFirst">算头(生产 "10"/"11" 为 true)</param>
|
||||
/// <param name="calcLast">算尾(生产 "10" 为 false)</param>
|
||||
/// <param name="annualDays">计息基准(生产 365)</param>
|
||||
public static decimal ReferenceRateAbsolute(
|
||||
DateTime startDate, DateTime endDate,
|
||||
int resetDays, decimal spread,
|
||||
Func<DateTime, decimal> fixing,
|
||||
bool calcFirst = true, bool calcLast = false,
|
||||
int annualDays = 365)
|
||||
{
|
||||
var totalDays = (endDate - startDate).Days + (calcFirst ? 0 : -1) + (calcLast ? 1 : 0);
|
||||
if (totalDays <= 0) return 0m;
|
||||
|
||||
decimal factor = 1m;
|
||||
var resetDate = startDate; // 首个重置期始于计息期首日
|
||||
var remaining = totalDays;
|
||||
while (remaining > 0)
|
||||
{
|
||||
var di = Math.Min(resetDays, remaining); // 完整期 di=resetDays,末段按实际日历日
|
||||
var fixingDate = PreviousBusinessDay(resetDate);
|
||||
var allIn = fixing(fixingDate) + spread;
|
||||
factor *= 1m + allIn * di / annualDays;
|
||||
remaining -= di;
|
||||
resetDate = resetDate.AddDays(di);
|
||||
}
|
||||
return factor - 1m;
|
||||
}
|
||||
|
||||
/// <summary>结息额(平仓部分)= 实际平掉额 × 参考利率(绝对)。</summary>
|
||||
public static decimal ClosedInterest(decimal closedNotional, decimal referenceRate)
|
||||
=> closedNotional * referenceRate;
|
||||
|
||||
/// <summary>利率确定日 = 重置日的上一营业日(周末近似)。</summary>
|
||||
public static DateTime PreviousBusinessDay(DateTime date)
|
||||
{
|
||||
do { date = date.AddDays(-1); }
|
||||
while (date.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday);
|
||||
return date;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user