Scaling 2018 2021
ODTS 03 — 规模扩张 2018–2021:前端革命、监管合规与记录系统
业务背景 2018–2021
2018 到 2021 这三年,交易台从一个小众结构化产品精品店 (boutique) 变成了中国 top-3 的 OTC 衍生品做市商 (dealer)。
财务规模的变化:
| 指标 | 2018 | 2021 |
|---|---|---|
| 未到期名义本金 | ~500 亿 RMB | ~3000 亿 RMB |
| 活跃合约数 | ~1,000 | ~5,000 |
| 日均 P&L 波动 | ±1000 万 RMB | ±1 亿 RMB |
| 客户数 | 100 | 300+ |
| 年收入 | ~1 亿 RMB | ~5 亿 RMB |
| 产品类型 | 8 | 15+ |
业务驱动因素有四个:
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 为什么爆发?
- MSCI 纳入 A 股 (2018–2019)——全球被动基金需要 A 股敞口,TRS 是最快的方式
- QFII 额度仍然有限——即使改革后,流程还是慢。TRS 是即时的
- 杠杆——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 衍生品监管大幅增加:
| 年份 | 法规 | 影响 |
|---|---|---|
| 2018 | SAC 1 号——所有 OTC 交易标准化报告 | 每笔交易 T+1 内必须上报 |
| 2019 | 资管新规——限制结构化产品销售 | 雪球对零售客户销售受限 |
| 2020 | SAC 交易对手信用风险 (CVA) | 必须计算对手方风险并分配资本 |
| 2021 | SAC 保证金规则——非清算衍生品初始保证金 (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)。
发生了什么:
- 违约触发了信用风险团队
- 团队平掉了与该对手方的所有头寸,亏损约 2000 万 RMB
- 修订了对手方授信额度 (credit limits)
- 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) | 2014 | Black-Scholes 解析解 |
| 股权互换 (TRS) | 2015 | 公司行为、多资产 |
| 雪球 | 2015 | 路径依赖、蒙特卡洛 |
| NDF | 2016 | 外汇定价、境内外价差 |
| 障碍期权 (Barrier) | 2017 | 敲入/敲出逻辑 |
| 彩虹期权 (Rainbow) | 2018 | 篮子相关性 |
| 方差互换 (Variance Swap) | 2019 | 波动率凸性 |
| TARN | 2019 | 目标赎回 |
| Phoenix | 2020 | 带记忆票息的自动赎回 |
| Daily Accrual | 2020 | 路径依赖的累积利息 |
| Bond TRS | 2021 | 固收进入权益交易台 |
系统适应的方式:
团队建立了 产品库 (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 系统的工作
有些规模扩张的挑战不是代码解决的,是人和流程。
不是软件的部分:
- 每日风险碰头会 (2019)——每天早上 8:30,交易员、风控、运营开 15 分钟会:看 Greeks、最大头寸、待处理保证金追缴、监管截止日期。系统提供数据,但决策是人的
- 交易审批流程 (2020)——在系统有自动化工作流之前,用微信审批:“请批准 TRS 与对手方 X,5000 万名义本金。” 交易员回:“批准。” 截图存合规文件夹
- 手工对账 (2018–2021)——每周五,运营对比系统的头寸报告和对手方的对账单。差异记在 Excel 里。这一直到 2022 年才自动化
最让人清醒的时刻: 2020 年团队建了一个漂亮的自动化保证金追缴系统。第一周跑下来,生成了 20 个错误追缴(因为数据 bug)。交易员退回手工发追缴。自动化系统关了 3 个月。信任很难建立。
崩溃点总结:2018–2021 的三个关键时刻
- 交易对手违约 (2019) → 暴露了信用风险监控的缺失,加了 CVA 模块和对手方敞口计算。业务损失 2000 万
- 前端 JSP 无法维护 → Vue 2 SPA 改造。但是两个团队各建一套,产生了前端重复——这成了 2019–2021 年最大的效率浪费源
- 监管报告潮 (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 微服务、到现在的路线