Freqtrade Orderflow 订单流数据分析实战:公开成交数据配置、下载与策略列使用指南
本文基于 Freqtrade 官方文档 docs/advanced-orderflow.md 展开,讲解如何利用交易所公开逐笔成交数据(public trades)在回测与实盘中做订单流(orderflow)分析:如何开启 use_public_trades、如何配置 orderflow 参数、如何用 --dl-trades 下载历史成交数据、策略 dataframe 中新增的 11 个订单流列各代表什么,以及 footprint 图表(成交量分布)与失衡(imbalances)检测的底层算法。读完后你可以独立搭建一套基于买卖盘口不平衡、Delta 与堆叠失衡的订单流指标策略。
功能定位与适用限制
Freqtrade 的 orderflow 功能允许你把交易所的逐笔公开成交记录(public trades)聚合到每一根 K 线上,从而在策略中分析订单流动态。官方文档将其明确标注为实验性(beta)特性,使用前后需要注意三点限制:
- 功能处于 beta 阶段:未来版本中配置项和列结构可能发生变化,遇到问题应向官方仓库反馈;
- 尚未与 FreqAI 测试组合使用:把 orderflow 和 FreqAI 两个功能叠加目前不在支持范围内;
- 性能开销显著:orderflow 需要原始逐笔成交数据,数据量远大于 OHLCV。首次启动时 Freqtrade 需要下载覆盖最近若干根 K 线的全部成交记录,导致启动变慢;开启后内存占用也会明显上升,需要预留足够的计算资源。
从源码结构看,该功能的所有计算集中在 freqtrade/data/converter/orderflow.py,新增列的完整清单定义在 freqtrade/constants.py 的 ORDERFLOW_ADDED_COLUMNS 常量中(trades、orderflow、imbalances、stacked_imbalances_bid、stacked_imbalances_ask、max_delta、min_delta、bid、ask、delta、total_trades),与文档描述一一对应。
开启功能:在 exchange 段启用 use_public_trades
第一步是在 config.json 的 exchange 段中将 use_public_trades 设为 true:
"exchange": {
...
"use_public_trades": true,
}
这一步不是"可选开关"那么简单。在配置校验层 freqtrade/configuration/config_validation.py 中,_validate_orderflow 会检查:一旦 exchange.use_public_trades 为 true,而配置中缺少顶层 orderflow 段,会直接抛出 ConfigurationError("Orderflow is a required configuration key when using public trades.")。也就是说,开启公开成交数据后,orderflow 配置段是必填项,两个配置必须同时存在。
策略侧的入口在 freqtrade/strategy/interface.py 的 _if_enabled_populate_trades 方法:当检测到 exchange.use_public_trades 为真时,它会以当前 dataframe 的日期范围构造 timerange,通过 self.dp.trades(...) 从 DataProvider 取成交记录,再调用 populate_dataframe_with_trades 把订单流列填充进你策略使用的 dataframe,并按交易对缓存已计算好的分组结果。由于该填充发生在 advise_indicators 阶段之前,你的 populate_indicators 中可以直接读取这些新列。
配置 orderflow 处理参数
orderflow 段共有 6 个参数,完整配置示例如下(来自官方文档):
"orderflow": {
"cache_size": 1000,
"max_candles": 1500,
"scale": 0.5,
"stacked_imbalance_range": 3, // needs at least this amount of imbalance next to each other
"imbalance_volume": 1, // filters out below
"imbalance_ratio": 3 // filters out ratio lower than
}
各参数含义、schema 约束与源码中的作用如下表:
| 参数 | 作用 | schema 约束(config_schema.py) | 源码中的行为 |
|---|---|---|---|
cache_size |
多少根历史 orderflow K 线被缓存,而不是每根新 K 线重新计算 | 数值,最小 1,默认 1500 | 计算完成后取 dataframe.tail(cache_size) 整体缓存;下一轮若某根 K 线命中缓存则直接复制结果,跳过全部计算 |
max_candles |
只为最近多少根 K 线获取并聚合成交数据 | 数值,最小 1,默认 1500 | 策略侧仅聚合晚于 dataframe.tail(max_candles).date.iat[0] 的成交;交易侧 needed_candle_for_trades_ms 用它决定从交易所拉取多少根 K 线量的成交 |
scale |
footprint 图表的价格分箱(bin)宽度 | 数值,最小 0.0 | 成交价按 round(price / scale) * scale 取整到 scale 的整数倍后分箱聚合 |
stacked_imbalance_range |
连续失衡价格层的最小个数 | 数值,最小 0 | 用于 stacked_imbalance 函数,识别"堆叠失衡"区间的起始价格 |
imbalance_volume |
失衡判定的最低总量阈值 | 数值,最小 0 | 价格层总成交量低于该值时,失衡直接判为 False |
imbalance_ratio |
失衡判定所需的 bid/ask 成交量比值下限 | 数值,最小 0.0 | bid 失衡要求本层 bid 量 / 上一层 ask 量 > 该比值 |
在 schema 中,max_candles 和 scale 属于必填字段(required 数组),而 cache_size 缺省为 1500。注意 scale 是绝对价格单位而非百分比:例如 scale: 0.5 表示每 0.5 个价格单位聚合成一个价格层,选择时应与所交易品种的典型价差量级匹配,分箱过粗会丢失细节,过细则单箱成交量被摊薄,难以触发失衡阈值。
为回测下载历史成交数据
回测需要历史逐笔成交数据,通过 freqtrade download-data 命令的 --dl-trades 标志下载(定义于 freqtrade/commands/cli_options.py 的 download_trades 选项,帮助文本为 "Download trades instead of OHLCV data")。官方文档给出的示例:
freqtrade download-data -p BTC/USDT:USDT --timerange 20230101- --trading-mode futures --timeframes 5m --dl-trades
该命令的执行链是:download-data 进入数据下载流程后,逐笔拉取由 freqtrade/data/history/history_utils.py 驱动——先读取本地已有成交文件,再调用 freqtrade/exchange/exchange.py 的 get_historic_trades(内部按交易对、since/until 时间窗,支持 time 或 id 两种游标分页方式)增量抓取新成交,去重后落盘。--trading-mode futures 决定成交数据归属现货还是合约交易模式,--timeframes 指定 K 线周期,因为 orderflow 列是按 K 线周期聚合的。
数据可用性提醒:并非所有交易所都提供历史公开成交数据。对于不支持的交易对/交易所,使用 --dl-trades 启动下载时 Freqtrade 会打印警告。此外同一目录下的 --convert 标志可以把已下载的成交数据转换为 OHLCV(主要用于没有历史 OHLCV 的交易所),这属于 download-data 文档 的范畴,与 orderflow 分析相互独立但共用同一份成交文件。
策略中自动生成的订单流列
启用后,populate_dataframe_with_trades(freqtrade/data/converter/orderflow.py)会为 dataframe 的每根 K 线填充以下列(文档列表 + 源码常量一致):
dataframe["trades"] # 本根 K 线内每笔成交的明细列表
dataframe["orderflow"] # footprint 图表 dict(见下文结构)
dataframe["imbalances"] # 本根 K 线的买卖盘失衡 dict
dataframe["bid"] # 本根 K 线 bid 方向总成交量
dataframe["ask"] # 本根 K 线 ask 方向总成交量
dataframe["delta"] # ask 与 bid 成交量之差
dataframe["min_delta"] # K 线内逐笔 delta 累计和的最小值
dataframe["max_delta"] # K 线内逐笔 delta 累计和的最大值
dataframe["total_trades"] # 成交笔数
dataframe["stacked_imbalances_bid"] # bid 侧堆叠失衡区间起始价格列表
dataframe["stacked_imbalances_ask"] # ask 侧堆叠失衡区间起始价格列表
在源码中可以确认这些列的计算细节:
- bid/ask 归属约定:
side == "sell"的成交计入bid方向,side == "buy"的成交计入ask方向——即以主动卖盘(砸向买盘)为 bid 量、主动买盘(吃掉卖盘)为 ask 量,delta = ask - bid,正值表示主动买盘占优; - min/max_delta:对 K 线内逐笔 delta 做累计和(cumsum),取该曲线的最大值与最小值,反映 K 线内部主动买卖力量的最强峰值;
- 计算窗口:只处理晚于最近
max_candles根 K 线起始时间的成交,更早的历史不会参与聚合,这正是内存开销可控的关键; - 异常处理:整个填充过程若抛错会被包装为
DependencyException并记录日志,而不是静默产出空列。
一个最小可用的策略集成示例(文档原版):
def populate_indicators(self, dataframe: DataFrame, metadata: dict) -> DataFrame:
# Calculating cumulative delta
dataframe["cum_delta"] = cumulative_delta(dataframe["delta"])
# Accessing total trades
total_trades = dataframe["total_trades"]
...
def cumulative_delta(delta: Series):
cumdelta = delta.cumsum()
return cumdelta
累计 delta(cumulative delta)是订单流分析中最常用的基础指标:对 delta 列求累计和即可得到资金主动流向的累积曲线,可配合均线或背离逻辑构建信号。
Footprint 图表:dataframe["orderflow"] 列
orderflow 列保存的是每根 K 线的 footprint(足迹图):按 scale 分箱后,各价格层上主动买/卖成交量与笔数的分布。其结构为 {价格: 统计dict}:
{
"price": {
"bid_amount": 0.0,
"ask_amount": 0.0,
"bid": 0,
"ask": 0,
"delta": 0.0,
"total_volume": 0.0,
"total_trades": 0
}
}
各字段含义:
| 字段 | 含义 |
|---|---|
| key(价格) | 价格层,按 scale 间隔分箱(round(price/scale)*scale) |
bid_amount |
该价格层上买方向(side=sell 主动卖盘)总成交量 |
ask_amount |
该价格层上卖方向(side=buy 主动买盘)总成交量 |
bid / ask |
该价格层的买/卖订单笔数 |
delta |
该价格层 ask_amount 与 bid_amount 之差 |
total_volume |
该价格层总量(ask_amount + bid_amount) |
total_trades |
该价格层总笔数(ask + bid) |
对应实现是 freqtrade/data/converter/orderflow.py 中的 trades_to_volumeprofile_with_total_delta_bid_ask:先用 np.where 把 side 映射为 bid/ask 的量与笔数,把成交价取整到 scale 的倍数,再 groupby("price").sum() 完成分箱聚合。footprint 分布可以让你直接看到单根 K 线内资金在哪些价位激烈换手,例如高价位出现集中的 ask_amount 峰通常意味着买方在该位置持续吃单上攻。
原始成交明细:dataframe["trades"] 列
trades 列是一个列表,保存本根 K 线时间窗内发生的所有逐笔成交,用于比列级指标更细粒度的自定义分析。每条记录为 dict,包含(文档列出):
timestamp:成交时间戳(毫秒);date:成交日期;price:成交价格;amount:成交数量;side:买或卖;id:交易所唯一成交标识;cost:成交总价值(price × amount)。
从源码结构看,存储进 trades 列的记录来源于 freqtrade/constants.py 定义的 DEFAULT_TRADES_COLUMNS(timestamp、id、type、side、price、amount、cost)外加 date 列,因此在实际使用中每条记录还会出现 type(limit/market 等订单类型)字段,聚合时用于剔除的 candle_start/candle_end 辅助列不会写入该列。
失衡检测:imbalances 与 stacked_imbalances
imbalances 列提供每根 K 线的盘口失衡信息:当某一价格层的 ask 与 bid 成交量出现显著差异时即构成失衡。其结构为 {价格: {bid_imbalance: 布尔, ask_imbalance: 布尔}}:
{
"price": {
"bid_imbalance": false,
"ask_imbalance": false
}
}
算法实现(trades_orderflow_to_imbalances)值得逐行理解,因为这里采用的是斜向对比而非同层对比:
ask = df.ask.shift(-1)——把 ask 列向下平移一格,即用价格层 N 的 bid 量与价格层 N+1 的 ask 量比较(footprint 分析中标准的对角比较);bid_imbalance = (bid / ask_above) > imbalance_ratio:本层 bid 量相对上一层 ask 量比值超过imbalance_ratio时判定为 bid 失衡;ask_imbalance对称处理;- 再按
total_volume < imbalance_volume把低量级的价格层强制置False,避免小盘噪音触发失衡。
stacked_imbalances_bid / stacked_imbalances_ask 列则进一步做堆叠失衡识别(stacked_imbalance 函数):把布尔失衡序列分组统计连续 True 段,凡是连续失衡层数达到 stacked_imbalance_range 的区间,就返回该区间起始价格层。多个这样的起始价列表即构成"堆叠失衡区"——在实盘语义上,连续多层买/卖盘压倒性占优的位置,常被视为短期支撑/阻力或流动性真空边界。注意列表记录的是"失衡区间的开始价格"而非全部失衡价格,策略中若需要区间端点,可用 scale 反推。
缓存机制与性能调优
orderflow 的计算成本决定了两个参数直接决定运行效率:
cache_size:populate_dataframe_with_trades每次运行结束后保存dataframe.tail(cache_size)的副本作为缓存;下一根新 K 线到来时,凡是 date 命中缓存的 K 线,其 11 个订单流列直接从缓存复制,不再重算 footprint 和失衡。cache_size越大,重算越少、内存越高——文档示例取 1000,schema 默认 1500,可按回测时长与内存权衡;max_candles:双重作用——策略侧只聚合最近max_candles根 K 线的成交;交易侧 freqtrade/exchange/exchange.py 的needed_candle_for_trades_ms用min(max_candles, 单次可拉取 K 线数)决定从交易所预取的成交时间窗(并额外多取 1 根 K 线作为安全边界)。_now_is_time_to_refresh_trades则在新 K 线形成后触发增量拉取,只抓自上一笔缓存成交 id 之后的新记录并合并去重,因此实盘运行期每个周期的增量成本很低,大头在首次冷启动。
回测时如果观察到启动阶段耗时集中,可以优先调小 max_candles(以覆盖策略回看窗口为准);如果实盘中每周期延迟偏高,再考虑增大 cache_size。
仓库中可深入阅读的参考文件
- 文档原文:docs/advanced-orderflow.md
- 核心实现:freqtrade/data/converter/orderflow.py(K 线分组、footprint 分箱、失衡与堆叠失衡算法、缓存逻辑)
- 列常量:freqtrade/constants.py(
ORDERFLOW_ADDED_COLUMNS、DEFAULT_TRADES_COLUMNS、TRADING_MODES) - 配置 schema:freqtrade/config_schema/config_schema.py(
orderflow段各参数类型、最小值与默认值) - 配置校验:freqtrade/configuration/config_validation.py(
use_public_trades与orderflow段的联动校验) - 策略填充入口:freqtrade/strategy/interface.py(
_if_enabled_populate_trades,按交易对缓存分组结果) - 成交拉取与刷新:freqtrade/exchange/exchange.py(
trades缓存、get_historic_trades、needed_candle_for_trades_ms、_now_is_time_to_refresh_trades) - 下载入口选项:freqtrade/commands/cli_options.py(
--dl-trades) - 单元测试:tests/data/test_converter_orderflow.py
- 测试样例数据:tests/testdata/orderflow(含
populate_dataframe_with_trades_DF.feather等预期结果文件,可用于核对列结构与聚合逻辑)
小结
Freqtrade 的 orderflow 功能把"逐笔成交 → K 线级订单流指标"这条链路完整地工程化了:--dl-trades 负责数据落盘,use_public_trades + orderflow 配置负责开关与分箱/失衡阈值,populate_dataframe_with_trades 负责带缓存的聚合计算,最终在 populate_indicators 前交付 delta、cum_delta、footprint、imbalances 与堆叠失衡区等可直接建模的列。作为 beta 特性,建议先在回测环境验证信号逻辑与资源消耗,再谨慎投入实盘,并注意它当前不与 FreqAI 组合使用。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00