功能

多时间周期分析

按每个值实际可获知的时间,跨周期重采样并重新对齐数据

如何在小时 K 线上使用日频指标,同时避免窥探未来?日 K 线以开盘时间标注时,其收盘价仍要到结束时才可获知。VBT 按每个数值实际可用的时间进行重采样和重新对齐,帮助您在 Python 多时间周期回测中避免前视偏差。

Filter hourly entries with a daily trend, aligned naively and safely
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           222
pf.value.vbt.plot().show()
2024 年使用日频趋势过滤器的小时策略,比较简单对齐与安全对齐的投资组合价值 图表数据(JSON)

简单版本看似盈利,但它是错误的。当日收盘价上穿均线时,简单过滤器在午夜就已启用,比该收盘价出现早了 23 小时:

Compare when each filter turns on
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 提供完整的函数和类集合,用于安全重采样和分析数据!

Calculate SMA on multiple timeframes and display on the same chart
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()
在日、周、月周期上计算的比特币简单移动平均线 图表数据(JSON)

教程

更多内容请参阅多时间周期分析教程。

可重采样对象

✅ 您不仅可以重采样时间序列,也能重采样复杂 VBT 对象!底层每个对象都由一组类数组属性组成,因此重采样意味着将所有相关信息一起聚合。如果希望以更高频率模拟以获得最高精度,再以较低频率分析以提高速度,这尤其有帮助。

Plot the monthly return heatmap of a random portfolio
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()
2018 至 2022 年固定随机种子的比特币随机投资组合月收益热图 图表数据(JSON)

教程

更多内容请参阅多时间周期分析教程。

TA-Lib 时间周期

✅ 比较不同时间周期的指标涉及许多细节。现在,所有 TA-Lib 指标都支持一个参数,将输入数组重采样到目标周期、计算指标,再将输出数组重采样回原始周期。参数化多时间周期分析因此更加轻松!

Run SMA on multiple timeframes and display the whole thing as a heatmap
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()
BTCUSDT 小时、四小时和日频上的简单移动平均线 图表数据(JSON)

教程

更多内容请参阅多时间周期分析教程。

版权所有 © 2021–2026 Oleg Polakow。保留所有权利。

本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。