Backtest (high‐level API) - Loren1166/NautilusTrader- GitHub Wiki

Backtest (high-level API) 回测(高级API)

Tutorial for NautilusTrader a high-performance algorithmic trading platform and event driven backtester.
NautilusTrader 是一个高性能算法交易平台和事件驱动回测器的教程。

View source on GitHub 在 GitHub 查看源码

Overview 概述

This tutorial walks through how to use a BacktestNode to backtest a simple EMA cross strategy on a simulated FX ECN venue using historical quote tick data.
本教程将介绍如何使用 BacktestNode 在模拟的外汇 ECN 平台上对简单的 EMA 交叉策略进行回测,使用历史报价 tick 数据。

The following points will be covered:
将涵盖以下几点:

  • How to load raw data (external to Nautilus) into the data catalog
  • 如何将原始数据(Nautilus 之外)加载到数据目录中
  • How to set up configuration objects for a BacktestNode
  • 如何为 BacktestNode 设置配置对象
  • How to run backtests with a BacktestNode
  • 如何使用 BacktestNode 运行回测

Prerequisites 前提条件

  • 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)

Imports 导入

We'll start with all of our imports for the remainder of this tutorial.
我们将开始导入本教程其余部分所需的所有库。

import shutil
from decimal import Decimal
from pathlib import Path

import pandas as pd

from nautilus_trader.backtest.node import BacktestDataConfig
from nautilus_trader.backtest.node import BacktestEngineConfig
from nautilus_trader.backtest.node import BacktestNode
from nautilus_trader.backtest.node import BacktestRunConfig
from nautilus_trader.backtest.node import BacktestVenueConfig
from nautilus_trader.config import ImportableStrategyConfig
from nautilus_trader.core.datetime import dt_to_unix_nanos
from nautilus_trader.model.data import QuoteTick
from nautilus_trader.persistence.catalog import ParquetDataCatalog
from nautilus_trader.persistence.wranglers import QuoteTickDataWrangler
from nautilus_trader.test_kit.providers import CSVTickDataLoader
from nautilus_trader.test_kit.providers import TestInstrumentProvider

As a once off before we start the notebook - we need to download some sample data for backtesting.
在开始笔记本之前,我们需要一次性下载一些回测的示例数据。

For this example we will use FX data from histdata.com. Simply go to histdata.com and select an FX pair, then select one or more months of data to download.
在本示例中,我们将使用来自 histdata.com 的外汇数据。只需访问 histdata.com 并选择一个外汇对,然后选择一个或多个月份的数据进行下载。

Once you have downloaded the data, set the variable DATA_DIR below to the directory containing the data. By default, it will use the users Downloads/Data/ directory.
下载数据后,将下面的变量 DATA_DIR 设置为包含数据的目录。默认情况下,它将使用用户的 Downloads/Data/ 目录。

DATA_DIR = "~/Downloads/Data/"

path = Path(DATA_DIR).expanduser() / "HISTDATA"
raw_files = list(path.iterdir())
assert raw_files, f"Unable to find any histdata files in directory {path}"
raw_files

Loading data into the Parquet data catalog

将数据加载到 Parquet 数据目录

The FX data from histdata is stored in CSV/text format, with fields timestamp, bid_price, ask_price. Firstly, we need to load this raw data into a pandas.DataFrame which has a compatible schema for Nautilus quote ticks.
从 histdata 获得的外汇数据以 CSV/text 格式存储,字段包括时间戳、买入价和卖出价。首先,我们需要将这些原始数据加载到一个具有兼容 Nautilus 报价 tick 的 pandas.DataFrame 中。

Then we can create Nautilus QuoteTick objects by processing the DataFrame with a QuoteTickDataWrangler.
然后,我们可以通过使用 QuoteTickDataWrangler 处理 DataFrame 来创建 Nautilus QuoteTick 对象。

# Here we just take the first data file found and load into a pandas DataFrame
# 在这里,我们只取找到的第一个数据文件并加载到 pandas DataFrame 中
df = CSVTickDataLoader.load(raw_files[0], index_col=0, datetime_format="%Y%m%d %H%M%S%f")
df.columns = ["timestamp", "bid_price", "ask_price"]

# Process quote ticks using a wrangler
# 使用 wrangler 处理报价 ticks
EURUSD = TestInstrumentProvider.default_fx_ccy("EUR/USD")
wrangler = QuoteTickDataWrangler(EURUSD)

ticks = wrangler.process(df)

See the Loading data guide for further details.
有关更多详细信息,请参阅加载数据指南。

Next, we simply instantiate a ParquetDataCatalog (passing in a directory where to store the data, by default we will just use the current directory). We can then write the instrument and tick data to the catalog, it should only take a couple of minutes to load the data (depending on how many months).
接下来,我们只需实例化一个 ParquetDataCatalog(传入一个目录以存储数据,默认情况下我们将使用当前目录)。然后,我们可以将Instrument和 tick 数据写入目录,这可能只需几分钟(具体取决于多少个月)。

CATALOG_PATH = Path.cwd() / "catalog"

# Clear if it already exists, then create fresh
# 如果已存在则清空,然后创建新的
if CATALOG_PATH.exists():
    shutil.rmtree(CATALOG_PATH)
CATALOG_PATH.mkdir(parents=True)

# Create a catalog instance
# 创建目录实例
catalog = ParquetDataCatalog(CATALOG_PATH)

# Write instrument to the catalog
# 将Instrument写入目录
catalog.write_data([EURUSD])

# Write ticks to catalog
# 将 ticks 写入目录
catalog.write_data(ticks)

Using the Data Catalog

使用数据目录

Once data has been loaded into the catalog, the catalog instance can be used for loading data for backtests, or simply for research purposes. It contains various methods to pull data from the catalog, such as .instruments(...) and quote_ticks(...) (shown below).
数据加载到目录中后,目录实例可以用于加载回测的数据,或仅用于研究目的。它包含从目录中提取数据的各种方法,例如 .instruments(...)quote_ticks(...)(如下所示)。

catalog.instruments()

start = dt_to_unix_nanos(pd.Timestamp("2020-01-03", tz="UTC"))
end = dt_to_unix_nanos(pd.Timestamp("2020-01-04", tz="UTC"))

catalog.quote_ticks(instrument_ids=[EURUSD.id.value], start=start, end=end)[:10]

instrument = catalog.instruments()[0]

Add venues 添加平台

venue_configs = [
    BacktestVenueConfig(
        name="SIM",
        oms_type="HEDGING",
        account_type="MARGIN",
        base_currency="USD",
        starting_balances=["1_000_000 USD"],
    ),
]

Add data 添加数据

data_configs = [
    BacktestDataConfig(
        catalog_path=str(ParquetDataCatalog.from_env().path),
        data_cls=QuoteTick,
        instrument_id=instrument.id,
        start_time=start,
        end_time=end,
    ),
]

Add strategies 添加策略

strategies = [
    ImportableStrategyConfig(
        strategy_path="nautilus_trader.examples.strategies.ema_cross:EMACross",
        config_path="nautilus_trader.examples.strategies.ema_cross:EMACrossConfig",
        config={
            "instrument_id": instrument.id,
            "bar_type": "EUR/USD.SIM-15-MINUTE-BID-INTERNAL",
            "fast_ema_period": 10,
            "slow_ema_period": 20,
            "trade_size": Decimal(1_000_000),
        },
    ),
]

Configure backtest 配置回测

Nautilus uses a BacktestRunConfig object, which enables backtest configuration in one place. It is a Partialable object (which means it can be configured in stages); the benefits of which are reduced boilerplate code when creating multiple backtest runs (for example when doing some sort of grid search over parameters).
Nautilus 使用 BacktestRunConfig 对象,它允许在一个地方配置回测。它是一个可部分配置的对象(这意味着可以分阶段配置);其好处是在创建多个回测运行时减少样板代码(例如,当进行某种网格搜索参数时)。

config = BacktestRunConfig(
    engine=BacktestEngineConfig(strategies=strategies),
    data=data_configs,
    venues=venue_configs,
)

Run backtest 运行回测

Now we can run the backtest node, which will simulate trading across the entire data stream.
现在我们可以运行回测节点,它将模拟在整个数据流中的交易。

node = BacktestNode(configs=[config])

results = node.run()
results