162 lines
8.9 KiB
Markdown
162 lines
8.9 KiB
Markdown
# 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),但**各自独立管理自己的持仓**(见下文"持仓归属")。
|
||
|
||
## 风控机制
|
||
|
||
1. **交易所硬止损(主)+ 软止损(兜底)**:每笔买入成交后,立即在交易所挂
|
||
**GTC 止损卖单(STP)**(`stop_loss_pct`,股票默认 -2%),`outsideRth=True` 盘后/隔夜
|
||
同样有效——即使 bot 停止、断网、电脑关机,止损仍由交易所执行。bot 每 60 秒同步
|
||
止损单状态:成交→更新持仓归属;被撤/丢失→自动补挂;重启→自动认领。策略正常卖出前
|
||
会先撤掉对应止损单。若止损单因故不存在(如挂单被拒),原"软止损"(每 60 秒检查
|
||
收盘价)自动兜底。
|
||
⚠️ STP 触发后变成市价单,快速行情中成交价可能略低于止损价(滑点)。
|
||
2. **持仓归属**:`bot_state.json` 记录每笔持仓属于哪个策略。策略只卖自己的持仓,
|
||
不会互相平仓。启动/重连时自动与账户真实持仓对账:
|
||
- 状态中有、账户没有 → 清除(说明已被手动平仓或断线期间成交)
|
||
- 账户中有、状态没有 → 标记为 **UNMANAGED**(bot 永不会卖,需手动处理或迁移)
|
||
3. **最低盈利限制解除阻塞**:死叉卖出被盈利条件阻止后,每轮都会重检,
|
||
盈利达标即卖;同时止损兜底,不会无限套牢。
|
||
3b. **全局持仓上限**:`max_positions`(默认 12 批)限制所有策略的并发持仓总数,
|
||
控制最大敞口约 $24k(12 × $2000)。达上限后新买入被跳过(日志记录 SKIPPED),
|
||
已有持仓正常管理退出,不会被强制平仓。
|
||
3c. **每日亏损熔断**:当日已实现亏损达到 `max_daily_loss`(默认 $150)后,
|
||
当天禁止开新仓(次日自动重置,已有持仓正常退出)。
|
||
3d. **止损冷却期**:同一策略同一标的被止损后 30 分钟内禁止重买,
|
||
避免下跌通道中"买入→止损→再买"的连续失血;下单被拒/超时同样进入冷却。
|
||
3e. **MeanRev 趋势过滤**:仅在收盘价高于 SMA50 时允许抄底,不接下跌中的飞刀。
|
||
4. **完整K线信号**:信号只用已收盘的K线计算,避免未收完K线导致的信号闪烁。
|
||
5. **休市禁交易**:通过最新K线时间判断市场是否开盘,收盘/周末/节假日自动暂停信号。
|
||
6. **订单确认**:下单后等待成交(默认30秒),超时自动撤单;同一策略同一标的
|
||
有未成交单时不会重复下单。每笔订单带 `orderRef`(如 `MAStockStrategy:META`)方便在 TWS 中识别来源。
|
||
7. **增量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` 等。
|
||
|
||
## 运行
|
||
|
||
```bash
|
||
# 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 并永远不管**(不会止损、不会止盈)。两个选择:
|
||
|
||
1. **手动平掉旧仓位**后再启动新 bot(推荐,最干净);
|
||
2. 或手动编辑 `bot_state.json` 把旧仓位归属到某个策略,例如:
|
||
|
||
```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 份),请确认账户风险敞口可接受
|