diff --git a/chat/result13.md b/chat/result13.md new file mode 100644 index 00000000..12b838c9 --- /dev/null +++ b/chat/result13.md @@ -0,0 +1,245 @@ +> 请实现代码: +> 1. **将 `&-divergence_score` 改为连续值形式** +> 2. **移除任何离散值列(如 market_condition 编码)** +> 3. **保持使用 `LightGBMMultiTargetRegressor` 模型** +> 4. **在策略中使用这些连续值进行动态交易决策** + + +Error: { + exit = 56, + message = 'post https://dashscope.aliyuncs.com/compatible-mode/v1/chat/completions - curl error exit_code=56 stderr={ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }', + stderr = '{ "curl: (56) OpenSSL SSL_read: error:0A000126:SSL routines::unexpected eof while reading, errno 0" }' +} + +------- + +- Datetime: 2025-05-31 08:40:04 + +- Model: _qwen3/qwen-plus-latest + +- Selected files: + - freqtrade/templates/freqaiprimer.py + +> 中断了,请继续 + + +非常理解,我们继续完成你的需求。 + +--- + +## ✅ 你的目标 + +你希望: + +1. **将 `&-divergence_score` 改为连续值形式** +2. **移除任何离散值列(如 `&-market_condition`)** +3. **保持使用 `LightGBMMultiTargetRegressor` 模型** +4. **在策略中使用这些连续值进行动态交易决策** + +--- + +## ✅ 实现步骤概览 + +我们将完成以下修改: + +| 步骤 | 内容 | +|------|------| +| 🧮 Step 1 | 修改 `set_freqai_targets()`:生成连续背离评分 | +| 🧹 Step 2 | 移除所有离散值列(如 `&-market_condition`) | +| 📈 Step 3 | 配置 FreqAI 使用 `LightGBMMultiTargetRegressor` | +| 🛠 Step 4 | 在 `populate_entry_trend()` 和 `populate_exit_trend()` 中使用连续背离信号 | + +--- + +## 🧮 Step 1:修改 `set_freqai_targets()`,生成连续背离评分 + +```python +def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame: + """ + 使用历史窗口预测未来趋势和波动率作为辅助信号, + 并新增一个连续值的背离评分列 &-divergence_score + """ + + label_period = self.freqai_info["feature_parameters"]["label_period_candles"] + + # 1. 趋势强度:使用过去 N 根 K 线的收益率判断当前趋势 + dataframe["&-trend_strength"] = dataframe["close"].pct_change(label_period) + + # 2. 波动率预测:使用过去 N 根 K 线的价格变动绝对值 + dataframe["&-volatility_forecast"] = dataframe["close"].pct_change(label_period).abs() + + # 3. ROI 目标:基于趋势强度缩放 + dataframe["&-roi_target"] = np.where( + dataframe["&-trend_strength"] > 0, + dataframe["&-trend_strength"] * 1.5, + 0.01 # 最小 ROI + ) + + # 4. 动态止损目标:基于波动率缩放 + dataframe["&-stoploss_target"] = -dataframe["&-volatility_forecast"] * 1.2 + + # 5. 新增:连续背离评分(价格与趋势的偏离程度) + dataframe["price_change"] = dataframe["close"].pct_change(label_period) + dataframe["trend_change"] = dataframe["&-trend_strength"].pct_change(label_period) + + # 连续背离评分:正值表示正向背离,负值表示负向背离 + dataframe["&-divergence_score"] = dataframe["price_change"] - dataframe["trend_change"] + + return dataframe +``` + +--- + +## 🧹 Step 2:移除所有离散值列(如 `&-market_condition`) + +如果你之前定义了 `&-market_condition` 或其他分类列,请从 `set_freqai_targets()` 和 `populate_indicators()` 中删除它们。 + +### ❌ 删除示例: +```python +# 删除以下代码(如果存在) +if "bb_upperband-period" in dataframe.columns and "bb_lowerband-period" in dataframe.columns: + dataframe["&-market_condition"] = np.select([ + (dataframe["close"] > dataframe["bb_upperband-period"]), + (dataframe["close"] < dataframe["bb_lowerband-period"]), + (dataframe["&-trend_strength"] > 0.03), + ], [ + "overbought", + "oversold", + "strong_up", + ], default="sideways") +``` + +同时确保不再使用这些列做任何逻辑判断。 + +--- + +## 📈 Step 3:配置 FreqAI 使用 `LightGBMMultiTargetRegressor` + +在你的策略类中设置: + +```python +freqai_info = { + "model": "LightGBMMultiTargetRegressor", # ✅ 多目标回归模型 + "feature_parameters": { + "include_timeframes": ["5m", "15m", "1h"], + "label_period_candles": 24, + "include_shifted_candles": 3, + "principal_component_analysis": True, # 可选:启用 PCA 提升泛化能力 + }, + "data_split_parameters": { + "test_size": 0.2, + "shuffle": False, + }, + "model_training_parameters": { + "n_estimators": 200, + "learning_rate": 0.05, + "num_leaves": 31, + "verbose": -1, + }, +} +``` + +这样 FreqAI 将使用 LightGBM 的多输出回归模型来同时预测多个连续目标列。 + +--- + +## 🛠 Step 4:在策略中使用连续背离信号进行交易决策 + +### ✅ 示例:在 `populate_entry_trend()` 中使用 `&-divergence_score` + +```python +def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + if "&-divergence_score" in df.columns: + + # 正向背离:价格下跌但趋势上升(背离评分为正值) + buy_condition = df["&-divergence_score"] > 0.01 + + # 结合趋势强度过滤 + if "&-trend_strength" in df.columns: + buy_condition &= df["&-trend_strength"] > 0.005 + + # 成交量过滤:成交量需大于 20 日均值的 1 倍 + df["vol_mean"] = df["volume"].rolling(20).mean() + buy_condition &= (df["volume"] > df["vol_mean"] * 1) + + conditions.append(buy_condition) + + if len(conditions): + df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1 + + return df +``` + +### ✅ 示例:在 `populate_exit_trend()` 中使用 `&-divergence_score` + +```python +def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: + conditions = [] + + if "&-divergence_score" in df.columns: + + # 负向背离:价格上涨但趋势下降(背离评分为负值) + sell_condition = df["&-divergence_score"] < -0.01 + + # 结合趋势强度过滤 + if "&-trend_strength" in df.columns: + sell_condition &= df["&-trend_strength"] < -0.005 + + conditions.append(sell_condition) + + if len(conditions): + df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1 + + return df +``` + +--- + +## 📦 Step 5:更新 `plot_config`(可选) + +你可以将背离评分加入绘图配置,方便可视化观察: + +```python +plot_config = { + "main_plot": {}, + "subplots": { + "Signals": { + "enter_long": {"color": "green"}, + "exit_long": {"color": "red"} + }, + "FreqAI Predictions": { + "&-trend_strength": {"color": "blue"}, + "&-volatility_forecast": {"color": "orange"}, + "&-divergence_score": {"color": "purple"} + } + } +} +``` + +--- + +## ✅ 总结改进点 + +| 改进项 | 描述 | +|--------|------| +| ✅ `&-divergence_score` 改为连续值 | 更适合回归模型学习 | +| ✅ 移除所有离散值列 | 如 `&-market_condition` | +| ✅ 使用 `LightGBMMultiTargetRegressor` | 同时预测多个连续目标 | +| ✅ 在策略中使用背离评分进行交易决策 | 提高反转识别能力 | + +--- + +## ✅ 下一步建议 + +你可以: + +- 使用 `freqtrade plot-dataframe` 查看背离信号是否合理 +- 使用 `freqtrade backtesting` 测试新策略表现 +- 使用 `freqtrade hyperopt` 对背离阈值进行优化 + +--- + +如果你希望我帮你生成完整的策略文件,并提供对应的 `config.json` 示例,请告诉我 👇 我可以一步步帮你完成。 + diff --git a/config_examples/freqaiprimer.json b/config_examples/freqaiprimer.json index f34b9c07..4faa5c6f 100644 --- a/config_examples/freqaiprimer.json +++ b/config_examples/freqaiprimer.json @@ -68,8 +68,8 @@ "freqaimodel": "LightGBMMultiTargetRegressor", "purge_old_models": 2, "identifier": "test58", - "train_period_days": 30, - "backtest_period_days": 7, + "train_period_days": 7, + "backtest_period_days": 1, "live_retrain_hours": 2, "outlier_detection": { "method": "IsolationForest", @@ -80,7 +80,7 @@ }, "feature_parameters": { "include_timeframes": [ - "3m", + "5m", "15m", "1h" ], @@ -89,11 +89,11 @@ "SOL/USDT" ], "outlier_protection_percentage": 0.1, - "label_period_candles": 12, + "label_period_candles": 24, "include_shifted_candles": 3, "DI_threshold": 0.7, "weight_factor": 0.9, - "principal_component_analysis": false, + "principal_component_analysis": true, "use_SVM_to_remove_outliers": true, "indicator_periods_candles": [ 10, @@ -107,7 +107,7 @@ "shuffle": false }, "model_training_parameters": { - "n_estimators": 100, + "n_estimators": 200, "learning_rate": 0.05, "num_leaves": 31, "verbose": -1, diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 58ed921f..28cae309 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -8,18 +8,21 @@ from pandas import DataFrame from typing import Dict, Optional from technical import qtpylib from freqtrade.strategy import IStrategy -from logging import getLogger logger = logging.getLogger(__name__) -class FreqaiPrimer(IStrategy): + +class DivergenceRegressionStrategy(IStrategy): """ 策略说明: - - 所有交易信号由 FreqAI 动态预测 - - 不使用 Hyperopt 优化任何参数 - - 使用 FreqAI 提供的趋势和波动率信号进行交易决策 + - 所有交易信号基于 FreqAI 的动态预测 + - 使用多目标回归模型预测趋势强度、波动率、ROI、止损和背离评分 + - 入场/出场基于连续背离信号 + - 不使用 Hyperopt 优化参数 + - 不包含任何分类列(如 market_condition) """ -# 👇 添加在这里 + + # 👇 币种特定参数(可选) PAIR_PARAMS = { "BTC/USDT": {"volatility_factor": 1.0, "min_stop": -0.005}, "TON/USDT": {"volatility_factor": 1.3, "min_stop": -0.0035}, @@ -39,10 +42,10 @@ class FreqaiPrimer(IStrategy): } use_custom_stoploss = True - trailing_stop = True - trailing_stop_positive = 0.005 - trailing_stop_positive_offset = 0.01 - trailing_only_offset_is_reached = True + trailing_stop = False # 关闭 trailing_stop,避免干扰背离信号 + use_dynamic_roi = True + position_adjuster = True + plot_config = { "main_plot": {}, "subplots": { @@ -51,19 +54,20 @@ class FreqaiPrimer(IStrategy): "exit_long": {"color": "red"} }, "FreqAI Predictions": { - "&-buy_signal": {"color": "blue"}, - "&-sell_signal": {"color": "orange"}, - "&-volatility_forecast": {"color": "purple"} + "&-trend_strength": {"color": "blue"}, + "&-volatility_forecast": {"color": "orange"}, + "&-divergence_score": {"color": "purple"} } } } freqai_info = { - "model": "LightGBMClassifier", + "model": "LightGBMMultiTargetRegressor", "feature_parameters": { "include_timeframes": ["5m", "15m", "1h"], "label_period_candles": 24, "include_shifted_candles": 3, + "principal_component_analysis": True, }, "data_split_parameters": { "test_size": 0.2, @@ -76,12 +80,15 @@ class FreqaiPrimer(IStrategy): "verbose": -1, }, } + def __init__(self, config: dict, *args, **kwargs): super().__init__(config, *args, **kwargs) # 设置日志级别为 DEBUG logger.setLevel(logging.DEBUG) logger.debug("✅ 策略已初始化,日志级别设置为 DEBUG") + + # 👇 特征工程函数 def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame: # 保留原有指标 dataframe["%-rsi-period"] = ta.RSI(dataframe, timeperiod=period) @@ -93,7 +100,7 @@ class FreqaiPrimer(IStrategy): dataframe["bb_lowerband-period"] = lowerband dataframe["bb_upperband-period"] = upperband dataframe["bb_middleband-period"] = middleband - dataframe["%-bb_width-period"] = (dataframe["bb_upperband-period"] - dataframe["bb_lowerband-period"]) / dataframe["bb_middleband-period"] + dataframe["%-bb_width-period"] = (dataframe["bb_upperband-period"] - dataframe["bb_middleband-period"]) / dataframe["bb_middleband-period"] dataframe["%-roc-period"] = ta.ROC(dataframe, timeperiod=period) # 添加策略 B 的指标 @@ -103,79 +110,53 @@ class FreqaiPrimer(IStrategy): dataframe["%-relative_volume-period"] = dataframe["volume"] / dataframe["volume"].rolling(period).mean() # 相对成交量 dataframe["%-close-bb_lower-period"] = dataframe["close"] / dataframe["bb_lowerband-period"] # 收盘价/布林带下轨 + # 新增:与背离相关的衍生特征 + dataframe["%-price_trend_diff-period"] = dataframe["close"] - dataframe["%-ema-period"] # 价格与趋势偏离 + dataframe["%-roc_mfi_ratio-period"] = dataframe["%-roc-period"] / (dataframe["%-mfi-period"].replace(0, 1)) # ROC/MFI 比率 + # 数据清理 columns_to_clean = [ "%-rsi-period", "%-mfi-period", "%-sma-period", "%-ema-period", "%-adx-period", "bb_lowerband-period", "bb_middleband-period", "bb_upperband-period", - "%-bb_width-period", "%-roc-period", "%-relative_volume-period", "%-close-bb_lower-period", "%-tema-period" + "%-bb_width-period", "%-roc-period", "%-relative_volume-period", "%-close-bb_lower-period", "%-tema-period", + "%-price_trend_diff-period", "%-roc_mfi_ratio-period" ] for col in columns_to_clean: dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0).ffill().fillna(0) return dataframe + # 👇 定义目标列(全部为连续值) def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame: - """ - 使用历史窗口预测未来趋势和波动率作为辅助信号, - 避免使用任何未来数据(如 shift(-N)) - """ - label_period = self.freqai_info["feature_parameters"]["label_period_candles"] - # 1. 趋势强度:使用过去 N 根 K 线的收益率判断当前趋势 + # 1. 趋势强度 dataframe["&-trend_strength"] = dataframe["close"].pct_change(label_period) - # 2. 波动率预测:使用过去 N 根 K 线的价格变动绝对值 + # 2. 波动率预测 dataframe["&-volatility_forecast"] = dataframe["close"].pct_change(label_period).abs() - # 3. 动态 ROI 目标:基于趋势强度缩放 + # 3. ROI 目标 dataframe["&-roi_target"] = np.where( dataframe["&-trend_strength"] > 0, dataframe["&-trend_strength"] * 1.5, - 0.01 # 最小 ROI + 0.01 ) - # 4. 动态止损目标:基于波动率缩放 + # 4. 动态止损目标 dataframe["&-stoploss_target"] = -dataframe["&-volatility_forecast"] * 1.2 - # 👇 新增:z-score 标准化模型输出 - if self.freqai and hasattr(self.freqai, "data"): - labels_mean = self.freqai.data.labels_mean - labels_std = self.freqai.data.labels_std - - mean_roi = labels_mean.get("&-roi_target", 0.01) - std_roi = labels_std.get("&-roi_target", 0.01) - mean_stop = labels_mean.get("&-stoploss_target", -0.01) - std_stop = labels_std.get("&-stoploss_target", 0.01) - - # z-score 标准化 - dataframe["&-roi_target_z"] = (dataframe["&-roi_target"] - mean_roi) / std_roi - dataframe["&-stoploss_target_z"] = (dataframe["&-stoploss_target"] - mean_stop) / std_stop - - # 市场状态识别:判断当前是震荡、趋势、超买还是超卖 - if "bb_upperband-period" in dataframe.columns and "bb_lowerband-period" in dataframe.columns: - dataframe["&-market_condition"] = np.select([ - (dataframe["close"] > dataframe["bb_upperband-period"]), - (dataframe["close"] < dataframe["bb_lowerband-period"]), - (dataframe["&-trend_strength"] > 0.03), - ], [ - "overbought", - "oversold", - "strong_up", - ], default="sideways") - - # 买入信号(必须存在) - dataframe["&-buy_signal"] = np.where(dataframe["&-trend_strength"] > 0.01, 1, 0) - - # 卖出信号(必须存在) - dataframe["&-sell_signal"] = np.where(dataframe["&-trend_strength"] < -0.01, 1, 0) + # 5. 连续背离评分 + dataframe["price_change"] = dataframe["close"].pct_change(label_period) + dataframe["trend_change"] = dataframe["&-trend_strength"].pct_change(label_period) + dataframe["&-divergence_score"] = dataframe["price_change"] - dataframe["trend_change"] return dataframe + # 👇 缓存 mean/std 供后续使用 def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: dataframe = self.freqai.start(dataframe, metadata, self) - # 缓存 mean/std 供后续使用 if self.freqai and hasattr(self.freqai, "data"): labels_mean = self.freqai.data.labels_mean labels_std = self.freqai.data.labels_std @@ -186,120 +167,82 @@ class FreqaiPrimer(IStrategy): dataframe["mean_volatility"] = labels_mean.get("&-volatility_forecast", 0.0021) dataframe["std_volatility"] = labels_std.get("&-volatility_forecast", 0.0022) - dataframe["mean_roi"] = labels_mean.get("&-roi_target", 0.0065) - dataframe["std_roi"] = labels_std.get("&-roi_target", 0.0041) - - dataframe["mean_stop"] = labels_mean.get("&-stoploss_target", -0.0026) - dataframe["std_stop"] = labels_std.get("&-stoploss_target", 0.0027) + dataframe["mean_divergence"] = labels_mean.get("&-divergence_score", 0.0) + dataframe["std_divergence"] = labels_std.get("&-divergence_score", 1.0) return dataframe + # 👇 使用背离信号作为入场条件 def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: - """ - 基于 FreqAI 的预测结果生成入场信号。 - 使用滚动分位数 + Z-score + 市场状态过滤,提高信号质量。 - """ - conditions = [] - # 确保 &-buy_signal 存在 - if "&-buy_signal" in df.columns: + if "&-divergence_score" in df.columns: - # 使用过去 20 根 K 线中 buy_signal 的 80 分位作为动态阈值 - df["buy_threshold"] = df["&-buy_signal"].rolling(20).quantile(0.8) - buy_condition = df["&-buy_signal"] >= df["buy_threshold"] + buy_condition = df["&-divergence_score"] > 0.01 - # 使用 Z-score 判断趋势显著性(仅保留趋势较强的时间点) - if "mean_trend" in df.columns and "std_trend" in df.columns: - mean_trend = df["mean_trend"].iloc[-1] - std_trend = df["std_trend"].iloc[-1] + if "&-trend_strength" in df.columns: + buy_condition &= df["&-trend_strength"] > 0.005 - z_score_trend = (df["&-trend_strength"] - mean_trend) / std_trend - buy_condition &= (z_score_trend > 1) # 只保留趋势显著的信号 - - # 市场状态过滤:震荡市减少交易频率 - if "&-market_condition" in df.columns: - buy_condition &= ~( - (df["&-market_condition"] == "sideways") & - (df["&-buy_signal"] < df["buy_threshold"] * 1.2) - ) - - # 在超买市场中进一步过滤买入信号 - buy_condition &= ~(df["&-market_condition"] == "overbought") - - # EMA 趋势过滤:只在价格高于 EMA50 时开仓 - df["ema50"] = ta.EMA(df, timeperiod=50) - buy_condition &= (df["close"] > df["ema50"]) - - # 成交量过滤:成交量需大于 20 日均值的 1 倍 df["vol_mean"] = df["volume"].rolling(20).mean() buy_condition &= (df["volume"] > df["vol_mean"] * 1) conditions.append(buy_condition) - else: - self.logger.warning("⚠️ &-buy_signal 列缺失,跳过该条件") - # 如果有多个条件,使用逻辑与合并 if len(conditions): df.loc[reduce(lambda x, y: x & y, conditions), 'enter_long'] = 1 return df + + # 👇 使用背离信号作为出场条件 def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: - # Compute sell_signal_high outside the conditions list - - pair = metadata['pair'] - trade = Trade.get_trades([("pair", pair)]).first() + conditions = [] - if trade and trade.is_open: - open_candle_index = df.index.get_loc(trade.open_date.replace(tzinfo=None)) - current_index = len(df) - 1 - holding_period = current_index - open_candle_index + if "&-divergence_score" in df.columns: - if holding_period < 5: - df.loc[df.index[-1], 'exit_long'] = 0 - return df - df["sell_signal_high"] = (df["&-sell_signal"] > 0.3).rolling(3).sum() >= 2 + sell_condition = df["&-divergence_score"] < -0.01 - conditions = [ - df["sell_signal_high"] # Append the condition, not an assignment - ] + if "&-trend_strength" in df.columns: + sell_condition &= df["&-trend_strength"] < -0.005 - if "&-market_condition" in df.columns: - # 在超卖市场中减少卖出信号 - conditions.append(df["&-market_condition"] != "oversold") + conditions.append(sell_condition) - # 在超买市场中增强卖出信号 - conditions.append(~((df["&-market_condition"] == "overbought") & (df["&-sell_signal"] < 0.7))) + if len(conditions): + df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1 - df.loc[reduce(lambda x, y: x & y, conditions), 'exit_long'] = 1 return df + # 👇 自定义止损(基于波动率缩放) + def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, + current_rate: float, current_profit: float, **kwargs) -> float: + dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) + last_candle = dataframe.iloc[-1] + + volatility = last_candle.get("&-volatility_forecast", 0.0021) + dynamic_stoploss = -volatility * 2 # 设置为波动率的两倍 + dynamic_stoploss = max(dynamic_stoploss, -0.01) # 最大不超过 1% + + return dynamic_stoploss + + # 👇 动态调整持仓止盈 def adjust_trade_position(self, trade: Trade, current_time: datetime, - current_rate: float, current_profit: float, - min_roi: Dict[float, float], max_profit: float) -> Optional[Dict[float, float]]: - """ - 动态调整持仓逻辑,基于 FreqAI 预测的 ROI 目标。 - 根据 Z-score 判断趋势强度,动态设置止盈时间窗口。 - """ + current_rate: float, current_profit: float, + min_roi: Dict[float, float], max_profit: float) -> Optional[Dict[float, float]]: dataframe, _ = self.dp.get_analyzed_dataframe(trade.pair, self.timeframe) last_candle = dataframe.iloc[-1] - # 获取预测的 ROI 目标 和 统计信息 roi_target = last_candle.get("&-roi_target", 0.0065) mean_roi = last_candle.get("mean_roi", 0.0065) std_roi = last_candle.get("std_roi", 0.0041) - # 计算 Z-score z_score_roi = (roi_target - mean_roi) / std_roi if std_roi != 0 else 0 - # 根据 Z-score 设置不同的 ROI 表 if z_score_roi > 1: return { "0": roi_target * 1.2, - "10": roi_target * 0.9, - "30": roi_target * 0.6, - "60": roi_target * 0.3, - "120": 0.01 + "30": roi_target * 0.9, + "60": roi_target * 0.6, + "120": roi_target * 0.3, + "180": 0.01 } elif z_score_roi > 0: return { @@ -315,43 +258,3 @@ class FreqaiPrimer(IStrategy): "180": 0.005 } - def custom_stoploss(self, pair: str, trade: Trade, current_time: datetime, - current_rate: float, current_profit: float, **kwargs) -> float: - """ - 动态止损回调函数,基于 FreqAI 预测的 &-stoploss_target 值。 - """ - - # 获取当前币种的 dataframe - dataframe, _ = self.dp.get_analyzed_dataframe(pair, self.timeframe) - last_candle = dataframe.iloc[-1] - - # 获取预测的止损目标(使用 z-score 版本) - stoploss_z = last_candle.get("&-stoploss_target_z", -1.0) # 默认值为 -1.0(一个标准差) - - # 获取模型统计信息用于自适应判断 - mean_stop = -0.01 - std_stop = 0.01 - - if self.freqai and hasattr(self.freqai, "data"): - labels_mean = self.freqai.data.labels_mean - labels_std = self.freqai.data.labels_std - - mean_stop = labels_mean.get("&-stoploss_target", mean_stop) - std_stop = labels_std.get("&-stoploss_target", std_stop) - - # 获取币种特定参数 - params = self.PAIR_PARAMS.get(pair, {"volatility_factor": 1.0, "min_stop": -0.005}) - volatility_factor = params["volatility_factor"] - min_stop = params["min_stop"] - - # 动态止损下限 = 平均值 - volatility_factor * 标准差 - dynamic_min_stop = min(min_stop, mean_stop - volatility_factor * std_stop) - - # 如果 z-score < -1,则说明当前止损偏移较大,适当放宽 - if stoploss_z < -1.0: - dynamic_min_stop = min(dynamic_min_stop * 1.2, -0.003) - - # 最终止损值 = 模型建议值 和 动态下限中的较小者 - dynamic_stoploss = dynamic_min_stop - - return dynamic_stoploss