修复追保金额计算逻辑
This commit is contained in:
@@ -110,7 +110,7 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 合约维度追保金额(需求原文 现金+授信−已使用 的应追加方向取值):账户透支为正=应补足,盈余为负。
|
||||
/// 合约维度追保金额(Max((现金+授信−已使用)×−1, 0)):账户透支为正=应补足,盈余截断为 0。
|
||||
/// </summary>
|
||||
[TestMethod]
|
||||
public void SB_013_合约维度追保金额_透支为正()
|
||||
@@ -121,10 +121,10 @@ namespace YLErp.Modules.SwapModule
|
||||
}
|
||||
|
||||
[TestMethod]
|
||||
public void SB_014_合约维度追保金额_盈余为负()
|
||||
public void SB_014_合约维度追保金额_盈余截断为0()
|
||||
{
|
||||
//现金50 + 授信100 − 已使用20 = 130 → 追保 = −130(盈余可返还方向)
|
||||
Assert.AreEqual(-130, SwapSpanBalanceCalc.CalcContractDimensionCallMargin(
|
||||
//现金50 + 授信100 − 已使用20 = 130 → 盈余,Max(...,0) 截断 → 追保 = 0
|
||||
Assert.AreEqual(0, SwapSpanBalanceCalc.CalcContractDimensionCallMargin(
|
||||
cashBalance: 50, totalCredit: 100, usedCredit: 20), 1e-6);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using DocumentFormat.OpenXml.Bibliography;
|
||||
using DocumentFormat.OpenXml.Spreadsheet;
|
||||
using MathNet.Numerics;
|
||||
@@ -392,7 +392,7 @@ namespace YLErp.BLL.EodSettlement
|
||||
}
|
||||
// 是否追保/追保金额(阶段四 §4.2 按维度分流,允许负值=双向,不以 0 截断):
|
||||
// 客户维度(==1)= (维持−初始) − (现金+授信−已使用),负=可返还;
|
||||
// 合约维度(==0)= −(现金+授信−已使用)(需求原文公式的应追加方向取值,开放问题2,两值均有产出);
|
||||
// 合约维度(==0)= Max(−(现金+授信−已使用), 0)(需求原文公式,盈余截断为 0);
|
||||
// 未配置(NULL 存量)维持旧口径:盯市低于维持时 = 初始保证金金额−盯市金额,否则 0
|
||||
if (client?.MarginWatchRule == 1)
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BaseOUDAL;
|
||||
using BaseOUDAL;
|
||||
using Confluent.Kafka;
|
||||
using DocumentFormat.OpenXml.Drawing.Charts;
|
||||
using DocumentFormat.OpenXml.Office2010.Excel;
|
||||
@@ -300,9 +300,9 @@ namespace YLErp.BLL.Eod
|
||||
{
|
||||
item.AvailableAmount = item.MarginBalance - item.FrozenMarginMoney;
|
||||
}
|
||||
// 是否追保/追保金额(阶段四 §4.2 按维度分流,与 ClientBalanceUtility 报告口径一致):
|
||||
// 是否追保/追保金额(按维度分流,与 ClientBalanceUtility 报告口径一致):
|
||||
// 客户维度(==1)双向追保 = (维持−初始) − (现金+授信−已使用),允许负值(负=可返还);
|
||||
// 合约维度(==0)= −(现金+授信−已使用);NULL 存量维持旧口径
|
||||
// 合约维度(==0)= Max(−(现金+授信−已使用), 0),盈余截断为 0;NULL 存量维持旧口径
|
||||
if (ruleClient?.MarginWatchRule == 1)
|
||||
{
|
||||
item.MarginByPayableMarginTotal = SwapSpanBalanceCalc.CalcClientDimensionCallMargin(
|
||||
|
||||
@@ -46,13 +46,12 @@ namespace YLErp.Modules.SwapModule.Margin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 追保金额(合约维度,MarginWatchRule=0,阶段四 §4.2):−(现金结存 + 授信额度 − 已使用授信)。
|
||||
/// 需求原文公式为 现金结存+授信额度−已使用授信(与"交易维度追加保证金"的关系为开放问题2,两值均有产出),
|
||||
/// 此处取负对齐字段"正数=应追加"口径:账户透支(现金+授信不足)为正=应补足,盈余为负。
|
||||
/// 追保金额(合约维度,MarginWatchRule=0):Max(−(现金结存 + 授信额度 − 已使用授信), 0)。
|
||||
/// 即需求原文公式 Max((现金结存+授信额度−已使用授信)×−1, 0):账户透支(现金+授信不足)为正=应补足,盈余截断为 0(不展示负数)。
|
||||
/// </summary>
|
||||
public static double CalcContractDimensionCallMargin(double cashBalance, double totalCredit, double usedCredit)
|
||||
{
|
||||
return Math.Round(-(cashBalance + totalCredit - usedCredit), 2, MidpointRounding.AwayFromZero);
|
||||
return Math.Max(Math.Round(-(cashBalance + totalCredit - usedCredit), 2, MidpointRounding.AwayFromZero), 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace YLErp.Modules.SwapModule.Margin
|
||||
/// - 互换初始保证金(净收取为正)= 客户 应付预付金 流水收付净额取反(客户应付入金记负、平仓返还为正,取负号后净收取为正);
|
||||
/// - 交易维度追加保证金(合约维度)= Σ(维持保证金 − 累计保证金):
|
||||
/// 维持保证金取当日 trade_span.Spv(区间追保结构引擎产出,我方净收取为正);
|
||||
/// 累计保证金 = 该交易 应付预付金+追加保证金 流水收付净额 + 追加保证金授信占用净额(§0 口径,阶段四 §4.1 起);
|
||||
/// 累计保证金 = 该交易 应付预付金+追加保证金 流水收付净额 + 追加保证金授信占用净额(§0 口径,阶段四 §4.1 起)
|
||||
/// + 初始预付金授信占用净额(非"追加保证金"前缀,授信垫付的初始预付金无现金流水,2026-08-27 与 EOD 追保侧同步修正);
|
||||
/// 仅统计规则15(区间追保结构,R1 三层级解析,与引擎同口径)且有当日 trade_span 的交易。
|
||||
/// </summary>
|
||||
public static class SwapSpanBalanceQueryService
|
||||
@@ -101,11 +102,22 @@ namespace YLErp.Modules.SwapModule.Margin
|
||||
.Select(g => new { TradeId = g.Key ?? 0, Sum = g.Sum(x => x.amount) })
|
||||
.ToDictionary(x => x.TradeId, x => x.Sum);
|
||||
|
||||
//初始预付金的授信占用净额(非"追加保证金"前缀:簿记初始占用 + 平仓释放取负,Σ(amount) 即净已缴)——
|
||||
//授信垫付的初始预付金不产生应付预付金流水,不计入会把授信初始占用当作未缴缺口多扣可用资金
|
||||
//(与 SwapAdditionalMarginService EOD 追保侧同笔修正,2026-08-27 交易2538实证:初始授信200万未扣)
|
||||
var initCreditOccupied = db.client_credit_inout.AsNoTracking()
|
||||
.Where(x => x.trade_id != null && spanTradeIds.Contains(x.trade_id ?? 0)
|
||||
&& (x.remark == null || !x.remark.StartsWith(ClientCreditInoutService.AdditionalMarginRemark)))
|
||||
.GroupBy(x => x.trade_id)
|
||||
.Select(g => new { TradeId = g.Key ?? 0, Sum = g.Sum(x => x.amount) })
|
||||
.ToDictionary(x => x.TradeId, x => x.Sum);
|
||||
|
||||
foreach (var group in maintenance.GroupBy(x => x.ClientId ?? 0))
|
||||
{
|
||||
var total = group.Sum(x => x.Spv
|
||||
- (accumulated.TryGetValue(x.TradeId, out var acc) ? acc : 0d)
|
||||
- (addCreditOccupied.TryGetValue(x.TradeId, out var occupied) ? occupied : 0d));
|
||||
- (addCreditOccupied.TryGetValue(x.TradeId, out var occupied) ? occupied : 0d)
|
||||
- (initCreditOccupied.TryGetValue(x.TradeId, out var initOccupied) ? initOccupied : 0d));
|
||||
result[group.Key] = total;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user