Turning backtest to an executable live trading strategy#

In this chapter, we discuss how to turn a Jupyter Notebook based backtests to a live trading strategy module.

  • Strategy development and backtesting is usually performed in Jupyter Notebook environment.

  • After the strategy is ready for forward-testing with real money, it is time for Deploying live trading strategies with a standalone strategy module.

  • The strategy module is a standalone Python file without outside dependencies, including command line applications. The strategy module does not have any dependencies to complex Jupyter environment.

  • The strategy module itself can be backtested and analysed using Trade-executor command binary commands.

  • After you have created an independent strategy module, you need to run trade-executor backtest command against it to see your strategy module is functional (no import errors, backtest results are what is expected).

  • Some example strategy modules are available at trade-executor Github repository. Please check with the community for the latest examples before starting to work.

Turning a backtest to a strategy module#

Backtests are Jupyter notebooks, but live strategies need to be deployed as Python modules.

To create a Python strategy module from a backtest

  • Looks up examples in trade-executor module

  • Extract the following to a new Python .py module

    • Strategy variables

    • decide_trade() function

    • create_trading_universe() function (must be with this name, even as backtests allow other names)

    • Make sure the strategy module has TRADING_STRATEGY_ENGINE_VERSION as this defines how the module is parsed and loaded. The version must be “0.2” or newer.

    • You also need to set correct TRADE_ROUTING option. This is irrelevant option for backtesting, because no real trades are performed.

You can store the Python module anywhere, but we recommend

  • Create a folder strategies

  • Store the Python module as strategies/strategy-id.py e.g. strategies/arbitrum-btc-usdc-sls.py

Limitations in strategy modules#

Strategy modules

  • Cannot import any Python files that are not part of tradeexecutor Python package installation and dependencies

  • Cannot have writable global variables (constants are ok)

  • Any variables, history and such need to be stored as the part of tradeexecutor.state.state.State, or recalculated every time decide_trades function is entered

Backtest specific variables#

Some variables are only relevant for backtesting, not to the live trade execution. However, you still want to set these variables in your strategy module, as there variables are used to generate the backtesting benchmark results that are shown on the website user interface.

Following variables need to be set in the strategy module in order to perform trade-executor backtest command:

# Version >= 0.2

# How much USD the backtest starts with

# Backtest range we will use to show the results
# on the website
BACKTEST_START = datetime.datetime(2022, 12, 20)
BACKTEST_END = datetime.datetime(2023, 6, 4)

# Live execution will always use real-times stop loss.
# Coarse stop loss is usedin backtesting.

Run a backtest on the standalone strategy module#

This will run a backtest on a strategy module from the command line and display the summary backtest.

Create folder state in the current working directory. The backtest command will write multiple report files in this folder. If you want to override the file locations you can use command line arguments for backtest command to set a different location:

mkdir state

Run the backtest. Here we assume you have your strategy module as strategy/strategy/arbitrum-btc-usdc-sls.py:

# Replace with the latest version
# or set the latest executor release version using the script
source scripts/set-latest-tag.sh

# Read command line help
docker run \
    ghcr.io/tradingstrategy-ai/trade-executor:${TRADE_EXECUTOR_VERSION} \
    backtest --help

# Run the backtest using the backtest period given in the strategy module
docker run \
    -t \
    -v `pwd`:`pwd` \
    -w `pwd` \
    ghcr.io/tradingstrategy-ai/trade-executor:${TRADE_EXECUTOR_VERSION} \
    backtest \
    --strategy-file=strategy/arbitrum-btc-usdc-sls.py \

The Docker command above maps the current working directory (pwd) to Docker as a volume, so that Trade-executor command can read and write your local files.

On the results

  • The trade-executor backtest command complains if there are any errors with your strategy file, like missing variables

  • It will display the summary results to the console

  • It will write a report files like a standalone .HTML file for the results

Run a backtest on the deployed strategy module#

After the strategy module and Docker instance and its configuration have been deployed, you can run the backtest on the live trade executor with.

  • You have a ready live trading environment set up with docker-composer

The major difference is that all configuration, like TRADING_STRATEGY_API_KEY will now come from the Docker or docker-compose configuration and not from the command line.

docker-compose run enzyme-polygon-eth-usdc backtest
  • This will use the final configuration (strategy module, environment files) to run the backtest and see that the strategy module functions properly.

  • This will generate backtest reports (HTML, notebook, state) for the web frontend

  • The backtest result is saved on the local file system. The result of this backtest run is used to show some of the key metrics (sharpe, sortino, max drawdown) in the web frontend UI via Webhook server.

  • The default generated state file will be state/{id}-backtest.json.


And you will get a report like:

Trading period length                      359 days
Return %                                     57.96%
Annualised return %                          58.87%
Cash at start                            $10,000.00
Value at end                             $15,796.42
Trade volume                            $948,224.62
Position win percent                         48.48%
Total positions                                  66
Won positions                                    32
Avg realised risk                            -0.96%
Max pullback of total capital                -6.47%
Max loss risk at opening of position          1.02%