Freqtrade 第15章:FreqAI 特征工程
特征工程是机器学习交易策略的核心环节。FreqAI 提供了完整的特征工程管道,涵盖特征构建、筛选、标准化和降维等全流程。本章详细讲解如何构建高质量的特征集。
特征构建方法
基础特征(Basic Features)
基础特征在 feature_engineering_expand_basic 方法中定义,每个特征会按 shift 参数生成对应的延时版本。
def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame:
# 动量指标
dataframe["%-rsi"] = ta.RSI(dataframe, timeperiod=14)
dataframe["%-williams_r"] = ta.WILLR(dataframe, timeperiod=14)
dataframe["%-cci"] = ta.CCI(dataframe, timeperiod=20)
# 趋势指标
dataframe["%-adx"] = ta.ADX(dataframe, timeperiod=14)
dataframe["%-macd"] = ta.MACD(dataframe)["macd"]
dataframe["%-macd_signal"] = ta.MACD(dataframe)["macdsignal"]
# 波动性指标
dataframe["%-atr"] = ta.ATR(dataframe, timeperiod=14)
dataframe["%-natr"] = ta.NATR(dataframe, timeperiod=14)
# 成交量指标
dataframe["%-obv"] = ta.OBV(dataframe)
dataframe["%-volume_sma"] = ta.SMA(dataframe["volume"], timeperiod=20)
return dataframe
扩展特征(Expanded Features)
扩展特征在 feature_engineering_expand_all 方法中定义,通常包含多周期计算。
def feature_engineering_expand_all(self, dataframe: DataFrame, **kwargs) -> DataFrame:
# 布林带多周期
for period in [10, 20, 50]:
bb = ta.BBANDS(dataframe, timeperiod=period)
dataframe[f"%-bb_upper_{period}"] = bb["bbupper"]
dataframe[f"%-bb_lower_{period}"] = bb["bblower"]
dataframe[f"%-bb_width_{period}"] = bb["bbupper"] - bb["bblower"]
# 多种移动平均线
for period in [5, 10, 20, 30, 50, 100]:
dataframe[f"%-sma_{period}"] = ta.SMA(dataframe, timeperiod=period)
dataframe[f"%-ema_{period}"] = ta.EMA(dataframe, timeperiod=period)
# 价格通道
for period in [20, 50]:
dataframe[f"%-hh_{period}"] = dataframe["high"].rolling(period).max()
dataframe[f"%-ll_{period}"] = dataframe["low"].rolling(period).min()
return dataframe
异常值检测技术
标准差方法
FreqAI 通过 DI_threshold 参数控制异常值检测的灵敏度。
{
"freqai": {
"feature_parameters": {
"DI_threshold": 0.9
}
}
}
DI_threshold = 1.0:不进行异常值过滤DI_threshold = 0.9:移除标准差超过 0.9 分位数的极端值DI_threshold = 0.5:严格过滤,移除更多异常值
手工异常值处理
在特征工程方法中,可以手动处理异常值:
def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame:
# 计算特征后,使用分位数裁剪
for col in dataframe.columns:
if col.startswith("%-"):
lower = dataframe[col].quantile(0.01)
upper = dataframe[col].quantile(0.99)
dataframe[col] = dataframe[col].clip(lower, upper)
return dataframe
PCA 降维
什么是 PCA
PCA(主成分分析)是一种线性降维技术,将高维特征压缩为少数"主成分"。FreqAI 支持内置的 PCA 功能。
{
"freqai": {
"feature_parameters": {
"principal_component_analysis": true,
"PCA_components": 20
}
}
}
何时使用 PCA
| 场景 | 建议 |
|---|---|
| 特征数 < 50 | 不需要 PCA |
| 特征数 50-200 | 可选 PCA,设 PCA_components=20-30 |
| 特征数 > 200 | 强烈建议使用 PCA |
数据管道配置
完整配置示例
{
"freqai": {
"enabled": true,
"train_period_days": 60,
"backtest_period_days": 14,
"live_retrain_hours": 6,
"identifier": "feature_demo",
"feature_parameters": {
"shift": 2,
"include_corr_pairlist": true,
"corr_pairlist": ["BTC/USDT", "ETH/USDT"],
"DI_threshold": 0.95,
"weight_factor": 0.95,
"principal_component_analysis": true,
"PCA_components": 30,
"use_SVM_to_remove_outliers": true,
"stratify_training_data": false
},
"data_split_parameters": {
"test_size": 0.2,
"random_state": 42
}
}
}
参数详解
| 参数 | 说明 | 建议值 |
|---|---|---|
shift | 特征的延时偏移数 | 2-5 |
include_corr_pairlist | 是否包含相关交易对的特征 | true |
weight_factor | 样本权重衰减因子 | 0.9-0.99 |
use_SVM_to_remove_outliers | 使用 SVM 检测异常值 | 视数据质量而定 |
特征标准化
FreqAI 自动对特征进行标准化处理,确保不同量纲的特征具有可比性。
标准化方法
- Z-score 标准化:使特征均值为 0,标准差为 1
- MinMax 标准化:将特征缩放到 [0, 1] 区间
标准化参数隐藏在 model_training_parameters 中:
{
"freqai": {
"model_training_parameters": {
"standardize": true,
"standardize_type": "zscore"
}
}
}
自动化数据下载
FreqAI 在训练开始前会自动下载所需的历史数据:
# 手动预下载(可选)
freqtrade download-data --exchange binance --days 90 -p BTC/USDT ETH/USDT
如果数据不足,FreqAI 会在日志中提示缺失的时间范围并自动补充下载。
常见特征模板
价量特征模板
def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame:
# 价格变化率
for period in [1, 3, 5, 10]:
dataframe[f"%-pct_change_{period}"] = dataframe["close"].pct_change(period)
# 价差特征
dataframe["%-spread"] = (dataframe["high"] - dataframe["low"]) / dataframe["close"]
# 量价关系
dataframe["%-vwap"] = ta.VWAP(dataframe)
dataframe["%-volume_ratio"] = dataframe["volume"] / dataframe["volume"].rolling(20).mean()
# 收益率分布
for period in [5, 10, 20]:
returns = dataframe["close"].pct_change(period)
dataframe[f"%-return_skew_{period}"] = returns.rolling(20).skew()
dataframe[f"%-return_kurt_{period}"] = returns.rolling(20).kurt()
return dataframe
跨交易对特征
def feature_engineering_expand_basic(self, dataframe: DataFrame, **kwargs) -> DataFrame:
# 对于每个交易对,计算相对于 BTC 的相对强度
if "btc" in str(kwargs.get("pair", "")).lower():
return dataframe
# 假设外部数据已加载为 btcd
btcd = kwargs.get("btc_dataframe")
if btcd is not None:
dataframe["%-rel_strength"] = (
dataframe["close"] / btcd["close"]
).pct_change(10)
return dataframe
特征选择最佳实践
- 从少到多:从 10-20 个核心特征开始逐步扩展
- 避免未来信息:确保所有特征只用当前可用的数据
- 监控特征重要性:利用模型内置的特征重要性评估剔除无用特征
- 周期性检查:市场结构变化时及时调整特征集