b733e551a0
Add scripts/normalize_ambiguous_unicode.py; fix corrupted patch_instance_theme_templates.py. Preserves curly quotes in string literals; removes Git homoglyph warnings on .env.example. Co-authored-by: Cursor <cursoragent@cursor.com>
390 lines
11 KiB
Markdown
390 lines
11 KiB
Markdown
# `crypto_monitor_binance` 部署指南:SSH SOCKS + Binance + PM2(Ubuntu)
|
|
|
|
项目功能,环境变量总览见 **[README.md](./README.md)**.Ubuntu 环境(Python / Node / PM2)见 **[docs/ubuntu-server.md](../docs/ubuntu-server.md)**.
|
|
|
|
本文面向:**在本机或 VPS 上运行本项目**,但 **直连 Binance API 不稳定,超时或被网络策略拦截** 的场景.思路是:
|
|
|
|
- 本机用 `ssh -D` 做动态转发,把 **SOCKS5 出口**放到能稳定访问 Binance 的机器(常见为一台境外 VPS)
|
|
- 项目在 `.env` 中设置 **`BINANCE_SOCKS_PROXY=socks5h://127.0.0.1:1080`**(或你实际端口),`ccxt` 经 SOCKS 访问交易所
|
|
- **SSH 隧道**:用 `ssh -D` 在本机常驻(可用 **tmux** 或 **autossh** 保持连接),**不要** 把 `ssh` 交给 PM2
|
|
- 使用 **PM2** 仅托管 **Flask 应用**;仓库根目录 **`ecosystem.config.cjs`** 默认进程名为 **`crypto-monitor-binance`**
|
|
|
|
> 安全提醒:不要把 `.env`,私钥 `.pem`,Binance API Key / Secret 提交到 Git;下文只用占位符.
|
|
|
|
---
|
|
|
|
## 0. 你需要准备的东西
|
|
|
|
- 一台 **Ubuntu**(或同类 Linux)运行项目的机器(下文称「本机」)
|
|
- 一台可 SSH 登录,且 **能正常访问 Binance API** 的 VPS(示例:`HostName` 填你的服务器 IP,用户如 `root`)
|
|
- SSH:**私钥登录**(推荐,便于隧道脚本无人值守)
|
|
- 本机已安装:`python3`,`python3-venv`,`pip`,`curl`,`ssh`,`git`(可选),`node` + `npm`(安装 PM2)
|
|
- Binance 账户:已开通 **USDT-M 永续合约**;API Key 勾选 **合约**,**万向划转**(若使用资金↔合约划转)等所需权限,并配置 **IP 白名单**(若启用)
|
|
|
|
---
|
|
|
|
## 1. 获取代码与目录
|
|
|
|
将包含 `app.py` 的项目放到固定目录,例如:
|
|
|
|
```bash
|
|
mkdir -p /opt/crypto_monitor
|
|
cd /opt/crypto_monitor
|
|
git clone https://git.bz121.com/dekun/crypto_monitor.git
|
|
cd crypto_monitor/crypto_monitor_binance
|
|
```
|
|
|
|
下文用 **`/opt/crypto_monitor/crypto_monitor_binance`** 仅为示例,请换成你的实际绝对路径.
|
|
|
|
拉取代码后,若目录下尚无 `.env`,先从模板生成(**勿**把填好密钥的 `.env` 提交 Git):
|
|
|
|
```bash
|
|
cp -n .env.example .env # -n:已存在 .env 时不覆盖
|
|
```
|
|
|
|
---
|
|
|
|
## 2. 配置 SSH 私钥与 `~/.ssh/config`
|
|
|
|
```bash
|
|
mkdir -p ~/.ssh
|
|
chmod 700 ~/.ssh
|
|
# 私钥示例:~/.ssh/vps1.pem
|
|
chmod 600 ~/.ssh/vps1.pem
|
|
```
|
|
|
|
编辑 `~/.ssh/config`(示例别名 **`bn-vps`**,与你手工启动 `ssh -D ... bn-vps` 一致即可):
|
|
|
|
```sshconfig
|
|
Host bn-vps
|
|
HostName 你的_VPS_IP
|
|
User root
|
|
IdentityFile ~/.ssh/vps1.pem
|
|
IdentitiesOnly yes
|
|
ServerAliveInterval 30
|
|
ServerAliveCountMax 3
|
|
ExitOnForwardFailure yes
|
|
BatchMode yes
|
|
```
|
|
|
|
测试:
|
|
|
|
```bash
|
|
ssh bn-vps true
|
|
```
|
|
|
|
> 若尚未完全改为密钥登录,可暂时注释 `BatchMode yes`,调试完成后再打开.
|
|
|
|
---
|
|
|
|
## 3. 手工验证:SSH SOCKS + Binance API
|
|
|
|
### 3.1 本地 SOCKS(示例端口 1080)
|
|
|
|
```bash
|
|
ssh -N -D 127.0.0.1:1080 bn-vps
|
|
```
|
|
|
|
保持运行,另开终端继续.
|
|
|
|
### 3.2 验证经 SOCKS 可访问 Binance(公开接口)
|
|
|
|
```bash
|
|
curl -4 -sS --max-time 15 --proxy socks5h://127.0.0.1:1080 https://api.binance.com/api/v3/time
|
|
```
|
|
|
|
应返回 JSON(含 `serverTime` 字段).若此处失败,**不要先启动应用**:先修隧道或 VPS 出站.
|
|
|
|
---
|
|
|
|
## 4. Python 虚拟环境
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
|
|
python3 -m venv .venv
|
|
source .venv/bin/activate
|
|
python -m pip install -U pip
|
|
pip install flask requests ccxt werkzeug PySocks Pillow
|
|
```
|
|
|
|
走 SOCKS 时 **必须** 安装 **`PySocks`**,否则易出现代理相关报错.
|
|
|
|
可选:
|
|
|
|
```bash
|
|
export PYTHONDONTWRITEBYTECODE=1
|
|
```
|
|
|
|
---
|
|
|
|
## 5. 配置环境变量(`.env.example` → `.env`)
|
|
|
|
| 文件 | 是否进 Git | 说明 |
|
|
|------|------------|------|
|
|
| **`.env.example`** | ✅ 是 | 变量模板与注释,可随 `git pull` 更新 |
|
|
| **`.env`** | ❌ 否 | 本机真实配置;`app.py` **只读此文件** |
|
|
|
|
### 5.1 首次配置
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
|
|
cp -n .env.example .env # 已存在 .env 时不覆盖
|
|
nano .env # 填入 API,登录密码,端口,代理等
|
|
```
|
|
|
|
### 5.2 备份与 `git pull`
|
|
|
|
- **`.env` 已被仓库根目录 `.gitignore` 忽略**:`git pull` **不会**覆盖或删除你本地的 `.env`.
|
|
- 若远端更新了 **`.env.example`**(新增变量名),pull 后请对照模板,**手动把新行补进你的 `.env`**(不会自动合并进 `.env`).
|
|
- **建议在每次 `git pull` 或大批量改配置前备份**:
|
|
|
|
```bash
|
|
cp .env .env.backup.$(date +%Y%m%d)
|
|
# 恢复示例:cp .env.backup.20260516 .env
|
|
```
|
|
|
|
- **换机 / 迁移**:用 `scp` 复制整份 `.env` 到新机器对应目录;或在新机重新 `cp .env.example .env` 后填写.
|
|
|
|
### 5.3 AI 复盘与模型(可选)
|
|
|
|
三所共用仓库根目录 **`ai_client.py`**(PM2 的 **`PYTHONPATH=..`** 须包含仓库根).在 `.env` 中配置 **`AI_PROVIDER`**:
|
|
|
|
| 模式 | 主要变量 |
|
|
|------|----------|
|
|
| **`openai`**(默认) | `OPENAI_API_BASE=https://op.bz121.com/v1`,`OPENAI_API_KEY`,`OPENAI_MODEL=gemma4:e4b` |
|
|
| **`ollama`** | `OLLAMA_API`,`AI_MODEL`(本机 Ollama) |
|
|
|
|
密钥在 [op.bz121.com](https://op.bz121.com/) 的 **`gateway.json`** 页面获取.改 `.env` 后需 **`pm2 restart`** 对应进程.详见根目录 **[AI复盘与模型配置说明.md](../AI复盘与模型配置说明.md)**.
|
|
|
|
### 5.4 自动备份(数据库 + 复盘图片)
|
|
|
|
默认每天 **北京时间 0:00** 备份到 **`/root/backups`**,保留 **30 天** 后自动删除更早的目录.
|
|
|
|
备份内容(路径来自 `.env` 的 `DB_PATH`,`UPLOAD_DIR`):
|
|
|
|
- `crypto.db`(优先 `sqlite3 .backup` 热备)
|
|
- `static/images` 打包为 `static_images.tar.gz`
|
|
|
|
目录结构示例:
|
|
|
|
```text
|
|
/root/backups/crypto_monitor_binance/2026-05-17/
|
|
crypto.db
|
|
static_images.tar.gz
|
|
manifest.txt
|
|
```
|
|
|
|
**一次性安装定时任务**(在对应项目目录执行,Binance / Gate 各执行一次):
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
chmod +x scripts/backup_data.sh scripts/install_backup_cron.sh
|
|
bash scripts/install_backup_cron.sh
|
|
```
|
|
|
|
Gate 实例:
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_gate
|
|
bash scripts/install_backup_cron.sh
|
|
```
|
|
|
|
实例(趋势回调等):
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_gate
|
|
bash scripts/install_backup_cron.sh
|
|
```
|
|
|
|
**立即试跑**(不写 cron):
|
|
|
|
```bash
|
|
bash scripts/backup_data.sh
|
|
```
|
|
|
|
日志默认:`/var/log/crypto-monitor-backup-<项目目录名>.log`.可选在 `.env` 中覆盖:`BACKUP_ROOT`,`BACKUP_RETENTION_DAYS`,`BACKUP_INSTANCE`.
|
|
|
|
**恢复示例**(先停 PM2,再覆盖文件):
|
|
|
|
```bash
|
|
pm2 stop crypto-monitor-binance
|
|
cp /root/backups/crypto_monitor_binance/2026-05-16/crypto.db ./crypto.db
|
|
tar -xzf /root/backups/crypto_monitor_binance/2026-05-16/static_images.tar.gz -C .
|
|
pm2 start ecosystem.config.cjs
|
|
```
|
|
|
|
建议安装:`apt install -y sqlite3`(热备更稳).
|
|
|
|
### 5.5 必填项检查(Binance + 代理)
|
|
|
|
与交易所相关的变量使用 **`BINANCE_`** 前缀(与代码一致).至少确认:
|
|
|
|
```env
|
|
APP_HOST=127.0.0.1
|
|
APP_PORT=5000
|
|
|
|
# 实盘(按需)
|
|
LIVE_TRADING_ENABLED=false
|
|
BINANCE_API_KEY=你的_Key
|
|
BINANCE_API_SECRET=你的_Secret
|
|
|
|
# 保证金:cross=全仓 isolated=逐仓(与币安账户/习惯一致)
|
|
BINANCE_MARGIN_MODE=cross
|
|
|
|
# 持仓模式:hedge=双向(需在币安开启双向持仓);oneway=单向
|
|
BINANCE_POSITION_MODE=hedge
|
|
|
|
# 条件单触发参考:CONTRACT_PRICE=最新成交价 MARK_PRICE=标记价
|
|
BINANCE_TRIGGER_WORKING_TYPE=CONTRACT_PRICE
|
|
|
|
# 经本机 SSH 动态转发访问 Binance(端口与隧道一致)
|
|
BINANCE_SOCKS_PROXY=socks5h://127.0.0.1:1080
|
|
|
|
# 若不用 SOCKS,可改用 HTTP 代理(一般二选一)
|
|
# BINANCE_HTTP_PROXY=http://127.0.0.1:7890
|
|
# BINANCE_HTTPS_PROXY=http://127.0.0.1:7890
|
|
```
|
|
|
|
说明:**推荐 `socks5h://`**,由 SOCKS 端解析域名,与 `curl --proxy socks5h://...` 行为一致.
|
|
|
|
**止盈止损说明(应用逻辑)**:实盘开仓后,程序会在 Binance USDT-M 永续上挂 **`STOP_MARKET`(止损)** 与 **`TAKE_PROFIT_MARKET`(止盈)**;`BINANCE_POSITION_MODE=hedge` 时会自动带 **`positionSide`**,须与币安合约「双向持仓」开关一致.不显式传 **`reduceOnly`**(否则易触发 API **`-1106`**:`Parameter 'reduceOnly' sent when not required`).
|
|
|
|
---
|
|
|
|
## 6. 自检脚本(可选)
|
|
|
|
在已配置 `.env` 且网络可达的前提下:
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
source .venv/bin/activate
|
|
python scripts/verify_binance_funding.py
|
|
```
|
|
|
|
用于粗测资金钱包与合约钱包 USDT 读取(需有效 API 与权限).
|
|
|
|
---
|
|
|
|
## 7. 手工启动 Flask(验证)
|
|
|
|
1. SOCKS 已监听 `127.0.0.1:1080`(若使用代理)
|
|
2. 已 `source .venv/bin/activate`
|
|
3. `.env` 已按需配置 `BINANCE_SOCKS_PROXY` 等
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
source .venv/bin/activate
|
|
python app.py
|
|
```
|
|
|
|
浏览器访问:`http://127.0.0.1:5000`(或你在 `.env` 中的端口).
|
|
|
|
---
|
|
|
|
## 8. 安装 PM2
|
|
|
|
```bash
|
|
sudo npm i -g pm2
|
|
pm2 -v
|
|
```
|
|
|
|
---
|
|
|
|
## 9. PM2:使用仓库内 `ecosystem.config.cjs`(推荐)
|
|
|
|
在项目根目录:
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
pm2 start ecosystem.config.cjs
|
|
pm2 status
|
|
pm2 logs --lines 200
|
|
```
|
|
|
|
默认只启动 **`crypto-monitor-binance`**(`.venv/bin/python app.py`).
|
|
|
|
### 本机已可直连 Binance,不需要隧道时
|
|
|
|
`.env` 里应 **去掉或留空** `BINANCE_SOCKS_PROXY`(除非仍要走别的代理),再 `pm2 start ecosystem.config.cjs`.
|
|
|
|
### 开机自启
|
|
|
|
```bash
|
|
pm2 save
|
|
pm2 startup
|
|
# 按屏幕提示执行一条 sudo 命令
|
|
```
|
|
|
|
---
|
|
|
|
## 10. 等价手工命令(不使用 ecosystem 文件时)
|
|
|
|
### 10.1 SSH SOCKS(自行后台常驻,不推荐用 PM2)
|
|
|
|
示例(前台调试;生产请用 **PM2**,见本文 §6 与 [docs/ubuntu-server.md](../docs/ubuntu-server.md)):
|
|
|
|
```bash
|
|
ssh -N -D 127.0.0.1:1080 bn-vps \
|
|
-o ServerAliveInterval=30 -o ServerAliveCountMax=3 \
|
|
-o ExitOnForwardFailure=yes
|
|
```
|
|
|
|
### 10.2 Flask
|
|
|
|
```bash
|
|
cd /opt/crypto_monitor/crypto_monitor_binance
|
|
pm2 start /opt/crypto_monitor/crypto_monitor_binance/.venv/bin/python --name crypto-monitor-binance -- \
|
|
/opt/crypto_monitor/crypto_monitor_binance/app.py
|
|
```
|
|
|
|
---
|
|
|
|
## 11. 交易所「连接不上」排查清单
|
|
|
|
1. **`.env` 是否为 Binance 变量**:`BINANCE_SOCKS_PROXY` / `BINANCE_HTTP_PROXY` / `BINANCE_API_KEY` / `BINANCE_API_SECRET` 等前缀需与代码一致.
|
|
2. **隧道是否在本机端口监听**(若配置了 `BINANCE_SOCKS_PROXY`):
|
|
```bash
|
|
ss -lntp | grep 1080 || true
|
|
```
|
|
3. **curl 复测 Binance**(与第 3.2 节相同);curl 不通则应用也不会通.
|
|
4. **PySocks**:`pip show PySocks`,缺失则 `pip install PySocks`.
|
|
5. **SSH 隧道连不上**:检查私钥权限,`~/.ssh/config`,VPS 出站与端口是否与 `.env` 一致.
|
|
6. **API 权限与 IP 白名单**:Secret 错误,权限不足,未放行当前出口 IP 时,私有接口会失败.
|
|
7. **启动顺序**:若走代理,先保证 SOCKS 已监听,再 `pm2 start` 应用(或重启应用).
|
|
|
|
---
|
|
|
|
## 12. 推荐启动顺序(习惯)
|
|
|
|
1. 若走代理:先启动并确认 SSH SOCKS 已监听,再 `curl --proxy socks5h://127.0.0.1:1080 https://api.binance.com/api/v3/time` 成功
|
|
2. `pm2 start ecosystem.config.cjs`
|
|
3. 再确认页面与余额等接口正常
|
|
|
|
---
|
|
|
|
## 13. 免责声明
|
|
|
|
交易所有合规与地区政策要求.请确保使用方式符合当地法律法规与交易所条款.本文仅描述网络与工程部署路径.
|
|
|
|
---
|
|
|
|
## 附录:数据库标签修复脚本 `scripts/fix_breakeven_labels.py`
|
|
|
|
在 Ubuntu 上:
|
|
|
|
1)预览(不写库):
|
|
|
|
```bash
|
|
python scripts/fix_breakeven_labels.py --db ./crypto.db --dry-run
|
|
```
|
|
|
|
2)确认后执行:
|
|
|
|
```bash
|
|
python scripts/fix_breakeven_labels.py --db ./crypto.db --apply
|
|
```
|
|
|
|
默认修复条件:`monitor_type='下单监控'` 且 `result='止损'` 且 `pnl_amount > 0` → 改为 `result='保本止盈'`.
|