☰
Level-2全推行情Python SDK部署避坑:多市场订阅与版本对齐
2026/11/3 3:53:32 网站建设 项目流程

简介:《同花顺level-2全推行情Python API操作手册》面向高频交易与量化开发者,尤其适合做涨停板、盘口异动类策略的研究与工程人员,用来解决Level-2行情如何借助Python稳定接入、按字段准确解析的落地问题。资料是单个PDF文档,压缩包约850KB,轻便易查。内容以版本修订表开篇,逐条梳理V2.0.0至V2.1.9的演进:单连接改多连接、上证逐笔委托接入、级联模式与异步订阅接口、极速盘口与内外盘字段、数据类型由int改float的精度修正,并注明各市场域名端口的默认配置。随后介绍TDS的C/S架构、Level-1与Level-2数据范围、64位双核8GB内存与Python3.5以上的运行环境、安装命令,以及初始化实例、注册六类行情回调、set_env环境参数、断线通知与重连的处理方式。五档十档快照、逐笔成交与委托、委托队列的字段说明也一并列出。已有2846人学习,适合需要对照接口联调、排查堵包与重连问题的开发者随手查阅。

1. 装完只收到半个市场:Level-2 全推行情 SDK 的坑多半不在装

有次排查一个现场:L2-tdsapi-python的 tar.gz 用 pip 装完,import datafeed不报错,登录也返回 0,可跑一整晚只有沪市快照,深市一条都没有。这套 Level-2 全推行情 Python API 的安装难点从来不在"装",而在版本和参数对齐。V2.0.0 把 SDK 从单连接改成多连接,要求按市场分别注册域名和端口;V2.1.3 又加了 -1018 版本过低,还把消息通知回调的入参从 int 换成 dict。手里拿着旧教程装新包,或者拿新包跑旧代码,都会翻车。机器要求其实不高,64 位双核、8G 内存、100Mb 下行,Windows 7 以上和 CentOS 7 都能跑,真正卡人的是 Python 位数、回调签名和订阅市场号这三样。常在量化侧盯涨停板封单变化、排队撤单和逐笔成交的人,最容易被这几个点拖住。

2. 装前清单:Python 位数、安装包形态与 Linux 下的 root 权限

装这套行情 SDK 之前,先把三件事定死:机器够不够、解释器是不是 64 位、包用什么方式落地。这三件事任何一件没对齐,后面调参数都是白费功夫——尤其 Python 位数,坑得最隐蔽,因为 32 位解释器装包时也可能一声不吭地成功。

2.1 硬件与系统基线:8G 内存是下限不是舒适线

官方给的最低配置是 CPU 64 位双核及以上、内存 8G 及以上、互联网下行带宽 100Mb 及以上;系统侧 Windows 7 及以上、CentOS 7 等常用 Linux 发行版都支持,软件侧要求 Python 3.5(64 位)及以上。

这套数值得理解成"能跑起来"而不是"跑得舒服"。全推行情意味着一个回调里data_list可能塞着几百上千条 dict,每条证券快照光十档买卖价量就是四十来个字段,再叠上委托笔数、内外盘、撤单统计,Python 对象的开销比字段表看起来大得多。内存 8G 是给单实例准备的,如果还要在同一个进程里落库或做因子计算,16G 更稳妥。

带宽同理。100Mb 下行是接入的最低门槛,一旦上到级联分发,主 SDK 那个节点要同时喂多个从节点,出口带宽得按实例数乘上去。我一般会在上线前用iftop或系统自带的流量统计盯十分钟峰值,确认余量在 30% 以上再谈别的。

项目最低要求我实际部署时的取值
CPU64 位双核4 核以上,留出回调线程余量
内存8G16G,落库场景再往上加
下行带宽100Mb单实例 100Mb,级联主节点按从节点数叠加
操作系统Windows 7+ / CentOS 7 等CentOS 7 / Windows Server 均可
Python3.5(64 位)及以上3.8~3.10 的 64 位解释器

2.2 解释器必须是 64 位:一行命令先自查

32 位 Python 在这套 SDK 上几乎是必翻车的,典型表现是装完 import 就异常,或者登录后跑一阵子直接 MemoryError。装之前先自查,别靠"我记得我装的是 64 位":

# 打印解释器版本与位数,calcsize('P') 返回指针字节数 python -c "import struct, sys; print(sys.version); print('64位' if struct.calcsize('P') * 8 == 64 else '32位,必须换')"

如果机器上有多个 Python,先确认 pip 到底绑在哪个解释器上。常见的错法是裸敲pip install,结果装进了系统默认的 Python 2 或者另一个 32 位环境,而脚本用python3跑,自然 import 不到:

# Windows 看重名解释器的安装路径,Linux 看全部候选 where python which -a python3 python # 明确指定解释器安装,避免 pip 绑错 python3 -m pip install ./L2-tdsapi-python-X.X.X-XXXXXXXX.tar.gz

用虚拟环境的话,python -m venv l2env建完之后一定要用 2.2 第一条命令在 venv 里再验一次位数。venv 继承的是基底解释器的架构,基底错了,venv 跟着错,而且 venv 里报错信息往往更含糊。

2.3 两种落地方式:pip 装 tar.gz 和解包跑 setup.py

SDK 给的是 tar.gz 源码包,两种路子都行,效果一样,区别在于你想不想留一份解包后的目录方便看示例。

# 方式一:直接让 pip 处理 tar.gz,适合一台机器装一次 python3 -m pip install ./L2-tdsapi-python-X.X.X-XXXXXXXX.tar.gz # 方式二:解包后本地安装,方便对照包内示例和字段模板 tar -xzf L2-tdsapi-python-X.X.X-XXXXXXXX.tar.gz cd L2-tdsapi-python-X.X.X-XXXXXXXX python3 setup.py install

Linux 下如果不用虚拟环境而是装到系统目录,需要 root 权限,sudo -i切过去再执行;Windows 下则要注意用管理员身份打开终端,否则可能因为目录写入权限半途失败。

装完必须验一步,而且要验"装到哪个解释器里了",这一步比"有没有报错"重要:

# 导入并打印包路径,路径指向哪个 Python 的 site-packages,就是装进哪个解释器 python3 -c "import datafeed; print(datafeed.__file__)"

打印出路径、没有异常,安装这一关才算过。如果打印的路径和你跑脚本的解释器不是同一个,别急着往下走,先把sys.path和解释器对应关系理清楚,不然后面所有"登录失败""回调不触发"的排查都会跑偏。

3. 环境参数配置:set_env 里那几个必须先定下来的键

set_env是整套 API 的闸门,创建实例之后、注册登录之前必须先调它,不调直接 login 会失败或者行为异常。它同时干两件事:注册回调函数、设定连接与重连参数。多数人只记得注册回调,把连接参数全用默认值,等到跨市场或者网络抖动时才回头补,代价很高。

3.1 回调注册:六个行情回调加断线通知,签名随版本变过

行情和事件通知全部走回调,回调签名不对是最难查的一类问题——主程序不报错,只是"收不到数据",因为异常发生在 SDK 的回调线程里。

from datafeed.tds_api import TDS tds = TDS() # 行情回调固定三个参数:数据列表、条数、链路时间戳 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,unix 微秒 """ pass # 断线通知回调,V2.1.3 起入参由 int 改为 dict def func_notify(msg_notify): """ @param msg_notify: {"code": int, "msg": str} code 1 网络断开,2 网卡不正常,3 重复登录被踢 收到即代表多次重连均失败,SDK 已停止工作,需要重新 Login 并重新订阅 """ print("disconnect! notify: {}".format(msg_notify["msg"])) # 订阅结果回调,V2.1.6 起参数有调整,注意与本机装的版本对齐 def func(data_type, op_type, market, code_list, statuscode, callback_type): print(statuscode) tds.set_env( fnctickstock=fnc_data, # 证券快照 fnctickindex=fnc_data, # 指数快照 fnctransaction=fnc_data, # 逐笔成交 fncorderdata=fnc_data, # 逐笔委托 fncorderqueue=fnc_data, # 委托队列 fncsuperstock=fnc_data, # 极速盘口,需另开产品权限 fncnotify=func_notify, # 断线通知 fucsubscribe=func, # 异步订阅结果回调 )

六个行情回调的参数签名完全一样,都是(data_list, count, stats),所以可以共用一个函数,在内部按data_list[0]['market']或者业务需要分流。stats里的三个时间戳是排查延迟的抓手:recv_time - send_time是服务端发出到你收到的链路耗时,send_time - produce_time是 SDK 内部的加工耗时,两者分开看,能快速判断慢在哪儿。

func_notify的msg_notify参数类型是个版本分水岭。V2.1.3 之前它是 int,之后是 dict;老代码里写print(msg_notify)看不出问题,写if msg_notify == 1就直接失效了。同理,订阅回调在 V2.1.6 增加过参数,如果你手里的示例代码参数个数和包版本对不上,回调线程会持续抛异常。

提示:回调函数里不要做耗时操作。落库、复杂计算、写文件都扔进队列交给独立线程,回调里只做入队。这是导致"行情堵包"最常见的原因,而且现象是逐渐变慢,不是一下子断掉,很难定位。

3.2 连接与重连参数:m_connectmarket 与 m_timeout 怎么取值

set_env的可选参数全部有默认值,但默认值不一定适合你的场景。下面几个是我每次都会显式写出来的:

参数类型默认值含义与取舍
m_heartbeat_intervalint系统默认心跳间隔,单位秒,最小 1,小于 1 走默认
m_reconn_countint系统默认断线重试次数,小于 1 表示不重连
m_reconn_intervalint系统默认重连间隔秒数,小于 1 表示立即重连
m_timeoutint5000同步请求超时,单位毫秒
m_connectmarketstr"USH;USZ"连接市场,可只填USH或USZ单市场
m_logpathstrdatafeed 包安装目录日志输出路径
m_loglevelstrwarn日志级别
m_connectsubscribeint默认关闭置 1 则断线重登后自动重发订阅
m_versionstr一般不用设版本标识

m_connectmarket是最容易出事的一个。V2.0.0 把单连接改成多连接之后,不同市场走不同的域名和端口,只填一个市场就只连一个市场——这就是第 1 章里"只收到半个市场"的根因。做沪深全推就必须保留"USH;USZ",除非你明确只要单边。

m_timeout默认 5000ms,对同步查询接口(get_tick_stock、get_code_list这类)够用。但如果代码里习惯在开盘瞬间一次性拉全市场快照,建议压到 2000~3000ms,让超时早点暴露,而不是卡住主线程五秒。反过来,网络条件差的机器可以放宽到 8000ms,但别无限放宽——同步接口卡住时,你的策略循环也就卡住了。

重连参数我是这么配的:m_reconn_count给 10~20,m_reconn_interval给 3 秒。连续重连太频繁会被服务端判成异常连接,间隔太短反而更容易被拒。

# 沪深双市场 + 明确重连策略 + 断线自动重发订阅 tds.set_env( fnctickstock=fnc_data, fnctransaction=fnc_data, fncnotify=func_notify, m_connectmarket="USH;USZ", # 双市场,缺一个就少一半数据 m_timeout=3000, # 同步请求 3 秒超时 m_reconn_count=15, # 重试 15 次 m_reconn_interval=3, # 间隔 3 秒 m_connectsubscribe=1, # 重登后自动重发订阅,省掉手工补订阅 )

m_connectsubscribe置 1 这一项,在长时间运行的程序里基本属于必开。不开的话,每次断线重连成功、登录成功之后,之前所有sub的订阅都失效了,而你的程序还以为在收数据。

3.3 日志路径:先把黑匣子打开

m_logpath默认是 datafeed 包的安装目录,m_loglevel默认warn。这两个默认值在 Linux 上很容易出问题:包可能装在系统 site-packages 里,普通用户对该目录没有写权限,日志写不进去又不报错,出问题时你手上什么都没有。

# 日志单独指到有写权限的目录,级别先放宽到 info,跑稳了再收紧 tds.set_env( fnctickstock=fnc_data, m_logpath="/data/log/tds", # Windows 下写成 r"D:\log\tds" m_loglevel="info", )

路径对应的目录要提前建好,权限给足。级别方面,调试期用info,能看清连接、登录、订阅每一步的返回;上线稳定运行一两周后再降到warn,减少磁盘写入。这个顺序别反了——先warn后调问题,等于蒙着眼修车。

4. 登录与订阅:从 login 返回码到 sub、async_sub 与级联模式

环境参数配好,接下来是登录、查代码表、订阅三件事。这一段的坑几乎全在返回码和参数对应关系上,接口本身不难。

4.1 登录返回值:-1004、-1018 和 1 分别指向什么

login(username, password)成功返回 0,失败返回负数(个别情况返回正数)。文档里列了完整返回码,实际排错时高频出现的就那么几个:

返回值含义现场处理
0成功继续订阅
1版本过低,请及时更新升级 SDK,别硬撑
-1002超时无响应查网络、查m_timeout
-1003IP 禁止访问找服务方报备出口 IP
-1004用户名密码错误先确认账号是否含空格
-1005无法连接至服务器查域名端口、查防火墙
-1007错误市场检查m_connectmarket
-1015级联模式下必须是同一局域网主从节点网络划分有问题
-1016重复登录同账号别开多实例
-1018版本太低,请更新程序与返回 1 同源,两个都要判

注意 1 和 -1018 都指向版本问题,不同版本分支下可能命中不同分支,判断逻辑里两个都要覆盖,别只写if ret < 0。

ret = tds.login("your_account", "your_password") if ret == 0: print("login ok") elif ret in (1, -1018): raise SystemExit("SDK 版本过低,先升级再跑") else: print("login failed, code =", ret) # 其余按返回码表逐项排查

4.2 市场号对照与同步订阅:少写一个市场就少一半数据

订阅之前得先知道市场号怎么分。沪深两边的编号规律一致,但名字不同,混用会直接返回错误市场:

市场号对应市场市场号对应市场
USHI上海指数USZI深圳指数
USHA上海 A 股USZA深圳 A 股
USHB上海 B 股USZB深圳 B 股
USHD上海债券USZD深圳债券
USHJ上海基金USZJ深圳基金
USHP上海退市整理USZP深圳退市整理
USHT上海风险警示板

注意:上证 A 股实际还包含 USHT(风险警示板)。做全市场扫描时只订阅 USHA,ST 类标的就漏了,而这恰恰是涨停板策略最关注的一批代码。

同步订阅有四个接口,语义要分清:sub是"清掉该市场该类型的全部订阅再重新订阅",unsub是"取消全部",add_sub是"增量加代码",del_sub是"增量减代码"。把sub当增量接口用,是新手最常见的误操作——每次调sub加一只票,前面订阅的全被冲掉了。

# 查询:获取 USHI 全部指数代码,再拉全市场指数快照 codes = tds.get_code_list("USHI") index_ticks = tds.get_tick_index("USHI", []) # [] 表示全市场 # 同步订阅:先清空 USHA 的证券快照订阅,再按新列表重订 tds.sub("stock", "USHA", ["600000", "600519"]) # 增量:再加两只,不影响已有订阅 tds.add_sub("stock", "USHA", ["601318"]) # 增量取消:只去掉一只 tds.del_sub("stock", "USHA", ["601318"]) # 整类取消:USHA 的证券快照订阅全部清掉 tds.unsub("stock", "USHA")

data_type的取值是固定的几个字符串:index、stock、queue、order、trans、superstock。极速盘口对应的superstock需要另开产品权限,没权限时订阅会返回失败码,别把它当成接口写错了。

4.3 异步订阅与 fucsubscribe:订阅结果不靠返回值靠回调

async_sub是为高频调订阅场景准备的,返回码只表示"请求发出去了",真正的订阅结果通过fucsubscribe注册的回调返回。

def on_subscribe(data_type, op_type, market, code_list, statuscode, callback_type): """ @param op_type: 1 全新订阅 2 取消订阅 3 增加订阅代码 4 取消订阅代码 @param statuscode: 0 成功,其余失败 @param callback_type: 1 异步订阅请求触发,2 重连或重登后自动重发触发 """ if statuscode != 0: print("sub failed", data_type, market, code_list, statuscode) tds.set_env(fnctickstock=fnc_data, fucsubscribe=on_subscribe) # op_type=1 全新订阅,op_type=3 增加代码,op_type=2 取消订阅 tds.async_sub("stock", 1, "USZA", []) tds.async_sub("trans", 3, "USZA", ["000001"])

callback_type这个参数很有用:值为 2 说明是断线重连后 SDK 自动重发的订阅结果,看到它就说明刚才断过一次线,可以据此在监控里打个点。把m_connectsubscribe置 1 之后,这类回调会明显变多,属正常现象。

4.4 级联模式:tool.ini 的 master 与 socket_port

需要在一台机器上跑多个 SDK 实例时用级联:主 SDK 连行情服务器,从 SDK 连主 SDK。切换靠一个本地配置文件tool.ini,Python 版本放在与程序文件同级的位置。

# 主 SDK 的 tool.ini master=true socket_port=9999 # 从 SDK 的 tool.ini,同一台机器上端口必须错开 master=false socket_port=9998

两个字段的语义:master区分主从,默认true;socket_port是本 SDK 的监听端口,同机多实例必须各不相同。文档里专门强调了一句——端口号后面要接换行符,否则可能读取失败。这个细节极其容易被忽略,用脚本生成配置文件时如果没有结尾换行,级联就起不来,而且报错信息不会指向配置文件。

从 SDK 侧还要在登录之前调用register_addr注册主节点地址:

# 从 SDK:先注册主节点地址,再登录 tds.register_addr("master", "192.168.1.10", 9999) tds.login("your_account", "your_password") # 账号密码需与主 SDK 一致

market参数固定填master,addr是主 SDK 所在机器的 IP,port与主 SDK 的socket_port一致。调用顺序不能反:register_addr必须在登录前,而且主 SDK 得先登录成功,从 SDK 才连得上。

5. 避坑排查:装完连不上、收不到数据的五个现场

下面五条是我在实际部署里重复遇到过的,按"现象、原因、解决"记,遇到同类问题时可以对着症状直接跳过去看。

5.1 现象:import 成功,一调后续接口就失败

现象很典型:import datafeed不报错,TDS()也能创建实例,但一调login就返回失败,或者干脆抛异常。

原因是漏了set_env。这个接口的定位是"必须先调用才能调用后续的注册、登录",它不只设参数,还承担了内部初始化。很多示例代码把set_env和login写在一起,抄的时候只抄了后半段。

解决方式是固定成模板:创建实例、set_env、login三步一条链,中间不插别的逻辑。写代码时我会把这行注释直接挂在TDS()上面,避免下次又忘。另外set_env有返回值,成功True失败False,一定要判——返回False还往下走,后面所有报错都是误导。

5.2 现象:登录一直返回 -1005,防火墙也没拦

明明账号密码没问题,返回码却是 -1005 无法连接至服务器,本机 telnet 行情端口也不通。

原因多半在版本与连接模式的组合上。V2.0.0 之前是单连接,一个域名一个端口;改成多连接之后,不同市场要注册各自的域名和端口。V2.0.1 起 Linux 版本已经把各市场的默认域名端口写进默认配置,正常情况下不用手工配;但如果你的环境是从旧版本升级上来的,残留的旧配置文件会覆盖掉新的默认值,表现就是连不上。

解决:升级时把旧的配置文件清干净,让 SDK 重新生成默认配置;m_connectmarket显式写成"USH;USZ",别留空也别只写一个。升级前先备份旧配置,出问题能对比着看。

5.3 现象:回调函数里异常不断,行情时快时慢

程序日志里零星出现回调异常,行情延迟越来越高,但连接一直没断。

原因基本可以锁定在回调里干了重活。回调运行在 SDK 的接收线程上,一旦这里阻塞,后面的数据包就在缓冲区排队。落库、写文件、复杂计算、同步 HTTP 请求,全都不该出现在回调里。

解决:回调只做一件事——把data_list和stats塞进queue.Queue,业务逻辑放独立线程消费。队列要设上限,满了就丢弃并计数,宁可丢几条也不能堵;同时把丢包计数打到监控里,它是判断消费能力是否够用的直接指标。

5.4 现象:级联模式起不来,从 SDK 连不上主 SDK

tool.ini按文档写了,register_addr也调了,从 SDK 就是连不上,返回负值。

三个原因里至少有一个中招:一是socket_port那一行结尾没换行,配置读取失败,SDK 认为自己在默认端口上;二是主从实例在同一台机器上却用了同一个端口;三是register_addr在login之后才调,或者主 SDK 自己还没登录成功。

解决:用cat -A tool.ini或十六进制编辑器确认文件末尾有换行;同机多实例的端口从 9999 往下依次错开;把调用顺序硬性固定为"主 SDK 登录成功 → 从 SDKregister_addr→ 从 SDKlogin"。另外级联要求主从在同一局域网内,跨网段会直接返回 -1015,这条限制没法绕。

5.5 现象:字段解析报类型错误,撤单金额变成整数

代码按老模板解析证券快照,某天开始对沪市的撤单字段报TypeError,或者金额明显被截断。

原因是 V2.0.6 改过数据类型:withdraw_buyturnover和withdraw_sellturnover由int改成float,目的是提高数据精度。如果你的解析逻辑里写死了int(...),或者用结构体偏移的方式读二进制,就会踩上。

解决:字段解析一律走"取值 + 类型转换 + 异常兜底",不要假设类型。落库时金额字段统一用浮点或定点小数,别在 ORM 里声明成整型。升级 SDK 之前,把用到的字段逐个对一遍版本变更说明——V2.0.6 是类型变化,V2.1.4 是新增字段,V2.1.9 是逐笔委托增加委托序号,每一类对下游的影响都不一样。

6. 跑通验证:先用离线回放走一遍,再切实时全推

上线前我固定跑两步验证,顺序不能颠倒:先离线调试模式确认回调链路通,再切实时确认市场覆盖全。跳过第一步直接连实时,等于拿生产流量当测试用例。

6.1 离线调试:用本地 CSV 驱动整条链路

离线调试模式读取本地数据文件驱动 SDK 运行,登录不连线上网关直接返回成功。调用时机很严格:实例创建之后、登录之前;已经登录再调不生效。

文件命名是硬约束,SDK 靠文件名判断数据类型,命名不规范的文件直接不读:stock.csv、index.csv、order.csv、queue.csv、trans.csv、superstock.csv、codelist.ini。CSV 表头字段名参照模板,列顺序不强制。

from datafeed.tds_api import TDS tds = TDS() def callback_stock(data, count, stats): print("receive count:", count) # 拿第一条看字段是否齐全,比逐条打印安全 print("first record:", data[0] if count else None) tds.set_env(fnctickstock=callback_stock) # 数据目录、要回放的文件类型、推送间隔(ms)、单次条数、遍历次数 tds.start_offline_debug( path="/data/offline", # Windows 下用 r"D:\datafeed" subtype=["stock", "index", "order", "queue", "trans", "superstock"], push_space=3000, # 每 3 秒推一批 push_count=5000, # 每批 5000 条 playback_times=1, # 文件遍历 1 遍 ) # 离线模式下 login 不连服务器,直接返回成功 tds.login("your_account", "your_password")

几个参数的实际影响:push_space决定回放速度,设得太小会一次把队列灌满,看不出消费能力;push_count决定单批条数,设成和实盘回调的量级接近才有参考价值。回放期间如果某批数据里不含你订阅的代码,回调可能不触发——这跟实时行情的机制一致,不是 bug。级联模式下只有父节点支持离线调试,子节点调这个函数无效。

6.2 上线前的四项验证

离线跑通之后切实时,我按下面四项依次确认,每项都要有明确的通过标准:

验证项方法通过标准
市场覆盖统计回调里market字段的去重值沪深两边都出现,且包含 USHT
订阅生效调sub后看fucsubscribe回调statuscode全部为 0
链路延迟用stats算recv_time - send_time稳定在毫秒级,无明显毛刺
断线恢复手动断网 10 秒再恢复重连成功,callback_type=2的订阅回调出现

第一项最容易出问题,也最容易被忽略——程序不报错,就是少了一半数据,跑一天才发现。我会在启动脚本里加一行统计,把出现的市场集合打印出来,跟预期集合做比对,对不上直接退出。

从那以后我每次装这套 SDK,都强制走一遍"位数自查 → import 验路径 → 离线回放 → 双市场确认"这四步,宁可多花十分钟,也不在盘中去猜为什么少了一半行情。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询