Business Concepts
ODTS 07 — 业务概念:每个产品到底是什么
为什么需要这篇文档
你知道 Java、Spring Boot,但不知道 TRS 是什么,雪球为什么敲出 (knock out),NDF 怎么结算。这篇文档填补这个空白。
阅读方式: 每个产品先读”业务”部分——它在现实世界中是什么。再读”在 ODTS 中”——系统怎么建模。然后看代码。
1. TRS — 总收益互换 (Total Return Swap)
业务是什么
总收益互换 (TRS) 是两方交换一项资产全部经济表现的合约:
- A 方(总收益接收方) 获得拥有资产的全部经济利益——价格增值 + 分红——但实际上没有持有该资产
- B 方(总收益支付方) 支付这些收益给 A 方,反过来收取融资付款(通常是 SHIBOR/TONA + 利差)
为什么用 TRS?
| 原因 | 谁 | 例子 |
|---|---|---|
| 合成所有权 | 不能实际持有中国 A 股的外资基金 | 对冲基金用 TRS 获取中证 500 敞口,不用开 QFII 账户 |
| 杠杆 | 想要 2–5 倍敞口但不全额出资的客户 | 1000 万名义本金,200 万保证金 = 5 倍杠杆 |
| 资产负债表管理 | 想释放资本的券商 | 通过 TRS 将资产移到表外 |
| 税务/监管套利 | 避免预扣税或持股限制的外资 | 港股 TRS vs 实体 ADR |
现实中的运作:
客户做 6 个月 TRS,标的贵州茅台(600519.SH)100 万股,100 元/股:
- 名义本金:1 亿 RMB
- 融资利率:SHIBOR 3M + 100bp
- 初始保证金:10%(1000 万 RMB)
- 茅台涨到 120 元:客户收到 2000 万 RMB(价差)+ 分红
- 茅台跌到 80 元:客户支付 2000 万 RMB
- 每月:客户付 (SHIBOR + 1%) / 12 × 1 亿的利息
在 ODTS 中
合约结构:
CtrContract {
productType = "TRS"
Leg 1 (价格回报 Leg): type = RETURN_SWAP, 收/付 = DESK→CLIENT, 标的=600519.SH
Leg 2 (融资 Leg): type = INTEREST_SWAP, 收/付 = CLIENT→DESK, 利率 = SHIBOR_3M + 100bp
}
代码入口: TrsPayoff.java(收益函数)、ContractDividendHelper.java(分红处理)、ContractEventLegHelper.java(利率重置)
关键簿记概念:
- 分红处理: TRS 中标的的分红归收益接收方。除息日系统贷记接收方
- 公司行为: 拆股调整乘数,合并可能触发提前终止
- 融资付款: 每日计算但每月支付。使用日计数惯例 (day-count convention: ACT/365, ACT/360)
TRS 运营的真实痛点——公司行为跟踪: 当 TRS 覆盖 300+ 只股票时,几乎每天都有一些公司行为(分红、配股、拆股)。每发生一个,运营需要确认:哪些 TRS 合约受影响?调整多少?是否需要人为介入?2020 年有一笔茅台除息,运营漏掉了一个 TRS 合约的分红调整,直到客户对账发现少了 50 万 RMB 的分红收入。结果是手工补账 + 客户投诉 + 流程检讨。此后运营每周一固定花 2 小时跑一遍”未来一周公司行为清单”,逐个确认 TRS 合约是否需要调整。
2. NDF — 无本金交割远期 (Non-Deliverable Forward)
业务是什么
无本金交割远期 (NDF) 是针对有交易限制的币种的远期合约——即不能实际交割。最常见的 NDF 是人民币 (CNY),因为中国有资本管制。
不是实际交换货币,双方用现金结算差额:
- 如果 CNY 走强超过约定汇率 → 交易台付给客户
- 如果 CNY 走弱超过约定汇率 → 客户付给交易台
例子: 美国对冲基金预期 USD/CNY 下跌(即 RMB 升值)。他们不能直接做在岸外汇。签 3m NDF:
- 名义本金:$1000 万
- 合约汇率:7.20
- 定盘日:3 个月后
- 结算:美元净差
如果定盘日 USD/CNY = 7.00(RMB 升值):差额 (7.20-7.00)×$1000万=¥200万→$285,714,客户从交易台收到 $285,714 如果定盘日 USD/CNY = 7.40(RMB 贬值):差额 (7.20-7.40)×$1000万=-¥200万→$270,270,客户付给交易台 $270,270
在 ODTS 中
productType = "NDOLLAR"
Leg: type = FORWARD, buyCcy=USD, sellCcy=CNY, contractRate=7.20
fixingSource=CFETS(中国外汇交易中心)
代码入口: NdollarPayoff.java(收益函数)、action/Fixing/(定盘处理)
关键点:
- NDF 始终现金结算,没有实体交割
- 定盘源至关重要: 人民币 NDF 使用北京时间 16:30 的 CFETS 定盘价。其他来源=不同结算金额
- CFETS 数据延迟的风险: 2021 年有两次 CFETS 定盘价在 16:30 没有准时发布(CFETS 系统问题)。系统在 16:30 读取到的是一小时前的旧价,导致 NDF 定盘结算算错了约 10 万 RMB。发现后手工修正,但结算指令已经发出去了。此后系统加了一个逻辑:定盘价比上一交易日变动超过 1% 时触发告警,人工确认后才使用
- 代码中的 “NDOLLAR” = NDF。“ND”=Non-Deliverable,“OLLAR” 是历史遗留后缀
3. 雪球 (Snowball)
业务是什么
雪球是一种在中国私人银行中极受欢迎的结构化产品。得名于”票息会像雪球一样累积”——只要障碍条件不被触发。
核心结构:
- 发行人卖出基于股指(中证 500、中证 1000)或个股的雪球
- 两个价格障碍:敲出 (KO) 障碍(通常初始价的 100–105%)和敲入 (KI) 障碍(通常初始价的 70–80%)
- 标的从未触发 KO → 到期全额票息
- 标的触发 KO → 产品提前终止,获得累积票息
- KI 被触发且没有 KO → 产品转为亏损头寸
四种情景:
| 情景 | 标的价格路径 | 投资者结果 |
|---|---|---|
| 最好情况 | 在 KI 和 KO 之间震荡→不触发 | 到期全额票息(年化 15%) |
| 提前敲出 | 敲出障碍被触发 | 提前终止 + 按比例累积票息 |
| 仅敲入 | 触发 KI 但从未 KO | 到期拿票息+本金(视条款而定) |
| 最坏情况 | 触发 KI 且到期价低于初始价 | 亏损 = 初始价 − 到期价 |
为什么流行: 投资者觉得”高收益(年化 12–20%)+ 看起来安全的障碍位”。交易台可以收取溢价并做 Gamma/Vega 对冲。
为什么危险: 市场暴跌时(如 2022 年中证 500 下跌 29%),大量雪球敲入→零售投资者巨亏。
实际损失案例(2022 年): 一个私人银行客户在 2021 年 9 月买入 500 万 RMB 的中证 500 雪球,初始价 7500、敲入障碍 80%(即 6000)、年化票息 15%(月付 1.25%)。2022 年 3 月中证 500 跌破 6000→敲入。到 2022 年 10 月到期,中证 500 收盘 5300。客户最终拿回 500 万 × (5300/7500) = 353 万,亏损 147 万(-29.4%)。而同期如果直接买中证 500 ETF,亏损约也是 29%——雪球在暴跌中几乎没有提供下行保护。这个”看起来有 20% 安全垫”的错觉正是雪球销售中最具争议的地方。
在 ODTS 中
雪球是系统中最复杂的产品(也是利润最高的):
productType = "SNOWBALL"
Legs: CouponSchedule[], KnockOutBarrier, KnockInBarrier, MemoryFeature
代码入口: SnowballPayoff.java(收益函数)、ContractKnockInOut.java(KO/KI 检查)、EOD 障碍检查
支持变体:
- 标准雪球: 固定票息、单 KO/KI 障碍
- 记忆雪球 (Memory Snowball): 未付票息在下次 KO 时补付
- 阶梯敲出雪球 (Step-Down): KO 障碍随时间降低(100%→90%→80%)
- Phoenix 雪球: 额外敲入特性
- 可赎回雪球 (Callable): 交易台可以提前赎回
4. 香草期权 (Vanilla Option)
业务是什么
香草期权给予买方权利(但没有义务)在约定日期前以约定价格买入(认购/call)或卖出(认沽/put)标的。
认购期权 (Call): 买入权利→看涨 认沽期权 (Put): 卖出权利→看跌
基金怎么用: 买入中证 500 认购期权替代直接买指数。好处:亏损有限(仅权利金),收益无限。坏处:要付权利金,市场不动就亏了权利金。
在 ODTS 中
productType = "OPTION"
Leg: optionType=CALL|PUT, strike=5500, style=EUROPEAN|AMERICAN
代码入口: VanillaOptionPayoff.java、edslib/valuation/(Black-Scholes 对欧式、二叉树对美式)、OptionExecutionController.java(行权/指派)
5. 障碍期权 (Barrier Option)
业务是什么
在香草期权上加一个触发价。标的触及障碍时,期权要么出现(敲入/Knock-In)要么消失(敲出/Knock-Out)。
敲出认购 (Knock-Out Call): 一开始是认购,标的触及障碍(如行权价的 120%)就消失。便宜,因为可能平白消失。
敲入认沽 (Knock-In Put): 一开始不存在,标的触及障碍后认沽期权出现。用于尾部风险对冲。
为什么用障碍: 比香草期权便宜。认为中证 500 半年内不会超过 4500–5500 的客户可以买一个半价的范围。
在 ODTS 中
代码入口: BarrierOptionPayoff.java,EOD 批处理中与雪球 KO/KI 检查逻辑相同
6. Swap(互换)
业务是什么
交换现金流的协议。ODTS 中最常见的是股权互换和利率互换。
股权互换: 用股票/投资组合的回报交换固定/浮动付款。本质上就是 TRS 但没叫 Total Return。
利率互换 (IRS): 固定利率付款换浮动利率付款。用于管理利率风险敞口。
在 ODTS 中
代码入口: SwapPayoff.java、ContractHelper.java
7. 产品到 Payoff 的映射
这是理解代码最重要的映射:
productType | Payoff 类 | 标的类型 | 关键业务指标 |
|---|---|---|---|
TRS | TrsPayoff | 股票、指数、ETF | 融资利差 (funding spread) |
NDOLLAR | NdollarPayoff | 外汇对 (USD/CNY) | 合约汇率 vs 定盘价 |
SNOWBALL | SnowballPayoff | 指数 (中证500/1000) | KO/KI 障碍位 |
OPTION (香草) | VanillaOptionPayoff | 股票、指数、ETF、商品 | 行权价、权利金 |
OPTION (障碍) | BarrierOptionPayoff | 股票、指数 | 障碍类型+价位 |
SWAP | SwapPayoff | 利率、股权 | 固定 vs 浮动利差 |
FORWARD | ForwardPayoff | 外汇、股权 | 远期价 |
8. 新产品上线的流程
业务要推新产品变体时:
- 量化/结构师设计收益函数→写 spec
- 开发在
edslib/payoff/实现 payoff - 开发在
eds-web-app的常量枚举中加产品类型 - 开发在
new-edsweb建簿记表单 - 开发在
hedging-as加 EOD 处理 - 开发在
hedging-as加定价服务 - QA 用历史市场数据+已知边界条件测试
- BA 确认配置模板(合约文件、报告)
- 发布→第一笔交易上线
时间线中的瓶颈: 实际交付中,大部分时间花在步骤 4-7 的联调上——因为每个新产品需要改 5 个模块(常量枚举、簿记表单、EOD 处理、定价服务、确认书模板),每个模块的负责人不同。如果某个人正好在忙其他需求(经常发生),整个链条就卡住了。2022 年一个 Daily Accrual 产品的上线因为确认书模板的法务审批等了 3 周——模板改好了,但没有一个开发者有权限改动法律措辞。
时间估计: 简单变体(如新雪球障碍结构)2–3 周。全新产品类型(如 Variance Swap)2–3 个月。
自测
对每个场景,能回答:用哪个产品类型?定价代码在哪?需要什么 EOD 处理?用什么 UI?
- 客户要中证 500 的 3 倍杠杆敞口 → TRS
- 外资基金要人民币敞口但不能做在岸外汇 → NDF
- 高净值客户要中证 1000 年化 18%、75% 下行保护 → Snowball
- 对冲基金要保护中证 2000 跌 30% → 障碍认沽期权
- 养老基金要把固息债回报换成浮动 → Swap
9. 内行才知道的:同一个 productType,代码里分了”簿记口径”和”定价口径”
新人最容易踩的一个坑:系统里有两套产品类型枚举,而且它们不是一一对应的。
- 簿记口径 在
eds-web-app的常量里(com.cicc.constant.ProductType),交易员簿记时选的就是这套——它贴近业务术语,雪球就是SNOWBALL,凤凰就是PHOENIX。 - 定价口径 在
hedging-as的 payoff 包里,它更”粗”——凤凰 (Phoenix) 在定价引擎里并没有独立的 Payoff 类,它和雪球共用SnowballPayoff,靠一组布尔标志位(hasMonthlyCoupon、memoryFeature、phoenixMode)来区分行为。
为什么会这样: 凤凰是雪球的一个”营销变体”——区别只是票息发放频率和记忆机制。量化团队认为”没必要为营销包装单独写一套数学”,所以定价层把它们合并了。但簿记层要按客户能理解的产品名走流程,所以保留了独立类型。
真实踩坑:凤凰被当雪球算了三个月
2021 年上线凤凰时,簿记口径加了 PHOENIX,但 SnowballPayoff 里的 phoenixMode 标志忘了在定价服务里打开。结果系统按普通雪球的票息频率给凤凰估值——凤凰是月度派息,雪球是到期一次性派息,两者 MTM 差距在长尾上能差到名义本金的 1-2%。这个问题在 EOD 里”看起来正常”(因为凤凰的首笔派息要一个月后才发生),直到第一个派息日,客户对账单的派息金额和预期对不上,才被运营揪出来。根因是两套枚举之间的映射靠人工记忆,没有任何编译期或启动期校验。
PM/BA 启示: 当你在需求里说”加一个产品”,先问清楚的是”簿记口径的新类型”还是”定价口径的新数学”。如果只是换了个营销名字、收益结构没变,开发可能根本不用碰定价引擎——但必须确认映射标志位已经打开,否则会重演凤凰事件。这套双口径的存在,是 ODTS 产品治理里最隐蔽的雷。
下一篇:08-Pricing-and-Risk.md —— 定价引擎如何工作、Greeks、保证金与压力测试