feat:在平仓时增加风控校验,创建通用超时教研函数,以备交易确认老风控下线后接入。

This commit is contained in:
ruisu
2026-08-06 16:00:25 +08:00
parent cfd5efd3d3
commit 8d58ef15e8
8 changed files with 561 additions and 31 deletions
+61 -2
View File
@@ -8,6 +8,7 @@ using YLErp.DBModels.Enums;
using YLErp.Helpers;
using YLErp.Modules.DataProviderModule;
using YLErp.Modules.EodModule;
using YLErp.Modules.RiskEngine;
using YLErp.Modules.TradeModule;
using YLErp.Modules.TradeModule.DealModule;
using YLErp.QdpModule;
@@ -1257,14 +1258,27 @@ namespace YLErp.Modules.SwapModule
/// 单标的平仓
/// </summary>
/// <param name="unwindData"></param>
/// <param name="confirmation">新风控二次确认信息;首次提交传空。</param>
/// <returns>本次平仓的新风控试算结果。</returns>
/// <exception cref="ServiceException"></exception>
public void SwapUnwind(UnwindData unwindData)
public RiskTrialResult SwapUnwind(UnwindData unwindData, RiskTrialConfirmation confirmation = null)
{
if (unwindData == null)
{
throw new ServiceException("平仓信息不能为空");
}
var td = FindTrade(unwindData.SwapTradeId);
if (td == null)
{
throw new ServiceException("未找到交易信息");
}
// 直接平仓不经过审核提交入口,落库前仍需执行平仓阶段的新风控,避免绕过 CLOSE_REVIEW 规则。
var riskTrialResult = CheckCloseRisk(unwindData, confirmation);
if (!riskTrialResult.Passed)
{
return riskTrialResult;
}
//CheckLastEod(unwindData.ValueDate, td.StartDate.Value, unwindData.SwapTradeId); //去掉平仓收盘限制
ValidateFrontendPnL(unwindData, isIncome: false); // 只读校验告警,不阻断交易
// 前端按"占期初(original)"语义传 ClosePercent(A);后端全链路按"占剩余(remaining)"语义(B)消费。
@@ -1304,6 +1318,7 @@ namespace YLErp.Modules.SwapModule
{
TriggerRealtimeSwapPosition();
}
return riskTrialResult;
}
/// <summary>
/// 自动全平仓
@@ -1824,19 +1839,36 @@ namespace YLErp.Modules.SwapModule
/// </summary>
/// <param name="unwindData"></param>
/// <param name="eventType"></param>
/// <param name="confirmation">新风控二次确认信息;首次提交传空。</param>
/// <returns>平仓事件返回新风控试算结果,互换事件返回空。</returns>
/// <exception cref="ServiceException"></exception>
public void ApplySwapTrade(UnwindData unwindData, int eventType)
public RiskTrialResult ApplySwapTrade(UnwindData unwindData, int eventType, RiskTrialConfirmation confirmation = null)
{
if (unwindData == null)
{
throw new ServiceException("互换或平仓信息不能为空");
}
var td = FindTrade(unwindData.SwapTradeId);
if (td == null)
{
throw new ServiceException("未找到交易信息");
}
RiskTrialResult riskTrialResult = null;
if (eventType == (int)SwapEventTypeEnum.)
{
NormalizeIncomeUnwindDate(unwindData);
ValidateIncomeValueDate(unwindData, td);
}
else if (eventType == (int)SwapEventTypeEnum.)
{
// 审核提交保存待审核事件前执行平仓阶段的新风控,需确认时先返回前端,不创建待审核事件。
riskTrialResult = CheckCloseRisk(unwindData, confirmation);
if (!riskTrialResult.Passed)
{
return riskTrialResult;
}
}
unwindData.SwapRealizedPnL = unwindData.SwapCloseAmount;
// 前端按"占期初(original)"语义传 ClosePercent(A);后端全链路按"占剩余(remaining)"语义(B)消费。
// 入口统一转换为 B,落库展示用的 A 由 SaveSwapDealInternal 还原。
@@ -1863,7 +1895,34 @@ namespace YLErp.Modules.SwapModule
});
}
});
return riskTrialResult;
}
/// <summary>
/// 执行互换交易平仓审核时点的新风控试算。
/// </summary>
/// <param name="unwindData">包含本次平仓日期和交易ID的平仓请求。</param>
/// <param name="confirmation">新风控二次确认信息;首次提交传空。</param>
/// <returns>包含阻断、审批、提示及试算记录ID的新风控结果。</returns>
/// <exception cref="ServiceException">平仓请求为空。</exception>
private RiskTrialResult CheckCloseRisk(UnwindData unwindData, RiskTrialConfirmation confirmation)
{
if (unwindData == null)
{
throw new ServiceException("平仓信息不能为空");
}
const string triggerPoint = "CLOSE_REVIEW";
const int closeTrialSource = 2;
var riskContext = new RiskContext
{
TradeId = unwindData.SwapTradeId,
TriggerPoint = triggerPoint,
UnwindDate = unwindData.UnwindDate
};
return new RiskTrialService(this).CheckRisk(riskContext, closeTrialSource, confirmation);
}
private void ValidateIncomeValueDate(UnwindData unwindData, trade td)
{
var maxIncomeValueDate = GetMaxIncomeValueDate(td).Date;