This commit is contained in:
薇薇安 2026-01-15 11:19:23 +08:00
parent 209a5cd376
commit 9983a892bd
9 changed files with 789 additions and 111 deletions

231
CURRENT_STRATEGY.md Normal file
View File

@ -0,0 +1,231 @@
# 当前交易策略方案文档
## 一、策略概述
当前系统采用基于技术指标的自适应交易策略,结合均值回归和趋势跟踪两种模式,根据市场状态自动切换。
### 核心特点
- **自适应策略**:根据市场状态(趋势/震荡)自动选择策略
- **技术指标过滤**使用RSI、MACD、布林带、EMA等多指标确认
- **信号强度要求**:信号强度 >= 5/10 才执行交易
- **时间段差异化**:晚间激进,白天平衡
## 二、当前配置参数
### 仓位控制
- **单笔最大仓位**5% (MAX_POSITION_PERCENT: 0.05)
- **总仓位上限**30% (MAX_TOTAL_POSITION_PERCENT: 0.30)
- **单笔最小仓位**1% (MIN_POSITION_PERCENT: 0.01)
### 市场扫描
- **扫描间隔**1小时 (SCAN_INTERVAL: 3600秒)
- **扫描交易对数量**500个 (MAX_SCAN_SYMBOLS: 500)
- **处理交易对数量**10个 (TOP_N_SYMBOLS: 10)
- **最小涨跌幅阈值**2% (MIN_CHANGE_PERCENT: 2.0)
- **最小24小时成交量**1000万USDT (MIN_VOLUME_24H: 10000000)
### 风险控制
- **止损**3% (STOP_LOSS_PERCENT: 0.03)
- **止盈**5% (TAKE_PROFIT_PERCENT: 0.05)
- **杠杆倍数**10倍 (LEVERAGE: 10)
- **移动止损**:启用 (USE_TRAILING_STOP: True)
- **移动止损激活阈值**1% (TRAILING_STOP_ACTIVATION: 0.01)
- **移动止损保护利润**1% (TRAILING_STOP_PROTECT: 0.01)
### 策略参数
- **最小信号强度**5/10 (MIN_SIGNAL_STRENGTH: 5)
- **K线周期**1小时 (KLINE_INTERVAL: 1h)
- **主周期**1小时 (PRIMARY_INTERVAL: 1h)
- **确认周期**4小时 (CONFIRM_INTERVAL: 4h)
- **入场周期**15分钟 (ENTRY_INTERVAL: 15m)
## 三、策略逻辑
### 1. 市场扫描
- 每小时扫描500个USDT交易对
- 筛选涨跌幅 >= 2% 且成交量 >= 1000万USDT的交易对
- 计算技术指标RSI、MACD、布林带、EMA等
- 按信号得分排序选择前10个进行详细分析
### 2. 市场状态判断
- **震荡市场 (ranging)**:使用均值回归策略
- **趋势市场 (trending)**:使用趋势跟踪策略
### 3. 交易信号生成
#### 均值回归策略(震荡市场)
- **做多信号**
- RSI < 30超卖
- 价格触及布林带下轨
- **做空信号**
- RSI > 70超买
- 价格触及布林带上轨
#### 趋势跟踪策略(趋势市场)
- **做多信号**
- MACD金叉MACD > Signal 且 Histogram > 0
- 价格 > EMA20 > EMA50上升趋势
- **做空信号**
- MACD死叉MACD < Signal Histogram < 0
- 价格 < EMA20 < EMA50下降趋势
#### 信号强度计算
- 基础信号2-4分
- 多指标确认:+2分
- 要求信号强度 >= 5/10 才执行交易
### 4. 风险控制
- 仓位大小:根据账户余额和涨跌幅动态计算
- 止损止盈固定百分比止损3%止盈5%
- 移动止损盈利1%后激活保护1%利润
- 持仓监控WebSocket实时监控 + 定时检查5分钟
## 四、时间段策略
### 晚间激进策略20:00-02:00 UTC+8
- **特点**:市场波动大,机会多
- **建议配置**
- MAX_SCAN_SYMBOLS: 350-400增加扫描范围
- TOP_N_SYMBOLS: 15-20处理更多交易对
- MIN_SIGNAL_STRENGTH: 3-4降低信号强度要求捕捉更多机会
- SCAN_INTERVAL: 1800-3600秒30分钟-1小时
### 白天平衡策略02:00-20:00 UTC+8
- **特点**:市场相对平稳,注重信号质量
- **建议配置**
- MAX_SCAN_SYMBOLS: 250-300平衡扫描范围
- TOP_N_SYMBOLS: 10-12选择优质机会
- MIN_SIGNAL_STRENGTH: 5-6提高信号强度要求
- SCAN_INTERVAL: 3600秒1小时
## 五、运行情况分析
### 统计数据
- **总交易单数**53单
- **当前胜率**40%
- **目标胜率**50-60%
### 胜率分析
#### 当前胜率偏低的原因
1. **信号强度要求可能偏低**
- 当前MIN_SIGNAL_STRENGTH: 5
- 可能接受了过多中等强度的信号
2. **时间段策略未完全实现**
- 晚间激进策略可能增加了低质量交易
- 白天平衡策略的信号强度要求可能还不够严格
3. **市场环境判断可能不准确**
- 震荡市场和趋势市场的判断可能不够准确
- 导致使用了错误的策略
4. **止损止盈比例**
- 止损3%止盈5%盈亏比约1.67:1
- 如果胜率低于37.5%,整体会亏损
## 六、改进建议
### 1. 提高信号强度要求
**建议**将MIN_SIGNAL_STRENGTH从5提高到6-7
- **理由**:减少假信号,提高入场质量
- **预期效果**胜率提升5-10%,但交易频率可能下降
### 2. 优化时间段策略
**建议**:实现自动时间段切换
- **晚间20:00-02:00**
- MIN_SIGNAL_STRENGTH: 4激进
- TOP_N_SYMBOLS: 15-18
- **白天02:00-20:00**
- MIN_SIGNAL_STRENGTH: 6-7保守
- TOP_N_SYMBOLS: 8-10
### 3. 优化止损止盈比例
**建议**:调整止损止盈比例,提高盈亏比
- **方案A**止损2.5%止盈5%盈亏比2:1
- **方案B**止损3%止盈6%盈亏比2:1
- **预期效果**即使胜率40%盈亏比2:1也能盈利
### 4. 加强市场状态判断
**建议**
- 使用更多指标判断市场状态
- 增加市场状态的确认机制
- 在不确定的市场状态下降低仓位或暂停交易
### 5. 增加过滤条件
**建议**
- 增加成交量确认(确保有足够的流动性)
- 增加波动率过滤(避免在极端波动时交易)
- 增加相关性检查(避免同时持有高度相关的币种)
### 6. 优化移动止损
**建议**
- 提高移动止损激活阈值到2%
- 增加移动止损保护利润到1.5-2%
- **预期效果**:更好地保护利润,减少盈利变亏损
## 七、预期改进效果
### 短期目标1-2周
- **胜率目标**45-50%
- **改进措施**
- 提高MIN_SIGNAL_STRENGTH到6
- 优化止损止盈比例到2:1
- 加强市场状态判断
### 中期目标1个月
- **胜率目标**50-55%
- **改进措施**
- 实现时间段自动切换
- 优化移动止损参数
- 增加更多过滤条件
### 长期目标3个月
- **胜率目标**55-60%
- **改进措施**
- 建立回测系统
- 使用机器学习优化信号权重
- 多时间周期确认
## 八、监控指标
### 关键指标
1. **胜率**:目标 > 50%
2. **盈亏比**:目标 > 1.5:1
3. **平均盈利/亏损**:确保平均盈利 > 平均亏损
4. **交易频率**每天3-10单根据市场情况
5. **持仓数量**同时持仓3-8个
### 需要关注的日志
- 信号强度分布
- 市场状态分布(趋势/震荡)
- 移动止损激活情况
- 止损/止盈触发比例
## 九、风险提示
1. **胜率40%偏低**:如果盈亏比不够高,整体可能亏损
2. **时间段策略**:需要根据实际市场情况调整,不能盲目激进
3. **市场环境变化**:策略需要适应不同的市场环境
4. **参数调整**:不要频繁大幅调整参数,建议渐进式优化
## 十、下一步行动
1. **立即执行**
- 提高MIN_SIGNAL_STRENGTH到6
- 调整止损止盈比例到2:1止损2.5%止盈5%
2. **本周完成**
- 实现时间段自动切换功能
- 优化移动止损参数
3. **本月完成**
- 加强市场状态判断
- 增加更多过滤条件
- 建立数据分析和回测系统
---
**文档更新时间**2024年
**策略版本**v1.0
**下次评估时间**运行100单后重新评估

View File

@ -65,7 +65,7 @@ async def get_trades(
如果同时提供了 period start_date/end_dateperiod 优先级更高
"""
try:
logger.info(f"获取交易记录请求: start_date={start_date}, end_date={end_date}, period={period}, symbol={symbol}, status={status}, limit={limit}")
logger.info(f"获取交易记录请求: start_date={start_date}, end_date={end_date}, period={period}, symbol={symbol}, status={status}, limit={limit}, trade_type={trade_type}, exit_reason={exit_reason}")
# 如果提供了 period使用快速时间段筛选
if period:
period_start, period_end = get_date_range(period)
@ -80,7 +80,7 @@ async def get_trades(
if end_date and len(end_date) == 10: # YYYY-MM-DD
end_date = f"{end_date} 23:59:59"
trades = Trade.get_all(start_date, end_date, symbol, status)
trades = Trade.get_all(start_date, end_date, symbol, status, trade_type, exit_reason)
logger.info(f"查询到 {len(trades)} 条交易记录")
# 格式化交易记录,添加平仓类型的中文显示

View File

@ -80,6 +80,8 @@ CREATE TABLE IF NOT EXISTS `trading_signals` (
INDEX `idx_executed` (`executed`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='交易信号表';
-- 初始化默认配置
INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `category`, `description`) VALUES
-- 仓位控制
@ -108,7 +110,7 @@ INSERT INTO `trading_config` (`config_key`, `config_value`, `config_type`, `cate
('MIN_VOLATILITY', '0.02', 'number', 'scan', '最小波动率2%'),
-- 高胜率策略参数
('MIN_SIGNAL_STRENGTH', '5', 'number', 'strategy', '最小信号强度0-10'),
('MIN_SIGNAL_STRENGTH', '7', 'number', 'strategy', '最小信号强度0-10已提升至7以提高入场质量'),
('LEVERAGE', '10', 'number', 'strategy', '杠杆倍数'),
('USE_TRAILING_STOP', 'true', 'boolean', 'strategy', '是否使用移动止损'),
('TRAILING_STOP_ACTIVATION', '0.01', 'number', 'strategy', '移动止损激活阈值盈利1%后激活)'),

138
newplan20260115.md Normal file
View File

@ -0,0 +1,138 @@
核心诊断:盈利公式与当前瓶颈
盈利的核心公式是:期望收益 = 胜率 × 平均盈利 - (1-胜率) × 平均亏损。
您当前配置是胜率40%盈亏比约1.67:1止损3%止盈5%)。
代入公式0.4*5 - 0.6*3 = 2 - 1.8 = 0.2%(每笔交易的期望收益为正,但非常微薄,易被滑点、手续费侵蚀)。
主要瓶颈在于:
胜率偏低40%的胜率对策略的容错率要求极高。
盈亏比不具优势1.67:1的盈亏比在40%胜率下仅能勉强保本。
“激进”与“平衡”时段的定义可能过于时间驱动,而非市场驱动。
系统性优化方案(从高优先级到低优先级)
第一阶段:立即实施(提高单笔交易质量)
严格强化入场信号(提升胜率最直接的方法)
多时间周期共振您已有主周期1h和确认周期4h。应严格执行 “大周期定方向,小周期找点位”。
做多4H趋势向上如价格 > 4H EMA20仅在1H和15min上寻找做多信号。绝对禁止在4H下跌趋势中做1H级别的“反弹多”。
做空:同理。这能极大过滤逆势交易,提升胜率。
增加量价确认:
买入信号时要求入场K线或前一根的成交量显著高于近期均量确认买盘力量。
突破布林带时要求K线实体饱满而非长影线触及。
将 MIN_SIGNAL_STRENGTH 从5提升至7。这看似激进但结合多周期共振能确保只有最强、最清晰的信号才被执行。预期牺牲20-30%的交易机会但目标是提升单笔交易胜率10%以上。
优化风险回报结构(提升盈亏比)
放弃固定止盈止损,采用 基于技术结构的动态风控。
止损:设置在关键支撑/阻力位、布林带外轨或前高/前低之外 + 一定缓冲。例如做多时止损放在近期波段低点下方0.5-1%。这通常比固定的3%更合理。
止盈:采用 分步止盈。
第一目标保守近期阻力位或盈亏比1:1的位置了结50%仓位。
第二目标(激进):更远的技术位(如趋势线、前高),让剩余仓位配合移动止损博取更大利润。
此举目标:将平均盈亏比提升至 2.5:1 甚至 3:1。
第二阶段:近期优化(提升系统适应性与仓位效率)
重构“时间段策略”为“市场波动率策略”
时间本身不产生机会波动率才是。建议根据平均真实波幅ATR或布林带带宽来定义“激进”与“保守”模式。
高波动率模式(激进):当波动率高于近期均值时。
仓位系数 = 0.5 (降低标准仓位的一半,以应对更大风险)。
MIN_SIGNAL_STRENGTH 可适当降低至6但必须配合更宽的止损如基于ATR的2倍
低波动率模式(保守):当波动率低于近期均值时。
仓位系数 = 1.0 (标准仓位)。
MIN_SIGNAL_STRENGTH = 7 (信号要求最高)。
极度波动模式(暂停):当波动率突破极端阈值(如+3标准差暂停开新仓仅管理现有持仓。
实施基于凯利公式或固定分数法的动态仓位管理
当前固定的5%仓位过于僵化。应根据交易信号的强度和账户当前状态动态调整。
简化版:单笔风险 = 账户总资金的0.5% - 1%。
假设止损距离是2%,那么仓位大小就是 (账户资金 * 0.5%) / (入场价 * 2%)。
优势:无论交易什么币种,每笔交易的最大亏损是固定的,真正控制了风险。
第三阶段:中长期建设(构建护城河)
增加“策略失效”监控与熔断机制
设定一个连续亏损次数如5次 或单日最大回撤比例如3% 的阈值。一旦触发,系统自动切换至“观察模式”或“极小仓位模式”,防止情绪化决策下的恶性循环。
建立简易但必须的回测与统计分析框架
记录每一笔交易的:入场理由(趋势/震荡)、信号强度、使用指标、持仓时间、结果。
定期(如每周)分析:
哪种市场状态下胜率高?(趋势强?震荡市?)
哪个技术指标组合的预测力最强是MACD金叉+放量还是RSI超卖+布林带下轨?)
据此动态调整信号权重,让策略自我进化。
优化后的预期与监控重点
预期效果:
短期1-2周通过强化信号多周期共振强度7 和动态风控目标将胜率稳定至45%-50%盈亏比提升至2.5:1。
中期1个月引入波动率仓位管理和分步止盈目标使策略在不同市场环境下回撤可控月化收益率曲线更加平滑。
长期:通过数据分析驱动策略微调,形成稳定正期望的交易系统。
新的关键监控指标:
期望收益核心中的核心必须为正且大于0.5%。
风险调整后收益:如夏普比率。
最大连续亏损次数/金额:衡量策略的逆境承受力。
不同市场状态下的胜率与盈亏比:检验策略的适应性。
信号强度与胜率的相关性:验证信号系统的有效性。
总结:行动路线图
本周:
立即:将 MIN_SIGNAL_STRENGTH 提升至 7。
立即:实施 多时间周期共振入场规则4H定方向
立即:将止损改为 基于支撑/阻力的动态止损。
设计:分步止盈和移动止损逻辑。
下周:
引入 基于ATR的波动率仓位管理。
实施 基于固定百分比风险的仓位计算。
本月内:
建立交易日志数据库。
建立 策略熔断机制连续亏损5次暂停
完成首次数据分析报告。
交易系统的优化是一场“精益求精”的工程。您的文档已有一个极好的起点。请务必记住每一次调整最好只改变1-2个变量并观察足够样本至少20-30笔交易后再做下一次调整这样才能清晰归因。

View File

@ -176,7 +176,7 @@ def _get_trading_config():
'ENTRY_INTERVAL': '15m',
'MIN_VOLUME_24H': 10000000,
'MIN_VOLATILITY': 0.02,
'MIN_SIGNAL_STRENGTH': 5,
'MIN_SIGNAL_STRENGTH': 7, # 提升至7以提高入场质量减少假信号
'LEVERAGE': 10,
'USE_TRAILING_STOP': True,
'TRAILING_STOP_ACTIVATION': 0.01,

View File

@ -194,11 +194,22 @@ class MarketScanner:
if len(klines) < 2:
return None
# 提取价格数据
# 获取4H周期数据用于多周期共振检查
confirm_interval = config.TRADING_CONFIG.get('CONFIRM_INTERVAL', '4h')
klines_4h = await self.client.get_klines(
symbol=symbol,
interval=confirm_interval,
limit=50 # 获取4H周期数据
)
# 提取价格数据(主周期)
close_prices = [float(k[4]) for k in klines] # 收盘价
high_prices = [float(k[2]) for k in klines] # 最高价
low_prices = [float(k[3]) for k in klines] # 最低价
# 提取4H周期价格数据
close_prices_4h = [float(k[4]) for k in klines_4h] if len(klines_4h) >= 2 else close_prices
# 计算涨跌幅(基于主周期)
current_price = close_prices[-1]
prev_price = close_prices[-2] if len(close_prices) >= 2 else close_prices[0]
@ -216,6 +227,9 @@ class MarketScanner:
ema20 = TechnicalIndicators.calculate_ema(close_prices, period=20)
ema50 = TechnicalIndicators.calculate_ema(close_prices, period=50)
# 计算4H周期的EMA20用于多周期共振检查
ema20_4h = TechnicalIndicators.calculate_ema(close_prices_4h, period=20) if len(close_prices_4h) >= 20 else None
# 判断市场状态
market_regime = TechnicalIndicators.detect_market_regime(close_prices)
@ -267,9 +281,12 @@ class MarketScanner:
'atr': atr,
'ema20': ema20,
'ema50': ema50,
'ema20_4h': ema20_4h, # 4H周期EMA20用于多周期共振
'price_4h': close_prices_4h[-1] if len(close_prices_4h) > 0 else current_price, # 4H周期当前价格
'marketRegime': market_regime,
'signalScore': signal_score,
'klines': klines[-10:] # 保留最近10根K线
'klines': klines[-10:], # 保留最近10根K线
'klines_4h': klines_4h[-10:] if len(klines_4h) >= 10 else klines_4h # 保留最近10根4H K线
}
except Exception as e:
logger.debug(f"获取 {symbol} 数据失败: {e}")

View File

@ -67,7 +67,9 @@ class PositionManager:
leverage: int = 10,
trade_direction: Optional[str] = None,
entry_reason: str = '',
atr: Optional[float] = None
atr: Optional[float] = None,
klines: Optional[List] = None,
bollinger: Optional[Dict] = None
) -> Optional[Dict]:
"""
开仓
@ -118,22 +120,52 @@ class PositionManager:
entry_price = ticker['price']
# 计算动态止损止盈使用ATR或固定比例
if atr and atr > 0:
# 使用ATR计算动态止损2倍ATR
atr_stop_loss_pct = (atr * 2) / entry_price
# 限制在合理范围内1%-5%
atr_stop_loss_pct = max(0.01, min(0.05, atr_stop_loss_pct))
stop_loss_price = self.risk_manager.get_stop_loss_price(
entry_price, side, stop_loss_pct=atr_stop_loss_pct
# 获取K线数据用于动态止损计算从symbol_info中获取如果可用
klines = None
bollinger = None
if 'klines' in locals() or 'symbol_info' in locals():
# 尝试从外部传入的symbol_info获取
pass
# 计算基于支撑/阻力的动态止损
# 优先使用技术结构(支撑/阻力位、布林带)
# 如果无法获取K线数据回退到ATR或固定止损
if not klines:
# 如果没有传入K线数据尝试获取
try:
primary_interval = config.TRADING_CONFIG.get('PRIMARY_INTERVAL', '1h')
klines_data = await self.client.get_klines(
symbol=symbol,
interval=primary_interval,
limit=20 # 获取最近20根K线用于计算支撑/阻力
)
# 止盈为止损的1.5-2倍
take_profit_pct = atr_stop_loss_pct * 1.8
klines = klines_data if len(klines_data) >= 10 else None
except Exception as e:
logger.debug(f"获取K线数据失败使用固定止损: {e}")
klines = None
# 使用基于支撑/阻力的动态止损
if klines or bollinger or atr:
stop_loss_price = self.risk_manager.get_stop_loss_price(
entry_price, side,
klines=klines,
bollinger=bollinger,
atr=atr
)
# 计算动态止损百分比(用于计算止盈)
if side == 'BUY':
stop_loss_pct = (entry_price - stop_loss_price) / entry_price
else:
stop_loss_pct = (stop_loss_price - entry_price) / entry_price
# 止盈为止损的2-2.5倍(提高盈亏比)
take_profit_pct = stop_loss_pct * 2.5
take_profit_price = self.risk_manager.get_take_profit_price(
entry_price, side, take_profit_pct=take_profit_pct
)
else:
# 使用固定止损止盈
# 回退到固定止损止盈
stop_loss_price = self.risk_manager.get_stop_loss_price(entry_price, side)
take_profit_price = self.risk_manager.get_take_profit_price(entry_price, side)
@ -170,7 +202,17 @@ class PositionManager:
elif not Trade:
logger.warning(f"Trade模型未导入无法保存 {symbol} 交易记录")
# 记录持仓信息(包含动态止损止盈)
# 计算分步止盈价格
# 第一目标盈亏比1:1保守了结50%仓位)
if side == 'BUY':
take_profit_1 = entry_price + (entry_price - stop_loss_price) # 盈亏比1:1
else:
take_profit_1 = entry_price - (stop_loss_price - entry_price) # 盈亏比1:1
# 第二目标原始止盈价激进剩余50%仓位)
take_profit_2 = take_profit_price
# 记录持仓信息(包含动态止损止盈和分步止盈)
position_info = {
'symbol': symbol,
'side': side,
@ -180,7 +222,11 @@ class PositionManager:
'orderId': order.get('orderId'),
'tradeId': trade_id, # 数据库交易ID
'stopLoss': stop_loss_price,
'takeProfit': take_profit_price,
'takeProfit': take_profit_price, # 保留原始止盈价(第二目标)
'takeProfit1': take_profit_1, # 第一目标盈亏比1:1了结50%
'takeProfit2': take_profit_2, # 第二目标原始止盈价剩余50%
'partialProfitTaken': False, # 是否已部分止盈
'remainingQuantity': quantity, # 剩余仓位数量
'initialStopLoss': stop_loss_price, # 初始止损(用于移动止损)
'leverage': leverage,
'entryReason': entry_reason,
@ -537,14 +583,126 @@ class PositionManager:
closed_positions.append(symbol)
continue
# 检查止盈
take_profit = position_info['takeProfit']
# 检查分步止盈
take_profit_1 = position_info.get('takeProfit1') # 第一目标盈亏比1:1
take_profit_2 = position_info.get('takeProfit2', position_info.get('takeProfit')) # 第二目标
partial_profit_taken = position_info.get('partialProfitTaken', False)
remaining_quantity = position_info.get('remainingQuantity', quantity)
# 第一目标盈亏比1:1了结50%仓位
if not partial_profit_taken:
if position_info['side'] == 'BUY' and current_price >= take_profit_1:
logger.info(
f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} >= {take_profit_1:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
# 部分平仓50%
partial_quantity = quantity * 0.5
try:
# 部分平仓
close_side = 'SELL' if position_info['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'] = remaining_quantity - partial_quantity
logger.info(
f"{symbol} 部分止盈成功: 平仓{partial_quantity:.4f},剩余{position_info['remainingQuantity']:.4f}"
)
# 更新止损为成本价(保护剩余仓位)
position_info['stopLoss'] = entry_price
position_info['trailingStopActivated'] = True
logger.info(f"{symbol} 剩余仓位止损移至成本价,配合移动止损博取更大利润")
except Exception as e:
logger.error(f"{symbol} 部分止盈失败: {e}")
elif position_info['side'] == 'SELL' and current_price <= take_profit_1:
logger.info(
f"{symbol} 触发第一目标止盈盈亏比1:1: {current_price:.4f} <= {take_profit_1:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
# 部分平仓50%
partial_quantity = quantity * 0.5
try:
# 部分平仓
partial_order = await self.client.place_order(
symbol=symbol,
side='BUY', # 做空平仓用买入
quantity=partial_quantity,
order_type='MARKET'
)
if partial_order:
position_info['partialProfitTaken'] = True
position_info['remainingQuantity'] = remaining_quantity - partial_quantity
logger.info(
f"{symbol} 部分止盈成功: 平仓{partial_quantity:.4f},剩余{position_info['remainingQuantity']:.4f}"
)
# 更新止损为成本价(保护剩余仓位)
position_info['stopLoss'] = entry_price
position_info['trailingStopActivated'] = True
logger.info(f"{symbol} 剩余仓位止损移至成本价,配合移动止损博取更大利润")
except Exception as e:
logger.error(f"{symbol} 部分止盈失败: {e}")
# 第二目标:原始止盈价,平掉剩余仓位
if partial_profit_taken:
if position_info['side'] == 'BUY' and current_price >= take_profit_2:
logger.info(
f"{symbol} 触发第二目标止盈: {current_price:.4f} >= {take_profit_2:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
exit_reason = 'take_profit'
# 更新数据库
if DB_AVAILABLE:
trade_id = position_info.get('tradeId')
if trade_id:
try:
Trade.update_exit(
trade_id=trade_id,
exit_price=current_price,
exit_reason=exit_reason,
pnl=pnl_percent * entry_price * quantity / 100,
pnl_percent=pnl_percent
)
except Exception as e:
logger.warning(f"更新止盈记录失败: {e}")
if await self.close_position(symbol, reason=exit_reason):
closed_positions.append(symbol)
continue
elif position_info['side'] == 'SELL' and current_price <= take_profit_2:
logger.info(
f"{symbol} 触发第二目标止盈: {current_price:.4f} <= {take_profit_2:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
exit_reason = 'take_profit'
# 更新数据库
if DB_AVAILABLE:
trade_id = position_info.get('tradeId')
if trade_id:
try:
Trade.update_exit(
trade_id=trade_id,
exit_price=current_price,
exit_reason=exit_reason,
pnl=pnl_percent * entry_price * quantity / 100,
pnl_percent=pnl_percent
)
except Exception as e:
logger.warning(f"更新止盈记录失败: {e}")
if await self.close_position(symbol, reason=exit_reason):
closed_positions.append(symbol)
continue
else:
# 如果未部分止盈,但达到第二目标,直接全部平仓
take_profit = position_info.get('takeProfit')
if position_info['side'] == 'BUY' and current_price >= take_profit:
logger.info(
f"{symbol} 触发止盈: {current_price:.4f} >= {take_profit:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
# 确定平仓原因
exit_reason = 'take_profit'
# 更新数据库
if DB_AVAILABLE:
@ -569,7 +727,6 @@ class PositionManager:
f"{symbol} 触发止盈: {current_price:.4f} <= {take_profit:.4f} "
f"(盈亏: {pnl_percent:.2f}%)"
)
# 确定平仓原因
exit_reason = 'take_profit'
# 更新数据库
if DB_AVAILABLE:

View File

@ -347,19 +347,83 @@ class RiskManager:
self,
entry_price: float,
side: str,
stop_loss_pct: Optional[float] = None
stop_loss_pct: Optional[float] = None,
klines: Optional[List] = None,
bollinger: Optional[Dict] = None,
atr: Optional[float] = None
) -> float:
"""
计算止损价格
计算止损价格基于支撑/阻力的动态止损
Args:
entry_price: 入场价格
side: 方向 'BUY' 'SELL'
stop_loss_pct: 止损百分比如果为None则使用配置值
klines: K线数据用于计算支撑/阻力位
bollinger: 布林带数据用于计算动态止损
atr: 平均真实波幅用于计算动态止损
Returns:
止损价格
"""
# 优先使用基于技术结构的动态止损
if klines and len(klines) >= 10:
# 计算支撑/阻力位
low_prices = [float(k[3]) for k in klines[-20:]] # 最近20根K线的最低价
high_prices = [float(k[2]) for k in klines[-20:]] # 最近20根K线的最高价
if side == 'BUY': # 做多,止损放在支撑位下方
# 找到近期波段低点
recent_low = min(low_prices)
# 止损放在低点下方0.5-1%
buffer = entry_price * 0.005 # 0.5%缓冲
dynamic_stop = recent_low - buffer
# 如果布林带可用,也可以考虑布林带下轨
if bollinger and bollinger.get('lower'):
bollinger_stop = bollinger['lower'] * 0.995 # 布林带下轨下方0.5%
dynamic_stop = max(dynamic_stop, bollinger_stop)
# 确保止损不超过固定止损范围1%-5%
fixed_stop_pct = stop_loss_pct or self.config['STOP_LOSS_PERCENT']
max_stop = entry_price * (1 - 0.01) # 最多1%止损
min_stop = entry_price * (1 - 0.05) # 最少5%止损(极端情况)
dynamic_stop = max(min_stop, min(max_stop, dynamic_stop))
logger.info(
f"动态止损计算 (BUY): 入场价={entry_price:.4f}, "
f"近期低点={recent_low:.4f}, 动态止损={dynamic_stop:.4f}, "
f"止损比例={((entry_price - dynamic_stop) / entry_price * 100):.2f}%"
)
return dynamic_stop
else: # 做空,止损放在阻力位上方
# 找到近期波段高点
recent_high = max(high_prices)
# 止损放在高点上方0.5-1%
buffer = entry_price * 0.005 # 0.5%缓冲
dynamic_stop = recent_high + buffer
# 如果布林带可用,也可以考虑布林带上轨
if bollinger and bollinger.get('upper'):
bollinger_stop = bollinger['upper'] * 1.005 # 布林带上轨上方0.5%
dynamic_stop = min(dynamic_stop, bollinger_stop)
# 确保止损不超过固定止损范围1%-5%
fixed_stop_pct = stop_loss_pct or self.config['STOP_LOSS_PERCENT']
min_stop = entry_price * (1 + 0.01) # 最少1%止损
max_stop = entry_price * (1 + 0.05) # 最多5%止损(极端情况)
dynamic_stop = min(max_stop, max(min_stop, dynamic_stop))
logger.info(
f"动态止损计算 (SELL): 入场价={entry_price:.4f}, "
f"近期高点={recent_high:.4f}, 动态止损={dynamic_stop:.4f}, "
f"止损比例={((dynamic_stop - entry_price) / entry_price * 100):.2f}%"
)
return dynamic_stop
# 回退到固定百分比止损
stop_loss_percent = stop_loss_pct or self.config['STOP_LOSS_PERCENT']
if side == 'BUY': # 做多,止损价低于入场价

View File

@ -149,7 +149,9 @@ class TradingStrategy:
leverage=config.TRADING_CONFIG.get('LEVERAGE', 10),
trade_direction=trade_direction,
entry_reason=entry_reason,
atr=symbol_info.get('atr')
atr=symbol_info.get('atr'),
klines=symbol_info.get('klines'), # 传递K线数据用于动态止损
bollinger=symbol_info.get('bollinger') # 传递布林带数据用于动态止损
)
if position:
@ -261,6 +263,7 @@ class TradingStrategy:
async def _analyze_trade_signal(self, symbol_info: Dict) -> Dict:
"""
使用技术指标分析交易信号高胜率策略
实施多周期共振4H定方向1H和15min找点位
Args:
symbol_info: 交易对信息包含技术指标
@ -277,68 +280,117 @@ class TradingStrategy:
ema20 = symbol_info.get('ema20')
ema50 = symbol_info.get('ema50')
# 多周期共振检查4H定方向
price_4h = symbol_info.get('price_4h', current_price)
ema20_4h = symbol_info.get('ema20_4h')
# 判断4H周期趋势方向
trend_4h = None # 'up', 'down', 'neutral'
if ema20_4h is not None:
if price_4h > ema20_4h:
trend_4h = 'up'
elif price_4h < ema20_4h:
trend_4h = 'down'
else:
trend_4h = 'neutral'
signal_strength = 0
reasons = []
direction = None
# 多周期共振检查4H定方向禁止逆势交易
if trend_4h == 'up':
# 4H趋势向上只允许做多信号
logger.debug(f"{symbol} 4H趋势向上只允许做多信号")
elif trend_4h == 'down':
# 4H趋势向下只允许做空信号
logger.debug(f"{symbol} 4H趋势向下只允许做空信号")
elif trend_4h is None:
# 无法判断4H趋势记录警告
logger.warning(f"{symbol} 无法判断4H趋势可能影响信号质量")
# 策略1均值回归震荡市场高胜率
if market_regime == 'ranging':
# RSI超卖做多信号
# RSI超卖做多信号需4H趋势向上或中性
if rsi and rsi < 30:
if trend_4h in ('up', 'neutral', None):
signal_strength += 4
reasons.append(f"RSI超卖({rsi:.1f})")
if direction is None:
direction = 'BUY'
else:
reasons.append(f"RSI超卖但4H趋势向下禁止逆势做多")
# RSI超买做空信号
# RSI超买做空信号需4H趋势向下或中性
elif rsi and rsi > 70:
if trend_4h in ('down', 'neutral', None):
signal_strength += 4
reasons.append(f"RSI超买({rsi:.1f})")
if direction is None:
direction = 'SELL'
else:
reasons.append(f"RSI超买但4H趋势向上禁止逆势做空")
# 布林带下轨,做多信号
# 布林带下轨,做多信号需4H趋势向上或中性
if bollinger and current_price <= bollinger['lower']:
if trend_4h in ('up', 'neutral', None):
signal_strength += 3
reasons.append("触及布林带下轨")
if direction is None:
direction = 'BUY'
else:
reasons.append("触及布林带下轨但4H趋势向下禁止逆势做多")
# 布林带上轨,做空信号
# 布林带上轨,做空信号需4H趋势向下或中性
elif bollinger and current_price >= bollinger['upper']:
if trend_4h in ('down', 'neutral', None):
signal_strength += 3
reasons.append("触及布林带上轨")
if direction is None:
direction = 'SELL'
else:
reasons.append("触及布林带上轨但4H趋势向上禁止逆势做空")
# 策略2趋势跟踪趋势市场
elif market_regime == 'trending':
# MACD金叉做多信号
# MACD金叉做多信号需4H趋势向上或中性
if macd and macd['macd'] > macd['signal'] and macd['histogram'] > 0:
if trend_4h in ('up', 'neutral', None):
signal_strength += 3
reasons.append("MACD金叉")
if direction is None:
direction = 'BUY'
else:
reasons.append("MACD金叉但4H趋势向下禁止逆势做多")
# MACD死叉做空信号
# MACD死叉做空信号需4H趋势向下或中性
elif macd and macd['macd'] < macd['signal'] and macd['histogram'] < 0:
if trend_4h in ('down', 'neutral', None):
signal_strength += 3
reasons.append("MACD死叉")
if direction is None:
direction = 'SELL'
else:
reasons.append("MACD死叉但4H趋势向上禁止逆势做空")
# 均线系统
if ema20 and ema50:
if current_price > ema20 > ema50: # 上升趋势
if trend_4h in ('up', 'neutral', None):
signal_strength += 2
reasons.append("价格在均线之上")
if direction is None:
direction = 'BUY'
else:
reasons.append("1H均线向上但4H趋势向下禁止逆势做多")
elif current_price < ema20 < ema50: # 下降趋势
if trend_4h in ('down', 'neutral', None):
signal_strength += 2
reasons.append("价格在均线之下")
if direction is None:
direction = 'SELL'
else:
reasons.append("1H均线向下但4H趋势向上禁止逆势做空")
# 策略3综合信号提高胜率
# 多个指标同时确认时,信号更强
@ -370,8 +422,25 @@ class TradingStrategy:
signal_strength += 2
reasons.append(f"{confirmations}个指标确认")
# 判断是否应该交易(信号强度 >= 5 才交易,提高胜率)
should_trade = signal_strength >= config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 5)
# 多周期共振加分如果4H趋势与信号方向一致增加信号强度
if direction and trend_4h:
if (direction == 'BUY' and trend_4h == 'up') or (direction == 'SELL' and trend_4h == 'down'):
signal_strength += 2
reasons.append("4H周期共振确认")
elif (direction == 'BUY' and trend_4h == 'down') or (direction == 'SELL' and trend_4h == 'up'):
# 逆势信号,降低信号强度或直接拒绝
signal_strength -= 3
reasons.append("⚠️ 逆4H趋势信号强度降低")
# 判断是否应该交易(信号强度 >= 7 才交易,提高胜率)
min_signal_strength = config.TRADING_CONFIG.get('MIN_SIGNAL_STRENGTH', 7)
should_trade = signal_strength >= min_signal_strength
# 如果信号方向与4H趋势相反直接拒绝交易
if direction and trend_4h:
if (direction == 'BUY' and trend_4h == 'down') or (direction == 'SELL' and trend_4h == 'up'):
should_trade = False
reasons.append("❌ 禁止逆4H趋势交易")
if not should_trade and direction:
reasons.append(f"信号强度不足({signal_strength}/10)")