Files
zszq-trs/项目文档/互换收益结算审核后状态卡死阻止收盘问题分析.md
hjhan cd03fc53fb 互换两个独立bug分析文档+诊断测试
Bug①利息默认值偏大: 互换结清后eod的InterestProfitSum(待实现)没归零
(=RealizedInterest=77.26), 导致后续平仓默认值=77.26(本该0)+增量→偏大。
6-29收盘后三天对比坐实: 6-30默认83.70, 7-1默认90.14, 均含已实现的77.26。
根因 eod公式cs:829 对互换场景扣减失效(TdInterestIncome≈TdCloseInterest抵消)。

Bug②收益结算审核后状态卡死: ApproveSwapTrade(cs:1525)漏ExerciseDate判断,
到期互换审核后状态退回'确认成交'(CloseMethod默认0≠全部平仓1),
导致EodCheckMaturityTrade一直阻止收盘。引入点083848fb(2025-05-28)。

- 新增利息偏大分析文档(根因/修复方案A扣RealizedInterest/B eod归零)
- 新增审核状态卡死分析文档(根因/修复补ExerciseDate判断)
- 新增SwapPartialUnwindInterestDefaultTest(Step0探查/Step0b诊断/Step0d三天对比)
2026-07-01 09:57:25 +08:00

5.4 KiB
Raw Permalink Blame History

互换收益结算审核后状态卡死、阻止收盘问题分析

本文分析到期互换"收益结算(互换)审核通过后,交易状态不流转,导致收盘到期检查一直阻止"的问题。 成文于 2026-07-01。


一、问题概述

复现场景:一笔互换交易到期日(如 2026-06-29),用户在界面做"收益结算(互换)"并审核通过,但:

  • 交易状态没变成"已到期"或"已平仓",仍是"确认成交"
  • 不管做多少次收益结算+审核,状态依旧不变
  • 收盘报错:[检查当日到期交易]当日到期的场外交易未全部操作完成,请操作完成后再执行收盘操作:收益互换 GLMS-20260427-0001

二、根因:审核路径 ApproveSwapTrade 漏了到期日判断

代码对照(铁证)

免审核路径 SwapIncome(正确,基线就有)SwapDealService.cs:1481-1485

if (td.ExerciseDate <= unwindData.ValueDate)   // 判断到期
{
    td.Notional = 0;
    td.StockEqvNotional = 0;
    td.TradeStatus = "已到期";                  // ✅ 到期 → 已到期
}

审核路径 ApproveSwapTrade(漏了)SwapDealService.cs:1525-1538

if (swapEvent.unwindData.CloseMethod == (int)CloseMethodEnum.全部平仓)
    td.TradeStatus = "已平仓";
else
{
    td.TradeStatus = ConsTrade.确认成交;   // ❌ 到期互换落到这里!没有 ExerciseDate 判断
    td.HasPartialUnWind = 1;
}

ApproveSwapTrade 完全没有 ExerciseDate 到期判断,而互换操作的 CloseMethod 又是默认值 0InitIncome cs:216 从不设它)→ 0 ≠ 全部平仓(1) → 走 else → 状态退回"确认成交"。

为什么互换必然走 else 分支

  • CloseMethodEnumUnknown=0 / 全部平仓=1 / 部分平仓=2
  • 互换初始化 InitIncomecs:216-292从不给 unwindData.CloseMethod 赋值 → 默认 0
  • 只有平仓路径(InitUnwind/InitLongShortUnwind)才设 CloseMethod=全部平仓
  • 0 ≠ 1 → 必走 else → 退回"确认成交"

收盘检查为什么一直阻止

EodCheckMaturityTrade.cs:27-33(到期检查):

var predicate = PredicateBuilder.Create<trade>(t =>
    t.ExerciseDate >= startDate && t.ExerciseDate <= settleDate   // 今日到期
    && t.TradeStatus == ConsTrade.确认成交                        // ★ 状态还是"确认成交"
    && t.SettlementFlag != 1);

判断口径只看 TradeStatusTradeCompleteStatus = { 已到期, 已执行, 已平仓 }ConsTrade.cs:33)。审核后状态停在"确认成交"(不在完成列表里)→ 永远命中 → 永远阻止。


三、关于"提交数量但审核时数量0"

用户还反馈"提交了数量但审核时候数量0"。经查:

  1. InitIncomecs:216-292从没给 unwindData.CloseQty 赋值(对比 InitUnwind cs:90 有赋值)→ CloseQty 默认 0
  2. SaveSwapDealcs:1597)的 item.Quantity = unwindData.CloseQtyeventType == 平仓 条件挡住 → 互换(3)不执行

但这不是核心问题——核心是状态没流转。互换的 Quantity 语义与平仓不同(互换是收益结清,不是按数量平仓),数量为 0 可能是设计如此。状态卡死才是阻止收盘的直接原因。


四、引入时间(git blame

路径 提交 时间 说明
SwapIncome 到期判断(正确) f9d8a256 2024-05-09 山证基线,一直有
ApproveSwapTrade 状态分支(漏判断) 083848fb 2025-05-28 审核流程重构,漏同步 ExerciseDate 判断

083848fb(2025-05-28)重构审核流程时把状态分支改成 CloseMethod==全部平仓 判断,但忘了同步 SwapIncome 里的 ExerciseDate 到期判断


五、涉及文件

文件:行号 问题
SwapDealService.cs:1525-1538ApproveSwapTrade 漏 ExerciseDate 判断,到期互换退回"确认成交"
SwapDealService.cs:1481-1485SwapIncome 正确对照(有到期判断)
SwapDealService.cs:216InitIncome 不设 CloseMethod → 默认 0,必然走 else
EodCheckMaturityTrade.cs:27-33 阻止收盘的检查(只认 TradeStatus
ConsTrade.cs:33 TradeCompleteStatus 定义(确认成交不在内)

六、修复方向(最小改动)

ApproveSwapTradecs:1534-1538)的 else 分支补到期判断,与 SwapIncome 对齐:

else
{
    // 补:到期互换应设为"已到期"(与 SwapIncome cs:1481 对齐)
    if (td.ExerciseDate <= swapEvent.unwindData.ValueDate)
    {
        td.Notional = 0;
        td.StockEqvNotional = 0;
        td.TradeStatus = "已到期";
    }
    else
    {
        td.TradeStatus = ConsTrade.确认成交;
        td.HasPartialUnWind = 1;
    }
}

改后到期互换审核通过 → 状态正确变成"已到期" → 收盘检查通过。


七、团队决策问题

  1. 互换的 CloseMethod 是否应该设值:当前 InitIncome 不设 CloseMethod(默认 0),是否应在互换初始化时根据是否全额结清设为"全部平仓"?这会影响 ApproveSwapTrade 走哪个分支。
  2. 互换 Quantity=0 是否符合预期InitIncome 不设 CloseQty,导致互换 flow_event 的 Quantity=0。需业务确认这是设计意图还是遗漏。
  3. 历史卡住的交易怎么处理GLMS-20260427-0001 等已卡住的交易,是否需要手动改 TradeStatus 为"已到期"才能继续收盘?