恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
用TqSdk从零搭建期货量化交易:行情订阅到自动化委托全流程实践
首页
资讯中心
/
用TqSdk从零搭建期货量化交易:行情订阅到自动化委托全流程实践
用TqSdk从零搭建期货量化交易:行情订阅到自动化委托全流程实践
发布时间:2026/10/15 6:00:37
做期货量化这条路我最初的两年基本是跟交易终端死磕过来的来回切窗口盯盘、手工敲单、用表格记盈亏一天下来手指比脑子还累还常因为止损单下晚了多亏冤枉钱。后来接触了TqSdk才第一次体验到行情接收、策略触发、自动下单整条链路能完完整整跑在Python程序里而不是靠人肉盯盘驱动。这篇实践记录我想把从环境搭建到跑通第一笔自动化委托、再到实盘化改造踩坑的整个过程摊开讲清楚。内容更适合两类人看一类是正在挑量化交易开发库的中小团队另一类是准备把自己的手工交易逻辑改写成代码的个人交易者。1. 从盯盘界面到写代码我为什么转向TqSdk1.1 传统手工盯盘的无力感以前做日内波段我需要同时盯三四个周期的走势再对照盘口挂单找进场点。信号出来了人得在几秒内完成切窗口、找合约、输价格、点确认这一串操作。频繁的时候一天来回十几次眼睛酸是小事真正让人崩溃的是手速跟不上信号。有一回我根据突破信号准备进场因为切换窗口慢了两秒价格直接跳空最后只能在更差的位置追进去当天那笔单子就亏损收场。这种经历多了以后我开始认真思考一个问题既然判断逻辑是明确的、可描述的为什么不让程序来执行当时团队里也有人提过直接对接底层交易接口但大家评估下来都觉得开发成本和维护成本有点高。后来有人拿TqSdk做了个Demo从行情订阅到自动下单只需要几十行代码我们才决定正式调研这个方案。1.2 TqSdk到底是个什么东西很多人第一次听到TqSdk会以为它是一个带Python接口的交易软件。事实上它的定位不太一样——它本质上是一个Python开发库直接连接行情和交易网关把行情推送、K线合成、账户查询、委托管理这些能力打包成了简洁的API。你不需要打开任何交易终端界面也不需要手动导出数据再导入Excel程序本身就是你的行情终端和下单终端。用一句话概括我的理解它把看盘和交易这两件事完全变成了程序内部的数据流。行情是数据订单是对象策略是一段循环逻辑。你写的代码就是在跟市场直接对话。1.3 为什么没有选更底层的接口可能有人会问既然要做量化为什么不直接用底层接口功能最全、性能最好这个我在调研阶段确实纠结过。后来拿我们自己的情况一算账就明白了底层接口确实强大但要自己处理通信协议、回报推送、断线重连、字段校验这些工程问题足够一个小团队忙上两三个月。而我们是做策略的不是做交易基础设施的。TqSdk的价值在于把交易通道这个复杂的基础设施封装好了让我们可以把精力集中在策略逻辑本身。这就像你要从A地到B地可以自己造一辆车也可以坐一辆调校好的车。造车能让你完全掌控每个零件但出发时间就遥遥无期了。对多数中小团队和个人交易者来说先跑起来比什么都重要。2. TqSdk的运行机制事件循环、K线合成与目标持仓2.1 wait_update()整个库的引擎点火器用TqSdk写程序绕不开一个方法wait_update()。第一次看到官方示例代码时我不太理解为什么每个例子都要在循环里反复调用它。后来才明白这个方法是整个库的引擎点火器——行情推送、数据更新、委托回报全都要靠它来驱动。你可以把它理解成一个水泵wait_update()每调用一次水泵就转一圈把最新的数据从服务端抽到你的程序里。如果你不调它程序里的行情数据就永远是静止的订单状态也不会变化。所以TqSdk的程序基本都是一个死循环结构循环里先调wait_update()然后检查你需要关注的数据有没有变变了就执行对应逻辑。from tqsdk import TqApi api TqApi() quote api.get_quote(某品种合约) # 替换为你的目标合约 while True: api.wait_update() # 驱动数据流动 if api.is_changing(quote): print(最新价:, quote.last_price)这个小例子虽然简单但它展示了一个很重要的思维转换你不必主动去请求行情只需要告诉库我关心这个合约然后它就源源不断地把更新推给你。这跟以前我写爬虫定时拉数据的思路完全不同。2.2 行情数据是推的不是拉的TqSdk的数据交互模式是服务端主动推送。你订阅一个合约后库会维护一个本地数据对象服务端每次推送变化这个对象就自动更新。is_changing()的作用就是告诉你这个对象在刚才那次更新中是否有变化避免你对没变化的数据做无意义的处理。K线的合成也是这个模式。你可以用get_kline_serial()拿到一个K线序列对象指定K线周期比如60秒、1天。库会在本地帮你把Tick级行情合成为对应周期的K线你不需要自己写合成逻辑。klines api.get_kline_serial(某品种合约, duration_seconds60) while True: api.wait_update() if api.is_changing(klines.iloc[-1]): print(最新60秒K线收盘价:, klines.iloc[-1][close])这里有个新手容易误解的细节K线对象的最后一行是正在形成中的K线它还在随时变化只有等它走完当前周期才会固定下来。后面我专门踩过这个坑这里先记住一个原则——信号判断尽量等K线闭合后再触发。2.3 目标持仓模型比裸下单更符合策略思维TqSdk里有两个层次的下单接口。一层是传统的裸下单——insert_order()你自己指定买卖方向、开平标志、手数、价格完全手动管理每一笔委托。另一层是set_target_volume()它实现的是目标持仓模型你告诉库我需要持有多少手剩下开仓还是平仓、开多少平多少全部由库自动计算和执行。这个设计我特别喜欢。因为策略本质上就是在表达我现在想持有多少仓位而不是我要下一张什么样的单子。目标持仓模型直接把策略逻辑和订单执行解耦了。比如你现在持有多单3手策略信号翻转了你想变成空单2手只需要调用set_target_volume(symbol, -2)库会自动把多单平掉再开空单。如果用裸下单你得自己算平3手再开2手中间还要处理可能成交不完整的情况。from tqsdk import TqApi, TqAccount api TqApi(TqAccount(某期货公司, 账号, 密码)) api.set_target_volume(某品种合约, 2) # 目标持仓2手多单 while True: api.wait_update()2.4 回测-仿真-实盘一条链路另一个让我觉得省心的点是TqSdk把回测、仿真交易和实盘交易用一套API串了起来。写策略的时候你可以直接在历史数据上做回测验证验证通过后切到仿真账户跑模拟盘模拟盘表现稳定了再把账户换成实盘账户。策略代码本身几乎不用改只是换一个账户对象。这意味着你从开发到实盘的整个流程用的都是同一套逻辑。策略在回测里怎么跑实盘就怎么跑不会出现回测好好的实盘总出问题这种最常见的人为偏差。对我们这种把大部分时间花在策略迭代上的团队来说这个一致性带来的价值非常高。3. 实操记录从环境准备到第一笔自动化委托3.1 环境准备与认证先聊环境。TqSdk是标准的Python库直接pip install tqsdk就能装。官方推荐的Python版本是3.7以上我们用3.9和3.10都跑过没有问题。安装本身很简单真正麻烦的是账号认证。要使用TqSdk你需要注册一个官方平台的账号然后在代码里配置账号信息。它区分了模拟盘和实盘两种账户类型模拟盘可以随时开通用来测试策略实盘则需要绑定真实的期货账户信息。第一次配置时我们团队一个同事把模拟盘的账号密码写错了程序一直提示认证失败排查了半天才发现是账号里多了个空格。这个提醒大家注意配置文件里尽量别手打密码复制粘贴也记得检查首尾有没有多余字符。pip install tqsdk认证的核心代码大概是这样的from tqsdk import TqApi, TqKq # 模拟盘认证 api TqApi(TqKq(你的模拟账号, 你的模拟密码))如果你是实盘账户只需要把TqKq换成TqAccount再传入期货资金账号、密码等信息即可。3.2 订阅行情和K线序列跑通认证后第一步是订阅行情。我们当时写了一个最简单的脚本订阅某品种主力合约的实时行情打印最新价和买卖五档。这个脚本的目的不是做策略而是验证网络链路通不通、数据推送是否流畅。from tqsdk import TqApi, TqKq api TqApi(TqKq(账密)) quote api.get_quote(某品种合约) while True: api.wait_update() if api.is_changing(quote): print(最新价:, quote.last_price, 买一:, quote.bid_price1, 卖一:, quote.ask_price1)实测下来行情推送延迟在可接受范围内对中低频策略完全够用。这里有个细节get_quote返回的报价对象包含很多字段比如last_price、bid_price1、ask_price1、volume、open_interest等官方文档里列得很清楚建议上手时先把这些字段都打出来看一遍对理解数据模型很有帮助。3.3 接入交易通道行情通了之后我们开始接交易通道。这一步的核心其实就是换账户对象。之前用模拟盘只需要账号密码接入实盘则需要期货账户信息。有一个重要的检查点在正式下单之前一定要先查询账户的资金和持仓情况确认你的程序读到的数据是真实的。我们当时写了个小函数启动时先打印账户可用资金和当前持仓确认无误后才进入主循环。这个习惯一直保留到现在每次重启程序都会做一次自检。3.4 第一笔自动化委托跑通第一笔自动化委托是我们项目里最有仪式感的时刻。我们用目标持仓模型下了一笔模拟单目标持仓设为1手多单。程序运行后库自动完成了开仓。我们全程没有手动操作任何交易软件只看到程序里打印出的委托状态变化已报、成交。from tqsdk import TqApi, TqKq api TqApi(TqKq(账密)) api.set_target_volume(某品种合约, 1) # 目标1手多单 while True: api.wait_update()这里要多说一句用set_target_volume下单的时候价格参数不是必须的默认按对手盘价格下单适合快速成交。但如果你对滑点敏感可以用set_target_volume(symbol, target, price)指定限价。这个函数还支持超价比例等参数具体可以查官方文档使用时注意自己的滑点容忍度。4. 实盘化改造中踩过的坑连接状态、数据回补与K线时序4.1 连接状态机与断线处理跑通模拟单之后我们很快就遇到了第一个实盘化的问题程序会断线。有一回模拟盘程序跑了几个小时突然卡住不动了行情数据一直不更新。排查后发现是网络连接断开了但程序没有任何感知还在傻傻地等数据。这个问题暴露了一个盲区wait_update()默认在连接断开时会阻塞等待如果你没有设置超时机制程序就会永久卡住。我们的解决办法是在主循环里检测连接状态字段比如账户的auth_station、trade_station等连接状态一旦发现异常就主动重启连接或退出程序并告警。while True: api.wait_update() if api.is_changing(account): if account.auth_station ! AuthOK: print(连接异常准备重启) break这个改造看起来简单但在实盘环境里价值巨大。因为实盘程序往往是7x24小时挂着的没人盯的时候断线卡死是最危险的故障。我们后来还加了看门狗机制程序异常退出后由外部脚本自动拉起尽量缩短无监控的空窗期。4.2 行情回补机制断线带来的另一个问题是数据缺口。重连之后断线期间错过的Tick数据不会自动补回来。如果你的策略依赖连续的高频数据比如统计过去N笔成交的分布这个缺口就可能导致计算错误。我们的处理思路分两层对于不依赖历史细节的策略让K线序列继续累积等待新K线闭合后自然覆盖缺口对于确实需要连续数据的场景在重连后主动拉取一段历史K线来重建状态。TqSdk提供了历史数据获取能力可以按时间段拉取分钟级或日线级数据重建成本不算高。这里我特别想提醒一点不要以为重连成功就万事大吉。重连只是恢复了链路数据层面的缺口需要额外补偿。实盘程序上线前一定要把断线重连数据补偿这个场景完整测试一遍别等实盘出了行情才手忙脚乱。4.3 未闭合K线的误判前面提到过K线序列的最后一根K线是正在形成中的它的收盘价会随行情不断变化。如果策略在K线未闭合时就触发信号可能会因为最后一两秒的波动产生错误信号就是我们常说的K线毛刺。我们曾有个策略在60秒K线临近收盘时判断突破结果多次出现假突破——价格在K线即将闭合时突破了阈值但马上又拉回来了。后来把策略改成等K线闭合确认后再计算信号虽然信号会延迟一点点触发但准确率明显提升。这个代价是值得的。判断K线是否闭合可以用K线对象的datetime字段和当前时间对比或者更简单地在一次wait_update()循环里检测到最后一根K线的datetime发生了变化说明新的一根K线开始了上一根已经闭合。这个模式在很多策略里都很常用。4.4 委托回报的时序问题实盘运行后我们还遇到过一个比较隐蔽的问题委托状态更新的时机。用目标持仓模型时库会拆成多笔委托逐步执行。如果你在主循环里立刻检查持仓可能发现目标持仓还没完全到位因为委托还没全部成交。这里要理解TqSdk的回报是异步推送的你发起委托后只是提交到交易所真正的成交回报要等撮合完成后才推回来。所以程序里必须有一个等成交的机制。我们写了个辅助函数循环调用wait_update()直到订单状态变为finished且成交量达到目标才返回。def wait_order_finished(api, order): while order.status ! finished: api.wait_update()这个细节在模拟盘上不容易暴露因为模拟盘成交速度极快。但实盘行情波动大的时候委托可能挂住很久不成交如果你的策略逻辑没有等待机制继续执行后续操作很容易造成超出预期的持仓风险。5. 用TqSdk搭日常量化工作流策略层与执行层分离5.1 策略层设计TqSdk把交易通道问题解决后我们开始搭建自己的量化工作流。第一步是把策略层和执行层分离。策略层只负责接收行情、计算信号、输出目标持仓——它不关心订单怎么拆、怎么报、怎么确认。执行层只负责把目标持仓变成实际委托并跟踪每笔委托的状态。这个分层的好处是策略代码可以保持纯净完全聚焦在交易逻辑上。我们内部约定了策略模块的统一输出格式一个字典包含目标持仓品种、方向、手数、失效时间等字段。执行模块拿到这个字典后统一处理。# 策略输出示例 signal { symbol: 某品种合约, target: 2, # 正数多单负数空单 expire: 2026-01-01 10:30:00 }也不是说TqSdk强制你这么分而是当你有多个策略需要同时跑在同一个账户上时如果不做这种分层很容易出现策略之间互相打架的情况。我们的做法是让执行层做持仓归并——每个品种最终只持有策略层给出的净目标持仓避免多个策略各自下单导致的冲突。5.2 执行层与风控层执行层之外我们额外加了一层风控层这层不做策略判断只做规则检查下单前检查可用资金是否足够、单笔下单手数是否超过上限、目标持仓是否触及风险阈值等。任一检查不过就拒绝执行这轮信号并告警。这个习惯是被一次模拟盘的教训逼出来的。有一回我们测试一个加仓策略逻辑写错导致目标持仓不断累加如果是在实盘环境后果很难收拾。从那以后我们就立了一条规矩任何策略信号都必须经过风控层校验才能进入执行模块。TqSdk本身不提供风控功能但因为它把下单接口封装得足够简洁我们只用了不到200行代码就实现了这层拦截。5.3 日志与监控量化的日常工作是跑程序和看日志。我们一开始并不重视日志后来一次程序毫无征兆地停止排查时发现没有任何记录只能靠猜。现在我们的程序会记录三类日志系统运行日志连接状态、异常信息、策略信号日志每次信号产生的时间、参数、目标持仓、委托成交日志每笔委托的报单、成交、撤单状态。监控方面我们给程序加了简单的告警通知程序异常退出、连接断开超过一定时间、单笔亏损超过阈值都会触发消息通知。我的经验是告警宁可多不可少少一次告警可能就多一笔亏损。尤其是长周期策略程序挂在服务器上几天不动没有告警系统的话半夜出了问题你都发现不了。6. 客观看待TqSdk的边界它解决不了哪些问题6.1 高频场景的瓶颈坦率说TqSdk不是为高频交易设计的。虽然它能提供Tick级行情但数据链路和委托链路的延迟并不适用于超高频套利场景。我们实测下来的结论是中低频策略分钟级、日线级用它非常顺手但如果你追求微秒级响应它显然不是合适的选择。这不算缺陷更多是定位问题。TqSdk面向的是用Python写好策略、稳定运行的群体而不是在极速柜台里比拼延迟的群体。选型之前想清楚自己的交易频率就不会对它有不切实际的期待。6.2 对第三方中转的依赖另一个需要认清的现实是TqSdk的数据和交易通道依赖第三方中转服务。这意味着你的程序和交易所之间多了一层节点。对合规要求特别严格的机构或者对数据链路自主性要求很高的场景这可能是个问题。我们的应对办法是把它用在非核心的低延迟敏感策略上同时保留另一条自主的数据通道做交叉验证。日常运行下来TqSdk链路稳定性在可接受范围内但可接受不等于零风险交易这行永远要给自己留备份方案。6.3 适用人群建议综合这段时间的使用体验我认为TqSdk最适合三类人个人量化交易者、小规模量化团队、以及需要快速搭建策略原型验证想法的研究型团队。如果你符合其中一类用它作为起步工具是很务实的选择。反过来如果你需要完全的链路自主可控或者你的策略本身就是超高频那可能需要评估更底层的解决方案。说到底工具的价值不在于它有多少华丽的功能而在于它能不能让你把精力花在真正重要的事情上。对我们来说把交易通道这件麻烦事外包出去换取更多时间去打磨策略这笔账怎么算都划算。最后分享一个我们自己的使用心得。最开始我们也是抱着试试看的心态接触TqSdk后来慢慢把它从模拟盘推到实盘整个过程走了不少弯路。如果你的团队也准备用它我的建议很简单先在模拟盘完整跑一个月把断线、数据缺口、委托状态这些基础问题全部暴露出来并解决掉再考虑上实盘。另外set_target_volume这个目标持仓模型值得多用它能让你的策略代码简洁很多——我们后来几乎所有策略的下单逻辑都改用目标持仓模型来表达代码量至少减少了一半。希望这篇实践记录能帮你少踩几个坑。