From 95a125f67f42ebf710220716a04613c8234d85c6 Mon Sep 17 00:00:00 2001 From: "zhangkun9038@dingtalk.com" Date: Wed, 7 May 2025 23:31:55 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8C=A3=E9=92=B1=E4=BA=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- freqtrade/templates/FreqaiExampleStrategy.py | 50 ++++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 29d5d49..2c9ccf3 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -84,39 +84,36 @@ class FreqaiExampleStrategy(IStrategy): logger.info(f"FreqAI 模型路径:{freqai_model_path}") + def _normalize_column(self, series: pd.Series) -> pd.Series: + """对单个列进行最小最大归一化""" + return (series - series.min()) / (series.max() - series.min()).fillna(0) + def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame: - # 保留关键的技术指标 + # 基础指标 dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14) + dataframe["macd"], dataframe["macdsignal"], dataframe["macdhist"] = ta.MACD( + dataframe, fastperiod=12, slowperiod=26, signalperiod=9 + ) - # 强制计算 MACD 并确保列存在 - macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9) - dataframe["macd"] = macd["macd"].fillna(0) - dataframe["macdsignal"] = macd["macdsignal"].fillna(0) - - # 确保列存在 - assert "macd" in dataframe.columns and "macdsignal" in dataframe.columns, \ - "MACD 列缺失,无法继续执行" - - # 确保 MACD 列存在 - if "macd" not in dataframe.columns or "macdsignal" not in dataframe.columns: - logger.error("MACD 或 MACD 信号列缺失,无法生成买入信号") - raise ValueError("DataFrame 缺少必要的 MACD 列") - - # 保留布林带相关特征 + # 布林带及其宽度 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_width"] = (dataframe["bb_upperband"] - dataframe["bb_lowerband"]) / dataframe["bb_middleband"] - # 保留成交量相关特征 - dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean() + # ATR (Average True Range) + dataframe["atr"] = ta.ATR(dataframe, timeperiod=14) + + # RSI 变化率 + dataframe["rsi_gradient"] = dataframe["rsi"].diff().fillna(0) + + # 数据清理与归一化 + for col in dataframe.select_dtypes(include=[np.number]).columns: + dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan) + dataframe[col] = dataframe[col].ffill().fillna(0) + dataframe[f"{col}_norm"] = self._normalize_column(dataframe[col]) - # 数据清理 - for col in dataframe.columns: - if dataframe[col].dtype in ["float64", "int64"]: - dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan) - dataframe[col] = dataframe[col].ffill().fillna(0) - logger.info(f"特征工程完成,特征数量:{len(dataframe.columns)}") return dataframe @@ -133,7 +130,10 @@ class FreqaiExampleStrategy(IStrategy): dataframe["%-pct-change"] = dataframe["close"].pct_change() dataframe["%-raw_volume"] = dataframe["volume"] dataframe["%-raw_price"] = dataframe["close"] -# 数据清理逻辑 + dataframe["%-volume_change"] = dataframe["volume"].pct_change(periods=5) + dataframe["%-price_momentum"] = dataframe["close"] / dataframe["close"].shift(20) - 1 + + # 数据清理逻辑 for col in dataframe.columns: if dataframe[col].dtype in ["float64", "int64"]: dataframe[col] = dataframe[col].replace([np.inf, -np.inf], 0)