From 95156ca595e97b51bd0afeb10638e1b911af2107 Mon Sep 17 00:00:00 2001 From: dekun Date: Wed, 1 Jul 2026 12:56:27 +0800 Subject: [PATCH] Update docs for CTP worker split and roll breakout off-session. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refresh DEPLOY, TRADING, STRATEGY, CTP_LIVE, FEATURES, INDEX, and README to document qihuo-ctp architecture, dual PM2 restarts, and休盘突破加仓. Co-authored-by: Cursor --- README.md | 7 +++-- docs/CTP_LIVE.md | 19 ++++++++++-- docs/DEPLOY.md | 81 +++++++++++++++++++++++++++++++++++------------- docs/FEATURES.md | 12 ++++--- docs/INDEX.md | 2 ++ docs/STRATEGY.md | 40 ++++++++++++++++-------- docs/TRADING.md | 12 +++++++ 7 files changed, 130 insertions(+), 43 deletions(-) diff --git a/README.md b/README.md index 943d7a9..7e21aad 100644 --- a/README.md +++ b/README.md @@ -46,9 +46,12 @@ cd /opt/qihuo && bash deploy.sh cd /opt/qihuo git fetch origin && git reset --hard origin/main source venv/bin/activate && pip install -r requirements.txt -pm2 restart qihuo +python scripts/run_schema_migrate.py +pm2 restart ecosystem.config.cjs --update-env ``` +生产环境须同时维护 **`qihuo`**(Web)与 **`qihuo-ctp`**(CTP Worker)两个 PM2 进程。 + 详见 [部署文档](docs/DEPLOY.md)。 **本地开发** @@ -69,7 +72,7 @@ python app.py ## 环境要求 - Python 3.10+(vnpy_ctp) -- PM2(生产部署) +- PM2(生产部署:**qihuo** + **qihuo-ctp** 两个进程) - 网络:新浪行情、Git 仓库、SimNow/CTP 前置(见部署文档) ## 仓库 diff --git a/docs/CTP_LIVE.md b/docs/CTP_LIVE.md index 3ffc609..e25b6bc 100644 --- a/docs/CTP_LIVE.md +++ b/docs/CTP_LIVE.md @@ -2,7 +2,22 @@ 本文说明如何接入 **期货公司实盘 CTP**,并对比 **SimNow 模拟盘** 与 **实盘** 的开平仓逻辑是否一致。 -相关代码:`vnpy_bridge.py`、`ctp_settings.py`、`trading_context.py`、`install_trading.py`。 +相关代码:`vnpy_bridge.py`、`ctp_worker.py`、`ctp_ipc_client.py`、`ctp_settings.py`、`trading_context.py`、`install_trading.py`。 + +--- + +## 进程架构(Web / CTP Worker) + +自 2026-03 起,CTP 与 vn.py **不在 Flask 进程内**运行: + +| 组件 | PM2 名 | 说明 | +|------|--------|------| +| Web | `qihuo` | 页面与 API;`QIHUO_CTP_ROLE=client`,经 `127.0.0.1:6601` IPC 访问 Worker | +| CTP Worker | `qihuo-ctp` | 唯一加载 vnpy_ctp;连接、报单、持仓回调、止盈止损、滚仓 pending 监控 | + +SimNow 与期货公司实盘的 **报单代码路径不变**,仍走 `execute_order()` → `vnpy_bridge.send_order()`;Web 侧为 IPC 代理,Worker 侧为原生调用。 + +部署与重启见 [DEPLOY.md](./DEPLOY.md)。 --- @@ -76,7 +91,7 @@ CTP_LIVE_ENV=实盘 3. **下单监控** → **连接 CTP** 4. 顶栏显示 **CTP 已连接**、**期货公司实盘**,权益为柜台资金 -修改模式或前置后建议 **重连 CTP** 或 `pm2 restart qihuo`。 +修改模式或前置后建议 **重连 CTP** 或 `pm2 restart ecosystem.config.cjs --update-env`(同时重启 Web 与 Worker)。 --- diff --git a/docs/DEPLOY.md b/docs/DEPLOY.md index fa646e9..4cb96e1 100644 --- a/docs/DEPLOY.md +++ b/docs/DEPLOY.md @@ -10,11 +10,21 @@ |------|--------| | 部署目录 | `/opt/qihuo` | | 运行用户 | `root`(与 `deploy.sh` / PM2 配置一致) | -| 服务端口 | `6600` | -| 进程管理 | PM2,应用名 `qihuo` | +| Web 端口 | `6600`(对外) | +| CTP Worker 端口 | `6601`(仅 `127.0.0.1`,Web 进程 IPC 调用,勿对外开放) | +| 进程管理 | PM2:`qihuo`(Flask Web)+ `qihuo-ctp`(CTP / vn.py 独立进程) | | 数据库 | **生产推荐 PostgreSQL**(见 [POSTGRES.md](./POSTGRES.md));未配置 `DATABASE_URL` 时使用 SQLite `futures.db` | | 仓库 | https://git.bz121.com/dekun/qihuo.git | +### 进程架构(2026-03 起) + +| PM2 应用 | 角色 | 说明 | +|----------|------|------| +| `qihuo` | Web(`QIHUO_CTP_ROLE=client`) | Flask、页面、API、数据库;通过 HTTP 调用本机 Worker | +| `qihuo-ctp` | Worker(`QIHUO_CTP_ROLE=worker`) | **唯一** 加载 vn.py / vnpy_ctp;CTP 连接、报单、持仓回调、止盈止损 tick、滚仓监控 | + +Web 进程崩溃或重启 **不会** 直接带走 CTP 原生连接;Worker 重启后 Web 会自动通过 IPC 恢复读写。两个进程的 Token 须一致(见 `ecosystem.config.cjs` 中 `QIHUO_CTP_WORKER_TOKEN`)。 + --- ## 环境要求 @@ -54,7 +64,7 @@ bash deploy.sh 6. 首次生成 `.env`,并补全 `SIMNOW_ENV=实盘`、`CTP_AUTO_RECONNECT=true` 等缺项 7. **自动探测 SimNow 前置**(`nc` 测端口),写入可用的 `SIMNOW_TD/MD_ADDRESS`(优先 `182.254.243.31`,其次 `180.168.146.187`) 8. 若已配置 SimNow 账号,运行 `scripts/test_simnow.py` 验证连接 -9. `pm2 restart --update-env` 或首次 `pm2 start`,并 `pm2 save` +9. `pm2 restart ecosystem.config.cjs --update-env` 或首次 `pm2 start ecosystem.config.cjs`,并 `pm2 save`(同时启动 **`qihuo`** 与 **`qihuo-ctp`**) 部署完成后访问:`http://<服务器IP>:6600` @@ -140,6 +150,9 @@ nano .env | `SIMNOW_MD_ADDRESS` | SimNow 行情前置 | | `CTP_LIVE_*` | 期货公司实盘 CTP(后期接入,见 `.env.example`) | | `TRADING_MODE` | `simulation`(SimNow)/ `live`(实盘) | +| `QIHUO_CTP_WORKER_TOKEN` | Web ↔ Worker IPC 鉴权(默认见 `ecosystem.config.cjs`,生产建议改随机串并保持两进程一致) | +| `QIHUO_CTP_WORKER_URL` | Web 侧 Worker 地址,默认 `http://127.0.0.1:6601` | +| `DATABASE_URL` | PostgreSQL 连接串(可选,见 [POSTGRES.md](./POSTGRES.md)) | 示例: @@ -171,11 +184,18 @@ SimNow 前置地址会随官网更新,部署前请到 [SimNow 官网](https:// ```bash cd /opt/qihuo -pm2 start ecosystem.config.cjs +pm2 start ecosystem.config.cjs # 启动 qihuo + qihuo-ctp pm2 save pm2 startup # 按提示执行命令,实现开机自启 ``` +确认两个进程均为 `online`: + +```bash +pm2 status +# 应看到 qihuo 与 qihuo-ctp +``` + ### 7. 创建日志目录(若不存在) ```bash @@ -194,9 +214,13 @@ git fetch origin git reset --hard origin/main source venv/bin/activate pip install -r requirements.txt -pm2 restart qihuo +python scripts/run_schema_migrate.py +pm2 restart ecosystem.config.cjs --update-env +pm2 save ``` +> 须 **同时重启** `qihuo` 与 `qihuo-ctp`。仅 `pm2 restart qihuo` 会导致 Web 与 Worker 代码/协议不一致。 + 若服务器曾用 SCP 覆盖文件导致 `git pull` 冲突,用 `git reset --hard origin/main` 与远端对齐。 若 `vnpy_ctp` 安装失败(常见于缺少编译环境): @@ -205,7 +229,7 @@ pm2 restart qihuo apt install -y build-essential python3-dev pkg-config source venv/bin/activate pip install --no-cache-dir vnpy vnpy_ctp -pm2 restart qihuo +pm2 restart ecosystem.config.cjs --update-env ``` 应用启动时会自动执行 SQLite 表结构迁移(`ALTER TABLE` 容错),一般无需手工改库。 @@ -213,8 +237,11 @@ pm2 restart qihuo ### 首次启用 CTP 下单 1. 浏览器登录 → **系统设置** 确认 **模拟盘 · SimNow** -2. 打开 **下单监控** 页 → 点击 **连接 CTP** -3. 连接成功后:权益来自柜台、显示 CTP 持仓、可报单与可开仓品种筛选 +2. 确认 `pm2 status` 中 **`qihuo-ctp` 为 online** +3. 打开 **下单监控** 页 → 点击 **连接 CTP**(或由后台自动重连) +4. 连接成功后:权益来自柜台、显示 CTP 持仓、可报单与可开仓品种筛选 + +CTP 连接与重连在 **`qihuo-ctp` Worker** 内执行;页面仅轮询状态,**切换页面不会重复发起连接**。 详见 [TRADING.md](./TRADING.md)。 @@ -223,19 +250,22 @@ pm2 restart qihuo ## PM2 常用命令 ```bash -pm2 status # 查看状态 -pm2 logs qihuo # 查看日志 +pm2 status # 查看 qihuo / qihuo-ctp 状态 +pm2 logs qihuo # Web 日志 +pm2 logs qihuo-ctp # CTP Worker 日志 pm2 logs qihuo --lines 100 -pm2 restart qihuo # 重启 -pm2 stop qihuo # 停止 -pm2 delete qihuo # 删除进程 -pm2 save # 保存进程列表 +pm2 restart ecosystem.config.cjs --update-env # 同时重启两个进程(推荐) +pm2 restart qihuo # 仅重启 Web +pm2 restart qihuo-ctp # 仅重启 CTP Worker(Web 应仍可访问) +pm2 stop qihuo # 停止 Web +pm2 delete qihuo # 删除 Web 进程 +pm2 save # 保存进程列表 ``` 日志文件: -- `/opt/qihuo/logs/pm2-out.log` -- `/opt/qihuo/logs/pm2-error.log` +- `/opt/qihuo/logs/pm2-out.log`、`pm2-error.log` — Web(`qihuo`) +- `/opt/qihuo/logs/pm2-ctp-out.log`、`pm2-ctp-error.log` — CTP Worker(`qihuo-ctp`) --- @@ -260,7 +290,7 @@ python app.py | 场景 | 操作 | |------|------| | 首次部署 | `.env` 中设置 `ADMIN_USERNAME` / `ADMIN_PASSWORD` 后启动 | -| 已部署后改 `.env` 密码 | 设 `ADMIN_SYNC_FROM_ENV=true`,`pm2 restart qihuo` | +| 已部署后改 `.env` 密码 | 设 `ADMIN_SYNC_FROM_ENV=true`,`pm2 restart ecosystem.config.cjs --update-env` | | 网页改密码 | 登录 → 系统设置 | | 忘记密码 | `cd /opt/qihuo && source venv/bin/activate && python reset_admin.py` | @@ -340,6 +370,9 @@ ufw allow 6600/tcp | 现象 | 可能原因 | 处理 | |------|----------|------| | 无法访问 6600 | 服务未启动 / 防火墙 | `pm2 status`、`pm2 logs qihuo` | +| **`qihuo-ctp` 不在线 / 反复重启** | vnpy 崩溃、SimNow 前置不可达、locale 缺失 | `pm2 logs qihuo-ctp --lines 200`;核对 SimNow 前置与 `zh_CN.GB18030` | +| **页面显示 CTP 未连接但 Worker 正常** | Web 与 Worker Token 不一致 | 检查 `ecosystem.config.cjs` 两进程 `QIHUO_CTP_WORKER_TOKEN` 相同后重启 | +| **API 报 `CTP worker unavailable`** | Worker 未启动或 6601 不可达 | `curl -s http://127.0.0.1:6601/health`;`pm2 restart qihuo-ctp` | | 登录失败 | 密码未同步 | 网页改密或 `reset_admin.py` | | 现价一直 `--` | 新浪网络不可达 | 检查服务器能否访问 `hq.sinajs.cn` | | 关键位 500 | 缺 `sina_code` 列 | `git pull` 重启;或手工 `ALTER TABLE` | @@ -387,7 +420,7 @@ source venv/bin/activate apt install -y build-essential python3-dev pkg-config # 首次需要 pip install -r requirements.txt python -c "from vnpy_ctp import CtpGateway; print('OK')" -pm2 restart qihuo +pm2 restart ecosystem.config.cjs --update-env ``` **2. 配置 SimNow(`.env`)** @@ -404,7 +437,7 @@ pm2 restart qihuo |-----------|------| | `pip install vnpy_ctp` 编译失败 / `Python dependency not found` | 安装 `build-essential python3-dev pkg-config` 后重试 | | CTP 连接超时 | 检查前置 IP、端口、SimNow 是否维护、是否在允许连接时段 | -| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | CTP 需 **zh_CN.GB18030**:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030`,再 `pm2 restart qihuo --update-env` | +| 连接后立即崩溃 `locale::facet::_S_create_c_locale` | CTP 需 **zh_CN.GB18030**:`sed -i '/^# zh_CN.GB18030/s/^# //' /etc/locale.gen && locale-gen zh_CN.GB18030`,再 `pm2 restart ecosystem.config.cjs --update-env` | | 服务器 `180.168.146.187` 超时 | 换 SimNow 备用前置 `182.254.243.31:30001/30011`(见 [SIMNOW.md](./SIMNOW.md)) | | 已连接但下单拒单 | 检查合约代码、价格精度、是否有足够保证金 | @@ -424,7 +457,9 @@ pm2 restart qihuo ``` /opt/qihuo/ ├── app.py -├── vnpy_bridge.py # CTP 执行层 +├── vnpy_bridge.py # CTP 桥接(Web=IPC 代理,Worker=原生 vn.py) +├── ctp_ipc_client.py # Web → Worker HTTP 客户端 +├── ctp_worker.py # 独立 CTP Worker 入口(PM2: qihuo-ctp) ├── recommend_store.py # 可开仓品种缓存 ├── recommend_stream.py # 可开仓品种 SSE 推送 ├── venv/ @@ -432,10 +467,12 @@ pm2 restart qihuo ├── .env ├── logs/ │ ├── pm2-out.log -│ └── pm2-error.log +│ ├── pm2-error.log +│ ├── pm2-ctp-out.log +│ └── pm2-ctp-error.log ├── uploads/ ├── data/fee_rates.json -├── ecosystem.config.cjs +├── ecosystem.config.cjs # PM2:qihuo + qihuo-ctp ├── deploy.sh ├── requirements.txt # 含 vnpy、vnpy_ctp └── docs/ diff --git a/docs/FEATURES.md b/docs/FEATURES.md index 4b5e46f..2acae0d 100644 --- a/docs/FEATURES.md +++ b/docs/FEATURES.md @@ -79,7 +79,8 @@ **路径**:`/strategy`、`/strategy/records` · 详见 [STRATEGY.md](./STRATEGY.md) -- 趋势回调自动补仓、顺势加仓等(需 CTP 已连接且有 active 持仓监控) +- 趋势回调(首仓/补仓/止盈须 CTP + 交易时段) +- 顺势加仓:**市价**须交易时段;**突破**可休盘提交监控,开盘触价成交 - 策略记录单独归档 --- @@ -248,9 +249,10 @@ | 计划/关键位轮询 | 约 3 秒,触发判断与微信推送 | | 可开仓品种刷新 | 每日 + 按需 | | 持仓 SSE | 前端订阅 `/api/trading/stream` | -| CTP 开盘前连接 | 默认开盘前 30 分钟 | +| CTP 开盘前连接 | 默认开盘前 30 分钟(`qihuo-ctp` Worker) | | 挂单超时撤单 | 可配置分钟数 | -| 止盈止损守护 | CTP 持仓监控线程 | +| 止盈止损守护 | `qihuo-ctp` Worker 内 tick 监控 | +| 滚仓 pending 监控 | `qihuo-ctp` Worker,交易时段扫描突破触价 | | 数据库自动备份 | 每日定时(默认 03:00)写入 `/root/qihuo_backup` | --- @@ -261,7 +263,9 @@ qihuo/ ├── app.py # 主路由、计划/关键位/记录/统计 ├── install_trading.py # 下单、可开仓品种、策略路由 -├── vnpy_bridge.py # CTP 连接、报单、持仓 +├── vnpy_bridge.py # CTP 桥接(Web=IPC,Worker=vn.py) +├── ctp_worker.py # 独立 CTP Worker(PM2: qihuo-ctp) +├── ctp_ipc_client.py # Web → Worker HTTP 客户端 ├── ctp_trade_sync.py # 柜台成交同步到 trade_logs ├── product_recommend.py # 可开仓品种计算 ├── stats_engine.py # 统计分析 diff --git a/docs/INDEX.md b/docs/INDEX.md index 9bd5393..3421f47 100644 --- a/docs/INDEX.md +++ b/docs/INDEX.md @@ -60,3 +60,5 @@ | 看板风控各指标什么意思 | [风控说明.md](./风控说明.md) | | 移动保本怎么抬止损 | [ORDER_MONITOR.md#移动保本](./ORDER_MONITOR.md) | | 实盘 CTP 怎么接、和 SimNow 开平是否一样 | [CTP_LIVE.md](./CTP_LIVE.md) | +| CTP 双进程、Worker 日志、6601 端口 | [DEPLOY.md](./DEPLOY.md) | +| 休盘能否提交突破滚仓 | [STRATEGY.md](./STRATEGY.md) | diff --git a/docs/STRATEGY.md b/docs/STRATEGY.md index 75274ae..4d76a08 100644 --- a/docs/STRATEGY.md +++ b/docs/STRATEGY.md @@ -2,7 +2,7 @@ **页面路径**:`/strategy`、`/strategy/records` -**相关文件**:`install_trading.py`(趋势回调、顺势加仓/滚仓) +**相关文件**:`install_trading.py`、`strategy/strategy_roll_lib.py`、`strategy/strategy_roll_monitor_lib.py` --- @@ -13,7 +13,8 @@ | 趋势回调 | 首仓 + 网格补仓 + 统一止盈 | | 顺势加仓(滚仓) | 对已有 active 持仓加仓,单独保证金上限 | -均需 **CTP 已连接** 且有对应持仓监控。 +趋势首仓与 **市价滚仓** 须 **交易时段内** 且 **CTP 已连接**。 +**突破加仓** 可在 **休盘**(小节休息、午间、日盘收盘后)提交监控,开盘触价后由 Worker 自动市价加仓。 --- @@ -61,9 +62,18 @@ ## 顺势加仓(滚仓)— 下单逻辑 -针对 **已有 active 持仓** 的加仓预览与执行。 +针对 **已有 active 持仓监控** 的加仓预览与执行。须 **固定金额(以损定仓)** 模式;**移动保本** 持仓不可滚仓。 -**特殊风控**: +### 加仓方式 + +| 方式 | 提交时机 | 执行 | +|------|----------|------| +| **市价加仓** | 仅 **交易时段** | 预览 → 10 秒倒计时 → 立即 CTP 市价成交 | +| **突破加仓** | **任意时间**(含休盘) | 预览 → **提交监控** → 标记价穿越突破价后 Worker 自动市价加仓 | + +休盘提交突破加仓时,几何校验放宽为「止损 vs 突破价」关系,不强制要求实时现价;开盘后有行情后按触价逻辑成交。 + +### 特殊风控 | 项 | 说明 | |----|------| @@ -71,20 +81,24 @@ | `roll_max_margin_pct` | 滚仓后总保证金占用单独上限 | | 手数收紧 | `cap_lots_for_margin_budget()` 按滚仓上限裁剪 | -流程:预览加仓价/手数/新止损 → 确认 → CTP 市价加仓 → 更新 monitor。 +流程: + +- **市价**:预览 → 确认 → CTP 市价加仓 → 更新 monitor +- **突破**:预览 → 提交 pending 腿 → `check_roll_monitors`(在 `qihuo-ctp` Worker 内)触价成交 --- ## 风控规则 -| 规则 | 趋势首仓 | 滚仓 | -|------|----------|------| -| assert_can_open | ✓ | 仓位冻结时仍可 | -| max_margin_pct | ✓ 首仓 | — | -| roll_max_margin_pct | — | ✓ | -| 交易时段 | ✓ | ✓ | -| 品种范围 | ✓ | ✓ | -| 单笔 50 手 | ✓ | ✓ | +| 规则 | 趋势首仓 | 市价滚仓 | 突破滚仓(pending) | +|------|----------|----------|---------------------| +| assert_can_open | ✓ | 仓位冻结时仍可 | 仓位冻结时仍可 | +| max_margin_pct | ✓ 首仓 | — | — | +| roll_max_margin_pct | — | ✓ | ✓(预览时按突破价估算) | +| 交易时段 | ✓ | ✓ | 提交 **不要求**;成交须交易时段 | +| CTP 连接 | ✓ | ✓ | 提交 **不要求**;触价成交须 CTP | +| 品种范围 | ✓ | ✓ | ✓ | +| 单笔 50 手 | ✓ | ✓ | ✓ | 全局规则见 [RISK.md](./RISK.md)。 diff --git a/docs/TRADING.md b/docs/TRADING.md index ae5b5cd..4ed4406 100644 --- a/docs/TRADING.md +++ b/docs/TRADING.md @@ -23,6 +23,18 @@ 模拟盘与实盘均走 **vnpy_ctp**,无本地假撮合。 **实盘接入与开平仓对比** → [CTP_LIVE.md](./CTP_LIVE.md) · SimNow → [SIMNOW.md](./SIMNOW.md) +### CTP 双进程与连接行为 + +| 项目 | 说明 | +|------|------| +| Web | PM2 `qihuo`,端口 6600 | +| CTP Worker | PM2 `qihuo-ctp`,端口 6601(本机) | +| 连接/重连 | 在 Worker 内执行;**小节休息、午间休盘** 仍保持连接(便于读缓存权益/持仓) | +| 页面行为 | 各页 **仅轮询** CTP 状态,**不会在打开页面时自动发起连接** | +| 权益缓存 | CTP 短暂断开时,看板/持仓可回退读最近快照 | + +手动 **连接 CTP** 仍通过 **下单监控** 页按钮或 API;成功后顶栏显示「CTP 已连接」。 + ## 下单与持仓 - **限价开仓**:先显示「挂单中」,柜台成交后进入持仓监控;超时未成交自动撤单(时长见系统设置)