一、API设计总纲:多品种交易系统概述、API设计原则与统一数据模型
各位同学,今天咱们聊聊多品种交易系统的API设计。说实话,这个领域我摸爬滚打了七八年,踩过的坑比吃过的盐还多。你想想看,一个系统要同时处理股票、期货、期权、甚至数字货币,每个品种的交易规则、数据频率、风控要求都不一样——这API要是设计不好,后面全是灾难。
1.1 多品种交易系统到底长什么样?
先给个直观印象。多品种交易系统,说白了就是一个能同时对接多个市场的交易中台。它要干三件事:
- 统一接入:不管你是上交所、CME还是币安,API接口风格得一致
- 统一风控:跨品种的保证金计算、持仓合并、风险敞口监控
- 统一执行:订单路由、成交回报、撤单重试,这些逻辑不能每个品种写一套
我个人习惯把系统分成三层:接入层、业务层、执行层。接入层管协议转换,业务层管策略逻辑,执行层管订单生命周期。嗯,这里要注意——很多团队一开始就把三层揉在一起,后面改起来想死的心都有。
核心观点:多品种交易系统的本质是「抽象共性,暴露差异」。共性做在框架里,差异做成配置项。
我曾经见过一个团队,为每个品种单独开发一套API,结果维护了20多套接口。后来行情一改,全得重写。你说这图啥?
1.2 API设计原则:RESTful vs WebSocket
这个问题我每次讲课都会被问到。我的回答很简单:查询用REST,实时用WebSocket。但实际落地时,远没这么简单。
1.2.1 RESTful:适合「一问一答」的场景
RESTful API适合做什么?账户查询、历史数据拉取、参数配置。这些操作的特点是:
- 请求频率低(秒级甚至分钟级)
- 数据量可控(一次返回几百条记录)
- 需要幂等性(重复请求不影响结果)
举个例子,查询账户持仓:
GET /api/v1/accounts/{account_id}/positions
响应:
{
"account_id": "ACC001",
"positions": [
{"symbol": "BTCUSDT", "side": "long", "qty": 1.5, "entry_price": 42000.0},
{"symbol": "600519.SH", "side": "long", "qty": 100, "entry_price": 185.0}
]
}
你看,股票和数字货币的持仓结构其实差不多。这就是统一数据模型的好处。
小技巧:RESTful API的版本号建议放在URL里(如 /api/v1/),而不是Header里。为什么?因为URL一眼就能看出版本,调试时省事。我在项目中吃过这个亏,后来全改了。
1.2.2 WebSocket:适合「持续推送」的场景
行情数据、成交回报、风控预警——这些必须用WebSocket。为什么?因为延迟要求高,而且数据是持续产生的。
我建议的WebSocket设计模式是:
- 订阅模式:客户端先订阅主题,服务端再推送
- 心跳机制:每5秒发一次ping,30秒无响应则断开重连
- 消息去重:每条消息带唯一ID,客户端做幂等处理
来看一个典型的WebSocket消息结构:
{
"type": "tick",
"symbol": "BTCUSDT",
"ts": 1700000000123,
"data": {
"bid": 42500.0,
"ask": 42501.5,
"last": 42500.5,
"volume": 1234.5
},
"msg_id": "tick_1700000000123_001"
}
避坑指南:我曾经遇到过一个项目,WebSocket消息里没带时间戳,结果客户端收到延迟数据后直接下单,亏了十几万。记住:所有推送消息必须带服务端时间戳,客户端必须校验时间有效性。
1.3 统一数据模型定义
这是整个API设计的基石。没有统一数据模型,后面所有接口都是空中楼阁。
我定义统一数据模型时,遵循三个原则:
- 最小化:只包含所有品种共有的字段,差异字段放到扩展属性里
- 标准化:字段名、类型、单位全部统一。比如价格一律用decimal,时间一律用毫秒时间戳
- 版本化:每个模型都有版本号,向后兼容
来看一个核心模型——订单模型:
// 统一订单模型(v1.0)
{
"order_id": "ORD202401010001", // 全局唯一订单ID
"account_id": "ACC001", // 账户ID
"symbol": "BTCUSDT", // 品种代码(统一格式)
"side": "buy", // 方向:buy/sell
"type": "limit", // 类型:market/limit/stop
"price": 42500.0, // 价格(decimal类型)
"qty": 1.0, // 数量(decimal类型)
"time_in_force": "GTC", // 有效期:GTC/IOC/FOK
"status": "new", // 状态:new/partially_filled/filled/cancelled/rejected
"created_at": 1700000000123, // 创建时间(毫秒时间戳)
"updated_at": 1700000000150, // 更新时间
"ext": {} // 扩展属性(品种特有字段放这里)
}
你看,股票、期货、数字货币的订单都能用这个模型表达。差异部分(比如期货的到期日、期权的行权价)都放到ext字段里。
关键点:统一数据模型不是「一刀切」,而是「求同存异」。共性字段必须严格统一,差异字段通过扩展机制处理。
下面这张图展示了统一数据模型在整个系统中的位置:
这张图你看懂了吗?从上到下,数据经过接入层、统一模型层、业务层、执行层。每一层都依赖统一数据模型来交换信息。说白了,统一数据模型就是整个系统的「通用语言」。
1.4 总结一下
这一章我们讲了三个核心点:
- 多品种交易系统:核心是抽象共性、暴露差异,别给每个品种单独造轮子
- API设计原则:RESTful做查询,WebSocket做推送,别混着用
- 统一数据模型:最小化、标准化、版本化,这是所有接口的基础
我的建议:开始设计API之前,先花一周时间把数据模型定下来。模型定好了,接口设计就是水到渠成的事。我在项目中吃过这个亏——模型没想清楚就开干,后面改了四版才稳定下来。
好了,这一章就到这里。记住:好的API设计,从统一数据模型开始。