# 中控与三实例 — 常见问题实录

本文档整理部署与运行 **manual_trading_hub**（复盘系统中控）及三所 `crypto_monitor_*` 时**实际遇到过**的问题与处理办法。操作步骤仍以 [使用说明.md](./使用说明.md)、[部署文档.md](./部署文档.md) 为准。

---

## 一、中控进程与代码版本

### 1.1 PM2 日志仍出现 `api_trade_key`、`python-multipart` 断言

**现象**：`pm2 logs` 里报错 `File "hub.py", line 324, in api_trade_key` 或 `The python-multipart library must be installed`。

**原因**：

- 服务器上的 `hub.py` 仍是**旧版**（含已移除的「下单区」接口），或 pull 后**未重启** PM2，日志是历史残留。
- 旧版「添加关键位」会 `request.form()`，未装 `python-multipart` 时直接 500。

**处理**：

```bash
cd /opt/crypto_monitor
git pull

cd manual_trading_hub
bash scripts/fix_hub_deps.sh          # 安装 python-multipart 等
bash scripts/verify_hub_deploy.sh     # 应显示无 api_trade_key、含 HUB_BUILD

pm2 restart manual-trading-hub
curl -s http://127.0.0.1:5100/api/ping
```

**正常 ping**（无需登录）应含 `"build":"20260521-no-trade-ui"`、`"trade_ui":false`。

**说明**：当前版本**已移除中控下单区**；添加关键位、人工下单、趋势回调请在监控卡片点 **「实例」** 进入各 Flask 网页。浏览器请 **Ctrl+F5** 强刷，避免旧前端缓存仍请求 `/api/trade/key`。

---

### 1.2 `curl /api/ping` 返回 `{"detail":"未登录"}`

**原因**：早期版本未把 `/api/ping` 列入免登录白名单（已修复）。

**处理**：`git pull` 后 `pm2 restart manual-trading-hub`；再测应直接返回 JSON，无需 Cookie。

---

### 1.3 `verify_hub_deploy.sh` 报 `Expecting value: line 1 column 1`

**原因**：5100 端口无进程监听（hub 未启动或已崩溃），`curl` 拿到空响应。

**处理**：

```bash
pm2 restart manual-trading-hub
sleep 2
pm2 logs manual-trading-hub --lines 30 --nostream
ss -ltn | grep 5100
bash scripts/verify_hub_deploy.sh
```

---

### 1.4 `bash scripts/fix_hub_deps.sh` 在仓库根目录找不到

**原因**：脚本在 `manual_trading_hub/scripts/` 下，不在 `/opt/crypto_monitor/scripts/`。

**处理**：

```bash
cd /opt/crypto_monitor/manual_trading_hub
bash scripts/fix_hub_deps.sh
```

---

## 二、登录与 Cookie（反代 / 域名 / 内网 IP）

### 2.1 设了密码后，域名能登录，`http://内网IP:5100` 不能

**原因**（最常见）：

- `.env` 中 `HUB_COOKIE_SECURE=true`，且用 **HTTP** 访问 IP:5100 → 浏览器**不保存**带 `Secure` 的 Cookie，表现为登录成功后又跳回登录页。
- **域名（HTTPS）** 与 **IP:5100（HTTP）** 是不同站点，Cookie **不共用**，需在 IP 上再登一次。

**处理**：

- 已支持：仅在实际 **HTTPS** 请求时发 `Secure` Cookie（读 `X-Forwarded-Proto`），HTTP 内网 IP 可正常登录。
- 反代 Nginx 需传：`proxy_set_header X-Forwarded-Proto $scheme;`
- 若仍异常：HTTPS 域名与 HTTP IP **分别登录**；或内网仅用 IP 时可注释 `HUB_COOKIE_SECURE`。

### 2.2 登录后接口仍 401

| 检查项 | 说明 |
|--------|------|
| 用户名密码 | `.env` 中 `HUB_USERNAME`（未设默认为 `admin`）、`HUB_PASSWORD` |
| 改密后 | 需重新登录；旧 Cookie 失效 |
| 混用地址 | 不要用 A 浏览器标签登域名、B 标签指望 IP 已登录 |

### 2.3 本地导航 iframe 嵌入：登录成功但一直「跳转中」/ 进不去

**原因**：父页（如 `http://192.168.8.6:5070`）跨域 `fetch` 中控 `/api/auth/login` 时，浏览器**不会**把 `Set-Cookie` 写进 iframe 里的中控站点，表现为接口 200、弹窗「登录成功」，但 iframe 仍无会话。

**处理**（中控 `git pull` 并重启 hub 后）：

1. 登录接口会返回 `session_token`；父页应把 iframe 指向：
   `http://中控地址/embed-auth?token=会话token&next=/monitor`
2. 若直接在 iframe 内打开中控 `/login` 登录，页面会自动走 `/embed-auth` 写入 Cookie。
3. 父页也可监听 `postMessage`，事件类型 `hub:login-ok`，字段含 `embed_auth_url`。

`.env` 可选：

```env
HUB_ALLOW_EMBED=true
HUB_EMBED_ORIGINS=http://192.168.8.6:5070
```

---

## 三、监控区无数据 / 子代理异常

### 3.1 卡片「子代理不可用」或余额为 —

| 原因 | 处理 |
|------|------|
| agent 未启动 | `pm2 restart ecosystem.config.cjs` 或 `pm2 restart manual-agent-*` |
| Agent URL 与端口不符 | 系统设置里应为 `http://127.0.0.1:15200` 等 |
| PM2 未加载策略 `.env` | 须用 `run_agent.sh` 启动（会 `source` 各目录 `.env`），勿裸跑 `agent.py` |
| `.env` 为 Windows CRLF | 日志 `$'\r': command not found` → `bash scripts/fix_env_crlf.sh` 后重启 |

验证：

```bash
curl -s http://127.0.0.1:15202/status | head -c 300
```

应 `ok: true` 且有 `balance_usdt`。

### 3.3 Gate 子代理「一会正常、一会连不上」（仅 Gate 两户）

| 现象 | 说明 |
|------|------|
| 中控某所子代理红 | 本机对应 agent 端口在 PM2 重启间隙连不上 |
| 日志 `$'\r': command not found` | `crypto_monitor_gate*` 的 `.env` 为 Windows CRLF |
| `curl` 有时通有时不通 | 与 Gate 外网无关，先修 CRLF 并重建 agent |

**修复**（服务器）：

```bash
cd /opt/crypto_monitor
sed -i 's/\r$//' crypto_monitor_gate/.env crypto_monitor_gate/.env
bash manual_trading_hub/scripts/fix_env_crlf.sh
cd manual_trading_hub && pm2 restart manual-agent-gate 
# 仍反复重启时：pm2 delete 后按 ecosystem.config.cjs 重新 start（见部署文档 §5.6）
```

修好后 `pm2 describe manual-agent-gate` 的 **restarts** 应不再疯涨；`pm2 flush manual-agent-gate` 可清掉旧 CRLF 日志。

**若子代理已绿但挂委托失败**：再查 `GATE_SOCKS_PROXY`、API 权限、止损止盈价格是否合理（与各实例策略页相同 `.env` 参数）。

### 3.2 有持仓但无关键位 / 趋势，或提示 Flask 404

| 原因 | 处理 |
|------|------|
| 对应 `crypto_*` Flask 未启动 | `pm2 restart crypto_gate` 等 |
| 未注册 `hub_bridge` | 启动日志勿含 `[hub_bridge] ImportError`；仓库根需在 `PYTHONPATH`（各实例 `ecosystem.config.cjs` 已配 `PYTHONPATH=..`） |
| 中控 `ModuleNotFoundError: hub_auth` | 确认仓库根存在 `/opt/crypto_monitor/hub_auth.py`（`git pull`）；`run_hub.sh` / PM2 已设 `PYTHONPATH=仓库根`；`pm2 restart manual-trading-hub` |
| `HUB_BRIDGE_TOKEN` 不一致 | 中控 `.env` 与三实例 `.env` 设相同令牌，或实例 `APP_AUTH_DISABLED=true`（仅建议本机） |

```bash
curl -s -H "X-Hub-Token:你的令牌" http://127.0.0.1:5000/api/hub/ping
```

### 3.3 中控监控区打开慢、一直转圈

**原因（常见）**：

1. 首屏要等 **`/api/monitor/board`**：向 4 个子代理拉持仓/余额，并向 4 个 Flask 拉监控与（默认）关键位行情；任一实例慢或超时都会拖住整页。
2. 旧版 hub 对每所 Flask **串行**请求，3 所 × 3 接口容易累计到十几秒；新版已改为**并行**（`git pull` 后 `pm2 restart manual-trading-hub`）。
3. 各实例 **`/api/price_snapshot`** 会调交易所接口（含全量持仓），最耗时；内网访问 Google 字体也会拖首屏渲染。
4. 子代理 `/status` 里 `fetch_balance` / `fetch_positions` / 挂单列表走交易所 API，网络差时单次可达数秒。

**加快办法**：

```env
# manual_trading_hub/.env
HUB_BOARD_KEY_PRICES=false   # 不拉 price_snapshot，关键位门控显示为「-」，首屏明显更快
HUB_AGENT_TIMEOUT=6
HUB_FLASK_TIMEOUT=8
```

并确认三所 `crypto_*` 与 `manual-agent-*` 均为 **online**，避免等满超时。浏览器 **Ctrl+F5** 强刷静态资源（版本号含 `20260525-perf`）。

---

## 四、云服务器 / 公网反代

**云服务器完整配置（安全组、宝塔、环境变量、PM2、验收）** 见 **[云服务器部署说明.md](./云服务器部署说明.md)**。

---

## 五、复盘链接与公网反代

### 4.1 监控里点「复盘」打开的是本机 127.0.0.1

**原因**：未设 `HUB_PUBLIC_ORIGIN`，浏览器拿到的链接仍是 Flask 本机地址。

**处理**：`manual_trading_hub/.env` 增加（示例）：

```env
HUB_PUBLIC_ORIGIN=http://192.168.8.6
```

或 `HUB_PUBLIC_HOST=192.168.8.6`。改后 `pm2 restart manual-trading-hub`。

**说明**：仅反代中控、三实例 Flask 仍只监听 127.0.0.1 时，其它电脑要能打开复盘，还须能访问各实例端口或单独反代。

### 4.2 只反代中控、不反代三实例

**可以**。中控聚合监控与全平；复盘、下单、关键位维护进各实例网页。实例 Flask/agent 建议 `127.0.0.1` + 与中控相同的 `HUB_BRIDGE_TOKEN`。

### 4.3 从中控「打开实例」仍要输密码

**完整说明**：[局域网与反代部署说明.md](./局域网与反代部署说明.md)

**常见原因**：

1. 三实例未重启，`/hub-sso` 未加载（启动日志勿长期 `[hub_bridge] ImportError`）。
2. `HUB_BRIDGE_TOKEN` 与三实例 `.env` 不一致。
3. `hub_settings` 里该户 `key` 与实例 `install_on_app(exchange=...)` 不一致（如 `okx`、`gate`）。
4. **HTTPS 跨域 iframe**：中控与实例不同域名时，三实例须 `APP_COOKIE_SECURE=true`（使 session Cookie 为 `SameSite=None`），否则 SSO 成功仍跳 `/login`。
5. **经本地导航打开中控**（LocalNav → 中控 iframe → 点实例）：旧版会在中控内再嵌一层实例 iframe，Cookie 易失效。请升级 **LocalNav + 中控** 最新代码：点实例后由导航页直接打开实例，工具栏有「← 中控」；须配置 `NAV_HUB_USERNAME` / `NAV_HUB_PASSWORD`，三实例 `HUB_EMBED_PARENT_ORIGINS` 含本地导航地址（如 `http://192.168.8.6:5070`）。
6. 浏览器仍用旧书签直链首页，未从中控点「实例」（直链本来就要登录）。

**直链**：`http://IP:端口` 或 `https://实例域名` → 使用各实例 **`APP_USERNAME` / `APP_PASSWORD`**（三所建议统一）。

---

## 六、Gate / 复盘相关（实例侧）

### 5.1 Gate `/records` 或预览 500（`preview_created_at`）

**原因**：数据库缺列或查询未兼容旧库。

**处理**：`git pull` 后重启 `crypto_gate`；必要时在实例目录执行一次带 `init_db` 的启动或按该目录更新文档迁移。

### 5.2 中控监控区 Gate「无关键位」

**说明**：若系统设置未勾选「监控关键位」，中控不会展示关键位区块；策略交易仍在各实例 `/strategy` 操作。

---

## 七、环境与配置

### 6.1 OKX 默认不显示

`HUB_DISABLED_IDS=1`（默认关 OKX）。要用 OKX：清空或改掉该变量，并在系统设置启用 id=1。

### 6.2 公网 IP 直连中控 403

`HUB_TRUST_LAN=true` 时仅允许本机 + RFC1918 私网（10/172.16/192.168）。公网 IP 直连 5100 会被拒；应走 **Nginx 反代到 127.0.0.1:5100**。

### 4.4 浏览器显示 `{"detail":"forbidden"}`

**原因**：中控 `local_only` 中间件认为访问来源 IP 不允许（常见于云上 `HUB_TRUST_LAN=false` 且反代未指向 `127.0.0.1:5100`）。

**处理**（二选一）：

1. `manual_trading_hub/.env` 增加 **`HUB_ALLOW_PUBLIC=true`**（已设 `HUB_PASSWORD` 时推荐），`pm2 restart manual-trading-hub`。
2. 宝塔反代目标改为 **`http://127.0.0.1:5100`**（不要用公网 IP:5100 作 upstream）。

改后强刷浏览器再开 `/login`。

### 6.3 `.env` 修改不生效

PM2 须重启：`pm2 restart manual-trading-hub`（`run_hub.sh` 每次启动会重读 `.env`）。

### 6.4 `hub_settings.json` 与 Git

网页「系统设置」保存生成，**一般不提交 Git**。`git pull` **不会覆盖** 该文件与 `.env`。

---

## 八、功能边界（避免误用）

| 项目 | 说明 |
|------|------|
| 中控下单区 | **已移除**；勿再在中控添加关键位/人工单/趋势预览 |
| 中控能力 | 监控聚合、单户/全局紧急全平、系统设置、登录保护 |
| 下单与关键位 | 各 `crypto_monitor_*` 原网页 |
| 复盘 | 各实例 `/records`；中控仅「复盘」外链 |
| 全平 | 市价减仓，不可撤销，操作前确认 |

---

## 九、推荐排障顺序

1. `git pull` → `manual_trading_hub` 下 `bash scripts/fix_hub_deps.sh` → `bash scripts/verify_hub_deploy.sh`
2. `pm2 restart manual-trading-hub`（及 `ecosystem.config.cjs` 若 agent/Flask 也有问题）
3. `curl http://127.0.0.1:5100/api/ping` → 确认 `build` 与 `trade_ui:false`
4. 浏览器打开 `/login` 登录 → `/monitor` 强刷
5. 逐项 `curl` 子代理 `/status`、Flask `/api/hub/ping`
6. 仍不行则查 `pm2 logs manual-trading-hub`、`pm2 logs crypto_gate` 最近 50 行

---

## 十、行情区 K 线

### 10.1 只加载约 300 根（目标 1000）

**原因**：旧版 `hub_ohlcv_lib` 无 `since` 分页时，OKX/Gate 单次 API 常只返回 ~300 根。

**处理**：`git pull` 后重启 **hub + 三实例 Flask**，行情区点 **强制刷新**；浏览器强刷（`chart.js` 带版本号）。

### 10.2 6h / 8h 周期错乱（已移除）

中控行情区 **已不再提供** `6h`、`8h`（以及 `3m`/`10m`/`20m`/`30m`）。若 URL 或旧缓存仍带这些周期，会回退为 `5m`。请改用 `4h` / `12h` 等当前列表，见 [行情区说明.md](./行情区说明.md)。

### 10.3 12h 数据异常

**原因**：部分交易所无原生 12h；或本地 `hub_kline.db` 存有升级前的错误缓存。

**处理**：强制刷新；仍异常可停 hub 后备份并删除 `manual_trading_hub/data/hub_kline.db` 再拉取。

### 10.4 快捷键无效

- 全屏请用 **`F`**（Win 下 Ctrl+空格常被输入法占用，已不作为全屏键）。
- 须在 **行情区** 页面且焦点不在币种输入框。
- 升级后确认加载 `chart.js?v=...` 新版本。

---

## 十一、相关脚本

| 脚本 | 作用 |
|------|------|
| `scripts/fix_hub_deps.sh` | 安装/更新中控 venv 依赖（含 python-multipart） |
| `scripts/verify_hub_deploy.sh` | 检查代码版本、multipart、ping、PM2 状态 |
| `scripts/fix_env_crlf.sh` | 去除各目录 `.env` 的 Windows 换行 |
| `scripts/run_hub.sh` | PM2 启动 hub（加载 `.env`） |
| `scripts/run_agent.sh` | PM2 启动 agent（加载策略目录 `.env`） |
| `scripts/pm2_hub.sh` | 启停/日志 hub+agent 一体 |

---

## 十二、文档索引

| 文档 | 内容 |
|------|------|
| [使用说明.md](./使用说明.md) | 架构、页面、环境变量、API |
| [行情区说明.md](./行情区说明.md) | K 线周期、缓存、快捷键 |
| [部署文档.md](./部署文档.md) | Ubuntu/PM2 安装与运维 |
| [云服务器部署说明.md](./云服务器部署说明.md) | VPS 配置、安全组、宝塔、env、验收 |
| [局域网与反代部署说明.md](./局域网与反代部署说明.md) | 内网 IP:端口 / 域名反代、SSO |
| [README.md](./README.md) | 速览与快速启动 |
| [.env.example](./.env.example) | 中控环境变量模板 |
