test(swap): 预付金腿两段式平仓计息过程暴露 + SwapCalcTrace追踪器
- 新增 SwapCalcTrace(零成本可开关追踪器,默认关闭,对生产零行为影响): 在 CalcDailySimpleInterest 埋点,逐日记录计息起点/日终归档 ValueDate 地板/ 计息基数 dynomicPrincipal/当日利率/当日利息/累计,便于定位计息异常根因。 - 新增 PrepaidPrincipalCloseTraceTest:用截图参数(本金100000.23/利率2.1111%/ 8.4平40%→8.7全平)暴露计息过程,证明第二次平仓利息完全由日终归档 ValueDate 决定——正确归档(ValueDate=8.4)+算尾=3天=10.41(Excel本次利息); 错误归档(ValueDate=8.1)复现系统截图 6天=20.83。守卫1钉正确值10.41, 守卫2复现20.83并证明 ValueDate 即『缺的要素』。 - 修正覆盖结论:浮动端/利息腿已有两段式覆盖,预付金腿两段式此前缺失(缺口 与截图坏『预付金端』一行精确对应)。
This commit is contained in:
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace YLErp.Modules.SwapModule
|
||||
{
|
||||
/// <summary>
|
||||
/// 计息计算过程追踪器(默认关闭,零运行时成本)。
|
||||
///
|
||||
/// 在 CalcDailySimpleInterest / CalcDailyCompoundInterest 等计息函数中调用
|
||||
/// SwapCalcTrace.Record(...),开启后逐日记录:计息起点、日终归档 ValueDate 地板、
|
||||
/// 计息基数、当日利率、当日利息、累计利息。便于定位"算出来一个数却不对"的根因,
|
||||
/// 也便于把一次真实平仓的逐步过程打印出来与 Excel 对账。
|
||||
///
|
||||
/// 用法(单元测试或临时排障):
|
||||
/// SwapCalcTrace.IsEnabled = true;
|
||||
/// SwapCalcTrace.Reset();
|
||||
/// ... 调用计息 ...
|
||||
/// Console.WriteLine(SwapCalcTrace.Dump());
|
||||
/// SwapCalcTrace.IsEnabled = false;
|
||||
/// </summary>
|
||||
public static class SwapCalcTrace
|
||||
{
|
||||
public static bool IsEnabled { get; set; } = false;
|
||||
|
||||
[ThreadStatic]
|
||||
private static List<string> _lines;
|
||||
|
||||
private static List<string> Lines => _lines ??= new List<string>();
|
||||
|
||||
public static void Reset() => Lines.Clear();
|
||||
|
||||
public static void Header(string title)
|
||||
{
|
||||
if (IsEnabled) Lines.Add($"== {title} ==");
|
||||
}
|
||||
|
||||
public static void Line(string text)
|
||||
{
|
||||
if (IsEnabled) Lines.Add(text);
|
||||
}
|
||||
|
||||
/// <summary>记录某一计息日的明细。</summary>
|
||||
public static void Day(int idx, DateTime date, decimal rate, decimal basePrincipal, decimal dayInterest, decimal accumulated)
|
||||
{
|
||||
if (IsEnabled)
|
||||
Lines.Add($" [{idx}] {date:yyyy-MM-dd} rate={rate:P6} base={basePrincipal:F4} day={dayInterest:F6} acc={accumulated:F6}");
|
||||
}
|
||||
|
||||
public static string Dump() => string.Join(Environment.NewLine, Lines);
|
||||
}
|
||||
}
|
||||
@@ -1360,6 +1360,15 @@ namespace YLErp.Modules.SwapModule
|
||||
decimal dynomicPrincipal = preEodPosition.TdInterestPrincipal + posiPrincipal - orginPv;
|
||||
decimal tdDynomicPrincipal = dynomicPrincipal;
|
||||
var calcDays = (endDate - startDate).Days;
|
||||
if (SwapCalcTrace.IsEnabled)
|
||||
{
|
||||
SwapCalcTrace.Header($"CalcDailySimpleInterest posId={position.id} mode={position.InterestMode} type={(position.InterestType == (int)InterestTypeEnum.复利 ? "复利" : "单利")}");
|
||||
SwapCalcTrace.Line($" PosiStartDate={startDate:yyyy-MM-dd} endDate={endDate:yyyy-MM-dd} calcDays={calcDays} calcFirst={calcFirst} calcLast={calcLast}");
|
||||
SwapCalcTrace.Line($" preEod.id={preEodPosition.id} ValueDate={preEodPosition.ValueDate:yyyy-MM-dd} TdInterestPrincipal={preEodPosition.TdInterestPrincipal:F4} InterestProfitSum={interestProfitSum:F4}");
|
||||
SwapCalcTrace.Line($" dynomicPrincipal = TdInterestPrincipal({preEodPosition.TdInterestPrincipal:F4}) + posiPrincipal({posiPrincipal:F4}) - orginPv({orginPv:F4}) = {dynomicPrincipal:F4}");
|
||||
SwapCalcTrace.Line($" 已结扣除(InterestProfitSum*closePercent)={interest:F4} consumedInterest={consumedInterest:F4} closePercent={closePercent}");
|
||||
SwapCalcTrace.Line($" 逐日累加上限: accrueDate > preEod.ValueDate({preEodPosition.ValueDate:yyyy-MM-dd}) 才计息");
|
||||
}
|
||||
double floatRate = Convert.ToDouble(floateRate);
|
||||
for (int i = 0; i <= calcDays; i++)
|
||||
{
|
||||
@@ -1400,6 +1409,8 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
interest += interest1;
|
||||
tdinterest += tdinterest1;
|
||||
if (SwapCalcTrace.IsEnabled)
|
||||
SwapCalcTrace.Day(i, accrueDate, (decimal)floatRate, flowEvent.InterestPrincipal, interest1, interest);
|
||||
}
|
||||
}
|
||||
InterestAmount = Math.Round(interest, InterestCalculationPrecision, MidpointRounding.AwayFromZero);
|
||||
|
||||
Reference in New Issue
Block a user