简介:这份《同花顺level-2全推行情Python API操作手册》面向从事高频交易、量化投资及涨停板策略的开发者与交易者,系统讲解如何通过Python API获取并处理沪深市场Level-2高频行情数据。手册以PDF形式提供,压缩包内共1个文件,约850KB,内容紧凑、便于随查随用。目前已有2813人学习下载,在证券量化圈内具备一定参考热度。手册围绕TDS系统的C/S架构展开,涵盖五档与十档行情快照、逐笔成交、逐笔委托、委托队列及极速盘口等数据类型的订阅与回调处理,并完整梳理了从V2.0.0到V2.1.9的版本演进,包括多连接模式、级联功能、异步订阅接口、离线调试、通道号与委托序号字段、快照字段类型由int改为float等关键变更。读者可据此掌握初始化TDS实例、注册回调函数、设置连接市场与超时时间等实操要点,理解运行环境要求与安装验证流程,为搭建低延迟行情接入与量化策略提供清晰指引。
1. 拆开一份 Level-2 全推行情 Python 手册:涨停板策略到底能不能靠它落地
做涨停板排板的人最怕什么?不是选不到票,是行情慢半拍。你盯着五档盘口,看到封单突然撤了一大截,手速再快也来不及,因为数据到你这里已经隔了几百毫秒。这份《同花顺level-2全推行情Python API操作手册》要解决的,就是把这个延迟压下来,让 Python 直接吃到沪深两市的 Level-2 全推数据——十档盘口、逐笔成交、逐笔委托、委托队列,还有极速盘口。它适合两类人:一类是做高频或准高频策略的量化开发者,另一类是想把涨停板封单变化、撤单节奏做成可回测信号的交易系统搭建者。手册本身是 SDK 的接口说明加版本修订记录,从 V2.0.0 一路更到 V2.1.9,中间踩过的坑基本都写在修订说明里了。下面我按实际接入的顺序,把这份手册拆成能直接抄作业的步骤。
2. TDS 系统架构与 Python 环境落地:从 tar.gz 到 import datafeed
2.1 为什么是 C/S 结构而不是纯 Python 库
TDS 这套系统没有走纯 Python 实现的路子,而是 C/S 架构:底层用 C/C++ 从交易所 VDE 接入行情,做解码和订阅分发,Python 只是作为 API 的一层封装。这么设计的原因很直接——Python 的 GIL 在高频回调场景下会成为瓶颈,如果解码和分发都在 Python 层做,逐笔数据的吞吐根本扛不住。实际的数据流是:交易所 VDE → TDS 服务端(解码、订阅管理)→ SDK(C++ 动态库)→ Python API 回调。你拿到的data_list已经是解码后的结构化数据,Python 层只负责业务逻辑。
这个架构决定了两个事:第一,Python 端的回调函数里绝对不能做耗时操作,手册里专门警告了“否则很可能会导致接收实时行情堵包”;第二,SDK 的版本更新往往涉及底层协议变化,不是简单换个 py 文件就能解决的。
2.2 安装:root 权限和 import 验证
Linux 下安装需要 root 权限,这是第一个容易翻车的地方。很多人用普通用户pip install完了发现 import 报错,其实是动态库没写进系统路径。
# Linux 下需要 root 权限安装 sudo pip install ./L2-tdsapi-python-X.X.X-XXXXXXXX.tar.gz # 或者用 setup.py 方式 sudo python setup.py install安装完成后必须做一步验证,手册里写得很清楚:
# 进入 Python 环境后执行 import datafeed # 没有异常抛出即为安装成功如果这一步报ImportError,先检查 Python 版本是不是 3.5 以上 64 位,再检查动态库路径。Windows 下一般不会有权限问题,但要注意 SDK 的位数必须和 Python 解释器一致——64 位 Python 配 32 位 SDK 是经典翻车场景。
2.3 硬件和网络的门槛
手册给的运行环境要求是:64 位双核以上 CPU、8G 以上内存、下行 100Mb 以上带宽。这个配置看起来不高,但实际跑全市场订阅的时候,内存消耗主要来自回调函数里积压的数据。如果你在回调里做 DataFrame 拼接,8G 很快就不够了。我一般建议把回调里的数据处理逻辑做成“收到即入队列,另起线程消费”的模式,避免堵包。
网络方面,Level-2 全推的数据量在开盘时段非常密集,100Mb 下行是底线。如果同时订阅沪深两市的逐笔和快照,实际带宽占用会更高。手册里 V2.0.0 提到“SDK由单连接改为多连接模式,需要针对不同市场注册域名和端口”,这意味着沪深两市的连接是独立的,网络层面也要保证两条链路都稳定。
3. 回调注册与登录:set_env 的参数怎么填才不堵包
3.1 回调函数的定义规范
TDS 的所有行情数据都通过回调函数推送到应用层。手册里定义了 6 个行情回调加 1 个通知回调,每个行情回调的签名是固定的:
def fnc_data(data_list: list, count: int, stats: dict): """ @param data_list: 列表,包含订阅的行情数据,可能多条 @param count: data_list 中数据的条数 @param stats: 数据包在传输链路中到达各个节点的时间戳 {'produce_time': 服务接收到行情的时间, 'send_time': 服务发送行情的时间, 'recv_time': sdk接收到行情的时间} """ passstats这个参数很多人会忽略,但它其实是做延迟分析的关键。produce_time和recv_time的差值就是端到端延迟,如果你发现这个值在开盘时段突然变大,说明回调处理堵了。我一般会在回调里只做一件事:把data_list和stats一起塞进queue.Queue,然后立刻返回。
3.2 set_env 的参数详解
set_env是登录前必须调用的函数,它负责注册回调函数和设置环境参数。手册里列了十几个参数,但实际常用的就几个:
from datafeed.tds_api import TDS tds = TDS() def callback_stock(data, count, stats): # 只做入队,不做耗时处理 data_queue.put((data, count, stats)) tds.set_env( fnctickstock=callback_stock, # 证券快照回调 m_heartbeat_interval=10, # 心跳间隔,最小 1 秒 m_reconn_count=5, # 断线重试次数 m_reconn_interval=3, # 重连间隔秒数 m_timeout=5000, # 同步请求超时,默认 5000ms m_connectmarket="USH;USZ", # 连接市场,默认沪深都连 m_logpath="./tds_log", # 日志路径 m_loglevel="warn", # 日志级别 m_connectsubscribe=1 # 断线重连后自动重发订阅 )几个关键参数的选择逻辑:m_heartbeat_interval不要设太小,1 秒是下限,实际用 5-10 秒比较稳;m_reconn_count设 0 或负数就是不重连,生产环境至少设 3 次以上;m_connectsubscribe=1是 V2.1.4 之后才有的,断线重连后自动重发订阅请求,省得自己写重连逻辑。
3.3 登录返回值与错误码排查
登录函数返回一个整数,0 表示成功,负数表示失败。手册里列了完整的错误码表,几个高频出现的:
| 返回值 | 含义 | 常见原因 |
|---|---|---|
| -1004 | 用户名密码错误 | 账号配置问题 |
| -1005 | 无法连接至服务器 | 网络不通或域名端口不对 |
| -1014 | 级联模式下主IP连接异常 | 主SDK没启动或IP填错 |
| -1016 | 重复登录 | 同一账号多处登录 |
| -1018 | 版本太低 | SDK 版本过旧,需更新 |
ret = tds.login('your_account', 'your_password') if ret != 0: print(f"登录失败,错误码: {ret}") # 根据错误码做对应处理-1018这个错误码是 V2.1.3 才加进去的,之前版本遇到版本过低可能直接返回一个模糊的错误。如果你在旧版本上遇到登录失败但错误码对不上,优先考虑升级 SDK。
4. 订阅、查询与级联模式:多市场多实例的配置细节
4.1 同步订阅与异步订阅的选择
TDS 提供了两套订阅接口:同步的sub/unsub/add_sub/del_sub,和异步的async_sub。同步接口会阻塞直到服务端返回结果,异步接口通过fncsubscribe回调通知结果。
# 同步订阅:订阅 USHA 全市场证券快照 ret = tds.sub('stock', 'USHA', []) # 返回 0 表示成功,负数表示失败 # 异步订阅:V2.1.4 新增 ret = tds.async_sub('stock', 1, 'USHA', []) # op_type: 1-全新订阅 2-取消订阅 3-增加订阅代码 4-取消订阅代码什么时候用异步?当你需要批量订阅多个市场多个数据类型的时候。同步接口每调一次都要等往返,批量操作会很慢。异步接口发出去就不管了,结果通过回调统一处理。但异步的代价是错误处理更麻烦——你得在fncsubscribe回调里根据statuscode判断哪些订阅成功了哪些失败了。
4.2 市场代码的坑
手册里列了完整的市场代码表,但有一个容易忽略的点:上证 A 股还包括 USHT(上证风险警示板)。如果你只订阅了 USHA,ST 股票的行情是收不到的。
| 市场号 | 对应市场 |
|---|---|
| USHI | 上海指数 |
| USHA | 上海A股 |
| USHB | 上海B股 |
| USHD | 上海债券 |
| USHJ | 上海基金 |
| USHT | 上海ST风险警示板 |
| USZI | 深圳指数 |
| USZA | 深圳A股 |
| USZB | 深圳B股 |
| USZD | 深圳债券 |
| USZJ | 深圳基金 |
做涨停板策略的话,USHT 必须单独订阅,否则 ST 股票的封单变化你完全看不到。
4.3 级联模式的配置
级联模式解决的是多实例场景下的数据分发问题。主 SDK 连接 datafeed 服务器,从 SDK 连接主 SDK 获取数据。配置分两步:
第一步,创建tool.ini文件,Python 版本放在程序文件同级目录:
# 主 SDK 的 tool.ini master=true socket_port=9999 # 从 SDK 的 tool.ini master=false socket_port=9998注意socket_port后面必须接换行符,否则配置读取会失败——这是手册里专门提醒的坑。
第二步,从 SDK 调用register_addr注册主 SDK 的 IP 和端口:
tds = TDS() tds.set_env(fnctickstock=callback_stock) # 从 SDK 注册主 SDK 地址,必须在登录前调用 tds.register_addr('master', '192.168.1.100', 9999) tds.login('account', 'password')级联模式有几个硬性约束:主 SDK 必须先登录成功,从 SDK 才能连接;主从必须在同一局域网;从 SDK 的账号密码要和主 SDK 一致。V2.0.8 对级联模式做了性能优化,如果用的是旧版本,多从节点场景下可能会有数据分发延迟。
5. 避坑排查:回调堵包、字段类型变更和离线调试的边界
5.1 回调函数里做耗时操作导致堵包
现象:开盘后一段时间,stats里的recv_time和produce_time差值越来越大,从几毫秒涨到几百毫秒甚至秒级,行情明显滞后。
原因:回调函数是在 SDK 的接收线程里同步执行的,如果你在回调里做 DataFrame 拼接、写数据库、发 HTTP 请求,接收线程就被阻塞了,后续数据包堆积。
解决:回调里只做入队操作,另起消费线程处理。队列用queue.Queue并设置合理的maxsize,满了就丢弃或落盘,不要无限堆积。
import queue import threading data_queue = queue.Queue(maxsize=10000) def callback_stock(data, count, stats): try: data_queue.put_nowait((data, count, stats)) except queue.Full: # 队列满了,记录丢弃计数 pass def consumer(): while True: data, count, stats = data_queue.get() # 在这里做数据处理 process(data) threading.Thread(target=consumer, daemon=True).start()5.2 withdraw_buyturnover 类型从 int 变 float
现象:升级 SDK 后,原来用int接收撤单金额的代码报类型错误,或者数值精度丢失。
原因:V2.0.6 把证券快照的withdraw_buyturnover和withdraw_sellturnover从int改成了float。如果你在代码里做了强制类型转换或者用int做键,就会出问题。
解决:检查所有涉及这两个字段的计算逻辑,确保用float处理。如果数据要入库,确认数据库字段类型也改了。
5.3 离线调试模式不生效
现象:调用start_offline_debug后,登录仍然连接线上,或者回调不触发。
原因:手册里写得很清楚——离线调试函数必须在实例创建之后、登录之前调用。如果已经登录了,这个函数不生效。另外,数据文件的命名必须严格匹配stock.csv、index.csv、order.csv、queue.csv、trans.csv、superstock.csv、codelist.ini,命名不对 SDK 直接不读。
解决:确保调用顺序是TDS()→set_env()→start_offline_debug()→login()。数据文件放在指定路径下,文件名一字不差。
tds = TDS() tds.set_env(fnctickstock=callback_stock) # 必须在 login 之前调用 tds.start_offline_debug( path='D:\\datafeed', subtype=['stock', 'index', 'order', 'queue', 'trans', 'superstock'], push_space=3000, # 回放推送间隔 ms push_count=5000, # 单次推送条数 playback_times=1 # 遍历次数 ) tds.login('test', '123456') # 不会连接线上5.4 消息通知回调参数类型变更
现象:V2.1.3 之前func_notify接收的是int,之后变成了dict,旧代码直接报错。
原因:V2.1.3 把消息通知回调函数的传入参数从int改成了dict,格式为{"code": int, "msg": str}。code的含义:1 表示网络断开,2 表示网卡不正常,3 表示重复登录被踢下线。
解决:更新回调函数签名,从def func_notify(code):改成def func_notify(msg_notify):,然后从msg_notify["code"]取错误码。
5.5 深交所交易方式字段的兼容问题
现象:2022.5.16 之后,深交所快照数据里出现了matching_volume、deal_mode、mode_state等新字段,旧代码解析时可能漏掉或者误读。
原因:2022.5.16 前深交所只有竞价交易数据,之后增加了协商成交、点击成交、询价成交、竞买成交等交易方式。原先快照字段的数值变成所有交易方式的汇总,同时额外提供 5 个字段来区分。
解决:如果你的策略依赖深交所快照的成交量字段,需要明确用的是汇总值还是匹配成交值。deal_mode为 1 表示匹配成交,mode_state的格式是“交易方式1交易状态1交易方式2交易状态2...”,解析时要按位拆。
6. 用离线调试做策略回放:一个可复现的验证流程
离线调试模式是这份手册里最被低估的功能。很多人只把它当“没行情的时候测试用”,但实际上它是做策略回测和回归验证的利器。你可以把历史逐笔数据整理成 CSV,用离线调试模式按真实的时间间隔回放,验证策略在历史行情下的表现。
具体做法:先从历史数据里导出某只股票某天的逐笔成交和快照,按手册要求的 CSV 格式整理好,表头字段名参照手册第 3 章的字段说明。然后启动离线调试,设置push_space和push_count来控制回放速度。
tds = TDS() def callback_trans(data, count, stats): for item in data: # 逐笔成交数据,包含通道号字段(V2.0.7 新增) print(item['code'], item['price'], item['volume']) tds.set_env(fnctransaction=callback_trans) tds.start_offline_debug( path='./historical_data', subtype=['trans', 'stock'], push_space=100, # 100ms 推送一次,模拟实时节奏 push_count=100, # 每次推 100 条 playback_times=1 ) tds.login('test', 'test')这里有个细节:push_space和push_count的配合决定了回放速度。如果原始数据是每 3 秒一个快照,你可以设push_space=3000、push_count=1来精确模拟。但如果是逐笔数据,一天可能有几十万条,设push_space=100、push_count=100大概能在一小时内回放完一天的逐笔。
验证策略的时候,我习惯在回调里记录每笔数据的recv_time和策略信号时间戳,回放结束后对比两者的差值分布。如果差值在回放模式下很稳定,但在实盘模式下波动很大,说明实盘的瓶颈在网络或回调处理,不在策略逻辑本身。
还有一个容易忽略的点:级联模式下父节点支持离线调试,启动调试后子节点可以获取数据,子节点不需要开启离线调试。这意味着你可以在局域网里用一台机器做数据回放,多台机器同时消费,做分布式策略验证。
从那以后我每次接入新的行情 SDK,都强制走一遍“离线回放 → 延迟分布分析 → 实盘小规模验证”的流程,不再直接上实盘。希望帮到你。
本文还有配套的精品资源,点击获取