429 lines
13 KiB
Markdown
429 lines
13 KiB
Markdown
# 交易策略与盈亏平仓处理分析报告
|
||
|
||
## 一、当前策略架构
|
||
|
||
### 1.1 策略核心逻辑
|
||
|
||
#### 多周期共振策略
|
||
- **4H周期定方向**:使用EMA20判断大趋势(up/down/neutral)
|
||
- **1H周期找信号**:使用RSI、MACD、布林带、均线系统
|
||
- **15min周期入场**:精细点位选择
|
||
|
||
#### 市场状态识别
|
||
- **震荡市场(ranging)**:均值回归策略
|
||
- RSI超卖(<30)→ 做多信号
|
||
- RSI超买(>70)→ 做空信号
|
||
- 布林带下轨 → 做多信号
|
||
- 布林带上轨 → 做空信号
|
||
|
||
- **趋势市场(trending)**:趋势跟踪策略
|
||
- MACD金叉 → 做多信号
|
||
- MACD死叉 → 做空信号
|
||
- 价格在均线之上(EMA20 > EMA50)→ 做多信号
|
||
- 价格在均线之下(EMA20 < EMA50)→ 做空信号
|
||
|
||
#### 信号强度计算
|
||
- **基础分数**:
|
||
- RSI超买/超卖:+4分
|
||
- 布林带触及:+3分
|
||
- MACD金叉/死叉:+3分
|
||
- 均线系统:+2分
|
||
- 多指标确认(≥2个):+2分
|
||
- 4H周期共振:+2分
|
||
|
||
- **扣分项**:
|
||
- 逆4H趋势:-3分
|
||
- 信号强度不足:拒绝交易
|
||
|
||
- **交易阈值**:信号强度 ≥ 7(可配置 `MIN_SIGNAL_STRENGTH`)
|
||
|
||
#### 开仓条件检查流程
|
||
```
|
||
1. 市场扫描 → 找出涨跌幅最大的前N个交易对
|
||
2. 技术指标分析 → 计算信号强度和方向
|
||
3. 风险检查:
|
||
- 最小涨跌幅阈值(MIN_CHANGE_PERCENT)
|
||
- 是否已有持仓(避免重复开仓)
|
||
- 成交量确认(MIN_VOLUME_24H)
|
||
4. 仓位计算:
|
||
- 单笔仓位限制(MAX_POSITION_PERCENT)
|
||
- 总仓位限制(MAX_TOTAL_POSITION_PERCENT)
|
||
- 最小保证金要求(MIN_MARGIN_USDT)
|
||
5. 动态杠杆计算(根据信号强度)
|
||
6. 开仓执行
|
||
```
|
||
|
||
### 1.2 风险管理
|
||
|
||
#### 仓位管理
|
||
- **单笔仓位**:账户余额的 1%-5%(可配置)
|
||
- **总仓位上限**:账户余额的 30%(可配置)
|
||
- **最小保证金**:0.5 USDT(可配置)
|
||
- **动态杠杆**:10x-20x(根据信号强度调整)
|
||
|
||
#### 止损止盈机制
|
||
|
||
**止损计算(混合策略)**:
|
||
1. **基于保证金的止损**:
|
||
- 止损金额 = 保证金 × STOP_LOSS_PERCENT(默认8%)
|
||
- 止损价 = 入场价 ± (止损金额 / 数量)
|
||
|
||
2. **基于价格百分比的保护**:
|
||
- 最小价格变动 = 入场价 × MIN_STOP_LOSS_PRICE_PCT(默认2%)
|
||
- 最终止损价 = max(基于保证金的止损, 基于价格的止损) [取更宽松的]
|
||
|
||
3. **技术止损(可选)**:
|
||
- 使用支撑/阻力位、布林带
|
||
- 如果技术止损更紧,使用技术止损
|
||
|
||
**止盈计算(混合策略)**:
|
||
1. **基于保证金的止盈**:
|
||
- 止盈金额 = 保证金 × TAKE_PROFIT_PERCENT(默认15%)
|
||
- 止盈价 = 入场价 ± (止盈金额 / 数量)
|
||
|
||
2. **基于价格百分比的保护**:
|
||
- 最小价格变动 = 入场价 × MIN_TAKE_PROFIT_PRICE_PCT(默认3%)
|
||
- 最终止盈价 = max(基于保证金的止盈, 基于价格的止盈) [取更宽松的]
|
||
|
||
**分步止盈策略**:
|
||
- **第一目标**:盈亏比 1:1,平仓 50%
|
||
- **第二目标**:原始止盈价,平仓剩余 50%
|
||
- 部分止盈后,止损移至成本价(保本)
|
||
|
||
**移动止损(Trailing Stop)**:
|
||
- **激活条件**:盈利达到保证金的 1%(TRAILING_STOP_ACTIVATION)
|
||
- **保护机制**:止损价跟随价格移动,保护保证金的 1%利润(TRAILING_STOP_PROTECT)
|
||
|
||
### 1.3 监控机制
|
||
|
||
#### 实时监控(WebSocket)
|
||
- 每个持仓独立WebSocket连接
|
||
- 实时接收价格更新
|
||
- 立即检查止损止盈条件
|
||
- 自动重连机制(最多5次)
|
||
|
||
#### 定时检查(备用)
|
||
- 扫描间隔:可配置(默认3600秒)
|
||
- 持仓同步:每5分钟(POSITION_SYNC_INTERVAL)
|
||
- 作为WebSocket的备用方案
|
||
|
||
## 二、发现的问题
|
||
|
||
### 2.1 代码问题
|
||
|
||
#### 问题1:部分止盈逻辑重复
|
||
**位置**:`position_manager.py` 第829-851行
|
||
```python
|
||
# 代码重复:做多和做空的处理逻辑几乎相同,但写了两遍
|
||
# 第一段(第808-828行):处理做多
|
||
# 第二段(第829-851行):处理做空,但逻辑相同
|
||
```
|
||
|
||
**影响**:代码冗余,维护困难,容易出错
|
||
|
||
#### 问题2:止损检查逻辑重复
|
||
**位置**:`position_manager.py` 第744-782行
|
||
```python
|
||
# 第744行:检查止损价是否设置
|
||
# 第747行:再次检查止损价(重复)
|
||
```
|
||
|
||
**影响**:代码冗余,逻辑不清晰
|
||
|
||
#### 问题3:移动止损计算可能有问题
|
||
**位置**:`position_manager.py` 第718-740行
|
||
```python
|
||
# 移动止损的计算方式:
|
||
# new_stop_loss = entry_price + (pnl_amount - protect_amount) / quantity
|
||
# 这个公式可能不正确,因为:
|
||
# 1. pnl_amount 是当前总盈亏,但应该基于剩余仓位
|
||
# 2. 如果已经部分止盈,应该基于剩余仓位计算
|
||
```
|
||
|
||
**影响**:移动止损可能不准确
|
||
|
||
#### 问题4:分步止盈后剩余仓位计算
|
||
**位置**:`position_manager.py` 第854-894行
|
||
```python
|
||
# 第二目标止盈时,使用 remaining_quantity 计算盈亏
|
||
# 但 pnl_amount 仍然是基于原始 quantity 计算的
|
||
# 这可能导致盈亏计算不准确
|
||
```
|
||
|
||
**影响**:盈亏统计可能不准确
|
||
|
||
### 2.2 策略问题
|
||
|
||
#### 问题1:信号强度计算不够清晰
|
||
- 多个指标同时触发时,分数可能过高
|
||
- 没有考虑指标之间的冲突(如RSI超买但MACD死叉)
|
||
- 4H趋势判断过于简单(只用EMA20)
|
||
|
||
#### 问题2:缺少策略回测
|
||
- 没有历史数据回测功能
|
||
- 无法验证策略有效性
|
||
- 无法优化参数
|
||
|
||
#### 问题3:缺少交易统计
|
||
- 没有胜率统计
|
||
- 没有盈亏比统计
|
||
- 没有按策略类型统计(均值回归 vs 趋势跟踪)
|
||
|
||
#### 问题4:移动止损激活条件可能太早
|
||
- 激活条件:盈利1% of margin
|
||
- 保护金额:1% of margin
|
||
- 这意味着一旦激活,就保护1%利润,但可能被正常波动触发
|
||
|
||
### 2.3 性能问题
|
||
|
||
#### 问题1:WebSocket连接过多
|
||
- 每个持仓一个WebSocket连接
|
||
- 如果有10个持仓,就有10个连接
|
||
- 可能达到币安连接数限制
|
||
|
||
#### 问题2:定时检查与WebSocket重复
|
||
- WebSocket实时监控 + 定时检查
|
||
- 可能造成重复计算
|
||
|
||
## 三、优化建议
|
||
|
||
### 3.1 代码优化
|
||
|
||
#### 建议1:重构部分止盈逻辑
|
||
```python
|
||
# 统一处理做多和做空
|
||
async def _partial_take_profit(self, symbol: str, position_info: Dict, target_pct: float):
|
||
"""统一的部分止盈逻辑"""
|
||
side = position_info['side']
|
||
quantity = position_info['quantity']
|
||
partial_quantity = quantity * 0.5
|
||
|
||
# 确定平仓方向
|
||
close_side = 'SELL' if side == 'BUY' else 'BUY'
|
||
|
||
# 执行部分平仓
|
||
partial_order = await self.client.place_order(
|
||
symbol=symbol,
|
||
side=close_side,
|
||
quantity=partial_quantity,
|
||
order_type='MARKET'
|
||
)
|
||
|
||
if partial_order:
|
||
position_info['partialProfitTaken'] = True
|
||
position_info['remainingQuantity'] = quantity - partial_quantity
|
||
position_info['stopLoss'] = position_info['entryPrice'] # 移至成本价
|
||
position_info['trailingStopActivated'] = True
|
||
```
|
||
|
||
#### 建议2:修复移动止损计算
|
||
```python
|
||
# 修复移动止损计算,基于剩余仓位
|
||
if position_info.get('partialProfitTaken', False):
|
||
remaining_quantity = position_info.get('remainingQuantity', quantity)
|
||
remaining_margin = (entry_price * remaining_quantity) / leverage
|
||
protect_amount = remaining_margin * trailing_protect
|
||
# 基于剩余仓位计算盈亏
|
||
if side == 'BUY':
|
||
remaining_pnl = (current_price - entry_price) * remaining_quantity
|
||
else:
|
||
remaining_pnl = (entry_price - current_price) * remaining_quantity
|
||
|
||
# 计算新的止损价
|
||
if side == 'BUY':
|
||
new_stop_loss = entry_price + (remaining_pnl - protect_amount) / remaining_quantity
|
||
else:
|
||
new_stop_loss = entry_price - (remaining_pnl - protect_amount) / remaining_quantity
|
||
else:
|
||
# 未部分止盈,使用原始逻辑
|
||
...
|
||
```
|
||
|
||
#### 建议3:统一止损止盈检查
|
||
```python
|
||
async def _check_sl_tp(self, symbol: str, current_price: float) -> Optional[str]:
|
||
"""
|
||
统一的止损止盈检查
|
||
返回:None(不触发)或 'stop_loss'/'take_profit'/'trailing_stop'
|
||
"""
|
||
position_info = self.active_positions.get(symbol)
|
||
if not position_info:
|
||
return None
|
||
|
||
# 计算盈亏
|
||
pnl_data = self._calculate_pnl(position_info, current_price)
|
||
|
||
# 检查止损
|
||
if self._check_stop_loss(position_info, pnl_data):
|
||
return 'stop_loss'
|
||
|
||
# 检查移动止损
|
||
if self._check_trailing_stop(position_info, pnl_data):
|
||
return 'trailing_stop'
|
||
|
||
# 检查止盈
|
||
if self._check_take_profit(position_info, pnl_data):
|
||
return 'take_profit'
|
||
|
||
return None
|
||
```
|
||
|
||
### 3.2 策略优化
|
||
|
||
#### 建议1:改进信号强度计算
|
||
```python
|
||
# 添加指标冲突检测
|
||
def _check_indicator_conflict(self, indicators: Dict) -> int:
|
||
"""检测指标冲突,返回冲突分数"""
|
||
conflict_score = 0
|
||
|
||
# RSI与MACD冲突
|
||
if indicators.get('rsi', 50) > 70 and indicators.get('macd_histogram', 0) < 0:
|
||
conflict_score += 2 # RSI超买但MACD死叉
|
||
|
||
if indicators.get('rsi', 50) < 30 and indicators.get('macd_histogram', 0) > 0:
|
||
conflict_score += 2 # RSI超卖但MACD金叉
|
||
|
||
return conflict_score
|
||
|
||
# 在信号强度计算中减去冲突分数
|
||
signal_strength -= conflict_score
|
||
```
|
||
|
||
#### 建议2:改进4H趋势判断
|
||
```python
|
||
# 使用多个指标判断4H趋势
|
||
def _judge_trend_4h(self, symbol_info: Dict) -> str:
|
||
"""使用多个指标判断4H趋势"""
|
||
price_4h = symbol_info.get('price_4h')
|
||
ema20_4h = symbol_info.get('ema20_4h')
|
||
ema50_4h = symbol_info.get('ema50_4h')
|
||
macd_4h = symbol_info.get('macd_4h')
|
||
|
||
signals = []
|
||
|
||
# EMA20 vs 价格
|
||
if price_4h > ema20_4h:
|
||
signals.append('up')
|
||
elif price_4h < ema20_4h:
|
||
signals.append('down')
|
||
|
||
# EMA20 vs EMA50
|
||
if ema20_4h > ema50_4h:
|
||
signals.append('up')
|
||
elif ema20_4h < ema50_4h:
|
||
signals.append('down')
|
||
|
||
# MACD
|
||
if macd_4h and macd_4h.get('histogram', 0) > 0:
|
||
signals.append('up')
|
||
elif macd_4h and macd_4h.get('histogram', 0) < 0:
|
||
signals.append('down')
|
||
|
||
# 多数投票
|
||
up_count = signals.count('up')
|
||
down_count = signals.count('down')
|
||
|
||
if up_count > down_count:
|
||
return 'up'
|
||
elif down_count > up_count:
|
||
return 'down'
|
||
else:
|
||
return 'neutral'
|
||
```
|
||
|
||
#### 建议3:调整移动止损参数
|
||
```python
|
||
# 建议的移动止损参数
|
||
TRAILING_STOP_ACTIVATION = 0.05 # 盈利5% of margin后激活(更保守)
|
||
TRAILING_STOP_PROTECT = 0.03 # 保护3% of margin利润(更合理)
|
||
```
|
||
|
||
### 3.3 性能优化
|
||
|
||
#### 建议1:使用组合流(Combined Stream)
|
||
```python
|
||
# 使用币安组合流,一个连接监控多个交易对
|
||
# wss://fstream.binance.com/stream?streams=btcusdt@ticker/ethusdt@ticker/...
|
||
ws_url = f"wss://fstream.binance.com/stream?streams={'/'.join([f'{s.lower()}@ticker' for s in symbols])}"
|
||
```
|
||
|
||
#### 建议2:减少定时检查频率
|
||
```python
|
||
# 如果WebSocket正常工作,减少定时检查频率
|
||
# 或者只在WebSocket断开时启用定时检查
|
||
if not self._websocket_connected:
|
||
await self.check_stop_loss_take_profit()
|
||
```
|
||
|
||
### 3.4 功能增强
|
||
|
||
#### 建议1:添加策略回测
|
||
```python
|
||
class StrategyBacktester:
|
||
"""策略回测器"""
|
||
async def backtest(self, start_date: str, end_date: str, initial_balance: float):
|
||
"""回测策略"""
|
||
# 加载历史数据
|
||
# 模拟交易
|
||
# 计算收益、胜率、最大回撤等
|
||
pass
|
||
```
|
||
|
||
#### 建议2:添加交易统计
|
||
```python
|
||
class TradeStatistics:
|
||
"""交易统计"""
|
||
def get_statistics(self, start_date: str, end_date: str):
|
||
"""获取交易统计"""
|
||
return {
|
||
'total_trades': 0,
|
||
'win_rate': 0.0,
|
||
'profit_factor': 0.0,
|
||
'avg_win': 0.0,
|
||
'avg_loss': 0.0,
|
||
'max_drawdown': 0.0,
|
||
'by_strategy': {
|
||
'mean_reversion': {...},
|
||
'trend_following': {...}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 四、优先级建议
|
||
|
||
### 高优先级(立即修复)
|
||
1. ✅ **修复部分止盈逻辑重复** - 代码质量问题
|
||
2. ✅ **修复移动止损计算** - 可能影响盈亏
|
||
3. ✅ **修复分步止盈后盈亏计算** - 统计准确性
|
||
|
||
### 中优先级(近期优化)
|
||
4. ⚠️ **改进信号强度计算** - 提高策略质量
|
||
5. ⚠️ **改进4H趋势判断** - 提高策略质量
|
||
6. ⚠️ **调整移动止损参数** - 优化风险控制
|
||
|
||
### 低优先级(长期优化)
|
||
7. 📝 **添加策略回测** - 功能增强
|
||
8. 📝 **添加交易统计** - 功能增强
|
||
9. 📝 **优化WebSocket连接** - 性能优化
|
||
|
||
## 五、总结
|
||
|
||
当前策略架构整体合理,采用了多周期共振、技术指标确认、风险管理等成熟方法。但存在一些代码质量和逻辑问题需要修复。
|
||
|
||
**核心优势**:
|
||
- 多周期共振策略,提高胜率
|
||
- 基于保证金的止损止盈,更合理
|
||
- WebSocket实时监控,响应及时
|
||
- 分步止盈策略,平衡风险收益
|
||
|
||
**主要问题**:
|
||
- 代码重复和逻辑错误
|
||
- 移动止损计算可能不准确
|
||
- 缺少策略验证和统计
|
||
|
||
**建议行动**:
|
||
1. 先修复高优先级问题(代码质量)
|
||
2. 然后优化策略逻辑(提高胜率)
|
||
3. 最后添加回测和统计功能(长期优化)
|