Cats Comparison
50. CATS —— 商品部的”迷你ODTS” / The Commodity Desk’s “Mini ODTS”
缘起:找到CATS
CATS(Commodity Auto Trading System)位于 /odts1/CATS 目录中。从目录名看它和 ODTS 在同一级,但从深处看它是商品部自用的交易系统。Git log 显示只有 79 次提交,活跃期约一年(2019-2020),之后再无人问津。
CATS 并非一个独立开发的系统——从它的代码结构看,它是从 ODTS/EDS 的体系”长出来”的。包名 com.cicc.commodity、共享的 webside-security、统一的 Ant 构建框架,都与主 OTC 系统出自同一套基础设施。这像是一个商品部团队拿主系统的脚手架,为 LME 金属期货业务搭了一套专用的交易系统,然后又把 OTC 衍生品 支持加了进去。
CATS 的两张面孔 / Two Faces
CATS 最核心的特征是:一个 WAR 里装了两个业务域。
Face 1:交易所商品(Exchange-Traded Commodities)
这是 CATS 的原生业务——处理港交所/ LME 等交易所的金属期货和期权交易。核心表 T_COMMODITY 包含:
| 字段 | 含义 | 等价 ODTS 概念 |
|---|---|---|
EXCHANGE | 交易所代码(LME/SHFE/etc.) | 无(ODTS不接交易所) |
EXCHANGE_SYMBOL | 交易所品种代码 | 无 |
TICKER | 行情代码 | UnderlyTicker |
CONTRACT_NAME | 合约名称 | 无 |
CONTRACT_SIZE | 每手数量 | 无 |
CONTRACT_NUMBER | 合约手数 | Quantity |
POSITION | Long/Short | Side |
TRADE_STATUS | Open/Close/Pending | TradeStatus |
CLEARING_FEE / EXCHANGE_FEE / STAMP_DUTY / TRANS_LEVY / COMMISSION_FEE | 费用明细 | 无统一字段 |
FEED_REF / FEED_STATUS | 数据源回执 | 类似但不尽相同 |
SETTLE_AMOUNT / SETTLE_DATE | 结算金额和日期 | Settlement |
这本质上是 期货交易管理系统,业务范围包括:
- 记录交易所成交(从经纪人/ Bloomberg 导入)
- 计算持仓和盈亏(每日盯市 P&L)
- 管理保证金(Initial Margin、Broker Margin Balance)
- 生成结算单和对账单(Statement / StatementMonthly)
- 费用管理(佣金、交易所费、印花税、过户费等)
Face 2:OTC 衍生品(Commodity OTC Derivatives)
这是后来加入的——CATS 在商品期货之上 + 了 OTC 支持,用另一张核心表 T_OTC_TRADE 存储。从字段数量看(约 80+ 列),这是一张典型的 单表大宽表——与 ODTS 早期做法完全一致。
CATS 支持的 OTC 产品线
从 ContractType.java 中看到的品类:
| 代码 | 品类 | 中文名 | ODTS 是否有等价品 |
|---|---|---|---|
| VAN | Vanilla Option | 香草期权 | 有 |
| VANS | Vanilla Spread | 香草价差 | 无(ODTS 用 Barrier 实现近似效果) |
| CPS | Call Put Spread | 看涨看跌价差 | 无 |
| SF | SharkFin | 鲨鱼鳍 | 无(最接近的是 Barrier) |
| DSF | Double SharkFin | 双鲨鱼鳍 | 无 |
| ESF | European SharkFin | 欧式鲨鱼鳍 | 无 |
| EDSF | European Double SharkFin | 欧式双鲨鱼鳍 | 无 |
| OT | One Touch | 触碰期权 | 无 |
| FX | FX | 外汇 | 有(但 CATS 只做商品端的 FX) |
| Forward | Forward | 远期 | 有 |
| Future | Future | 期货 | 无(ODTS 不做交易所期货) |
| Option | Option | 期权 | 有 |
SharkFin(鲨鱼鳍) 是 CATS 最有特色的产品。它是一种保本型结构化产品,设有一个上限价格(knock-out level),标的在期限内如果未触碰上限则到期获得固定收益,触碰后收益按标的涨幅线性计算但封顶。与 ODTS 的 Snowball 相比:
- SharkFin:保本、单层 barrier、期限较短(通常 1-3 个月)
- Snowball:不保本、两层 barrier(敲入/敲出)、期限长(12-24 个月)、票息递延
CATS 的 T_OTC_TRADE 包含了面向这些结构所需的字段:
BARRIER_PRICE, BARRIER_SIZE, -- 障碍价格/比例
HIGH_KNOCK_OUT_PRICE, -- 敲出价格(SharkFin 上限)
LOW_KNOCK_OUT_PRICE, -- 敲入价格
OBSERVATION_DATE_BEGIN, -- 观察期开始
MIN_RETURN, -- 最低回报率
DIGITAL_SIZE, -- 数字期权固定回报
KICKOUT_RETURN, -- 敲出回报率
NOTIONAL_AMOUNT -- 名义本金
OTC 业务的辅助模块
CATS 为 OTC 业务补充了完整的交易后模块:
| 模块 | CATS 实现 | ODTS 对比 |
|---|---|---|
| P&L | 按产品类型拆分:OTC_PNL_AU/OTC_PNL_FUTURE/OTC_PNL_OPTION/OTC_PNL_VANILLA + 汇总 OTC_SUMMARY + 历史 OTC_HIS_SUMMARY | 统一 P&L 表 + Delta/Gamma/Vega 风险表 |
| 定价 | PricingCalculator.java 用 Black-76 + OTC_UNDERLY(含 sigma/价格/利率) | Black-76 + Monte Carlo + Python bridge |
| 合约确认函 | JasperReports PDF 生成(中英双语) | 同上 + Murex/ Bloomberg XML |
| 估值 | OTC_VALUE_ITEM 逐日盯市 | ValuationDay 批量估值 |
| 资金管理 | CASH_MANAGEMENT + CASH_VOUCHER(凭证) | CashMovement |
| 抵押品 | COLLATERAL | Collateral(更复杂) |
| 报告 | OTC_REPORT + OTC_REPORT_TEMPLATE | Reporting engine |
| 平仓 | OTC_CLOSED_TRADE + OTC_PARTIAL_SETTLED_TRADE | 类似 |
| Termsheet | 自动生成 PDF | 类似 |
技术栈对比 / Tech Stack Comparison
| 层面 | CATS | ODTS |
|---|---|---|
| Web 框架 | Struts 2.3 | JFinal (世界1) / Spring Boot (世界2) |
| ORM | Hibernate 3.6.7 + XML mapping | ActiveRecord (世界1) / MyBatis (世界2) |
| Spring | Spring 3.0.6 | Spring Boot 2.x |
| 前端 | FreeMarker 服务器端渲染 + jQuery jqGrid | Vue SPA (世界1) / Vue3 (世界2) |
| 数据库 | Oracle(C3P0 连接池) | MySQL |
| 构建 | Ant + WebLogic 部署 | Maven + Jenkins |
| 消息 | ActiveMQ 5.3 | RabbitMQ |
| 认证 | CAS SSO + Spring Security | 类似(同一 CAS 体系) |
| 报表 | JasperReports 6.3 | JasperReports + 定制 |
| 数据集成 | Bloomberg 数据接入 | Bloomberg + Wind + 自采 |
| 缓存 | Ehcache + OSCache | Redis |
| 单元测试 | 无(测试目录为空) | JUnit + Mockito |
架构风格差异
CATS 是典型的 单层单体应用——一个 WAR 部署到 WebLogic,一个 commodity.hbm.xml 包含全部 65 个实体映射,所有 Action 继承同一个 BaseAction。代码量虽然不大(79 commits),但 65 张表说明它是一个表驱动的系统——每个业务概念都有对应的数据库表,CRUD 骨架从 ODTS 体系中复制后定制。
ODTS 经历了从单体到微服务的完整演化路径(详见 04-Modernization),40+ 个内部项目 + 8+ 个外部集成系统,Maven 多模块构建,REST API 网关。
数据模型对比
CATS 的 T_OTC_TRADE 是一个典型的 大宽表反模式——无论 Vanilla、SharkFin、FX 还是 One-Touch,全部塞进同一张表。这种做法:
- 和 ODTS 早期做法一样——ODTS 的
t_trade_order也曾是这种”一把梭”的通用结构 - 问题也一样——字段可空(nullable)是常态,约束只能靠代码,DB 本身无法保证数据完整性
- 但 CATS 规模小,问题不致命——79 次提交的代码量,一个开发者就能维护
CATS 比 ODTS 多了一个处理维度:交易所。 它的 T_COMMODITY 有 EXCHANGE、EXCHANGE_SYMBOL、FEED_REF 等字段,这是 ODTS 完全不需要的——ODTS 只做场外。
要命的业务逻辑 / Business Logic Worth Dying For
费用计算
交易所期货的费用极其复杂。CATS 的 Commodity 模型中有 7 个费用字段:
CLEARING_FEE(清算费)EXCHANGE_FEE(交易所费)STAMP_DUTY(印花税)TRANS_LEVY(交易征费)COMMISSION_FEE(佣金)OTHER_FEE(其他费用)MARKUP_FEE(加价)
相比之下,ODTS 没有这些细分——OTC 衍生品没有交易所费/印花税的概念,费用结构简单得多(一般就是名义本金 × 费率)。
保证金模型
CATS 的保证金系统比 ODTS 复杂,因为它有两种保证金:
- 交易所保证金——交易所规定的 Initial Margin,通过
BROKER_MARGIN_BALANCE和INITIAL_MARGIN_PER_LOT管理 - 客户保证金——
MARGIN和MARGIN_CALL表管理,CLIENT_MARGIN_MONITOR监控 - LME 特有——LME 是 tier 保证金制度,
LME_TIER_MARGIN_TABLE和LME_TIER为此而生
ODTS 的保证金(详见 16-Margin-Calls)主要是 IM + VM,通过 ISDA CSA 协议约束,不需要关心交易所的 tier 保证金计算。
为什么说 CATS 是”迷你 ODTS”?
从代码树结构看,CATS 和 ODTS 的关系是:
/odts1/
├── CATS/ ← 商品部自用
│ └── commodity/ ← 单一项目
├── eds-web-app/ ← OTC 衍生品(世界1, 2016-2018)
├── option-frontend/ ← OTC 前端
├── finance-data-backend/ ← OTC 数据(世界2)
├── trade-backend/ ← OTC 交易(世界2)
├── sentinel-backend/ ← OTC 风控
├── lens-backend/ ← OTC 报表
├── ...
CATS 是一个 小号、单机的 ODTS——它用 ODTS 的框架和设计模式,但只服务商品部这一个业务线。它的 OTC 部分几乎是对 ODTS 的简化模仿:
| 维度 | ODTS | CATS |
|---|---|---|
| 开发团队 | 10+ 人持续 10+ 年 | 2-3 人迭代约 1 年 |
| 代码规模 | 100K+ commits, 45+ 项目 | 79 commits, 1 项目 |
| 产品复杂度 | Snowball、TRS、NDF、多标的 Basket | SharkFin、Vanilla、CPS |
| 交易量级 | 千亿级名义本金 | 商品部级别(小几个数量级) |
| 定价模型 | Black-76 + Monte Carlo + Python | Black-76(纯 Java) |
| 对接系统 | 恒生、地杰、Murex、Bloomberg | Bloomberg(主要是行情) |
| 监管报告 | SAC/ SFC/ ISDA/ NAFMII 全面覆盖 | 基本无(交易所已有清算所报告) |
业务代价:一个被放弃的”迷你系统”的真实成本
79 次提交,1 年后无人维护
CATS 在 2019-2020 年开发了约一年,79 次提交后彻底停更。
投入(估算):
→ 2-3 名开发,约 1 年
→ 人力成本:约 150-200 万人民币
→ 产出:1 个 WAR 包,65 张表,覆盖 LME 期货 + 商品 OTC
为什么停了?
→ 商品部的 OTC 业务量始终不大("小几个数量级")
→ 维护成本 vs 业务价值不匹配
→ 2020 年后商品部可能把 OTC 业务迁回了主 ODTS 或交给了别的团队
→ 但 CATS 的代码和数据库并没有删除——它"死"在那里
PM/BA 注意:
当你看到一个内部系统"停更"但没被回收时,
它变成一个"技术债定时炸弹"——
某天有人需要查 2019 年的一笔商品 OTC 交易,
发现数据只在 CATS 的 Oracle 库里,
而 CATS 的部署环境可能已经无法启动。
同一客户的”两边账”——CATS vs ODTS
CATS 做商品 OTC,ODTS 做金融 OTC。如果同一个机构客户既做商品又做金融衍生品:
场景:
→ 客户 A 在 CATS 里有一笔 SharkFin(商品 OTC)
→ 客户 A 在 ODTS 里有一笔 Snowball(金融 OTC)
→ 客户 A 的总信用风险需要合并计算(这是监管要求的)
问题:
→ CATS 的信用风险表和 ODTS 的完全独立
→ 没有自动的"跨系统客户合并"机制
→ 风控团队要手工把两个系统的客户敞口汇总
→ 手工汇总 → 出错概率高 → 客户总敞口可能被低估
业务影响:
→ 2019-2020 年商品 OTC 量小,这个问题不突出
→ 但如果有大客户跨两个系统,手工合并就是隐患
→ 这正是为什么"系统复制"在合规视角下是危险的:
每个副本都维护一份客户数据,合并时可能漏算
测试目录为空——生产环境的隐性风险
CATS 的技术栈对比中明确写着:单元测试:无(测试目录为空)。
这意味着:
→ 任何一个 bug 修复都没有自动化验证
→ 改一个费用计算逻辑,只能靠"上线后看对不对"
→ 如果有客户因为费用算错而投诉,那是事后才发现
对比 ODTS:
→ ODTS 有 JUnit + Mockito(虽然覆盖率也有限,见 46-Testing-and-QA)
→ CATS 连这个都没有
对于 BA/PM:
一个没有测试的系统如果被用于生产(哪怕是小业务),
每一次代码改动都是"盲飞"。
商品 OTC 虽然量小,但一笔错误的 SharkFin 敲出计算,
仍可能导致对客户的多付或少收。
-
同一个公司内部的”系统复制”是常态——CATS 证明了当一个部门有垂直业务需求时,他们会拿现成的框架搭一套定制系统。这对分析师意味着:CICC 内部可能还有更多类似的”派生系统”。
-
商品期货 ≠ OTC 衍生品——CATS 同时做这两个,但它们是根本不同的业务:
- 期货:标准化合约、交易所清算、逐日盯市、费用复杂
- OTC:非标准化合约、双边清算、ISDA 约束、费用简单但条款复杂
- 放在同一系统中是”历史包袱”,并非设计上的优势
-
SharkFin vs Snowball 的对比值得深究——二者都是结构化产品,但结构完全不同。CATS 做 SharkFin 说明 CICC 的商品部客户群体偏好 低风险保本型 产品,而 ODTS 的 Snowball 客户(机构投资者)愿意承担更大的风险以换取更高收益。
-
技术选择反映团队规模——CATS 用 Ant + Struts2 + FreeMarker + Oracle,全是”重”基础设施的选择,适合小团队用成熟框架快速交付。ODTS 在规模扩大后转向 Spring Boot + Maven + Vue,是”现代化”的自然演进。