diff --git a/freqtrade/templates/freqaiprimer.json b/freqtrade/templates/freqaiprimer.json index 462a7667..8b2bb643 100644 --- a/freqtrade/templates/freqaiprimer.json +++ b/freqtrade/templates/freqaiprimer.json @@ -16,33 +16,33 @@ }, "buy": { "stake_divisor": 2, - "add_position_callback": 0.056, - "bb_length": 22, + "add_position_callback": 0.04, + "bb_length": 28, "bb_lower_deviation": 1.03, - "bb_std": 2.1, + "bb_std": 3.0, "bb_width_threshold": 0.01, - "h1_max_candles": 223, - "h1_max_consecutive_candles": 4, - "h1_rapid_rise_threshold": 0.061, - "max_entry_adjustments": 5, + "h1_max_candles": 218, + "h1_max_consecutive_candles": 3, + "h1_rapid_rise_threshold": 0.063, + "max_entry_adjustments": 2, "min_condition_count": 2, - "rsi_bull_threshold": 53, - "rsi_length": 10, - "rsi_oversold": 49, - "stochrsi_bull_threshold": 40, - "stochrsi_neutral_threshold": 20, - "volume_multiplier": 1.4 + "rsi_bull_threshold": 48, + "rsi_length": 11, + "rsi_oversold": 44, + "stochrsi_bull_threshold": 32, + "stochrsi_neutral_threshold": 29, + "volume_multiplier": 1.6 }, "sell": { "exit_bb_upper_deviation": 0.98, - "exit_volume_multiplier": 1.9, - "roi_param_a": 0.06, - "roi_param_c": 0.0057, - "roi_param_k": 0.0088, - "rsi_overbought": 66 + "exit_volume_multiplier": 2.0, + "roi_param_a": 0.062, + "roi_param_k": 0.0054, + "roi_param_t0": 0.0082, + "rsi_overbought": 53 }, "protection": {} }, "ft_stratparam_v": 1, - "export_time": "2025-09-10 13:07:34.606541+00:00" + "export_time": "2025-09-10 20:55:14.197341+00:00" } \ No newline at end of file diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 71818dd9..dc631cd2 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -109,7 +109,7 @@ class FreqaiPrimer(IStrategy): # 动态ROI参数 - 指数衰减函数参数 (ROI(t) = a·e^(-k·t) + c) roi_param_a = DecimalParameter(0.01, 0.1, decimals=3, default=0.05, optimize=True, load=True, space='sell') # 初始ROI水平 roi_param_k = DecimalParameter(0.001, 0.01, decimals=4, default=0.003, optimize=True, load=True, space='sell') # 衰减速率 - roi_param_c = DecimalParameter(0, 0.01, decimals=4, default=0.005, optimize=True, load=True, space='sell') # 最低ROI水平 + roi_param_t0 = DecimalParameter(0, 0.01, decimals=4, default=0.005, optimize=True, load=True, space='sell') # 最低ROI水平 # 出场条件阈值参数 exit_bb_upper_deviation = DecimalParameter(0.98, 1.02, decimals=2, default=1.0, optimize=True, load=True, space='sell') exit_volume_multiplier = DecimalParameter(1.5, 3.0, decimals=1, default=2.0, optimize=True, load=True, space='sell') @@ -548,78 +548,52 @@ class FreqaiPrimer(IStrategy): return -1.2 * atr / current_rate # 基础1.2倍ATR止损 return self.stoploss - def custom_exit(self, pair: str, trade: 'Trade', current_time, current_rate: float, + def custom_exit(self, pair: str, trade: Trade, current_time: datetime, current_rate: float, current_profit: float, **kwargs) -> float: - """ - 结合指数衰减ROI逻辑的动态止盈函数 - - 根据交易持仓时间使用指数衰减公式计算动态止盈阈值 - - 考虑当前市场状态调整止盈策略 - - 仅支持多头交易 - """ - # 只支持多头 if trade.is_short: return 0.0 - - # 计算交易已持仓时间(分钟) + trade_age_minutes = (current_time - trade.open_date_utc).total_seconds() / 60 - - # 防止负数时间 if trade_age_minutes < 0: trade_age_minutes = 0 - - # 获取Hyperopt优化的指数衰减参数值 + a = self.roi_param_a.value k = self.roi_param_k.value - c = self.roi_param_c.value - - # 应用指数衰减公式计算动态ROI阈值 - dynamic_roi_threshold = a * math.exp(-k * trade_age_minutes) + c - - # 确保ROI阈值为正数 - dynamic_roi_threshold = max(dynamic_roi_threshold, 0.0) - - # 获取当前市场状态以调整止盈策略 - dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) - current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else 'unknown' - - # 根据市场状态调整退出比例计算 - exit_ratio = 0.0 - - # 计算当前利润与动态ROI阈值的比值 - if dynamic_roi_threshold > 0: - profit_ratio = current_profit / dynamic_roi_threshold - else: - profit_ratio = 0 - - # 根据市场状态和利润比值确定退出比例 - if profit_ratio >= 1.0: - # 利润达到或超过动态ROI阈值 - if current_state == 'strong_bull': - # 强劲牛市中,允许部分利润奔跑 - if profit_ratio < 1.5: - exit_ratio = 0.5 # 达到ROI阈值时只退出50% - else: - exit_ratio = 0.8 # 利润显著高于阈值时退出80% - elif current_state == 'weak_bull': - # 弱牛市中,平衡利润和风险 - if profit_ratio < 1.2: - exit_ratio = 0.6 # 达到ROI阈值时退出60% - else: - exit_ratio = 0.9 # 利润高于阈值时退出90% - else: - # 其他市场状态下,更保守的策略 - exit_ratio = 1.0 # 达到ROI阈值时全部退出 - - # 记录动态止盈决策 - #logger.info(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, \ - # 动态ROI阈值={dynamic_roi_threshold:.4f}, 利润比值={profit_ratio:.2f}, \ - # 市场状态={current_state}, 退出比例={exit_ratio:.0%}") - - # 返回应退出的比例(0.0表示不退出,1.0表示全部退出) - return exit_ratio - + t0 = self.roi_param_t0.value + + dynamic_roi_threshold = -a * math.atan(k * (trade_age_minutes - t0)) + if dynamic_roi_threshold < 0: + dynamic_roi_threshold = 0.0 + + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + current_state = dataframe['market_state'].iloc[-1] if 'market_state' in dataframe.columns else ( + 'strong_bull' if dataframe['sma'].diff().iloc[-1] > 0.01 else 'weak_bull' if dataframe['sma'].diff().iloc[-1] > 0 else 'neutral' + ) + + entry_tag = trade.enter_tag if hasattr(trade, 'enter_tag') else None + profit_ratio = current_profit / dynamic_roi_threshold if dynamic_roi_threshold > 0 else 0 + + exit_ratio = 0.0 + if profit_ratio >= 1.0: + if current_state == 'strong_bull': + exit_ratio = 0.5 if profit_ratio < 1.5 else 0.8 + elif current_state == 'weak_bull': + exit_ratio = 0.6 if profit_ratio < 1.2 else 0.9 + else: + exit_ratio = 1.0 + if entry_tag == 'strong_trend': + exit_ratio *= 0.8 + + if dynamic_roi_threshold < 0: + exit_ratio = 1.0 + + logger.info(f"[{pair}] 动态止盈: 持仓时间={trade_age_minutes:.1f}分钟, 当前利润={current_profit:.2%}, " + f"动态ROI阈值={dynamic_roi_threshold:.4f}, 利润比值={profit_ratio:.2f}, " + f"市场状态={current_state}, entry_tag={entry_tag}, 退出比例={exit_ratio:.0%}") + + return exit_ratio + - def adjust_trade_position(self, trade: 'Trade', current_time, current_rate: float, current_profit: float, min_stake: float, max_stake: float, **kwargs) -> float: """ diff --git a/tools/hyperopt.sh b/tools/hyperopt.sh index 6e252f80..07c32e61 100755 --- a/tools/hyperopt.sh +++ b/tools/hyperopt.sh @@ -243,8 +243,8 @@ docker-compose run --rm freqtrade hyperopt $PAIRS_FLAG \ --enable-protections \ --strategy-path /freqtrade/templates \ --timerange ${START_DATE}-${END_DATE} \ - -e 200 \ - -j 3 \ + -e 400 \ + -j 4 \ --hyperopt-loss SharpeHyperOptLossDaily \ --spaces buy sell \ --fee 0.0016