diff --git a/config_examples/freqaiprimer.json b/config_examples/freqaiprimer.json index aaa06fc3..4db242e9 100644 --- a/config_examples/freqaiprimer.json +++ b/config_examples/freqaiprimer.json @@ -113,32 +113,15 @@ "shuffle": false }, "model_training_parameters": { - "price_value_divergence": { - "model": "LightGBMRegressor", - "model_params": { - "n_estimators": 400, - "learning_rate": 0.03, - "num_leaves": 40, - "max_depth": 10, - "min_data_in_leaf": 20, - "feature_fraction": 0.8, - "bagging_fraction": 0.8, - "bagging_freq": 5, - "verbose": -1 - } - }, - "optimal_first_length": { - "model": "LightGBMClassifier", - "model_params": { - "n_estimators": 150, - "learning_rate": 0.1, - "num_leaves": 15, - "max_depth": 8, - "min_data_in_leaf": 10, - "class_weight": "balanced", - "verbose": -1 - } - } + "n_estimators": 400, + "learning_rate": 0.03, + "num_leaves": 40, + "max_depth": 10, + "min_data_in_leaf": 20, + "feature_fraction": 0.8, + "bagging_fraction": 0.8, + "bagging_freq": 5, + "verbose": -1 } }, "api_server": { diff --git a/freqtrade/templates/freqaiprimer.json b/freqtrade/templates/freqaiprimer.json index 5d7e77df..49d2865f 100644 --- a/freqtrade/templates/freqaiprimer.json +++ b/freqtrade/templates/freqaiprimer.json @@ -9,17 +9,27 @@ "max_open_trades": 5 }, "buy": { - "trend_final_bearish_threshold": 13, - "trend_final_bullish_threshold": 55 + "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.472, + "SELL_THRESHOLD_MAX": 0.065, + "SELL_THRESHOLD_MIN": 0.002, + "TRAILING_STOP_DISTANCE": 0.015, + "TRAILING_STOP_START": 0.016 }, - "sell": {}, "protection": {}, "trailing": { "trailing_stop": true, - "trailing_stop_positive": 0.046, - "trailing_stop_positive_offset": 0.14600000000000002, + "trailing_stop_positive": 0.106, + "trailing_stop_positive_offset": 0.196, "trailing_only_offset_is_reached": false } + }, "ft_stratparam_v": 1, "export_time": "2025-08-14 06:30:51.352733+00:00" diff --git a/freqtrade/templates/freqaiprimer.py b/freqtrade/templates/freqaiprimer.py index 2d20f1db..9dde091a 100644 --- a/freqtrade/templates/freqaiprimer.py +++ b/freqtrade/templates/freqaiprimer.py @@ -243,7 +243,14 @@ class FreqaiPrimer(IStrategy): dataframe["volume_z_score"] = (dataframe["volume"] - dataframe["volume_mean_20"]) / dataframe["volume_std_20"] dataframe["volume_z_score"] = dataframe["volume_z_score"].replace([np.inf, -np.inf], 0).ffill().fillna(0) - dataframe["&-price_value_divergence"] = dataframe["&-price_value_divergence"].replace([np.inf, -np.inf], 0).ffill().fillna(0) + # 严格清理price_value_divergence,确保数据类型正确 + price_divergence = dataframe["&-price_value_divergence"].replace([np.inf, -np.inf], 0).ffill().fillna(0) + dataframe["&-price_value_divergence"] = price_divergence.astype(np.float64) + + # 验证数据类型和范围 + if not np.isfinite(dataframe["&-price_value_divergence"]).all(): + logger.warning(f"[{pair}] price_value_divergence包含非有限值,进行清理") + dataframe["&-price_value_divergence"] = dataframe["&-price_value_divergence"].replace([np.inf, -np.inf, np.nan], 0.0) # 新增:分类模型优化 first_length # 基于市场状态预测最优的 first_length 分类(2, 4, 6, 8, 10) @@ -265,9 +272,22 @@ class FreqaiPrimer(IStrategy): ] choices = [0, 1, 2, 3] - # 确保分类目标列是整数类型 - optimal_length_class = np.select(conditions, choices, default=4) - dataframe["&*-optimal_first_length"] = optimal_length_class.astype(int) + # 确保分类目标列是整数类型,添加严格验证 + try: + optimal_length_class = np.select(conditions, choices, default=4) + # 确保所有值都是有效的整数 + optimal_length_class = np.clip(optimal_length_class, 0, 4) # 限制在0-4范围内 + dataframe["&*-optimal_first_length"] = optimal_length_class.astype(np.int32) + + # 验证分类值的有效性 + unique_values = np.unique(optimal_length_class) + if not all(0 <= val <= 4 for val in unique_values): + logger.warning(f"[{pair}] 发现无效的first_length分类值: {unique_values}") + dataframe["&*-optimal_first_length"] = np.clip(optimal_length_class, 0, 4).astype(np.int32) + + except Exception as e: + logger.error(f"[{pair}] 计算分类目标时出错: {e}") + dataframe["&*-optimal_first_length"] = np.full(len(dataframe), 2, dtype=np.int32) # 默认值为2 # 添加调试信息 logger.info(f"[{pair}] 📈 分类目标统计: {dict(pd.Series(optimal_length_class).value_counts())}") @@ -428,20 +448,14 @@ class FreqaiPrimer(IStrategy): if col in dataframe.columns: dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0).ffill().fillna(0) - # 调用 FreqAI 预测 - 分别处理回归和分类模型 + # 调用 FreqAI 预测 - 使用单一回归模型 if not hasattr(self, 'freqai') or self.freqai is None: logger.error(f"[{pair}] FreqAI 未初始化,回退到规则计算") dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"] - dataframe["&*-optimal_first_length"] = 2.0 # 默认分类值 else: logger.info(f"[{pair}] 调用 FreqAI 预测,类型:{type(self.freqai)}") - # 先处理回归模型 - original_targets = list(self.freqai_info.get("model_training_parameters", {}).keys()) - logger.info(f"[{pair}] 原始目标列: {original_targets}") - try: - # 只保留回归目标进行预测 dataframe = self.freqai.start(dataframe, metadata, self) # 检查 FreqAI 生成的列 @@ -455,28 +469,6 @@ class FreqaiPrimer(IStrategy): except Exception as e: logger.error(f"[{pair}] FreqAI 预测失败: {e}") dataframe["&-price_value_divergence"] = dataframe["price_value_divergence"] - - # 分类模型预测值将通过训练数据直接生成,这里创建默认值 - if "&*-optimal_first_length" not in dataframe.columns: - # 使用规则计算分类值 - atr = ta.ATR(dataframe, timeperiod=14) - volatility_ratio = atr / dataframe['close'] - trend_strength = abs(dataframe['close'] - dataframe['ema200']) / dataframe['ema200'] - volume_anomaly = abs(dataframe['volume_z_score']) > 2 - - conditions = [ - (volatility_ratio > 0.02) & (trend_strength > 0.05), - (volatility_ratio > 0.015) & (trend_strength > 0.03), - (volatility_ratio > 0.01) | (volume_anomaly), - (volatility_ratio < 0.008) & (trend_strength < 0.02), - ] - choices = [0, 1, 2, 3] - optimal_length_class = np.select(conditions, choices, default=4) - dataframe["&*-optimal_first_length"] = optimal_length_class.astype(float) - - logger.info(f"[{pair}] ✅ 使用规则计算分类值: {dict(pd.Series(optimal_length_class).value_counts())}") - else: - logger.info(f"[{pair}] ✅ FreqAI 生成了 &*-optimal_first_length: {dataframe['&*-optimal_first_length'].value_counts().to_dict()}") # 计算 labels_mean 和 labels_std labels_mean = None