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

Scaling 2018 2021

OTC 衍生品 · 19 JUL 2026 · 12 min read · 2,760 words
· · ·

ODTS 03 — 规模扩张 2018–2021:前端革命、监管合规与记录系统

业务背景 2018–2021

2018 到 2021 这三年,交易台从一个小众结构化产品精品店 (boutique) 变成了中国 top-3 的 OTC 衍生品做市商 (dealer)。

财务规模的变化:

指标20182021
未到期名义本金~500 亿 RMB~3000 亿 RMB
活跃合约数~1,000~5,000
日均 P&L 波动±1000 万 RMB±1 亿 RMB
客户数100300+
年收入~1 亿 RMB~5 亿 RMB
产品类型815+

业务驱动因素有四个:

1. 雪球结构化产品爆发 (2019–2020)

中证 500 雪球成了主流产品。到 2020 年,中国所有主要券商都在发雪球。整个市场从 2018 年的 ~500 亿 RMB 涨到了 2020 年的 ~5000 亿 RMB。

中金交易台是市场领头羊,占了约 30% 的份额。原因:资历(2016 年就开始做雪球)和技术(有 hedging-as 定价引擎)。

但市场变了:

  • 利润率压缩——竞争者增多,雪球票息 (coupon) 从 15% → 10% → 7%
  • 产品越来越复杂——“提前终止”(early termination) 计划、“保底票息”(guaranteed coupon) 期权、“触发回扣”(trigger rebates)
  • 零售分销爆发——雪球通过支付宝和微信销售(有限制——雪球是私募产品,不是公募基金)

业务启示: 当市场从寡头竞争变成红海,产品复杂度飙升,系统的适应能力直接决定了你能不能留住利润率。

2. 总收益互换 (TRS) 爆发 (2019–2020)

A 股 TRS (Total Return Swap,总收益互换) 成为外资投资者的主要入口:

外资对冲基金想要 100 只中国股票的敞口。
问题:他们不能直接买每一只(QFII 额度有限)。
方案:和中金签 TRS。
  - 客户交保证金 (margin)
  - 中金买入股票,把总收益 (total return) 转给客户
  - 中金收取融资成本 (funding) + 利差 (spread)

TRS 为什么爆发?

  1. MSCI 纳入 A 股 (2018–2019)——全球被动基金需要 A 股敞口,TRS 是最快的方式
  2. QFII 额度仍然有限——即使改革后,流程还是慢。TRS 是即时的
  3. 杠杆——TRS 给客户 2–3 倍杠杆(只需交 30–50% 保证金)

系统负担: TRS 操作上简单但计算上痛苦——每一只标的股票的公司行为 (corporate action) 都要追踪:分红、拆股、配股、股权登记。如果中金持有 1 亿 RMB 腾讯的 TRS,腾讯发了 1 元每股的分红,系统必须:记录分红、贷记客户 TRS 账户、重算 P&L、生成立结算指令。在 300+ 个 TRS、500+ 只股票的规模下,这是 EOD 批处理每天跑 2+ 小时的任务。

3. 监管浪潮 (2018–2021)

2018–2021 年中国 OTC 衍生品监管大幅增加:

年份法规影响
2018SAC 1 号——所有 OTC 交易标准化报告每笔交易 T+1 内必须上报
2019资管新规——限制结构化产品销售雪球对零售客户销售受限
2020SAC 交易对手信用风险 (CVA)必须计算对手方风险并分配资本
2021SAC 保证金规则——非清算衍生品初始保证金 (IM)必须用 SIMM 或等同方法计算 IM

监管合规的人力投入:

  • 2018: 1 人兼职做 SAC 报告
  • 2020: 3 人全职
  • 2021: 5 人 + 2 个开发人员专职做监管报告

系统变化:

eds-web-app/src/action/sacReport/    — SAC XML 生成(人人恨)
eds-web-app/src/action/cva/          — CVA 计算
hedging-as/src/pricing/margin/       — SIMM 式保证金引擎

最痛苦的是 SAC 报告模块。SAC 每 6 个月改一次 XML schema。每次改都要重写 XSLT 模板。后来团队改为”输出原始数据,让报告团队自己格式化”——这样就解耦了 SAC schema 变更。

4. 交易对手违约事件 (2019)

2019 年,一个中等规模的中国私人银行在雪球交易上违约了。他们买了 5 亿 RMB 名义本金的雪球,付不出保证金追缴 (margin call)。

发生了什么:

  1. 违约触发了信用风险团队
  2. 团队平掉了与该对手方的所有头寸,亏损约 2000 万 RMB
  3. 修订了对手方授信额度 (credit limits)
  4. EOD 批处理现在对每个对手方计算违约风险敞口 (exposure at default)(CVA 模块)

业务教训: 牛市里(2017-2018)所有人看起来都有偿付能力。下跌时才知道谁真有资本。这次违约让信用风险监控 (credit risk surveillance) 成为了系统的硬需求。

前端革命 (2019–2020)

到 2019 年,前端 JSP 是交易台最大的抱怨。页面慢、UI 丑、改一个东西要改 JSP 文件、重启 Tomcat、祈祷别炸。

前端演进:

2015: JSP + jQuery + Bootstrap (AccessApp)
2018: JSP + jQuery + Datatables (eds-web-app 早期)
2019: Vue 2 + Element UI (new-edsweb — "新"前端)
2020: Vue 2 + KoiUI (odts-option-web — 另一个团队的 fork)

为什么选 Vue 而不是 React: 团队已经会 JavaScript(jQuery),Vue 2 比 React 好学(API 更少),Element UI 是最流行的中文组件库。一个开发花了 2 天做了原型给交易台看,交易台说”就这个”。

命名混乱:

new-edsweb/:      eds-web-app 的"新前端"(交易簿记、报告)
odts-option-web/: 期权交易台前端(用的 KoiUI)

两个都是 Vue 2 SPA,都连同一个后端,但是不同 UI、不同构建流程、不同部署脚本。因为它们是不同团队做的(“簿记团队”和”期权团队”),没有协调。

前端改造最大的挑战: 后端 API 不是为前端 SPA 设计的,是为服务端渲染的 JSP 页面设计的。

JSP 模式:页面加载 → 服务端渲染 HTML → 数据内嵌在 HTML 中 SPA 模式:页面加载 → 空白 HTML → AJAX 请求 → JSON → 前端渲染

结果是团队必须新增 REST 端点,老的 JSP Action 还要保留给老旧页面 (edsWeb)。于是有了两套端点

旧: /eds-boot/action/contract/list.do  → JSP 页面
新: /eds-boot/api/v1/contract/list    → JSON REST

双轨维护的痛苦: 每加一个字段,要改 5 个地方:数据库、JSP Action、REST 端点、JSP 页面、Vue 组件。

不是桥接而是扼杀 (strangler fig): 系统没有建新老之间的桥梁,而是让两者并行运行。Strangler Fig 模式——逐步用新功能替代旧功能——但没有一个计划。每个团队成员凭心情选择做哪个前端。到 2021 年,edsWeb 有 10 万行 JSP,new-edsweb 有 8 万行 Vue——两个都活跃,但谁都没完全覆盖对方。

确认书生成器

业务问题: 每笔交易都需要一份法律确认书 (confirmation document)。2018 年全靠手工:运营从系统复制交易详情,粘贴到 Word 模板,邮件发给对手方,对手方签回。

每天 50 笔交易,这就是 2–3 小时的复制粘贴。到 2020 年每天 200 笔,完全不可能。

解决方案: Apache POI + .docx 模板占位符。用户在交易界面点”生成确认书”,系统从数据库加载交易数据,选择对应模板(TRS 模板、期权模板等),替换占位符({{counterparty}}{{notional}} 等),生成 .docx 文件提供下载。

麻烦的地方: 中国监管要求用中文的 ISDA 等同措辞。每次模板变动(法律审核周期 2–4 周),占位符系统都要更新。

到 2020 年,确认书生成器处理了 80% 的交易。剩下 20%(定制产品、非标准条款)仍然需要手工起草。

遗留系统问题

到 2020 年,遗留代码已经积重难返:

遗留项为什么还在为什么杀不掉
edsWeb/ (JSP)原始前端有些页面从未迁移
accessapp-new/原始簿记系统还有人用它查历史数据
jzmq/FIX+ZMQ 集成没人理解完整的集成链路
50+ 个 .proto 文件服务合约改了会破坏兼容性
ActiveMQ异步消息替换它意味着重写所有服务

最痛苦的遗留问题: 两个前端、两套 API、一个后端。

2020 年开发对话: 开发 A:“我刚花了两天在 new-edsweb 上加了一个合同字段。” 开发 B:“用户在期权页面也要加同样的字段——那个在 odts-option-web 里。” 开发 A:“不同项目。不同 API 封装。不同团队。” 开发 B:“所以我得再建一次?” 开发 A:“是的。” 开发 B:“不能共享 Vue 组件吗?” 开发 A:“可以,但没设置共享组件库。” 开发 B:“要多久?” 开发 A:“大概两周。但雪球需求做不完。” 开发 B:”……我还是再做一次吧。”

这种事发生了几十次。前端重复是 2019–2021 年间开发者精力最大的浪费源。

产品多样化

到 2021 年交易台做的产品:

产品起始年核心挑战
香草期权 (Vanilla)2014Black-Scholes 解析解
股权互换 (TRS)2015公司行为、多资产
雪球2015路径依赖、蒙特卡洛
NDF2016外汇定价、境内外价差
障碍期权 (Barrier)2017敲入/敲出逻辑
彩虹期权 (Rainbow)2018篮子相关性
方差互换 (Variance Swap)2019波动率凸性
TARN2019目标赎回
Phoenix2020带记忆票息的自动赎回
Daily Accrual2020路径依赖的累积利息
Bond TRS2021固收进入权益交易台

系统适应的方式:

团队建立了 产品库 (product library) 模式。每个产品是一个 Payoff 模块:

hedging-as/edslib/payoff/
├── PayoffBase.java          — 抽象基类
├── VanillaOptionPayoff.java — Black-Scholes
├── SnowballPayoff.java       — 蒙特卡洛
├── BarrierOptionPayoff.java — 敲入/敲出
├── NDVPayoff.java           — 无交割
├── VarianceSwapPayoff.java   — 已实现方差
├── TARNPayoff.java          — 目标赎回
└── ... (15+ 个 payoff 类)

每个 payoff 类实现相同接口。加一个新产品 = 写一个新 payoff 类。估值引擎、保证金引擎、EOD 批处理不用改。

业务启示: 接口抽象是 ODTS 系统里少有的”一开始就设计对了”的部分。因为定价逻辑天然适合策略模式 (Strategy pattern),所以扩展很容易。真正痛苦的是前端 UI、数据库 schema、以及跨系统的数据流。

人的工作 vs 系统的工作

有些规模扩张的挑战不是代码解决的,是人和流程。

不是软件的部分:

  1. 每日风险碰头会 (2019)——每天早上 8:30,交易员、风控、运营开 15 分钟会:看 Greeks、最大头寸、待处理保证金追缴、监管截止日期。系统提供数据,但决策是人的
  2. 交易审批流程 (2020)——在系统有自动化工作流之前,用微信审批:“请批准 TRS 与对手方 X,5000 万名义本金。” 交易员回:“批准。” 截图存合规文件夹
  3. 手工对账 (2018–2021)——每周五,运营对比系统的头寸报告和对手方的对账单。差异记在 Excel 里。这一直到 2022 年才自动化

最让人清醒的时刻: 2020 年团队建了一个漂亮的自动化保证金追缴系统。第一周跑下来,生成了 20 个错误追缴(因为数据 bug)。交易员退回手工发追缴。自动化系统关了 3 个月。信任很难建立。

崩溃点总结:2018–2021 的三个关键时刻

  1. 交易对手违约 (2019) → 暴露了信用风险监控的缺失,加了 CVA 模块和对手方敞口计算。业务损失 2000 万
  2. 前端 JSP 无法维护 → Vue 2 SPA 改造。但是两个团队各建一套,产生了前端重复——这成了 2019–2021 年最大的效率浪费源
  3. 监管报告潮 (2018–2021) → SAC XML schema 每 6 个月改一次,团队从 1 人兼职变成了 5+2 人全职。系统被迫从”紧耦合 XSLT”转为”输出原始数据”策略

2021 年底的状态

月交易量:        ~500 笔
活跃合约:        ~5,000 笔
EOD 运行时间:    ~90 分钟
前端框架:        3 个 (Vue, KoiUI, JSP)
API 协议:        2 个 (REST, Protobuf/ActiveMQ)
异步消息:        ActiveMQ (~50 万条/天)
地区:            香港、上海
客户:            300+
开发者:          15 人

做得好的: 定价引擎扎实(挺过了股灾)、交易簿记流程快(new-edsweb)、EOD 批处理基本可靠(每月炸 2–3 次)

做得不好的: 两个前端两套 API 严重重复、没有自动化测试(每次部署都紧张)、遗留代码没人敢碰(edsWeb、accessapp-new)、没有像样的 CI/CD(部署还是手工)、系统是”长出来”的不是”设计出来”的

下一篇:04-Modernization-2021-2024.md —— Strangler Fig 迁移、Odyssey 微服务、到现在的路线