更新合约维度追保金额计算逻辑

This commit is contained in:
锦麟 王
2026-08-28 13:31:05 +08:00
parent 821d984ef8
commit 07dd3e8eb5
5 changed files with 58 additions and 18 deletions
@@ -46,12 +46,16 @@ namespace YLErp.Modules.SwapModule.Margin
}
/// <summary>
/// 追保金额(合约维度,MarginWatchRule=0):Max(−(现金结存 + 授信额度 − 已使用授信), 0)。
/// 即需求原文公式 Max((现金结存+授信额度−已使用授信)×−1, 0):账户透支(现金+授信不足)为正=应补足,盈余截断为 0(不展示负数)。
/// 追保金额(合约维度,MarginWatchRule=02026-08-28 新口径):
/// = 当日产生的追加保证金资金记录中"资金来源=现金"的金额合计(入参即该值,见
/// SwapSpanBalanceQueryService.GetTodayCashAdditionalMarginByClients),Max(...,0) 兜底截断。
/// 语义:当日该笔合约产生的现金追保额(不与现金结存轧差、闲置现金不冲抵;授信部分不追);
/// 恒 ≥ 0(只追不退,退还走平仓/出金)。通知书按当日现金追保全额展示,
/// 累计未补足欠款体现在账户余额(现金结存)中,不并入本字段。
/// </summary>
public static double CalcContractDimensionCallMargin(double cashBalance, double totalCredit, double usedCredit)
public static double CalcContractDimensionCallMargin(double todayCashAdditionalMargin)
{
return Math.Max(Math.Round(-(cashBalance + totalCredit - usedCredit), 2, MidpointRounding.AwayFromZero), 0);
return Math.Max(Math.Round(todayCashAdditionalMargin, 2, MidpointRounding.AwayFromZero), 0);
}
/// <summary>
@@ -154,5 +154,34 @@ namespace YLErp.Modules.SwapModule.Margin
return result;
}
/// <summary>
/// 合约维度追保金额输入(2026-08-28 新口径):当日产生的追加保证金资金记录中"资金来源=现金"的金额合计(按客户)。
/// 仅统计 Action=系统操作_追加保证金 且 HappenDate=当日 的现金流水(−Σ(Money),收取为正)——
/// 授信部分只写 client_credit_inout 不产生资金记录(授信不追、现金才追);
/// 腿化改造后现金流水逐日增量(每日新腿一条、HappenDate=结算日,同日重跑先清后建,幂等);
/// 该 Action 仅 EOD 追保会写(手工链路写应付预付金,语义天然隔离);追保回落不返还(无负记录),结果天然 ≥ 0。
/// 注意:EOD 未跑(日间实时)时当日无记录,结果为 0——与通知书口径一致。
/// </summary>
public static Dictionary<int, double> GetTodayCashAdditionalMarginByClients(List<int> clientIds, DateTime valueDate, YLContext db)
{
if (clientIds == null || clientIds.Count == 0)
{
return new Dictionary<int, double>();
}
var dayStart = valueDate.Date;
var dayEnd = dayStart.AddDays(1);
return db.ClientCashInCashOut.AsNoTracking()
.Where(x => clientIds.Contains(x.ClientId ?? 0)
&& x.Action == ClientCashInCashOut._追加保证金
&& x.HappenDate >= dayStart && x.HappenDate < dayEnd
&& x.ValidState != ConsGlobal.InValid
&& (x.State == ClientCashInCashOut. || x.State == ClientCashInCashOut.)
&& x.Money != null)
.GroupBy(x => x.ClientId ?? 0)
.Select(g => new { ClientId = g.Key, Sum = -g.Sum(x => x.Money ?? 0d) })
.ToDictionary(x => x.ClientId, x => x.Sum);
}
}
}