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

Ipmp Money Transfer

OTC 衍生品 · 19 JUL 2026 · 7 min read · 1,237 words
· · ·

ODTS-53: IPMP 资金划拨平台——XML 报文的银行间转账

目标读者:想理解 ODTS 资金如何真实转出、XML 报文结构、失败处理机制的 BA/PM

相关文档:ODTS-14 (结算), ODTS-52 (外部系统可视化), ODTS-43 (通信架构)

为什么 BA/PM 需要理解资金划拨

场外衍生品交易中,所有 P&L 最终要变成资金流动:票息支付、margin call 催缴、到期结算、敲出结算。这些资金通过 IPMP 从交易台的银行账户转到客户账户(或反过来)。IPMP 出问题 = 交易台无法支付 = 违约。

资金划拨失败的真实代价:

  • Margin call 延迟: 如果一笔 IM 催缴的转账因为 XML 报文格式错误被拒,客户当天收不到保证金。第二天市场大幅波动,交易台暴露在无抵押风险中。5000 万名义本金的交易,隔夜波动 3% = 150 万未覆盖风险敞口。
  • 票息支付延迟: 雪球产品的月度票息如果因转账失败延后 1 天支付,根据 SAC 主协议,交易台需要支付违约金(通常按日万分之五计算)。1000 万票息 × 0.05% = 每天 5000 元。金额本身不大,但客户关系受损——客户会质疑交易台的运营能力。
  • 期初结算延迟: 一笔新交易需要客户将初始保证金打入交易台账户。如果 IPMP 转账失败导致期初结算延迟 1 天,交易无法起息 (value date),交易台损失 1 天的对冲收益。对于 1 亿名义本金的雪球,首日 Delta 约 0.3 = 3000 万对冲头寸。3000 万 × 1 天资金成本(年化 2%)= 1644 元。这事不大,但客户和销售都会追问”为什么还没开始?”
  • UNKNOWN 状态——最可怕的情况: IPMP 返回 status=4(不确定),系统不知道银行是否已扣款。运营需要联系银行人工确认。这个过程可能耗时 2-4 小时,甚至跨天。如果这时市场剧烈波动,交易台处于”不知道钱在哪”的状态,风险敞口无法准确衡量。

运营团队专门有 0.5–1 个 FTE 处理转账失败和异常——每天检查失败转账、联系银行、重发、人工对账。

概述

IPMP (Inter-bank Payment Management Platform) 是 ODTS 对接的银行间资金划拨平台。当一笔 CashTransfer 被运营审批通过后,Odyssey cash-manager-service 将转账指令组装为 XML 报文发送至 IPMP,由 IPMP 通过 CNAPS (中国现代化支付系统) 执行实际资金划拨。

转账协议

报文格式

IPMP 使用 XML over HTTP 通信。所有请求和响应包裹在 <ipmp><head>...</head><body>...</body></ipmp> 结构中。

转账指令 (TransMoneyRequest)

<ipmp>
  <head>
    <reference>CT20250716001</reference>     <!-- CashTransfer.id -->
    <busiCode>1001</busiCode>                 <!-- 业务类型: 1001=普通转账 -->
  </head>
  <body>
    <ftOrderNo>CT20250716001</ftOrderNo>      <!-- 转账单号(幂等键) -->
    <urgent>02</urgent>                        <!-- 01=加急, 02=普通 -->
    <settledAmount>
      <date>20250716</date>                    <!-- 结算日期 YYYYMMDD -->
      <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 (XML VO), MoneyTransfer.java (DTO)

转账结果 (TransMoneyResult)

<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>

StatusBody — 状态查询响应

轮询状态时, IPMP 返回 StatusBody:

字段类型说明
requestBusiCodeString请求业务编码
relatedReferenceStringIPMP 流水号
statusint1=处理中, 2=成功, 3=失败, 4=不确定
codeString结果代码 (SUCCESS/FAILED/UNKNOWN)
remarkString备注 (失败时含原因)

转账生命周期

CashTransfer PENDING
    │ 运营审核批准

CashTransfer CONFIRMED


cash-manager-service 组装 XML


POST /ipmp/message (转账指令)
    ├── 成功 → queryReference + instructionStatus=PROCESSING
    └── 失败 → 标记 FAILED, 运营重新审批


轮询状态 (配置: statusPollIntervalSeconds)
    ├── SUCCESS  → CashTransfer SETTLED
    ├── FAILED   → CashTransfer FAILED (人工干预)
    └── UNKNOWN  → 报警, 人工核实


转账完成 → JUMS 通知客户+运营

转账失败模式

失败场景IPMP 返回业务影响
余额不足status=3, remark=“账户余额不足”交易台补充资金后重发。如果当天 16:00 前未能补足,可能构成技术性违约 (technical default)
收款行号错误status=3, remark=“收款行不存在”修正后重发。但资金可能已进入银行处理流程,需向银行追回——平均耗时 1-3 个工作日
金额超限status=3, remark=“大额转账需授权”大额转账(>5000 万)需提前向银行报备,当天处理可能来不及
银行系统异常status=4 (UNKNOWN)运营只能打电话问银行柜员。每个 UNKNOWN 状态平均消耗运营 2 小时,月均 5-10 次 = 每月 10-20 小时浪费。
部分成功successAmount < 总金额, failureAmount > 0运营需决定是否补发差额或等退款重发。决策错误可能重复支付——某交易台曾因 UNKNOWN + 银行重复入账,多付 2000 万,耗时两个月追回

银行编码映射

IPMP 需要银行 SWIFT 代码和 CNAPS 联行号。系统维护两张映射表:

EdsBank — 银行信息

字段说明示例
bankid内部银行 ID1001
bankname银行全称中国工商银行
bankabbr银行缩写ICBC
ipmpbankcodeIPMP 银行编码ICBKCNBJ

EdsCnaps — CNAPS 联行号

字段说明示例
cnapsPrefix联行号前缀10210000
cnapsCode完整联行号102100000004
branchNam支行名称中国工商银行北京市分行营业部
ipmpBankCode对应 IPMP 银行编码ICBKCNBJ

为什么需要两张表: EdsBank 解决”选哪家银行”,EdsCnaps 解决”选哪个支行”。一笔转账需要同时指定银行(通过 SWIFT)和支行(通过 CNAPS)。如果 EdsCnaps 表维护不及时(支行合并、撤销),错误的联行号会导致转账失败——这也是运营团队每季度需要花 2-3 天维护银行信息的业务原因。

关键代码目录

odyssey/cash-manager-service/src/main/java/.../ipmp/
├── money-transfer/
│   ├── TransMoneyRequestMessage.java   ← 转账请求 XML VO
│   ├── TransMoneyResultBody.java       ← 转账结果 XML VO
│   ├── StatusBody.java                 ← 状态查询 XML VO
│   ├── MoneyTransfer.java              ← 转账 DTO
│   └── IPMPClient.java                ← HTTP 客户端封装
├── config/
│   └── IPMPConfig.java                 ← IPMP 连接配置
├── query/
│   └── QueryStatementBody.java         ← 对账单查询 VO
└── polling/
    └── TransferStatusPoller.java        ← 转账状态轮询