The APEX:E3 API offers users access to a powerful backtesting framework.
The following information uses javascript examples, but they can be easily converted to Python or any other programming language of choice.
The run-backtest.js contains an example of how to run a backtest.
The trading strategy buys when the EMA 50 crosses the EMA 200 from below and sells when the opposite condition arises.
The file contains the required trading strategy and indicator configurations:
let indicatorParams = {
indicator1: { type: 'ema', period: 50, priceComponent: 'close' },
indicator2: { type: 'ema', period: 200, priceComponent: 'close'}
};
let strategyParams = {
entryIndicator1: 'ema_ind1',
entryOperator: 'CROSSES_BELOW',
entryIndicator2: 'ema_ind2',
exitIndicator1: 'ema_ind1',
exitOperator: 'CROSSES_ABOVE',
exitIndicator2: 'ema_ind2',
stopLoss: 0.1
}
This indicator params specifiy the indicators and their parameters.
The strategy params specify the trade entry and exit conditions.
These configurations can be supplied as parameters to the runBacktest function:
let results = await apexe3.runBacktest(
10000,
'COINBASEPRO',
'BTC',
'USD',
'2018-01-01',
'2020-12-31',
indicatorParams,
strategyParams,
'DIGITAL',
'SPOT');
10000 - represents the startup capital
COINBASEPRO - the exchange
BTC - the base
USD - the quote
2018-01-01 - start date
2020-12-31 - end date
indicatorParams - indicator settings
strategyParams - strategy settings
Backtest MACD strategies
Strategy settings (strategyParams)
Entry condition: Buy when the macd is greater than the macd histogram
Exit condition: Sell when the macd signal is less than the macd
Stop Loss: Sell if losses exceed 5%
Indicator settings (indicatorParams):
Indicator 1 has type price
Indicator 2 has type macd. Because it is of type macd, we have to specify the shortPeriod, longPeriod and signal period. The priceComponent is used to define which part of the open high low close to use when calculating the macd. In the example below, close is used. If the priceComponent is not specified, close is used by default.
Note: the macd indicator has the following attributes, which are referenced in the strategy:
macd
histogram
signal
Read about the Macd indicator here.
***single quotes will be needed for all attributes and values when using Python
let indicatorParams = {
indicator1: { type: 'price' },
indicator2: { type: 'macd', shortPeriod: 12, longPeriod: 26,
signalPeriod: 9, priceComponent: 'close' }
};
let strategyParams = { entryIndicator1: 'macd_ind2',
entryOperator: '>',
entryIndicator2: 'histogram_ind2',
exitIndicator1: 'signal_ind2',
exitOperator: '<',
exitIndicator2: 'macd_ind2',
stopLoss: 5
}
*** notice the _ind2 suffix in the strategyParams: _ind2 refers to indicator2 in the indicatorParams. macd was specified within indicator2, therefore the macd indicators attributes have a _ind2 suffix in the strategyParams.
Backtest RSI strategies
Strategy settings (strategyParams)
Entry condition: Buy when the rsi is less than 30
Exit condition: Sell when the rsi is greater than 70
Stop Loss: Sell if losses exceed 5%
Indicator settings (indicatorParams):
Indicator 1 has type price
Indicator 2 has type rsi. Because it is of type rsi, we have to specify the period.
You can replace rsi with ema or sma.
The priceComponent is used to define which part of the open high low close to use when calculating the rsi. In the example below, close is used. If the priceComponent is not specified, close is used by default.
Read more about the RSI here.
***single quotes will be needed for all attributes and values when using Python
let indicatorParams = {
indicator1: { type: 'price' },
indicator2: { type: 'rsi', period: '14'}
};
let strategyParams = {
entryIndicator1: 'rsi_ind2',
entryOperator: '<',
entryIndicator2: '30',
exitIndicator1: 'rsi_ind2',
exitOperator: '>',
exitIndicator2: '70',
stopLoss: 5
};
Backtest EMA or SMA strategies
Strategy settings (strategyParams)
Entry condition: Buy when the EMA 50 crosses the EMA 200 from below
Exit condition: Sell when the EMA 50 crosses the EMA 200 from above
Stop Loss: Sell if losses exceed 1%
Indicator settings (indicatorParams):
Indicator 1 has type ema. Because it is of type ema, we have to specify the period (50).
Indicator 2 has type ema. Because it is of type ema, we have to specify the period (200).
You can replace ema with sma, if you want to test the SMA.
The priceComponent is used to define which part of the open high low close to use when calculating the ema or sma. In the example below, close is used. If the priceComponent is not specified, close is used by default.
Replace EMA with SMA if the indicatorParams setup uses SMA.
***single quotes will be needed for all attributes and values when using Python
let indicatorParams = {
indicator1: { type: 'ema', period: 50, priceComponent: 'close' },
indicator2: { type: 'ema', period: 200, priceComponent: 'close'}
};
let strategyParams = {
entryIndicator1: 'ema_ind1',
entryOperator: 'CROSSES_BELOW',
entryIndicator2: 'ema_ind2',
exitIndicator1: 'ema_ind1',
exitOperator: 'CROSSES_ABOVE',
exitIndicator2: 'ema_ind2',
stopLoss: 1
}
***Notice the use of _ind1 and _ind2 suffixes in the strategyParams
Backtest Bollinger Bands strategies
This strategy uses 2 indicators - EMA and Bollinger Bands:
Strategy settings (strategyParams)
Entry condition: Buy when the close price crosses the bollinger lower band from below
Exit condition: Sell when the close price crosses the EMA from above
Stop Loss: Sell if losses exceed 5%
Indicator settings (indicatorParams):
Indicator 1 has type bollinger. Because it is of type bollinger, we have to specify the period, stdDevUpper and stdDevLower values.
Indicator 2 has type ema. Because it is of type ema, we have to specify the period.
The priceComponent is used to define which part of the open high low close to use when calculating the bollinger . In the example below, close is used. If the priceComponent is not specified, close is used by default.
Note: the bollinger indicator has the following attributes, which are refrenced in the strategy:
bollingerUpper
bollingerMiddle
bollingerLower
***single quotes will be needed for all attributes and values when using Python
let indicatorParams = {
indicator1: { type: 'bollinger',
period: 20,
stdDevUpper: 2,
stdDevLower: 2
},
indicator2: { type: 'ema', period: 30}
};
let strategyParams = {
entryDirection: 'long',
entryIndicator1: 'close',
entryOperator: 'CROSSES_BELOW',
entryIndicator2: 'bollingerLower_ind1',
exitIndicator1: 'close',
exitOperator: 'CROSSES_ABOVE',
exitIndicator2: 'ema_ind2',
stopLoss: 5
}
***Notice the use of _ind1 and _ind2 suffixes in the strategyParams
Data Generated by the Backtest
Once a backtest is successfully run, 3 data sets are generated:
analysis - this is a summary report showing how the backtest performed
trades - this contains all the trades associated with the backtest
maketData - this contains the OHLCV prices, relevant indicator values and entry and exit prices used in the backtest