FreqAI 数据管道拆解:原始K线到模型张量,中间到底发生了什么
【免费下载链接】freqtradeFree, open source crypto trading bot项目地址: https://gitcode.com/GitHub_Trending/fr/freqtrade
刚用download-data拉回一整年 5m 的 BTC/USDT K 线,想直接喂给 LSTM?它离"可用"还很远:列里混着特征和标签、指标前几百行全是 NaN、训练窗里还藏着"未来数据"。Freqtrade 的 FreqAI 模块把这些脏活统一收在FreqaiDataKitchen(可以理解为 FreqAI 的"数据厨房",负责把生食材加工成模型能吃的菜)这个类里,完成全部数据转换工作。
整个流程像一条管道:原始 K 线从入口进来,依次经过过滤器(清洗校验)、变换器(特征工程、标准化)、出口(张量)。下文就按管道阶段拆解每一站发生了什么。
🧭 管道概览:K 线进,张量出
先看全景:策略负责算指标,数据厨房负责加工,预测模型负责消费。
值得留意的一点:每个交易对、每次训练或推理,都会新建一个FreqaiDataKitchen实例。它不持久化,生命周期就是"这一次加工",所以不存在跨币种、跨周期的状态污染。
特征和标签是怎么被认出来的
管道第一站不写代码,而是认名字。约定很简单:列名带%的是特征,带&的是标签(&开头的那列会被当作训练目标)。数据厨房扫一遍 DataFrame 列名就能自动建好特征列表:
def find_features(self, dataframe): features = [c for c in dataframe.columns if "%" in c] if not features: raise OperationalException("Could not find any features!") self.training_features_list = features def find_labels(self, dataframe): self.label_list = [c for c in dataframe.columns if "&" in c]上面两段来自data_kitchen.py的find_features和find_labels方法。这个约定的好处是零维护:你在策略里加了一列%my_indicator,下一轮训练它自动进模型;忘加%前缀则整条链路直接报错,而不是静默少一列特征。识别出特征之后,数据还带着原始量纲和空值,下一步要先做特征工程再谈清洗。
配置驱动的指标展开:维度从哪来
特征工程由feature_parameters这段配置触发:
"feature_parameters": { "include_timeframes": ["5m", "1h"], "indicator_periods_candles": [1, 10], "include_shifted_candles": 2, "include_corr_pairlist": ["ETH/USDT"] }数据厨房的populate_features会遍历include_timeframes里的每个周期,把策略中feature_engineering_expand_all在不同candle_access_prefix下算出的指标按indicator_periods_candles逐个展开,再ffill对齐合并回主周期;然后为每个特征追加include_shifted_candles个滞后副本(列名带_shift-n后缀),include_corr_pairlist里的关联币种特征也会拼进来。
所以特征维度是"配置 × 周期 × 滞后 × 币种"的乘积,很容易膨胀到几百列。膨胀本身不可怕——后面管道里的 PCA 和常量剔除就是为它准备的——但这也意味着startup_candle_count必须给足,否则展开后的前段几乎全是 NaN。数据维度定下来了,接下来的过滤器要处理的就是这些 NaN。
🧹 NaN 占比超 10% 时系统做了什么
NaN 处理是整条管道里最容易被忽略、也最影响回测可信度的一环。训练和预测走的是两条不同分支:
if training_filter: filtered_df = filtered_df[drop_index == 0] # 训练:整行丢弃 else: filtered_df.fillna(0, inplace=True) # 预测:用 0 占位 self.do_predict = np.array(~drop_index).astype(int) # 无效行打标记上面是data_kitchen.py中filter_features方法的核心逻辑。训练时任何含 NaN 的行直接删除,日志会报出丢了多少行;一旦丢弃比例超过 10%,系统会警告并点名 NaN 最多的那列——通常就是某条指标的最小周期没满足。预测时则相反:行结构必须保留(策略依赖它对齐 K 线),NaN 填 0 占位,do_predict标记哪些行不可信,策略端拿到标记后不会基于这些行开单。
如果训练数据 100% 被 NaN 清空,系统会直接抛异常并提示"回测区间前的数据下载不够",而不是训练出一个空壳模型。到这里数据已经干净了,但"干净"≠"没泄露",下一站要解决的是时间维度的切分。
滑动窗口怎么配才不泄露未来数据
时序数据最怕随机切分:一旦打乱,"未来"的 K 线就混进了训练集,回测收益虚高。FreqAI 的解法是滑动窗口:
while True: timerange_train.stopts = timerange_train.startts + train_period_days tr_training_list.append(timerange_train.timerange_str) timerange_backtest.startts = timerange_train.stopts # 回测窗紧跟训练窗 timerange_backtest.stopts = timerange_backtest.startts + bt_period tr_backtesting_list.append(timerange_backtest.timerange_str) if timerange_backtest.stopts >= config_timerange.stopts: break timerange_train.startts += int(bt_period) # 整体前滑上面是split_timerange方法的骨架。每个训练窗结束后的下一段才是回测窗,然后整体向前滑动backtest_period_days再训一个新模型。效果是:每个时点上的预测,只来自一个"只见过它之前数据"的模型。
配置上只有train_period_days和backtest_period_days两个旋钮,默认 28 天训练 + 7 天回测。另外两个和时序强相关的参数值得一提:
weight_factor:>0 时按指数曲线给训练样本加权,越新的 K 线权重越高,用来应对市场状态漂移;test_size:每个训练窗内部再切一小段做验证,设为 0 则整窗全用于训练。
窗口切好、数据也干净了,但特征尺度仍然五花八门——波动率是 0~1 的小数,量纲可能是六位数的价格。标准化管道来接手最后一站。
⚙️ 标准化与降维:Pipeline 到张量
管道末端是define_data_pipeline(位于freqai_interface.py),前两步固定,后四步看配置:
pipe_steps = [ ("const", ds.VarianceThreshold(threshold=0)), # 移除常量列 ("scaler", SKLearnWrapper(MinMaxScaler(feature_range=(-1, 1)))), # 缩放到 [-1, 1] ] if ft_params.get("principal_component_analysis", False): pipe_steps.append(("pca", ds.PCA(n_components=0.999))) # 保留 99.9% 方差 if ft_params.get("use_DBSCAN_to_remove_outliers", False): pipe_steps.append(("dbscan", ds.DBSCAN(n_jobs=threads))) # 剔除离群点VarianceThreshold(threshold=0)清掉那些展开后变成常量的"僵尸特征";MinMaxScaler把所有列压进 [-1, 1];开了 PCA 会在降维后再补一次 scaler。DBSCAN 那一步的原理图长这样:
特征空间里邻域密度足够低的孤立点被判定为噪声剔除。管道出口处,DataFrame 还差最后一步:freqai/torch/下的PyTorchDataConvertor把train_features这类 DataFrame 直接转成 float32 张量,标签按任务类型转 long(分类)或 float(回归),再交给模型的fit/predict。对 LSTM、Transformer 这类模型,窗口切分和批次维度由各自训练器处理,厨房只保证"进来的是干净的二维特征矩阵"。
整条链路串起来
把各站连起来就是一句话:K 线 → 命名约定识别特征 → 多周期指标展开 → NaN 双模式清洗 → 滑动窗口切分 → Pipeline 标准化降维 → 张量。三个入口对应三样东西:配置(feature_parameters决定展开和管道步骤、train_period_days决定窗口节奏)、命名约定(决定哪些列进模型)、日志(NaN 丢弃比例、被点名的最差列)。
管道跑通之后,接下来值得看的有两处:freqtrade/freqai/RL/下的强化学习接口,把同一份 data_dictionary 直接喂给 RL 环境;以及训练后生成的特征重要性图表,用它定位那些占维度却不贡献信息量的特征。相关文档见 FreqAI 总览、特征工程指南 与 FreqAI 运行说明。
【免费下载链接】freqtradeFree, open source crypto trading bot项目地址: https://gitcode.com/GitHub_Trending/fr/freqtrade
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考