diff --git a/freqtrade/templates/FreqaiExampleStrategy.py b/freqtrade/templates/FreqaiExampleStrategy.py index 1d7ed33..245f771 100644 --- a/freqtrade/templates/FreqaiExampleStrategy.py +++ b/freqtrade/templates/FreqaiExampleStrategy.py @@ -128,9 +128,9 @@ class FreqaiExampleStrategy(IStrategy): return dataframe def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: - logger.info(f"Processing pair: {metadata['pair']}") - logger.info(f"DataFrame rows: {len(dataframe)}") - logger.info(f"Columns before freqai.start: {list(dataframe.columns)}") + logger.info(f"populate_indicators Processing pair: {metadata['pair']}") + logger.info(f"populate_indicators DataFrame rows: {len(dataframe)}") + logger.info(f"populate_indicators Columns before freqai.start: {list(dataframe.columns)}") if "close" not in dataframe.columns or dataframe["close"].isna().all(): logger.error(f"DataFrame missing 'close' column or all NaN for pair: {metadata['pair']}") @@ -173,6 +173,19 @@ class FreqaiExampleStrategy(IStrategy): logger.warning("bb_lowerband contains NaN, filling with close") dataframe["bb_lowerband"] = dataframe["bb_lowerband"].fillna(dataframe["close"]) logger.info(f"bb_lowerband stats: {dataframe['bb_lowerband'].describe().to_string()}") + # 生成 up_or_down + label_period = self.freqai_info["feature_parameters"]["label_period_candles"] + if len(dataframe) < label_period + 1: + logger.warning(f"DataFrame too short ({len(dataframe)} rows), cannot compute up_or_down") + dataframe["up_or_down"] = 0 + else: + dataframe["up_or_down"] = np.where( + dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0 + ) + if dataframe["up_or_down"].isna().any(): + logger.warning("up_or_down contains NaN, filling with 0") + dataframe["up_or_down"] = dataframe["up_or_down"].fillna(0) + logger.info(f"up_or_down stats: {dataframe['up_or_down'].describe().to_string()}") if "date" in dataframe.columns: dataframe["%-day_of_week"] = dataframe["date"].dt.dayofweek @@ -197,17 +210,18 @@ class FreqaiExampleStrategy(IStrategy): dataframe[col] = 50 if col == "buy_rsi_pred" else 80 logger.info(f"{col} stats: {dataframe[col].describe().to_string()}") - if "%-bb_width-period_20_SOL/USDT_5m" in dataframe.columns: - if dataframe["%-bb_width-period_20_SOL/USDT_5m"].std() > 0: - dataframe["%-bb_width-period_20_SOL/USDT_5m"] = ( - dataframe["%-bb_width-period_20_SOL/USDT_5m"] - dataframe["%-bb_width-period_20_SOL/USDT_5m"].mean() - ) / dataframe["%-bb_width-period_20_SOL/USDT_5m"].std() - logger.info(f"%-bb_width-period_20 stats: {dataframe['%-bb_width-period_20_SOL/USDT_5m'].describe().to_string()}") + # 调试特征分布 + if "%-bb_width-period_10_SOL/USDT_5m" in dataframe.columns: + if dataframe["%-bb_width-period_10_SOL/USDT_5m"].std() > 0: + dataframe["%-bb_width-period_10_SOL/USDT_5m"] = ( + dataframe["%-bb_width-period_10_SOL/USDT_5m"] - dataframe["%-bb_width-period_10_SOL/USDT_5m"].mean() + ) / dataframe["%-bb_width-period_10_SOL/USDT_5m"].std() + logger.info(f"%-bb_width-period_10 stats: {dataframe['%-bb_width-period_10_SOL/USDT_5m'].describe().to_string()}") def get_expected_columns(freqai_config: dict) -> list: indicators = ["rsi", "bb_width", "pct-change"] - periods = freqai_config.get("feature_parameters", {}).get("include_periods", [20]) - pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT"]) + periods = freqai_config.get("feature_parameters", {}).get("include_periods", [10, 20]) + pairs = freqai_config.get("include_corr_pairlist", ["SOL/USDT", "BTC/USDT"]) timeframes = freqai_config.get("include_timeframes", ["5m"]) shifts = [0] expected_columns = ["%-volatility", "%-day_of_week", "%-hour_of_day"] @@ -242,11 +256,17 @@ class FreqaiExampleStrategy(IStrategy): def populate_entry_trend(self, df: DataFrame, metadata: dict) -> DataFrame: enter_long_conditions = [ - qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"]), + qtpylib.crossed_above(df["rsi"], df["buy_rsi_pred"] + (5 if metadata["pair"] == "BTC/USDT" else 0)), df["tema"] > df["tema"].shift(1), df["volume"] > 0, - df["do_predict"] == 1 + df["do_predict"] == 1, + df["up_or_down"] == 1 ] + if enter_long_conditions: + df.loc[ + reduce(lambda x, y: x & y, enter_long_conditions), + ["enter_long", "enter_tag"] + ] = (1, "long") df["entry_signal"] = reduce(lambda x, y: x & y, enter_long_conditions) df["entry_signal"] = df["entry_signal"].rolling(window=2, min_periods=1).max().astype(bool) df.loc[ @@ -259,14 +279,16 @@ class FreqaiExampleStrategy(IStrategy): def populate_exit_trend(self, df: DataFrame, metadata: dict) -> DataFrame: exit_long_conditions = [ - (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"] - 5)) | + (qtpylib.crossed_above(df["rsi"], df["sell_rsi_pred"])) | (df["close"] < df["close"].shift(1) * 0.98) | (df["close"] < df["bb_lowerband"]), df["volume"] > 0, - df["do_predict"] == 1 + df["do_predict"] == 1, + df["up_or_down"] == 0 ] + time_exit = (df["date"] >= df["date"].shift(1) + pd.Timedelta(days=1)) df.loc[ - reduce(lambda x, y: x & y, exit_long_conditions), + (reduce(lambda x, y: x & y, exit_long_conditions)) | time_exit, "exit_long" ] = 1 return df