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

Foundation 2016 2018

OTC 衍生品 · 19 JUL 2026 · 13 min read · 3,168 words
· · ·

ODTS 02 — 奠基 2016–2018:定价引擎与雪球大爆发

业务背景 2016–2017

2016–2017 年是 雪球 (Snowball) 结构化产品的”淘金热”(gold rush)。

到 2016 年,雪球结构化产品是中国财富管理市场最火的东西。几乎所有私人银行、财富管理公司、零售券商都想做。中金的交易台从每月几笔雪球变成了每天 5-10 笔

为什么雪球会爆发? 这不是一个系统故事,这是一个市场故事

  1. 利率在降(2014-2016 年央行多次降息)。理财产品收益率从 4% 降到 3%。投资者需要高收益替代品。
  2. 中证 500 指数在区间震荡(5000–6500 点)。低波动、没暴跌——对雪球卖方来说完美。
  3. 中国零售投资者喜欢保本型产品——雪球被包装成”高收益理财”,有保底机制(一定程度的下跌保护)。
  4. 私人银行搭建了结构化票据 (structured note) 计划——把雪球打包成”增强型存款”(enhanced deposit) 产品。

雪球在业务层面是什么?

投资者说:“给你 15% 年化票息,每个月付,只要中证 500 不跌破期初水平的 75%。如果跌破,我开始亏钱。但如果中证 500 任何一个月涨过 102%,产品提前结束 (early termination),我拿完票息走人。”

银行(交易台)说:“我们通过买入中证 500 期货 (futures) 来对冲 (hedge)。如果市场涨,多余收益归我们。如果市场跌,我们管理头寸来控制损失。”

之所以叫”雪球”(Snowball),是因为:票息会累积 (snowball effect)——如果某个月没触发付息条件(指数跌了),票息会”记住”并在下个月一起付;同时风险也在累积——产品跑得越久,Delta 敞口越大。

商业模式: 银行赚的是支付给客户的票息(比如 15%)和对冲收益 (hedging return) 之间的价差 (spread)。如果市场保持震荡,银行一年能赚名义本金 (notional) 的 3-5%。10 亿 RMB 的雪球组合,年收入就是 3000-5000 万 RMB。听起来很简单?

问题是: 这个商业模式成立,前提是你能准确定价和对冲。如果票息给高了,你亏钱。如果对冲做错了,你爆仓。2017 年,中国没有一家公司有像样的雪球定价引擎 (pricing engine)。所有人都在用 Excel。利润率很高,但没人知道自己真正的风险敞口。

这就是下文的第一个崩溃点:业务规模已经大到 Excel 定价不可持续了。

量化研究员进场

陈博士 2016 年底加入交易台。他的任务:建一个雪球定价引擎,不要在 VBA 里跑 5 分钟

他的方法:

  • 能用解析解 (closed-form solutions) 的地方用解析解(Black-Scholes 对香草期权 (vanilla options) 很快)
  • 障碍期权 (barrier options) 用有限差分法 (finite-difference methods)
  • 复杂产品用蒙特卡洛 (Monte Carlo)——但只在必须的时候(慢)
  • Greeks 用 Bump-and-Reval 方法(暴力但正确)

他设计的定价流水线 (pricing pipeline):市场数据 (Market Data) → 即期价格、波动率、利率、股息率 (Spot, Vol, IR, Div) → 合约参数 (Instrument Parameters) → 收益函数 (Payoff Function) → 估值 (Value) → Greeks

这条流水线到今天仍然在用,基本没变。

构建 hedging-as

定价引擎成为了一个独立项目:

hedging-as/
├── pricing/          — 核心定价逻辑
│   ├── dataCenter/   — 市场数据缓存
│   ├── engine/       — 估值引擎(即期、蒙特卡洛、PDE)
│   └── service/      — 按产品类型的定价服务
├── service/
│   ├── contract/     — 合约领域模型
│   └── eod/          — 日终批处理
└── edslib/
    └── payoff/       — 收益函数库

为什么选 JFinal 而不是 Spring Boot

这是 ODTS 历史上最有争议的技术决策。2016 年 Spring Boot 1.x 已经发布。团队选 JFinal 只有一个原因:陈博士讨厌 XML 配置。2016 年的 Spring 还有 XML bean 配置。JFinal 是”约定优于配置”(convention over configuration),几乎不用 XML。

这个决策后来一直困扰着团队。JFinal 没有 Spring 的生态:没有 AOP、没有依赖注入容器 (DI container)、没有自动配置 (autoconfiguration)。每加一个新服务都要继承一个底层的 Controller 类,手工接线。

业务启示: 开发者的开发体验 (developer experience/DevEx) 对技术选型有很大影响——即使选了”错误”的长期方案。陈博士的原话(2023 年回看):“如果现在让我选,我不会选 JFinal。但 2016 年我是一个量化研究员,不是软件工程师。我只要一个能用的。Spring 的 XML 让我生气。JFinal 不挡我的路。“

三大件拆分

2017 年,AccessApp 已经长成了一个有 100+ JSP 页面的单体应用 (monolith),团队已经无法维护。决策:拆成三个项目。

AccessApp(单体,正在消亡)

    ├──→ eds-web-app (Spring Boot,簿记 + 运营)
    ├──→ hedging-as (JFinal,定价 + 风险)
    └──→ edsWeb (遗留 JSP,给历史页面续命)

为什么拆?

项目用途框架
eds-web-app交易簿记、确认书、客户报告Spring Boot
hedging-as定价、风险、EOD 批处理JFinal(计算密集,需要独立扩缩)
edsWeb没人想重写的遗留页面旧 Spring

集成挑战: 三个项目必须互相通信。eds-web-app 通过 ActiveMQ + Protobuf 调用 hedging-as 定价。eds-web-app 读取 hedging-as 的数据库获取保证金结果。edsWebeds-web-app 共用数据库。这不是干净的微服务 (microservices)——这是一个演进的单体 (evolved monolith),碰巧部署在不同的 JVM 里。

当时的一个真实对话:

开发:“我们之间不加个 REST API?” 架构师:“过度设计了。先共享数据库。” 开发:“耦合问题怎么办?” 架构师:“同一个团队。Schema 变了,两边一起改。”

这个判断在 2017 年是务实的,但后来证明是错的。Schema 耦合在后来的维护中带来了很多痛苦。

雪球定价引擎详解

雪球定价流程(至今仍在用)值得理解,因为它是系统最重要的路径:

  1. 合约在 eds-web-app 创建(用户输入交易细节)
  2. 定价请求通过 ActiveMQ 发送到 hedging-as
  3. hedging-as 读取市场数据(即期价、波动率、利率、股息率)
  4. HedgingAsPricingController 接收请求
  5. 调用 SnowballPayoff.computePayoff()
  6. 估值引擎运行(雪球用蒙特卡洛)
  7. 计算 Greeks(Delta、Gamma、Vega、Theta)
  8. 结果存入 TodayContractRaInfo
  9. 结果返回 eds-web-app
  10. 用户看到按市值计价 (MTM)

蒙特卡洛的痛点: 雪球需要蒙特卡洛模拟,因为路径依赖(敲出事件 (knock-out) 和记忆票息 (memory coupon))。2017 年,单个雪球估值约 2 秒。EOD 批处理要定价 500 个雪球——这就是 1000 秒(17 分钟)。对于隔夜批处理来说可以接受,但对于盘中”试算”定价来说太慢了。

优化: 团队预计算了场景网格 (scenario grid)。不是对每个雪球跑蒙特卡洛,而是对一组参数网格跑一次,然后插值 (interpolate)。盘中定价从 2 秒降到了 50 毫秒。代价:非标准雪球的精度降低。

交易簿记变革 (2017)

hedging-as 是明星项目,但 eds-web-app 是业务真正生活的地方——运营团队整天在里面操作。

它能做好的:

  • 交易簿记表单(有结构的,不是自由输入)
  • 交易列表,带搜索和过滤
  • Excel 导出(用户很喜欢这个)
  • 用户认证与基于角色的权限控制

它做得不好的:

  • UI 还是 JSP + jQuery(维护起来很痛苦)
  • 没有完善的数据校验(可以簿记一笔不一致的交易)
  • 错误消息是 Java 堆栈 (stack trace) 的红色文字
  • 没有撤销或确认(删了就是删了)

但不管怎样——系统能用。交易台一天能簿记 50 笔交易不出错。这是当时的胜利。

NDF 业务

2017 年,交易台开始交易人民币 NDF (Non-Deliverable Forward,无本金交割远期)。业务模式:外国投资者(对冲基金、养老基金)想要人民币敞口 (CNY exposure),但不能进入在岸外汇市场 (onshore FX market)。NDF 给了他们合成人民币敞口(以美元结算 (USD-settled))。

客户的现金流: 先交保证金(约名义本金的 10%),到期时收(即期汇率 - 远期汇率)x 名义本金,美元结算。因为客户实际上不能交割人民币。

NDF 定价的挑战: 人民币 NDF 不在公开交易所交易。定价依赖于中国外汇交易中心 (CFETS) 每天 9:15 发布的中间价 (central parity rate)。

如果错估中间价呢?1% 的误差在 1 亿美元名义本金上 = 100 万美元的 P&L 波动。

系统如何应对: FixingManager.java——每天从外部源获取中间价,存入 FixingData 表。定价时,如果当天的中间价已发布就用已发布的,如果是未来日期就用远期曲线 (forward curve) 推算。

NDF 模块是 2017 年初加进 hedging-as 的。这是团队第一次在定价引擎内部建一个产品模块 (product module),而不是另起一个 Excel。建立了一个可以复用的模式:定义收益函数 → 加定价服务 → 加数据源 → 加 Protobuf 消息 → 加前端 UI。

期权业务的增长

香草期权 (vanilla options) 仍然是基本业务。2017 年,交易台在做:

  • 单只股票期权(港股和中概股 ADR)——给对冲基金客户
  • 指数期权(沪深 300、中证 500、恒指)——给结构化票据发行人
  • 彩虹期权 (Rainbow options)(一篮子股票)——给需要股权挂钩融资的企业客户

香草期权的定价并不难(Black-Scholes 解析解)。真正的挑战不是定价,是库存管理 (inventory management)

比如:如果卖给客户 A 一个 3 个月看涨 (call),同时从客户 B 那里买入一个 6 个月看涨,就产生了一个”期限错配”头寸——空头 3 个月、多头 6 个月。系统需要追踪这个缺口并计算净对冲量。

这个逻辑后来成为 hedging-as 中的 HedgingService.java——告诉交易员”你需要买入/卖出 X 手标的来实现 Delta 中性 (delta-neutral)“。

2018 年:雪球调整(第一次生产危机)

2018 年,A 股市场下跌。中证 500 从 6500 跌到 4500(跌幅 30%)。很多雪球敲入了 (knocked in)——触及了 75% 的障碍价格。

发生了什么:

  1. 一直在付 15% 票息的雪球开始跟着指数亏钱
  2. 买了”保本”产品的投资者现在面临亏损
  3. 交易台必须管理平仓——随着雪球敲出或到期,将对冲头寸平掉

系统的影响: 这是 hedging-as 的第一次生产危机

  • EOD 批处理定价了 800+ 个雪球。蒙特卡洛花了 45 分钟
  • 保证金计算对大实值雪球 (deep ITM Snowballs) 返回了负值——团队忘记处理封顶下跌 (capped downside)
  • “记忆票息”功能对已经交易了 18+ 个月的雪球计算错误

业务代价: 交易员按照系统给的 Greeks 做对冲,三天后发现 Greeks 是错的。一个真实对话:

交易员:“系统说我雪球组合的 Delta 是 -1500 万。我叫 junior 买了 1500 万期货。三天后 Delta 变成了 +2000 万。我们在这个对冲上亏了 300 万人民币。系统的 Greeks 用的是股灾前的隐含波动率 (implied volatility)。”

这个事件导致了一个业务上的改变:交易员可以手动覆盖 (override) 波动率表面 (vol surface),不再完全依赖自动计算。

教训:

  1. 没经历过市场崩盘的定价引擎不可信。Excel 测试覆盖不了边界条件 (edge cases)
  2. 雪球 Greeks 在障碍价格附近变化剧烈。Delta 一天内可以从 0.2 跳变到 0.8
  3. 交易台需要一个风险仪表盘 (risk dashboard) 展示每个雪球到障碍价格的距离

技术债积累 (2018 年底)

到 2018 年底:

指标数据
系统组件3 (eds-web-app, hedging-as, edsWeb)
代码库15+ 个
开发人数8
总代码行数~30 万行
数据库表80+
Protobuf 定义50+
ActiveMQ 队列10+

痛点:

  • 没有测试文化。 几乎没有单元测试 (unit tests)。理由:“我们动得太快了,没时间写测试。”
  • 没有 CI/CD。 部署是手动的:./gradlew build, ssh to server, copy JAR, restart
  • 没有 API 文档。 Protobuf 定义是唯一的”合约”。想知道某个字段什么意思,要去读 .proto 文件
  • 没有监控 (monitoring)。 EOD 批处理凌晨 2 点失败,没人知道,直到第二天早上 9 点才发现
  • 没有回滚方案。 每次部署都是”祈祷式部署”

但业务在增长。收入比 2016 年翻了 3 倍。系统基本能用。

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

  1. 雪球业务爆发但定价还在 Excel → 招了量化研究员,建了独立定价引擎
  2. AccessApp 单体撑不住了 → 三大件拆分,分立了簿记、定价、遗留页面
  3. 2018 年股灾暴露了 Greeks 不准 → 加了波动率手动覆盖,意识到没经过市场考验的系统不可信

每个节点的应对都是”修一个具体问题”而不是”重构系统”。这个模式会在后续年份反复出现。

下一篇:03-Scaling-2018-2021 —— Vue 前端、监管合规、记录系统