4. 开发环境搭建

CTP行情接入的第一步不是写代码,而是把“能编译、能连上、能收到行情”这条链路打通。很多初学者卡在环境阶段:头文件找不到、动态库加载失败、SimNow登录返回“不合法的登录”、行情前置连不上。本章按“获取—编译—依赖—账户—连接”的顺序,把每个环节的关键动作和常见坑讲清楚。

一、核心原理:CTP行情API的组成与运行机制

CTP行情API(MdApi)本质上是一套C++动态库,由交易所前置通过TCP推送行情,客户端通过API回调接收。它由三部分构成:

  • 头文件:ThostFtdcMdApi.h、ThostFtdcUserApiStruct.h、ThostFtdcUserApiDataType.h,定义接口与数据结构。
  • 动态库:Linux下为libthostmduserapi_se.so,Windows下为thostmduserapi_se.dll,是实际通信与回调的载体。
  • 回调接口:CThostFtdcMdSpi,开发者继承并实现OnFrontConnected、OnRspUserLogin、OnRtnDepthMarketData等方法。

行情API与交易API是两套独立库,行情只负责订阅与推送,不涉及报单。理解这一点,能避免把交易账户和行情账户混用。

CTP行情API运行链路与依赖关系 应用层 继承 MdSpi 实现回调方法 API接口层 ThostFtdcMdApi.h CreateFtdcMdApi 动态库 libthostmduserapi_se.so thostmduserapi_se.dll 行情前置 tcp://...:41213 SimNow / 生产 调用 加载 TCP通信

二、方法流程:从获取到编译的完整步骤

以Linux环境为例,标准流程如下:

  1. 获取API包:从期货公司官网或SimNow下载对应版本的CTP API压缩包,注意区分Linux/Windows、32/64位。
  2. 解压并规划目录:将头文件放入include/,动态库放入lib/,保持工程结构清晰。
  3. 编写最小可运行程序:创建MdApi实例、注册Spi、连接前置、登录、订阅。
  4. 编译链接:指定头文件路径与库路径,链接thostmduserapi_se。
  5. 配置运行时库路径:通过LD_LIBRARY_PATH或rpath让程序找到.so。
# 目录结构示例
ctp_demo/
├── include/
│   ├── ThostFtdcMdApi.h
│   ├── ThostFtdcUserApiStruct.h
│   └── ThostFtdcUserApiDataType.h
├── lib/
│   └── libthostmduserapi_se.so
└── main.cpp

# 编译命令
g++ main.cpp -o md_demo \
  -I./include \
  -L./lib \
  -lthostmduserapi_se \
  -Wl,-rpath,./lib \
  -lpthread -std=c++11

# 运行
./md_demo
使用 -Wl,-rpath,./lib 可以把库搜索路径写进可执行文件,避免每次手动设置 LD_LIBRARY_PATH,在部署时更省心。

三、依赖库配置与账户申请

CTP API依赖系统基础库,常见缺失包括libpthread、libstdc++、libcrypto等。若运行时报error while loading shared libraries,可用ldd检查依赖:

ldd ./md_demo | grep "not found"
# 若提示 libthostmduserapi_se.so => not found
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(pwd)/lib

账户方面,SimNow是官方模拟环境,注册后获得InvestorID、密码和BrokerID。行情前置地址通常为tcp://180.168.146.187:10131(具体以官网为准)。生产环境则由期货公司提供,需签署协议并开通行情权限。

项目SimNow模拟生产环境
BrokerID9999期货公司分配
行情前置tcp://180.168.146.187:10131期货公司提供
账户来源官网自助注册临柜/线上开通
费用免费按交易所标准
适用阶段开发调试实盘交易

四、模拟环境连接与常见误区复盘

连接SimNow的典型代码片段如下,重点在于RegisterFront与Init的调用顺序:

CThostFtdcMdApi* api = CThostFtdcMdApi::CreateFtdcMdApi("./flow/");
api->RegisterSpi(&spi);
api->RegisterFront("tcp://180.168.146.187:10131");
api->Init();
api->Join();  // 阻塞等待回调

登录成功后,OnRspUserLogin会返回交易日;随后调用SubscribeMarketData订阅合约,行情通过OnRtnDepthMarketData持续推送。

常见误区:
1. 把行情前置地址写成交易前置,导致连接失败;
2. 未实现OnFrontDisconnected,断线后无重连逻辑;
3. 在OnRtnDepthMarketData中做耗时操作,阻塞回调线程;
4. 忽略Join()或未正确释放API,导致进程退出异常。

复盘建议:先用官方Demo跑通,再逐步替换为自己的封装。每次连接失败,优先检查前置地址、BrokerID、InvestorID和密码四项,再排查网络与库路径。环境打通后,后续的行情标准化才有稳定的数据来源。