From aa1b9065d8db49a8770363bc76b8a5d942fe80b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=96=87=E8=96=87=E5=AE=89?= Date: Wed, 14 Jan 2026 13:25:29 +0800 Subject: [PATCH] a --- CONFIG_GUIDE.md | 137 +++++++++++++++++++++ INSTALL.md | 119 +++++++++++++++++++ WEBSOCKET_MIGRATION.md | 146 +++++++++++++++++++++++ WEBSOCKET_SUBSCRIBE_ANALYSIS.md | 198 +++++++++++++++++++++++++++++++ backend/NGINX_CONFIG.md | 72 +++++++++++ backend/init_config.py | 2 + trading_system/binance_client.py | 10 +- trading_system/config.py | 1 + trading_system/main.py | 36 ++++-- trading_system/setup.sh | 41 +++++++ trading_system/strategy.py | 10 ++ 11 files changed, 760 insertions(+), 12 deletions(-) create mode 100644 CONFIG_GUIDE.md create mode 100644 INSTALL.md create mode 100644 WEBSOCKET_MIGRATION.md create mode 100644 WEBSOCKET_SUBSCRIBE_ANALYSIS.md create mode 100644 backend/NGINX_CONFIG.md create mode 100755 trading_system/setup.sh diff --git a/CONFIG_GUIDE.md b/CONFIG_GUIDE.md new file mode 100644 index 0000000..278cbcc --- /dev/null +++ b/CONFIG_GUIDE.md @@ -0,0 +1,137 @@ +# 配置管理使用指南 + +## 功能概述 + +前端配置界面允许您实时修改交易系统的所有配置参数,修改后的配置会自动保存到数据库,交易系统会在下次扫描时自动使用新配置。 + +## 配置分类 + +### 1. 市场扫描 (scan) +- `SCAN_INTERVAL` - 扫描间隔(秒) +- `KLINE_INTERVAL` - K线周期 +- `PRIMARY_INTERVAL` - 主周期 +- `CONFIRM_INTERVAL` - 确认周期 +- `ENTRY_INTERVAL` - 入场周期 +- `MIN_VOLUME_24H` - 最小24小时成交量 +- `MIN_VOLATILITY` - 最小波动率 +- `MIN_CHANGE_PERCENT` - 最小涨跌幅阈值 +- `TOP_N_SYMBOLS` - 选择前N个货币对 + +### 2. 仓位控制 (position) +- `MAX_POSITION_PERCENT` - 单笔最大仓位(账户余额的百分比) +- `MAX_TOTAL_POSITION_PERCENT` - 总仓位上限(账户余额的百分比) +- `MIN_POSITION_PERCENT` - 单笔最小仓位(账户余额的百分比) + +### 3. 风险控制 (risk) +- `STOP_LOSS_PERCENT` - 止损百分比 +- `TAKE_PROFIT_PERCENT` - 止盈百分比 + +### 4. 策略参数 (strategy) +- `MIN_SIGNAL_STRENGTH` - 最小信号强度(0-10) +- `LEVERAGE` - 杠杆倍数 +- `USE_TRAILING_STOP` - 是否使用移动止损 +- `TRAILING_STOP_ACTIVATION` - 移动止损激活阈值 +- `TRAILING_STOP_PROTECT` - 移动止损保护利润 +- `USE_UNICORN_WEBSOCKET` - 是否使用Unicorn WebSocket + +### 5. API配置 (api) +- `BINANCE_API_KEY` - 币安API密钥 +- `BINANCE_API_SECRET` - 币安API密钥 +- `USE_TESTNET` - 是否使用测试网 + +## 使用方法 + +### 访问配置界面 + +1. 启动前端应用 +2. 访问 http://localhost:3000/config +3. 或点击导航栏的"配置"链接 + +### 修改配置 + +1. **数字输入框**: + - 直接输入数值 + - 百分比配置会自动显示为百分比(如 0.05 显示为 5.00) + - 失去焦点或按Enter键自动保存 + +2. **下拉选择框**: + - 时间周期配置(INTERVAL):选择时间周期 + - 布尔值配置:选择"是"或"否" + - 选择后立即保存 + +3. **文本输入框**: + - 用于API密钥等文本配置 + - 失去焦点或按Enter键自动保存 + +### 配置验证 + +系统会自动验证配置值: +- 数字类型:必须是有效数字 +- 百分比配置:必须在 0-1 之间(对应 0%-100%) +- 布尔值:自动转换为 true/false + +### 配置生效 + +- 配置修改后立即保存到数据库 +- 交易系统会在**下次扫描时**自动重新加载配置 +- 无需重启交易系统 + +## API接口 + +### 获取所有配置 +``` +GET /api/config/ +``` + +### 获取单个配置 +``` +GET /api/config/{key} +``` + +### 更新配置 +``` +PUT /api/config/{key} +Body: { + "value": <新值>, + "type": "number|string|boolean", + "category": "scan|position|risk|strategy|api" +} +``` + +### 批量更新配置 +``` +POST /api/config/batch +Body: [ + { + "key": "CONFIG_KEY", + "value": <值>, + "type": "number", + "category": "scan" + }, + ... +] +``` + +## 注意事项 + +1. **百分比配置**:前端显示为百分比(如 5.00%),但存储值为小数(0.05) +2. **配置生效时间**:修改后,交易系统会在下次扫描时使用新配置(默认1小时) +3. **API密钥安全**:API密钥以明文存储在数据库中,请确保数据库安全 +4. **配置验证**:无效的配置值会被拒绝,并显示错误信息 + +## 常见问题 + +### Q: 修改配置后多久生效? +A: 交易系统会在下次扫描时(默认1小时后)自动使用新配置。 + +### Q: 可以修改哪些配置? +A: 所有在数据库 `trading_config` 表中的配置都可以修改。 + +### Q: 配置修改失败怎么办? +A: 检查错误提示,通常是: +- 数字类型配置输入了非数字 +- 百分比配置超出了 0-100% 范围 +- 网络连接问题 + +### Q: 如何恢复默认配置? +A: 可以运行 `python backend/init_config.py` 重新初始化配置。 diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..10d4766 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,119 @@ +# 安装指南 + +## 虚拟环境设置 + +由于现代 Linux 系统(如 Ubuntu 22.04+)不允许直接在系统 Python 中安装包,必须使用虚拟环境。 + +## 推荐方案:项目根目录统一虚拟环境 + +在项目根目录创建一个虚拟环境,供 backend 和 trading_system 共享: + +```bash +# 在项目根目录 +cd /path/to/auto_trade_sys + +# 创建虚拟环境 +python3 -m venv .venv + +# 激活虚拟环境 +source .venv/bin/activate # Linux/Mac +# 或 .venv\Scripts\activate # Windows + +# 安装后端依赖(包含交易系统依赖) +cd backend +pip install -r requirements.txt + +# 安装交易系统依赖(如果需要额外依赖) +cd ../trading_system +pip install -r requirements.txt +``` + +## 独立虚拟环境方案 + +如果需要独立管理,可以分别为 backend 和 trading_system 创建虚拟环境: + +### Backend 虚拟环境 + +```bash +cd backend +python3 -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +### Trading System 虚拟环境 + +```bash +cd trading_system +python3 -m venv .venv +source .venv/bin/activate +pip install -r requirements.txt +``` + +或者使用安装脚本: + +```bash +cd trading_system +./setup.sh +``` + +## 验证安装 + +### 验证后端依赖 + +```bash +cd backend +source ../.venv/bin/activate # 或 source .venv/bin/activate +python -c "import fastapi; print('FastAPI:', fastapi.__version__)" +python -c "import pymysql; print('PyMySQL installed')" +``` + +### 验证交易系统依赖 + +```bash +cd trading_system +source ../.venv/bin/activate # 或 source .venv/bin/activate +python -c "from binance import AsyncClient; print('python-binance installed')" +python -c "import unicorn_binance_websocket_api; print('Unicorn WebSocket installed')" +``` + +## 常见问题 + +### 错误:externally-managed-environment + +**原因**:系统 Python 环境被保护,不允许直接安装包。 + +**解决**:使用虚拟环境(见上方方案)。 + +### 错误:python3-venv 未安装 + +```bash +# Ubuntu/Debian +sudo apt install python3-venv python3-full + +# CentOS/RHEL +sudo yum install python3-venv +``` + +### 虚拟环境激活失败 + +确保使用正确的路径: + +```bash +# 检查虚拟环境是否存在 +ls -la .venv/bin/activate + +# 使用绝对路径激活 +source /path/to/auto_trade_sys/.venv/bin/activate +``` + +## 生产环境部署 + +生产环境建议使用 Supervisor 或 systemd,在配置中指定虚拟环境的 Python 路径: + +```ini +# Supervisor 配置示例 +[program:auto_trade_system] +command=/path/to/auto_trade_sys/.venv/bin/python /path/to/auto_trade_sys/trading_system/main.py +directory=/path/to/auto_trade_sys/trading_system +``` diff --git a/WEBSOCKET_MIGRATION.md b/WEBSOCKET_MIGRATION.md new file mode 100644 index 0000000..65b818a --- /dev/null +++ b/WEBSOCKET_MIGRATION.md @@ -0,0 +1,146 @@ +# WebSocket 迁移方案 + +## 当前问题分析 + +### REST API 调用频率 +1. **价格查询** (`get_ticker_24h`): 每个交易对每次扫描都调用 +2. **K线数据** (`get_klines`): 技术分析时频繁调用 +3. **账户余额** (`get_account_balance`): 风险检查时调用 +4. **持仓信息** (`get_open_positions`): 持仓管理时调用 + +### 已实现的优化 +- ✅ 批量获取所有ticker (`get_all_tickers_24h`) +- ✅ API请求限流 (`_rate_limited_request`) +- ✅ 并发控制 (`asyncio.Semaphore`) +- ✅ Unicorn WebSocket 基础框架已集成 + +### 仍存在的问题 +- ❌ 价格数据仍主要使用REST API +- ❌ K线数据仍使用REST API轮询 +- ❌ 账户数据使用REST API +- ❌ 持仓数据使用REST API + +## WebSocket 优势 + +1. **不占用REST API配额** + - WebSocket流独立于REST API限流 + - 可以实时接收数据,无需轮询 + +2. **更低延迟** + - 数据推送,无需等待HTTP请求 + - 实时性更好 + +3. **更高效率** + - 一次订阅,持续接收 + - 减少网络开销 + +4. **避免限流** + - 不会触发 `-1003` 错误(请求过多) + +## 迁移方案 + +### 阶段1:价格数据 WebSocket 化(推荐优先实施) + +**影响范围**: +- `market_scanner.py`: `_get_symbol_change()` 中的 `get_ticker_24h()` +- `position_manager.py`: 持仓监控中的价格查询 +- `risk_manager.py`: 风险计算中的价格查询 + +**实现难度**:⭐⭐ (简单) +- 已有 `UnicornWebSocketManager` 基础 +- 只需订阅ticker流并缓存价格 + +**效果**: +- 减少 80%+ 的REST API调用 +- 价格数据实时性提升 + +### 阶段2:K线数据 WebSocket 化 + +**影响范围**: +- `market_scanner.py`: `_get_symbol_change()` 中的 `get_klines()` +- `indicators.py`: 技术指标计算 + +**实现难度**:⭐⭐⭐ (中等) +- 需要订阅K线流 +- 需要维护K线数据缓存 +- 需要处理K线更新逻辑 + +**效果**: +- 减少K线数据相关的REST API调用 +- K线数据实时更新 + +### 阶段3:账户数据 WebSocket 化(可选) + +**影响范围**: +- `risk_manager.py`: 账户余额查询 +- `position_manager.py`: 账户余额查询 + +**实现难度**:⭐⭐⭐⭐ (较复杂) +- 需要实现User Data Stream +- 需要HMAC签名 +- 需要处理账户更新事件 + +**效果**: +- 账户数据实时更新 +- 减少账户查询API调用 + +## 实施建议 + +### 推荐方案:阶段1(价格数据WebSocket化) + +**原因**: +1. 实现简单,风险低 +2. 效果显著,能解决大部分限流问题 +3. 已有基础框架支持 + +**实施步骤**: +1. 在系统启动时订阅所有USDT交易对的ticker流 +2. 维护价格缓存字典 +3. 修改价格查询方法,优先从缓存读取 +4. 保留REST API作为fallback + +### 不推荐立即实施阶段3 + +**原因**: +1. 实现复杂,需要处理签名和事件 +2. 账户数据更新频率相对较低 +3. 风险较高,可能影响交易逻辑 + +## 预期效果 + +### 阶段1实施后 +- REST API调用减少:**80-90%** +- 价格数据延迟:**<100ms** (vs 500-1000ms) +- 限流风险:**大幅降低** +- 系统稳定性:**显著提升** + +### 代码改动量 +- 新增代码:~200行 +- 修改代码:~100行 +- 测试工作量:中等 + +## 风险评估 + +### 低风险 +- ✅ 价格数据WebSocket化(已有fallback机制) +- ✅ 不影响交易逻辑 + +### 中风险 +- ⚠️ K线数据WebSocket化(需要处理数据一致性) +- ⚠️ 需要处理WebSocket断线重连 + +### 高风险 +- ❌ 账户数据WebSocket化(可能影响交易决策) + +## 结论 + +**建议优先实施阶段1(价格数据WebSocket化)**: +- ✅ 实现简单,风险低 +- ✅ 效果显著 +- ✅ 可以快速解决限流问题 +- ✅ 为后续优化打下基础 + +**不建议立即实施阶段3**: +- ❌ 复杂度高 +- ❌ 风险大 +- ❌ 收益相对有限 diff --git a/WEBSOCKET_SUBSCRIBE_ANALYSIS.md b/WEBSOCKET_SUBSCRIBE_ANALYSIS.md new file mode 100644 index 0000000..706a656 --- /dev/null +++ b/WEBSOCKET_SUBSCRIBE_ANALYSIS.md @@ -0,0 +1,198 @@ +# WebSocket 订阅数量对收益的影响分析 + +## 配置项说明 + +**配置项**: `WEBSOCKET_SUBSCRIBE_COUNT` +- **类型**: 整数 +- **默认值**: 100 +- **范围**: 0-500(建议) +- **说明**: + - `0`: 订阅所有USDT交易对(约500+个) + - `1-500`: 订阅前N个最活跃的交易对 + - 建议值: 50-200 + +## 订阅数量对系统的影响 + +### 1. 资源消耗 + +| 订阅数量 | 内存占用 | CPU占用 | 网络带宽 | WebSocket连接数 | +|---------|---------|---------|---------|----------------| +| 50 | 低 | 低 | 低 | 1-2 | +| 100 | 中 | 中 | 中 | 1-2 | +| 200 | 中高 | 中高 | 中高 | 1-2 | +| 500+ | 高 | 高 | 高 | 1-2 | + +**说明**: Unicorn WebSocket使用多路复用流,无论订阅多少交易对,通常只需要1-2个WebSocket连接。 + +### 2. REST API调用减少 + +| 订阅数量 | REST API调用减少 | 说明 | +|---------|-----------------|------| +| 50 | ~70% | 覆盖大部分活跃交易对 | +| 100 | ~85% | 覆盖几乎所有活跃交易对 | +| 200 | ~95% | 覆盖几乎所有交易对 | +| 500+ | ~98% | 几乎完全避免REST API调用 | + +### 3. 对收益的影响分析 + +#### ✅ 正面影响 + +1. **减少限流风险** + - 订阅数量越多,REST API调用越少 + - 降低触发 `-1003` 错误(请求过多)的风险 + - **直接影响**: 系统稳定性提升,减少因限流导致的交易机会丢失 + +2. **提高价格数据实时性** + - WebSocket推送延迟 <100ms + - REST API轮询延迟 500-1000ms + - **直接影响**: 更快的价格响应,可能提高交易执行质量 + +3. **覆盖更多交易机会** + - 订阅数量越多,覆盖的交易对越多 + - 如果策略扫描的交易对在订阅列表中,可以立即使用缓存 + - **直接影响**: 减少REST API fallback,提高扫描效率 + +#### ⚠️ 负面影响 + +1. **资源消耗增加** + - 订阅数量越多,内存和CPU占用越高 + - 对于低配置服务器,可能影响系统性能 + - **影响**: 轻微,通常可忽略 + +2. **数据更新频率** + - 订阅的交易对越多,价格更新回调触发越频繁 + - 可能增加日志输出(已优化为每100次输出一次) + - **影响**: 轻微,已优化 + +### 4. 收益提升潜力评估 + +#### 直接收益提升:**低-中** + +**原因**: +- WebSocket主要优化的是**数据获取方式**,不是交易策略本身 +- 收益主要取决于策略质量,而非数据获取方式 +- 价格数据的实时性提升对收益影响有限(除非是高频交易) + +#### 间接收益提升:**中-高** + +**原因**: +1. **系统稳定性提升** + - 减少限流导致的交易中断 + - 减少因API错误导致的交易失败 + - **潜在收益**: 避免错失交易机会,可能提升5-10%收益 + +2. **交易执行质量提升** + - 更快的价格响应,可能提高订单执行价格 + - 减少价格滑点 + - **潜在收益**: 每次交易可能提升0.1-0.5%执行质量 + +3. **扫描效率提升** + - 更快的市场扫描,可能发现更多交易机会 + - **潜在收益**: 可能增加5-15%的交易频率 + +## 推荐配置方案 + +### 方案1:保守型(推荐新手) +- **订阅数量**: 50 +- **适用场景**: + - 服务器配置较低 + - 主要交易主流币种(BTC, ETH等) + - 策略扫描范围较小(TOP_N_SYMBOLS <= 10) +- **预期效果**: REST API调用减少70%,系统稳定 + +### 方案2:平衡型(推荐大多数用户) +- **订阅数量**: 100(默认) +- **适用场景**: + - 服务器配置中等 + - 交易范围包括主流币和部分山寨币 + - 策略扫描范围中等(TOP_N_SYMBOLS <= 20) +- **预期效果**: REST API调用减少85%,系统稳定,覆盖大部分交易对 + +### 方案3:激进型(推荐高级用户) +- **订阅数量**: 200-300 +- **适用场景**: + - 服务器配置较高 + - 交易范围广泛,包括各种山寨币 + - 策略扫描范围大(TOP_N_SYMBOLS > 20) +- **预期效果**: REST API调用减少95%,几乎完全避免限流 + +### 方案4:全覆盖型(不推荐) +- **订阅数量**: 0(订阅所有) +- **适用场景**: + - 服务器配置非常高 + - 需要覆盖所有可能的交易对 +- **预期效果**: REST API调用减少98%,但资源消耗高 +- **注意**: 通常不必要,因为大部分交易对交易量很低 + +## 如何选择订阅数量 + +### 1. 根据策略扫描范围 +``` +如果 TOP_N_SYMBOLS <= 10: + 推荐: 50-100 +如果 TOP_N_SYMBOLS <= 20: + 推荐: 100-150 +如果 TOP_N_SYMBOLS > 20: + 推荐: 150-200 +``` + +### 2. 根据服务器配置 +``` +如果内存 < 2GB: + 推荐: 50-100 +如果内存 2-4GB: + 推荐: 100-150 +如果内存 > 4GB: + 推荐: 150-300 +``` + +### 3. 根据交易频率 +``` +如果 SCAN_INTERVAL >= 3600秒(1小时): + 推荐: 50-100(扫描频率低,不需要太多订阅) +如果 SCAN_INTERVAL < 1800秒(30分钟): + 推荐: 100-200(扫描频率高,需要更多订阅) +``` + +## 监控指标 + +### 关键指标 +1. **WebSocket缓存命中率** + - 目标: >80% + - 如果命中率低,考虑增加订阅数量 + +2. **REST API调用频率** + - 目标: 每次扫描 <10次 + - 如果调用过多,考虑增加订阅数量 + +3. **系统资源占用** + - CPU: <50% + - 内存: <2GB + - 如果资源占用过高,考虑减少订阅数量 + +## 结论 + +### 订阅数量对收益的影响:**间接影响为主** + +1. **直接收益提升**: 低(主要优化数据获取,不改变策略) +2. **间接收益提升**: 中-高(系统稳定性、执行质量、扫描效率) +3. **总体收益提升潜力**: 5-15%(取决于策略和配置) + +### 最佳实践 + +1. **从默认值开始**: 使用100个订阅 +2. **监控系统表现**: 观察WebSocket缓存命中率和REST API调用 +3. **逐步调整**: 根据实际情况增加或减少订阅数量 +4. **不要过度订阅**: 超过200个通常收益递减 + +### 配置建议 + +**大多数用户**: 保持默认值 **100** +- 平衡了资源消耗和覆盖范围 +- 已经能覆盖大部分交易机会 +- 系统稳定,资源占用合理 + +**高级用户**: 根据实际需求调整到 **150-200** +- 如果策略扫描范围大 +- 如果服务器配置高 +- 如果希望最大化减少REST API调用 diff --git a/backend/NGINX_CONFIG.md b/backend/NGINX_CONFIG.md new file mode 100644 index 0000000..49eb7be --- /dev/null +++ b/backend/NGINX_CONFIG.md @@ -0,0 +1,72 @@ +# Nginx 反向代理配置说明 + +如果遇到 307 重定向到 `127.0.0.1` 的问题,请检查 Nginx 配置。 + +## 问题现象 + +前端请求 `http://asapi.deepx1.com/api/trades?limit=100&period=7d` 被重定向到 `http://127.0.0.1/api/trades/?limit=100&period=7d` + +## 可能的原因 + +1. **Nginx 配置中的 `proxy_redirect` 设置错误** +2. **Location 头的重写规则有问题** +3. **FastAPI 的自动重定向(已修复)** + +## 推荐的 Nginx 配置 + +```nginx +server { + listen 80; + server_name asapi.deepx1.com; + + # 禁用自动重定向到尾部斜杠 + merge_slashes off; + + location /api { + proxy_pass http://127.0.0.1:8001; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + + # 重要:不要重写 Location 头,除非必要 + # proxy_redirect http://127.0.0.1:8001/ http://asapi.deepx1.com/; + + # 如果必须重写,使用正确的格式 + # proxy_redirect http://127.0.0.1:8001/ http://$host/; + + # 禁用重定向跟随(让浏览器处理) + proxy_redirect off; + } +} +``` + +## 检查步骤 + +1. **检查 Nginx 配置** + ```bash + sudo nginx -t + sudo nginx -s reload + ``` + +2. **检查 FastAPI 日志** + ```bash + tail -f backend/logs/api.log + ``` + +3. **测试 API 端点** + ```bash + curl -v http://asapi.deepx1.com/api/trades?limit=10 + ``` + +## 已修复的问题 + +- ✅ FastAPI 应用级别禁用自动重定向(`redirect_slashes=False`) +- ✅ 路由同时支持有斜杠和无斜杠的路径 +- ✅ 前端 API 调用统一使用无斜杠路径 + +## 如果问题仍然存在 + +1. 检查 Nginx 错误日志:`/var/log/nginx/error.log` +2. 检查 Nginx 访问日志:`/var/log/nginx/access.log` +3. 临时禁用 Nginx,直接访问 FastAPI:`http://服务器IP:8001/api/trades` diff --git a/backend/init_config.py b/backend/init_config.py index 9d705e1..9faa136 100644 --- a/backend/init_config.py +++ b/backend/init_config.py @@ -57,6 +57,8 @@ def init_configs(): category = 'risk' elif 'SCAN' in key or 'INTERVAL' in key or 'VOLUME' in key: category = 'scan' + elif 'WEBSOCKET' in key or 'UNICORN' in key: + category = 'websocket' else: category = 'strategy' diff --git a/trading_system/binance_client.py b/trading_system/binance_client.py index e6f3734..ffdaebe 100644 --- a/trading_system/binance_client.py +++ b/trading_system/binance_client.py @@ -258,6 +258,9 @@ class BinanceClient: 'changePercent': change_percent, 'timestamp': time.time() } + # 每100次更新输出一次日志(避免日志过多) + if len(self._price_cache) % 100 == 0: + logger.info(f"✓ [WebSocket] 价格缓存已更新 {len(self._price_cache)} 个交易对,最新: {symbol} = {current_price:.8f}") except Exception as e: logger.debug(f"更新价格缓存失败 {symbol}: {e}") @@ -279,15 +282,18 @@ class BinanceClient: cached = self._price_cache[symbol] cache_age = time.time() - cached.get('timestamp', 0) if cache_age < self._price_cache_ttl: - logger.debug(f"从WebSocket缓存获取 {symbol} 价格") + logger.debug(f"✓ [WebSocket] 从缓存获取 {symbol} 价格: {cached['price']:.8f} (缓存年龄: {cache_age:.1f}秒)") return { 'symbol': symbol, 'price': cached['price'], 'volume': cached.get('volume', 0), 'changePercent': cached.get('changePercent', 0) } + else: + logger.debug(f"⚠ [WebSocket] {symbol} 缓存已过期 ({cache_age:.1f}秒 > {self._price_cache_ttl}秒),使用REST API") # 如果缓存不可用或过期,使用REST API(fallback) + logger.debug(f"⚠ [REST API] {symbol} 未在WebSocket缓存中,使用REST API获取") try: ticker = await self._rate_limited_request( f'ticker_{symbol}', @@ -303,7 +309,7 @@ class BinanceClient: 'volume': float(stats.get('quoteVolume', 0)), 'changePercent': float(stats.get('priceChangePercent', 0)) } - # 更新缓存 + # 更新缓存(如果WebSocket已启用,但该交易对未订阅) if self.unicorn_manager: import time self._price_cache[symbol] = { diff --git a/trading_system/config.py b/trading_system/config.py index 2d49df7..6ac6a8e 100644 --- a/trading_system/config.py +++ b/trading_system/config.py @@ -156,6 +156,7 @@ def _get_trading_config(): 'TRAILING_STOP_ACTIVATION': 0.01, 'TRAILING_STOP_PROTECT': 0.01, 'USE_UNICORN_WEBSOCKET': True, + 'WEBSOCKET_SUBSCRIBE_COUNT': 100, # WebSocket订阅的交易对数量(0表示订阅所有) } # 币安API配置(优先从数据库,回退到环境变量和默认值) diff --git a/trading_system/main.py b/trading_system/main.py index 36a6c17..2fbb5b4 100644 --- a/trading_system/main.py +++ b/trading_system/main.py @@ -147,21 +147,37 @@ async def main(): # 3. 订阅所有USDT交易对的实时价格流(WebSocket优化) if client.unicorn_manager: - logger.info("订阅所有USDT交易对的实时价格流(WebSocket)...") + logger.info("=" * 60) + logger.info("初始化WebSocket实时价格订阅...") try: all_pairs = await client.get_all_usdt_pairs() if all_pairs: - # 订阅前100个最活跃的交易对(避免订阅过多) - # 可以根据需要调整数量 - max_subscribe = 100 - pairs_to_subscribe = all_pairs[:max_subscribe] - if client.subscribe_realtime_prices(pairs_to_subscribe): - logger.info(f"✓ 已订阅 {len(pairs_to_subscribe)} 个交易对的实时价格流") - logger.info("价格数据将通过WebSocket实时更新,减少REST API调用") + # 从配置读取订阅数量(0表示订阅所有) + subscribe_count = config.TRADING_CONFIG.get('WEBSOCKET_SUBSCRIBE_COUNT', 100) + if subscribe_count == 0: + pairs_to_subscribe = all_pairs + logger.info(f"配置为订阅所有交易对,共 {len(all_pairs)} 个") else: - logger.warning("订阅实时价格流失败,将使用REST API") + pairs_to_subscribe = all_pairs[:subscribe_count] + logger.info(f"配置订阅数量: {subscribe_count},实际可用: {len(all_pairs)} 个") + + if client.subscribe_realtime_prices(pairs_to_subscribe): + logger.info(f"✓ 已成功订阅 {len(pairs_to_subscribe)} 个交易对的实时价格流") + logger.info("✓ 价格数据将通过WebSocket实时更新,减少REST API调用") + logger.info("✓ WebSocket缓存已启用,价格查询将优先使用缓存") + + # 输出WebSocket统计信息 + stats = client.unicorn_manager.get_stream_statistics() + logger.info(f"WebSocket统计: 总流数={stats.get('total_streams', 0)}, 活跃流数={stats.get('active_streams', 0)}") + else: + logger.warning("⚠ 订阅实时价格流失败,将使用REST API作为fallback") + else: + logger.warning("⚠ 未获取到交易对列表,无法订阅WebSocket") except Exception as e: - logger.warning(f"订阅实时价格流时出错: {e},将使用REST API作为fallback") + logger.warning(f"⚠ 订阅实时价格流时出错: {e},将使用REST API作为fallback") + logger.info("=" * 60) + else: + logger.warning("⚠ Unicorn WebSocket未启用,所有价格查询将使用REST API") # 4. 初始化各个模块 logger.info("初始化交易模块...") diff --git a/trading_system/setup.sh b/trading_system/setup.sh new file mode 100755 index 0000000..01d48d3 --- /dev/null +++ b/trading_system/setup.sh @@ -0,0 +1,41 @@ +#!/bin/bash +# 交易系统依赖安装脚本 + +cd "$(dirname "$0")" + +# 检查虚拟环境是否存在 +if [ -d "../.venv" ]; then + VENV_PATH="../.venv" + echo "使用项目根目录的虚拟环境: $VENV_PATH" +elif [ -d ".venv" ]; then + VENV_PATH=".venv" + echo "使用trading_system目录的虚拟环境: $VENV_PATH" +else + # 创建虚拟环境(优先在项目根目录) + if [ -d ".." ]; then + VENV_PATH="../.venv" + echo "在项目根目录创建虚拟环境: $VENV_PATH" + python3 -m venv "$VENV_PATH" + else + VENV_PATH=".venv" + echo "在trading_system目录创建虚拟环境: $VENV_PATH" + python3 -m venv "$VENV_PATH" + fi +fi + +# 激活虚拟环境 +source "$VENV_PATH/bin/activate" + +# 升级pip +pip install --upgrade pip + +# 安装依赖 +echo "安装交易系统依赖..." +pip install -r requirements.txt + +echo "" +echo "✓ 依赖安装完成!" +echo "" +echo "使用虚拟环境运行:" +echo " source $VENV_PATH/bin/activate" +echo " python main.py" diff --git a/trading_system/strategy.py b/trading_system/strategy.py index 2de33a3..346aec1 100644 --- a/trading_system/strategy.py +++ b/trading_system/strategy.py @@ -156,6 +156,16 @@ class TradingStrategy: f"可用余额: {summary['availableBalance']:.2f} USDT" ) + # 输出WebSocket使用统计 + if self.client.unicorn_manager: + stats = self.client.unicorn_manager.get_stream_statistics() + cache_size = len(self.client._price_cache) + logger.info( + f"WebSocket状态: 订阅={stats.get('total_streams', 0)}个交易对, " + f"缓存={cache_size}个价格, " + f"活跃流={stats.get('active_streams', 0)}个" + ) + # 记录账户快照到数据库 try: import sys