This commit is contained in:
zhangkun9038@dingtalk.com 2025-04-29 17:20:29 +08:00
parent fdc1fa0374
commit 5df9f23baf

View File

@ -72,31 +72,37 @@ class FreqaiExampleStrategy(IStrategy):
}
def featcaure_engineering_expand_all(self, dataframe: DataFrame, period: int, metadata: dict, **kwargs) -> DataFrame:
# 保留关键的技术指标
# 计算关键指标
dataframe["rsi"] = ta.RSI(dataframe, timeperiod=14)
# 计算短期和长期SMA
dataframe["sma_short"] = ta.SMA(dataframe, timeperiod=12)
dataframe["sma_long"] = ta.SMA(dataframe, timeperiod=26)
# 检查 SMA 列是否存在
if "sma_short" not in dataframe.columns or "sma_long" not in dataframe.columns:
logger.error("SMA 列缺失,无法生成买入信号")
raise ValueError("DataFrame 缺少必要的 SMA 列")
# 计算SMA交叉信号
dataframe["sma_cross"] = np.where(
dataframe["sma_short"] > dataframe["sma_long"], 1, -1
)
# 确保 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_pct"] = (dataframe["close"] - dataframe["bb_lowerband"]) / (
dataframe["bb_upperband"] - dataframe["bb_lowerband"]
)
# 成交量相关特征
dataframe["volume_ma"] = dataframe["volume"].rolling(window=20).mean()
dataframe["volume_pct"] = dataframe["volume"] / dataframe["volume_ma"]
# 价格变化特征
dataframe["pct_change"] = dataframe["close"].pct_change()
dataframe["pct_change_5"] = dataframe["close"].pct_change(5)
dataframe["pct_change_10"] = dataframe["close"].pct_change(10)
# 数据清理
for col in dataframe.columns:
@ -142,34 +148,36 @@ class FreqaiExampleStrategy(IStrategy):
label_period = self.freqai_info["feature_parameters"]["label_period_candles"]
# 定义目标变量为未来价格变化百分比(连续值)
dataframe["up_or_down"] = (
dataframe["target"] = (
dataframe["close"].shift(-label_period) - dataframe["close"]
) / dataframe["close"]
# 添加辅助目标变量
dataframe["target_5"] = (
dataframe["close"].shift(-5) - dataframe["close"]
) / dataframe["close"]
dataframe["target_10"] = (
dataframe["close"].shift(-10) - dataframe["close"]
) / dataframe["close"]
# 数据清理:处理 NaN 和 Inf 值
dataframe["up_or_down"] = dataframe["up_or_down"].replace([np.inf, -np.inf], np.nan)
dataframe["up_or_down"] = dataframe["up_or_down"].ffill().fillna(0)
for col in ["target", "target_5", "target_10"]:
dataframe[col] = dataframe[col].replace([np.inf, -np.inf], np.nan)
dataframe[col] = dataframe[col].ffill().fillna(0)
# 确保目标变量是二维数组
if dataframe["up_or_down"].ndim == 1:
dataframe["up_or_down"] = dataframe["up_or_down"].values.reshape(-1, 1)
if dataframe["target"].ndim == 1:
dataframe["target"] = dataframe["target"].values.reshape(-1, 1)
# 检查并处理 NaN 或无限值
dataframe["up_or_down"] = dataframe["up_or_down"].replace([np.inf, -np.inf], np.nan)
dataframe["up_or_down"] = dataframe["up_or_down"].ffill().fillna(0)
# 生成 %-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"]:
# 使用直接操作避免链式赋值
for col in ["target", "target_5", "target_10", "%-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 值
dataframe[col] = dataframe[col].ffill()
dataframe[col] = dataframe[col].fillna(dataframe[col].mean())
if dataframe[col].isna().any():
logger.warning(f"目标列 {col} 仍包含 NaN填充为默认值")
@ -178,8 +186,8 @@ class FreqaiExampleStrategy(IStrategy):
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()}")
logger.info(f"目标列形状:{dataframe['target'].shape}")
logger.info(f"目标列预览:\n{dataframe[['target', 'target_5', 'target_10']].head().to_string()}")
return dataframe
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame: