refactor(swap): Phase3 提取ClosePercentMath共享模块
SwapDealService的4个public static ClosePercent方法body搬到ClosePercentMath.cs: - ResolveUnwindPreviousNotional (上一日终浮动端名义本金) - ToRemainingClosePercent (A→B 占期初→占剩余) - ToOriginalClosePercent (B→A 逆转换) - CalcDefaultInitClosePercent (默认占期初比例) DealService保留4个一行转发壳, 外部调用(含6+测试文件)零改动 核实EodService内联closePercent公式与此不同, 非重复, 不替换 SwapModule零回归(7基线/510通过)
This commit is contained in:
@@ -0,0 +1,65 @@
|
||||
using YLErp.DBModels;
|
||||
|
||||
namespace YLErp.Modules.SwapModule;
|
||||
|
||||
/// <summary>
|
||||
/// 平仓比例(ClosePercent) 数学——占期初(A) / 占剩余(B) 两种口径的转换。
|
||||
/// 从 SwapDealService 提取为共享模块,两个 service 均可引用。
|
||||
/// </summary>
|
||||
public static class ClosePercentMath
|
||||
{
|
||||
/// <summary>
|
||||
/// 取上一日终的浮动端名义本金(orginPv 的来源)。
|
||||
/// 优先取浮动腿 PosiNotionalValue 之和,取不到用 eod_swap 多空绝对值之和,都没有用 currentNotional 兜底。
|
||||
/// </summary>
|
||||
public static decimal ResolveUnwindPreviousNotional(
|
||||
eod_swap lastEod,
|
||||
IEnumerable<eod_swap_position> lastEodPositions,
|
||||
decimal currentNotional)
|
||||
{
|
||||
var floatingPositions = lastEodPositions?.Where(x => x.PosiDirection > 0).ToList();
|
||||
decimal previousNotional;
|
||||
if (floatingPositions?.Count > 0)
|
||||
{
|
||||
previousNotional = floatingPositions.Sum(x => x.PosiNotionalValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
previousNotional = lastEod == null
|
||||
? currentNotional
|
||||
: Math.Abs(lastEod.NotionalValueLong) + Math.Abs(lastEod.NotionalValueShort);
|
||||
}
|
||||
|
||||
return previousNotional == 0m && currentNotional != 0m
|
||||
? currentNotional
|
||||
: previousNotional;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A(占期初) → B(占剩余),用于把前端传入的占期初比例换算成后端计算用的占剩余比例。
|
||||
/// </summary>
|
||||
public static decimal ToRemainingClosePercent(decimal originalClosePercent, decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
if (posiNotionalValue <= 0) return originalClosePercent;
|
||||
var remaining = originalClosePercent * notionalValue / posiNotionalValue;
|
||||
return remaining > 1 ? 1 : remaining;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// B(占剩余) → A(占期初),用于落库 / 事件列表展示还原。见 ToRemainingClosePercent。
|
||||
/// </summary>
|
||||
public static decimal ToOriginalClosePercent(decimal remainingClosePercent, decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
if (notionalValue <= 0) return remainingClosePercent;
|
||||
return remainingClosePercent * posiNotionalValue / notionalValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 计算 InitUnwind 默认占期初(A)平仓比例 = PosiNotionalValue / NotionalValue。
|
||||
/// 未平仓时 =1(平100%);部分平仓后自动变为剩余比例。
|
||||
/// </summary>
|
||||
public static decimal CalcDefaultInitClosePercent(decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
return notionalValue > 0 ? posiNotionalValue / notionalValue : 1;
|
||||
}
|
||||
}
|
||||
@@ -625,24 +625,7 @@ namespace YLErp.Modules.SwapModule
|
||||
eod_swap lastEod,
|
||||
IEnumerable<eod_swap_position> lastEodPositions,
|
||||
decimal currentNotional)
|
||||
{
|
||||
var floatingPositions = lastEodPositions?.Where(x => x.PosiDirection > 0).ToList();
|
||||
decimal previousNotional;
|
||||
if (floatingPositions?.Count > 0)
|
||||
{
|
||||
previousNotional = floatingPositions.Sum(x => x.PosiNotionalValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
previousNotional = lastEod == null
|
||||
? currentNotional
|
||||
: Math.Abs(lastEod.NotionalValueLong) + Math.Abs(lastEod.NotionalValueShort);
|
||||
}
|
||||
|
||||
return previousNotional == 0m && currentNotional != 0m
|
||||
? currentNotional
|
||||
: previousNotional;
|
||||
}
|
||||
=> ClosePercentMath.ResolveUnwindPreviousNotional(lastEod, lastEodPositions, currentNotional);
|
||||
|
||||
/// <summary>
|
||||
/// 获取利息腿"已通过历史互换结出的累计利息"(用于复利重算时扣除,类比分红的 CalcConsumedDividend)。
|
||||
@@ -822,32 +805,19 @@ namespace YLErp.Modules.SwapModule
|
||||
/// 分母为 0(无持仓等异常场景)时原样返回,避免除零。
|
||||
/// </summary>
|
||||
public static decimal ToRemainingClosePercent(decimal originalClosePercent, decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
if (posiNotionalValue <= 0) return originalClosePercent;
|
||||
var remaining = originalClosePercent * notionalValue / posiNotionalValue;
|
||||
return remaining > 1 ? 1 : remaining;
|
||||
}
|
||||
=> ClosePercentMath.ToRemainingClosePercent(originalClosePercent, notionalValue, posiNotionalValue);
|
||||
|
||||
/// <summary>
|
||||
/// B(占剩余) → A(占期初),用于落库 / 事件列表展示还原。见 ToRemainingClosePercent。
|
||||
/// </summary>
|
||||
public static decimal ToOriginalClosePercent(decimal remainingClosePercent, decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
if (notionalValue <= 0) return remainingClosePercent;
|
||||
return remainingClosePercent * posiNotionalValue / notionalValue;
|
||||
}
|
||||
=> ClosePercentMath.ToOriginalClosePercent(remainingClosePercent, notionalValue, posiNotionalValue);
|
||||
|
||||
/// <summary>
|
||||
/// 计算 InitUnwind 默认占期初(A)平仓比例 = "平掉剩余全部持仓"对应的占期初比例。
|
||||
/// 即:ClosePercent(A) = PosiNotionalValue / NotionalValue。
|
||||
/// 未平仓时 PosiNotionalValue==NotionalValue → 1(平100%);
|
||||
/// 部分平仓后自动变为剩余比例(如已平 30% 则默认 0.7)。
|
||||
/// 与互换/提前终止 InitIncome 保持一致。抽出为纯函数以支持无库单测。
|
||||
/// 计算 InitUnwind 默认占期初(A)平仓比例 = PosiNotionalValue / NotionalValue。
|
||||
/// </summary>
|
||||
public static decimal CalcDefaultInitClosePercent(decimal notionalValue, decimal posiNotionalValue)
|
||||
{
|
||||
return notionalValue > 0 ? posiNotionalValue / notionalValue : 1;
|
||||
}
|
||||
=> ClosePercentMath.CalcDefaultInitClosePercent(notionalValue, posiNotionalValue);
|
||||
|
||||
/// <summary>
|
||||
/// 读取"上一收盘日"浮动腿的待实现分红(eod_swap_position.PosiDividendSum),
|
||||
|
||||
Reference in New Issue
Block a user