译文说明
- 原文链接:docs/IB.md
- 原作者:Rob Carver
- 对应版本:master
- 译者:fanrong
- 许可:GPL-3.0(见 GPL-3.0.txt)
注:本文为非官方翻译,可能存在疏漏;请以原文为准。
本文档专门讨论如何使用 pysystemtrade 连接 Interactive Brokers(IB)。
从 0.28.0 版本开始,这需要依赖库 ib-insync。
尽管本文围绕 Interactive Brokers 展开,但如果你计划接入其他券商,也应该认真阅读本文,因为这里解释了需要修改哪些类来实现这一点;或者,如果你想用其它 Python 封装来对接 IB API,这篇文档也会很有帮助。
相关文档:
重要提示:务必确认你清楚自己在做什么。所有金融交易都可能带来亏损。杠杆交易(例如期货交易)可能会导致你亏光全部资金,甚至出现欠款。回测结果并不能保证未来表现。本软件不提供任何形式的担保或保证。因使用 pysystemtrade 进行实盘交易而造成的任何损失,本人概不负责。使用本软件风险自负。
目录
- 目录
- Preliminaries(预备工作)
- Reference(参考)
由 gh-md-toc 生成
Preliminaries
Getting started with interactive brokers
如果这是你第一次接触 IB 的 Python API,建议先阅读我的博客文章,了解整体架构和工作方式。
遇到 IB 相关问题,可以到这个讨论组提问:twsapi 组。
IB 官方也提供了一个 API 相关的 webinar。
IB API 的官方手册在这里,ib-insync 的官方文档在这里。
Gateway / TWS
你需要从 IB 网站下载 Gateway 或 TWS 软件。
建议使用 Gateway,因为它更稳定、更轻量,而且不会像 TWS 那样定期自重启。
ib-insync library
我使用 ib-insync 作为对 IB API 的封装层。这个库是 pysystemtrade 的一个必需依赖。
非常建议先跑一遍 ib-insync cookbook 里的示例,确认:
- IB 连接是正常的;
- Gateway 设置正确;
- 权限、行情订阅等都配置妥当。
如果 ib-insync 都跑不通,pysystemtrade 自然也无法正常工作。
提示:ib-insync 自 2024 年 3 月起已被标记为归档项目(archived)。未来我们可能需要迁移到它的某个 fork 上。
IBC
很多人会使用 ibcAlpha 这个项目:
- 它可以自动维持一个长期在线的 IB Gateway 会话;
- 避免你每天手动重启 Gateway 的痛苦;
- 尤其适合在“无头”交易服务器上跑全自动系统时使用。
Launching and configuring the Gateway
在运行任何 Python 代码之前,你必须先启动 Gateway 软件。当前版本的 Gateway 通常通过桌面图标启动。
你需要使用以下账户之一登录:
- 纸面交易账户(paper trading account);
- 实盘交易账户(如果使用实盘账户,请务必确认自己知道在做什么。因使用 pysystemtrade 进行实盘交易导致的任何损失,本人概不负责,风险自担!)。
你还需要对 Gateway 做一些配置:
- Socket port:应设置为
4001。如果你使用其他端口,需要在稍后建立连接时同步修改端口设置(见这里和这里)。 - 白名单(trusted IP addresses):应包含
127.0.0.1。
如果你计划在一台机器上运行 Gateway,而在另一台机器上通过网络连接它,则应在白名单中添加那台“客户端机器”的 IP 地址。 - 如果你要进行真实交易,必须关闭“Read only API”选项(也就是允许通过 API 下单)。
- 你可能还需要检查并调整“precautions”和“preset options”等选项(这些与 IB 的风控提示和下单模板相关)。
Making a connection
| |
更多细节见下文的 Creating and closing connection objects。
Reference
Classes and object references
在 pysystemtrade 的 sysbrokers/IB 目录中,IB 相关代码可以大致分为三类对象:
Data source objects(数据源对象)
- 向系统其它部分提供“标准数据对象 API”。
- 例如,无论期货合约价格来自数据库还是来自 IB,调用方式应该保持一致。
- 它们通常通过
/sysproduction/data/broker/中的接口函数被生产环境代码调用。 - 创建这类对象时,需要传入一个 connection object;内部再通过它调用各类 client object。
Client objects(客户端对象)
- 这些对象通过 ib-insync 在具体领域内与 IB 通信(获取数据、下单等)。
- 它们同样在初始化时接收一个 connection object。
Connection objects(连接对象)
- 封装一个具体的 IB Gateway 连接;
- 内部持有 ib-insync 的
IB实例,用于实际的网络交互。
Data source objects
在设计上,我们把 IB 视作“另一种数据源”,因此它必须遵守通用的数据对象 API(参见存储期货与即期外汇数据)。
区别在于:对于 IB 这类“外部券商”,我们不会执行“删除”或“写入”操作(至少不会像对数据库那样随意操作)。
在生产环境中,数据源对象通常通过 /sysproduction/data/broker/ 中的接口函数被调用;
不建议在业务逻辑中直接操作 IB 数据源对象,因为接口层会屏蔽掉“具体对接的是哪家券商”的细节。
所有 IB 数据源对象都继承自 sysbrokers/ 目录下的相关基类(例如 broker*data.py 中的类)。
这样做有两点好处:
- 可以在这些基类中添加“券商特有”的通用方法(这些方法对数据库就没意义);
- 也清楚地展示了:如果要对接其它券商,你需要实现哪些接口。
数据源对象在初始化时会接收并持有:
- 一个 connection object(连接对象);
- 可选的 logger(日志对象)。
它们内部包含并调用若干 client objects,具体实现位于该模块目录。
你可以从某个数据源对象上访问到它所使用的 client 和 connection,例如:
| |
FX Data
| |
Futures price data
| |
Capital data
| |
Contracts data
| |
Instruments data
| |
Orders data
| |
Position data
| |
Client objects
Client 对象负责通过 ib-insync 向券商发出请求(取数、下单、查询持仓等)。
它们通常由“券商数据源对象”在初始化时创建,并从数据源对象那里接收:
- 一个连接对象(connection);
- 可选的日志记录器。
这些类位于此模块目录,并通过一个略显“奇怪”的继承树连接在一起:
- 基类
ibClientibAccountingClient(ibClient)ibPositionsClient(ibClient)ibContractsClient(ibClient)ibOrdersClient(ibContractsClient)ibPriceClient(ibContractsClient)ibFxClient(ibPriceClient)
Client 对象内部还持有:
- 一个连接对象;
- 一个实时的
ib_inysnc.IB实例(实际执行请求的 ib-insync 对象)。
示例:
| |
Connection objects
在 pysystemtrade 中,你通常不会自己手动新建 IB 连接对象——在生产环境中,这些连接由 dataBlob(见 data blobs)统一管理并复用。
不过了解它们的工作方式有助于你在调试或扩展系统时更灵活。
Creating and closing connection objects
| |
ib_port应与 Gateway 配置中的端口号一致;client_id(例如这里的1)不能与任何已连接的 Python 进程重复(哪怕是“卡死挂着”的进程也不行)。
在生产环境中,client id 通常通过数据库统一分配,以避免冲突;ib_ipaddress为127.0.0.1时表示“本机”;如果 Gateway 跑在局域网中另一台机器上,你需要在这里填那台机器的 IP。
如果没有显式传入 account、ib_ipaddress 和 ib_port 参数,则会按以下优先级使用默认值:
private_config.yaml文件中的配置(见下文);defaults.yaml配置文件中的默认值。
你应该先在 pysystemtrade 的 private 目录 中创建 private_config.yaml 文件,然后加入一行或多行:
| |
之后也可以用“从配置对象创建连接”的方式:
| |
连接对象在创建时会立即尝试连接 IB,因此只有在你准备好连接 IB 时才应创建它们。
同样,在生产环境中,连接通常由包含它们的 dataBlob 对象在适当时机关闭;
如有需要,你也可以手动调用 conn.close_connection() 来关闭连接。
Using connections
我们把 IB 当作“另一种数据源”,因此它也要遵守统一的数据对象 API(参见存储期货与即期外汇数据)。
由于连接对象抽象了“与券商交互”的细节,只要接口兼容,理论上也可以很容易把它们替换为其他券商的连接实现。
连接对象提供的最重要服务是:封装了一个实时的 ib_inysnc.IB 实例:
| |
如果你熟悉 ib-insync,可以直接使用它,例如:conn.ib.positions();
但在典型用法中,这个实例主要由上文的各类 IB client 对象内部使用。
Make multiple connections
可以从多个进程同时连接到同一个 IB Gateway,每个进程维护自己的连接对象;
但每个连接必须使用唯一的 client id。
已经使用过的 client id 会存储在“活动数据库”(通常是 MongoDB)中,以确保不会重复使用正在活跃的 client id。