up3
Some checks are pending
Update Docker Hub Description / dockerHubDescription (push) Waiting to run

This commit is contained in:
zhangkun9038@dingtalk.com 2025-04-28 16:07:03 +08:00
parent 8777726441
commit 887c4778b4
3 changed files with 81 additions and 30 deletions

View File

@ -64,8 +64,12 @@
"data_kitchen": {
"fillna": "ffill"
},
"freqaimodel": "CatboostClassifier",
"purge_old_models": 2,
"freqaimodel": "XGBoostRegressor",
"model_training_parameters": {
"n_estimators": 100,
"learning_rate": 0.05,
"max_depth": 5
},
"train_period_days": 15,
"train_period_days": 180,
"backtest_period_days": 60,

View File

@ -64,7 +64,7 @@ services:
command: >
backtesting
--logfile /freqtrade/user_data/logs/freqtrade.log
--freqaimodel LightGBMRegressor
--freqaimodel XGBoostRegressor
--config /freqtrade/config_examples/config_freqai.okx.json
--config /freqtrade/templates/FreqaiExampleStrategy.json
--strategy-path /freqtrade/templates

View File

@ -71,40 +71,50 @@ class FreqaiExampleStrategy(IStrategy):
},
}
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
def feature_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
# 保留关键的技术指标
dataframe["%-rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe["%-macd"] = macd["macd"]
dataframe["%-macdsignal"] = macd["macdsignal"]
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
# 保留布林带相关特征
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["bb_pct"] = (dataframe["close"] - dataframe["bb_lowerband"]) / (dataframe["bb_upperband"] - dataframe["bb_lowerband"])
# 保留成交量相关特征
dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
dataframe["volume_roc"] = dataframe["volume"].pct_change(periods=10)
# 保留价格变化率
dataframe["close_roc"] = dataframe["close"].pct_change(periods=10)
# 改进数据清理
# 数据清理
for col in dataframe.columns:
if dataframe[col].dtype in ["float64", "int64"]:
# 使用更稳健的归一化方法
mean = dataframe[col].mean()
std = dataframe[col].std()
dataframe[col] = (dataframe[col] - mean) / std
dataframe[col] = dataframe[col].clip(-3, 3) # 限制在3个标准差内
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill().fillna(0)
dataframe.replace([np.inf, -np.inf], 0, inplace=True)
dataframe.ffill(inplace=True)
dataframe.fillna(0, inplace=True)
logger.info(f"特征工程完成,特征数量:{len(dataframe.columns)}")
return dataframe
# 保留关键的技术指标
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
macd = ta.MACD(dataframe, fastperiod=12, slowperiod=26, signalperiod=9)
dataframe["macd"] = macd["macd"]
dataframe["macdsignal"] = macd["macdsignal"]
# 保留布林带相关特征
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["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
# 数据清理
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
@ -134,7 +144,42 @@ class FreqaiExampleStrategy(IStrategy):
dataframe.fillna(0, inplace=True)
return dataframe
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
def set_freqai_targets(self, dataframe: DataFrame, metadata: dict, **kwargs) -> DataFrame:
logger.info(f"设置 FreqAI 目标,交易对:{metadata['pair']}")
if "close" not in dataframe.columns:
logger.error("数据框缺少必要的 'close'")
raise ValueError("数据框缺少必要的 'close'")
try:
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 确保目标变量是二维数组
if dataframe["up_or_down"].ndim == 1:
dataframe["up_or_down"] = dataframe["up_or_down"].values.reshape(-1, 1)
# 生成 %-volatility 特征
dataframe["%-volatility"] = dataframe["close"].pct_change().rolling(20).std()
# 确保 &-buy_rsi 列的值计算正确
dataframe["&-buy_rsi"] = ta.RSI(dataframe, timeperiod=14)
# 数据清理
for col in ["&-buy_rsi", "up_or_down", "%-volatility"]:
# 使用直接操作避免链式赋值
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill() # 替代 fillna(method='ffill')
dataframe[col] = dataframe[col].fillna(dataframe[col].mean()) # 使用均值填充 NaN 值
if dataframe[col].isna().any():
logger.warning(f"目标列 {col} 仍包含 NaN填充为默认值")
except Exception as e:
logger.error(f"创建 FreqAI 目标失败:{str(e)}")
raise
# Log the shape of the target variable for debugging
logger.info(f"目标列形状:{dataframe['up_or_down'].shape}")
logger.info(f"目标列预览:\n{dataframe[['up_or_down', '&-buy_rsi']].head().to_string()}")
return dataframe
logger.info(f"设置 FreqAI 目标,交易对:{metadata['pair']}")
if "close" not in dataframe.columns:
logger.error("数据框缺少必要的 'close'")
@ -185,9 +230,10 @@ class FreqaiExampleStrategy(IStrategy):
# 生成 up_or_down 信号(非 FreqAI 目标)
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 使用历史数据生成 up_or_down 信号
# 使用未来价格变化方向生成 up_or_down 信号
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
dataframe["up_or_down"] = np.where(
dataframe["close"] > dataframe["close"].shift(1), 1, 0
dataframe["close"].shift(-label_period) > dataframe["close"], 1, 0
)
# 动态设置参数
@ -208,12 +254,12 @@ class FreqaiExampleStrategy(IStrategy):
# 简化动态参数生成逻辑
# 放松 buy_rsi 和 sell_rsi 的生成逻辑
# 计算 buy_rsi_pred 并清理 NaN 值
dataframe["buy_rsi_pred"] = dataframe["&-buy_rsi"].rolling(window=10).mean().clip(30, 50)
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(dataframe["buy_rsi_pred"].mean())
dataframe["buy_rsi_pred"] = dataframe["rsi"].rolling(window=10).mean().clip(30, 50)
dataframe["buy_rsi_pred"] = dataframe["buy_rsi_pred"].fillna(dataframe["buy_rsi_pred"].median())
# 计算 sell_rsi_pred 并清理 NaN 值
dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 40
dataframe["sell_rsi_pred"] = dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].mean())
dataframe["sell_rsi_pred"] = dataframe["buy_rsi_pred"] + 20
dataframe["sell_rsi_pred"] = dataframe["sell_rsi_pred"].fillna(dataframe["sell_rsi_pred"].median())
# 计算 stoploss_pred 并清理 NaN 值
dataframe["stoploss_pred"] = -0.1 - (dataframe["%-volatility"] * 10).clip(0, 0.25)
@ -279,6 +325,7 @@ class FreqaiExampleStrategy(IStrategy):
(df["rsi"] < df["buy_rsi_pred"]), # RSI 低于买入阈值
(df["volume"] > df["volume"].rolling(window=10).mean() * 1.2), # 成交量高于近期均值20%
(df["close"] > df["bb_middleband"]), # 价格高于布林带中轨
(df["macd"] > df["macdsignal"]), # MACD 金叉
(df["do_predict"] == 1) # 确保模型预测为买入
]
if enter_long_conditions: