Learning
VOL. VII · NO. 63 · OTC Derivatives · 19 JUL 2026

Settlement And Cash Movement

OTC 衍生品 · 19 JUL 2026 · 14 min read · 2,059 words
· · ·

ODTS 14 — 结算和资金流转:钱实际怎么流动

业务问题

交易簿记了。定价引擎估值了。但这两件事一分钱也没有动。结算是钱实际易手的地方。

簿记 → 估值 → 保证金计算 → 资金流转 (CASH MOVEMENT) → 结算

                          真正的 P&L 发生在这里

如果交割指令 (settlement instruction) 错了:

  • 客户收到错误的金额
  • 交易台必须手动纠正(冲账)
  • 如果错误被晚发现,交易台可能要承担利息

一笔交易产生哪些资金流转

1. 权利金 (Premium)——期权

时间:T+1 或 T+2
内容:客户付权利金给交易台(或反向)
金额:期权权利金 × 乘数
系统:产生一条资金划转指令

2. 融资付款 (Funding Payments)——TRS

时间:每个定盘周期(月/季度)
内容:客户付融资款 = (SHIBOR + spread) × 名义本金 × 天数/365
金额:可变,取决于 SHIBOR
系统:ContractHelper 计算,产生资金指令

3. 分红支付 (Dividend Payments)——TRS

时间:标的股票的除息日
内容:交易台将收到的分红付给 TRS 客户
金额:每股分红 × 股数
系统:ContractDividendHelper 计算

4. 盯市追保 (MTM Margin Calls)

时间:每日(如 CSA 要求)
内容:如果头寸向不利方向变动,交易台向客户追保
金额:自上次追保以来的 MTM 变动
系统:hedging-as 保证金引擎计算

5. 到期结算 (Settlement)

时间:到期日或终止日
内容:交易的最后现金结算
金额:最终 MTM 价值
系统:计算后加入批量结算

系统如何处理资金流转

资金划转模块

~/odts1/eds-web-app/src/com/cicc/edsBoot/cash/
├── CashTransferController.java          — REST API
├── CashTransferService.java             — 业务逻辑
├── CashTransferGenerator.java           — 指令生成
└── CashTransferDao.java                 — 数据库访问

资金划转表:

CashTransfer {
  id:             CT20250716001
  contractId:     SNOWBALL202507001
  direction:      PAY / RECEIVE
  counterparty:   CLT0001
  amount:         1,230,456.78
  currency:       RMB
  reason:         FUNDING_PAYMENT / PREMIUM / MARGIN / DIVIDEND / SETTLEMENT
  status:         PENDING / CONFIRMED / SETTLED / FAILED
  settlementDate: 2025-08-16
  instructionRef: "CMS-20250816-001"    (清算系统引用)
}

资金流转工作流

T-1 日:系统计算资金流转
  → CashTransferGenerator.createInstructions()
  → 在 CashTransfer 表中创建条目,状态 = PENDING

T 日:运营审核
  → 用户在 new-edsweb 中打开资金划转页面
  → 审核所有待处理指令
  → 批准/拒绝每一条
  → 批准后的指令状态 = CONFIRMED

T+1 日:结算 — IPMP 转账
  → Odyssey cash-manager-service 将 CONFIRMED 指令组装成 XML 报文
  → 通过 IPMP 平台发起银行间转账
  → 轮询转账状态直至完成
  → 结算成功:状态 = SETTLED
  → 结算失败:状态 = FAILED(需要人工干预)

为什么运营人工审核: 系统没有 100% 的准确率。边缘情况(公司行为、到期交易、提前终止)仍然会产生错误金额。运营在钱实际转出前进行拦截。

运营审核的实际工作负荷:一个活跃的中型交易台每天产生 20–50 条资金指令。每条指令运营需要检查:收款方是否正确、金额是否合理、结算日期是否匹配合同。每条约 2–5 分钟。每天就是 40–250 分钟——1–4 小时。在交易量高峰期(如月末、季末结算日),指令数可以翻倍到 80–100 条,运营审核变成专职工作。这就是为什么每个交易台至少需要 1 个运营人员全职处理结算——不是因为他们技术含量高,而是因为每笔钱都需要人眼确认后才能转出。

实际转账系统:IPMP(资金划拨平台)

IPMP 是 ODTS 对接的银行间资金划拨平台,负责将运营确认的资金指令实际发送到银行执行。ODTS 通过 Odyssey cash-manager-service 与 IPMP 交互,协议为 XML over HTTP

转账指令报文结构

<ipmp>
  <head>
    <reference>CT20250716001</reference>   <!-- 流水号,对应 CashTransfer.id -->
    <busiCode>1001</busiCode>               <!-- 业务类型编码 -->
  </head>
  <body>
    <ftOrderNo>CT20250716001</ftOrderNo>    <!-- 转账单号 -->
    <urgent>02</urgent>                      <!-- 02=普通,01=加急 -->
    <settledAmount>
      <date>20250716</date>                  <!-- 结算日期 -->
      <currency>CNY</currency>               <!-- 币种 -->
      <amount>1230456.78</amount>            <!-- 金额 -->
    </settledAmount>
    <orderingCustomer>
      <account>3100xxxxxx</account>          <!-- 付款方账号(交易台) -->
      <bankCode>ICBKCNBJ</bankCode>          <!-- 付款方银行 SWIFT -->
      <name>中金公司</name>
      <publicBankCode>102100000004</publicBankCode>  <!-- 付款行联行号 -->
    </orderingCustomer>
    <beneficiaryCustomer>
      <account>6200xxxxxx</account>          <!-- 收款方账号(客户) -->
      <bankCode>COMMCNSH</bankCode>          <!-- 收款方银行 SWIFT -->
      <name>某某投资有限公司</name>
      <publicBankCode></publicBankCode>       <!-- 收款行联行号(可选) -->
    </beneficiaryCustomer>
    <summary>期权权利金-SNOWBALL202507001</summary>  <!-- 摘要 -->
  </body>
</ipmp>

数据来源:TransMoneyRequestMessage.java (VO),MoneyTransfer.java (DTO)

响应报文

<ipmp>
  <head>
    <reference>CT20250716001</reference>
    <busiCode>1001</busiCode>
  </head>
  <body>
    <relatedReference>IPMP2025071600001</relatedReference>  <!-- IPMP 流水号 -->
    <queryReference>QR2025071600001</queryReference>        <!-- 查詢引用号 -->
    <ftOrderNo>CT20250716001</ftOrderNo>
    <instructionStatus>PROCESSING</instructionStatus>       <!-- 初始状态 -->
    <successAmount>0</successAmount>
    <failureAmount>0</failureAmount>
    <unknownAmount>0</unknownAmount>
  </body>
</ipmp>

转账轮询机制

IPMP 转账是异步的——提交指令后系统返回一个 queryReference,Odyssey cash-manager-service 通过轮询获取最终结果:

1. 提交: POST /ipmp/message (XML)
   → 返回: relatedReference + queryReference + instructionStatus=PROCESSING

2. 轮询: 每隔 N 秒查询状态 (config: statusPollIntervalSeconds)
   → 查询参数: bankCode + queryReference
   → 返回: StatusBody { requestBusiCode, relatedReference, status, code, remark }

3. 最终状态:
   → SUCCESS: successAmount = 总金额, successTime = 完成时间
   → FAILED:  failureAmount = 失败金额, remark = 原因
   → UNKNOWN: 不确定(需要人工核实)

转账失败处理

IPMP 转账可能部分成功(部分金额成功、部分失败)。响应中的 successAmount / failureAmount / unknownAmount 三个字段分别记录三种状态的金额。运营需要根据 remark 判断原因并决定是否重新发起。

IPMP 转账超时事故: 某次市场剧烈波动日,IPMP 平台因银行端交易量激增导致转账处理时间从通常的 30 秒飙升到 10+ 分钟。Odyssey 的轮询机制在默认超时设置下反复重试,产生了同一个转账请求被提交多次的 “重复转账”风险。运营在 2 小时内手动处理了 40+ 条转账状态不确定性案例,其中 3 条因重复提交导致实际转出金额翻倍。多转的资金花了 3 个工作日才追回。事后增加了幂等性检查——IPMP 端使用 reference 字段去重,Odyssey 端将超时从 30 秒延长到 120 秒。

银行信息映射

系统维护两张银行信息表,用于将内部银行代码映射到 IPMP 的银行编码:

  • EdsBank: bankid (内部ID) → bankname (名称) → bankabbr (缩写) → ipmpbankcode (IPMP编码)
  • EdsCnaps: cnapsPrefixcnapsCode (CNAPS号) → branchNam (支行名) → bankNam (总行名) → ipmpBankCode

这两张表解决了”交易员选银行→系统找到对应 IPMP 银行编码”的映射问题。

通知系统:JUMS(邮件/SMS 通知)

资金划转完成后,Odyssey cash-manager-service 通过 JUMS 发送通知给相关方。JUMS 是一个模板化的通知服务,支持邮件和短信两种渠道。

模板邮件通知

JUMS 使用预定义的模板发送邮件,通过 template_id 指定模板,template_para 传递填充参数:

{
  "aud_email": [{
    "instance": "email",
    "group": { "to": ["client@example.com", "ops@cicc.com"] }
  }],
  "template_id": 1001,
  "template_para": {
    "clientName": "某某投资有限公司",
    "amount": "1,230,456.78",
    "currency": "CNY",
    "settlementDate": "2025-07-16",
    "tradeRef": "SNOWBALL202507001"
  }
}

邮件+SMS 组合通知

对于需要即时触达的场景(如 Margin Call),JUMS 支持同时发送邮件和短信:

{
  "aud_email": [{ "instance": "email", "data": ["ops@cicc.com"] }],
  "aud_sms":  [{ "instance": "sms",  "data": ["13800138000"] }],
  "msg_email": [{ "subject": "Margin Call 通知", "text": "..." }],
  "msg_sms":  [{ "content": "您的账户需要追加保证金..." }]
}

JUMS 配置

JUMS 通过 Spring Boot application.yml 配置:

jums:
  url: https://jums.internal.cicc.com/api
  channelKey: odts-cash-channel
  masterSecret: ****
  templateUrl: https://jums.internal.cicc.com/templates
  templateId: 1001

数据来源:JUMSConfig.java, EmailTemplateNotice.java, EmailSmsNotice.java

结算日历

交易在特定日期结算。系统必须知道结算日历:

日历:香港、上海、伦敦、纽约
  — 如果结算日落在假日 → 顺延到下一个工作日
  — 不同币种在不同日历上结算
  — 人民币在上海日历上结算
  — 美元在纽约日历上结算
  
  一笔跨币种交易 (USD/CNY) 按以下方式结算:
    USD leg:纽约日历
    CNY leg:上海日历
    
  如果 NY 关闭但上海开放:USD leg 延迟,CNY leg 正常

结算批处理 (Settle Batch)

结算批处理每天在 EOD 批处理后运行:

1. ComputeSettle:        找出所有今天结算的交易
2. GenerateInstructions: 生成付款指令
3. Match:                与客户的交割指令交叉核对
4. Report:               生成结算报告 (Excel) 给运营

代码:

~/odts1/eds-web-app/src/com/cicc/edsBoot/settle/
├── SettleBatchService.java            — 批处理编排
├── SettleInstructionGenerator.java    — 生成付款指令
├── SettleMatcher.java                 — 指令与客户主数据匹配
└── SettleReportGenerator.java         — Excel 报告

什么会出错

1. 交割指令不匹配

问题:客户换了银行账户但运营没有更新系统
结果:钱发到了旧账户 → 被退回 → 延迟 1–3 天
修复:人工干预,检查客户主数据

2. 周末/假日时间问题

问题:结算日落在周日
结果:系统生成周五(如果 T+2)或周一(如果 T+1)的指令
  — 但天数计算用了 365 天,而不是实际日历天数
  — 产生微小金额差异
修复:日历感知的结算日期计算

3. 支付失败

问题:客户银行拒收付款(余额不足、合规拦截)
结果:CashTransfer 状态 = FAILED
  — 交易台必须通过替代方式收款
  — 如果超过 N 天仍未支付,构成违约事件
修复:运营联系客户的资金部门

4. 公司行为结算

问题:TRS 标的股票在结算日发放分红
结果:分红现金流和结算现金流交叉
  — 交易台在一个 leg 上向客户支付分红
  — 交易台在另一个 leg 上接收交易结算款
  — 净额结算应该合并它们,但系统不跨 leg 轧差
  — 客户收到两笔资金流转而不是一笔轧后金额
修复:系统不做净额结算(已知限制)。运营手动调整。

结算错误的累积成本: 以上四种错误场景出现的频率——交割指令不匹配约每月 1–2 次、时间问题每季度 1 次、支付失败每月 2–3 次(大部分当天解决)、公司行为结算每月 1–2 次(看分红/拆股频率)。大部分错误在当天被运营发现并修复,但剩下 5–10% 的错误需要 2–5 个工作日来解决。这些”遗留错误”每年 10–20 次,平均每次造成 2–5 人时的对账工作量。以一个错误涉及运营、销售、客户的 3 方沟通,每次沟通 30 分钟计算,每年结算排错的总时间是 100–200 人时——约 0.5–1 人月。

“未对账”问题

所有结算完成后,交易台的现金余额应该与银行对账单一致。实际上:

系统显示:现金余额 = 150,234,567 RMB
银行显示:现金余额 = 150,234,567 RMB ←(很少见)

更常见:
系统显示:现金余额 = 150,234,567 RMB
银行显示:现金余额 = 149,800,000 RMB
差异:     434,567 RMB(未对账)

为什么有差异?
  - 某条结算指令延迟了 1 天
  - 扣了一笔手续费(银行手续费、清算费)
  - 收到了一笔分红但尚未记录
  - 外汇兑换的汇率与预期不同

对账 (Reconciliation) 由运营每周进行一次。他们将系统资金流转与银行对账单对比。任何超过 1 万 RMB 的差异都需要调查。

交易台说: “对账很无聊但必不可少。第 1 天发现 10 万的差异很容易修复。同样的差异 6 个月后才发现,要花 2 周来追查。”

对账的实际人力成本: 一个运营人员每周花半天到一天做对账。对于一个有 50+ 存续合约、20+ 客户的交易台,每月的资金流转条数约 300–600 条。运营需要对每条流转确认银行端是否已处理。每月对账时间约 2–4 天。每年的对账人力投入约 1–2 人月。这笔成本是固定的——不管市场好不好、交易量涨不涨,对账都得做。这也意味着当交易量翻倍时,对账工作量并不是翻倍——资金流转条数增加但银行对账单条目不线性增长。系统缺少的是自动对账功能:将 CashTransfer 表的记录与银行端下发的电子对账单自动匹配。

已知局限

问题现状影响
转账无净额结算每条 CashTransfer 独立提交 IPMP客户一天内收到多笔转账而非一笔轧后金额
JUMS 通知不可靠通知发送后无回执确认运营不知道客户是否收到 Margin Call 通知
状态轮询延迟IPMP 转账结果通过固定间隔轮询获取从提交到确认最长可能延迟数分钟
银行信息手工维护EdsBank/CNAPS 映射表手动更新新银行接入慢,可能使用了错误的联行号
无自动对账运营每周手动核对银行对账单差异发现晚,追回困难

这意味着什么: 结算 bug 会让交易台亏钱——如果你发错了金额,交易台先垫付差额再向客户追偿。把结算做对比你想象的重要。1bp 的定价错误是零头。10 万 RMB 的结算错误就是实打实的 10 万 RMB。

真实结算损失案例——重复支付: 某次到期结算,系统在 T 日生成了 Snowball 产品的到期返款指令。运营审核后提交 IPMP。由于 IPMP 响应延迟,系统认为提交失败并重新生成了同一笔指令。运营看到两条”待审核”指令,以为是两笔不同的结算(到期本金 + 最后一次票息),都批准了。结果是本金被支付了两次。客户收到双倍金额后没有主动退回——直到 3 天后对账时发现银行余额与系统记录差了 2000 万。交易台联系客户,客户表示”需要内部审计确认才能退款”,又拖了 5 个工作日。这 2000 万在 8 天里处于”已付但未确认”状态——如果客户在这期间违约,交易台就是一笔坏账。事后修复是增加了重复指令检测逻辑:相同的 contractId + reason + amount 在 24 小时内只能创建一条。