Skip to content

Note: This the documentation for the current version toolbox released by Auquan. The old, stripped down version (installed as auquanToolbox, has been deprecated). You can see the current toolbox repository here - if you face any bugs, please open an issue on the github repository or email us at: [email protected]

Welcome to Auquan Toolbox

Auquan provides a backtesting toolbox to develop your trading algorithms. The toolbox is free and open source which you can use to create and backtest strategies.

Demo Video

You can watch a quick video demo for the toolbox below

Installation Guide

  1. Install Python and dependent packages
    Our toolbox is compatible with both Python 2.7( there are currently some issues with Python 3, we'll fix them shortly). The easiest way to install Python is through Anaconda since it will reliably install all the necessary dependencies. Download Anaconda and follow the instructions on the installation page. Once you have Python, you can then install the toolbox.

  2. Get the Auquan Toolbox There are multiple ways to install the toolbox for the competition.

    • Via pip: The easiest way and the most recommended way is via pip. Just run the following command: pip install -U auquan_toolbox. If we publish any updates to the toolbox, the same command pip install -U auquan_toolbox will also automatically get the new version of the toolbox. Note: Mac users, if you face any issues with installation, try using pip install --user auquan_toolbox
    • Via git: Clone/Download this repository.

      git clone https://github.com/Auquan/auquantoolbox.git

  3. Read the Getting Started Guide Above This guide explains the basics about how the toolbox works in a little more detail than here. It can also be accessed here

  4. Download this sample file and navigate to the place where you downloaded it (if you cloned the repo, the file is already present). Go inside that folder and run the following code to make sure everything is setup properly.

    python my_trading_params.py
    
  5. Use my_trading_params.py as a template which contains skeleton functions (with explanation) that need to be filled in to create your own trading strategy. Copy that template to another file and then start implementing the methods in that file. You can use pair_trading_params.py and meanreversion_trading_params.py as motivation.

How does the toolbox work?

Any security you want to trade with the toolbox is called an instrument. Right now, the toolbox supports stock and future instruments. All the parameters for the toolbox are supplied in class MyTradingParams().

Quick Setup

To get started quickly with the toolbox, you need to

  1. Get Historical Data
  2. Specify Features to be created from the Data
  3. Create a prediction function using above features to make your prediction for the market

The toolbox can handle everything else for you. You can do the above by modifying the following functions:

Getting Data - DataSource

Data Source parses data from external sources (csv, log file, html file etc) and loads and converts it into a toolbox compatible form. You need to specify the instrumentID's that you need data for and start and end date for data in in getDataParser() function.

def getDataParser(self):
        instrumentIds = ['IBM', 'AAPL', 'MSFT']
        startDateStr = '2017/05/10'
        endDateStr = '2017/06/09'
        return YahooStockDataSource(cachedFolderName='yahooData',
                                     instrumentIds=instrumentIds,
                                     startDateStr=startDateStr,
                                     endDateStr=endDateStr)

Current choices for datasource are: * YahooStockDataSource - Stock data from Yahoo (daily data) * NSEStockDataSource - Stock data from NSE (daily data) * AuquanDataSource - Data from US stock database of 500 biggest stocks maintained by Auquan.

Specifying Features - Instrument, Market and Custom Features

You can manipulate historical data by creating features. Features are called by specifying config dictionaries. You have to:

  1. Create one config dictionary per feature.

    Feature config Dictionary has the following keys:

    featureId: string representing the feature you want to use
    featureKey: {optional} string representing key to access value of this feature. If not present, use featureId
    params: {optional} A dictionary with which contains other parameters, if needed by the feature

  2. Return an array of all feature config dictionaries as market features or instrument features. Specify the instrument features in function getInstrumentFeatureConfigDicts() and market features in function getMarketFeatureConfigDicts(). Instrument features are calculated per instrument (for example position, fees, moving average of instrument price). The toolbox auto-loops through all instruments to calculate features for you. Market features are calculated for whole trading system (for example portfolio value).

    Example: If you want to use the moving_sum feature and calculate this for all instruments, your getInstrumentFeatureConfigDicts() function should be:

  def getInstrumentFeatureConfigDicts(self):
        msDict = {'featureKey': 'ms_5',
                'featureId': 'moving_sum',
                'params': {'period': 5,
                'featureName': 'basis'}}
        return [msDict]

You can now use this feature by calling it's featureKey, 'ms_5'.
Full list of features with featureId and params is available here.

Custom Features - Optional

To use your own custom features, you need to create them separately. Follow the example of this template. Specifically, you'll have to:

  • Create a new class for the feature and implement your logic. You can copy the template from this file. Example: If you were implementing a new InstrumentFeature
class MyCustomFeatureClassName(Feature):
    @classmethod
    def computeForInstrument(cls, featureParams, featureKey, currentFeatures, instrument, instrumentManager):
        return 5
  • Modify function getCustomFeatures() to return a dictionary with

    key: featureId to access this feature (Make sure this doesn't conflict with any of the pre defined feature Ids)
    value: Your custom Class Name which computes this feature. The class should be an instance of Feature

    Eg. to use the feature we create above via featureId='my_custom_feature_identifier',

def getCustomFeatures(self):
        return {'my_custom_feature_identifier': MyCustomFeatureClassName}
  • Now you can create a dict for this feature in getInstrumentFeatureConfigDicts(). Dict format is:
  customFeatureDict = {'featureKey': 'my_custom_feature_key',
                         'featureId': 'my_custom_feature_identifier',
                          'params': {'param1': 'value1'}}

Use this feature by calling it's featureKey, 'my_custom_feature_key'



Prediction Function

Combine all the features to create the desired prediction function. Fill the funtion getPrediction() to return the prediction for instrument you are trading.

Here you can call your previously created features by referencing their featureId. For example, I can call my moving sum and custom feature as:

def getPrediction(self, time, currentMarketFeatures, instrumentManager):

        # holder for all the instrument features
        lookbackInstrumentFeatures = instrumentManager.getLookbackInstrumentFeatures()

        ms5Data = lookbackInstrumentFeatures.getFeatureDf('ms_5')
        # dataframe for a historical instrument feature (ms_5 in this case).   
        # The index is the timestamps of atmost lookback data points.
        # The last row of this data frame would contain the features
        # which are being calculated in this update cycle or for this time.
        # The second to last row (if exists) would have the features for the previous
        # time update.
        # The columns of this dataframe are the stock symbols/instrumentIds.

        ms5 = ms5Data.iloc[-1]

        # This returns the value of the feature at the last time update
        # Returns a series with index as all the instrumentIds.

        customData = lookbackInstrumentFeatures.getFeatureDf('my_custom_feature_key')
        custom = customData.iloc[-1]
        predictions = ms5 / custom
        return predictions

Predictions can be of many types. You can calculate(predict) the FairValue of a parameter, for example price. You can predict the probability that price will increase in the future. You can predict the ratio of price of two securities. You can predict the ranking of a basket of securities. Output of the prediction function is used by the toolbox to make further trading decisions via the execution system. Choice of execution system depends on the type of prediction made.



Final Metrics

The system returns the following final metrics:

  1. Total PnL: Total Profit(or Loss) from your strategy as a % of initial capital
  2. Annualized Return: The yearly average % Profit(or Loss) from your trading strategy
  3. Annualized Volatility: The standard deviation of daily returns of the model in a year. Volatility is used as a measure of risk, therefore higher vol implies riskier model.
  4. Sharpe Ratio: The reward/risk ratio or risk adjusted returns of the strategy, calculated as Annualized Return/Annualized Volatility
  5. Sortino Ratio: Returns adjusted for downside risk, calculated as Annualized Return/Annualized Volatility of Negative Returns
  6. Max Drawdown: Largest drop in Pnl or maximum negative difference in total portfolio value. It is calculated as the maximum high to subsequent low difference before a new high is reached.
  7. Win/Loss, Average Profit/Loss: Sum(or Avergae) of Profits from trades that results in profits/Sum(or Average) of losses from trades that results in losses
  8. % Profitability = % of total trades that resulted in profits
  9. Return on Capital = Total Profit(or Loss) from your strategy as a % of max capital used

Other Metrics can be supported if needed.



Importing a trained model

If you would like to write your own custom datasource/execution system or you want to import a pre-trained ML model, you can do so in the manner below. Here we store a file training_execution_system.py on github. Then we specify the path to file, and the code downloads the file as fileName and imports the required class from it.

import urllib

path_to_file = 'https://raw.githubusercontent.com/Auquan/quant-quest-2/master/training_execution_system.py'
fileName = 'training_execution_system.py'
if not os.path.isfile(fileName):
    urllib.urlretrieve (path_to_file, fileName)

from training_execution_system import TrainingExecutionSystem