CTP C++客户端必须使用官方ThostTraderApi动态库,不可自行封装;需正确配置DLL/SO路径、继承CThostFtdcTraderSpi实现回调、RegisterFront传纯host:port地址、严格校验登录字段与时间同步、通过异步回调处理订单全生命周期。

ctp api 的 C++ 客户端必须用 CTP 官方提供的 ThostTraderApi 动态库,不能自己封装 TCP
CTP 不是标准 HTTP 或 WebSocket 接口,而是基于自研的二进制协议(类似 FIX 扩展)+ 本地 DLL/SO 的 C 风格回调接口。你写 C++ 程序时,本质是在调用中金所官方发布的 thosttraderapi.dll(Windows)或 libthosttraderapi.so(Linux),不是“对接 API”,而是“加载并驱动一个本地交易中间件”。
常见错误现象:undefined reference to 'CreateFtdcTraderApi' 或程序启动后 OnFrontConnected 死活不触发——大概率是没把 DLL 放对位置,或没正确设置运行时路径(PATH / LD_LIBRARY_PATH),或用了 32 位程序链接了 64 位 DLL。
- Windows 下确保
thosttraderapi.dll和你的 EXE 在同一目录,或在系统 PATH 中;不要试图用LoadLibrary手动加载再 GetProcAddress,官方头文件已封装好CreateFtdcTraderApi - Linux 下注意 GCC 编译时加
-L. -lthosttraderapi,且运行前执行export LD_LIBRARY_PATH=.:$LD_LIBRARY_PATH - 所有回调函数(如
OnRspUserLogin)必须继承CThostFtdcTraderSpi并重写,不能只写个普通函数;对象生命周期必须由你管理,别让 SPI 实例被提前析构
登录前必须先 RegisterFront,且地址不能带 tcp:// 前缀
CTP 的前置机地址是纯 host:port 字符串,比如 "180.168.146.187:41213",不是 URL。传错格式会导致 OnFrontConnected 永远不回调,也没有错误日志——它就静默失败。
使用场景:模拟交易、实盘、穿透式监管测试环境用的地址全不同,且每个地址只支持一种协议(TCP 或 UDP),不能混用。上期所和中金所的地址也不同,别拿上期所的地址去连中金所的柜台。
立即学习“C++免费学习笔记(深入)”;
-
RegisterFront必须在CreateFtdcTraderApi之后、Init之前调用;调一次就够了,多次调用不会覆盖,但也没必要 - 实盘地址通常由期货公司提供,格式类似
"tcp://xxx.xxx.xxx.xxx:xxxx"—— 注意,这里的tcp://是期货公司文档写的示意,实际传参时**必须删掉**,只留"xxx.xxx.xxx.xxx:xxxx" - 如果连的是穿透式监管网关(如恒生、金仕达),地址端口和认证方式可能额外要求填写投资者代码、席位号等字段,这些要填在
CThostFtdcReqUserLoginField里,不是地址里
ReqUserLogin 失败的常见原因不是账号密码错,而是校验字段没填全或时间不同步
CTP 登录失败时,OnRspUserLogin 的 nRequestID 和 pRspInfo 会返回错误码,但多数人只看 pRspInfo->ErrorID,忽略 pRspInfo->ErrorMsg 里的中文提示。真正卡住的往往不是“密码错误”,而是:ErrorID = 20(前置未连接)、ErrorID = 10(用户代码不存在)、ErrorID = 14(认证失败,常因客户端时间与服务器偏差 > 5 秒)。
性能影响:每次 ReqUserLogin 都会触发完整握手流程,频繁重试会触发风控限流,导致后续请求被拒绝。
-
CThostFtdcReqUserLoginField中TradingDay字段可为空(填""),CTP 服务端会自动填充;但UserID、Password、UserProductInfo(建议填 "program")、InterfaceProductInfo(填 "api")都不能为空字符串 - 客户端系统时间必须与 NTP 同步,误差控制在 3 秒内;否则
ErrorID = 14无解,改密码也没用 - 模拟交易账户首次登录需先在期货公司官网激活,否则返回
ErrorID = 11(用户未签约)
下单用 ReqOrderInsert,但成交回报在 OnRtnOrder 和 OnRtnTrade 里分开发,别只监听一个
CTP 把订单生命周期拆得很细:OnRtnOrder 推送委托状态变更(已报、已撤、部成、已成),OnRtnTrade 只推成交明细(一笔委托可能对应多笔成交)。新手常犯的错是只处理 OnRtnOrder,结果漏掉部分成交记录,导致持仓计算错误。
容易踩的坑:OnRtnTrade 的 OrderRef 和 OrderSysID 不一定与你发单时的 OrderRef 一致;实盘中柜台可能重发、乱序,必须用 TradeID 做幂等去重。
- 下单前务必检查
CThostFtdcInputOrderField中InstrumentID是否已通过ReqQryInstrument获取过,否则返回ErrorID = 23(合约不存在) -
LimitPrice对市价单(OrderPriceType = THOST_FTDC_OPT_AnyPrice)必须设为 0;对限价单则必须大于 0,且精度要匹配合约最小变动价位(比如 IF 主力合约是 0.2) - 实盘下单前建议先
ReqQryTradingAccount查可用资金,避免ErrorID = 30(资金不足)直接拒单
ReqXXX)返回值只是“是否成功提交到本地 API”,不代表服务器已处理;真正的结果全靠异步回调驱动,且回调可能延迟数百毫秒甚至丢包。别依赖 ReqOrderInsert 返回值判断下单成功。











