功能
工作流自动化
调度数据更新、发送 Telegram 提醒、并行运行任务,并跟踪进度
如何无人值守地运行研究与数据更新,并在事件发生时收到通知?VBT 为交易研究调度 Python 任务,例如每小时更新数据,在信号触发时发送 Telegram 提醒,并提供并行任务、嵌套进度条和命令行界面。
def signal_message(data):
close = data.close.iloc[:-1]
fast = vbt.MA.run(close, window=20)
slow = vbt.MA.run(close, window=50)
bar = f"{close.index[-1]:%Y-%m-%d %H:%M} BTCUSDT 20h MA crossed"
if fast.ma_crossed_above(slow).iloc[-1]:
return f"{bar} above 50h MA at {close.iloc[-1]:,.0f}"
if fast.ma_crossed_below(slow).iloc[-1]:
return f"{bar} below 50h MA at {close.iloc[-1]:,.0f}"
class AlertUpdater(vbt.DataUpdater):
def __init__(self, data, notify, **kwargs):
vbt.DataUpdater.__init__(self, data, notify=notify, **kwargs)
self._notify = notify
def update(self, **kwargs):
vbt.DataUpdater.update(self, **kwargs)
message = signal_message(self.data)
if message is not None:
self._notify(message)
data = vbt.BinanceData.pull(
"BTCUSDT", timeframe="1h", start="2024-11-24", end="2024-12-01 00:01"
)
updater = AlertUpdater(data, notify=print)
for hour in pd.date_range("2024-12-01 01:00", periods=7 * 24, freq="h", tz="UTC"):
updater.update(end=hour + pd.Timedelta(minutes=1)) 2024-12-01 20:00 BTCUSDT 20h MA crossed above 50h MA at 97,100
2024-12-02 12:00 BTCUSDT 20h MA crossed below 50h MA at 94,972
2024-12-04 07:00 BTCUSDT 20h MA crossed above 50h MA at 96,589
2024-12-06 09:00 BTCUSDT 20h MA crossed below 50h MA at 98,000
2024-12-07 07:00 BTCUSDT 20h MA crossed above 50h MA at 99,405该周共触发五次交叉。每次更新只从 Binance 获取最新 K 线,因此同一对象可运行数月,无须重新下载历史。实时运行时,改用 Telegram 机器人发送消息,而非 print,并让调度器调用
update:
bot = vbt.TelegramBot(token="YOUR_BOT_TOKEN")
bot.start(in_background=True)
updater = AlertUpdater(data, notify=bot.send_message_to_all)
updater.update_every("hour", "01:00") 选择周期性工作流
同一套工具可运行数据流、一批回测或定期报告。Python 函数定义工作内容,VBT 负责运行时机与重复调用的结果收集:
| 您想自动化什么 | 使用什么工具 |
|---|---|
| 刷新价格并检查最新信号 | DataUpdater 配合定时更新及自己的信号函数。 |
| 新 K 线到达时持续保存市场数据到磁盘 | 带定时更新的数据 saver。 |
| 跨交易品种、日期或配置重复研究 | Task、execute 或 iterated 装饰器。 |
| 每日运行分析并保存结果 | ScheduleManager 调用构建并保存研究对象的函数。 |
调度
vbt.ScheduleManager 按计划运行任意函数,以自然词汇指定间隔、单位、星期和时间,例如
every(10, "minutes")、every("hour", "01:00") 或 every("monday", "09:30")。任务可在阻塞循环中运行,也可作为后台
asyncio 任务,使运行期间 notebook 仍可使用。标签将任务分组,便于一起替换或移除。vbt.DataUpdater
和数据存储页中的数据 saver 使用同一调度器,因此数据更新、磁盘保存和信号检查可以共用一个任务。
无人值守任务可在 Python 进程中运行阻塞调度器;notebook 若有活跃事件循环,可使用 start_in_background 启动,再用 stop 停止。进程或 notebook
会话负责维持计划运行。对于需对齐时钟边界的间隔,zero_offset=True 可将每十分钟检查等周期任务对齐。
定时函数也可重建指标、运行参数搜索,并保存结果投资组合供之后检查。配置与持久化展示如何在多次运行间保存输入、设置与结果。
任务与迭代
vbt.Task 将函数及参数打包而不执行,vbt.execute 则带进度条,按顺序、在线程或进程中运行任务列表。@vbt.iterated
将围绕某个参数的循环变成带标签结果的并行运行,详见下方迭代装饰器与任务。对于可复现随机运行,vbt.set_seed 同时设置
Python、NumPy 和 Numba 的随机种子。独立随机任务应各自使用显式种子,使实验能记录每项任务所用的随机输入。
互不依赖结果的独立实验适合任务;同一计算跨交易品种、时期或其他参数重复时,适合迭代函数。执行和结果合并选项使该计算可以保持为普通 Python 函数。并行执行与缓存介绍可用引擎及已完成工作的复用方式。
串联任务步骤
数据对象还支持 pipe 和
chain,用于依赖前一步输出的步骤。操作序列可以拉取数据、选择品种、添加指标,再传给自己的函数。这样,交互式使用的数据准备也能用于同一个定时任务。数据流程页介绍数据准备部分。
进度
数据下载、参数扫描和任务执行等较长 VBT
操作,运行超过两秒后显示进度条,可关闭或定制。进度条可以嵌套,因此依次遍历交易品种、参数和切分时,每层各显示一行,详见下方嵌套进度条。并行工作进程内绘制的进度条会相互干扰,因此在工作进程中运行的
VBT 调用应传入 show_progress=False,例如由其他库负责并行化时。
命令行工作流
vbt 命令无需 Python 脚本即可在终端运行。它可以向 VBT 文档助手提问、搜索知识库,以及启动或调用 MCP 服务器,详见下方 CLI。
通知
vbt.TelegramBot 通过 python-telegram-bot 连接
Telegram。除发送消息外,还能响应自定义命令,让聊天查询最新价格或投资组合摘要。send_giphy 可通过文本在 GIPHY 搜索并附加 GIF。CCXT 和 Polygon
数据类重试发生网络错误的请求,TradingView 类重试无法解析的响应。在配置的尝试次数用尽前,这些重试可从临时故障中恢复。自定义 HTTP 集成可用
requests_retry_session 设置重试次数、退避和可重试状态码。
提醒既可报告交易信号,也可报告研究完成。可根据任务结果发送简短摘要,或定义机器人命令,在您查询时读取已保存投资组合。实时模拟页展示如何在新数据到达时继续投资组合。
✅ VBT 现提供基于 Typer 的命令行界面,可直接在终端对话、搜索和调用 MCP 工具,无需 Python
脚本。安装软件包后,在终端运行 vbt 即可查看全部可用命令。
vbt chat "How to backtest a weekly rebalancing strategy?" 多数命令首次运行时,准备文档可能需要一些时间。不过,大部分准备步骤会缓存保存,因此后续调用快得多,无须重复准备。
✅ 想将 for 循环并行化?VBT 有相应装饰器。
import calendar
data = vbt.YFData.pull("BTC-USD")
@vbt.iterated(over_arg="year", merge_func="column_stack", engine="pathos")
@vbt.iterated(over_arg="month", merge_func="concat")
def get_year_month_sharpe(data, year, month):
mask = (data.index.year == year) & (data.index.month == month)
if not mask.any():
return np.nan
year_returns = data.loc[mask].returns
return year_returns.vbt.returns.sharpe_ratio()
years = data.index.year.unique().sort_values().rename("year")
months = data.index.month.unique().sort_values().rename("month")
sharpe_matrix = get_year_month_sharpe(
data,
years,
{calendar.month_abbr[month]: month for month in months},
)
sharpe_matrix.transpose().vbt.heatmap(
trace_kwargs=dict(colorscale="RdBu", zmid=0),
yaxis=dict(autorange="reversed")
).show()✅ 测试多个参数组合通常使用 @vbt.parameterized 装饰器。但如果要测试完全无关的配置,甚至不同函数呢?VBT
新增功能可将每项测试分配给一个任务,并行执行任意一系列互不相关的测试。
data = vbt.YFData.pull("BTC-USD")
task1 = vbt.Task(
vbt.PF.from_random_signals,
data,
n=100, seed=42,
sl_stop=vbt.Param(np.arange(1, 51) / 100)
)
task2 = vbt.Task(
vbt.PF.from_random_signals,
data,
n=100, seed=42,
tsl_stop=vbt.Param(np.arange(1, 51) / 100)
)
task3 = vbt.Task(
vbt.PF.from_random_signals,
data,
n=100, seed=42,
tp_stop=vbt.Param(np.arange(1, 51) / 100)
)
pf1, pf2, pf3 = vbt.execute([task1, task2, task3], engine="pathos")
fig = pf1.trades.expectancy.rename("SL").vbt.plot()
pf2.trades.expectancy.rename("TSL").vbt.plot(fig=fig)
pf3.trades.expectancy.rename("TP").vbt.plot(fig=fig)
fig.show()✅ 进度条现在能感知彼此。新进度条启动时,会检查同一标识符的其他进度条是否已完成任务。若是,新进度条会关闭自身,并将进度委托给已有进度条。
symbols = ["BTC-USD", "ETH-USD"]
fast_windows = range(5, 105, 5)
slow_windows = range(5, 105, 5)
sharpe_ratios = dict()
with vbt.ProgressBar(total=len(symbols), bar_id="pbar1") as pbar1:
for symbol in symbols:
pbar1.set_description(dict(symbol=symbol), refresh=True)
data = vbt.YFData.pull(symbol)
with vbt.ProgressBar(total=len(fast_windows), bar_id="pbar2") as pbar2:
for fast_window in fast_windows:
pbar2.set_description(dict(fast_window=fast_window), refresh=True)
with vbt.ProgressBar(total=len(slow_windows), bar_id="pbar3") as pbar3:
for slow_window in slow_windows:
if fast_window < slow_window:
pbar3.set_description(dict(slow_window=slow_window), refresh=True)
fast_sma = data.run("talib_func:sma", fast_window)
slow_sma = data.run("talib_func:sma", slow_window)
entries = fast_sma.vbt.crossed_above(slow_sma)
exits = fast_sma.vbt.crossed_below(slow_sma)
pf = vbt.PF.from_signals(data, entries, exits)
sharpe_ratios[(symbol, fast_window, slow_window)] = pf.sharpe_ratio
pbar3.update()
pbar2.update()
pbar1.update()sharpe_ratios = pd.Series(sharpe_ratios)
sharpe_ratios.index.names = ["symbol", "fast_window", "slow_window"]
sharpe_ratiossymbol fast_window slow_window
BTC-USD 5 10 1.063616
15 1.218345
20 1.273154
25 1.365664
30 1.394469
...
ETH-USD 80 90 0.582995
95 0.617568
85 90 0.701215
95 0.616037
90 95 0.566650
Length: 342, dtype: float64版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。