功能
形态与事件研究
在价格历史中搜索相似形态,研究事件后的变化
某种价格形态或市场事件此前出现后,接下来发生了什么?VBT 在历史价格中搜索与形态相似的窗口,并将任意事件集合转化为可汇总的后续价格路径。只需几行 Python,就能以编译速度开展形态识别和事件研究。
close = vbt.YFData.pull("BTC-USD", start="2015-01-01", end="2025-01-01").close
pattern = close.iloc[-30:]
ranges = close.vbt.find_pattern(
pattern=pattern.values,
rescale_mode="rebase",
min_similarity=0.75,
)
past = ranges.end_idx.values < len(close) - 60
similarity = np.where(past, ranges.similarity.values, -np.inf)
top10 = ranges.apply_mask(similarity >= np.sort(similarity)[-10])
top10.readable[["Start Index", "End Index", "Similarity"]].round(3) Start Index End Index Similarity
0 2015-07-20 00:00:00+00:00 2015-08-19 00:00:00+00:00 0.831
1 2016-07-07 00:00:00+00:00 2016-08-06 00:00:00+00:00 0.810
2 2017-08-18 00:00:00+00:00 2017-09-17 00:00:00+00:00 0.829
3 2017-11-08 00:00:00+00:00 2017-12-08 00:00:00+00:00 0.808
4 2019-03-04 00:00:00+00:00 2019-04-03 00:00:00+00:00 0.809
5 2022-05-18 00:00:00+00:00 2022-06-17 00:00:00+00:00 0.816
6 2022-08-28 00:00:00+00:00 2022-09-27 00:00:00+00:00 0.807
7 2022-11-29 00:00:00+00:00 2022-12-29 00:00:00+00:00 0.801
8 2023-04-21 00:00:00+00:00 2023-05-21 00:00:00+00:00 0.830
9 2024-08-11 00:00:00+00:00 2024-09-10 00:00:00+00:00 0.807after = top10.with_delta(30)
after.get_projections().iloc[-1].quantile([0.1, 0.5, 0.9]).round(3)0.1 0.989
0.5 1.071
0.9 1.413
Name: 2025-01-30 00:00:00+00:00, dtype: float64after.plot_projections(plot_past_period=90).show() 十个最相似窗口结束 30 天后,路径中位数上涨 7.1%,第 10 至第 90 百分位范围从亏损 1.1% 到盈利 41.3%。十个历史案例是对历史的描述,而非预测;分布跨度与中位数同样值得关注。
形态搜索
find_pattern 沿序列滑动窗口,将形态拟合到每个窗口,并给出 0 至 1 的拟合评分。形态可以是点列表,例如表示下降三角形的
[5, 1, 3, 1, 2, 1],也可以是一段真实历史价格。每个窗口都会拉伸到形态长度,并按 rescale_mode 缩放:"minmax"
忽略价格范围比较形状,"rebase" 比较百分比变动。设置 max_window
后,搜索会尝试不超过该值的每种窗口长度,从而找到不同速度下的同一形态。每增加一种长度就要完整搜索一次,因此也可用 row_select_prob 和 window_select_prob
抽样一部分行和长度。距离可使用平均绝对误差或均方误差,max_error 限制任意单点可偏离的程度。
匹配结果以带相似度评分的区间记录返回,可筛选、绘图并转换为信号。记录的结束索引是匹配之后的 K 线,last_pd_mask 标记每个匹配完成时的 K 线。同一评分也可作为滚动指标,每根 K
线一个值:
patsim = vbt.PATSIM.run(
close,
pattern=pattern.values,
window=30,
rescale_mode="rebase",
)
patsim.similarity.iloc[-5:].round(3)Date
2024-12-27 00:00:00+00:00 0.682
2024-12-28 00:00:00+00:00 0.682
2024-12-29 00:00:00+00:00 0.730
2024-12-30 00:00:00+00:00 0.796
2024-12-31 00:00:00+00:00 1.000
Freq: D, Name: (array, 30, rebase), dtype: float64最后一个值为 1,因为形态正是取自这 30 根 K 线。
将匹配用作交易信号
默认情况下,重叠匹配通过保留最相似者来处理,后面找到的更好匹配可能移除较早的匹配。这会引入前视。用于信号时,请以 overlap_mode="allowall"
搜索,或使用滚动相似度指标。匹配在最后一根 K 线收盘时完成,因此应在下一根 K 线上交易。
事件之后的价格路径
投影适用于任意事件,而非仅限形态。将信号掩码转换为从每个事件起始的区间,VBT 就会收集每次事件之后的价格路径,并将起点重设为 1。下面是 SPY 自 2010 年以来所有幅度不低于 1% 的开盘跳空:
data = vbt.YFData.pull("SPY", start="2010-01-01", end="2025-01-01", auto_adjust=False)
gap_down = data.open / data.close.shift(1) - 1 <= -0.01
events = gap_down.vbt.signals.delta_ranges(5, close=data.close)
paths = events.get_projections()
paths.shape (6, 176)paths.iloc[-1].quantile([0.1, 0.5, 0.9]).round(3)0.1 0.960
0.5 1.010
0.9 1.041
Name: 2025-01-05 00:00:00-05:00, dtype: float64print((paths.iloc[-1] > 1).mean().round(3))0.631向下跳空五天后,SPY 有 63% 的情况上涨,中位涨幅为 1.0%。投影可以汇总为分位数区间,或绘制为扇形路径。同样的方法也适用于财报日期、宏观数据发布或任意其他带日期的事件。
使用自己的事件日历
如果已有事件日期列表,可标记对应 K 线,并提取每次事件之后的路径。这里使用两个示例日期,从一个小型价格序列中选取两根 K 线的变动:
event_close = pd.Series([100.0, 102.0, 103.0, 104.0, 200.0, 198.0, 196.0, 198.0], index=pd.date_range("2026-01-01", periods=8))
event_dates = pd.to_datetime(["2026-01-01", "2026-01-05"])
event_mask = pd.Series(event_close.index.isin(event_dates), index=event_close.index)
event_ranges = event_mask.vbt.signals.delta_ranges(2, close=event_close)
event_paths = event_ranges.get_projections(id_level="start_idx")
((event_paths.iloc[-1] - 1) * 100).rename("Return [%]").round(1)start_idx
2026-01-01 3.0
2026-01-05 -2.0
Name: Return [%], dtype: float64第一条路径从 100 到 103,第二条从 200 到 196。每条都从各自事件的收盘价起始,让不同价格水平转化为可比较的百分比变动。将示例日期替换为您自己的日历,并对齐价格 K
线,即可比较财报公告、定期发布事件或自己的信号日期。完整的 event_paths DataFrame 还让您比较每个结果的形成路径,而非仅看最终收益。
当事件提示了某种交易规则,信号回测可加入仓位规模、退出和交易成本。使用前向滚动与交叉验证,在未用于选择规则的区间上进行测试。
市场结构事件
许多事件只是简单掩码。价格跳空是开盘价与前收盘价的比较。标记达到最小幅度反转的方向变化,只有在价格充分移动后才被确认,因此随着新 K 线到来,暂定转折点可能改变。vbt.PIVOTINFO
使用高低价和独立的上涨、下跌阈值查找它们,并报告最近已确认拐点、最新暂定拐点及各自发生的 K 线。在回测中使用拐点前,请考虑确认延迟。
绘制匹配与投影
ranges.plot() 在价格上显示每次匹配及相似度,plot_projections()
则在当前价格旁绘制后续路径,并可选显示分位数区间。下方形态和投影功能介绍展示了两者。
教程
会员专属的形态与投影(英文)教程深入介绍拟合、距离度量和基于形态的信号。
✅ 形态是图表中价格运动形成的独特结构,也是技术分析的核心。现在提供专门的函数和类,可在任意时间序列数据中检测任意复杂度的形态。思路很简单:将形态拟合到所选数据窗口的尺度和周期,再计算逐元素距离,得到单个相似度评分。您可调整评分阈值,决定超过哪个值时将窗口标记为“匹配”。借助 Numba,此操作每秒可以执行数十万次!🔎
data = vbt.YFData.pull("BTC-USD")
data.hlc3.vbt.find_pattern(
pattern=[5, 1, 3, 1, 2, 1],
window=100,
max_window=700,
).loc["2017":"2019"].plot().show()教程
更多内容请参阅形态与投影教程。
✅ 除了传统回测,还有更简洁的方法来分析事件及其对价格的影响。认识一下投影!👋 它不仅帮助您直观、定量地评估事件表现,还可以将事件投影到未来以辅助交易。具体做法是提取每次事件之后的价格区间,将所有区间收集到多维数组,再从数组计算置信区间及其他有用统计。与形态结合后,这些工具堪称量化分析师的理想助手!🌟
data = vbt.YFData.pull("ETH-USD")
pattern_ranges = data.hlc3.vbt.find_pattern(
pattern=data.close.iloc[-7:],
rescale_mode="rebase"
)
delta_ranges = pattern_ranges.with_delta(7)
fig = data.iloc[-7:].plot(plot_volume=False)
delta_ranges.plot_projections(fig=fig)
fig.show()教程
更多内容请参阅形态与投影教程。
版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。