3. CTP行情接口概览

在CTP衍生品交易系统中,行情接入是所有策略、风控与监控模块的“第一公里”。行情接口负责把交易所的报单簿变化、最新价、成交量、持仓量等数据,以标准化结构推送给上层应用。理解CTP行情API的分类、版本演进、连接方式、前置地址与通信流程,是后续做行情标准化、断线重连、多路复用与性能优化的前提。

一、核心原理:行情API的分类与版本演进

CTP行情接口在官方层面主要分为两类:一类是面向期货的MdApi(Market Data API),另一类是面向期权及部分组合行情的扩展接口。MdApi以C++动态库形式提供,核心类为CThostFtdcMdApi,通过继承CThostFtdcMdSpi回调类接收行情。其典型生命周期为:创建实例、注册前置地址、注册SPI、登录、订阅、接收回调、登出、释放。

版本演进方面,CTP行情接口经历了从早期6.3.x到6.5.x、6.6.x、6.7.x的迭代。主要变化集中在:前置地址协议从纯TCP扩展为支持tcp://与ssl://;行情订阅支持更细粒度的合约过滤;部分版本增加了对OnRspSubMarketData返回码的细化;同时API对多线程回调的线程安全性逐步增强。生产环境中,版本必须与柜台、前置、操作系统位数严格匹配,否则会出现“能登录但收不到行情”或“订阅返回成功但无回调”的典型问题。

版本选择原则:优先与柜台服务端版本保持一致;若使用SimNow等仿真环境,需确认其支持的API版本范围,避免高版本API连接低版本前置。

二、连接方式与前置地址

CTP行情连接采用“客户端API → 行情前置 → 交易所行情源”的三段式结构。客户端通过RegisterFront注册一个或多个前置地址,API内部维护连接池与自动重连。前置地址通常形如:

tcp://180.168.146.187:10131
tcp://180.168.146.187:10132
ssl://180.168.146.187:10133

其中tcp://为明文传输,ssl://为加密传输。生产环境建议至少配置两个不同前置,形成主备冗余。需要注意的是,RegisterFront只是“注册候选地址”,真正连接发生在Init()调用之后;若在Init()之后再注册前置,通常不会生效。

连接方式上,行情API与交易API是两套独立实例,行情前置端口与交易前置端口不同,不能混用。行情登录只需要BrokerID、UserID、Password,不涉及资金账户,因此行情登录比交易登录更轻量,但同样受“一个用户多终端登录”限制。

CTP行情接入三段式结构与通信路径 客户端行情API CThostFtdcMdApi MdSpi 回调 订阅/登录/重连 行情前置 tcp:// 或 ssl:// 主备双路 端口独立于交易 交易所行情源 报单簿/最新价 成交量/持仓量 时间戳/合约状态 基本通信时序(简化) 1. CreateFtdcMdApi → 2. RegisterFront → 3. Init → 4. OnFrontConnected 5. ReqUserLogin → 6. OnRspUserLogin → 7. SubscribeMarketData → 8. OnRspSubMarketData 9. OnRtnDepthMarketData 持续推送 → 10. 断线后 OnFrontDisconnected → 自动重连

三、基本通信流程与关键回调

行情API的通信流程可以概括为“创建—注册—初始化—登录—订阅—回调—重连”。其中最容易出错的环节是回调顺序与线程模型。以下为典型C++伪代码:

CThostFtdcMdApi* mdApi = CThostFtdcMdApi::CreateFtdcMdApi("./flow/");
mdApi->RegisterSpi(&mdSpi);
mdApi->RegisterFront("tcp://180.168.146.187:10131");
mdApi->RegisterFront("tcp://180.168.146.187:10132");
mdApi->Init();
// 等待 OnFrontConnected 后:
CThostFtdcReqUserLoginField login = {0};
strcpy(login.BrokerID, "9999");
strcpy(login.UserID, "user01");
strcpy(login.Password, "pass01");
mdApi->ReqUserLogin(&login, 1);
// 登录成功后:
char* instruments[] = {"rb2510", "au2512"};
mdApi->SubscribeMarketData(instruments, 2);

关键回调包括:OnFrontConnected(前置连接成功)、OnFrontDisconnected(前置断开,需触发重连)、OnRspUserLogin(登录响应)、OnRspSubMarketData(订阅响应)、OnRtnDepthMarketData(深度行情推送)。其中OnRtnDepthMarketData是数据量最大的回调,必须避免在其中做阻塞操作,否则会拖慢整个行情线程。

常见误区:在OnRtnDepthMarketData中直接写数据库或做复杂计算,会导致回调堆积、行情延迟甚至丢包。正确做法是回调中只做浅拷贝入队,由独立线程消费。

四、案例/场景与误区复盘

场景:某量化团队在SimNow环境接入行情,登录成功、订阅返回成功,但始终收不到OnRtnDepthMarketData。排查发现:一是订阅的合约代码未加交易所后缀或大小写不匹配;二是SubscribeMarketData在OnRspUserLogin之前调用,被API内部丢弃;三是前置地址只注册了一个且该前置已失效。修正后,先等待登录回调,再订阅,并配置主备前置,行情恢复正常。

环节 关键对象/参数 常见问题 排查要点
创建与注册 CreateFtdcMdApi、RegisterFront Init后再注册前置无效 确保RegisterFront在Init之前
连接 OnFrontConnected 前置地址错误或端口不通 telnet测试端口,检查tcp/ssl
登录 ReqUserLogin、BrokerID BrokerID与环境不匹配 仿真与生产BrokerID不同
订阅 SubscribeMarketData 合约代码格式错误 确认交易所后缀与大小写
推送 OnRtnDepthMarketData 回调阻塞导致延迟 入队异步处理,避免阻塞
重连 OnFrontDisconnected 未重新登录与订阅 重连后需重走登录与订阅

复盘结论:CTP行情接入的稳定性,不取决于单次连接成功,而取决于“断线—重连—重新登录—重新订阅—恢复推送”这一闭环是否完整。工程上应把前置地址、登录参数、订阅列表做成配置化,并在OnFrontDisconnected中触发带退避的重连策略。只有把通信流程的每个回调都纳入状态机管理,后续的行情标准化与多路复用才有可靠基础。