# --- Do not remove these libs --- from freqtrade.strategy import IStrategy from typing import Dict, List, Tuple, Optional from functools import reduce from pandas import DataFrame import freqtrade.vendor.qtpylib.indicators as qtpylib import pandas as pd # -------------------------------- from technical.util import resample_to_interval, resampled_merge import talib.abstract as ta import freqtrade.vendor.qtpylib.indicators as qtpylib from datetime import datetime, timedelta, timezone from freqtrade.persistence import Trade, Order from typing import Optional import numpy as np import logging logger = logging.getLogger(__name__) # freqtrade backtesting -c ./user_data/Chan/config/ChanLun_SOL.json --strategy Chan_SOL_2 --strategy-path ./user_data/Chan/strategies --timerange=20240801-20241201 class Chan_SOL_2(IStrategy): """ 稳定盈利交易策略 - 基于多重技术分析 结合趋势跟踪、动量指标和风险管理 """ INTERFACE_VERSION: int = 3 # 优化的ROI设置 - 阶梯式获利了结 minimal_roi = { "0": 0.15, # 15%快速获利 "30": 0.08, # 30分钟后8% "60": 0.05, # 1小时后5% "120": 0.03, # 2小时后3% "240": 0.02, # 4小时后2% "480": 0.015, # 8小时后1.5% "960": 0.01 # 16小时后1% } can_short = True stoploss = -0.08 # 8%止损 # 动态追踪止损 trailing_stop = True trailing_stop_positive = 0.015 # 1.5%开始追踪 trailing_stop_positive_offset = 0.025 # 2.5%偏移 trailing_only_offset_is_reached = True # 仓位管理 position_adjustment_enable = True max_entry_position_adjustment = 2 max_dca_multiplier = 3.0 timeframe = '5m' startup_candle_count = 200 # 自定义参数 buy_volume_threshold = 1.5 sell_volume_threshold = 1.2 rsi_oversold = 25 rsi_overbought = 75 adx_trend_threshold = 25 def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ 添加技术指标 - 多维度分析 """ # === 趋势指标 === # 多周期移动平均线 dataframe['ema_8'] = ta.EMA(dataframe, timeperiod=8) dataframe['ema_21'] = ta.EMA(dataframe, timeperiod=21) dataframe['ema_50'] = ta.EMA(dataframe, timeperiod=50) dataframe['ema_200'] = ta.EMA(dataframe, timeperiod=200) # === 动量指标 === # RSI - 超买超卖 dataframe['rsi'] = ta.RSI(dataframe, timeperiod=14) dataframe['rsi_fast'] = ta.RSI(dataframe, timeperiod=9) dataframe['rsi_slow'] = ta.RSI(dataframe, timeperiod=21) # MACD - 趋势动量 macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9) dataframe['macd'] = macd['macd'] dataframe['macdsignal'] = macd['macdsignal'] dataframe['macdhist'] = macd['macdhist'] # === 波动率指标 === # ATR - 真实波动幅度 dataframe['atr'] = ta.ATR(dataframe, timeperiod=14) # 布林带 bollinger = qtpylib.bollinger_bands(qtpylib.typical_price(dataframe), window=20, stds=2) dataframe['bb_lowerband'] = bollinger['lower'] dataframe['bb_middleband'] = bollinger['mid'] dataframe['bb_upperband'] = bollinger['upper'] dataframe['bb_percent'] = (dataframe['close'] - dataframe['bb_lowerband']) / (dataframe['bb_upperband'] - dataframe['bb_lowerband']) dataframe['bb_width'] = (dataframe['bb_upperband'] - dataframe['bb_lowerband']) / dataframe['bb_middleband'] # === 趋势强度指标 === # ADX - 趋势强度 dataframe['adx'] = ta.ADX(dataframe, timeperiod=14) dataframe['plus_di'] = ta.PLUS_DI(dataframe, timeperiod=14) dataframe['minus_di'] = ta.MINUS_DI(dataframe, timeperiod=14) # === 成交量指标 === # 成交量移动平均 dataframe['volume_sma_20'] = dataframe['volume'].rolling(window=20).mean() dataframe['volume_ratio'] = dataframe['volume'] / dataframe['volume_sma_20'] # OBV - 能量潮 dataframe['obv'] = ta.OBV(dataframe) dataframe['obv_ema'] = ta.EMA(dataframe['obv'], timeperiod=20) # === 价格行为指标 === # 价格变化率 dataframe['price_change'] = dataframe['close'].pct_change() dataframe['price_change_5'] = dataframe['close'].pct_change(periods=5) # 高低点分析 dataframe['high_20'] = dataframe['high'].rolling(window=20).max() dataframe['low_20'] = dataframe['low'].rolling(window=20).min() # === 自定义复合指标 === # 趋势确认信号 dataframe['trend_up'] = ( (dataframe['ema_8'] > dataframe['ema_21']) & (dataframe['ema_21'] > dataframe['ema_50']) & (dataframe['close'] > dataframe['ema_8']) ) dataframe['trend_down'] = ( (dataframe['ema_8'] < dataframe['ema_21']) & (dataframe['ema_21'] < dataframe['ema_50']) & (dataframe['close'] < dataframe['ema_8']) ) # 动量强度评分 dataframe['momentum_score'] = ( ((dataframe['rsi'] > 50).astype(int) * 1) + ((dataframe['macd'] > dataframe['macdsignal']).astype(int) * 1) + ((dataframe['adx'] > self.adx_trend_threshold).astype(int) * 1) + ((dataframe['volume_ratio'] > 1.0).astype(int) * 1) ) # 波动率适应性指标 dataframe['volatility_high'] = dataframe['atr'] > dataframe['atr'].rolling(window=20).mean() * 1.5 return dataframe def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ 入场信号 - 多条件确认系统 """ # === 多头入场条件 === # 条件1: 强势突破入场 dataframe.loc[ ( # 趋势确认 (dataframe['trend_up']) & (dataframe['close'] > dataframe['ema_21']) & # 动量确认 (dataframe['rsi'] > 45) & (dataframe['rsi'] < 75) & (dataframe['macd'] > dataframe['macdsignal']) & (dataframe['macdhist'] > dataframe['macdhist'].shift(1)) & # 成交量确认 (dataframe['volume_ratio'] > self.buy_volume_threshold) & (dataframe['obv'] > dataframe['obv_ema']) & # 价格行为确认 (dataframe['close'] > dataframe['bb_middleband']) & (dataframe['bb_percent'] > 0.2) & (dataframe['bb_percent'] < 0.8) & # 趋势强度确认 (dataframe['adx'] > self.adx_trend_threshold) & (dataframe['plus_di'] > dataframe['minus_di']) ), ['enter_long', 'enter_tag']] = (1, 'breakout_long') # 条件2: 超卖反弹入场 dataframe.loc[ ( # 超卖反弹 (dataframe['rsi'] < self.rsi_oversold + 10) & (dataframe['rsi'] > dataframe['rsi'].shift(1)) & (dataframe['bb_percent'] < 0.2) & # 趋势不能太差 (dataframe['ema_8'] >= dataframe['ema_50']) & (dataframe['close'] > dataframe['low_20'] * 1.02) & # 成交量支持 (dataframe['volume_ratio'] > 1.2) & # MACD底背离迹象 (dataframe['macdhist'] > dataframe['macdhist'].shift(1)) & # 不与第一个条件重复 (~dataframe['enter_long'].astype(bool)) ), ['enter_long', 'enter_tag']] = (1, 'oversold_long') # === 空头入场条件 === # 条件1: 强势下跌入场 dataframe.loc[ ( # 趋势确认 (dataframe['trend_down']) & (dataframe['close'] < dataframe['ema_21']) & # 动量确认 (dataframe['rsi'] < 55) & (dataframe['rsi'] > 25) & (dataframe['macd'] < dataframe['macdsignal']) & (dataframe['macdhist'] < dataframe['macdhist'].shift(1)) & # 成交量确认 (dataframe['volume_ratio'] > self.sell_volume_threshold) & (dataframe['obv'] < dataframe['obv_ema']) & # 价格行为确认 (dataframe['close'] < dataframe['bb_middleband']) & (dataframe['bb_percent'] > 0.2) & (dataframe['bb_percent'] < 0.8) & # 趋势强度确认 (dataframe['adx'] > self.adx_trend_threshold) & (dataframe['minus_di'] > dataframe['plus_di']) ), ['enter_short', 'enter_tag']] = (1, 'breakdown_short') # 条件2: 超买回调入场 dataframe.loc[ ( # 超买回调 (dataframe['rsi'] > self.rsi_overbought - 10) & (dataframe['rsi'] < dataframe['rsi'].shift(1)) & (dataframe['bb_percent'] > 0.8) & # 趋势不能太好 (dataframe['ema_8'] <= dataframe['ema_50']) & (dataframe['close'] < dataframe['high_20'] * 0.98) & # 成交量支持 (dataframe['volume_ratio'] > 1.2) & # MACD顶背离迹象 (dataframe['macdhist'] < dataframe['macdhist'].shift(1)) & # 不与第一个条件重复 (~dataframe['enter_short'].astype(bool)) ), ['enter_short', 'enter_tag']] = (1, 'overbought_short') return dataframe def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: """ 出场信号 - 及时止盈止损 """ # === 多头出场条件 === # 条件1: 趋势转弱 dataframe.loc[ ( ( (dataframe['rsi'] > self.rsi_overbought) | (dataframe['macd'] < dataframe['macdsignal']) | (dataframe['close'] < dataframe['ema_8']) | (dataframe['bb_percent'] > 0.95) | (dataframe['adx'] < 20) ) & (dataframe['volume_ratio'] > 1.0) ), ['exit_long', 'exit_tag']] = (1, 'trend_weak_long') # === 空头出场条件 === # 条件1: 趋势转强 dataframe.loc[ ( ( (dataframe['rsi'] < self.rsi_oversold) | (dataframe['macd'] > dataframe['macdsignal']) | (dataframe['close'] > dataframe['ema_8']) | (dataframe['bb_percent'] < 0.05) | (dataframe['adx'] < 20) ) & (dataframe['volume_ratio'] > 1.0) ), ['exit_short', 'exit_tag']] = (1, 'trend_strong_short') return dataframe def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: """ 动态止损策略 """ # 基础止损 if current_profit < -0.05: # 如果亏损超过5%,严格止损 return -0.08 # 盈利后的动态止损 if current_profit > 0.02: # 盈利超过2%后,调整止损至成本价附近 return 0.005 elif current_profit > 0.05: # 盈利超过5%后,保证1%利润 return -current_profit + 0.01 elif current_profit > 0.10: # 盈利超过10%后,保证5%利润 return -current_profit + 0.05 return self.stoploss def adjust_trade_position(self, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, min_stake: float, max_stake: float, current_entry_rate: float, current_exit_rate: float, current_entry_profit: float, current_exit_profit: float, **kwargs) -> Optional[float]: """ 仓位调整策略 - 金字塔加仓 """ # 如果亏损超过3%,不加仓 if current_profit < -0.03: return None # 如果盈利超过2%且趋势持续,可以加仓 if current_profit > 0.02 and len(trade.select_filled_orders(trade.entry_side)) < self.max_entry_position_adjustment: # 获取当前数据进行趋势确认 try: # 简单的趋势确认逻辑 if trade.is_short: return max_stake * 0.5 # 空头加仓 else: return max_stake * 0.5 # 多头加仓 except: pass return None def leverage(self, pair: str, current_time: datetime, current_rate: float, proposed_leverage: float, max_leverage: float, entry_tag: Optional[str], side: str, **kwargs) -> float: """ 杠杆设置 - 保守策略 """ # 根据入场类型调整杠杆 if entry_tag and 'breakout' in entry_tag: return min(2.0, max_leverage) # 突破信号使用较高杠杆 elif entry_tag and ('oversold' in entry_tag or 'overbought' in entry_tag): return min(1.5, max_leverage) # 超买超卖信号使用中等杠杆 else: return 1.0 # 默认无杠杆