Origins 2014 2016
ODTS 01 — 起源 2014–2016:从 Excel 到 AccessApp
业务背景 (2014 年)
中金公司 (CICC) 的权益衍生品交易台 (equity derivatives desk) 在 2014 年时规模很小:约 10 人——3 个交易员 (trader)、2 个结构化产品设计师/量化 (structurer/quant)、3 个销售 (sales)、2 个运营 (operations)。
交易的产品:
- 香草场外期权 (Vanilla OTC Options) —— 标的为港股单只股票(腾讯、友邦、汇丰)和通过 QFII 渠道的少量 A 股
- 权益互换 (Equity Swaps) —— 后来称为 TRS(总收益互换 Total Return Swap)的前身,客户主要是需要杠杆的私人银行
- 结构化产品 (Structured Products) —— 挂钩港股指数的简单自动赎回结构 (autocallables)
客户构成:
- 私人银行(UBP、Julius Baer、Credit Suisse)—— 从交易台买入结构化票据 (structured notes)
- 对冲基金(主要在 HK,部分在美国)—— 需要 A 股敞口 (exposure)
- 企业客户 —— 需要权益对冲 (equity hedging)
市场环境:
2014–2015 年是中国 A 股的一轮大牛市(上证指数从 2000 涨到 5178)。2015 年夏天的股灾还没到来。A 股市场对外资基本封闭(QFII 额度很小)。中国的场外衍生品市场刚刚起步——中国证券业协会 (SAC) 才开始对其进行监管。
业务痛点:问题不是”系统不好”,是”没有系统”
2014 年交易台的运营方式大致如此:所有交易簿记 (booking) 靠 Excel。估值 (valuation) 用 VBA 写成的 Excel 公式跑。风险报告 (risk report) 靠手动更新。
一个典型工作日的业务流程:
- 销售接到客户询价 (电话或 IM)
- 结构化产品设计师 (structurer) 在 Excel VBA 里定价 (price)
- 客户确认后,structurer 发 Word 版成交确认书 (trade confirmation)
- 运营 (operations) 手动把交易簿记进…另一个 Excel
- 收市后 (EOD),有人手动把所有头寸复制到风险表 (risk spreadsheet)
- 保证金计算 (margin calculation) 在计算器上完成
这种模式最严重的问题不是效率低,是:无法扩张 (couldn’t scale)。每增加一个客户就要多一套 Excel。每增加一个产品就要多一套 VBA 宏。到 2015 年中,交易台每周处理 50+ 笔交易,运营人员每天加班到凌晨。
这个阶段是下文的第一个崩溃点 (breaking point):Excel 撑不住了,必须建系统。
第一个系统:AccessApp
2014 年底,团队决定建一个”能用的东西”——不是完整交易系统,只是一个能追踪已交易合约的簿记工具。
结果就是 AccessApp(这个名字说明了一切:最初它是一个 Access 数据库,后来被改成了一个 Web 应用)。
技术栈: Java、Spring(pre-Boot)、JSP、jQuery
它能做的:
- 基本的交易簿记 (trade capture)——表单录单
- 交易列表 (trade list)——表格展示所有交易
- 简单的按市值计价报告 (MTM report)——手工更新价格,展示盈亏 (P&L)
它不能做的:
- 定价引擎 (pricing engine) —— 仍然用 Excel
- 风险管理 (risk management)
- 保证金计算 (margin calculation)
- 成交确认书生成 (confirmation generation)
- 监管报送 (regulatory reporting)
为什么只做成这样:
团队只有 2 个开发,其中一个还在学 Java。业务方说不清自己要什么(他们之前没用过交易系统)。“完美”的系统要太久,团队需要在 3 个月内做出一个能用的。
技术上是对的,业务上呢?
如果从纯技术角度看,AccessApp 的架构很简陋——一个 WAR 包、一张大表、直接 JDBC。但如果从业务发展角度看,它是当时最好的选择:
团队选择”先做出来”而不是”先设计好”,是因为业务本身在飞速演变。2014 年 3 个产品,2015 年变成了 8 个——如果等到设计好再动手,系统还没上线产品就已经变了。
这个判断可以从 AccessApp 的演进过程中得到验证:最初的 TRADE 表只有 20 列,到 2016 年膨胀到了 80 列。每列都是业务临时需要的字段——说明业务需求在不停变化,不可能一次性设计好。
产品大爆发 (2015–2016)
2015 到 2016 年,产品类型急剧增加:
新产品:
- 雪球 (Snowball) 结构化产品,挂钩中证 500 —— 今后会成为最大的产品线
- A 股 TRS (Total Return Swap) —— 通过 2014 年开通的沪港通和 2016 年开通的深港通,外资大量涌入
- 人民币 NDF (Non-Deliverable Forward) —— 外资需要人民币敞口但没有在岸渠道
- 障碍期权 (Barrier Options) —— 客户想要更便宜的带敲出特征 (knock-out) 的期权
驱动因素:
- 沪深港通 (Stock Connect 2014/2016) 首次让外资可以直接投资 A 股 → TRS 需求暴增
- 人民币国际化 (RMB internationalisation) → 离岸投资者需要人民币对冲 → NDF 需求
- 中国零售财富管理热潮 → 私人银行想卖结构化产品给高净值客户 → 雪球需求
系统跟不上了
AccessApp 的单表 (one-big-table) 设计无法应对产品多样性。一个 TRS 有 2+ 条腿 (legs)——融资腿和收益腿。雪球有障碍价格 (barrier)、敲出日程表 (knock-out schedule)、记忆息票 (memory coupon)。团队试图在一个”通用”表里用可空列 (nullable columns) 来兼容所有产品——最终成了一个大泥团。
定价仍然在 Excel 里——每个产品有自己的 VBA 定价表。
业务后果: 团队处于”疲于应对”的状态。每来一个新需求就加一列,每加一列就要改前端表单、改查询、改报表。AccessApp 的开发周期从”一周一个功能”变成了”两周一个功能”。业务等不及的功能就回到了 Excel 里做。
表面上公司在扩展业务,实际上后台的运营和开发正在被复杂度压垮。
FIX 连接——第一次与外部系统打交道
2015 年,交易台需要连接期货经纪商进行对冲 (hedging)。经纪商只支持 FIX 协议 (Financial Information Exchange protocol)。团队之前从未程序化对接过外部系统。
方案: 用 QuickFIX/J 库写了一个极简的 FIX 客户端。这是团队第一次做外部系统集成 (external system integration)。
这个 FIX 连接的经验很重要——它让团队开始思考对冲工作流 (hedging workflow)——不只是簿记 (book) 交易,还要对冲 (hedge) 交易。它也暴露了一个关键问题:基于 Excel 的定价太慢,无法支撑盘中对冲决策。
BORO 事件——当咨询公司试图建衍生品系统
2015 年左右,一个名为 BORO 的项目启动了。目标是用”现代化技术栈”从零搭建一个统一的衍生品平台。
BORO 的设计: 一个全功能的前台到后台系统 (front-to-back system),由独立团队(不是交易台的 2 个开发)构建,采用”企业架构方法”——UML 图、需求文档、完整瀑布模型 (waterfall)。
BORO 的实际产出(18 个月、几百万人民币后):
- 一份 200 页的需求文档
- 一个什么都不连的 POC 前端
- 一块交易台用不了的”系统”
为什么 BORO 注定失败: 系统由一个不懂 OTC 衍生品的咨询公司在设计。需求文档里有 “系统应支持所有产品类型” 这种话,但没有具体说明怎么支持。交易台自己也说不清需要什么——因为他们不知道一个交易系统能做什么。与此同时,坐在交易台旁边的 AccessApp 团队已经在交付可用的软件了。
商业决策的启示:
BORO 花的几百万买了什么?一份没人读得完的需求文档和一个 POC。如果这些钱用来雇 2 个懂衍生品的开发,AccessApp 可能在 6 个月内就能成长为一个真正的系统。
这个案例的教训不是”咨询公司不好”,而是:在复杂的业务领域(如 OTC 衍生品),你不能靠需求文档设计系统。你必须让开发坐在交易员旁边。 AccessApp 团队能成功,就是因为他们每天听到交易员的对话、看到他们的工作流、理解他们的痛点。咨询公司坐在写字楼里写需求文档,连交易员长什么样都没见过。
Protobuf 决策——一个正确的技术选择
到 2016 年,AccessApp 和定价库需要互相通信。定价库里的雪球蒙特卡洛模拟在 VBA 里跑一次要 5 分钟——团队决定把定价搬到 Java 服务里。
为什么选 Protobuf:
- SOAP XML 太重(2016 年 SOAP 已经在退场了)
- JSON 当时还不被视为”企业级”
- Protobuf 新、快,Google 在用
- 团队已经在用 Java——Protobuf 生成 Java 代码
Protobuf 的用处: .proto 文件成为了组件之间的合约 (contract)。定价引擎要加新字段,先改 .proto,两边重新生成代码。
为什么这个选择正确: Protobuf 在当时的选择是合理的——快、有类型、跨语言。但它也有成本:二进制格式意味着不能直接 curl 一个接口看返回什么。每次定价请求都要从十六进制解码。调试 (debugging) 变得更困难了。
2016 年:不归点 (The Point of No Return)
到 2016 年底,交易台每月处理 200+ 笔交易。AccessApp 的架构出现了明显的能力不足——JDBC 查询开始变慢,JSP 页面要加载好几秒。
三件事同时发生,迫使团队重建系统:
事件一:SAC 监管报送 (regulatory reporting) 成为强制要求。 每笔 OTC 交易必须向中国证券业协会报送指定 XML 格式的报告。AccessApp 做不了。合规官用 Excel 手工做。
事件二:雪球交易量爆发。 到 2016 年中,雪球占到了新交易的 60%。AccessApp 无法处理雪球的障碍价格 (barrier)、敲出日程 (knock-out schedule)、记忆息票 (memory coupon)。团队回到了 Excel 追踪一半交易细节的状态——这是倒退。
事件三:交易台招了一个量化研究员。 陈博士(北大数学博士)看到 VBA 定价后说:“这个撑不住了。我们需要一个真正的定价引擎 (pricing engine)。”
这三个事件构成了 01 文档的核心崩溃点。前两个是业务压力——合规做不了、产品管不住了。第三个是量化策略——知道该做什么方向,但现有系统做不了。
决定: 拆分系统。定价成为独立的服务 (hedging-as)。簿记系统重写(演化为 eds-web-app)。前端…以后再管。
这个架构写在了一个白板上。它花了两年才真正实现。
自建还是采购 (Make vs Buy)
2014-2016 年反复出现的一个主题是”自建还是采购”:
| 组件 | 决策 | 原因 |
|---|---|---|
| 定价引擎 | 自建 | 没有商业化产品(COTS)能处理中国 OTC 衍生品(雪球在西方市场不存在) |
| 交易簿记 | 自建 | 商用系统(Murex、Calypso)的预算贵 10 倍 |
| FIX 引擎 | 用库 | QuickFIX/J 免费且好用 |
| 市场数据 | 买 | Reuters Eikon(后来 Bloomberg) |
| 确认书 | 自建 | Word 模板 + Java 便宜 |
| 数据库 | 用 | MySQL(免费,后来因为监管要求换到 Oracle) |
关键洞察: 对于像中国 OTC 衍生品这样的利基 (niche)、快速变化的市场,自建往往比采购更便宜、更好。西方系统不理解中国产品。中国系统又太通用。
2016 年底的全景
| 指标 | 2014 | 2016 |
|---|---|---|
| 月交易量 | 20-30 笔 | 200+ 笔 |
| 产品类型 | 3 个 | 8+ 个 |
| 客户数 | 10 | 50+ |
| 开发人数 | 1 | 4 |
| 定价方式 | Excel VBA | 混合(Excel + 早期 Java) |
| 簿记方式 | Excel | AccessApp(Web) |
| 风险管理 | Excel | AccessApp(基础功能) |
| 报送 | Excel | AccessApp + 人工 SAC |
| 对冲管理 | 手工 | 手工 |
总结:这一阶段到底发生了什么
从业务角度看,2014–2016 年的核心冲突是:
- 业务增长(从 20 笔/月到 200 笔/月,从 3 个产品到 8+ 个)远快于系统建设能力
- Excel 撑不住的时候,团队选了”先做一个能用的”(AccessApp),这个选择是对的
- 但不归点在于:AccessApp 的设计(一张大表、没有扩展性)决定了它最终也撑不住
- 当监管要求 (SAC) 和产品复杂度 (雪球) 同时到来时,团队别无选择——只能重写
如果回到 2014 年,能做什么不一样? 不是等需求文档写完整——那是 BORO 走的死胡同。而是:在 AccessApp 的基础上,更早地预见”一张大表的极限在哪里”。比如在设计 TRADE 表时就意识到:当产品类型从 3 个变成 10 个时,列会膨胀,应该考虑扩展表 (extension tables) 而不是在单表里塞列。但这个”预见”在有 20 列、3 个产品的时候很难做——只有做过了才知道。
下一篇:02-Foundation-2016-2018 —— 定价引擎、三大件拆分、雪球爆发