8.9 KiB
Interactive Brokers 自动交易系统
基于 Python + ib_insync 的 IB 自动化交易框架,支持多策略并行、持仓归属追踪、 自动止损、断线自动重连。
项目结构
BotDeepSeek/
├── config.py # 配置管理(dataclass + .env 环境变量)
├── connection.py # TWS/IB Gateway 连接管理(含自动重连)
├── bars.py # 共享K线订阅管理(keepUpToDate 增量推送)
├── orders.py # 下单执行(成交确认、超时撤单、防重复单)
├── state.py # 持仓归属追踪(JSON 持久化 + 启动对账)
├── main.py # 主程序入口
├── strategies/
│ ├── __init__.py
│ ├── base.py # 策略基类
│ ├── ma_cross.py # SMA 20/50 金叉 + ADX 趋势过滤
│ ├── short_term.py # EMA 5/10 金叉 + VWAP 确认 + 最长持仓限制
│ ├── mean_reversion.py # RSI超卖/布林带下轨/急跌 抄底
│ └── forex.py # 外汇均线交叉(默认关闭)
├── bot_state.json # 运行时生成:持仓归属状态(勿手动编辑,除非迁移持仓)
├── requirements.txt
└── .env.example
策略说明
| 策略 | 入场 | 出场(每轮重检) |
|---|---|---|
| MAStockStrategy | 金叉 + 连续2根确认 且 ADX>25 | 交易所STP止损 -2%;快线跌破慢线且盈利 ≥1.5% |
| ShortTermMAVWAP | EMA金叉 + 连续2根确认 且 价格>VWAP | 交易所STP止损 -2%;持仓≥5天;死叉且盈利 ≥1.5% |
| MeanReversion | RSI<30 / 触及布林下轨(均需连续2根)/ 5根急跌1% | 交易所STP止损 -2%;RSI>70 / 回到布林中轨 / 反弹1.5%(需盈利≥1.5%) |
| ForexMAStrategy | 快线金叉慢线 | 软止损 -1%;死叉 |
交易规模:每笔按 trade_value_usd(默认 $2000)按信号价折算股数
(如 $600 的股买 3 股,$95 的股买 21 股),每策略每标的最多一笔。
入场确认:交叉类信号要求交叉后下一根 K 线仍同向,超卖类信号要求
连续 2 根 K 线满足条件,过滤单根毛刺、降低交易频率。
所有策略共用 2 只标的(AMZN、AAPL),但各自独立管理自己的持仓(见下文"持仓归属")。
风控机制
- 交易所硬止损(主)+ 软止损(兜底):每笔买入成交后,立即在交易所挂
GTC 止损卖单(STP)(
stop_loss_pct,股票默认 -2%),outsideRth=True盘后/隔夜 同样有效——即使 bot 停止、断网、电脑关机,止损仍由交易所执行。bot 每 60 秒同步 止损单状态:成交→更新持仓归属;被撤/丢失→自动补挂;重启→自动认领。策略正常卖出前 会先撤掉对应止损单。若止损单因故不存在(如挂单被拒),原"软止损"(每 60 秒检查 收盘价)自动兜底。 ⚠️ STP 触发后变成市价单,快速行情中成交价可能略低于止损价(滑点)。 - 持仓归属:
bot_state.json记录每笔持仓属于哪个策略。策略只卖自己的持仓, 不会互相平仓。启动/重连时自动与账户真实持仓对账:- 状态中有、账户没有 → 清除(说明已被手动平仓或断线期间成交)
- 账户中有、状态没有 → 标记为 UNMANAGED(bot 永不会卖,需手动处理或迁移)
- 最低盈利限制解除阻塞:死叉卖出被盈利条件阻止后,每轮都会重检,
盈利达标即卖;同时止损兜底,不会无限套牢。
3b. 全局持仓上限:
max_positions(默认 12 批)限制所有策略的并发持仓总数, 控制最大敞口约 $24k(12 × $2000)。达上限后新买入被跳过(日志记录 SKIPPED), 已有持仓正常管理退出,不会被强制平仓。 3c. 每日亏损熔断:当日已实现亏损达到max_daily_loss(默认 $150)后, 当天禁止开新仓(次日自动重置,已有持仓正常退出)。 3d. 止损冷却期:同一策略同一标的被止损后 30 分钟内禁止重买, 避免下跌通道中"买入→止损→再买"的连续失血;下单被拒/超时同样进入冷却。 3e. MeanRev 趋势过滤:仅在收盘价高于 SMA50 时允许抄底,不接下跌中的飞刀。 - 完整K线信号:信号只用已收盘的K线计算,避免未收完K线导致的信号闪烁。
- 休市禁交易:通过最新K线时间判断市场是否开盘,收盘/周末/节假日自动暂停信号。
- 订单确认:下单后等待成交(默认30秒),超时自动撤单;同一策略同一标的
有未成交单时不会重复下单。每笔订单带
orderRef(如MAStockStrategy:META)方便在 TWS 中识别来源。 - 增量K线订阅:每个标的只订阅一次
keepUpToDate实时K线流,三个策略共享, 替代原来每分钟全量拉取(原来 5 小时约 845MB 流量)。
配置
复制 .env.example 为 .env 后编辑(程序自动加载 .env):
| 变量 | 默认值 | 说明 |
|---|---|---|
IB_HOST |
127.0.0.1 |
IB Gateway 地址 |
IB_PORT |
4001 |
4001=Gateway实盘, 4002=Gateway模拟, 7496=TWS实盘, 7497=TWS模拟 |
IB_CLIENT_ID |
1 |
客户端唯一 ID |
IB_ACCOUNT |
U4845070 |
指定下单账户 |
IB_PAPER |
false |
仅用于启动日志警示;真实模式由端口/Gateway登录类型决定 |
策略参数在 config.py 中调整:symbols、fast_ma_period、slow_ma_period、
trade_quantity、stop_loss_pct、min_profit_pct 等。
运行
# 1. 启动 IB Gateway(脚本会自动准备 JDK;注意 /tmp 重启后会被清空)
./start_gateway.sh
# 在 Gateway 中登录,并确认 API 设置:Enable ActiveX and Socket Clients、
# 端口、Trusted IPs 加入 127.0.0.1
# 2. 启动 bot(前台调试)
.venv/bin/python main.py
# 或后台重启(会自动先杀掉旧进程)
./restart_bot.sh
tail -f trading_bot.log
# 3. 查看当天成交明细与盈亏(可指定日期)
./report.sh [YYYY-MM-DD]
# 4. 复盘:往返交易统计(胜率/期望值/盈亏比/保本胜率,按策略/标的/信号归因)
.venv/bin/python analytics.py
.venv/bin/python analytics.py --since 2026-08-01
# 5. 可视化看板(单文件 HTML,含权益曲线、收益分布、完整历史表,可交互筛选)
./dashboard.sh
# 6. 离线测试(不连 IB、不下单,改动策略后必跑)
.venv/bin/python -m unittest test_offline -v
复盘工具说明
| 工具 | 用途 |
|---|---|
daily_report.py / report.sh |
单日成交明细与盈亏(原有工具,中文文本输出) |
analytics.py |
全历史往返交易分析:FIFO 配对 → 胜率、期望值、盈亏比、profit factor、最大回撤、以及按策略/标的/入场信号/出场原因/时段的归因。--json 输出可供程序消费 |
dashboard.py / dashboard.sh |
把上述分析渲染成自包含 HTML 看板(权益曲线+回撤带、每日盈亏、四张归因图、收益分布直方图、持仓时长散点、完整交易历史表)。支持策略/标的/时间范围交互筛选,深浅色自适应,无 CDN 依赖 |
analytics.py 输出中最关键的一列是 保本胜率(breakeven win rate):按该策略自己实现的平均盈利/平均亏损计算,需要多高的胜率才能不亏。实际胜率低于它,说明这套参数的风险收益结构本身是负期望的,调信号过滤器不会解决问题。
启动时如为实盘模式,日志会有醒目的 LIVE TRADING MODE 警示。
⚠️ 从旧版本迁移(重要)
旧版本没有持仓归属记录。如果升级时账户里还有旧 bot 开的仓位,新 bot 会把它们标记为 UNMANAGED 并永远不管(不会止损、不会止盈)。两个选择:
- 手动平掉旧仓位后再启动新 bot(推荐,最干净);
- 或手动编辑
bot_state.json把旧仓位归属到某个策略,例如:
{
"MAStockStrategy": {
"NVDA": {"quantity": 1, "entry_price": 207.33, "entry_date": "2026-07-20"}
}
}
注意:归属后该仓位立即受止损/止盈规则约束,若浮亏已超过 stop_loss_pct,
启动后第一轮检查就会被止损卖出。
一次性迁移任务(2026-07-22 已排期)
close_legacy_positions.py + cron 实现无人值守迁移:开盘后(09:45 ET)
自动卖出 5 笔旧仓位(NVDA/META/AVGO/MSFT/PLTR 各 1 股),成功后才自动
启动新 bot;失败则不启动(避免遗留 UNMANAGED 仓位),日志见
close_legacy_positions.log。该 cron 任务执行后自动删除。
安全警告
- 当前配置为实盘模式(4001 端口),下单即真实成交
- 策略有止损,但软止损依赖程序持续运行;请保证机器、网络、Gateway 稳定
- 建议定期查看
trading_bot.log和bot_state.json - 三个策略对同一标的最多各持 1 份(共 3 份),请确认账户风险敞口可接受