功能

自定义指标

将 Python、pandas 或 Numba 计算转为可复用的参数网格指标

如何将自己的公式变成可扫描参数并重复使用的指标?VBT 指标工厂将任意 Python 或 Numba 函数封装成具有参数网格、带标签输出、信号辅助方法和绘图能力的指标类,让 Python 自定义指标与内置指标具有相同使用方式。

Build a volatility-adjusted momentum indicator and test six parameter pairs
@njit
def vam_nb(close, fast, slow):  
    momentum = close / vbt.nb.fshift_nb(close, fast) - 1
    returns = close / vbt.nb.fshift_nb(close, 1) - 1
    volatility = vbt.nb.rolling_std_nb(returns, slow)
    return momentum / (volatility * np.sqrt(fast))

VAM = vbt.IF(
    class_name="VAM",
    short_name="vam",
    input_names=["close"],
    param_names=["fast", "slow"],
    output_names=["vam"],
).with_apply_func(vam_nb, takes_1d=False, fast=10, slow=50)  

data = vbt.YFData.pull(["BTC-USD", "ETH-USD"], start="2023-01-01", end="2025-01-01")
vam = VAM.run(
    data.close,
    fast=vbt.Param([5, 10, 20, 40], condition="fast < slow"),  
    slow=vbt.Param([10, 20, 40]),
    param_product=True,
)
vam.vam.shape
(731, 12)
vam.vam.columns.droplevel("symbol").unique().tolist()
[(5, 10), (5, 20), (5, 40), (10, 20), (10, 40), (20, 40)]
entries = vam.vam_crossed_above(1)  
exits = vam.vam_crossed_below(0)
pf = vbt.PF.from_signals(data, entries, exits)
pf.total_return.unstack("symbol").round(3)
symbol             BTC-USD  ETH-USD
vam_fast vam_slow
5        10          0.717   -0.187
         20          0.388    0.454
         40          0.771    0.228
10       20          0.576    0.131
         40          1.119    0.000
20       40          1.322   -0.004

函数只有十行。工厂添加参数网格、列标签、信号方法及指标需要的其他能力,结果可直接进入回测。

从函数到指标

vbt.IF 接受输入、参数和输出的名称,以及计算它们的函数。函数可以逐列或处理整个数组,返回一个或多个输出,并将额外结果保存在原地输出中。生成类拥有带默认值的 run 方法、可读输出属性、各输出的 crossed_above、above 等比较辅助方法,以及绘图能力。输出像 pandas 对象一样支持算术,因此可直接使用 vam.vam * 2 或 fast.ma - slow.ma。

函数默认接收 NumPy 数组,以保持可编译。传入 keep_pd=True 则改为接收 pandas 对象,例如调用 pandas 滚动或分组方法。这时函数必须是普通 Python,因为 Numba 无法编译接收 pandas 对象的代码。常规指标输出在每种参数组合下与输入形状一致。返回每次运行一个数字或其他长度数组等结果的函数,更适合参数化装饰器,详见参数化任意函数。

复用 pandas 计算

您可以从 notebook 中已可运行的计算开始。这里普通 Python 函数返回滚动均值,以及价格相对均值的百分比距离。keep_pd=True 让它直接使用 pandas,工厂则处理窗口、标的和输出标签。

Turn a pandas calculation into a reusable indicator
def distance_from_mean(close, window):
    mean = close.rolling(window).mean()
    return mean, 100 * (close / mean - 1)

Distance = vbt.IF(
    class_name="Distance",
    short_name="dist",
    input_names=["close"],
    param_names=["window"],
    output_names=["mean", "distance"],
).with_apply_func(distance_from_mean, keep_pd=True)
close = pd.DataFrame({
    "A": [10, 11, 12, 11, 13, 15],
    "B": [20, 19, 18, 19, 17, 15],
}, index=pd.date_range("2025-01-01", periods=6))
close.columns.name = "symbol"
result = Distance.run(close, window=[2, 3])
result.output_names
('mean', 'distance')
result.distance.iloc[-1].unstack("symbol").round(2)
symbol           A      B
dist_window
2             7.14  -6.25
3            15.38 -11.76

在这些虚构价格上,A 最终高于滚动均值,B 则低于均值。均值和距离都可继续用于绘图、比较或其他计算。您可以将距离作为模型特征或均值回归策略阈值,再通过信号回测测试规则。

参数与网格

参数接受单个值、列表或 vbt.Param 对象。列表默认逐元素配对,param_product=True 构建全部组合。条件可以按名称筛选组合,如上所示;每个参数成为以指标短名称命名的列层级,因此可按参数选择和分组结果。

输入

不同形状的输入会相互广播。单个价格序列与参数组合,每种组合产生一列;多个资产则扩展网格,正如上面的两个资产与六组参数。设置 takes_1d=True 后,函数每次接收一列,由工厂负责遍历各列。如果每个资产需要自己的设置,而非相同网格,per_column=True 会将每个输入列与对应参数组合配对。

将公式作为指标

指标也可写成表达式,例如 (close - low) / (high - low),按名称解析输入、参数和辅助函数,如下方指标表达式功能介绍所示。表达式适合快速尝试想法,工厂将其转换为与编译函数相同类型的类。

性能

编译函数以 Numba 速度运行整个网格。如果多个组合需要同一中间结果,例如多组参数共享一条均线,工厂可在缓存函数中计算一次后复用。逐列工作的指标可以使用并行线程,为一维编写的指标也能自动跨列并行,如原生一维指标和可并行指标功能介绍所示。滚动指标需要预热期,因此足够 K 线出现前,初始值为 NaN。

组合与复用

指标可以组合:一个输出成为另一个输入,多个指标堆叠为一个对象,结果像 DataFrame 一样索引。注册后,自定义指标可通过 vbt.indicator() 按名称查找,并通过数据对象的 data.run() 运行,与内置指标相同。下方指标搜索功能介绍展示跨全部集成库查找指标,机器学习指标则将多个指标转换为特征矩阵。

注册也能将指标组织为具名分组,例如趋势过滤器或波动率特征。通过数据对象运行整个分组,可在新数据集上重建相同特征集,适合比较应接收相同输入的模型。

通过 lazy_outputs 可以添加派生属性,仅在请求时计算。例如,返回多条线的指标可将线间差值作为另一属性公开。这让相关计算保存在一起,同时可自行选择检查哪些结果。随新 K 线更新的计算,请参阅流式指标。

✅ VBT 实现或集成了 500 多个指标,难以逐一记住。为了更容易查找,现提供多种全局搜索指标的新方法。

List all moving average indicators
vbt.IF.list_indicators("*ma")
[
    'vbt:MA',
    'talib:DEMA',
    'talib:EMA',
    'talib:KAMA',
    'talib:MA',
    ...
    'technical:ZEMA',
    'technical:ZLEMA',
    'technical:ZLHMA',
    'technical:ZLMA'
]
vbt.indicator("technical:ZLMA")  
vectorbtpro.indicators.factory.technical.ZLMA

机器学习指标

✅ 想将指标作为机器学习模型特征?无需逐个运行:可以让 VBT 在给定数据实例上运行某个指标包的全部指标。数据实例识别各指标输入名称,提供所需数据,也可轻松修改每个指标的默认参数。

Run all talib indicators on entire BTC-USD history
data = vbt.YFData.pull("BTC-USD")
features = data.run("talib", mavp=vbt.run_arg_dict(periods=14))
features.shape
(3046, 175)

原生一维指标

✅ 此前,自定义指标只能接受二维输入数组,用户必须相应调整所有函数。现在,指标工厂可以按列拆分每个输入数组,每次传入一列,使设计原本面向一维数据的指标(例如 TA-Lib!)轻松得多。

Create a TA-Lib powered STOCHRSI indicator
import talib

params = dict(
    rsi_period=14,
    fastk_period=5,
    slowk_period=3,
    slowk_matype=0,
    slowd_period=3,
    slowd_matype=0
)

def stochrsi_1d(close, *args):
    rsi = talib.RSI(close, args[0])
    k, d = talib.STOCH(rsi, rsi, rsi, *args[1:])
    return rsi, k, d

STOCHRSI = vbt.IF(
    input_names=["close"],
    param_names=list(params.keys()),
    output_names=["rsi", "k", "d"]
).with_apply_func(stochrsi_1d, takes_1d=True, **params)

data = vbt.YFData.pull("BTC-USD", start="2022-01", end="2022-06")
stochrsi = STOCHRSI.run(data.close)
fig = stochrsi.k.rename("%K").vbt.plot()
stochrsi.d.rename("%D").vbt.plot(fig=fig)
fig.show()
基于 TA-Lib 的 BTC-USD 随机 RSI:%K 与 %D 图表数据(JSON)

可并行指标

✅ 指标工厂处理参数组合时,可分配到多个线程、进程,甚至云端。这对运行较慢的指标帮助很大 🐌

Benchmark a serial and multithreaded rolling min-max indicator
@njit
def minmax_nb(close, window):
    return (
        vbt.nb.rolling_min_nb(close, window),
        vbt.nb.rolling_max_nb(close, window)
    )

MINMAX = vbt.IF(
    class_name="MINMAX",
    input_names=["close"],
    param_names=["window"],
    output_names=["min", "max"]
).with_apply_func(minmax_nb, window=14)

data = vbt.YFData.pull("BTC-USD")
%%timeit
minmax = MINMAX.run(
    data.close,
    np.arange(2, 200),
    jitted_loop=True
)
420 ms ± 2.05 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)
%%timeit
minmax = MINMAX.run(
    data.close,
    np.arange(2, 200),
    jitted_loop=True,
    jitted_warmup=True,  
    execute_kwargs=dict(engine="threadpool", n_chunks="auto")  
)
120 ms ± 355 µs per loop (mean ± std. dev. of 7 runs, 10 loops each)

指标表达式

✅ 现在可以从表达式创建指标。指标表达式是表示 Python 代码的普通字符串,并增强了多种扩展。借助独特格式和内置匹配机制,指标工厂自动推导全部所需信息,包括输入、参数、输出、NumPy、VBT、TA-Lib 函数,甚至复杂指标。设计指标从未如此轻松!

Build a MACD indicator from an expression
data = vbt.YFData.pull("BTC-USD", start="2020", end="2021")

expr = """
MACD:
fast_ema = @talib_ema(close, @p_fast_w)
slow_ema = @talib_ema(close, @p_slow_w)
macd = fast_ema - slow_ema
signal = @talib_ema(macd, @p_signal_w)
macd, signal
"""
MACD = vbt.IF.from_expr(expr, fast_w=12, slow_w=26, signal_w=9)  
macd = MACD.run(data.close)
fig = macd.macd.rename("MACD").vbt.plot()
macd.signal.rename("Signal").vbt.plot(fig=fig)
fig.show()
使用表达式构建的 2020 年 BTC-USD MACD 线与信号线 图表数据(JSON)

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

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