☰
TqSdk 开发指南:设计原则、asyncio 数据流与 Diff 协议技术内幕
2026/10/13 2:04:41 网站建设 项目流程
  • 金融科技

【免费下载链接】tqsdk-python

天勤量化开发包, 期货量化, 实时行情/历史数据/实盘交易

项目地址:https://gitcode.com/gh_mirrors/tq/tqsdk-python
点击查看免费下载

TqSdk 天勤量化开发包(tqsdk-python)不仅是一套面向策略用户的量化 SDK,其内部架构也遵循着一套明确的开发原则与规范。本文基于官方开发文档 doc/dev_general.rst,系统梳理 TqSdk 的三大设计原则(不预设用户策略模型、保持用户代码简单、行为可验证),并结合仓库源码剖析这些原则在TqApi、TqChan、Diff 协议、日志与单元测试框架中的具体落地方式。读完本文,你将理解 TqSdk 为什么是"同步写法 + 异步内核"的形态、为什么切换实盘/模拟/回测只需单点修改,以及如何利用日志复现线上问题并参与源码开发。

一、TqSdk 的三大设计原则

doc/dev_general.rst将 TqSdk 的开发纲领概括为三条原则。它们共同决定了仓库中每一行代码的形态,是理解全部源码的前提。

1. 不预设用户策略模型

量化交易是一个高度竞争与创新的领域,成功的用户总是在不断构思和尝试全新的理念与模型。在这方面,用户比库的开发者知道得更多、走得也更快。因此 TqSdk 在设计时尽力避免对用户的策略模型结构做任何限定,专注于提供通用性的资源和能力。文档中列出的三项设计决策印证了这一原则:

  • 不提供策略类模板,只以示例程序方式展示各类策略应用:仓库中不存在任何强制继承的Strategy基类,而是通过 tqsdk/demo/example/(双均线、网格、海龟、统计套利、价差交易等数十个示例)与 tqsdk/demo/tutorial/(t10 行情、backtest 回测、replay 复盘等教程)演示各类策略写法。
  • 一个策略程序中可以任意获取数据和发出指令:获取行情、K 线、下单、撤单等操作全部是TqApi上的平级方法,没有"数据阶段/决策阶段/执行阶段"的强约束流程。
  • 允许用户在一个程序中使用任意多个TqApi实例:同时操作多组行情与账户(如股票 + 期货并行),或借助 TqMultiAccount 在单个 api 内组合多个账户。

从源码看,TqApi的构造参数刻意设计成"组合式"而非"模板式":账户(实盘TqAccount、模拟TqSim、快期TqKq、众期TqZq、CTP 直连TqCtp等)、鉴权TqAuth、回测TqBacktest都是独立对象,见 tqsdk/api.py。用户按需传入即可,库本身不做策略框架假设。

2. 保持用户代码简单

TqSdk 的一个核心设计目标是:让用户的代码与需求方案保持一致(顺序相同、篇幅相当)。也就是说,策略逻辑"是什么样就写成什么样",而不是被 SDK 的复杂度"污染"。

对应四项设计决策:

设计决策含义源码佐证
不使用多线程避免用户处理线程同步问题整个 tqsdk 源码目录中不存在import threading,并发全部基于asyncio单线程协程模型
不使用回调模型避免用户维护状态机状态变量用户代码以api.wait_update()驱动的"主动查询"写法为主,数据更新由 is_changing 判断,而非注册回调
提供专门的调仓工具把"目标持仓→拆单→下单"的机械工作交给库TargetPosTask、TargetPosScheduler、InsertOrderTask等封装在 tqsdk/lib 中
实盘/模拟/回测单点切换运行模式切换只需改一处代码见下文"模式切换"小节

典型的用户代码只有十来行,却完成了"订阅行情→计算信号→目标持仓调整→循环等待"的完整闭环,例如官方教程 tqsdk/demo/tutorial/backtest.py:

from datetime import date from tqsdk import TqApi, TqAuth, TqBacktest, TargetPosTask api = TqApi(backtest=TqBacktest(start_dt=date(2018, 5, 1), end_dt=date(2018, 10, 1)), auth=TqAuth("快期账户", "账户密码")) klines = api.get_kline_serial("DCE.m1901", 5 * 60, data_length=15) target_pos = TargetPosTask(api, "DCE.m1901") while True: api.wait_update() if api.is_changing(klines): ma = sum(klines.close.iloc[-15:]) / 15 if klines.close.iloc[-1] > ma: target_pos.set_target_volume(5) # 目标多头 5 手 elif klines.close.iloc[-1] < ma: target_pos.set_target_volume(0) # 目标空仓

这段代码没有多线程、没有回调、没有状态机,与"价格高于 MA 就多、低于就平"的需求描述几乎一一对应——这正是"保持用户代码简单"原则的直接体现。

3. 行为可验证

作为库质量管控的关键措施,TqSdk 要求运行时可以记录完整的输入信息,确保发生问题时可以稳定重现问题和定位原因。对应三项设计决策:

  • 以数据流衔接库中的各组件:组件之间不直接互相调用,而是通过通道传递数据包,使数据走向可追踪、可插拔(详见第二节)。
  • TqSdk 的日志文件完整记录收到的全部数据包:日志默认写入~/.tqsdk/logs/目录,见 tqsdk/log.py。
  • 专门构建了一个单元测试框架,可以直接用日志作为测试用例输入:开发文档中对应的 doc/dev/unittest.rst 记录了这一设计;把真实运行日志作为回放输入,可以精确复现历史数据到达顺序,从而稳定重现 BUG。

二、设计原则的落地:TqChan 数据流与 asyncio 内核

"保持用户代码简单"与"行为可验证"在架构层面的统一解是:内部用 asyncio 协程 + 数据流管道,外部向用户暴露同步风格 API。

1. TqChan:本质是一个 asyncio.Queue

配套开发文档 doc/dev/framework.rst 明确指出:

TqSdk 中以数据流的方式连接各组件。TqChan(本质是一个 asyncio.Queue)被用作两个组件间的单向数据流管道,一个组件向 TqChan 中放入数据包,另一个组件从 TqChan 中依次取出数据包。

源码中TqChan直接继承自asyncio.Queue(tqsdk/channel.py),并支持last_only(只保留最后一个对象)等参数。作为开发调试的辅助,可以设置TqChan._level = 10让内部 chan 传输的数据也打印到日志中,方便追踪数据包流转:

from tqsdk import TqChan TqChan._level = 10

2. 实盘数据流:上行与下行

doc/dev/framework.rst给出了实盘模式下组件与通道的全景:行情网关与交易网关各有一个 websocket 客户端(TqConnect),中间组件(TqAccount等)与TqApi之间通过 6 条通道衔接:

  • md_send_chan/md_recv_chan:行情方向的上行/下行管道
  • td_send_chan/td_recv_chan:交易方向的上行/下行管道
  • api_send_chan/api_recv_chan:与TqApi主循环衔接的管道

数据包上行流程(以报单为例):

  1. 用户程序调用TqApi.insert_order等需要发出数据包的功能函数;
  2. 该函数生成一个数据包,放入api_send_chan;
  3. TqAccount从api_send_chan取出数据包,根据aid字段决定放入td_send_chan;
  4. 连接到交易网关的 websocket client 从td_send_chan取出数据包,通过网络发出。

数据包下行流程(以接收行情为例):

  1. 连接到行情网关的 websocket client 从网络收到一个数据包,放入md_recv_chan;
  2. TqAccount从md_recv_chan取出数据包,放入api_recv_chan;
  3. TqApi从api_recv_chan取出数据包,将其中携带的行情数据合并到内存存储区中。

每个环节的日志中都会带chan_id/conn_id等结构化字段(见 tqsdk/channel.py),配合日志可以完整还原某一数据包从网络到用户可见对象的全路径——这正是"行为可验证"的架构保障。

3. 模式切换:单点修改如何做到

基于"组件可插拔"的数据流结构,通过简单更换部分组件即可实现不同工作模式:

  • 模拟交易:用TqSim替换TqAccount,本地完成撮合成交(tqsdk/tradeable/sim/);
  • 回测:在TqSim之上再插入TqBacktest组件,由它从回测行情服务拉取历史数据并按start_dt/end_dt推进时间(tqsdk/backtest/backtest.py),backtest_send_chan/backtest_recv_chan取代实盘通道。

因此用户代码中唯一的差异就是TqApi构造参数。对比两个官方教程即可验证"单点修改":

实时行情(tqsdk/demo/tutorial/t10.py):

from tqsdk import TqApi, TqAuth api = TqApi(auth=TqAuth("快期账户", "账户密码")) # 默认使用内部模拟账户 TqSim quote = api.get_quote("SHFE.ni2206") print(quote.datetime, quote.last_price) api.close()

回测(tqsdk/demo/tutorial/backtest.py):

api = TqApi(backtest=TqBacktest(start_dt=date(2018, 5, 1), end_dt=date(2018, 10, 1)), auth=TqAuth("快期账户", "账户密码"))

实盘则把第一个参数换成TqAccount("期货公司", "资金账号", "密码")即可。策略主体代码完全不变。

值得一提的是回测模式下wait_update每次最多推进一个行情时间,回测结束时会抛出BacktestFinished异常(tqsdk/backtest/backtest.py),这是策略循环退出回测的标准途径,开发者编写/调试回测代码时应予以处理。

三、用户视角的"同步写法":wait_update 与 is_changing

"不使用多线程、不使用回调模型"落到实处,是TqApi提供的一对核心原语:

  • wait_update(deadline):这是 TqApi 主循环里最重要的函数(tqsdk/api.py)。调用时当前线程会阻塞,直到收到业务数据更新或到达deadline。每次调用都会顺带完成:实际发出待发送的网络请求(订阅、下单、撤单)、推进后台任务(如TargetPosTask调仓)、尝试接收并合并新的业务数据包。不填deadline时无限等待;填写后超时返回False。
  • is_changing(obj, key):在wait_update返回后,判断本次更新是否包含特定对象或字段(tqsdk/api.py)。key可以是单个字段名或字段名列表;不指定则任意字段更新都视为变化。is_changing内部通过比对"待处理 diff 列表"(self._diffs/self._sync_diffs)与对象路径实现,这也是它需要与wait_update配对使用的原因。
while True: api.wait_update() if api.is_changing(quote, "last_price"): print(quote.last_price)

这一"同步风格循环 + 内部异步调度"的写法,让不了解 asyncio 的用户也能写出正确的策略;而开发者阅读源码时则需要理解背后的协程模型(见第四节)。

四、参与 TqSdk 开发所需的知识与技能

doc/dev_general.rst明确列出了理解与改进 TqSdk 代码前需要掌握的四块知识点。下面结合源码逐项说明其在仓库中的落点。

1. 金融相关业务知识

TqSdk 是用于金融交易领域的专用软件包,文档假定用户和开发者已具备相应基础知识(合约、订单类型、保证金、涨跌停、换月等),并在文档中不再详加解释。策略业务字段(如pos_long、pos_short、float_profit)定义于 tqsdk/objs.py,交易账户类(期货、期权、股票、资管柜台)实现于 tqsdk/tradeable/,均以金融业务概念为语义基础。

2. Python asyncio

TqSdk 的代码大量依赖 python asyncio 机制,这是内部并发模型的基石:

  • TqApi维护自己的事件循环,wait_update在内部驱动该循环处理待发/待收数据包;
  • TqChan本质是asyncio.Queue,通道两端的"生产者/消费者"都是协程;
  • websocket 通信基于异步库(见 tqsdk/connect.py 中的import asyncio、import websockets);
  • 用户还可以通过api.create_task(coro)把自己的异步任务纳入 TqApi 循环统一调度(tqsdk/api.py)。

文档特别提醒:对使用者,TqSdk 尽量隐藏了 asyncio 概念,允许用户在不了解 asyncio 的情况下实现绝大多数业务需求;但对开发者,若不了解 asyncio,理解 TqSdk 内部实现会非常困难。与之配套的异步开发细节见 doc/dev/async_tool.rst。

3. Diff 协议

TqSdk 并不是一个 all-in-one 的包,它的能力有赖于一系列后台服务(行情网关、交易中继网关)的支持。Diff 协议是 TqSdk 与后台服务间通讯的主要协议,也是"以数据流衔接组件"的直接体现:

  • 网关统一以 Diff 协议对下方提供服务(见 README.md 的"系统架构"说明);
  • 客户端侧,TqApi按照 Diff 协议推荐的实践,使用单一变量_data存储全部业务数据(行情 + 交易),结构分层为quotes/klines/ticks/trade等(详见 doc/dev/framework.rst);
  • 核心合并函数是 tqsdk/diff.py 中的_merge_diff:将收到的 diff 包递归合并进内存数据,同时同步发送更新通知,保证"业务数据更新与通知"是原子操作;reduce_diff参数还支撑了is_changing需要"真正有变化的字段"这一场景。

理解 Diff 协议,才能掌握 TqSdk 内部实现的精髓——包括增量更新、断线重连后如何重建完整数据截面(TqReconnectHandler的职责之一,见 tqsdk/connect.py)。

4. Pandas / NumPy

Pandas/NumPy 是非常优秀的 Python 数值计算库,TqSdk 利用它们完成K 线序列数据的存储和操作:

  • api.get_kline_serial()返回的是 pandas DataFrame 形态的序列对象(见 tqsdk/api.py),klines.close.iloc[-1]、sum(klines.close.iloc[-15:]) / 15这类向量化计算直接可用;
  • 内部还针对不同 pandas 版本兼容了底层BlockPlacement/FloatBlock等内部结构(tqsdk/api.py),说明 TqSdk 对 pandas 的适配是深度级别的;
  • 技术指标与计算函数位于 tqsdk/ta.py、tqsdk/tafunc.py,示例见 tqsdk/demo/ta.py。

五、行为可验证的工程配套:日志与调试

"行为可验证"不是口号,而是有具体的工程配套。理解这些,无论排查问题还是参与开发都事半功倍。

1. 日志文件的位置、命名与清理

源码 tqsdk/log.py 定义了默认日志行为:

  • 日志目录:~/.tqsdk/logs(首次使用时自动创建);
  • 文件名格式:%Y%m%d%H%M%S%f-{进程号}.log,即每个进程启动即生成独立日志文件;
  • 日志内容:完整记录收到的全部数据包,配合TqChan._level = 10可进一步记录内部 chan 流转的数据;
  • 清理策略(_clear_logs):默认保留最近 30 天(可用环境变量TQ_SAVE_LOG_DAYS调整),并且保证磁盘剩余空间大于 3G,且最近 3 个自然日(至少一个最近交易日)的日志永不清除。

当出现持仓、成交、行情对不上等问题时,把对应时间段的日志连同复现脚本一起提供给开发者,即可用日志回放定位问题——这正是单元测试框架"以日志作为测试用例输入"的前提。

2. 单元测试与开发文档导航

参与开发的完整入口是 doc/dev/index.rst,其中按general(原则与规范,即本文)、framework(整体结构)、async_tool(异步工具)、gui、backtest、unittest(单元测试)等主题组织。其中 doc/dev/framework.rst 提供了文件结构、数据流图与内存数据结构的详细说明,建议与本文配套阅读。

六、代码风格与开发约定

TqSdk 的代码风格遵循PEP8 规范(见 doc/dev_general.rst)。仓库中可观察到的配套约定还包括:

  • 模块划分清晰:api.py(TqApi 主接口)、objs.py(业务数据结构)、diff.py(Diff 协议实现)、channel.py(数据流管道)、connect.py(网络连接与重连)、log.py(日志)各司其职,与 doc/dev/framework.rst 的文件结构说明一致;
  • 工程配置齐全:setup.py/setup.cfg/requirements.txt与MANIFEST.in位于仓库根目录,供安装与打包使用;
  • 安装方式:TqSdk 支持 Python 3.9 及以上版本,可通过pip install tqsdk安装(见 README.md)。

结语

TqSdk 的三条设计原则——不预设用户策略模型、保持用户代码简单、行为可验证——并不是抽象的口号,而是贯穿了TqApi的同步风格 API、TqChan的数据流管道、Diff 协议的增量数据管理、~/.tqsdk/logs的完整日志以及"日志即测试用例"的测试思路。理解这些原则,你就掌握了阅读与改进 TqSdk 源码的钥匙:从 tqsdk/api.py 的主循环进入,沿TqChan顺藤摸瓜,用 Diff 协议解释数据更新,用日志验证每一个数据包的来龙去脉,即可快速融入这个成熟量化 SDK 的开发工作。

  • 金融科技

【免费下载链接】tqsdk-python

天勤量化开发包, 期货量化, 实时行情/历史数据/实盘交易

项目地址:https://gitcode.com/gh_mirrors/tq/tqsdk-python
点击查看免费下载
上一篇:sway-farm前端自动化测试:Jest与React Testing Library实践
下一篇:GitBucket前端框架选型解决方案指南:方法论与工具选型

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询