教程
SuperFast SuperTrend
构建流式、多线程 SuperTrend 指标,并进行回测
会员内容预览(英文)
While Python is slower than many compiled languages, it is easy to use and extremely versatile. For many users, especially in the data science field, Python's practicality outweighs concerns about speed. It serves as a Swiss Army knife for programmers and researchers alike.
Unfortunately for quants, Python can become a significant bottleneck when working with large datasets. To address this, an entire ecosystem of scientific packages—such as NumPy and Pandas—exists. These packages are highly optimized for performance, with critical code paths often written in Cython or C. They primarily operate on arrays, providing a consistent interface for efficient data processing.
This approach is especially valuable when creating indicators that can be expressed as a set of vectorized operations, such as OBV. Even for non-vectorized operations like the exponentially weighted moving average (EMA), which is used in many indicators such as MACD, implementations are written in compiled languages and exposed as ready-to-use Python functions. However, some indicators are challenging or even impossible to develop solely with standard array operations because they introduce path dependency, where today's decisions depend on those made yesterday. SuperTrend is one such indicator.
In this example, you will learn how to design and implement a SuperTrend indicator, and step by step optimize it for exceptional performance using TA-Lib and Numba. We will also backtest the new indicator across a range of parameters using VBT (PRO).
Data
The first step is always obtaining the right data. Specifically, we need enough data to benchmark
different SuperTrend implementations. Let's pull 2 years of hourly Bitcoin and Ethereum data from
Binance using VBT's vectorbtpro.data.custom.binance.BinanceData class:
from vectorbtpro import *
data = vbt.BinanceData.pull(
['BTCUSDT', 'ETHUSDT'],
start='2020-01-01 UTC',
end='2022-01-01 UTC',
timeframe='1h'
)Fetching data for both symbols took about 30 seconds to complete. Since Binance, like any other exchange, will not return all the data at once, VBT first requested the maximum amount of data starting from January 1, 2020, and then gradually collected the remaining data, while respecting Binance's API rate limits. In total, this resulted in 18 requests per symbol. Finally, VBT aligned both symbols in case their indexes or columns were different and made the final index timezone-aware (in UTC).
To avoid repeatedly hitting the Binance servers every time we start a new Python session, we should
save the downloaded data locally using either VBT's vectorbtpro.data.base.Data.to_csv or
vectorbtpro.data.base.Data.to_hdf:
data.to_hdf('my_data.h5')We can then easily access the saved data using vectorbtpro.data.custom.hdf.HDFData:
data = vbt.HDFData.pull('my_data.h5')We can access any of the symbols in an HDF file using regular path expressions. For example, the
same as above: vbt.HDFData.pull(['my_data.h5/BTCUSDT', 'my_data.h5/ETHUSDT']).
Once we have the data, let's take a quick look at what is inside. To get any of the stored
DataFrames, use the vectorbtpro.data.base.Data.data dictionary, where each DataFrame is keyed by
symbol:
data.data['BTCUSDT'].info()<class 'pandas.DataFrame'>
DatetimeIndex: 17513 entries, 2020-01-01 00:00:00+00:00 to 2021-12-31 23:00:00+00:00
Data columns (total 9 columns):
# Column Non-Null Count Dtype
--- ------ -------------- -----
0 Open 17513 non-null float64
1 High 17513 non-null float64
2 Low 17513 non-null float64
3 Close 17513 non-null float64
4 Volume 17513 non-null float64
5 Quote volume 17513 non-null float64
6 Trade count 17513 non-null int64
7 Taker base volume 17513 non-null float64
8 Taker quote volume 17513 non-null float64
dtypes: float64(8), int64(1)
memory usage: 1.3 MBWe can also get an overview of all the symbols collected:
data.stats()Start Index 2020-01-01 00:00:00+00:00
End Index 2021-12-31 23:00:00+00:00
Total Duration 729 days 17:00:00
Total Symbols 2
Null Counts: BTCUSDT 0
Null Counts: ETHUSDT 0
Name: agg_stats, dtype: objectEach symbol has 17513 data points with no NaNs—perfect!
If you have ever worked with VBT, you know that VBT prefers data with symbols as columns (one per
backtest) instead of features as columns. Since SuperTrend depends on the high, low, and close
price, let's get those three features as separate DataFrames using vectorbtpro.data.base.Data.get:
high = data.get('High')
low = data.get('Low')
close = data.get('Close')
closesymbol BTCUSDT ETHUSDT
Open time
2020-01-01 00:00:00+00:00 7177.02 128.87
2020-01-01 01:00:00+00:00 7216.27 130.64
2020-01-01 02:00:00+00:00 7242.85 130.85
2020-01-01 03:00:00+00:00 7225.01 130.20
2020-01-01 04:00:00+00:00 7217.27 130.20
... ... ...
2021-12-31 19:00:00+00:00 45728.28 3626.27
2021-12-31 20:00:00+00:00 45879.24 3645.04
2021-12-31 21:00:00+00:00 46333.86 3688.41
2021-12-31 22:00:00+00:00 46303.99 3681.80
2021-12-31 23:00:00+00:00 46216.93 3676.23
[17513 rows x 2 columns]✅ 学习设计流式指标并编写单元测试。这类指标只需单次遍历数据,并随每个新数据点更新。我们将以流式 SuperTrend 指标为例,打造 Python 中速度最快的 SuperTrend!
✅ 由于 GIL,大多数 Python 操作只使用一个 CPU 核心。学习绕过这一限制,构建利用所有可用核心的指标!
✅ 学习设计恰当的回测流水线。我们将讨论并实现四种不同的设计,从模块化程度最高、最灵活的方案,到速度最快的方案。最后,我们将锦上添花,在短短一秒内完成 67,200 次 SuperTrend 回测!
会员主题(英文内容)
版权所有 © 2021–2026 Oleg Polakow。保留所有权利。
本站内容与文档供使用和评估 VectorBT PRO 以及教育用途。任何其他用途,包括开发或支持竞争产品或服务,均须事先取得书面同意。