- 金融科技
【免费下载链接】tqsdk-python
天勤量化开发包, 期货量化, 实时行情/历史数据/实盘交易
本文围绕 TqSdk(tqsdk-python)中的TqCtp直连 CTP 交易类展开,系统讲解其构造函数全部参数与标准接入代码、运行依赖(tqsdk_zq_otg本地柜台适配包)的安装与版本要求,并结合仓库源码剖析zqotg://交易协议、本地otg_adapter子进程与TqApi之间的完整连接链路,帮助已申请期货公司程序化外接权限的开发者把 TqSdk 策略程序直连到期货公司 CTP 柜台。
一、TqCtp 是什么:直连 CTP 柜台与中继模式的差异
TqCtp是 TqSdk 提供的直连 CTP 账户类,用于让 TqSdk 策略程序绕过官方交易中继网关,直接接入用户所在期货公司的 CTP 交易系统。在TqApi的账户参数说明中,它的定位是一句话:「:py:class:~tqsdk.TqCtp`:使用直连 CTP 账号」,见 api.py 的 TqApi 文档。
从仓库文档(doc/enterprise.rst)可以看到,直连模式属于 TqSdk 企业版提供的能力:
- 交易指令直达期货公司,省去中继服务器路径,官方文档给出的说法是交易延迟平均减少 10ms 左右;
- 减少了对交易服务器(中继)的依赖,程序运行稳定性提升;
- 与
TqAccount(中继模式)相比,直连模式还需要自行向期货公司申请程序化外接,取得柜台代码、柜台地址等接入信息。
for_ctp_user.rst 一节的系统架构描述也印证了这一点:TqSdk 常规链路是「期货公司交易系统 → Open Trade Gateway 交易中继网关 → TqSdk」,而TqCtp则通过本机上自部署的柜台适配进程直连期货公司 CTP,不再经过官方中继转发交易指令。
二、构造函数与标准接入代码
TqCtp定义在 tqsdk/tradeable/otg/tqctp.py,类声明为class TqCtp(BaseOtg, FutureMixin),即继承自通用 OTG(柜台网关)交易模块基类,并混入期货账户数据接口。其完整签名与参数如下:
def __init__(self, account_id: str, password: str, front_broker: str, front_url: str, app_id: str, auth_code: str) -> None| 参数 | 类型 | 说明 |
|---|---|---|
account_id | str | 期货账户(CTP 资金账号) |
password | str | CTP 账户密码 |
front_broker | str | CTP 柜台代码(期货公司代码) |
front_url | str | CTP 柜台地址,格式为tcp://ip:port,文档给出的示例形如tcp://129.211.138.170:10001 |
app_id | str | CTP AppID |
auth_code | str | CTP AuthCode |
标准接入方式(源码 docstring 中的 Example1,也是官方文档 tqsdk.tqctp.rst 通过autoclass呈现的完整示例):
from tqsdk import TqApi, TqAuth, TqCtp account = TqCtp( account_id="CTP 账户", password="CTP 密码", front_broker="CTP 柜台代码", front_url="CTP 柜台地址", # 如 tcp://129.211.138.170:10001 app_id="CTP AppID", auth_code="CTP AuthCode", ) api = TqApi(account, auth=TqAuth("快期账户", "账户密码"))有两点注意事项直接来自源码 docstring:
- 需要额外安装
tqsdk_zq_otg包:pip install -U tqsdk_zq_otg; front_broker、front_url、app_id、auth_code四组信息必须向期货公司申请程序化外接后取得,无法凭公开资料自行拼出。
另注意:TqApi的auth参数(快期账户)仍然是必需的,用于行情与数据服务授权——直连的只是交易链路,行情仍走天勤行情服务。
三、运行依赖与环境前提
TqCtp的可用性与两个前置条件强相关,均可在仓库中确认:
1. 必须安装并满足版本要求的tqsdk_zq_otg
自 3.7.2 起,tqsdk_zq_otg已从安装依赖中移除(version.rst:「BREAKING:从安装依赖中移除 tqsdk_zq_otg 模块,用户使用多柜台需要手动安装依赖包:pip install -U tqsdk_zq_otg」),当前仓库的 requirements.txt 中确实不再包含它。
版本校验逻辑在 tqsdk/zq_otg.py 的ZqOtgContext.__init__中:
try: from tqsdk_zq_otg import __version__ as otg_version from tqsdk_zq_otg import get_zq_otg_path except ImportError: raise Exception(f"使用 {acc_types} 账户需要安装 tqsdk_zq_otg 包: pip install -U tqsdk_zq_otg") from None if version.parse(otg_version) < version.parse("3.10.1"): raise Exception(f"使用 {acc_types} 账户需要更新 tqsdk_zq_otg 包到最新版本: pip install -U tqsdk_zq_otg")即:未安装会抛出「需要安装 tqsdk_zq_otg 包」,版本低于 3.10.1 会抛出「需要更新 tqsdk_zq_otg 包到最新版本」。当前仓库版本为 3.10.1(见 tqsdk/__version__.py),两者通常保持同步。
2. 快期账户权限(tq_direct特性)
tqctp.py中_account_auth属性返回{"feature": "tq_direct", "account_id": ..., "auto_add": True},说明该账户类型在授权体系中归属tq_direct特性;ZqOtgContext也正是靠feature == "tq_direct"从账户列表中识别出需要启动本地柜台适配进程的所有账户(tqsdk/zq_otg.py#L30-L31)。因此直连模式还要求快期账户具备对应的直连授权(企业版权益,见 doc/enterprise.rst)。
四、继承的交易数据接口(FutureMixin)
TqCtp的第二个基类FutureMixin(tqsdk/tradeable/mixin.py)提供了与TqAccount等账户一致的四个行情化数据接口,均返回「引用对象」,其内容在api.wait_update()时刷新:
get_account():账户资金信息(Account对象,含float_profit浮动盈亏等字段);get_position(symbol=None):持仓信息,不传symbol返回全部持仓的Entity字典视图;get_order(order_id=None):委托单信息;get_trade(trade_id=None):成交记录,官方推荐优先使用Order.trade_records按委托单查成交。
这些方法通过_get_obj(api._data, ["trade", self._account_key, "accounts"/"positions"/"orders"/"trades", ...], ...)从 Diff 数据树中取对象,因此对TqCtp而言,取数方式与任何其他账户类型完全一致——这正是把 CTP 柜台纳入 TqSdk 统一 Diff 数据模型的意义所在。
TqCtp还可直接传入TqMultiAccount作为多账户之一:TqApi的账户参数说明明确列出TqMultiAccount支持包含TqCtp在内的「0 至 N 个或者组合」(api.py#L140-L145,另见 tqsdk/multiaccount.py)。多账户模式下,TqApi.insert_order等下单接口需要通过account=参数指定具体账户实例(见 tqsdk/risk_rule.py 中各风控下单接口的参数说明)。
五、底层原理:zqotg://协议与本地 otg_adapter 子进程
TqCtp的「直连」并不是 Python 进程里直接拉起 CTP API 回调,而是采用「本地适配进程 + WebSocket 控制」的架构。以下从源码调用链逐步拆解。
1. 构造时固定td_url = "zqotg://127.0.0.1:0/trade"
TqCtp.__init__末尾的super().__init__调用(tqctp.py#L47)把交易服务器地址硬编码为本机占位地址:
super(TqCtp, self).__init__(broker_id="", account_id=account_id, password=password, td_url="zqotg://127.0.0.1:0/trade")broker_id传空串是直连类账户的共同做法(柜台身份改由front_broker表达);zqotg这一自定义 scheme 与官方中继的wss://地址区分开来,作为后续「需要启动本地柜台适配进程」的信号。
2. 账户唯一标识_get_account_key包含柜台信息
tqctp.py重写了_get_account_key(tqctp.py#L57-L61):
def _get_account_key(self): s = self._broker_id + self._account_id s += self._front_broker if self._front_broker else "" s += self._front_url if self._front_url else "" return hashlib.md5(s.encode('utf-8')).hexdigest()对比基类BaseOtg._get_account_key(base_otg.py#L57-L59)只用broker_id + account_id,TqCtp额外把front_broker和front_url纳入哈希。这个_account_key是账户在api._data数据树(trade/{account_key}/...)与 Web 界面中的唯一键——从源码结构看,同一 CTP 资金账号若接入不同柜台(不同 front_url),会得到不同的account_key,即被视为两个不同交易实例,这也意味着同进程内为不同柜台创建多个TqCtp实例时,其交易数据是互相隔离的。
3.ZqOtgContext:启动本地otg_adapter并解析真实地址
连接发生在 tqsdk/connect.py 的TqConnect._run中:当 URL scheme 为zqotg时创建ZqOtgContext(self._api)作为上下文,随后在连接循环里调用await cm.get_url(url_info)换取真实 WebSocket 地址。
ZqOtgContext的实现(tqsdk/zq_otg.py)关键点:
- 二进制来源:
self._zq_otg_exe = str(Path(self._zq_otg_path) / "otg_adapter"),其中_zq_otg_path来自tqsdk_zq_otg.get_zq_otg_path(),即otg_adapter可执行文件随tqsdk_zq_otgpip 包分发,并设置LD_LIBRARY_PATH指向同目录(Linux/macOS); - 启动方式:
get_url()中以--config=<json> --mode=cmd启动子进程,config 传入log_file_path、user_file_path、host=127.0.0.1、port=0(随机端口),日志目录位于~/.tqsdk/otg_logs下按时间戳命名的子目录(并内置最多 30 个日志目录、3 天保留期的自动清理逻辑,见 zq_otg.py#L20-L28 与_clear_otg_logs); - 地址协商:启动后最多轮询 30 秒读取数据目录下的
port.json,取到非 0 端口后把zqotg://127.0.0.1:0/trade替换为ws://127.0.0.1:{port}/trade(zq_otg.py#L120-L127);若 30 秒内拿不到端口则抛出TqContextManagerError("获取交易服务地址失败"); - 生命周期:
__aexit__时关闭子进程 stdin 并等待其退出,保证TqApi关闭后适配进程不残留。
也就是说,真正持有 CTP API 会话的是otg_adapter这个本地原生进程;TqSdk 只是通过ws://127.0.0.1:{port}/trade与它做 Diff 协议通信,从而把 CTP 的下单、回报、持仓等数据统一映射为 TqSdk 的实体对象。
4. 登录包:把柜台接入参数透传给适配进程
BaseOtg._run(base_otg.py#L126-L133)建立通道后会先await self._send_login_pack()发送登录请求。TqCtp重写了该方法(tqctp.py#L63-L75),把全部直连参数打包发给tqsdk_zq_otg:
async def _send_login_pack(self): req = { "aid": "req_login", "bid": "tqsdk_zq_otg", "user_name": self._account_id, "password": self._password, "broker_id": self._front_broker, "front": self._front_url, "app_id": self._app_id, "auth_code": self._auth_code, "backend": "ctp" } await self._td_send_chan.send(req)其中backend: "ctp"指定由otg_adapter使用 CTP 后端,front即用户填写的front_url。可以推断:tqsdk_zq_otg适配进程收到该包后,在本地完成 CTP 前置连接、认证与登录,之后的所有业务数据都以 Diff 协议经本机 WebSocket 回传。_td_handler(base_otg.py#L158-L165)还会把回报中trade记录里以 user_id(资金账号)为键的字段替换为account_key,保证多账户数据树键值一致。
5. 交易通道建立与重连
BaseOtg._connect_td(base_otg.py#L105-L124)为该账户建立TqConnect+TdReconnectHandler双通道:底层TqConnect负责实际的 WebSocket 连接与断线重连,TdReconnectHandler在其上再包一层交易专用重连缓冲。下单类请求(insert_order、cancel_order、set_risk_management_rule、pre_insert_order)由Tradeable._is_self_trade_pack(tradeable.py#L43-L52)按account_key精确路由到对应账户的交易通道,其余请求走行情通道——这套路由机制保证了TqMultiAccount混合多个TqCtp/其他账户时的指令互不串包。
六、版本沿革与适用限制
从 doc/version.rst 的变更记录可以确认TqCtp的演进与适用版本前提:
- 3.7.0(2024/08/22):新增
TqCtp账户类型,支持直连 CTP 柜台; - 3.7.1(2024/08/29):修复 Windows 系统上使用
TqCtp导致多TqApi实例无法运行的问题,并修复文档 demo 代码拼写错误; - 3.7.2(2024/09/12):
tqsdk_zq_otg从安装依赖中移除,改为手动安装; - 3.7.5(2024/11/13):补充
TqCtp等直连类文档的front_url示例。
因此使用TqCtp时需注意:
- TqSdk 版本应不低于 3.7.0,并优先使用当前最新版本(仓库当前为 3.10.1);
- 必须手动
pip install -U tqsdk_zq_otg且版本不低于 3.10.1,否则初始化阶段即抛出依赖异常; - 需要向期货公司完成程序化外接申请,拿到
front_broker/front_url/app_id/auth_code; - 直连属于企业版功能范畴,账户侧需要具备相应授权(
tq_direct特性),详见 doc/enterprise.rst; - 若同时希望查询保证金率等 CTP 柜台特有数据,仓库文档 tqsdk2ctptest.rst 给出了 TqSdk + TqSdk2 直连混合使用的参考方案(受 CTP 柜台每秒 1 笔查询的流控限制,建议盘前完成查询)。
七、小结
TqCtp让用户在保留 TqSdk「引用对象 +wait_update」统一编程模型与官方行情服务的前提下,把交易链路从官方中继切换为「本机otg_adapter适配进程直连期货公司 CTP」:对外只暴露 6 个构造参数和标准的TqApi(account, auth=...)用法,对内则通过zqotg://协议、随机端口协商、req_login柜台参数透传与按account_key路由的 Diff 通道完成柜台会话管理。对需要更低交易延迟、更可控依赖路径的实盘策略,这是 TqSdk 仓库中完整的直连 CTP 接入方案;相关源码入口为 tqsdk/tradeable/otg/tqctp.py、tqsdk/tradeable/otg/base_otg.py 与 tqsdk/zq_otg.py。
- 金融科技
【免费下载链接】tqsdk-python
天勤量化开发包, 期货量化, 实时行情/历史数据/实盘交易
相关推荐
TqJees 杰宜斯资管账户接入指南:tqsdk 多柜台直连交易架构与源码级解析
TqJees 杰宜斯资管账户接入指南:tqsdk 多柜台直连交易架构与源码级解析 在 tqsdk python(天勤量化开发包)中, TqJees 是用于直连杰
金融科技tqsdk-python 直连恒生 O32 柜台:TqO32 与 O32Account 账户完整实战指南
tqsdk python 直连恒生 O32 柜台:TqO32 与 O32Account 账户完整实战指南 本文围绕 tqsdk python 中恒生 O32 柜
金融科技tqsdk 中 TqYida 易达交易账户:直连易达柜台的参数详解与底层接入机制
tqsdk 中 TqYida 易达交易账户:直连易达柜台的参数详解与底层接入机制 本文围绕 tqsdk 的 TqYida (易达交易类)展开,说明如何在策略代码
金融科技
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考