功能
多时间周期分析
按每个值实际可获知的时间,跨周期重采样并重新对齐数据
如何在小时 K 线上使用日频指标,同时避免窥探未来?日 K 线以开盘时间标注时,其收盘价仍要到结束时才可获知。VBT 按每个数值实际可用的时间进行重采样和重新对齐,帮助您在 Python 多时间周期回测中避免前视偏差。
h1_data = vbt.GBMOHLCData.pull(
"SYN",
start="2024-01-01",
end="2025-01-01",
timeframe="1h",
std=0.002,
seed=7,
)
d1_data = h1_data.resample("1d")
d1_uptrend = d1_data.close > d1_data.close.rolling(10).mean()
naive_filter = d1_uptrend.reindex(h1_data.index, method="ffill")
safe_filter = (
d1_uptrend.vbt.realign_closing(h1_data.index)
.fillna(False)
.astype(bool)
)
h1_sma = h1_data.close.rolling(24).mean()
entries = h1_data.close.vbt.crossed_above(h1_sma)
exits = h1_data.close.vbt.crossed_below(h1_sma)
pf = vbt.PF.from_signals(
h1_data,
entries=pd.concat({
"naive": entries & naive_filter,
"safe": entries & safe_filter,
}, axis=1),
exits=exits,
fees=0.0005,
)
pf.stats(["total_return", "sharpe_ratio", "win_rate", "total_trades"], agg_func=None) Total Return [%] Sharpe Ratio Win Rate [%] Total Trades
naive 42.179045 0.863159 26.050420 239
safe -56.766534 -1.172668 18.552036 222pf.value.vbt.plot().show()简单版本看似盈利,但它是错误的。当日收盘价上穿均线时,简单过滤器在午夜就已启用,比该收盘价出现早了 23 小时:
filters = pd.DataFrame({"naive": naive_filter, "safe": safe_filter})
filters.loc["2024-01-28 23:00":"2024-01-30 00:00"].iloc[[0, 1, 2, 22, 23, 24, 25]] naive safe
2024-01-28 23:00:00+00:00 False False
2024-01-29 00:00:00+00:00 True False
2024-01-29 01:00:00+00:00 True False
2024-01-29 21:00:00+00:00 True False
2024-01-29 22:00:00+00:00 True False
2024-01-29 23:00:00+00:00 True True
2024-01-30 00:00:00+00:00 True True按信息实际存在的时间对齐过滤器后,同样的策略亏损。两条曲线之间的差距完全来自前视偏差。
标记为 23:00 的小时行表示从 23:00 到午夜的 K 线。其收盘价和日收盘价在该 K 线结束时同时可获知。这一行的安全过滤器用于在 K 线收盘时作出决策。若在下一根 K
线执行,信号回测页面介绍了延迟信号的方法。
在一个策略中组合时间周期
为每个时间周期分配任务,再将结果对齐到作出决策的 K 线:
| 研究想法 | 如何构建 |
|---|---|
| 仅在日频趋势一致时执行小时入场 | 如上所示,计算日频过滤器,并对齐到小时收盘 |
| 使用四小时动量信号和 15 分钟入场 | 在四小时 K 线上计算,再将输出重新对齐到 15 分钟索引 |
| 比较同一指标的多个时间周期 | 向 TA-Lib 的 timeframe 参数传入列表 |
| 将逐分钟模拟以月收益形式查看 | 对已完成投资组合重采样以生成报告 |
从策略需要的最细分辨率数据开始。一份分钟 K 线数据可以提供五分钟、小时和日频视图。也可通过将各结果重新对齐到共同目标索引,组合下载分辨率不同的数据。
开盘与收盘对齐
两条规则涵盖大多数情况。由 K 线开盘价得到的值在起点已知,用 realign_opening 重新对齐。由收盘、最高、最低或成交量得到的值在结束时已知,用 realign_closing
对齐。基于收盘价计算的指标遵循收盘规则。两者均支持双向操作:将小时数据降采样为日 K 线,或将日频值带回小时 K 线。
重新对齐的掩码以浮点数返回,第一个值可获知前的 K 线为 NaN。转换类型前先用 False 填充,如上方 safe_filter 所示,因为 NaN 转为布尔值会成为
True,从而从第一根 K 线开始启用过滤器。
data.resample() 使用适合各列的函数聚合完整 OHLCV 数据集,vbt.Resampler
在任意两个索引之间建立映射,包括不规则索引和交易时段等自定义边界。下方安全重采样功能介绍在日、周、月收盘价上运行同一指标,并将三者显示在日 K 线上。
从日内数据构建日 K 线,或将已完成的日频水平带入小时策略。VBT 同时处理聚合和对齐,让每个时间周期在同一回测中发挥自己的作用。
对于带额外字段的数据集,可以通过自定义聚合规则指定这些字段重采样时的行为。VBT 的提供商类已包含 Binance 计价资产成交量等字段的规则。
对完整对象重采样
可改变时间周期的不仅是数据。指标、记录和完整投资组合也能重采样,并对各部分使用相应规则:价格取最后值,现金流求和,订单保留时间戳。常见模式是在细 K 线上模拟以准确成交,再在粗 K 线上分析以提高速度和可读性,如下方可重采样对象功能介绍所示。对已完成投资组合重采样只改变报告频率。若要测试另一时间周期上的交易决策,请对输入重采样,并在该周期重新运行模拟。
频率
年化指标和重采样需要 K 线频率。VBT 从连续时间戳样本中推断频率,即使偶尔有缺口也能工作。数据开头不规则或没有固定间隔时,请显式传入 freq,或通过
vbt.settings.wrapping["freq"] 统一设置。毫秒和纳秒等日期时间精度不同的索引,应先转换为相同精度再重新对齐。
其他时间周期上的指标
每个 TA-Lib 指标都接受 timeframe 参数。先将输入重采样到该周期,在该周期计算指标,再安全地将输出对齐回原始 K
线,因此时间周期列表就成为与其他参数相同的一个参数。其他指标可以手动完成相同三步:重采样输入、计算指标、用 realign_closing 重新对齐输出。下方
TA-Lib 时间周期功能介绍在三个周期上运行同一指标。
指标窗口以计算时间周期的 K 线数衡量。14 周期日频 SMA 使用 14 个日收盘价,14 周期小时 SMA 使用 14 个小时收盘价。日频结果随后带回小时索引,并在每个新日频值可获知时更新。您可以通过参数优化,将时间周期与其他参数一起比较。
完整的高时间周期 K 线只有在结束时才已知。有些平台使用仍在形成的 K 线,在每根低周期 K 线上更新指标,得到更早但持续变化至收盘的数值。如果需要这种行为,请在每一步从部分 K 线显式计算,并在回测中使用当时真实存在的数值。
教程
会员专属的多时间周期分析(英文)教程深入介绍重采样、对齐和聚合。
✅ 处理数组数据时,前视偏差始终存在风险,尤其涉及多时间周期时。强烈不建议仅使用 Pandas,因为它无法识别金融数据主要由开盘时间标记的 K 线组成,事件可能发生在 K 线之间任意时刻。因此,Pandas 会错误地假设时间戳就是事件准确发生时间。VBT 提供完整的函数和类集合,用于安全重采样和分析数据!
def mtf_sma(close, close_freq, target_freq, timeperiod=5):
target_close = close.vbt.realign_closing(target_freq)
target_sma = vbt.talib("SMA").run(target_close, timeperiod=timeperiod).real
target_sma = target_sma.rename(f"SMA ({target_freq})")
return target_sma.vbt.realign_closing(close.index, freq=close_freq)
data = vbt.YFData.pull("BTC-USD", start="2020", end="2023")
fig = mtf_sma(data.close, "D", "daily").vbt.plot()
mtf_sma(data.close, "D", "weekly").vbt.plot(fig=fig)
mtf_sma(data.close, "D", "monthly").vbt.plot(fig=fig)
fig.show()教程
更多内容请参阅多时间周期分析教程。
✅ 您不仅可以重采样时间序列,也能重采样复杂 VBT 对象!底层每个对象都由一组类数组属性组成,因此重采样意味着将所有相关信息一起聚合。如果希望以更高频率模拟以获得最高精度,再以较低频率分析以提高速度,这尤其有帮助。
import calendar
data = vbt.YFData.pull("BTC-USD", start="2018", end="2023")
pf = vbt.PF.from_random_signals(data, n=100, direction="both", seed=42)
mo_returns = pf.resample("M").returns
mo_return_matrix = pd.Series(
mo_returns.values,
index=pd.MultiIndex.from_arrays([
mo_returns.index.year,
mo_returns.index.month
], names=["year", "month"])
).unstack("month")
mo_return_matrix.columns = mo_return_matrix.columns.map(lambda x: calendar.month_abbr[x])
mo_return_matrix.vbt.heatmap(
is_x_category=True,
trace_kwargs=dict(zmid=0, colorscale="Spectral")
).show()教程
更多内容请参阅多时间周期分析教程。
✅ 比较不同时间周期的指标涉及许多细节。现在,所有 TA-Lib 指标都支持一个参数,将输入数组重采样到目标周期、计算指标,再将输出数组重采样回原始周期。参数化多时间周期分析因此更加轻松!
h1_data = vbt.BinanceData.pull(
"BTCUSDT",
start="3 months ago UTC",
timeframe="1h"
)
mtf_sma = vbt.talib("SMA").run(
h1_data.close,
timeperiod=14,
timeframe=["1d", "4h", "1h"],
skipna=True
)
mtf_sma.real.vbt.ts_heatmap().show()教程
更多内容请参阅多时间周期分析教程。
版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。