第二十七章:波动率曲面API设计

说实话,API设计这事儿,看着简单,做起来全是坑。我在做波动率曲面系统的时候,前后重构了三次API接口,才找到比较顺手的方案。今天咱们就聊聊RESTful API怎么设计、WebSocket怎么推实时数据、以及安全认证那些绕不开的坎儿。

一、RESTful API设计:别把接口搞成四不像

很多人设计API,上来就是一堆动词。比如 /getVolSurface/updateVolData。我个人习惯是:资源用名词,操作用HTTP方法。你想想看,RESTful的核心就是资源导向。

核心原则:

  • 用名词表示资源:/api/v1/volatility/surfaces
  • 用HTTP方法表示操作:GET(查)、POST(增)、PUT(改)、DELETE(删)
  • 版本号放路径里:/api/v1/,方便迭代

举个例子,查询某个期权链的波动率曲面:

# 请求
GET /api/v1/volatility/surfaces?underlying=SPX&expiry=2025-06-20

# 响应
{
  "status": "success",
  "data": {
    "surface_id": "surf_20250620",
    "underlying": "SPX",
    "expiry": "2025-06-20",
    "strikes": [4500, 4550, 4600, 4650, 4700],
    "maturities": ["1W", "2W", "1M", "3M", "6M"],
    "vol_matrix": [
      [0.185, 0.182, 0.180, 0.183, 0.190],
      [0.188, 0.185, 0.183, 0.186, 0.193],
      ...
    ],
    "updated_at": "2025-04-01T10:30:00Z"
  }
}

这里要注意,响应里我加了 status 字段。为什么?因为我在项目中遇到过,前端解析错误码时,HTTP状态码和业务错误码混在一起,调试起来特别痛苦。所以我习惯把业务状态单独拎出来。

我的小技巧:

分页查询曲面历史数据时,用 cursor 分页而不是 offset。曲面数据量大了以后,offset分页在数据库里会越来越慢。cursor分页虽然实现麻烦点,但性能稳定。

二、WebSocket实时推送:别让数据等太久

波动率曲面是实时变化的。尤其是期权做市商,每秒钟都在调整报价。RESTful轮询?那延迟能让你亏到哭。WebSocket才是正解。

我设计WebSocket接口时,分了三个频道:

频道名称 推送内容 推送频率
vol.surface.update 曲面数据变化(新增/修改) 实时(有变化即推)
vol.surface.snapshot 全量曲面快照 每5分钟一次
vol.surface.alert 异常波动告警 触发时推送

连接方式很简单:

// 客户端连接
const ws = new WebSocket('wss://api.volsurface.com/v1/ws');

// 订阅曲面更新
ws.send(JSON.stringify({
  "action": "subscribe",
  "channel": "vol.surface.update",
  "params": {
    "underlying": "SPX",
    "expiry": "2025-06-20"
  }
}));

// 接收推送
ws.onmessage = function(event) {
  const data = JSON.parse(event.data);
  // 更新前端曲面图
  updateSurfaceChart(data);
};

踩过的坑:

我曾经没做心跳检测,结果连接断了三天都没发现。后来加了每30秒一次的ping/pong机制,断线后自动重连。另外,推送数据别太大,曲面矩阵动辄几百个点,压缩一下能省不少带宽。

三、API安全与认证:别裸奔

波动率数据是核心资产。你想想看,要是被人爬走了曲面数据,那策略就白做了。安全这块,我分了三个层次。

3.1 认证:JWT + API Key

我习惯用双因子认证。API Key用于机器对机器的调用,JWT用于用户会话。

# 获取JWT Token
POST /api/v1/auth/login
{
  "api_key": "sk_live_xxxxx",
  "api_secret": "your_secret_key"
}

# 响应
{
  "token": "eyJhbGciOiJIUzI1NiIs...",
  "expires_in": 3600
}

# 后续请求带上Token
GET /api/v1/volatility/surfaces
Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

3.2 授权:细粒度权限控制

不是所有人都能看全量曲面。比如实习生只能看历史数据,交易员能看实时数据,管理员才能修改参数。我一般用RBAC(基于角色的访问控制)。

角色 可访问接口 说明
viewer GET /surfaces, GET /history 只读历史数据
trader GET /surfaces, WebSocket实时推送 可看实时数据
admin 全部接口(含PUT/POST/DELETE) 可修改模型参数

3.3 防护:限流与加密

限流是必须的。我见过有人用脚本疯狂刷接口,直接把数据库打挂了。我的做法是:

  • 每个API Key每分钟最多100次请求
  • WebSocket每个连接最多订阅5个频道
  • 所有传输走HTTPS,敏感字段(如曲面原始数据)用AES-256加密

避坑指南:

我曾经把API Key明文存在前端代码里,结果被用户抓包抓到了。后来改用后端代理转发,前端只存短期Token。另外,日志里别打印完整Token,只打后四位,方便排查又不泄露。

四、整体架构图

下面这张图是我做系统时的核心架构。你看一眼就明白数据怎么流转了。

客户端 Web / App / 量化终端 REST / WebSocket API 网关 认证 / 限流 / 路由 JWT验证 / 请求转发 服务层 曲面计算服务 / 数据聚合服务 WebSocket推送管理 数据层 Redis(缓存曲面数据) PostgreSQL(存储历史曲面) 图例 客户端 API网关 服务层 数据层

你看这个架构,客户端只跟API网关打交道。网关负责认证、限流、路由。服务层做真正的计算和推送。数据层存历史数据和缓存。各层职责清晰,出了问题也好排查。

五、总结

API设计这事儿,说白了就是三个字:稳、快、安全。稳是指接口设计要规范,别今天改个字段名明天改个路径;快是指实时数据推送要低延迟;安全是指别让数据裸奔。我在项目中吃过不少亏,但每次重构都让系统更健壮。嗯,希望这些经验能帮你少走弯路。


公众号:蓝海资料掘金营,微信deep3321