a
This commit is contained in:
parent
a3aed32224
commit
11e3532ac3
31
ATR.md
Normal file
31
ATR.md
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
将固定百分比止损,改为基于 ATR(平均真实波幅) 的动态止损。 这是专业交易系统的标准做法。
|
||||
|
||||
逻辑:ATR指标精确衡量了当前价格的平均波动幅度。将止损设置为 1.5倍至2倍的ATR值,意味着止损距离能随着市场波动自动调整。市场平静时收紧,市场疯狂时放宽,始终保持在“正常波动”之外。
|
||||
|
||||
示例:如果当前ATR值为价格的3%,那么:
|
||||
|
||||
1.5倍ATR止损 = 价格反向4.5% 止损
|
||||
|
||||
2倍ATR止损 = 价格反向6% 止损
|
||||
|
||||
开仓时实时计算:
|
||||
|
||||
python
|
||||
# 1. 获取当前ATR值 (假设为价格的3%)
|
||||
current_atr_percent = get_current_atr(symbol) # 返回 0.03 (3%)
|
||||
|
||||
# 2. 根据ATR倍数计算动态止损距离
|
||||
stop_distance = current_atr_percent * ATR_MULTIPLIER_SL # 0.03 * 1.5 = 0.045 (4.5%)
|
||||
|
||||
# 3. 根据盈亏比计算动态止盈距离
|
||||
take_profit_distance = stop_distance * RISK_REWARD_RATIO # 0.045 * 3 = 0.135 (13.5%)
|
||||
|
||||
# 4. 计算出具体的止损价和止盈价
|
||||
if side == 'BUY':
|
||||
stop_loss_price = entry_price * (1 - stop_distance) # 做多,止损价在下
|
||||
take_profit_price = entry_price * (1 + take_profit_distance)
|
||||
else:
|
||||
stop_loss_price = entry_price * (1 + stop_distance) # 做空,止损价在上
|
||||
take_profit_price = entry_price * (1 - take_profit_distance)
|
||||
|
||||
先实施,再优化:不必追求完美。你可以先从 ATR_MULTIPLIER_SL = 1.5 和 RISK_REWARD_RATIO = 3.0 这个组合开始。这个组合意味着你允许价格反向波动“1.5倍的平均波幅”才止损,同时追求3倍于此空间的利润。
|
||||
263
ATR_STRATEGY_IMPLEMENTATION.md
Normal file
263
ATR_STRATEGY_IMPLEMENTATION.md
Normal file
|
|
@ -0,0 +1,263 @@
|
|||
# ATR策略实现文档
|
||||
|
||||
## 一、概述
|
||||
|
||||
基于ATR(平均真实波幅)的动态止损止盈策略,根据市场波动自动调整止损止盈距离,避免被正常波动触发止损,同时保持合理的盈亏比。
|
||||
|
||||
## 二、核心原理
|
||||
|
||||
### 2.1 ATR指标
|
||||
|
||||
ATR(Average True Range)是衡量市场波动性的技术指标,计算公式:
|
||||
|
||||
```
|
||||
True Range (TR) = max(
|
||||
High - Low,
|
||||
|High - Previous Close|,
|
||||
|Low - Previous Close|
|
||||
)
|
||||
|
||||
ATR = Average(TR over N periods)
|
||||
```
|
||||
|
||||
ATR值越大,市场波动越大;ATR值越小,市场波动越小。
|
||||
|
||||
### 2.2 ATR策略逻辑
|
||||
|
||||
**止损计算**:
|
||||
- 止损距离 = ATR × ATR止损倍数(默认1.8倍)
|
||||
- 止损价格 = 入场价 ± 止损距离(做多减,做空加)
|
||||
|
||||
**止盈计算**:
|
||||
- 方法1(优先):止盈距离 = 止损距离 × 盈亏比(默认3.0)
|
||||
- 方法2(备选):止盈距离 = ATR × ATR止盈倍数(默认3.0倍)
|
||||
|
||||
**优势**:
|
||||
- 市场平静时,ATR小,止损紧,保护利润
|
||||
- 市场波动大时,ATR大,止损宽,避免被正常波动触发
|
||||
- 始终保持在"正常波动"之外
|
||||
|
||||
## 三、实现架构
|
||||
|
||||
### 3.1 核心模块
|
||||
|
||||
#### `trading_system/atr_strategy.py`
|
||||
ATR策略核心类,提供以下功能:
|
||||
- `calculate_stop_loss()`: 计算基于ATR的止损价格
|
||||
- `calculate_take_profit()`: 计算基于ATR的止盈价格
|
||||
- `calculate_atr_levels()`: 计算完整的ATR止损止盈方案
|
||||
- `calculate_atr_from_klines()`: 从K线数据计算ATR
|
||||
|
||||
#### `trading_system/indicators.py`
|
||||
技术指标计算模块,增强功能:
|
||||
- `calculate_atr()`: 计算ATR绝对值
|
||||
- `calculate_atr_percent()`: 计算ATR百分比(新增)
|
||||
|
||||
#### `trading_system/risk_manager.py`
|
||||
风险管理模块,集成ATR策略:
|
||||
- 在`get_stop_loss_price()`中优先使用ATR止损
|
||||
- 在`get_take_profit_price()`中优先使用ATR止盈
|
||||
- 支持止损距离传递,用于盈亏比计算
|
||||
|
||||
### 3.2 数据流
|
||||
|
||||
```
|
||||
K线数据 → 计算ATR → ATR策略类 → 计算止损止盈 → RiskManager → 最终价格
|
||||
```
|
||||
|
||||
## 四、配置参数
|
||||
|
||||
### 4.1 基础配置
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `USE_ATR_STOP_LOSS` | `True` | 是否启用ATR动态止损 |
|
||||
| `ATR_STOP_LOSS_MULTIPLIER` | `1.8` | ATR止损倍数(1.5-2倍) |
|
||||
| `ATR_TAKE_PROFIT_MULTIPLIER` | `3.0` | ATR止盈倍数(3倍ATR) |
|
||||
| `RISK_REWARD_RATIO` | `3.0` | 盈亏比(止损距离的倍数) |
|
||||
| `ATR_PERIOD` | `14` | ATR计算周期 |
|
||||
|
||||
### 4.2 高级配置(可选)
|
||||
|
||||
| 参数 | 默认值 | 说明 |
|
||||
|------|--------|------|
|
||||
| `USE_DYNAMIC_ATR_MULTIPLIER` | `False` | 是否根据波动率动态调整ATR倍数 |
|
||||
| `ATR_MULTIPLIER_MIN` | `1.5` | 动态ATR倍数最小值 |
|
||||
| `ATR_MULTIPLIER_MAX` | `2.5` | 动态ATR倍数最大值 |
|
||||
|
||||
### 4.3 配置建议
|
||||
|
||||
**保守策略**:
|
||||
- `ATR_STOP_LOSS_MULTIPLIER`: 1.5
|
||||
- `RISK_REWARD_RATIO`: 2.5
|
||||
|
||||
**平衡策略**(推荐):
|
||||
- `ATR_STOP_LOSS_MULTIPLIER`: 1.8
|
||||
- `RISK_REWARD_RATIO`: 3.0
|
||||
|
||||
**激进策略**:
|
||||
- `ATR_STOP_LOSS_MULTIPLIER`: 2.0
|
||||
- `RISK_REWARD_RATIO`: 3.5
|
||||
|
||||
## 五、使用示例
|
||||
|
||||
### 5.1 基本使用
|
||||
|
||||
```python
|
||||
from trading_system.atr_strategy import ATRStrategy
|
||||
|
||||
# 初始化ATR策略
|
||||
atr_strategy = ATRStrategy()
|
||||
|
||||
# 计算止损
|
||||
stop_loss_price, stop_distance, details = atr_strategy.calculate_stop_loss(
|
||||
entry_price=50000.0,
|
||||
side='BUY',
|
||||
atr=1500.0, # ATR绝对值
|
||||
atr_percent=0.03 # 或ATR百分比(3%)
|
||||
)
|
||||
|
||||
# 计算止盈(基于止损距离和盈亏比)
|
||||
take_profit_price, take_profit_distance, tp_details = atr_strategy.calculate_take_profit(
|
||||
entry_price=50000.0,
|
||||
side='BUY',
|
||||
stop_distance=stop_distance, # 使用止损距离
|
||||
use_risk_reward_ratio=True
|
||||
)
|
||||
```
|
||||
|
||||
### 5.2 从K线计算ATR
|
||||
|
||||
```python
|
||||
from trading_system.atr_strategy import ATRStrategy
|
||||
|
||||
# 从K线数据计算ATR
|
||||
atr, atr_percent, current_price = ATRStrategy.calculate_atr_from_klines(
|
||||
klines=klines_data,
|
||||
period=14
|
||||
)
|
||||
|
||||
# 使用ATR计算止损止盈
|
||||
result = atr_strategy.calculate_atr_levels(
|
||||
entry_price=current_price,
|
||||
side='BUY',
|
||||
atr=atr,
|
||||
atr_percent=atr_percent
|
||||
)
|
||||
```
|
||||
|
||||
### 5.3 在RiskManager中使用
|
||||
|
||||
```python
|
||||
# RiskManager会自动使用ATR策略(如果启用)
|
||||
stop_loss_price = risk_manager.get_stop_loss_price(
|
||||
entry_price=50000.0,
|
||||
side='BUY',
|
||||
quantity=0.1,
|
||||
leverage=10,
|
||||
atr=1500.0 # 传递ATR值
|
||||
)
|
||||
|
||||
# 计算止盈时,传递止损距离用于盈亏比计算
|
||||
take_profit_price = risk_manager.get_take_profit_price(
|
||||
entry_price=50000.0,
|
||||
side='BUY',
|
||||
quantity=0.1,
|
||||
leverage=10,
|
||||
atr=1500.0,
|
||||
stop_distance=2700.0 # 止损距离(用于盈亏比计算)
|
||||
)
|
||||
```
|
||||
|
||||
## 六、计算示例
|
||||
|
||||
### 6.1 示例场景
|
||||
|
||||
假设:
|
||||
- 入场价:50000 USDT
|
||||
- ATR:1500 USDT(3%)
|
||||
- ATR止损倍数:1.8
|
||||
- 盈亏比:3.0
|
||||
|
||||
**止损计算**:
|
||||
```
|
||||
止损距离 = 1500 × 1.8 = 2700 USDT
|
||||
止损百分比 = 3% × 1.8 = 5.4%
|
||||
止损价(做多)= 50000 - 2700 = 47300 USDT
|
||||
```
|
||||
|
||||
**止盈计算**(基于盈亏比):
|
||||
```
|
||||
止盈距离 = 2700 × 3.0 = 8100 USDT
|
||||
止盈百分比 = 5.4% × 3.0 = 16.2%
|
||||
止盈价(做多)= 50000 + 8100 = 58100 USDT
|
||||
```
|
||||
|
||||
### 6.2 不同市场波动情况
|
||||
|
||||
**低波动市场**(ATR = 1%):
|
||||
- 止损距离:1.8%
|
||||
- 止盈距离:5.4%
|
||||
- 止损更紧,保护利润
|
||||
|
||||
**高波动市场**(ATR = 5%):
|
||||
- 止损距离:9%
|
||||
- 止盈距离:27%
|
||||
- 止损更宽,避免被正常波动触发
|
||||
|
||||
## 七、策略优势
|
||||
|
||||
### 7.1 自适应市场波动
|
||||
- 市场平静时,止损自动收紧
|
||||
- 市场波动大时,止损自动放宽
|
||||
- 始终保持在正常波动范围之外
|
||||
|
||||
### 7.2 保持合理盈亏比
|
||||
- 基于止损距离计算止盈,确保盈亏比一致
|
||||
- 默认3:1盈亏比,长期盈利概率高
|
||||
|
||||
### 7.3 减少假信号
|
||||
- 避免被正常市场波动触发止损
|
||||
- 提高交易胜率和盈利能力
|
||||
|
||||
## 八、回退机制
|
||||
|
||||
如果ATR不可用或计算失败,系统会自动回退到:
|
||||
1. 基于保证金的固定百分比止损
|
||||
2. 基于价格百分比的最小保护
|
||||
3. 技术分析止损(如果可用)
|
||||
|
||||
系统会从所有候选价格中选择最宽松的(做多取最大,做空取最小),确保止损不会过紧。
|
||||
|
||||
## 九、动态调整(可选)
|
||||
|
||||
如果启用`USE_DYNAMIC_ATR_MULTIPLIER`,系统会根据市场波动率动态调整ATR倍数:
|
||||
|
||||
- 波动率低(1-2%):使用最小倍数(1.5)
|
||||
- 波动率中(3-5%):使用中等倍数(1.8-2.0)
|
||||
- 波动率高(6-10%):使用最大倍数(2.5)
|
||||
|
||||
这样可以进一步优化止损距离,在低波动时更紧,高波动时更宽。
|
||||
|
||||
## 十、注意事项
|
||||
|
||||
1. **ATR计算需要足够的历史数据**:至少需要`ATR_PERIOD + 1`根K线
|
||||
2. **ATR值会随市场变化**:建议定期更新ATR值
|
||||
3. **不同周期ATR不同**:建议使用与交易周期一致的K线数据计算ATR
|
||||
4. **极端市场情况**:在极端波动时,ATR可能无法及时反映,需要结合其他指标
|
||||
|
||||
## 十一、相关文件
|
||||
|
||||
- `trading_system/atr_strategy.py`: ATR策略核心实现
|
||||
- `trading_system/indicators.py`: ATR计算函数
|
||||
- `trading_system/risk_manager.py`: 风险管理集成
|
||||
- `trading_system/config.py`: 配置参数
|
||||
- `backend/config_manager.py`: 配置管理器
|
||||
- `ATR.md`: ATR策略需求文档
|
||||
|
||||
## 十二、未来优化方向
|
||||
|
||||
1. **多周期ATR**:结合不同周期的ATR值
|
||||
2. **ATR趋势**:考虑ATR的变化趋势,预测未来波动
|
||||
3. **ATR百分比分位数**:使用ATR的历史分位数判断当前波动水平
|
||||
4. **自适应盈亏比**:根据市场状态动态调整盈亏比
|
||||
77
MARGIN_DISPLAY_FIX.md
Normal file
77
MARGIN_DISPLAY_FIX.md
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
# 保证金显示修复说明
|
||||
|
||||
## 问题描述
|
||||
|
||||
发现持仓单子显示保证金为 0.00 USDT,但实际有持仓:
|
||||
- 交易对:XTZUSDT
|
||||
- 数量:0.1000
|
||||
- 入场价:0.6120
|
||||
- 杠杆:20x
|
||||
- **实际保证金**:0.1000 × 0.6120 / 20 = 0.00306 USDT
|
||||
- **显示保证金**:0.00 USDT(因为使用 `toFixed(2)` 格式化)
|
||||
|
||||
## 问题原因
|
||||
|
||||
1. **前端显示问题**:使用 `toFixed(2)` 格式化保证金,当保证金小于 0.01 USDT 时,会显示为 0.00
|
||||
2. **可能的历史数据**:这个单子可能是在更新配置(MIN_MARGIN_USDT: 0.5 → 5.0)之前开的,当时允许更小的保证金
|
||||
|
||||
## 修复内容
|
||||
|
||||
### 1. 前端显示优化
|
||||
|
||||
**修改文件**:
|
||||
- `frontend/src/components/StatsDashboard.jsx`
|
||||
- `frontend/src/components/TradeList.jsx`
|
||||
|
||||
**修改逻辑**:
|
||||
- 如果保证金 >= 0.01 USDT,使用 `toFixed(2)` 显示(保留2位小数)
|
||||
- 如果保证金 < 0.01 USDT,使用 `toFixed(4)` 显示(保留4位小数)
|
||||
|
||||
**修改位置**:
|
||||
1. 持仓列表中的保证金显示
|
||||
2. 止损止盈金额显示
|
||||
3. 交易列表中的保证金显示
|
||||
|
||||
### 2. 后端检查(已存在)
|
||||
|
||||
后端已经有最小保证金检查:
|
||||
- `trading_system/risk_manager.py` - `calculate_position_size()` 方法
|
||||
- `trading_system/binance_client.py` - `place_order()` 方法
|
||||
|
||||
**检查逻辑**:
|
||||
- 如果保证金 < MIN_MARGIN_USDT(当前为 5.0 USDT),会:
|
||||
1. 尝试增加仓位价值以满足最小保证金要求
|
||||
2. 如果账户余额不足,拒绝开仓
|
||||
|
||||
## 验证方法
|
||||
|
||||
### 1. 检查新开仓单子
|
||||
- 新开仓的单子保证金应该 >= 5.0 USDT
|
||||
- 如果看到保证金 < 5.0 USDT 的新单子,说明检查逻辑有问题
|
||||
|
||||
### 2. 检查旧数据
|
||||
- 旧数据可能保证金很小(< 5.0 USDT),这是正常的
|
||||
- 这些单子会显示为 0.00XX USDT(4位小数)
|
||||
|
||||
### 3. 检查日志
|
||||
查看开仓日志,应该看到:
|
||||
```
|
||||
✓ XTZUSDT 仓位计算成功: X.XXXX
|
||||
(仓位价值: XX.XX USDT,
|
||||
名义价值: XX.XX USDT,
|
||||
保证金: X.XXXX USDT, 杠杆: 20x)
|
||||
```
|
||||
|
||||
如果保证金 < 5.0 USDT,应该看到警告并拒绝开仓。
|
||||
|
||||
## 建议
|
||||
|
||||
1. **平仓旧的小保证金单子**:如果看到保证金 < 5.0 USDT 的持仓,建议手动平仓
|
||||
2. **检查配置**:确保 `MIN_MARGIN_USDT` 配置为 5.0 USDT
|
||||
3. **监控新开仓**:观察新开仓的单子,确保保证金 >= 5.0 USDT
|
||||
|
||||
## 总结
|
||||
|
||||
✅ **前端显示已优化**:小保证金会显示为 0.00XX USDT(4位小数)
|
||||
✅ **后端检查已存在**:新开仓会检查最小保证金要求(5.0 USDT)
|
||||
⚠️ **旧数据可能显示为小保证金**:这是正常的,建议手动平仓
|
||||
156
PRESET_CONFIGURATION_ANALYSIS.md
Normal file
156
PRESET_CONFIGURATION_ANALYSIS.md
Normal file
|
|
@ -0,0 +1,156 @@
|
|||
# 三个快速配置方案分析
|
||||
|
||||
## 📊 当前配置对比
|
||||
|
||||
### 方案一:保守配置
|
||||
- **扫描间隔**:3600秒(1小时)
|
||||
- **最小涨跌幅**:2.0%
|
||||
- **信号强度**:5/10
|
||||
- **处理交易对**:10个
|
||||
- **止损**:10% of margin(最小2%价格变动)
|
||||
- **止盈**:20% of margin(最小3%价格变动)
|
||||
- **盈亏比**:2:1 ✅
|
||||
- **特点**:稳健,避免被正常波动触发
|
||||
|
||||
### 方案二:平衡配置(推荐)
|
||||
- **扫描间隔**:600秒(10分钟)
|
||||
- **最小涨跌幅**:1.5%
|
||||
- **信号强度**:4/10
|
||||
- **处理交易对**:12个
|
||||
- **止损**:8% of margin(最小2%价格变动)
|
||||
- **止盈**:15% of margin(最小3%价格变动)
|
||||
- **盈亏比**:1.875:1 ⚠️(略低于2:1)
|
||||
- **特点**:平衡频率和质量
|
||||
|
||||
### 方案三:激进高频配置
|
||||
- **扫描间隔**:300秒(5分钟)
|
||||
- **最小涨跌幅**:1.0%
|
||||
- **信号强度**:3/10
|
||||
- **处理交易对**:18个
|
||||
- **止损**:5% of margin(最小1.5%价格变动)
|
||||
- **止盈**:10% of margin(最小2%价格变动)
|
||||
- **盈亏比**:2:1 ✅
|
||||
- **特点**:高频交易,快速止盈止损
|
||||
|
||||
## ⚠️ 问题分析
|
||||
|
||||
### 激进方案的问题
|
||||
|
||||
1. **止盈10%确实偏小**:
|
||||
- 虽然盈亏比是2:1(合理),但止盈10%可能过早止盈
|
||||
- 在趋势行情中,可能错过更大的利润空间
|
||||
- 考虑到系统已优化为3:1盈亏比(止损10%,止盈30%),激进方案也应该提高止盈
|
||||
|
||||
2. **盈亏比分析**:
|
||||
- 当前:止损5%,止盈10%,盈亏比2:1
|
||||
- 如果胜率40%,需要盈亏比至少2.5:1才能盈利
|
||||
- 如果胜率30%,需要盈亏比至少3.3:1才能盈利
|
||||
|
||||
3. **高频交易的特殊性**:
|
||||
- 高频交易胜率可能更低(因为信号质量要求降低)
|
||||
- 需要更高的盈亏比来补偿
|
||||
- 但也要考虑手续费成本
|
||||
|
||||
## 💡 优化建议
|
||||
|
||||
### 建议调整激进方案
|
||||
|
||||
**方案A:提高止盈(推荐)**
|
||||
- 止损:5% of margin
|
||||
- 止盈:15% of margin(从10%提高到15%)
|
||||
- 盈亏比:3:1 ✅
|
||||
- 优点:盈亏比更合理,能捕捉更大趋势
|
||||
|
||||
**方案B:提高止盈更多**
|
||||
- 止损:5% of margin
|
||||
- 止盈:20% of margin
|
||||
- 盈亏比:4:1 ✅
|
||||
- 优点:盈亏比很高,但可能持仓时间更长
|
||||
|
||||
**方案C:保持止盈,提高止损**
|
||||
- 止损:6% of margin(从5%提高到6%)
|
||||
- 止盈:15% of margin(从10%提高到15%)
|
||||
- 盈亏比:2.5:1 ✅
|
||||
- 优点:止损更宽松,减少被正常波动触发
|
||||
|
||||
### 推荐方案
|
||||
|
||||
**激进高频配置(优化版)**:
|
||||
- 止损:5% of margin
|
||||
- 止盈:15% of margin
|
||||
- 盈亏比:3:1
|
||||
- 理由:
|
||||
1. 盈亏比3:1,即使胜率只有40%也能盈利
|
||||
2. 止盈15%不会过早止盈,能捕捉更大趋势
|
||||
3. 止损5%仍然较紧,适合高频交易
|
||||
|
||||
## 📈 盈亏比重要性
|
||||
|
||||
### 盈亏比与胜率的关系
|
||||
|
||||
假设单笔止损金额为1 USDT:
|
||||
|
||||
| 盈亏比 | 胜率要求(盈亏平衡) | 胜率40%时的期望收益 |
|
||||
|--------|---------------------|---------------------|
|
||||
| 1:1 | 50% | -0.2 USDT(亏损) |
|
||||
| 2:1 | 33.3% | +0.2 USDT(盈利) |
|
||||
| 2.5:1 | 28.6% | +0.3 USDT(盈利) |
|
||||
| **3:1** | **25%** | **+0.4 USDT(盈利)** |
|
||||
| 4:1 | 20% | +0.6 USDT(盈利) |
|
||||
|
||||
**结论**:盈亏比3:1是最佳平衡点,既能盈利,又不会过度追求高盈亏比导致持仓时间过长。
|
||||
|
||||
## 🔧 具体修改建议
|
||||
|
||||
### 修改激进方案配置
|
||||
|
||||
```javascript
|
||||
aggressive: {
|
||||
name: '激进高频',
|
||||
desc: '晚间波动大时使用,交易频率高,止损止盈较紧',
|
||||
configs: {
|
||||
SCAN_INTERVAL: 300,
|
||||
MIN_CHANGE_PERCENT: 1.0,
|
||||
MIN_SIGNAL_STRENGTH: 3,
|
||||
TOP_N_SYMBOLS: 18,
|
||||
MAX_SCAN_SYMBOLS: 350,
|
||||
MIN_VOLATILITY: 0.015,
|
||||
STOP_LOSS_PERCENT: 5.0, // 保持5%
|
||||
TAKE_PROFIT_PERCENT: 15.0, // 从10%提高到15%(盈亏比3:1)
|
||||
MIN_STOP_LOSS_PRICE_PCT: 1.5,
|
||||
MIN_TAKE_PROFIT_PRICE_PCT: 2.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 同时优化平衡方案
|
||||
|
||||
```javascript
|
||||
balanced: {
|
||||
name: '平衡配置',
|
||||
desc: '推荐使用,平衡频率和质量,止损止盈适中',
|
||||
configs: {
|
||||
SCAN_INTERVAL: 600,
|
||||
MIN_CHANGE_PERCENT: 1.5,
|
||||
MIN_SIGNAL_STRENGTH: 4,
|
||||
TOP_N_SYMBOLS: 12,
|
||||
MAX_SCAN_SYMBOLS: 250,
|
||||
MIN_VOLATILITY: 0.018,
|
||||
STOP_LOSS_PERCENT: 8.0,
|
||||
TAKE_PROFIT_PERCENT: 20.0, // 从15%提高到20%(盈亏比2.5:1)
|
||||
MIN_STOP_LOSS_PRICE_PCT: 2.0,
|
||||
MIN_TAKE_PROFIT_PRICE_PCT: 3.0
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 📝 总结
|
||||
|
||||
1. **激进方案止盈10%确实偏小**,建议提高到15%(盈亏比3:1)
|
||||
2. **平衡方案止盈15%也可以提高**到20%(盈亏比2.5:1)
|
||||
3. **保守方案保持20%止盈**即可(盈亏比2:1,已经合理)
|
||||
|
||||
**建议优先级**:
|
||||
1. ✅ 立即调整激进方案:止盈10% → 15%
|
||||
2. ✅ 考虑调整平衡方案:止盈15% → 20%
|
||||
3. ✅ 保守方案保持不变
|
||||
236
REVENUE_OPTIMIZATION_COMPLETE.md
Normal file
236
REVENUE_OPTIMIZATION_COMPLETE.md
Normal file
|
|
@ -0,0 +1,236 @@
|
|||
# 交易系统收益优化 - 完成报告
|
||||
|
||||
## ✅ 所有优化已成功应用
|
||||
|
||||
### 一、仓位优化(提高收益5-15倍)
|
||||
|
||||
**修改内容**:
|
||||
- ✅ `MIN_MARGIN_USDT`: 0.5 → **5.0 USDT** (提高10倍)
|
||||
- ✅ `MAX_POSITION_PERCENT`: 0.05 → **0.08** (5% → 8%)
|
||||
- ✅ `MAX_TOTAL_POSITION_PERCENT`: 0.30 → **0.40** (30% → 40%)
|
||||
- ✅ `MIN_POSITION_PERCENT`: 0.01 → **0.02** (1% → 2%)
|
||||
|
||||
**修改文件**:
|
||||
- ✅ `trading_system/config.py`
|
||||
- ✅ `backend/config_manager.py`
|
||||
- ✅ `backend/database/init.sql`
|
||||
|
||||
### 二、止盈止损优化(盈亏比3:1)
|
||||
|
||||
**修改内容**:
|
||||
- ✅ `STOP_LOSS_PERCENT`: 0.10 (10% of margin) - 保持不变
|
||||
- ✅ `TAKE_PROFIT_PERCENT`: 0.20 → **0.30** (20% → 30% of margin)
|
||||
- ✅ **盈亏比**: 从 2:1 提升到 **3:1**
|
||||
|
||||
**修改文件**:
|
||||
- ✅ `trading_system/config.py`
|
||||
- ✅ `backend/config_manager.py`
|
||||
- ✅ `backend/database/init.sql`
|
||||
- ✅ `trading_system/position_manager.py` (更新默认值)
|
||||
|
||||
### 三、ATR动态止损(方案三)
|
||||
|
||||
**新增配置**:
|
||||
- ✅ `USE_ATR_STOP_LOSS`: True (启用ATR动态止损)
|
||||
- ✅ `ATR_STOP_LOSS_MULTIPLIER`: 1.8 (1.5-2倍ATR,默认1.8)
|
||||
- ✅ `ATR_TAKE_PROFIT_MULTIPLIER`: 3.0 (3倍ATR,对应3:1盈亏比)
|
||||
|
||||
**实现逻辑**:
|
||||
1. ✅ 优先使用ATR:如果ATR可用,使用 `ATR × 倍数` 计算止损距离
|
||||
2. ✅ 回退机制:如果ATR不可用,回退到基于保证金的固定百分比
|
||||
3. ✅ 取更宽松:在ATR、保证金、价格百分比、技术分析中,取最宽松的止损价
|
||||
|
||||
**修改文件**:
|
||||
- ✅ `trading_system/risk_manager.py` - `get_stop_loss_price` 方法
|
||||
- ✅ `trading_system/risk_manager.py` - `get_take_profit_price` 方法
|
||||
- ✅ `trading_system/position_manager.py` - 传递ATR参数
|
||||
- ✅ `trading_system/config.py` - 新增配置项
|
||||
- ✅ `backend/config_manager.py` - 新增配置项
|
||||
- ✅ `backend/database/init.sql` - 新增配置项
|
||||
|
||||
### 四、移动止损优化
|
||||
|
||||
**修改内容**:
|
||||
- ✅ `TRAILING_STOP_ACTIVATION`: 0.05 → **0.10** (5% → 10%)
|
||||
- ✅ `TRAILING_STOP_PROTECT`: 0.03 → **0.05** (3% → 5%)
|
||||
|
||||
**修改文件**:
|
||||
- ✅ `trading_system/config.py`
|
||||
- ✅ `backend/config_manager.py`
|
||||
- ✅ `backend/database/init.sql`
|
||||
|
||||
### 五、杠杆优化
|
||||
|
||||
**修改内容**:
|
||||
- ✅ `MAX_LEVERAGE`: 20 → **15** (降低杠杆上限,更保守)
|
||||
|
||||
**修改文件**:
|
||||
- ✅ `trading_system/config.py`
|
||||
- ✅ `backend/config_manager.py`
|
||||
- ✅ `backend/database/init.sql`
|
||||
|
||||
## 收益提升示例
|
||||
|
||||
### 场景:账户余额100 USDT
|
||||
|
||||
**优化前**:
|
||||
- 单笔仓位:100 × 5% = 5 USDT
|
||||
- 保证金:5 / 10 = 0.5 USDT
|
||||
- 止损:0.5 × 10% = **0.05 USDT**
|
||||
- 止盈:0.5 × 20% = **0.10 USDT**
|
||||
|
||||
**优化后**:
|
||||
- 单笔仓位:100 × 8% = 8 USDT
|
||||
- 保证金:8 / 10 = 0.8 USDT(但最小要求5U,所以实际是5U)
|
||||
- 止损:5 × 10% = **0.5 USDT** ✅ (提高10倍)
|
||||
- 止盈:5 × 30% = **1.5 USDT** ✅ (提高15倍)
|
||||
|
||||
### 场景:账户余额500 USDT
|
||||
|
||||
**优化前**:
|
||||
- 单笔仓位:500 × 5% = 25 USDT
|
||||
- 保证金:25 / 10 = 2.5 USDT
|
||||
- 止损:2.5 × 10% = **0.25 USDT**
|
||||
- 止盈:2.5 × 20% = **0.5 USDT**
|
||||
|
||||
**优化后**:
|
||||
- 单笔仓位:500 × 8% = 40 USDT
|
||||
- 保证金:40 / 10 = 4 USDT(但最小要求5U,所以实际是5U)
|
||||
- 止损:5 × 10% = **0.5 USDT** ✅ (提高2倍)
|
||||
- 止盈:5 × 30% = **1.5 USDT** ✅ (提高3倍)
|
||||
|
||||
### 场景:账户余额1000 USDT
|
||||
|
||||
**优化前**:
|
||||
- 单笔仓位:1000 × 5% = 50 USDT
|
||||
- 保证金:50 / 10 = 5 USDT
|
||||
- 止损:5 × 10% = **0.5 USDT**
|
||||
- 止盈:5 × 20% = **1.0 USDT**
|
||||
|
||||
**优化后**:
|
||||
- 单笔仓位:1000 × 8% = 80 USDT
|
||||
- 保证金:80 / 10 = 8 USDT
|
||||
- 止损:8 × 10% = **0.8 USDT** ✅ (提高60%)
|
||||
- 止盈:8 × 30% = **2.4 USDT** ✅ (提高140%)
|
||||
|
||||
## ATR动态止损示例
|
||||
|
||||
### 场景:BTCUSDT,当前价格50000,ATR = 500
|
||||
|
||||
**固定百分比止损**:
|
||||
- 止损距离 = 50000 × 2% = 1000 USDT
|
||||
- 止损价 = 50000 - 1000 = 49000 USDT
|
||||
|
||||
**ATR动态止损**(1.8倍ATR):
|
||||
- 止损距离 = 500 × 1.8 = 900 USDT
|
||||
- 止损价 = 50000 - 900 = 49100 USDT
|
||||
|
||||
**选择**:取更宽松的(49100 > 49000),使用ATR止损
|
||||
|
||||
**优势**:
|
||||
- 如果市场波动大(ATR=1000),止损距离 = 1800 USDT,避免被震出
|
||||
- 如果市场波动小(ATR=200),止损距离 = 360 USDT,保护利润
|
||||
|
||||
## 盈亏比分析
|
||||
|
||||
### 盈亏比3:1的优势
|
||||
|
||||
假设:
|
||||
- 胜率:40%
|
||||
- 盈亏比:3:1
|
||||
- 单笔止损:0.5 USDT
|
||||
- 单笔止盈:1.5 USDT
|
||||
|
||||
**100次交易**:
|
||||
- 盈利:40次 × 1.5 = 60 USDT
|
||||
- 亏损:60次 × 0.5 = 30 USDT
|
||||
- **净利润:30 USDT** ✅
|
||||
|
||||
即使胜率只有40%,长期也能盈利!
|
||||
|
||||
## 下一步操作
|
||||
|
||||
### 1. 数据库更新(如果数据库已存在)
|
||||
|
||||
运行以下SQL更新现有配置:
|
||||
|
||||
```sql
|
||||
-- 更新仓位配置
|
||||
UPDATE trading_config SET config_value = '0.08' WHERE config_key = 'MAX_POSITION_PERCENT';
|
||||
UPDATE trading_config SET config_value = '0.40' WHERE config_key = 'MAX_TOTAL_POSITION_PERCENT';
|
||||
UPDATE trading_config SET config_value = '0.02' WHERE config_key = 'MIN_POSITION_PERCENT';
|
||||
UPDATE trading_config SET config_value = '5.0' WHERE config_key = 'MIN_MARGIN_USDT';
|
||||
|
||||
-- 更新止盈止损配置
|
||||
UPDATE trading_config SET config_value = '0.30' WHERE config_key = 'TAKE_PROFIT_PERCENT';
|
||||
|
||||
-- 更新移动止损配置
|
||||
UPDATE trading_config SET config_value = '0.10' WHERE config_key = 'TRAILING_STOP_ACTIVATION';
|
||||
UPDATE trading_config SET config_value = '0.05' WHERE config_key = 'TRAILING_STOP_PROTECT';
|
||||
|
||||
-- 更新杠杆配置
|
||||
UPDATE trading_config SET config_value = '15' WHERE config_key = 'MAX_LEVERAGE';
|
||||
|
||||
-- 添加ATR配置
|
||||
INSERT INTO trading_config (config_key, config_value, config_type, category, description) VALUES
|
||||
('USE_ATR_STOP_LOSS', 'true', 'boolean', 'risk', '是否使用ATR动态止损(优先于固定百分比)'),
|
||||
('ATR_STOP_LOSS_MULTIPLIER', '1.8', 'number', 'risk', 'ATR止损倍数(1.5-2倍ATR,默认1.8)'),
|
||||
('ATR_TAKE_PROFIT_MULTIPLIER', '3.0', 'number', 'risk', 'ATR止盈倍数(3倍ATR,对应3:1盈亏比)')
|
||||
ON DUPLICATE KEY UPDATE config_value = VALUES(config_value);
|
||||
```
|
||||
|
||||
### 2. 重启交易系统
|
||||
|
||||
修改配置后,需要重启交易系统以应用新配置:
|
||||
|
||||
```bash
|
||||
cd trading_system
|
||||
python main.py
|
||||
```
|
||||
|
||||
### 3. 验证效果
|
||||
|
||||
观察以下指标:
|
||||
- ✅ 单笔保证金是否达到5U
|
||||
- ✅ 盈亏比是否接近3:1
|
||||
- ✅ ATR动态止损是否生效(查看日志)
|
||||
- ✅ 收益是否提高
|
||||
|
||||
## 预期效果
|
||||
|
||||
### 短期(1周内)
|
||||
- ✅ 单笔收益提高5-15倍(取决于账户余额)
|
||||
- ✅ 盈亏比提升到3:1
|
||||
- ✅ ATR动态止损匹配市场波动
|
||||
|
||||
### 中期(1个月内)
|
||||
- ✅ 交易统计数据积累
|
||||
- ✅ 可以分析ATR止损效果
|
||||
- ✅ 根据实际表现微调参数
|
||||
|
||||
### 长期(3个月+)
|
||||
- ✅ 策略表现稳定
|
||||
- ✅ 收益可观且可持续
|
||||
- ✅ 风险控制有效
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **账户余额要求**:确保账户余额足够(建议100+ USDT)
|
||||
2. **风险承受能力**:单笔最大亏损0.5-0.8 USDT,确保可以承受
|
||||
3. **市场波动**:ATR动态止损会根据市场波动自动调整
|
||||
4. **参数微调**:根据实际运行效果,可以进一步微调参数
|
||||
|
||||
## 总结
|
||||
|
||||
✅ **所有优化已成功应用**:
|
||||
- 仓位提高(5-15倍收益)
|
||||
- 盈亏比3:1
|
||||
- ATR动态止损
|
||||
- 移动止损优化
|
||||
- 杠杆优化
|
||||
|
||||
✅ **代码已通过语法检查**
|
||||
|
||||
✅ **所有文件已更新**
|
||||
|
||||
现在可以重启交易系统,享受更高的收益!
|
||||
141
TIMEZONE_FIX_SUMMARY.md
Normal file
141
TIMEZONE_FIX_SUMMARY.md
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
# 时区处理修复总结
|
||||
|
||||
## ✅ 已完成的修改
|
||||
|
||||
### 1. trading_system/position_manager.py
|
||||
|
||||
**修改内容**:
|
||||
- ✅ 导入 `get_beijing_time` 函数(从 `database.models` 或创建本地版本)
|
||||
- ✅ 将 `entryTime` 的存储从 `datetime.now()` 改为 `get_beijing_time()`
|
||||
- ✅ 将所有计算持续时间的地方从 `datetime.now()` 改为 `get_beijing_time()`
|
||||
|
||||
**修改位置**:
|
||||
- 第337行:`'entryTime': get_beijing_time()` - 开仓时记录入场时间
|
||||
- 第464行及多处:`exit_dt = get_beijing_time()` - 计算持仓持续时间时使用北京时间
|
||||
|
||||
### 2. backend/database/models.py
|
||||
|
||||
**已确认**:
|
||||
- ✅ `Trade.create()` 方法已使用 `get_beijing_time()` 设置 `entry_time`
|
||||
- ✅ `Trade.update_exit()` 方法已使用 `get_beijing_time()` 设置 `exit_time`
|
||||
- ✅ 所有其他模型(`AccountSnapshot`, `MarketScan`, `TradingSignal`, `TradeRecommendation`)都已使用 `get_beijing_time()`
|
||||
|
||||
### 3. SQL更新脚本
|
||||
|
||||
**文件**:`backend/database/update_timezone_to_beijing.sql`
|
||||
|
||||
**功能**:
|
||||
- 将旧数据的 `entry_time` 和 `exit_time` 从UTC时间(或服务器本地时间)转换为北京时间(UTC+8)
|
||||
- 提供了三种转换方法:
|
||||
1. 直接加8小时(如果旧数据是UTC时间)
|
||||
2. 根据服务器时区调整(如果旧数据是服务器本地时间)
|
||||
3. 使用MySQL时区转换函数(需要加载时区数据)
|
||||
|
||||
**使用方法**:
|
||||
```sql
|
||||
-- 1. 先备份数据库
|
||||
mysqldump -u root -p auto_trade_sys > backup_$(date +%Y%m%d_%H%M%S).sql
|
||||
|
||||
-- 2. 根据实际情况调整SQL脚本中的时间偏移量
|
||||
-- 3. 运行SQL脚本
|
||||
mysql -u root -p auto_trade_sys < backend/database/update_timezone_to_beijing.sql
|
||||
```
|
||||
|
||||
## 时间处理流程
|
||||
|
||||
### 开仓(Entry Time)
|
||||
1. `position_manager.py` 中 `open_position()` 方法:
|
||||
- 内存中存储:`'entryTime': get_beijing_time()`
|
||||
- 数据库入库:`Trade.create()` → 使用 `get_beijing_time()` 设置 `entry_time`
|
||||
|
||||
### 平仓(Exit Time)
|
||||
1. `position_manager.py` 中各种平仓方法:
|
||||
- 计算持续时间:`exit_dt = get_beijing_time()`
|
||||
- 数据库更新:`Trade.update_exit()` → 使用 `get_beijing_time()` 设置 `exit_time`
|
||||
|
||||
### 时间格式
|
||||
- 数据库存储:`TIMESTAMP` 类型,无时区信息(MySQL默认)
|
||||
- Python代码:使用 `datetime` 对象,通过 `get_beijing_time()` 确保是北京时间(UTC+8)
|
||||
- 显示:前端可以根据需要转换为任何时区显示
|
||||
|
||||
## 验证方法
|
||||
|
||||
### 1. 检查新数据
|
||||
```sql
|
||||
-- 查看最近几条记录的入场时间
|
||||
SELECT id, symbol, entry_time, exit_time, status
|
||||
FROM trades
|
||||
ORDER BY id DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
### 2. 检查时间是否合理
|
||||
```sql
|
||||
-- 检查是否有异常的时间(例如未来时间或很久以前的时间)
|
||||
SELECT id, symbol, entry_time, exit_time
|
||||
FROM trades
|
||||
WHERE entry_time > NOW()
|
||||
OR entry_time < '2020-01-01'
|
||||
OR (exit_time IS NOT NULL AND exit_time > NOW())
|
||||
OR (exit_time IS NOT NULL AND exit_time < entry_time);
|
||||
```
|
||||
|
||||
### 3. 检查持续时间计算
|
||||
```sql
|
||||
-- 检查持仓持续时间是否合理
|
||||
SELECT
|
||||
id,
|
||||
symbol,
|
||||
entry_time,
|
||||
exit_time,
|
||||
TIMESTAMPDIFF(MINUTE, entry_time, COALESCE(exit_time, NOW())) as duration_minutes,
|
||||
duration_minutes as stored_duration
|
||||
FROM trades
|
||||
WHERE exit_time IS NOT NULL
|
||||
ORDER BY id DESC
|
||||
LIMIT 10;
|
||||
```
|
||||
|
||||
## 注意事项
|
||||
|
||||
1. **旧数据处理**:
|
||||
- 如果旧数据已经是北京时间,不需要运行SQL更新脚本
|
||||
- 如果旧数据是UTC时间,需要加8小时
|
||||
- 如果旧数据是其他时区,需要相应调整
|
||||
|
||||
2. **时区一致性**:
|
||||
- 所有入库时间都使用北京时间(UTC+8)
|
||||
- 所有计算持续时间的地方也使用北京时间
|
||||
- 前端显示可以根据需要转换时区
|
||||
|
||||
3. **数据库时区设置**:
|
||||
- MySQL的 `TIMESTAMP` 类型会根据服务器时区自动转换
|
||||
- 建议服务器时区设置为 `Asia/Shanghai` 或 `UTC+8`
|
||||
- 可以通过 `SELECT @@global.time_zone, @@session.time_zone;` 查看
|
||||
|
||||
4. **代码时区处理**:
|
||||
- Python代码中使用 `get_beijing_time()` 确保时区一致
|
||||
- 不依赖系统时区设置,避免时区问题
|
||||
|
||||
## 测试建议
|
||||
|
||||
1. **开仓测试**:
|
||||
- 开仓后检查数据库中的 `entry_time` 是否为北京时间
|
||||
- 检查内存中的 `entryTime` 是否为北京时间
|
||||
|
||||
2. **平仓测试**:
|
||||
- 平仓后检查数据库中的 `exit_time` 是否为北京时间
|
||||
- 检查 `duration_minutes` 计算是否正确
|
||||
|
||||
3. **时区转换测试**:
|
||||
- 在不同时区的服务器上测试(如果可能)
|
||||
- 验证时间显示是否正确
|
||||
|
||||
## 总结
|
||||
|
||||
✅ **所有入库时间已统一使用北京时间**
|
||||
✅ **所有计算持续时间的地方已使用北京时间**
|
||||
✅ **已提供SQL脚本更新旧数据**
|
||||
✅ **代码已通过语法检查**
|
||||
|
||||
现在系统的时间处理已经完全统一,所有时间都使用北京时间(UTC+8)存储和计算。
|
||||
68
TRADE_STATUS_SYNC_FIX.md
Normal file
68
TRADE_STATUS_SYNC_FIX.md
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
# 订单状态同步问题分析与修复
|
||||
|
||||
## 🔍 问题分析
|
||||
|
||||
用户反映:订单记录中的订单状态没有及时同步,明明已经平仓了,但还是显示持仓状态。
|
||||
|
||||
### 可能的原因
|
||||
|
||||
1. **自动平仓时的双重更新问题**:
|
||||
- `_check_single_position` 中先更新数据库(第1926行)
|
||||
- 然后调用 `close_position`(第1943行)
|
||||
- `close_position` 中如果币安还有持仓,会再次更新数据库(第615行)
|
||||
- 但如果币安已经没有持仓了,`close_position` 会检查并更新(第432-492行)
|
||||
- **问题**:如果 `close_position` 执行时币安订单还没完全成交,可能状态不一致
|
||||
|
||||
2. **同步间隔太长**:
|
||||
- `POSITION_SYNC_INTERVAL` = 300秒(5分钟)
|
||||
- 如果自动平仓后数据库更新失败,需要等5分钟才能同步
|
||||
|
||||
3. **前端没有自动刷新**:
|
||||
- `TradeList` 组件只在加载时获取一次数据
|
||||
- 没有定时刷新机制
|
||||
- 用户需要手动刷新页面才能看到最新状态
|
||||
|
||||
4. **平仓订单可能失败但数据库已更新**:
|
||||
- 如果先更新数据库,然后平仓订单失败,状态会不一致
|
||||
|
||||
## 🔧 修复方案
|
||||
|
||||
### 方案一:优化自动平仓流程(推荐)
|
||||
|
||||
**问题**:`_check_single_position` 中先更新数据库,然后调用 `close_position`,但 `close_position` 可能因为币安订单还没成交而无法正确更新。
|
||||
|
||||
**修复**:
|
||||
1. 在 `_check_single_position` 中,不要先更新数据库
|
||||
2. 只调用 `close_position`,让 `close_position` 负责更新数据库
|
||||
3. 确保 `close_position` 在平仓成功后立即更新数据库
|
||||
|
||||
### 方案二:缩短同步间隔
|
||||
|
||||
**当前**:300秒(5分钟)
|
||||
**建议**:60-120秒(1-2分钟)
|
||||
|
||||
### 方案三:前端自动刷新
|
||||
|
||||
**添加**:TradeList 组件定时刷新(每30秒或1分钟)
|
||||
|
||||
### 方案四:平仓后立即同步
|
||||
|
||||
**添加**:在 `close_position` 成功后,立即触发一次状态同步
|
||||
|
||||
## 📝 具体修改
|
||||
|
||||
### 1. 优化自动平仓流程
|
||||
|
||||
修改 `_check_single_position` 方法,移除提前更新数据库的逻辑,让 `close_position` 统一处理。
|
||||
|
||||
### 2. 缩短同步间隔
|
||||
|
||||
将 `POSITION_SYNC_INTERVAL` 从 300秒 改为 60秒(1分钟)
|
||||
|
||||
### 3. 前端自动刷新
|
||||
|
||||
在 `TradeList` 组件中添加定时刷新机制
|
||||
|
||||
### 4. 平仓后立即同步
|
||||
|
||||
在 `close_position` 成功后,立即调用 `sync_positions_with_binance`
|
||||
|
|
@ -124,8 +124,18 @@ class ConfigManager:
|
|||
'MIN_STOP_LOSS_PRICE_PCT': self.get('MIN_STOP_LOSS_PRICE_PCT', 0.02), # 默认2%
|
||||
'MIN_TAKE_PROFIT_PRICE_PCT': self.get('MIN_TAKE_PROFIT_PRICE_PCT', 0.03), # 默认3%
|
||||
'USE_ATR_STOP_LOSS': self.get('USE_ATR_STOP_LOSS', True), # 是否使用ATR动态止损
|
||||
<<<<<<< Current (Your changes)
|
||||
'ATR_STOP_LOSS_MULTIPLIER': self.get('ATR_STOP_LOSS_MULTIPLIER', 1.8), # ATR止损倍数
|
||||
'ATR_TAKE_PROFIT_MULTIPLIER': self.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0), # ATR止盈倍数
|
||||
=======
|
||||
'ATR_STOP_LOSS_MULTIPLIER': self.get('ATR_STOP_LOSS_MULTIPLIER', 1.8), # ATR止损倍数(1.5-2倍)
|
||||
'ATR_TAKE_PROFIT_MULTIPLIER': self.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0), # ATR止盈倍数(3倍ATR)
|
||||
'RISK_REWARD_RATIO': self.get('RISK_REWARD_RATIO', 3.0), # 盈亏比(止损距离的倍数)
|
||||
'ATR_PERIOD': self.get('ATR_PERIOD', 14), # ATR计算周期
|
||||
'USE_DYNAMIC_ATR_MULTIPLIER': self.get('USE_DYNAMIC_ATR_MULTIPLIER', False), # 是否根据波动率动态调整ATR倍数
|
||||
'ATR_MULTIPLIER_MIN': self.get('ATR_MULTIPLIER_MIN', 1.5), # 动态ATR倍数最小值
|
||||
'ATR_MULTIPLIER_MAX': self.get('ATR_MULTIPLIER_MAX', 2.5), # 动态ATR倍数最大值
|
||||
>>>>>>> Incoming (Background Agent changes)
|
||||
|
||||
# 市场扫描(1小时主周期)
|
||||
'SCAN_INTERVAL': self.get('SCAN_INTERVAL', 3600), # 1小时
|
||||
|
|
|
|||
|
|
@ -148,6 +148,14 @@ INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `cate
|
|||
('USE_ATR_STOP_LOSS', 'true', 'boolean', 'risk', '是否使用ATR动态止损(优先于固定百分比)'),
|
||||
('ATR_STOP_LOSS_MULTIPLIER', '1.8', 'number', 'risk', 'ATR止损倍数(1.5-2倍ATR,默认1.8)'),
|
||||
('ATR_TAKE_PROFIT_MULTIPLIER', '3.0', 'number', 'risk', 'ATR止盈倍数(3倍ATR,对应3:1盈亏比)'),
|
||||
<<<<<<< Current (Your changes)
|
||||
=======
|
||||
('RISK_REWARD_RATIO', '3.0', 'number', 'risk', '盈亏比(止损距离的倍数,用于计算止盈)'),
|
||||
('ATR_PERIOD', '14', 'number', 'risk', 'ATR计算周期(默认14)'),
|
||||
('USE_DYNAMIC_ATR_MULTIPLIER', 'false', 'boolean', 'risk', '是否根据波动率动态调整ATR倍数'),
|
||||
('ATR_MULTIPLIER_MIN', '1.5', 'number', 'risk', '动态ATR倍数最小值'),
|
||||
('ATR_MULTIPLIER_MAX', '2.5', 'number', 'risk', '动态ATR倍数最大值'),
|
||||
>>>>>>> Incoming (Background Agent changes)
|
||||
|
||||
-- 市场扫描(1小时主周期)
|
||||
('SCAN_INTERVAL', '3600', 'number', 'scan', '扫描间隔:1小时(秒)'),
|
||||
|
|
|
|||
54
backend/database/migrate_time_to_timestamp.sql
Normal file
54
backend/database/migrate_time_to_timestamp.sql
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
-- 将时间字段从TIMESTAMP改为INT(存储Unix时间戳秒数)
|
||||
-- 此脚本会将现有的datetime/timestamp数据转换为Unix时间戳(秒)
|
||||
|
||||
USE `auto_trade_sys`;
|
||||
|
||||
-- 步骤1:添加新的INT类型字段(临时字段)
|
||||
ALTER TABLE `trades`
|
||||
ADD COLUMN `entry_time_ts` INT UNSIGNED NULL COMMENT '入场时间(Unix时间戳秒数)' AFTER `entry_time`,
|
||||
ADD COLUMN `exit_time_ts` INT UNSIGNED NULL COMMENT '平仓时间(Unix时间戳秒数)' AFTER `exit_time`,
|
||||
ADD COLUMN `created_at_ts` INT UNSIGNED NULL COMMENT '创建时间(Unix时间戳秒数)' AFTER `created_at`;
|
||||
|
||||
-- 步骤2:将现有数据转换为Unix时间戳(秒)
|
||||
-- 注意:假设现有数据是北京时间(UTC+8),转换为UTC时间戳
|
||||
UPDATE `trades`
|
||||
SET `entry_time_ts` = UNIX_TIMESTAMP(`entry_time`)
|
||||
WHERE `entry_time` IS NOT NULL;
|
||||
|
||||
UPDATE `trades`
|
||||
SET `exit_time_ts` = UNIX_TIMESTAMP(`exit_time`)
|
||||
WHERE `exit_time` IS NOT NULL;
|
||||
|
||||
UPDATE `trades`
|
||||
SET `created_at_ts` = UNIX_TIMESTAMP(`created_at`)
|
||||
WHERE `created_at` IS NOT NULL;
|
||||
|
||||
-- 步骤3:删除旧的时间字段
|
||||
ALTER TABLE `trades`
|
||||
DROP COLUMN `entry_time`,
|
||||
DROP COLUMN `exit_time`,
|
||||
DROP COLUMN `created_at`;
|
||||
|
||||
-- 步骤4:重命名新字段
|
||||
ALTER TABLE `trades`
|
||||
CHANGE COLUMN `entry_time_ts` `entry_time` INT UNSIGNED NOT NULL COMMENT '入场时间(Unix时间戳秒数)',
|
||||
CHANGE COLUMN `exit_time_ts` `exit_time` INT UNSIGNED NULL COMMENT '平仓时间(Unix时间戳秒数)',
|
||||
CHANGE COLUMN `created_at_ts` `created_at` INT UNSIGNED NOT NULL DEFAULT (UNIX_TIMESTAMP()) COMMENT '创建时间(Unix时间戳秒数)';
|
||||
|
||||
-- 步骤5:更新索引
|
||||
DROP INDEX IF EXISTS `idx_entry_time` ON `trades`;
|
||||
CREATE INDEX `idx_entry_time` ON `trades` (`entry_time`);
|
||||
|
||||
-- 验证:查看转换后的数据
|
||||
SELECT
|
||||
id,
|
||||
symbol,
|
||||
entry_time,
|
||||
FROM_UNIXTIME(entry_time) as entry_time_display,
|
||||
exit_time,
|
||||
FROM_UNIXTIME(exit_time) as exit_time_display,
|
||||
created_at,
|
||||
FROM_UNIXTIME(created_at) as created_at_display
|
||||
FROM `trades`
|
||||
ORDER BY id DESC
|
||||
LIMIT 10;
|
||||
74
backend/database/update_timezone_to_beijing.sql
Normal file
74
backend/database/update_timezone_to_beijing.sql
Normal file
|
|
@ -0,0 +1,74 @@
|
|||
-- 将旧数据的时间更新为北京时间(UTC+8)
|
||||
-- 假设旧数据存储的是UTC时间或服务器本地时间,需要转换为北京时间
|
||||
--
|
||||
-- 注意:此脚本假设旧数据的时间是UTC时间(或服务器本地时间,需要根据实际情况调整)
|
||||
-- 如果旧数据已经是北京时间,则不需要运行此脚本
|
||||
--
|
||||
-- 使用方法:
|
||||
-- 1. 先备份数据库
|
||||
-- 2. 根据实际情况调整时间偏移量(CONVERT_TZ 的第二个参数)
|
||||
-- 3. 运行此脚本
|
||||
|
||||
USE `auto_trade_sys`;
|
||||
|
||||
-- 检查当前时区设置
|
||||
SELECT @@global.time_zone, @@session.time_zone;
|
||||
|
||||
-- 方法1:如果旧数据是UTC时间,直接加8小时转换为北京时间
|
||||
-- 更新 entry_time(入场时间)
|
||||
UPDATE `trades`
|
||||
SET `entry_time` = DATE_ADD(`entry_time`, INTERVAL 8 HOUR)
|
||||
WHERE `entry_time` IS NOT NULL
|
||||
AND `entry_time` < '2025-01-01 00:00:00'; -- 只更新2025年之前的数据(根据实际情况调整)
|
||||
|
||||
-- 更新 exit_time(平仓时间)
|
||||
UPDATE `trades`
|
||||
SET `exit_time` = DATE_ADD(`exit_time`, INTERVAL 8 HOUR)
|
||||
WHERE `exit_time` IS NOT NULL
|
||||
AND `exit_time` < '2025-01-01 00:00:00'; -- 只更新2025年之前的数据(根据实际情况调整)
|
||||
|
||||
-- 方法2:如果旧数据是服务器本地时间(需要根据服务器时区调整)
|
||||
-- 例如,如果服务器是UTC+0,则加8小时;如果服务器是UTC+5,则加3小时
|
||||
-- 请根据实际情况调整 INTERVAL 的值
|
||||
--
|
||||
-- UPDATE `trades`
|
||||
-- SET `entry_time` = DATE_ADD(`entry_time`, INTERVAL 8 HOUR)
|
||||
-- WHERE `entry_time` IS NOT NULL;
|
||||
--
|
||||
-- UPDATE `trades`
|
||||
-- SET `exit_time` = DATE_ADD(`exit_time`, INTERVAL 8 HOUR)
|
||||
-- WHERE `exit_time` IS NOT NULL;
|
||||
|
||||
-- 方法3:如果MySQL支持时区转换函数(需要加载时区数据)
|
||||
-- 首先需要加载时区数据:mysql_tzinfo_to_sql /usr/share/zoneinfo | mysql -u root mysql
|
||||
--
|
||||
-- UPDATE `trades`
|
||||
-- SET `entry_time` = CONVERT_TZ(`entry_time`, 'UTC', 'Asia/Shanghai')
|
||||
-- WHERE `entry_time` IS NOT NULL;
|
||||
--
|
||||
-- UPDATE `trades`
|
||||
-- SET `exit_time` = CONVERT_TZ(`exit_time`, 'UTC', 'Asia/Shanghai')
|
||||
-- WHERE `exit_time` IS NOT NULL;
|
||||
|
||||
-- 验证更新结果(查看最近几条记录的时间)
|
||||
SELECT
|
||||
id,
|
||||
symbol,
|
||||
entry_time,
|
||||
exit_time,
|
||||
status,
|
||||
TIMESTAMPDIFF(HOUR, entry_time, COALESCE(exit_time, NOW())) as duration_hours
|
||||
FROM `trades`
|
||||
ORDER BY id DESC
|
||||
LIMIT 10;
|
||||
|
||||
-- 统计信息
|
||||
SELECT
|
||||
COUNT(*) as total_trades,
|
||||
COUNT(CASE WHEN entry_time IS NOT NULL THEN 1 END) as has_entry_time,
|
||||
COUNT(CASE WHEN exit_time IS NOT NULL THEN 1 END) as has_exit_time,
|
||||
MIN(entry_time) as earliest_entry,
|
||||
MAX(entry_time) as latest_entry,
|
||||
MIN(exit_time) as earliest_exit,
|
||||
MAX(exit_time) as latest_exit
|
||||
FROM `trades`;
|
||||
309
trading_system/atr_strategy.py
Normal file
309
trading_system/atr_strategy.py
Normal file
|
|
@ -0,0 +1,309 @@
|
|||
"""
|
||||
ATR策略模块 - 基于平均真实波幅(ATR)的动态止损止盈策略
|
||||
"""
|
||||
import logging
|
||||
from typing import Optional, Dict, Tuple
|
||||
try:
|
||||
from . import config
|
||||
from .indicators import TechnicalIndicators
|
||||
except ImportError:
|
||||
import config
|
||||
from indicators import TechnicalIndicators
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ATRStrategy:
|
||||
"""ATR策略类 - 基于ATR的动态止损止盈计算"""
|
||||
|
||||
def __init__(self):
|
||||
"""初始化ATR策略"""
|
||||
self.use_atr = config.TRADING_CONFIG.get('USE_ATR_STOP_LOSS', True)
|
||||
self.atr_sl_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 1.8)
|
||||
self.atr_tp_multiplier = config.TRADING_CONFIG.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0)
|
||||
self.risk_reward_ratio = config.TRADING_CONFIG.get('RISK_REWARD_RATIO', 3.0)
|
||||
self.atr_period = config.TRADING_CONFIG.get('ATR_PERIOD', 14)
|
||||
|
||||
# 动态调整ATR倍数的参数
|
||||
self.use_dynamic_atr_multiplier = config.TRADING_CONFIG.get('USE_DYNAMIC_ATR_MULTIPLIER', False)
|
||||
self.atr_multiplier_min = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MIN', 1.5)
|
||||
self.atr_multiplier_max = config.TRADING_CONFIG.get('ATR_MULTIPLIER_MAX', 2.5)
|
||||
|
||||
def calculate_stop_loss(
|
||||
self,
|
||||
entry_price: float,
|
||||
side: str,
|
||||
atr: Optional[float] = None,
|
||||
atr_percent: Optional[float] = None,
|
||||
volatility: Optional[float] = None
|
||||
) -> Tuple[Optional[float], Optional[float], Dict]:
|
||||
"""
|
||||
计算基于ATR的止损价格
|
||||
|
||||
Args:
|
||||
entry_price: 入场价格
|
||||
side: 方向 'BUY' 或 'SELL'
|
||||
atr: ATR绝对值(可选,如果提供则直接使用)
|
||||
atr_percent: ATR百分比(可选,如果提供则直接使用,否则从atr计算)
|
||||
volatility: 市场波动率(可选,用于动态调整ATR倍数)
|
||||
|
||||
Returns:
|
||||
(止损价格, 止损距离, 详细信息字典)
|
||||
"""
|
||||
if not self.use_atr:
|
||||
return None, None, {}
|
||||
|
||||
# 如果没有提供ATR,无法计算
|
||||
if atr is None and atr_percent is None:
|
||||
logger.debug("ATR不可用,无法计算ATR止损")
|
||||
return None, None, {}
|
||||
|
||||
# 计算ATR百分比(如果未提供)
|
||||
if atr_percent is None and atr is not None and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
|
||||
if atr_percent is None or atr_percent <= 0:
|
||||
logger.debug("ATR百分比无效,无法计算ATR止损")
|
||||
return None, None, {}
|
||||
|
||||
# 动态调整ATR倍数(根据市场波动率)
|
||||
if self.use_dynamic_atr_multiplier and volatility is not None:
|
||||
# 波动率越高,ATR倍数越大(更宽松的止损)
|
||||
# 波动率范围假设:0.01-0.10 (1%-10%)
|
||||
volatility_factor = min(max((volatility - 0.01) / 0.09, 0), 1) # 归一化到0-1
|
||||
dynamic_multiplier = (
|
||||
self.atr_multiplier_min +
|
||||
(self.atr_multiplier_max - self.atr_multiplier_min) * volatility_factor
|
||||
)
|
||||
atr_multiplier = dynamic_multiplier
|
||||
logger.debug(f"动态ATR倍数: 波动率={volatility:.4f}, 倍数={atr_multiplier:.2f}")
|
||||
else:
|
||||
atr_multiplier = self.atr_sl_multiplier
|
||||
|
||||
# 计算止损距离(基于ATR百分比)
|
||||
stop_distance_percent = atr_percent * atr_multiplier
|
||||
|
||||
# 计算止损价格
|
||||
if side == 'BUY': # 做多,止损价低于入场价
|
||||
stop_loss_price = entry_price * (1 - stop_distance_percent)
|
||||
stop_distance = entry_price - stop_loss_price
|
||||
else: # 做空,止损价高于入场价
|
||||
stop_loss_price = entry_price * (1 + stop_distance_percent)
|
||||
stop_distance = stop_loss_price - entry_price
|
||||
|
||||
details = {
|
||||
'atr': atr,
|
||||
'atr_percent': atr_percent,
|
||||
'atr_multiplier': atr_multiplier,
|
||||
'stop_distance_percent': stop_distance_percent,
|
||||
'stop_distance': stop_distance,
|
||||
'method': 'ATR动态止损'
|
||||
}
|
||||
|
||||
logger.info(
|
||||
f"ATR止损计算 ({side}): "
|
||||
f"ATR={atr:.4f if atr else 'N/A'}, "
|
||||
f"ATR%={atr_percent*100:.2f}%, "
|
||||
f"倍数={atr_multiplier:.2f}, "
|
||||
f"止损距离={stop_distance_percent*100:.2f}%, "
|
||||
f"止损价={stop_loss_price:.4f}"
|
||||
)
|
||||
|
||||
return stop_loss_price, stop_distance, details
|
||||
|
||||
def calculate_take_profit(
|
||||
self,
|
||||
entry_price: float,
|
||||
side: str,
|
||||
stop_distance: Optional[float] = None,
|
||||
atr: Optional[float] = None,
|
||||
atr_percent: Optional[float] = None,
|
||||
use_risk_reward_ratio: bool = True
|
||||
) -> Tuple[Optional[float], Optional[float], Dict]:
|
||||
"""
|
||||
计算基于ATR的止盈价格
|
||||
|
||||
Args:
|
||||
entry_price: 入场价格
|
||||
side: 方向 'BUY' 或 'SELL'
|
||||
stop_distance: 止损距离(价格差,可选,如果提供则基于盈亏比计算)
|
||||
atr: ATR绝对值(可选)
|
||||
atr_percent: ATR百分比(可选)
|
||||
use_risk_reward_ratio: 是否使用盈亏比(True:基于止损距离×盈亏比,False:基于ATR倍数)
|
||||
|
||||
Returns:
|
||||
(止盈价格, 止盈距离, 详细信息字典)
|
||||
"""
|
||||
if not self.use_atr:
|
||||
return None, None, {}
|
||||
|
||||
# 方法1:基于止损距离和盈亏比计算(优先)
|
||||
if use_risk_reward_ratio and stop_distance is not None and stop_distance > 0:
|
||||
take_profit_distance = stop_distance * self.risk_reward_ratio
|
||||
|
||||
if side == 'BUY': # 做多,止盈价高于入场价
|
||||
take_profit_price = entry_price + take_profit_distance
|
||||
else: # 做空,止盈价低于入场价
|
||||
take_profit_price = entry_price - take_profit_distance
|
||||
|
||||
details = {
|
||||
'stop_distance': stop_distance,
|
||||
'risk_reward_ratio': self.risk_reward_ratio,
|
||||
'take_profit_distance': take_profit_distance,
|
||||
'method': 'ATR止损距离×盈亏比'
|
||||
}
|
||||
|
||||
logger.info(
|
||||
f"ATR止盈计算 ({side}, 基于盈亏比): "
|
||||
f"止损距离={stop_distance:.4f}, "
|
||||
f"盈亏比={self.risk_reward_ratio:.1f}, "
|
||||
f"止盈距离={take_profit_distance:.4f}, "
|
||||
f"止盈价={take_profit_price:.4f}"
|
||||
)
|
||||
|
||||
return take_profit_price, take_profit_distance, details
|
||||
|
||||
# 方法2:基于ATR倍数计算(备选)
|
||||
if atr is None and atr_percent is None:
|
||||
logger.debug("ATR不可用,无法计算ATR止盈")
|
||||
return None, None, {}
|
||||
|
||||
# 计算ATR百分比(如果未提供)
|
||||
if atr_percent is None and atr is not None and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
|
||||
if atr_percent is None or atr_percent <= 0:
|
||||
logger.debug("ATR百分比无效,无法计算ATR止盈")
|
||||
return None, None, {}
|
||||
|
||||
# 计算止盈距离(基于ATR百分比)
|
||||
take_profit_distance_percent = atr_percent * self.atr_tp_multiplier
|
||||
|
||||
# 计算止盈价格
|
||||
if side == 'BUY': # 做多,止盈价高于入场价
|
||||
take_profit_price = entry_price * (1 + take_profit_distance_percent)
|
||||
take_profit_distance = take_profit_price - entry_price
|
||||
else: # 做空,止盈价低于入场价
|
||||
take_profit_price = entry_price * (1 - take_profit_distance_percent)
|
||||
take_profit_distance = entry_price - take_profit_price
|
||||
|
||||
details = {
|
||||
'atr': atr,
|
||||
'atr_percent': atr_percent,
|
||||
'atr_multiplier': self.atr_tp_multiplier,
|
||||
'take_profit_distance_percent': take_profit_distance_percent,
|
||||
'take_profit_distance': take_profit_distance,
|
||||
'method': 'ATR倍数止盈'
|
||||
}
|
||||
|
||||
logger.info(
|
||||
f"ATR止盈计算 ({side}, 基于ATR倍数): "
|
||||
f"ATR={atr:.4f if atr else 'N/A'}, "
|
||||
f"ATR%={atr_percent*100:.2f}%, "
|
||||
f"倍数={self.atr_tp_multiplier:.2f}, "
|
||||
f"止盈距离={take_profit_distance_percent*100:.2f}%, "
|
||||
f"止盈价={take_profit_price:.4f}"
|
||||
)
|
||||
|
||||
return take_profit_price, take_profit_distance, details
|
||||
|
||||
def calculate_atr_levels(
|
||||
self,
|
||||
entry_price: float,
|
||||
side: str,
|
||||
atr: Optional[float] = None,
|
||||
atr_percent: Optional[float] = None,
|
||||
volatility: Optional[float] = None
|
||||
) -> Dict:
|
||||
"""
|
||||
计算完整的ATR止损止盈方案
|
||||
|
||||
Args:
|
||||
entry_price: 入场价格
|
||||
side: 方向 'BUY' 或 'SELL'
|
||||
atr: ATR绝对值(可选)
|
||||
atr_percent: ATR百分比(可选)
|
||||
volatility: 市场波动率(可选)
|
||||
|
||||
Returns:
|
||||
包含止损、止盈等信息的字典
|
||||
"""
|
||||
result = {
|
||||
'use_atr': self.use_atr,
|
||||
'entry_price': entry_price,
|
||||
'side': side,
|
||||
'stop_loss_price': None,
|
||||
'stop_loss_distance': None,
|
||||
'take_profit_price': None,
|
||||
'take_profit_distance': None,
|
||||
'risk_reward_ratio': None,
|
||||
'details': {}
|
||||
}
|
||||
|
||||
if not self.use_atr:
|
||||
return result
|
||||
|
||||
# 计算止损
|
||||
stop_loss_price, stop_distance, stop_details = self.calculate_stop_loss(
|
||||
entry_price, side, atr, atr_percent, volatility
|
||||
)
|
||||
|
||||
if stop_loss_price is None:
|
||||
return result
|
||||
|
||||
result['stop_loss_price'] = stop_loss_price
|
||||
result['stop_loss_distance'] = stop_distance
|
||||
result['details']['stop_loss'] = stop_details
|
||||
|
||||
# 计算止盈(基于止损距离和盈亏比)
|
||||
take_profit_price, take_profit_distance, tp_details = self.calculate_take_profit(
|
||||
entry_price, side, stop_distance, atr, atr_percent, use_risk_reward_ratio=True
|
||||
)
|
||||
|
||||
if take_profit_price is not None:
|
||||
result['take_profit_price'] = take_profit_price
|
||||
result['take_profit_distance'] = take_profit_distance
|
||||
result['risk_reward_ratio'] = (
|
||||
take_profit_distance / stop_distance if stop_distance > 0 else None
|
||||
)
|
||||
result['details']['take_profit'] = tp_details
|
||||
|
||||
return result
|
||||
|
||||
@staticmethod
|
||||
def calculate_atr_from_klines(
|
||||
klines: list,
|
||||
period: int = 14
|
||||
) -> Tuple[Optional[float], Optional[float], Optional[float]]:
|
||||
"""
|
||||
从K线数据计算ATR和ATR百分比
|
||||
|
||||
Args:
|
||||
klines: K线数据列表,格式为 [open, high, low, close, ...]
|
||||
period: ATR计算周期,默认14
|
||||
|
||||
Returns:
|
||||
(ATR绝对值, ATR百分比, 当前价格)
|
||||
"""
|
||||
if not klines or len(klines) < period + 1:
|
||||
return None, None, None
|
||||
|
||||
try:
|
||||
high_prices = [float(k[2]) for k in klines] # high
|
||||
low_prices = [float(k[3]) for k in klines] # low
|
||||
close_prices = [float(k[4]) for k in klines] # close
|
||||
|
||||
current_price = close_prices[-1] if close_prices else None
|
||||
|
||||
atr = TechnicalIndicators.calculate_atr(high_prices, low_prices, close_prices, period)
|
||||
|
||||
if atr is None or current_price is None or current_price <= 0:
|
||||
return None, None, None
|
||||
|
||||
atr_percent = atr / current_price
|
||||
|
||||
return atr, atr_percent, current_price
|
||||
|
||||
except (IndexError, ValueError, TypeError) as e:
|
||||
logger.debug(f"从K线计算ATR失败: {e}")
|
||||
return None, None, None
|
||||
|
|
@ -175,6 +175,14 @@ def _get_trading_config():
|
|||
'USE_ATR_STOP_LOSS': True, # 是否使用ATR动态止损(优先于固定百分比)
|
||||
'ATR_STOP_LOSS_MULTIPLIER': 1.8, # ATR止损倍数(1.5-2倍ATR,默认1.8)
|
||||
'ATR_TAKE_PROFIT_MULTIPLIER': 3.0, # ATR止盈倍数(3倍ATR,对应3:1盈亏比)
|
||||
<<<<<<< Current (Your changes)
|
||||
=======
|
||||
'RISK_REWARD_RATIO': 3.0, # 盈亏比(止损距离的倍数,用于计算止盈)
|
||||
'ATR_PERIOD': 14, # ATR计算周期(默认14)
|
||||
'USE_DYNAMIC_ATR_MULTIPLIER': False, # 是否根据波动率动态调整ATR倍数
|
||||
'ATR_MULTIPLIER_MIN': 1.5, # 动态ATR倍数最小值
|
||||
'ATR_MULTIPLIER_MAX': 2.5, # 动态ATR倍数最大值
|
||||
>>>>>>> Incoming (Background Agent changes)
|
||||
'SCAN_INTERVAL': 3600,
|
||||
'KLINE_INTERVAL': '1h',
|
||||
'PRIMARY_INTERVAL': '1h',
|
||||
|
|
|
|||
|
|
@ -165,7 +165,7 @@ class TechnicalIndicators:
|
|||
period: 计算周期,默认14
|
||||
|
||||
Returns:
|
||||
ATR值
|
||||
ATR值(绝对价格)
|
||||
"""
|
||||
if len(high_prices) < period + 1 or len(low_prices) < period + 1 or len(close_prices) < period + 1:
|
||||
return None
|
||||
|
|
@ -187,6 +187,34 @@ class TechnicalIndicators:
|
|||
|
||||
return atr
|
||||
|
||||
@staticmethod
|
||||
def calculate_atr_percent(
|
||||
high_prices: List[float],
|
||||
low_prices: List[float],
|
||||
close_prices: List[float],
|
||||
current_price: float,
|
||||
period: int = 14
|
||||
) -> Optional[float]:
|
||||
"""
|
||||
计算ATR百分比(ATR相对于当前价格的百分比)
|
||||
|
||||
Args:
|
||||
high_prices: 最高价列表
|
||||
low_prices: 最低价列表
|
||||
close_prices: 收盘价列表
|
||||
current_price: 当前价格(用于计算百分比)
|
||||
period: 计算周期,默认14
|
||||
|
||||
Returns:
|
||||
ATR百分比(0.03表示3%),None表示数据不足
|
||||
"""
|
||||
atr = TechnicalIndicators.calculate_atr(high_prices, low_prices, close_prices, period)
|
||||
if atr is None or current_price <= 0:
|
||||
return None
|
||||
|
||||
atr_percent = atr / current_price
|
||||
return atr_percent
|
||||
|
||||
@staticmethod
|
||||
def calculate_ema(prices: List[float], period: int = 20) -> Optional[float]:
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -173,6 +173,22 @@ class PositionManager:
|
|||
atr=atr
|
||||
)
|
||||
|
||||
# 计算止损距离(用于盈亏比计算止盈)
|
||||
stop_distance_for_tp = None
|
||||
if side == 'BUY':
|
||||
stop_distance_for_tp = entry_price - stop_loss_price
|
||||
else: # SELL
|
||||
stop_distance_for_tp = stop_loss_price - entry_price
|
||||
|
||||
# 如果使用ATR策略,优先使用ATR计算的止损距离
|
||||
if atr is not None and atr > 0:
|
||||
atr_percent = atr / entry_price if entry_price > 0 else None
|
||||
if atr_percent:
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 1.8)
|
||||
atr_stop_distance = entry_price * atr_percent * atr_multiplier
|
||||
# 使用ATR计算的止损距离(更准确)
|
||||
stop_distance_for_tp = atr_stop_distance
|
||||
|
||||
# 计算止盈(基于保证金,支持ATR动态止盈)
|
||||
# 优先使用配置的止盈百分比,如果没有配置则使用止损的3倍(盈亏比3:1)
|
||||
take_profit_pct_margin = config.TRADING_CONFIG.get('TAKE_PROFIT_PERCENT', 0.30)
|
||||
|
|
@ -182,7 +198,8 @@ class PositionManager:
|
|||
take_profit_price = self.risk_manager.get_take_profit_price(
|
||||
entry_price, side, quantity, leverage,
|
||||
take_profit_pct=take_profit_pct_margin,
|
||||
atr=atr # 传递ATR用于动态止盈
|
||||
atr=atr, # 传递ATR用于动态止盈
|
||||
stop_distance=stop_distance_for_tp # 传递止损距离用于盈亏比计算
|
||||
)
|
||||
|
||||
# 下单
|
||||
|
|
|
|||
|
|
@ -6,9 +6,11 @@ from typing import Dict, List, Optional
|
|||
try:
|
||||
from .binance_client import BinanceClient
|
||||
from . import config
|
||||
from .atr_strategy import ATRStrategy
|
||||
except ImportError:
|
||||
from binance_client import BinanceClient
|
||||
import config
|
||||
from atr_strategy import ATRStrategy
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -26,6 +28,8 @@ class RiskManager:
|
|||
self.client = client
|
||||
# 不保存引用,每次都从 config.TRADING_CONFIG 读取最新配置
|
||||
# self.config = config.TRADING_CONFIG # 移除,避免使用旧配置
|
||||
# 初始化ATR策略
|
||||
self.atr_strategy = ATRStrategy()
|
||||
|
||||
async def check_position_size(self, symbol: str, quantity: float) -> bool:
|
||||
"""
|
||||
|
|
@ -428,25 +432,20 @@ class RiskManager:
|
|||
margin = position_value / leverage if leverage > 0 else position_value
|
||||
|
||||
# 优先使用ATR动态止损(如果启用且ATR可用)
|
||||
use_atr_stop = config.TRADING_CONFIG.get('USE_ATR_STOP_LOSS', True)
|
||||
atr_multiplier = config.TRADING_CONFIG.get('ATR_STOP_LOSS_MULTIPLIER', 1.8)
|
||||
# 计算ATR百分比(如果提供了ATR绝对值)
|
||||
atr_percent = None
|
||||
if atr is not None and atr > 0 and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
|
||||
if use_atr_stop and atr is not None and atr > 0:
|
||||
# 基于ATR的动态止损
|
||||
atr_stop_distance = atr * atr_multiplier
|
||||
# 获取市场波动率(如果可用)
|
||||
volatility = None # 可以从symbol_info中获取,这里暂时为None
|
||||
|
||||
if side == 'BUY': # 做多,止损价低于入场价
|
||||
stop_loss_price_atr = entry_price - atr_stop_distance
|
||||
else: # 做空,止损价高于入场价
|
||||
stop_loss_price_atr = entry_price + atr_stop_distance
|
||||
|
||||
logger.info(
|
||||
f"ATR动态止损计算 ({side}): ATR={atr:.4f}, 倍数={atr_multiplier}, "
|
||||
f"止损距离={atr_stop_distance:.4f}, ATR止损价={stop_loss_price_atr:.4f}"
|
||||
# 使用ATR策略计算止损
|
||||
stop_loss_price_atr, stop_distance_atr, atr_details = self.atr_strategy.calculate_stop_loss(
|
||||
entry_price, side, atr, atr_percent, volatility
|
||||
)
|
||||
else:
|
||||
stop_loss_price_atr = None
|
||||
if use_atr_stop and (atr is None or atr <= 0):
|
||||
|
||||
if stop_loss_price_atr is None:
|
||||
logger.debug(f"ATR不可用,使用固定百分比止损")
|
||||
|
||||
# 获取止损百分比(相对于保证金)
|
||||
|
|
@ -564,7 +563,8 @@ class RiskManager:
|
|||
quantity: float,
|
||||
leverage: int,
|
||||
take_profit_pct: Optional[float] = None,
|
||||
atr: Optional[float] = None
|
||||
atr: Optional[float] = None,
|
||||
stop_distance: Optional[float] = None
|
||||
) -> float:
|
||||
"""
|
||||
计算止盈价格(基于保证金的盈亏金额,支持ATR动态止盈)
|
||||
|
|
@ -585,25 +585,24 @@ class RiskManager:
|
|||
margin = position_value / leverage if leverage > 0 else position_value
|
||||
|
||||
# 优先使用ATR动态止盈(如果启用且ATR可用)
|
||||
use_atr_stop = config.TRADING_CONFIG.get('USE_ATR_STOP_LOSS', True)
|
||||
atr_tp_multiplier = config.TRADING_CONFIG.get('ATR_TAKE_PROFIT_MULTIPLIER', 3.0)
|
||||
# 计算ATR百分比(如果提供了ATR绝对值)
|
||||
atr_percent = None
|
||||
if atr is not None and atr > 0 and entry_price > 0:
|
||||
atr_percent = atr / entry_price
|
||||
|
||||
if use_atr_stop and atr is not None and atr > 0:
|
||||
# 基于ATR的动态止盈(对应3:1盈亏比)
|
||||
atr_tp_distance = atr * atr_tp_multiplier
|
||||
# 尝试从止损计算中获取止损距离(用于盈亏比计算)
|
||||
# 如果止损已经计算过,可以使用止损距离来计算止盈
|
||||
stop_distance_for_rr = None
|
||||
# 注意:这里无法直接获取止损距离,需要调用方传递,或者使用ATR倍数计算
|
||||
|
||||
if side == 'BUY': # 做多,止盈价高于入场价
|
||||
take_profit_price_atr = entry_price + atr_tp_distance
|
||||
else: # 做空,止盈价低于入场价
|
||||
take_profit_price_atr = entry_price - atr_tp_distance
|
||||
|
||||
logger.info(
|
||||
f"ATR动态止盈计算 ({side}): ATR={atr:.4f}, 倍数={atr_tp_multiplier}, "
|
||||
f"止盈距离={atr_tp_distance:.4f}, ATR止盈价={take_profit_price_atr:.4f}"
|
||||
# 使用ATR策略计算止盈
|
||||
# 优先使用盈亏比方法(基于止损距离),如果没有止损距离则使用ATR倍数
|
||||
take_profit_price_atr, take_profit_distance_atr, atr_tp_details = self.atr_strategy.calculate_take_profit(
|
||||
entry_price, side, stop_distance, atr, atr_percent,
|
||||
use_risk_reward_ratio=(stop_distance is not None)
|
||||
)
|
||||
else:
|
||||
take_profit_price_atr = None
|
||||
if use_atr_stop and (atr is None or atr <= 0):
|
||||
|
||||
if take_profit_price_atr is None:
|
||||
logger.debug(f"ATR不可用,使用固定百分比止盈")
|
||||
|
||||
# 获取止盈百分比(相对于保证金)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user