diff --git a/config_examples/freqaiprimer.json b/config_examples/freqaiprimer.json index f533990c..d74cf124 100644 --- a/config_examples/freqaiprimer.json +++ b/config_examples/freqaiprimer.json @@ -11,7 +11,7 @@ "timeframe": "3m", "dry_run_wallet": 2000, "cancel_open_orders_on_exit": true, - "stoploss": -0.05, + "stoploss": -0.14, "max_entry_position_adjustment": 3, "position_adjustment_enable": true, "amount_reserve_percent": 0.05, diff --git a/freqtrade/templates/freqaiprimer.json b/freqtrade/templates/freqaiprimer.json index e237e6ca..5036dc8b 100644 --- a/freqtrade/templates/freqaiprimer.json +++ b/freqtrade/templates/freqaiprimer.json @@ -9,27 +9,27 @@ "max_open_trades": 5 }, "buy": { - "ADD_POSITION_THRESHOLD": -0.013, - "BUY_THRESHOLD_MAX": -0.007, - "BUY_THRESHOLD_MIN": -0.066, - "COOLDOWN_PERIOD_MINUTES": 10, - "MAX_ENTRY_POSITION_ADJUSTMENT": 1 + "ADD_POSITION_THRESHOLD": -0.021, + "BUY_THRESHOLD_MAX": -0.001, + "BUY_THRESHOLD_MIN": -0.035, + "COOLDOWN_PERIOD_MINUTES": 9, + "MAX_ENTRY_POSITION_ADJUSTMENT": 3 }, "sell": { - "EXIT_POSITION_RATIO": 0.207, - "SELL_THRESHOLD_MAX": 0.029, - "SELL_THRESHOLD_MIN": 0.011, - "TRAILING_STOP_DISTANCE": 0.019, - "TRAILING_STOP_START": 0.03 + "EXIT_POSITION_RATIO": 0.472, + "SELL_THRESHOLD_MAX": 0.065, + "SELL_THRESHOLD_MIN": 0.002, + "TRAILING_STOP_DISTANCE": 0.015, + "TRAILING_STOP_START": 0.016 }, "protection": {}, "trailing": { "trailing_stop": true, - "trailing_stop_positive": 0.126, - "trailing_stop_positive_offset": 0.197, + "trailing_stop_positive": 0.106, + "trailing_stop_positive_offset": 0.196, "trailing_only_offset_is_reached": false } }, "ft_stratparam_v": 1, - "export_time": "2025-07-01 03:49:57.502762+00:00" + "export_time": "2025-07-01 14:51:29.420394+00:00" } \ No newline at end of file diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 3f70c8cc..8d8e1e2e 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -15,7 +15,7 @@ logger = logging.getLogger(__name__) class FreqaiPrimer(IStrategy): """ - 基于 FreqAI 的动态阈值交易策略,集成动态加仓和减仓逻辑,兼容最新 Freqtrade 版本 + 基于 FreqAI 的动态阈值交易策略,集成动态加仓、减仓和自定义 ROI 逻辑,兼容最新 Freqtrade 版本 """ # --- 🧪 Hyperopt Parameters --- @@ -34,11 +34,18 @@ class FreqaiPrimer(IStrategy): MAX_ENTRY_POSITION_ADJUSTMENT = IntParameter(1, 3, default=2, space='buy', optimize=True) # --- 🛠️ 固定配置参数 --- - stoploss = -0.015 + stoploss = -0.15 timeframe = "3m" use_custom_stoploss = True position_adjustment_enable = True # 启用动态仓位调整 + minimal_roi = { + "0": 0.08, # 30分钟(0-30分钟)内,8% 盈利退出 + "15": 0.04, # 2小时(30-120分钟)内,4% 盈利退出 + "60": 0.02, # 4小时(120-240分钟)内,2% 盈利退出 + "120": 0.0 # 8小时(240-480分钟)内,0% 盈利退出 + } + plot_config = { "main_plot": { "ema200": {"color": "blue"}, @@ -270,7 +277,6 @@ class FreqaiPrimer(IStrategy): ] def populate_entry_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - pair = metadata.get('pair', 'Unknown') conditions = [] @@ -329,6 +335,7 @@ class FreqaiPrimer(IStrategy): logger.debug(f"[{pair}] 无有效买入条件") return dataframe + def populate_exit_trend(self, dataframe: DataFrame, metadata: dict) -> DataFrame: pair = metadata.get('pair', 'Unknown') conditions = [] @@ -509,6 +516,54 @@ class FreqaiPrimer(IStrategy): f"调整后卖出价:{adjusted_rate:.6f}") return True + def custom_roi(self, trade: Trade, current_profit: float, current_time: datetime, trade_dur: int, + current_rate: float = None, min_stake: float | None = None, max_stake: float | None = None) -> dict: + """ + 动态调整 ROI 表格,基于 FreqAI 预测的 &-price_value_divergence 和 RSI。 + - 负的 divergence(预测上涨)或低 RSI 时提高 ROI。 + - 正的 divergence(预测下跌)或高 RSI 时降低 ROI。 + - 长时间持仓降低 ROI 目标。 + """ + pair = trade.pair + logger.debug(f"[{pair}] 计算自定义 ROI,当前盈利: {current_profit:.2%}, 持仓时间: {trade_dur} 分钟") + + # 获取最新数据 + dataframe = self.dp.get_pair_dataframe(pair=pair, timeframe=self.timeframe) + dataframe = self.populate_indicators(dataframe, {'pair': pair}) # 计算指标 + + # 获取 FreqAI 预测和 RSI + divergence = dataframe["&-price_value_divergence"].iloc[-1] if "&-price_value_divergence" in dataframe else 0 + rsi = dataframe["rsi"].iloc[-1] if "rsi" in dataframe else 50 + + # 计算调整系数 + # 1. Divergence 调整:负值(预测上涨)-> 提高 ROI,正值(预测下跌)-> 降低 ROI + divergence_factor = self.linear_map(divergence, -0.1, 0.1, 1.2, 0.8) + + # 2. RSI 调整:低 RSI(超卖)-> 提高 ROI,高 RSI(超买)-> 降低 ROI + rsi_factor = self.linear_map(rsi, 30, 70, 1.2, 0.8) + + # 3. 时间调整:持仓时间越长,ROI 目标降低 + time_factor = self.linear_map(trade_dur, 0, 240, 1.0, 0.7) # 4小时后 ROI 降低到 70% + + # 综合调整系数 + roi_factor = divergence_factor * rsi_factor * time_factor + + # 默认 ROI 表格 + base_roi = { + 0: 0.08, + 15: 0.04, + 60: 0.02, + 120: 0.0 + } + + # 动态调整 ROI,限制在 0% 到 20% 之间 + dynamic_roi = {time: min(max(roi * roi_factor, 0.0), 0.2) for time, roi in base_roi.items()} + + logger.debug(f"[{pair}] Divergence: {divergence:.4f}, RSI: {rsi:.2f}, 持仓时间: {trade_dur} 分钟, " + f"调整系数: divergence={divergence_factor:.2f}, rsi={rsi_factor:.2f}, time={time_factor:.2f}, " + f"总系数={roi_factor:.2f}, 动态 ROI 表格: {dynamic_roi}") + return dynamic_roi + def custom_entry_price(self, pair: str, trade: Trade | None, current_time: datetime, proposed_rate: float, entry_tag: str | None, side: str, **kwargs) -> float: adjusted_rate = proposed_rate * (1 - 0.005) @@ -522,7 +577,6 @@ class FreqaiPrimer(IStrategy): logger.debug(f"[{pair}] 自定义卖出价:{adjusted_rate:.6f}(原价:{proposed_rate:.6f})") return adjusted_rate - def get_market_trend(self, dataframe: DataFrame = None, metadata: dict = None) -> int: try: timeframes = ["3m", "15m", "1h"] @@ -646,10 +700,10 @@ class FreqaiPrimer(IStrategy): final_score = max(0, min(100, final_score)) logger.info(f"[{pair}] 最终趋势得分:{final_score}, " - f"3m得分:{trend_scores.get('3m', 50)}, 15m得分:{trend_scores.get('15m', 50)}, " - f"1h得分:{trend_scores.get('1h', 50)}") + f"3m得分:{trend_scores.get('3m', 50)}, 15m得分:{trend_scores.get('15m', 50)}, " + f"1h得分:{trend_scores.get('1h', 50)}") return final_score except Exception as e: logger.error(f"[{pair}] 获取市场趋势失败:{e}", exc_info=True) - return 50 + return 50