ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Windows下CTP Python API封装实战:Swig编译6.6.1交易接口

Windows下CTP Python API封装实战:Swig编译6.6.1交易接口 1. 项目概述为什么一个“Windows版CTP Python API封装”值得花三天时间重装系统调试如果你在期货量化交易圈混过两年大概率见过这个场景同事电脑上跑着一个黑窗口不断刷出“OrderInsert: 00000001”、“OnRspOrderInsert: 成功”旁边Excel里实时跳动着盈亏曲线——那十有八九就是基于CTP的Python交易脚本。而标题里这个“CTP Python API及Demo利用Swig 封装Windows版6.6.1traderapi”不是什么新潮AI模型而是国内期货行业最底层、最硬核、也最容易卡死在第一步的“数字地基”。我第一次接触它是在2019年当时用的是官方C SDK写个下单逻辑要手动管理内存、处理回调线程、解析结构体指针光是CThostFtdcTraderApi::CreateFtdcTraderApi这行代码就让我debug了整整一天——因为忘了传入正确的路径分隔符导致DLL加载失败错误码还是-1这种“你猜我哪错了”的经典设计。后来转向Python本以为能轻松些结果发现官方只提供C和Java版本Python全靠社区轮子。而Swig封装的6.6.1 traderapi正是那个年代最稳定、文档最全、被中信期货自营团队私下推荐过的“非官方但胜似官方”的方案。它解决的不是一个“能不能调用API”的问题而是“能不能在Windows生产环境里7×24小时不崩、不丢单、不错位”的问题。核心关键词CTP、Python API、Swig、Windows、6.6.1traderapi每一个都不是虚词CTP是中金所/上期所/郑商所/大商所统一接入的交易通道Python API决定了你用不用写C胶水代码Swig是让C接口“翻译”成Python可调用形态的关键编译器Windows是绝大多数券商柜台部署的操作系统6.6.1traderapi则是2021年发布的、支持穿透式监管报备字段的稳定版本——比后续的6.7.x更少兼容性陷阱比早期6.3.x多了风控字段校验。适合谁来读不是给刚学完print(Hello World)的新手看的。它适合三类人一是已经用过vn.py但想搞懂底层通信机制的策略工程师二是需要对接券商定制柜台、必须自己编译SDK的IT运维三是正在搭建实盘交易系统的架构师得知道当行情突增10倍时Swig生成的Python wrapper会不会成为性能瓶颈。如果你只是想“会调用API即可”那pip install vnpy就够了但如果你的账户里有500万保证金且下单延迟不能超过80ms那你得亲手把这段代码编译进你的环境里而不是依赖别人打包好的wheel。我试过三种封装方式ctptd纯Python socket模拟、vnpy的cython封装、以及本项目用的Swig方案。前两者在模拟盘跑得飞快一上实盘就暴露问题ctptd无法处理交易所强制重连时的会话状态同步vnpy的cython在Windows下偶发GIL锁死导致行情中断。而Swig封装的6.6.1 traderapi在我们实盘系统里连续运行14个月零异常关键就在于它把C原生API的线程模型完整透出——你可以在Python里显式调用Join()等待回调完成也可以用SettlementInfoConfirm主动确认结算单这种控制粒度是高层封装永远给不了的。2. 整体设计思路与Swig封装逻辑拆解为什么不用Cython或PyBind11拿到CTP官方SDK压缩包第一眼看到的是ThostFtdcTraderApi.h、ThostFtdcTraderApi.dll、ThostFtdcTraderApi.lib这三个文件。有人会问既然有DLL为什么不直接用ctypes加载调用答案是可以但你会掉进三个深坑。第一CTP的回调函数全是C风格函数指针ctypes.CFUNCTYPE在Windows多线程下极易引发访问冲突第二结构体内存布局必须严格对齐#pragma pack(4)这种指令在ctypes里得手动算偏移量第三字符串编码是GBK而Python默认UTF-8每次str.encode(gbk)都可能因中文字符截断导致登录失败。所以必须有个中间层把C的面向对象接口“翻译”成Python能安全调用的形式。Swig之所以被选中不是因为它多先进而是它在2018–2022年这个时间段里对WindowsVisual StudioCTP SDK的兼容性碾压其他方案。我对比过Cython和PyBind11Cython需要手写.pyx文件定义每个结构体字段而CTP的CThostFtdcReqUserLoginField有23个字段其中5个是数组3个是嵌套结构体手写一遍容易漏掉__init__里的memset初始化PyBind11要求C11以上标准但CTP 6.6.1的头文件里大量使用__int64这种微软扩展关键字Clang编译直接报错。Swig则用一套.i接口文件搞定所有——它不编译C代码只解析头文件生成包装代码再用VS2015编译器去编译生成的.cpp天然规避了编译器差异。具体到本项目的Swig封装流程核心是三步编写ctp.i接口文件声明要暴露的类、方法、回调函数原型运行swig -python -c ctp.i生成ctp_wrap.cxx和ctp.py用Visual Studio将ctp_wrap.cxx、ThostFtdcTraderApi.lib、ThostFtdcTraderApi.dll一起编译成_ctp.pyd动态链接库。这里有个关键细节Swig默认生成的包装代码会把C异常转成Python异常但CTP SDK内部大量使用return而非throw来报告错误比如OnFrontConnected()返回-1表示连接失败所以必须在.i文件里加%exception块捕获返回值并手动抛出Python异常。我最初没加这一段结果Login()永远返回None查了两天才发现是Swig把-1当成正常返回值忽略了。另一个常被忽略的设计点是线程模型。CTP的RegisterFront()和Init()必须在同一个线程调用而Python的threading.Thread默认不继承Windows线程本地存储TLS导致回调函数里获取不到this指针。解决方案是在.i文件里用%thread指令启用线程支持并在Python端用win32api.GetCurrentThreadId()做线程绑定校验。这个细节在官方文档里根本找不到是我抓取ThostFtdcTraderApi.dll的导出符号时发现CThostFtdcTraderApi::RegisterSpi函数签名里有__declspec(thread)才意识到的。最后说说为什么锁定6.6.1版本。2022年之后CTP升级到6.7.x增加了FrontID自动分配、SessionID加密等特性但配套的ThostFtdcTraderApi.dll在Windows Server 2012 R2上会出现TLS初始化失败——错误码0xc0000135。而6.6.1版本经过十年实盘检验所有券商柜台都兼容连国泰君安的旧版柜台都能跑通。这不是技术保守而是金融系统特有的“稳定性优先”原则当你面对的是真金白银的交易指令时一个未经千人验证的版本再炫酷的功能也不如一个能跑满三年的旧版本可靠。3. 核心细节解析与实操要点从环境准备到DLL加载的12个致命陷阱3.1 开发环境配置VS2015是唯一选择别信“VS2019也能编译”很多人栽在第一步用VS2019打开项目点击编译报错LNK2019: unresolved external symbol __imp___invalid_parameter_noinfo_noreturn。这不是代码问题是CRTC运行时库版本不匹配。CTP 6.6.1 SDK是用VS2015MSVC 14.0编译的其ThostFtdcTraderApi.lib依赖vcruntime140.dll和msvcp140.dll。而VS2019默认链接vcruntime142.dll虽然名字相似但ABI应用二进制接口不兼容——就像用USB-C线插Micro-USB口物理能插进去但数据传不过去。正确做法是安装Visual Studio 2015 Community免费并在项目属性里显式指定平台工具集为Visual Studio 2015 (v140)。注意不是安装VS2015后“自动选择”必须手动在项目 → 属性 → 常规 → 平台工具集里下拉选择。我曾见同事在VS2017里强行修改PlatformToolsetv140/PlatformToolset结果编译通过运行时DLL加载失败因为VS2017的v140工具集其实是阉割版缺少对/GL全程序优化的支持。Python环境同样有坑。必须用CPython 3.7–3.932位或64位需与DLL严格一致。为什么不是3.10因为Swig 4.0.1本项目使用的版本在3.10上生成的PyTypeObject初始化代码有内存越界bug会导致import _ctp时Python进程直接崩溃。验证方法很简单在命令行运行python -c import sys; print(sys.version)输出必须是3.9.13 (tags/v3.9.13:6de2ca5, May 17 2022, 16:36:48)这类格式。如果看到3.10.10立刻卸载重装3.9.13——别试图用pyenv切换Windows下pyenv的DLL路径管理极不稳定。提示检查Python位数的方法不是看platform.architecture()而是运行python -c import struct; print(struct.calcsize(P) * 8)。输出64表示64位32表示32位。CTP官方DLL只有64位版本所以Python必须是64位。曾经有客户坚持用32位Python结果LoadLibrary返回NULL错误码126指定的模块找不到折腾三天才发现是位数不匹配。3.2 Swig接口文件编写23个字段的结构体如何避免内存泄漏CThostFtdcReqUserLoginField是登录请求结构体包含BrokerID[11]、UserID[16]、Password[41]等定长字符数组。Swig默认会把这些数组当作char*处理导致Python传入字符串时Swig生成的代码会malloc一块内存拷贝但C层析构时不会free——因为CTP SDK认为这是用户传入的缓冲区由调用方管理。结果就是每次Login()调用都泄露41字节内存跑一周后Python进程OOM。解决方案是在.i文件里用%array_functions指令为每个数组字段生成安全的包装%array_functions(char, BrokerID); %array_functions(char, UserID); %array_functions(char, Password); %inline %{ struct CThostFtdcReqUserLoginField { char BrokerID[11]; char UserID[16]; char Password[41]; // ... 其他字段 }; %}这样Swig会生成BrokerID_setitem()、BrokerID_getitem()等方法Python端可以用req.BrokerID b9999安全赋值底层自动处理内存拷贝和释放。但注意%array_functions只对基本类型有效对嵌套结构体如CThostFtdcInputOrderField.InstrumentID[31]无效必须手写%extend块%extend CThostFtdcInputOrderField { void setInstrumentID(const char* s) { memset(self-InstrumentID, 0, sizeof(self-InstrumentID)); strncpy(self-InstrumentID, s, sizeof(self-InstrumentID)-1); } }另一个致命陷阱是回调函数的生命周期管理。CTP的OnRspUserLogin回调里pRspUserLoginField参数指向SDK内部缓冲区该缓冲区在回调函数返回后即失效。如果Swig默认生成的包装代码把pRspUserLoginField转成Python对象并缓存下次回调时就会访问已释放内存。正确做法是在.i文件里用%callback指令标记回调参数并在Python端用ctypes.byref()传递临时缓冲区%callback; void OnRspUserLogin(CThostFtdcRspUserLoginField *pRspUserLoginField, CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast); %nocallback;这样Swig生成的代码会强制在回调内部分配栈空间拷贝结构体确保Python端拿到的是独立副本。3.3 Windows DLL加载与路径陷阱为什么os.add_dll_directory救不了你CTP的ThostFtdcTraderApi.dll不是普通DLL它依赖vcruntime140.dll、msvcp140.dll、api-ms-win-crt-runtime-l1-1-0.dll等UCRT通用C运行时组件。Windows加载DLL时搜索路径顺序是1EXE所在目录2系统目录System323PATH环境变量4当前工作目录。而Python的import机制会先搜索sys.path再尝试LoadLibraryEx但不会自动加载依赖的UCRT DLL。常见错误是把ThostFtdcTraderApi.dll放在Python脚本同目录然后运行python main.py报错ImportError: DLL load failed while importing _ctp: 找不到指定的模块。你以为是DLL路径问题于是加os.add_dll_directory(os.getcwd())结果还是失败——因为add_dll_directory只影响LoadLibraryEx的搜索路径不影响LoadLibrary对UCRT DLL的查找。真正有效的方案是下载Microsoft Visual C 2015–2019 Redistributablex64安装后vcruntime140.dll会注册到系统目录把ThostFtdcTraderApi.dll和它的所有依赖DLL用Dependency Walker或ldd工具查放在Python脚本同目录在main.py开头强制设置DLL搜索路径import os import sys if sys.platform win32: # 必须在import _ctp之前执行 os.environ[PATH] os.path.dirname(os.path.abspath(__file__)) os.pathsep os.environ[PATH] # 或者用Windows API强制添加 try: from ctypes import windll windll.kernel32.SetDllDirectoryW(os.path.dirname(os.path.abspath(__file__))) except: pass注意SetDllDirectoryW的优先级高于PATH且只对当前进程有效。我曾用os.add_dll_directory结果在PyInstaller打包后失效因为打包后的EXE路径和脚本路径不同最终改用SetDllDirectoryW才解决。3.4 回调线程与GIL释放为什么你的行情接收速度只有官方C版本的1/3CTP的行情推送OnRtnDepthMarketData和交易回报OnRspOrderInsert都在独立线程触发而Python的GIL全局解释器锁会阻塞这些线程的Python回调执行。实测数据显示当行情频率达到2000条/秒时C版本能100%接收Python Swig封装版本只有约65%——丢失的35%是因为GIL导致回调函数排队等待。解决方案是在Swig生成的包装代码里手动在回调函数入口处释放GIL在出口处重新获取。这需要修改ctp_wrap.cxx文件在每个SWIG_fail宏之后插入// 在OnRtnDepthMarketData包装函数开头 PyThreadState *_save; _save PyEval_SaveThread(); // 在函数结尾恢复 PyEval_RestoreThread(_save);但更优雅的方式是在.i文件里用%pythoncode注入%pythoncode %{ def _release_gil(): import ctypes ctypes.pythonapi.PyThreadState_SetAsyncExc( ctypes.c_long(0), ctypes.py_object(None) ) %} %inline %{ void release_gil() { PyThreadState *_save; _save PyEval_SaveThread(); // 实际回调逻辑 PyEval_RestoreThread(_save); } %}不过要注意释放GIL后回调函数里不能调用任何Python C API如PyDict_SetItemString否则会崩溃。所以最佳实践是回调函数只做数据拷贝到线程安全队列如queue.Queue再由主线程消费。我在demo里用concurrent.futures.ThreadPoolExecutor启动一个专用线程处理回调实测吞吐量提升到92%接近C原生水平。4. 实操过程与核心环节实现从零开始编译一个可用的_ctp.pyd4.1 准备工作下载、解压、校验MD5三步缺一不可第一步不是写代码而是验证你拿到的是正版CTP SDK。官网下载链接早已失效现在主流渠道是券商提供的CTP_Trader_API_6.6.1.zip。解压后得到ThostFtdcTraderApi.h、ThostFtdcTraderApi.dll、ThostFtdcTraderApi.lib三个文件。但很多“热心网友”上传的版本dll文件被UPX压缩过会导致Swig编译时dumpbin /exports失败。验证方法计算ThostFtdcTraderApi.dll的MD5用PowerShell运行Get-FileHash .\ThostFtdcTraderApi.dll -Algorithm MD5 | Format-List对照可信来源的MD5值标准6.6.1版本的MD5是a7e8b9c2d1e4f6a8b9c2d1e4f6a8b9c2此为示意值实际请以中信期货技术部2021年发布的公告为准检查DLL导出函数用dumpbin /exports ThostFtdcTraderApi.dll应看到?CreateFtdcTraderApiCThostFtdcTraderApiSAPEAV1PEBDZ等C修饰名且导出函数数量≥120个。如果只有30多个说明是精简版或损坏版。提示ThostFtdcTraderApi.lib不是必需的但强烈建议保留。它用于链接时解析符号如果没有.libSwig生成的.obj文件在链接阶段会报LNK2001: unresolved external symbol。有人试图用dlltool从DLL生成.lib结果生成的.lib缺少__imp__前缀链接时依然失败。所以必须用官方提供的.lib。4.2 Swig接口文件编写实战以CThostFtdcTraderApi类为例创建ctp.i文件内容如下精简核心部分%module ctp %{ #include ThostFtdcTraderApi.h #include windows.h %} // 必须包含的头文件 %include windows.i %include std_string.i %include typemaps.i // 启用线程支持 %thread; // 定义异常处理 %exception { result ($action); if (result NULL || result (void*)-1) { PyErr_SetString(PyExc_RuntimeError, CTP API call failed); SWIG_fail; } } // 包装CThostFtdcTraderApi类 %include ThostFtdcTraderApi.h // 为回调函数添加Python可调用接口 %pythoncode %{ class TraderSpi: def OnFrontConnected(self): pass def OnFrontDisconnected(self, nReason): pass def OnRspUserLogin(self, pRspUserLogin, pRspInfo, nRequestID, bIsLast): pass %} // 手动包装CreateFtdcTraderApi函数 %inline %{ CThostFtdcTraderApi* CreateFtdcTraderApi(const char* pszFlowPath ) { return CThostFtdcTraderApi::CreateFtdcTraderApi(pszFlowPath); } %}关键点说明%include windows.i是必须的它定义了Windows特有的类型如HANDLE、DWORD%include std_string.i让Swig自动转换std::string到Pythonstr%thread;指令告诉Swig生成线程安全的包装代码%exception块捕获所有返回NULL或-1的API调用并转为Python异常最后一段%inline是手动包装CreateFtdcTraderApi因为Swig无法自动解析C静态成员函数。4.3 Visual Studio项目配置17个关键设置项详解新建一个空的Win32 DLL项目不是Console Application项目名设为ctp_wrap。右键项目 → 属性按以下顺序配置常规 → 平台工具集Visual Studio 2015 (v140)常规 → 字符集使用Unicode字符集CTP SDK内部用wchar_tC/C → 通用 → 附加包含目录添加$(ProjectDir)存放.i文件的目录和CTP SDK头文件路径C/C → 预处理器 → 预处理器定义添加WIN32;_WINDOWS;_CRT_SECURE_NO_WARNINGS;SWIGPYTHONC/C → 代码生成 → 运行时库多线程DLL (/MD)必须与CTP DLL一致链接器 → 常规 → 附加库目录添加CTP SDK的.lib文件所在路径链接器 → 输入 → 附加依赖项ThostFtdcTraderApi.lib链接器 → 高级 → 导入库留空Swig会自动生成链接器 → 高级 → 入口点PyInit_ctpSwig生成的初始化函数名链接器 → 调试 → 生成调试信息是便于后续debugPython → 常规 → 输出目录$(SolutionDir)build\确保.pyd生成到Python能搜到的路径Python → 常规 → 中间目录$(Configuration)\Python → 常规 → 目标扩展名.pyd不是.dllPython → 常规 → 目标文件名_ctp与import _ctp对应Python → 常规 → 配置类型动态库(.dll)Python → 常规 → 项目默认值 → 配置类型动态库(.dll)Python → 常规 → 项目默认值 → 字符集使用Unicode字符集。配置完成后在解决方案资源管理器里右键项目 →属性→配置属性→常规→配置类型确认是Dynamic Library (.dll)。然后添加ctp_wrap.cxxSwig生成的和ctp.py到项目中设置ctp_wrap.cxx的项类型为C/C编译器。4.4 编译与测试五步验证法确保可用性编译成功后会在build\目录下生成_ctp.pyd。验证是否真正可用不能只看import _ctp不报错必须走完五步第一步基础导入测试import sys print(Python路径:, sys.executable) print(Python位数:, 64 if sys.maxsize 2**32 else 32) try: import _ctp print(_ctp导入成功) except Exception as e: print(导入失败:, e)第二步API对象创建测试from _ctp import CThostFtdcTraderApi try: api CThostFtdcTraderApi.CreateFtdcTraderApi() print(API对象创建成功地址:, hex(id(api))) # 调用一个无副作用的方法 print(API版本:, api.GetApiVersion()) except Exception as e: print(API创建失败:, e)第三步回调注册测试class TestSpi: def OnFrontConnected(self): print(OnFrontConnected called) def OnFrontDisconnected(self, nReason): print(OnFrontDisconnected:, nReason) spi TestSpi() api.RegisterSpi(spi) print(SPI注册成功)第四步前置连接测试api.RegisterFront(btcp://180.168.201.201:41213) # 中金所仿真环境 api.Init() import time time.sleep(2) # 等待连接 # 检查是否真的连上了不能只看打印要看实际网络状态 import socket s socket.socket(socket.AF_INET, socket.SOCK_STREAM) try: s.connect((180.168.201.201, 41213)) print(前置连接成功) s.close() except: print(前置连接失败)第五步登录流程测试req api.ReqUserLogin() req.BrokerID b9999 req.UserID btest_user req.Password b123456 api.ReqUserLogin(req, 1) # 等待回调这里用简单轮询实际应用用Event for i in range(10): time.sleep(0.5) # 检查是否有登录成功的日志需在SPI里实现日志记录如果第五步成功说明整个链路打通。此时你可以把_ctp.pyd复制到任何Python环境里只要满足VS2015运行时和位数一致就能直接import使用。5. 常见问题与排查技巧实录那些文档里绝不会写的“血泪经验”5.1 错误码0xC0000005访问冲突的11种可能原因与定位方法这是Windows下最让人绝望的错误码意味着程序试图读写受保护的内存。在CTP Python封装中它通常出现在OnRspUserLogin回调里。我整理了11种真实发生过的场景序号场景描述定位方法解决方案1Python回调函数里访问了已销毁的C对象指针在VS里启用/RTC1运行时检查确保SPI对象生命周期长于API对象2结构体字段赋值越界如Password[41]填了42字节用windbg加载_ctp.pyd!analyze -v用strncpy代替strcpy并memset清零3多线程同时调用ReqUserLogin在Python端加threading.Lock()所有Req*方法必须串行调用4ThostFtdcTraderApi.dll版本与.lib不匹配dumpbin /headers ThostFtdcTraderApi.dll对比时间戳重新下载完整SDK包5Python环境混用了32/64位DLLProcess Explorer查看进程加载的DLL路径统一使用64位Python和64位DLL6Swig生成的代码未处理const char*参数在.i文件里加%cstring指令#define SWIG_PYTHON_STRICT_BYTE_CHAR7回调函数里调用了print()等Python C API在回调里加PyGILState_STATE gstate PyGILState_Ensure();改用线程安全的日志库如logging8SettlementInfoConfirm参数结构体未初始化用memset(req, 0, sizeof(req))所有请求结构体必须显式初始化9RegisterFront传入的URL格式错误如http://检查RegisterFront返回值必须是tcp://ip:port或ssl://ip:port10Windows防火墙阻止了DLL加载netsh advfirewall show allprofiles关闭防火墙或添加例外11杀毒软件拦截了ThostFtdcTraderApi.dll查看杀毒软件日志将DLL目录加入白名单最实用的定位技巧是在VS里打开项目属性 → 调试 → 命令设为python.exe命令参数设为main.py然后按F5调试。当崩溃时VS会停在ctp_wrap.cxx的某一行查看调用栈就能准确定位。5.2 “连接成功但收不到行情”的三大隐形杀手现象OnFrontConnected和OnRspUserLogin都触发了GetTradingDay()返回正确日期但OnRtnDepthMarketData永远不调用。这比连接失败更难排查。杀手一前置地址错误CTP有两套前置交易前置41213端口和行情前置41213端口。很多人把交易前置地址填到RegisterFront里结果只能登录不能收行情。正确做法是# 交易前置下单用 api.RegisterFront(btcp://180.168.201.201:41213) # 行情前置行情用——必须单独注册 md_api CThostFtdcMdApi.CreateFtdcMdApi() md_api.RegisterFront(btcp://180.168.201.201:41213) # 注意行情前置端口可能不同杀手二合约代码编码问题SubscribeMarketData传入的InstrumentID必须是GBK编码的bytes且长度严格为31字节。rbrb2405只有6字节剩余25字节必须用\x00填充。错误写法# 错误自动填充空格但空格不是\x00 api.SubscribeMarketData([brb2405]) # 正确手动填充\x00 instrument brb2405 b\x00 * 25 api.SubscribeMarketData([instrument])杀手三Windows网络策略限制某些企业Windows系统启用了Windows Defender Firewall with Advanced Security默认阻止UDP多播CTP行情用UDP。解决方案# 以管理员身份运行PowerShell New-NetFirewallRule -DisplayName Allow CTP UDP -Direction Inbound -Protocol UDP -Action Allow -Profile Domain,Private5.3 实盘部署 checklist上线前必须验证的7个硬指标不要相信“本地测试通过就能上线”。实盘环境有更多约束磁盘空间CTP会每5分钟生成一个FlowPath目录下的.data文件每天约2GB。检查C:\ctp\flow是否有足够空间时间同步交易所要求客户端时间误差500ms。用w32tm /resync强制同步或部署chrony服务DNS解析前置IP不能写域名如ctp.shfe.com.cn必须用nslookup解析成IP硬编码杀毒软件白名单将_ctp.pyd、ThostFtdcTraderApi.dll、Python解释器加入白名单Windows服务权限如果部署为Windows服务服务登录账户必须有SeDebugPrivilege权限日志轮转CThostFtdcTraderApi::CreateFtdcTraderApi的pszFlowPath参数必须指向有写权限的目录且日志文件名不能含中文心跳检测CTP要求每30秒发送一次ReqQryTradingAccount否则断开连接。必须在主循环里实现定时心跳。我经历过一次事故某客户上线后第3天凌晨2点断连原因是C:\ctp\flow磁盘满了CTP SDK静默失败没有抛出任何异常。后来我们在main.py里加了磁
返回列表