refactor(swap): relaxedFixingFromDate 改名 exclusionStart——名实归位
该参数诞生于"有价则取/缺价回退"口径(55363e9f由 exclusionEndDate 改名而来), 自洽化(fafae5ca)后排除日一概不取价,"放宽取价"语义已不存在——名字回到 排除区间本义,并与 FIX 日志既有用词"排除起点"对齐: - BuildSegmentRates/CalcDailyCompoundInterest/CalcDailySimpleInterest 三签名 + 全平重放传参点 + 方法摘要补 exclusionStart 参数语义文档 零行为变更。 验证:内存套件 113/113;全量 981 例 145 败与基线 diff=0
This commit is contained in:
@@ -577,9 +577,9 @@ namespace YLErp.Modules.SwapModule
|
||||
StringAssert.Contains(o.Ex.Message, "FR007");
|
||||
}
|
||||
|
||||
// ── 到期日当天全平:replayEndDate=endDate+1 补计分支(relaxedFixingFromDate 的存在理由)──
|
||||
// ── 到期日当天全平:replayEndDate=endDate+1 补计分支(exclusionStart 的存在理由)──
|
||||
// 不算尾时 InitInterestDate 把 endDate 回拨一天;最终全平的历史差分重放需把窗口补回真实
|
||||
// 平仓/到期日(replayEndDate=endDate+1),但该边界日的定盘经 relaxedFixingFromDate 标记为
|
||||
// 平仓/到期日(replayEndDate=endDate+1),但该边界日的定盘经 exclusionStart 标记为
|
||||
// "有价则取/缺价跳过"——否则到期日上午全平会被尾日价误拦(EQD-6968 在到期日的镜像场景)。
|
||||
|
||||
[TestMethod]
|
||||
|
||||
@@ -1294,7 +1294,7 @@ namespace YLErp.Modules.SwapModule
|
||||
// 计算截至本次平仓日的累计利息 amountAtEnd
|
||||
CalcDailyCompoundInterest(replayEndDate, position, closePosiNotionalValue,
|
||||
interestAtEnd, annualDays, floateRate, closePrecent,
|
||||
calcFirst, calcLast, ref amountAtEnd, ref tdAmountAtEnd, consumedInterest, relaxedFixingFromDate: endDate);
|
||||
calcFirst, calcLast, ref amountAtEnd, ref tdAmountAtEnd, consumedInterest, exclusionStart: endDate);
|
||||
var interestAtPreviousEod = new swap_flow_event { InterestRate = rate };
|
||||
decimal amountAtPreviousEod = 0m;
|
||||
decimal tdAmountAtPreviousEod = 0m;
|
||||
@@ -1356,11 +1356,13 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <summary>
|
||||
/// 按重置周期切分利率段,每段记录 all-in 利率(spread+fixing)。返回 (分段列表, 末段浮动利率)。
|
||||
/// fetchAfterDate: 仅该日期之后的重置日才取 FR007(单利传 ValueDate,复利传 null 全程取)。
|
||||
/// exclusionStart: 排除区间起点——该日期起(含)的重置日视为"排除日"(不算尾的不计息边界日),
|
||||
/// 一概不取价;缺省=endDate。仅不算尾(calcLast=false)生效;算尾所有重置日照常强制取价。
|
||||
/// </summary>
|
||||
private (List<(DateTime StartDate, decimal Rate)> Segments, decimal LastFloat) BuildSegmentRates(
|
||||
DateTime startDate, DateTime endDate, int interestPeriod,
|
||||
swap_position position, decimal spread, decimal initialFloat,
|
||||
DateTime? fetchAfterDate, bool calcLast = true, DateTime? relaxedFixingFromDate = null)
|
||||
DateTime? fetchAfterDate, bool calcLast = true, DateTime? exclusionStart = null)
|
||||
{
|
||||
var rates = new List<(DateTime, decimal)>();
|
||||
var calcDays = (endDate - startDate).Days;
|
||||
@@ -1368,7 +1370,7 @@ namespace YLErp.Modules.SwapModule
|
||||
SwapCalcTrace.Critical(
|
||||
$"FIX Segments p{position.id} [{startDate:yyyy-MM-dd}→{endDate:yyyy-MM-dd}] period={interestPeriod} " +
|
||||
$"fetchAfter={(fetchAfterDate?.ToString("yyyy-MM-dd") ?? "全程")} calcLast={calcLast} " +
|
||||
$"排除起点={(relaxedFixingFromDate?.ToString("yyyy-MM-dd") ?? (calcLast ? "无" : endDate.ToString("yyyy-MM-dd")))} seed={initialFloat:P6} spread={spread:P6}");
|
||||
$"排除起点={(exclusionStart?.ToString("yyyy-MM-dd") ?? (calcLast ? "无" : endDate.ToString("yyyy-MM-dd")))} seed={initialFloat:P6} spread={spread:P6}");
|
||||
for (int i = 0; i <= calcDays; i += interestPeriod)
|
||||
{
|
||||
var resetDate = startDate.AddDays(i);
|
||||
@@ -1377,7 +1379,7 @@ namespace YLErp.Modules.SwapModule
|
||||
// 排除日(EQD-6968 自洽化)一概不取价(有价也不取),currentFloat 保持末段已消费利率:
|
||||
// 事件/快照回写的浮动利率与金额同源、与平仓时刻无关。剩余持仓的新周期利率由
|
||||
// SwapEodPositionService 的"重置日再定盘"显式获取,不靠排除日顺带。算尾照常强制取价。
|
||||
bool isExcludedEnd = !calcLast && resetDate >= (relaxedFixingFromDate ?? endDate);
|
||||
bool isExcludedEnd = !calcLast && resetDate >= (exclusionStart ?? endDate);
|
||||
if (needFetch && !isExcludedEnd)
|
||||
{
|
||||
currentFloat = ResolveFloatRate(position, resetDate, currentFloat);
|
||||
@@ -1405,17 +1407,17 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <returns></returns>
|
||||
public void CalcDailyCompoundInterest(DateTime endDate, swap_position position, decimal principal, swap_flow_event flowEvent,
|
||||
int annualDays, decimal floateRate, decimal closePercent, bool calcFirst, bool calcLast,
|
||||
ref decimal InterestAmount, ref decimal TdInterestAmount, decimal consumedInterest = 0m, decimal resetCarryInterest = 0m, DateTime? relaxedFixingFromDate = null)
|
||||
ref decimal InterestAmount, ref decimal TdInterestAmount, decimal consumedInterest = 0m, decimal resetCarryInterest = 0m, DateTime? exclusionStart = null)
|
||||
{
|
||||
var startDate = position.PosiStartDate;
|
||||
int interestPeriod = position.interest_rest_days ?? 1;
|
||||
|
||||
// 分段取率:复利全程重放,每个重置日(含 startDate)取 FR007(fetchAfterDate=null)。
|
||||
// calcLast 透传,与下方 AccruePeriod 的边界同源,避免两处漂移;
|
||||
// relaxedFixingFromDate 仅重放补计不算尾漏计利息时非 null(=真实平仓日),锚定尾日跳过取价起点。
|
||||
// exclusionStart 仅重放补计不算尾漏计利息时非 null(=真实平仓日),锚定尾日跳过取价起点。
|
||||
var (segmentRates, currentFloat) = BuildSegmentRates(
|
||||
startDate, endDate, interestPeriod, position, flowEvent.InterestRate, floateRate,
|
||||
fetchAfterDate: null, calcLast: calcLast, relaxedFixingFromDate: relaxedFixingFromDate);
|
||||
fetchAfterDate: null, calcLast: calcLast, exclusionStart: exclusionStart);
|
||||
|
||||
// 纯函数复利计息:分段重置日并本金 + resetCarryInterest + 扣 consumedInterest
|
||||
var interestTrace = new AccrualTrace();
|
||||
@@ -1445,7 +1447,7 @@ namespace YLErp.Modules.SwapModule
|
||||
/// <summary>
|
||||
/// 计算单利 盘中(按重置天数分段,每段使用对应浮动利率)
|
||||
/// </summary>
|
||||
public void CalcDailySimpleInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount, decimal consumedInterest = 0m, DateTime? relaxedFixingFromDate = null)
|
||||
public void CalcDailySimpleInterest(eod_swap_position preEodPosition, DateTime endDate, swap_position position, decimal posiPrincipal, swap_flow_event flowEvent, int annualDays, decimal floateRate, decimal closePercent, decimal orginPv, bool calcFirst, bool calcLast, ref decimal InterestAmount, ref decimal TdInterestAmount, decimal consumedInterest = 0m, DateTime? exclusionStart = null)
|
||||
{
|
||||
var startDate = position.PosiStartDate;
|
||||
int interestPeriod = position.interest_rest_days ?? 1;
|
||||
@@ -1458,7 +1460,7 @@ namespace YLErp.Modules.SwapModule
|
||||
// calcLast 透传,与下方 AccruePeriod 的边界同源,避免两处漂移。
|
||||
var (segmentRates, currentFloat) = BuildSegmentRates(
|
||||
startDate, endDate, interestPeriod, position, flowEvent.InterestRate, floateRate,
|
||||
fetchAfterDate: preEodPosition.ValueDate, calcLast: calcLast, relaxedFixingFromDate: relaxedFixingFromDate);
|
||||
fetchAfterDate: preEodPosition.ValueDate, calcLast: calcLast, exclusionStart: exclusionStart);
|
||||
|
||||
// 纯函数计息:Accrued=缩放累计(InterestAmount),AccruedToday=未缩放累计(TdInterestAmount)
|
||||
var interestTrace = new AccrualTrace();
|
||||
|
||||
Reference in New Issue
Block a user