a
This commit is contained in:
parent
043276bb81
commit
aa1b9065d8
137
CONFIG_GUIDE.md
Normal file
137
CONFIG_GUIDE.md
Normal file
|
|
@ -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` 重新初始化配置。
|
||||||
119
INSTALL.md
Normal file
119
INSTALL.md
Normal file
|
|
@ -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
|
||||||
|
```
|
||||||
146
WEBSOCKET_MIGRATION.md
Normal file
146
WEBSOCKET_MIGRATION.md
Normal file
|
|
@ -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**:
|
||||||
|
- ❌ 复杂度高
|
||||||
|
- ❌ 风险大
|
||||||
|
- ❌ 收益相对有限
|
||||||
198
WEBSOCKET_SUBSCRIBE_ANALYSIS.md
Normal file
198
WEBSOCKET_SUBSCRIBE_ANALYSIS.md
Normal file
|
|
@ -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调用
|
||||||
72
backend/NGINX_CONFIG.md
Normal file
72
backend/NGINX_CONFIG.md
Normal file
|
|
@ -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`
|
||||||
|
|
@ -57,6 +57,8 @@ def init_configs():
|
||||||
category = 'risk'
|
category = 'risk'
|
||||||
elif 'SCAN' in key or 'INTERVAL' in key or 'VOLUME' in key:
|
elif 'SCAN' in key or 'INTERVAL' in key or 'VOLUME' in key:
|
||||||
category = 'scan'
|
category = 'scan'
|
||||||
|
elif 'WEBSOCKET' in key or 'UNICORN' in key:
|
||||||
|
category = 'websocket'
|
||||||
else:
|
else:
|
||||||
category = 'strategy'
|
category = 'strategy'
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -258,6 +258,9 @@ class BinanceClient:
|
||||||
'changePercent': change_percent,
|
'changePercent': change_percent,
|
||||||
'timestamp': time.time()
|
'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:
|
except Exception as e:
|
||||||
logger.debug(f"更新价格缓存失败 {symbol}: {e}")
|
logger.debug(f"更新价格缓存失败 {symbol}: {e}")
|
||||||
|
|
||||||
|
|
@ -279,15 +282,18 @@ class BinanceClient:
|
||||||
cached = self._price_cache[symbol]
|
cached = self._price_cache[symbol]
|
||||||
cache_age = time.time() - cached.get('timestamp', 0)
|
cache_age = time.time() - cached.get('timestamp', 0)
|
||||||
if cache_age < self._price_cache_ttl:
|
if cache_age < self._price_cache_ttl:
|
||||||
logger.debug(f"从WebSocket缓存获取 {symbol} 价格")
|
logger.debug(f"✓ [WebSocket] 从缓存获取 {symbol} 价格: {cached['price']:.8f} (缓存年龄: {cache_age:.1f}秒)")
|
||||||
return {
|
return {
|
||||||
'symbol': symbol,
|
'symbol': symbol,
|
||||||
'price': cached['price'],
|
'price': cached['price'],
|
||||||
'volume': cached.get('volume', 0),
|
'volume': cached.get('volume', 0),
|
||||||
'changePercent': cached.get('changePercent', 0)
|
'changePercent': cached.get('changePercent', 0)
|
||||||
}
|
}
|
||||||
|
else:
|
||||||
|
logger.debug(f"⚠ [WebSocket] {symbol} 缓存已过期 ({cache_age:.1f}秒 > {self._price_cache_ttl}秒),使用REST API")
|
||||||
|
|
||||||
# 如果缓存不可用或过期,使用REST API(fallback)
|
# 如果缓存不可用或过期,使用REST API(fallback)
|
||||||
|
logger.debug(f"⚠ [REST API] {symbol} 未在WebSocket缓存中,使用REST API获取")
|
||||||
try:
|
try:
|
||||||
ticker = await self._rate_limited_request(
|
ticker = await self._rate_limited_request(
|
||||||
f'ticker_{symbol}',
|
f'ticker_{symbol}',
|
||||||
|
|
@ -303,7 +309,7 @@ class BinanceClient:
|
||||||
'volume': float(stats.get('quoteVolume', 0)),
|
'volume': float(stats.get('quoteVolume', 0)),
|
||||||
'changePercent': float(stats.get('priceChangePercent', 0))
|
'changePercent': float(stats.get('priceChangePercent', 0))
|
||||||
}
|
}
|
||||||
# 更新缓存
|
# 更新缓存(如果WebSocket已启用,但该交易对未订阅)
|
||||||
if self.unicorn_manager:
|
if self.unicorn_manager:
|
||||||
import time
|
import time
|
||||||
self._price_cache[symbol] = {
|
self._price_cache[symbol] = {
|
||||||
|
|
|
||||||
|
|
@ -156,6 +156,7 @@ def _get_trading_config():
|
||||||
'TRAILING_STOP_ACTIVATION': 0.01,
|
'TRAILING_STOP_ACTIVATION': 0.01,
|
||||||
'TRAILING_STOP_PROTECT': 0.01,
|
'TRAILING_STOP_PROTECT': 0.01,
|
||||||
'USE_UNICORN_WEBSOCKET': True,
|
'USE_UNICORN_WEBSOCKET': True,
|
||||||
|
'WEBSOCKET_SUBSCRIBE_COUNT': 100, # WebSocket订阅的交易对数量(0表示订阅所有)
|
||||||
}
|
}
|
||||||
|
|
||||||
# 币安API配置(优先从数据库,回退到环境变量和默认值)
|
# 币安API配置(优先从数据库,回退到环境变量和默认值)
|
||||||
|
|
|
||||||
|
|
@ -147,21 +147,37 @@ async def main():
|
||||||
|
|
||||||
# 3. 订阅所有USDT交易对的实时价格流(WebSocket优化)
|
# 3. 订阅所有USDT交易对的实时价格流(WebSocket优化)
|
||||||
if client.unicorn_manager:
|
if client.unicorn_manager:
|
||||||
logger.info("订阅所有USDT交易对的实时价格流(WebSocket)...")
|
logger.info("=" * 60)
|
||||||
|
logger.info("初始化WebSocket实时价格订阅...")
|
||||||
try:
|
try:
|
||||||
all_pairs = await client.get_all_usdt_pairs()
|
all_pairs = await client.get_all_usdt_pairs()
|
||||||
if all_pairs:
|
if all_pairs:
|
||||||
# 订阅前100个最活跃的交易对(避免订阅过多)
|
# 从配置读取订阅数量(0表示订阅所有)
|
||||||
# 可以根据需要调整数量
|
subscribe_count = config.TRADING_CONFIG.get('WEBSOCKET_SUBSCRIBE_COUNT', 100)
|
||||||
max_subscribe = 100
|
if subscribe_count == 0:
|
||||||
pairs_to_subscribe = all_pairs[:max_subscribe]
|
pairs_to_subscribe = all_pairs
|
||||||
if client.subscribe_realtime_prices(pairs_to_subscribe):
|
logger.info(f"配置为订阅所有交易对,共 {len(all_pairs)} 个")
|
||||||
logger.info(f"✓ 已订阅 {len(pairs_to_subscribe)} 个交易对的实时价格流")
|
|
||||||
logger.info("价格数据将通过WebSocket实时更新,减少REST API调用")
|
|
||||||
else:
|
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:
|
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. 初始化各个模块
|
# 4. 初始化各个模块
|
||||||
logger.info("初始化交易模块...")
|
logger.info("初始化交易模块...")
|
||||||
|
|
|
||||||
41
trading_system/setup.sh
Executable file
41
trading_system/setup.sh
Executable file
|
|
@ -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"
|
||||||
|
|
@ -156,6 +156,16 @@ class TradingStrategy:
|
||||||
f"可用余额: {summary['availableBalance']:.2f} USDT"
|
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:
|
try:
|
||||||
import sys
|
import sys
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user