-
Notifications
You must be signed in to change notification settings - Fork 0
Backtest (low‐level API)
Tutorial for NautilusTrader a high-performance algorithmic trading platform and event driven backtester. NautilusTrader 是一个高性能算法交易平台和事件驱动回测器的教程。
View source on GitHub 在 GitHub 查看源码
This tutorial walks through how to use a BacktestEngine to backtest a simple EMA cross strategy with a TWAP execution algorithm on a simulated Binance Spot exchange using historical trade tick data. 本教程将介绍如何使用 BacktestEngine 在模拟的 Binance 现货交易所上对简单的 EMA 交叉策略进行回测,使用 TWAP 执行算法和历史交易 tick 数据。
The following points will be covered: 将涵盖以下几点:
- How to load raw data (external to Nautilus) using data loaders and wranglers
- 如何使用数据加载器和整理器加载原始数据(Nautilus 之外)
- How to add this data to a BacktestEngine
- 如何将这些数据添加到 BacktestEngine
- How to add venues, strategies and execution algorithms to a BacktestEngine
- 如何将平台、策略和执行算法添加到 BacktestEngine
- How to run backtests with a BacktestEngine
- 如何使用 BacktestEngine 运行回测
- Post-run analysis and options for repeated runs
- 回测后的分析和重复运行的选项
- Python 3.10+ installed
- 已安装 Python 3.10 及以上版本
- JupyterLab or similar installed (
pip install -U jupyterlab
) - 已安装 JupyterLab 或类似工具 (
pip install -U jupyterlab
) - NautilusTrader latest release installed (
pip install -U nautilus_trader
) - 已安装最新的 NautilusTrader 版本 (
pip install -U nautilus_trader
)
We'll start with all of our imports for the remainder of this tutorial. 我们将开始导入本教程其余部分所需的所有库。
from decimal import Decimal
from nautilus_trader.backtest.engine import BacktestEngine
from nautilus_trader.backtest.engine import BacktestEngineConfig
from nautilus_trader.examples.algorithms.twap import TWAPExecAlgorithm
from nautilus_trader.examples.strategies.ema_cross_twap import EMACrossTWAP
from nautilus_trader.examples.strategies.ema_cross_twap import EMACrossTWAPConfig
from nautilus_trader.model.currencies import ETH
from nautilus_trader.model.currencies import USDT
from nautilus_trader.model.data import BarType
from nautilus_trader.model.enums import AccountType
from nautilus_trader.model.enums import OmsType
from nautilus_trader.model.identifiers import TraderId
from nautilus_trader.model.identifiers import Venue
from nautilus_trader.model.objects import Money
from nautilus_trader.persistence.wranglers import TradeTickDataWrangler
from nautilus_trader.test_kit.providers import TestDataProvider
from nautilus_trader.test_kit.providers import TestInstrumentProvider
For this tutorial we'll use some stub test data which exists in the NautilusTrader repository (this data is also used by the automated test suite to test the correctness of the platform). 在本教程中,我们将使用存在于 NautilusTrader 仓库中的一些示例测试数据(这些数据也用于自动化测试套件以测试平台的正确性)。
Firstly, instantiate a data provider which we can use to read raw CSV trade tick data into memory as a pd.DataFrame. We then need to initialize the instrument which matches the data, in this case the ETHUSDT spot cryptocurrency pair for Binance. We'll use this instrument for the remainder of this backtest run. 首先,实例化一个数据提供者,以便我们可以将原始 CSV 交易 tick 数据读入内存作为 pd.DataFrame。然后,我们需要初始化与数据匹配的Instrument,在本例中是 Binance 的 ETHUSDT 现货加密货币对。我们将在本次回测中使用这个Instrument。
# Load stub test data
# 加载示例测试数据
provider = TestDataProvider()
trades_df = provider.read_csv_ticks("binance/ethusdt-trades.csv")
# Initialize the instrument which matches the data
# 初始化与数据匹配的Instrument
ETHUSDT_BINANCE = TestInstrumentProvider.ethusdt_binance()
# Process into Nautilus objects
# 处理为 Nautilus 对象
wrangler = TradeTickDataWrangler(instrument=ETHUSDT_BINANCE)
ticks = wrangler.process(trades_df)
See the Loading External Data guide for a more detailed explanation of the typical data processing components and pipeline. 有关典型数据处理组件和管道的更详细解释,请参见加载外部数据指南。
Now we'll need a backtest engine, minimally you could just call BacktestEngine()
which will instantiate an engine with a default configuration.
现在我们需要一个回测引擎,最简单的方法是调用 BacktestEngine()
,这将实例化一个具有默认配置的引擎。
Here we also show initializing a BacktestEngineConfig (will only a custom trader_id specified) to show the general configuration pattern. 在这里,我们还展示了如何初始化 BacktestEngineConfig(仅指定自定义 trader_id),以展示一般配置模式。
See the Configuration API reference for details of all configuration options available. 有关所有可用配置选项的详细信息,请参见配置 API 参考。
# Configure backtest engine
# 配置回测引擎
config = BacktestEngineConfig(trader_id=TraderId("BACKTESTER-001"))
# Build the backtest engine
# 构建回测引擎
engine = BacktestEngine(config=config)
We'll need a venue to trade on, which should match the market data being added to the engine. 我们需要一个交易平台,它应与添加到引擎中的市场数据匹配。
In this case we'll set up a simulated Binance Spot exchange. 在这种情况下,我们将设置一个模拟的 Binance 现货交易所。
# Add a trading venue (multiple venues possible)
# 添加交易平台(可以有多个平台)
BINANCE = Venue("BINANCE")
engine.add_venue(
venue=BINANCE,
oms_type=OmsType.NETTING,
account_type=AccountType.CASH, # Spot CASH account (not for perpetuals or futures)
# 现货现金账户(不适用于永续合约或期货)
base_currency=None, # Multi-currency account
# 多币种账户
starting_balances=[Money(1_000_000.0, USDT), Money(10.0, ETH)],
)
Now we can add data to the backtest engine. First add the Instrument object we previously initialized, which matches our data. 现在我们可以将数据添加到回测引擎。首先添加之前初始化的 Instrument 对象,它与我们的数据匹配。
Then we can add the trade ticks we wrangled earlier. 然后我们可以添加之前整理的交易 tick 数据。
# Add instrument(s)
# 添加Instrument
engine.add_instrument(ETHUSDT_BINANCE)
# Add data
# 添加数据
engine.add_data(ticks)
Note
The amount of and variety of data types is only limited by machine resources and your imagination (custom types are possible). Also, multiple venues can be used for backtesting, again only limited by machine resources.注意
数据类型的数量和多样性仅受机器资源和您的想象力的限制(自定义类型是可能的)。此外,可以使用多个平台进行回测,同样仅受机器资源的限制。
Now we can add the trading strategies we’d like to run as part of our system. 现在我们可以添加我们希望作为系统一部分运行的交易策略。
Note
Multiple strategies and instruments can be used for backtesting, only limited by machine resources.注意
可以使用多个策略和Instrument进行回测,仅受机器资源的限制。
Firstly, initialize a strategy configuration, then use this to initialize a strategy which we can add to the engine: 首先,初始化一个策略配置,然后使用它来初始化一个策略,我们可以将其添加到引擎中:
# Configure your strategy
# 配置您的策略
strategy_config = EMACrossTWAPConfig(
instrument_id=ETHUSDT_BINANCE.id,
bar_type=BarType.from_str("ETHUSDT.BINANCE-250-TICK-LAST-INTERNAL"),
trade_size=Decimal("0.10"),
fast_ema_period=10,
slow_ema_period=20,
twap_horizon_secs=10.0,
twap_interval_secs=2.5,
)
# Instantiate and add your strategy
# 实例化并添加您的策略
strategy = EMACrossTWAP(config=strategy_config)
engine.add_strategy(strategy=strategy)
You may notice that this strategy config includes parameters related to a TWAP execution algorithm. This is because we can flexibly use different parameters per order submit, we still need to initialize and add the actual ExecAlgorithm component which will execute the algorithm - which we'll do now. 您可能会注意到,该策略配置包含与 TWAP 执行算法相关的参数。这是因为我们可以灵活地为每个订单提交使用不同的参数,但我们仍然需要初始化并添加实际的 ExecAlgorithm 组件以执行该算法 - 我们现在就来做。
NautilusTrader enables us to build up very complex systems of custom components. Here we show just one of the custom components available, in this case a built-in TWAP execution algorithm. It is configured and added to the engine in generally the same pattern as for strategies: NautilusTrader 使我们能够构建非常复杂的自定义组件系统。在这里,我们展示了可用的一个自定义组件,即内置的 TWAP 执行算法。它的配置和添加到引擎的模式与策略基本相同:
Note
Multiple execution algorithms can be used for backtesting, only limited by machine resources.注意
可以使用多个执行算法进行回测,仅受机器资源的限制。
# Instantiate and add your execution algorithm
# 实例化并添加您的执行算法
exec_algorithm = TWAPExecAlgorithm() # Using defaults
engine.add_exec_algorithm(exec_algorithm)
Now that we have our data, venues and trading system configured - we can run a backtest. Simply call the .run(...)
method which will run a backtest over all available data by default.
现在我们已经配置了数据、平台和交易系统 - 我们可以运行回测。只需调用 .run(...)
方法,默认情况下将对所有可用数据运行回测。
See the BacktestEngineConfig API reference for a complete description of all available methods and options. 有关所有可用方法和选项的完整描述,请参见 BacktestEngineConfig API 参考。
# Run the engine (from start to end of data)
# 运行引擎(从数据开始到结束)
engine.run()
Once the backtest is completed, a post-run tearsheet will be automatically logged using some default statistics (or custom statistics which can be loaded, see the advanced Portfolio statistics guide). 一旦回测完成,将使用一些默认统计数据(或可以加载的自定义统计数据,见高级投资组合统计指南)自动记录一份回测后统计表。
Also, many resultant data and execution objects will be held in memory, which we can use to further analyze the performance by generating various reports. 此外,许多结果数据和执行对象将保留在内存中,我们可以使用这些数据进一步生成各种报告以分析性能。
engine.trader.generate_account_report(BINANCE)
engine.trader.generate_order_fills_report()
engine.trader.generate_positions_report()
We can also choose to reset the engine for repeated runs with different strategy and component configurations. Calling the .reset(...)
method will retain all loaded data and components, but reset all other stateful values as if we had a fresh BacktestEngine (this avoids having to load the same data again).
我们还可以选择重置引擎,以便使用不同的策略和组件配置进行重复运行。调用 .reset(...)
方法将保留所有加载的数据和组件,但会重置所有其他状态值,仿佛我们有一个新的 BacktestEngine(这避免了再次加载相同的数据)。
# For repeated backtest runs make sure to reset the engine
# 对于重复的回测运行,请确保重置引擎
engine.reset()
Individual components (actors, strategies, execution algorithms) need to be removed and added as required. 单个组件(参与者、策略、执行算法)需要根据需要移除和添加。
See the Trader API reference for a description of all methods available to achieve this. 有关实现此目的的所有可用方法的描述,请参见 Trader API 参考。
# Once done, good practice to dispose of the object if the script continues
# 一旦完成,好的做法是在脚本继续时处置该对象
engine.dispose()