Python 3.9+

This page will guide you through the steps to backtest your strategy locally in Python 3.9+

Let us do a small backtest with our strategy locally, to ensure our algo logic is working and behaving as expected.

Preparing your main file for testing and live deployment scenarios

Once your strategy class is ready, now is the time to use it to test and deploy your strategy with Algorum. As mentioned in the Code your first strategy section, your strategy class will receive some parameters, which you need to pass in if you are testing/debugging your strategy class locally. As you can see in the below main method of your main.py file in the src sub folder of your project, we are reading those parameters from the environment variables. These environment variables will be filled in for you during the backtesting and live deployment of the strategy in Algorum Cloud. But for local testing and debugging you need to have these in the main.py file or somewhere that your main method can access.

import datetime
import os
import uuid

import AlgorumQuantClient.algorum_types
import golden_crossover_quant_strategy

if __name__ == '__main__':

    if 'url' in os.environ:
        url = os.environ['url']
    else:
        url = None

    if url is None or url == '':
        url = 'wss://<Your Algorum Quant Engine IP/URL>/quant/engine/api/v1'

    if 'apiKey' in os.environ:
        apikey = os.environ['apiKey']
    else:
        apikey = None

    if apikey is None or apikey == '':
        apikey = '<Your ALgorum API Key>'

    if 'launchMode' in os.environ:
        launchmode = os.environ['launchMode']
    else:
        launchmode = None

    if launchmode is None or launchmode == '':
        launchmode = AlgorumQuantClient.algorum_types.StrategyLaunchMode.Backtesting

    if 'sid' in os.environ:
        sid = os.environ['sid']
    else:
        sid = None

    if sid is None or sid == '':
        sid = uuid.uuid4().hex

    if 'userId' in os.environ:
        user_id = os.environ['userId']
    else:
        user_id = None

    if user_id is None or user_id == '':
        user_id = '<Your Alogrum User Account Id>'
        
    if 'bkApiKey' in os.environ:
        bk_api_key = os.environ['bkApiKey']
    else:
        bk_api_key = None

    if bk_api_key is None or bk_api_key == '':
        bk_api_key = '<Your Brokerage/Alpaca API Key>'

    if 'bkApiSecretKey' in os.environ:
        bk_api_secret_key = os.environ['bkApiSecretKey']
    else:
        bk_api_secret_key = None

    if bk_api_secret_key is None or bk_api_secret_key == '':
        bk_api_secret_key = '<Your Brokerage/Alpaca API Secret Key>'

    if 'clientCode' in os.environ:
        client_code = os.environ['clientCode']
    else:
        client_code = None

    if 'password' in os.environ:
        password = os.environ['password']
    else:
        password = None

    if 'twoFactorAuth' in os.environ:
        two_factor_auth = os.environ['twoFactorAuth']
    else:
        two_factor_auth = None

    if 'brokerageCountry' in os.environ:
        brokerage_country = os.environ['brokerageCountry']
    else:
        brokerage_country = None

    if brokerage_country is None or brokerage_country == '':
        brokerage_country = 'USA'

    if 'samplingTime' in os.environ:
        sampling_time = os.environ['samplingTime']
    else:
        sampling_time = 15

    url += '?sid=' + sid + '&apiKey=' + apikey + '&launchMode=' + launchmode + '&brokerageCountry=' + brokerage_country

    client = golden_crossover_quant_strategy.GoldenCrossoverQuantStrategy(
        url,
        apikey,
        launchmode,
        sid,
      	user_id
    )

    if 'brokeragePlatform' in os.environ:
        brokerage_platform = os.environ['brokeragePlatform']
    else:
        brokerage_platform = None

    if brokerage_platform is None or brokerage_platform == '':
        brokerage_platform = AlgorumQuantClient.algorum_types.BrokeragePlatform.Alpaca

    # Backtesting mode
    if launchmode == AlgorumQuantClient.algorum_types.StrategyLaunchMode.Backtesting:
        if 'startDate' in os.environ:
            startDate = datetime.datetime.strptime(os.environ['startDate'], '%d-%m-%Y')
        else:
            startDate = None

        if startDate is None or startDate == '':
            startDate = datetime.datetime.strptime('07-04-2021', '%d-%m-%Y')

        if 'endDate' in os.environ:
            endDate = datetime.datetime.strptime(os.environ['endDate'], '%d-%m-%Y')
        else:
            endDate = None

        if endDate is None or endDate == '':
            endDate = datetime.datetime.strptime('09-04-2021', '%d-%m-%Y')

        backtestRequest = AlgorumQuantClient.algorum_types.BacktestRequest(
            startDate, endDate, sid, bk_api_key, bk_api_secret_key,
            client_code, password, two_factor_auth, sampling_time, brokerage_platform)
        client.backtest(backtestRequest)
    else:
        tradingRequest = AlgorumQuantClient.algorum_types.TradingRequest(
            bk_api_key, bk_api_secret_key,
            client_code, password, two_factor_auth, sampling_time, brokerage_platform)
        client.start_trading(tradingRequest)

    client.wait()
    print('Main strategy thread exited')

Strategy Parameters

We have read about apikey, url, launchmode and sid parameters in the Code your first strategy section. The other parameters that you need for your strategy are described below.

Parameter NameDescription
bkApiKeyThis parameter is your brokerage API key. Applies mostly to the brokerages that provide access to their API using an API Key and Secret Key mechanism. Typical example is Alpaca Brokerage users.
bkApiSecretKeyThis parameter is your brokerage API Secret key. Applies mostly to the brokerages that provide access to their API using an API Key and Secret Key mechanism. Typical example is Alpaca Brokerage users.
clientCodeThis parameter is your brokerage account user id or client code, where applicable. Typically used only for live trading for Indian users. Not applicable for Alpaca Brokerage users.
passwordThis parameter is you brokerage account password, where applicable. Typically used only for live trading for Indian users. Not applicable for Alpaca Brokerage users.
twoFactorAuthThis parameter is your brokerage account two factor authentication code, where applicable. Typically used only for live trading for Indian users. Not applicable for Alpaca Brokerage users.
samplingTimeThis parameter is the sampling time, which indicates a period in seconds. Your strategy will receive the tick data from the Algorum Cloud at the interval of the given period in seconds. So if the value of samplingTime is 1, your strategy will receive ticks accumulated for each second. If you want to receive every tick from Algorum Cloud, then set this parameter value to 0.
brokeragePlatformThis parameter indicates the brokerage your strategy would run on. For USA users this is always Alpaca for now. For India users, this will be brokerage of the user, from the list of brokerages supported by Algorum.

Security of your strategy parameters

We understand that your strategy parameters are sensitive and need to be protected when deploying onto the Algorum Cloud. While running your strategy locally, you can use whatever means that best suites you to secure these parameters. While deploying the strategy to Algorum cloud, you need not embed these parameters in your code or in appsettings.json file. You can pass them directly to the Algorum CLI commands (backtest or paper/live trading), which encrypts them and makes them available to your strategy while running in Algorum Cloud. None of these parameters are stored permanently in any of our databases.

Create an instance of your strategy

Once you understand about the strategy parameters, you have to now create an instance of your strategy and initialize it with required parameters, which include your Algorum Quant Engine IP, your Algorum API Key, Launch Mode and Strategy Identifier.

url += '?sid=' + sid + '&apiKey=' + apikey + '&launchMode=' + launchmode

client = golden_crossover_quant_strategy.GoldenCrossoverQuantStrategy(
  url,
  apikey,
  launchmode,
  sid
)

Backtesting locally

Once you are ready with your parameters and instantiated your strategy class, as you can see in the main method, you can initiate the backtest using QuantEngineClient backtest method, by setting your launchMode parameter to a value of backtesting in your main method. If you want to preload the indicator data, you can override the backtest method in your strategy class, and use QuantEngineClient preload_candles method. Below is how you can override the backtest method.

def backtest(self, backtest_request: AlgorumQuantClient.algorum_types.BacktestRequest):
  # Preload the indicator evaluator with 200 candles
  self.evaluator.preload_candles(200, backtest_request.StartDate, backtest_request.ApiKey,
                                 backtest_request.ApiSecretKey)

  AlgorumQuantClient.quant_client.QuantEngineClient.backtest(self, backtest_request)

To start the backtesting you need to pass in the BacktestRequest object with backtest date range, Api keys (for USA users), etc.,. As the backtesting starts, your strategy on_tick method will start receiving the ticks from the backtest period and you can test and debug your strategy logic accordingly.

# Backtesting mode
if launchmode == AlgorumQuantClient.algorum_types.StrategyLaunchMode.Backtesting:
    if 'startDate' in os.environ:
        startDate = datetime.datetime.strptime(os.environ['startDate'], '%d-%m-%Y')
    else:
        startDate = None

    if startDate is None or startDate == '':
        startDate = datetime.datetime.strptime('07-04-2021', '%d-%m-%Y')

    if 'endDate' in os.environ:
        endDate = datetime.datetime.strptime(os.environ['endDate'], '%d-%m-%Y')
    else:
        endDate = None

    if endDate is None or endDate == '':
        endDate = datetime.datetime.strptime('09-04-2021', '%d-%m-%Y')

    backtestRequest = AlgorumQuantClient.algorum_types.BacktestRequest(
        startDate, endDate, sid, bk_api_key, bk_api_secret_key,
        client_code, password, two_factor_auth, sampling_time, brokerage_platform)
    client.backtest(backtestRequest)