# 手工交易多账户中控(manual_trading_hub) > **完整操作说明见 [使用说明.md](./使用说明.md)**(监控区 / 系统设置、鉴权、四所能力与故障排查)。 本目录提供多账户 **监控 + 紧急全平**。人工下单、关键位、趋势回调请在各 `crypto_monitor_*` 实例网页操作;策略与复盘仍在各实例。 --- ## 功能概览 | 能力 | 说明 | |------|------| | 监控 | 汇总各子代理的永续持仓、未实现盈亏、余额(USDT)、持仓模式等 | | 单账户全平 | 对某一子代理发起市价减仓,尽量平掉该所 USDT 永续仓位 | | 全局全平 | 对当前「已开启监控」的子代理依次发起全平 | | 关闭某账户 | 网页上取消「参与监控」,或环境变量 `HUB_DISABLED_IDS`;被关闭的不轮询、不参与全局全平 | --- ## 架构说明 ``` 浏览器 → 中控 hub.py(默认监听 0.0.0.0:5100,私网可访问;本机仍可用 127.0.0.1) ↓ HTTP 子代理 agent.py × N(默认 127.0.0.1:15200~15203,与 Flask 的 APP_PORT 错开) ↓ ccxt 各交易所 API ``` - **中控(hub)**:读配置、并行请求各子代理 `/status`;全平时转发 `POST /emergency/close-all`。 - **子代理(agent)**:每个进程绑定一个交易所 API Key,只做只读状态 + 紧急平仓;与 `crypto_monitor_*` 里的 Flask **独立进程**,互不影响日常手工/策略操作。 ### 与四个 `crypto_monitor_*` 目录的关系(已对照 `app.py`) 各策略项目在**本目录**用 **`.env`**(由 **`cp .env.example .env`** 生成,勿提交 Git;`git pull` 不覆盖)加载配置(`load_env_file`),并用其中的 **`APP_HOST` / `APP_PORT`** 启动 **Flask 网页**(`app.py` 里 `HOST`、`PORT`)。这是你在浏览器里打开策略/监控后台用的端口,例如 `APP_PORT=5001`。 子代理 **不用 `APP_PORT`**,而是用环境变量 **`PORT`**(FastAPI/uvicorn 监听)。若子代理与 Flask 抢同一端口,后启动的会起不来,因此中控默认把子代理配在 **`15200`~`15203`**,与常见 `5000` 段 Flask 配置**错开**。 | 子代理 `PORT`(建议) | 对应策略目录 | `EXCHANGE` | |----------------------|--------------|------------| | 15200 | `crypto_monitor_binance` | `binance` | | 15201 | `crypto_monitor_okx` | `okx` | | 15202 | `crypto_monitor_gate` | `gate` | | 15203 | `crypto_monitor_gate_bot` | `gate` | Flask 仍可继续用 `APP_HOST=0.0.0.0` 方便云服务器外网访问;**子代理**建议 **`HOST=127.0.0.1`**。中控默认 `HUB_HOST=0.0.0.0` 便于局域网打开页面;若只给自己用,设 `HUB_HOST=127.0.0.1` 或 `HUB_TRUST_LAN=0`。 --- ## 依赖 - Python 3.10+(与仓库其他项目相近即可) - 见 `requirements.txt`:`fastapi`、`uvicorn`、`httpx`、`ccxt` 安装: ```bash cd manual_trading_hub pip install -r requirements.txt ``` 建议使用独立虚拟环境,避免与全局包冲突。 --- ## 快速启动(本机) ### 1. 启动子代理(每个账户一个终端) 在**对应策略目录**下加载该目录已有 `.env`(含 API 密钥与可选代理),再启动 agent,避免密钥分散维护两套。 **Binance(子代理端口 15200,与 Flask APP_PORT 无关)** ```powershell cd ..\crypto_monitor_binance $env:EXCHANGE="binance" $env:PORT="15200" $env:HOST="127.0.0.1" python ..\manual_trading_hub\agent.py ``` **OKX(15201)** ```powershell cd ..\crypto_monitor_okx $env:EXCHANGE="okx" $env:PORT="15201" python ..\manual_trading_hub\agent.py ``` **Gate / Gate-Bot(15202 / 15203)** ```powershell $env:EXCHANGE="gate" $env:PORT="15202" # Gate-Bot 用 15203 python ..\manual_trading_hub\agent.py ``` ### 2. 启动中控 ```powershell cd manual_trading_hub $env:HUB_HOST="0.0.0.0" $env:HUB_PORT="5100" # 可选:自定义各账户卡片标题(顺序与默认 HUB_AGENTS 一致:15200→15201→15202→15203) # $env:HUB_AGENT_NAMES="币安主号,OKX,Gate主号,Gate机器人" python hub.py ``` 浏览器打开:**http://127.0.0.1:5100/** 或 **http://本机局域网IP:5100/** --- ## 子代理(agent)环境变量 | 变量 | 含义 | 默认 | |------|------|------| | `EXCHANGE` | `binance` / `okx` / `gate` | `binance` | | `HOST` | 监听地址 | `127.0.0.1` | | `PORT` | 子代理监听端口(勿与 Flask 的 `APP_PORT` 相同) | `15200` | | `CONTROL_TOKEN` | 若设置,请求须带头 `X-Control-Token` | 空 | **Binance**:`BINANCE_API_KEY`、`BINANCE_API_SECRET`;可选 `BINANCE_POSITION_MODE`(`hedge`/`oneway`)、`BINANCE_MARGIN_MODE`;代理 `BINANCE_SOCKS_PROXY` 或 `BINANCE_HTTP_PROXY` / `HTTPS_PROXY`。`/status` 的 `balance_usdt` 为 **U 本位永续合约**账户 USDT(与 `crypto_monitor_binance` 合约口径一致,非现货钱包)。 **OKX**:`OKX_API_KEY`、`OKX_API_SECRET`、`OKX_API_PASSPHRASE`;可选 `OKX_TD_MODE`、`OKX_POS_MODE`;代理 `OKX_SOCKS_PROXY` 等。 **Gate**:`GATE_API_KEY`、`GATE_API_SECRET`;可选 `GATE_TD_MODE`、`GATE_POS_MODE`;代理 `GATE_SOCKS_PROXY` 等。 --- ## 中控(hub)环境变量 | 变量 | 含义 | 默认 | |------|------|------| | `HUB_HOST` | 监听地址 | `0.0.0.0`(局域网可连);`127.0.0.1` 仅本机 | | `HUB_PORT` | 监听端口 | `5100` | | `HUB_AGENTS` | 子代理 base URL,逗号分隔 | `http://127.0.0.1:15200` … `15203` | | `HUB_AGENT_NAMES` | 与 `HUB_AGENTS` **顺序一一对应**的卡片显示名(逗号分隔)。不设则用内置默认名。改后需重启 hub,**所有访问该中控的浏览器**显示一致 | 内置与四目录对应的英文标签 | | `HUB_DISABLED_IDS` | 不参与监控与全局全平的账户 `id`,逗号分隔(如暂不用 OKX 写 `1`) | 空 | | `HUB_TRUST_LAN` | 默认 `true`;设为 `0`/`false`/`off` 则仅允许本机 IP 访问中控 | 开 | | `CONTROL_TOKEN` | 与子代理一致时,中控代发 `X-Control-Token` | 空 | --- ## 网页操作说明 - **立即刷新 / 自动刷新**:拉取最新汇总;自动刷新默认约 3 秒一轮(仅请求已开启监控的账户)。 - **账户显示名**:在运行 `hub.py` 的机器上设置环境变量 **`HUB_AGENT_NAMES`**(逗号分隔,顺序与 **`HUB_AGENTS`** 里每个子代理 URL 一致),重启中控后,任意电脑打开同一中控地址都会看到相同名称。名称里若含逗号,需整体用引号包裹或避免使用逗号。 - **参与监控**:勾选则参与轮询与「全局一键全平」;取消则本浏览器记住(`localStorage` 键 `manual_trading_hub_excluded`),不再请求该子代理。 - **该账户全平**:仅针对该子代理;与是否关闭「参与监控」无关(仍可直接调交易所紧急平仓)。 - **全局一键全平**:只对当前「参与监控」且未被 `HUB_DISABLED_IDS` 关闭的账户发起全平;请求体中的 `exclude_ids` 与网页关闭状态一致。 服务端 `HUB_DISABLED_IDS` 与浏览器关闭**取并集**:任一方关闭即不轮询、不进全局全平。 --- ## HTTP API(访问控制与浏览器一致) 允许来源:**本机**或 **RFC1918 私网 IPv4**(与 `HUB_TRUST_LAN` 开启时一致);`HUB_TRUST_LAN=0` 时仅本机。 | 方法 | 路径 | 说明 | |------|------|------| | GET | `/` | 中控页面 | | GET | `/api/agents` | 当前配置的账户列表(id、name、url) | | GET | `/api/snapshot` | 聚合状态;可选查询参数 `exclude_ids`(逗号分隔 id) | | POST | `/api/close/{agent_id}` | 单账户紧急全平 | | POST | `/api/close-all` | JSON 体可选 `{"exclude_ids":["1"]}`,与 `HUB_DISABLED_IDS` 合并 | 子代理: | 方法 | 路径 | 说明 | |------|------|------| | GET | `/health` | 健康检查 | | GET | `/status` | 余额、持仓、盈亏汇总 | | POST | `/emergency/close-all` | 市价尽量平掉 USDT 永续仓位,并尝试撤该合约挂单 | --- ## 安全与边界 - 中控默认 **监听 0.0.0.0** 并放行私网访问,便于局域网使用;**公网非私网 IP** 仍会被中间件拒绝。 - 若机器有公网 IP,请用 **防火墙** 限制 `HUB_PORT` 仅内网可进,或改为 `HUB_HOST=127.0.0.1` + `HUB_TRUST_LAN=0` 仅本机。 - 子代理建议仍用 **`HOST=127.0.0.1`**,不要对局域网暴露交易所密钥通道。 - 中控**不具备**开仓、改策略、划转账能力;全平为**市价减仓**,请谨慎操作。 - 子代理与主策略进程共用密钥时,注意权限与 IP 白名单仍按交易所要求配置。 --- ## 常见问题 **1. 某一行一直连不上** 检查该端口上的 `agent.py` 是否已启动、防火墙是否放行本机回环、`.env` 密钥是否与交易所一致。 **2. 暂时不用 OKX** 网页取消该行的「参与监控」,或启动中控前设置 `HUB_DISABLED_IDS=1`(默认 OKX 的 id 为 `1`)。 **3. 策略项目要不要改?** 不需要改 `crypto_monitor_*` 代码;只需额外运行 `agent.py` 进程。 **5. 局域网里别的电脑打不开中控** 默认应已可访问:中控监听 `0.0.0.0` 且 `HUB_TRUST_LAN` 默认开启。请检查:防火墙是否放行 `HUB_PORT`;浏览器是否使用 **中控机器的局域网 IP**(不要用另一台电脑上的 `127.0.0.1`)。若你曾设置 `HUB_TRUST_LAN=0` 或 `HUB_HOST=127.0.0.1`,改回默认或删掉环境变量后重启 hub。 **Linux 常驻(PM2)**:`pm2 start ecosystem.config.cjs` 会**同时**启动 4 路子代理 + 中控 `manual-trading-hub`。详见 **《部署文档.md》**。