第 1 节 概述
IB Gateway 是 Interactive Brokers (IB) 提供的轻量级应用程序,允许用户通过 API 接口与 IB 的交易系统进行连接。与 TWS (Trader Workstation) 相比,IB Gateway 更适合程序化交易,因为它:
• 没有 GUI 界面,降低资源占用。
• 支持持续运行,更稳定,适合无人值守的量化策略。
• 提供完整的 API 支持,包括行情数据、下单、账户管理等功能。
IB Gateway 可以通过 IB API(支持多种语言:Python、Java、C++、C# 等) 进行交互,使开发者能够编写自己的量化交易程序。
第 2 节 服务器端
2.1 容器部署
使用这个 Github 项目,因为作者一直在持续更新,且部署起来相对简单。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
docker run -itd --name ibkr --restart always \
-p PORT1:6080 \
-p PORT2:8888 \
--ulimit nofile=10000 \
-e USERNAME=USERNAME \
-e PASSWORD=PASSWORD \
-e TWOFA_TIMEOUT_ACTION=restart \
-e GATEWAY_OR_TWS=gateway \
-e IBC_TradingMode=paper \
-e IBC_ReadOnlyApi=no \
-e TWS_SETTINGS_PATH=/settings \
-v /PATH/IBKR/settings:/settings:rw \
ghcr.io/extrange/ibkr:latest
|
6080端口是 noVNC 的地址,用于访问 IB Gateway GUI 界面
8888端口是 API 的地址,客户端连接该地址访问服务器
GATEWAY_OR_TWS为了轻量选gateway
TWOFA_TIMEOUT_ACTION表示timeout自动重启
IBC_TradingMode表示部署在测试环境,上线时改成live
IBC_ReadOnlyApi表示可以下单,而非只读
2.2 容器设置
Configuration -> Lock and Exit

为了安全考虑,IB Gateway 需要设置自动退出或者自动重启,设置在中午的 12:15 比较不错。
Configuration -> API -> Settings

取消只读,这样才可以下单交易
Configuration -> API -> Precautions

取消预防措施,下单不会因为预防措施而被忽略
第 3 节 客户端
IB API 最初基于 Java 开发,由于 IB 的核心交易系统是用 Java 编写的,所以官方 API 最早是为 Java 提供的支持,后来才逐渐扩展到其他语言。
尽管 IB 提供了多种语言的 API,但因为 API 的核心逻辑和结构源于 Java 实现,所以其他语言版本的 API 在设计和使用上受到 Java 风格的影响,尤其是 Python 版本,经常被开发者吐槽“难用”。
所以就出现了基于 IB API 包装下的第三方实现,最初的项目名为 ib_insync,由于原作者去世,其他继任者维护的项目变更为 ib_async,两者的使用方法相同,文档也可以互相参考。
3.1 安装
3.2 连接服务器
1
2
3
4
5
6
7
|
from ib_async import *
# 使用notebook 或者 jypyterlab 时 startLoop()
util.startLoop()
ib = IB()
ib.connect('192.168.0.103', 7751, clientId=0)
# 最后断开连接
ib.disconnect()
|

3.3 账户信息
持仓信息
1
2
3
4
5
|
# 获取账户持仓
positions = ib.positions()
# 输出持仓信息
for position in positions:
print(position)
|
比如,可能显示以下信息:
1
2
3
4
5
6
7
8
9
10
|
# 持有 100股 苹果 (AAPL),每股成本 145 美元
Position(
contract=Stock(
symbol='AAPL',
exchange='SMART',
currency='USD'
),
position=100,
avgCost=145.0
)
|
交易信息
1
2
3
4
5
6
7
8
9
10
11
12
13
|
# 获取已成交的交易记录
trades = ib.trades()
# 输出交易记录
for trade in trades:
print(trade)
# 获取未平仓的交易
open_trades = ib.openTrades()
# 输出未平仓交易
for trade in open_trades:
print(trade)
|
比如,可能显示以下信息:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
# 以每股150美元限价单购买了200股苹果 (AAPL)
Trade(
order=Order(
id=12347,
action='BUY',
totalQuantity=200,
lmtPrice=150.0
),
contract=Stock(
symbol='AAPL',
exchange='SMART',
currency='USD'
),
price=150.0,
qty=200,
time='2025-01-13 10:30:00'
)
|
资金状态
1
2
3
4
5
6
|
# 获取账户资金状态
account_values = ib.accountValues()
# 输出账户资金信息
for value in account_values:
print(value)
|
比如,可能显示以下信息:
1
2
3
4
5
6
7
|
# 账户现金余额为50,000美元
AccountValue(
account='DU123456',
tag='CashBalance',
value='50000.0',
currency='USD'
)
|
| Tag |
描述 |
CashBalance |
现金余额 |
AvailableFunds |
可用资金 |
BuyingPower |
购买力 |
NetLiquidation |
净清算值 |
RealizedPnL |
已实现盈亏 |
UnrealizedPnL |
未实现盈亏 |
使用现金,没有融资
使用保证金,融资
- 可用资金 = 现金余额+融资额度-已用保证金
- 购买力=可用资金\times融资倍数
3.4 创建交易
创建合约
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
# 创建一个股票合约
contract = Stock(
symbol='AAPL',
exchange='SMART',
currency='USD'
)
# 创建一个期权合约
contract = Option(
symbol='AAPL',
lastTradeDateOrContractMonth='20250119',
strike=150,
right='C',
exchange='SMART',
currency='USD'
)
|
还有其他合约,比如期货(Futures)、外汇(Forex)、债券(Bond)、指数(Index)等。
创建订单
1
2
3
4
5
6
7
8
9
10
|
# 市价单
order = MarketOrder('BUY', 100) # 以市场价买入100股
# 限价单
order = LimitOrder('BUY', 100, 150) # 以150美元或更低价格买入100股
# 止损单
order = StopOrder('SELL', 100, 140) # 当价格达到140美元时卖出100股
# 限价止损
order = StopLimitOrder('SELL', 100, 140, 139) # 当价格达到140时卖出100股,且不低于139美元
# 区间订单
order = BracketOrder('BUY', 100, 150, 155, 145) # 以150美元买入100股,止盈155,止损145
|
创建交易
1
2
3
|
trade = ib.placeOrder(contract, order)
# 取消交易
ib.cancelOrder(order)
|
3.5 历史数据
1
2
3
4
5
6
7
8
9
|
bars = ib.reqHistoricalData(
contract, # 合约对象
endDateTime='', # 结束时间
durationStr='60 D', # 请求过去60天的历史数据
barSizeSetting='1 hour',# 每个数据点代表1小时
whatToShow='TRADES', # 请求成交数据
useRTH=True, # 仅包含常规交易时段的数据
formatDate=1 # 返回日期为字符串格式
)
|
endDateTime格式为2025-01-13 16:00:00,缺失表示当前时刻
durationStr单位有D天、W周、M月、Y年
barSizeSetting单位有min(s)、hour(s)、day(s)
whatToShow可选值:
TRADES成交价
MIDPOINT中间价
BID买价
ASK卖价
ADJUSTED_LAST调整后的成交价,前复权价格
useRTH:True 为常规交易时间段,False 为全天数据
formatDate:1表示2025-01-13 16:00:00这种字符串格式,2表示时间戳
信息
barSizeSetting设置成1 sec时,可以获取历史 Tick 数据。因为个人难以训练足够庞大的模型对 Tick 数据进行处理并预测,因此不讨论 Tick 数据。
3.6 热门股票
获取股票
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
# 创建扫描器订阅:筛选涨幅较大和成交量较大的股票
scanner = ScannerSubscription(
numberOfRows=10, # 获取前10个股票
instrument='STK', # 股票
locationCode='STK.US.MAJOR', # 美国股票市场
scanCode='TOP_PERC_GAIN', # 漲幅最大
abovePrice=5, # 股票价格大于5美元
belowPrice=500, # 股票价格小于500美元
marketCapAbove=1000000000, # 市值大于10亿
averageOptionVolumeAbove=100 # 平均期权成交量大于100
)
# 执行扫描
scan_data = ib.reqScannerData(scanner)
# 提取扫描结果中的股票信息
stocks = []
for item in scan_data:
stock_info = {
'Symbol': item.contract.symbol,
'Name': item.contract.localSymbol,
'Price': item.marketPrice,
'Change Percent': item.changePercent,
'Volume': item.volume
}
stocks.append(stock_info)
# 将数据转换为 DataFrame
df = pd.DataFrame(stocks)
# 输出数据
print(df)
|
绘制热力图
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import seaborn as sns
import matplotlib.pyplot as plt
# 选择需要展示的列:涨幅和成交量
df_heatmap = df[['Symbol', 'Change Percent', 'Volume']]
# 设置画布大小
plt.figure(figsize=(10, 8))
# 使用 Seaborn 绘制热力图,设置颜色映射和注释显示数据
heatmap_data = df_heatmap.set_index('Symbol').T
sns.heatmap(heatmap_data, annot=True, cmap='YlGnBu', fmt='.2f', linewidths=0.5)
# 设置标题
plt.title('Heatmap of Stock Change Percent and Volume', fontsize=16)
# 显示图形
plt.show()
|