Backtester Documentation

Docs

Backtester Documentation

Welcome to the backtesting documentation! Here you will find detailed information about creating python-based strategies and indicators, as well as how to backtest them. We provide information on the different backtesting functions, the data used, creating scripts and the limitations of different types of backtests. We also provide sections on creating multi-timeframe strategies, creating custom indicators for your charts, and how to access and use the marketplace. Additionally, you can learn about your plan and API limit. Start exploring and leveraging our powerful backtester today!


Get Started
  • Create and customise trading strategies
  • Optimise performance and improve returns
  • Robustness and usage across different tickers and asset classes
  • Testing and live execution of your strategy

Your Plan
No active plan.
Your Backtest Limit

10 per day

Daily Backtests

7 run


Your Scipts
Your profile page is home to all of your custom strategies and indicators. Within the 'Scripts' tab on your profile page, you will find all scripts whether you create strategies and indicators from scratch or downloaded them from the marketplace. From here, you can also edit your scripts and backtest them.

API Key

How to use your API Key

In order to make an call, you will need to pass an API key into the URL or the header of your request. This can be anywhere in the URL or header, but must be in the format: apiKey={yourApiKey}

bdpo.io/api/endpoint?apiKey={yourApiKey}


The Backtester Lab: Introduction

The BDPO Backtester Lab is a python-based backtesting platform that allows you to create, backtest and optimise your own trading strategies. Designed for traders of all levels, the backtester lab will provide in-depth details on performance, risk, returns, statistics and individual trades.

As well as backtesting your strategy on a historical data, the backtester lab allows for optimisation of your strategy parameters, forward testing on unseen data (both backtests and optimisations), as well as stress testing of your strategy on hundreds of samples of data. This allows you to understand the robustness of your strategy and how it may perform in the future.


Structure

When creating strategies and indicators in the Strategy Editor, these scripts will be written using the Python programming language. As a result, strategies and indicators should be written in a specific format using classes/functions in order to be backtested. The documentation below will provide an overview of the structure of both strategies and indicators, as well as how to write and backtest them.

It is important to note that the backtester lab is designed to be as flexible as possible, allowing for the creation of a wide range of strategies and indicators. If you are not familiar with Python, there are many community written scripts available in the marketplace that you can download and backtest yourself without the need to write any code.


Whitelist

To prevent abuse of the backtester lab, we have implemented a whitelist system. This means that only certain python libraries can be imported and used when defining your strategies and indicators. The following libraries are whitelisted and can be used in your scripts:

  • BDPO
  • datetime
  • pandas
  • numpy
  • time
This list is constantly being updated, so if you would like to use a library that is not on this list, please contact us and we will consider adding it to the whitelist.


Strategy Editor

The Strategy Editor is where you will create and edit your strategies and indicators. This is an in-browser code editor that allows you to write your scripts in Python. Once you have written your script, you can save it to your profile and backtest it using the backtester lab, or apply it to your charts in the charting platform.

In the event of an error in your script, check the console (in the backtester lab for strategies or in the chart console for indicators) for more information on the error.

To begin writing your own scripts, visit the Strategy Editor page.


Backtest

Once you have written your strategy or indicator in the Strategy Editor, or downloaded a script from the marketplace, you can backtest it using the backtester lab. This will provide you with detailed information on the performance of your strategy, including returns, risk, statistics and individual trades.

To begin backtesting your scripts, visit the Backtester Lab page.


Chart

Once you have written your indicator script in the Strategy Editor, or downloaded a script from the marketplace, you can apply it to your charts in the charting platform. This will allow you to see the indicator plotted on the chart, as well as any buy/sell signals that are generated by the indicator.

To begin applying your scripts to your charts, visit the Charting page.


Structure

Strategies in the BDPO Backtester Lab are written in Python and should be structured in a specific way in order to be backtested. The structure of a strategy is as python class as follows:

  • Library Imports
  • Strategy Class
  • 'params' dictionary
  • __init__ Method
  • 'next' Method

Here is a skeleton structure of a strategy script:

import BDPO

class Strategy(BDPO.Strategy):

    params = {
        'param1': 1,
        'param2': 2
    }

    def __init__(self, data):

        # define any variables here
        pass

    def next(self, data):

        # define your strategy logic here (evaluated at each new datapoint)
        pass

Within this strategy structure there are three main components. The first being the params dictionary. This dictionary is used to define any parameters that you would like to be able to adjust when backtesting your strategy. These parameters can be adjusted in the backtester lab and will be passed to the strategy when it is initialized. The second component is the __init__ method. This method is used to initialize any variables that you would like to use in your strategy. The third component is the next method. This method is called at each new datapoint and is where you define the logic of your strategy. This is where you will define your buy/sell signals based on the data that is passed to the strategy.

You'll notice that 'data' is passed as an argument to both the __init__ and next methods. This 'data' object contains the OHLCV data for the asset that you are backtesting, and is needed for the strategy to run.


Data Format

Arguably, the most crucial part of creating a strategy of your own is to be able to understand and work with the data in which you are testing on.
The BDPO backtest was designed with speed and accuracy in mind. To achieve this, the data is stored, and passed to the strategy in the form of a Numpy array. To understand how to work with this data, we will look at the format of the data, and also how to access it.

  • data

Lets see what happens when printing the following:

def next(self, data):
    self.log(data)


The result of printing this will look something like:

BDPO.Engine.data_handler.backtest_data_handler object at 0x00000259B8E42790

This isn't very helpful to us, so lets look at how we can access the data.


  • data[0]
The data is stored so you can access multiple timeframes within the same strategy. When you begin a backtest, you will chose the timeframe you wish to test on. This will be your base timeframe, or timeframe [0].

To demonstrate this, if we set up a backtest to run on the 1hour timeframe, my base timeframe will be the 1hour timeframe, and therefore, data[0] will be the 1hour timeframe data. The same will apply if I set up a backtest on the 5minute timeframe, I can access this timeframe's data by calling data[0]. Now lets look at what happens when we print data[0]:

def next(self, data):
    self.log(data[0])


Console:
>> [(datetime.datetime(2024, 2, 15, 0, 0), 1.07322, 1.0733, 1.073, 1.07319, 57)]


We have data!

With each candle that passes, we have logged our data. This backtest was run on the 1hour timeframe, and as a result of logging data[0], we have access to the 1hour timeframe data. As the backtest progresses, we will see the dataset evolve and continue to be printed to the console.

Note: The next() function runs on each new datapoint on the tick and/or minute timeframe. Therefore, by printing data[0] in the next() function, we are printing the latest candle, which is updated with any new incoming data on the tick/minute timeframe. As a result, the data is 'built' up as it would be in a live trading environment. The data['1h'] for example, will appear to only have one candle until the next 1 hour candle is formed from the tick/minute data.

  • Note: While printing data (or any variables) to the console like this is helpful for development, these log statements will slow down your backtest significantly. It is recommended to remove these log statements when they are no longer needed.


To take this a step further, we can print just the last element (which is the latest candle), by calling:

def next(self, data):
    self.log(data[0][-1])


Console:
>> (datetime.datetime(2024, 2, 15, 0, 0), 1.07322, 1.0733, 1.073, 1.07319, 57)


Now we have the latest candle printed to the console, in the format (datetime, open, high, low, close, volume). As mentioned, this is the latest candle which is being updated live as the script executes. What if we just wanted the close price of the latest candle?

def next(self, data):
    self.log(data[0][-1]['c'])


Console:
>> 1.0903
>> 1.09059
>> 1.09045


It is possible to also access the datetime / open / high / low / close / volume of the previous candle by calling them in the same way.

  • ['t']
  • ['o']
  • ['h']
  • ['l']
  • ['c']
  • ['v']

Now we have accessed the latest candles of our based timeframe using data[0], but what if we wanted to access the latest candles of a different timeframe?

Multi-Timeframes:
In the backtester, we choose our base timeframe when we initialize our strategy. However we also have the following timeframes at our disposal:

  • '1m'
  • '5m'
  • '15m'
  • '30m'
  • '1h'
  • '4h'
  • '1d'

We can access the multitimeframe data in a similar way:

def next(self, data):

    # base timeframe
    self.log(data[0])

    # 1m timeframe
    self.log(data['1m'])

    # 5m timeframe
    self.log(data['5m'])

    # 15m timeframe
    self.log(data['15m'])

    # 30m timeframe
    self.log(data['30m'])

    # 1h timeframe
    self.log(data['1h'])

    # 4h timeframe
    self.log(data['4h'])

    # 1d timeframe
    self.log(data['1d'])


Now we have access to the multi timeframes' data. We can access this data by now by calling data['5m'] etc., as well as accessing the base timeframe using data[0]. We can also access the latest candle of the each timeframe by calling data[timeframe][-1] as we have done previously with the base timeframe data. below are some examples of accessing different timeframes and candles:

def next(self, data):
    self.log(data['1m']) # This will get the '1m' candles since the start of the backtest
    self.log(data['5m']) # This will get the '5m' candles since the start of the backtest
    self.log(data['15m']) # This will get the '15m' candles since the start of the backtest
    self.log(data['30m']) # This will get the '30m' candles since the start of the backtest
    self.log(data['1h']) # This will get the '1h' candles since the start of the backtest
    self.log(data['4h']) # This will get the '4h' candles since the start of the backtest
    self.log(data['1d']) # This will get the '1d' candles since the start of the backtest

    self.log(data['1m'][-1]) # This will get the latest '1m' candle
    self.log(data['5m'][-1]) # This will get the latest '5m' candle
    # etc...

    self.log(data['1m']['c']) # This will get all the 'close' prices of the '1m' candles
    self.log(data['5m']['c']) # This will get all the 'close' prices of the '5m' candles
    # etc...

    self.log(data['1m']['c'][-1]) # This will get the latest 'close' price of the '1m' candles
    self.log(data['5m']['c'][-1]) # This will get the latest 'close' price of the '5m' candles
    # etc...

    self.log(data[-1]) # This will get the latest candle of all timeframes including the base timeframe
    self.log(data['c']) # This will get all close prices of all timeframes including the base timeframe

    self.log(data[-3:]) # This will get the last 3 candles of all timeframes including the base timeframe
    self.log(data[0][-3:]) # This will get the last 3 candles of the base timeframe
    self.log(data[("t", "c")]) # This will get the datetime and close prices of all timeframes



Getting Started

Let's run through a simple RSI strategy template to get started. The first step for every strategy is to import the BDPO library. This is a built-in library that provides powerful and flexible functionality for backtesting. By importing it, you will be able to access all the functions and methods that are required to build your strategy. The strategy will not run without it:

import BDPO
# import other libraries here


The benefits of using a python based strategy editor is that you have access to all the powerful libraries that python has to offer. You can import multiple libraries, and use it to enhance your strategy.

NOTE: BDPO has a whitelist of libraries that are allowed to be imported. This is to ensure that the platform is secure and to prevent any malicious code from being executed. Navigate to the 'Whitelist' section of this documentation to find out more.After importing your libraries, it is time to set up the strategy Class.

To create a strategy, you need to create a class that inherits from the BDPO.Strategy class. This class will contain all the methods and attributes that are required to run your strategy. We can also define our strategy params here too. The params dictionary is used to store all the parameters that are required for the strategy. These parameters can be modified in the backtester lab when running the strategy. Here is an example of a strategy class:

import BDPO

class Strategy(BDPO.Strategy):

    params = {
        'length': 4,
        'deviation': 2
        'max_trades': 1
    }

...


So far we have imported the BDPO library and created a strategy class. We have then also defined the params dictionary. The next step is to define the __init__ method. This method is called when the strategy is initialized. It is used to set up the strategy and to define any variables that are required. Here is an example of the __init__ method:

import BDPO

class Strategy(BDPO.Strategy):

    params = {
        'length': 4,
        'deviation': 2
        'max_trades': 1
    }


    def __init__(self, data):
        self.my_variable = 10

Here, the __init__ function is defined with 'self' and 'data' as input arguments. This is necessary for the strategy to run.

Within the __init__ function, we define any variables we wish to refer back to during the running of the strategy. If no variables have been defined, the __init__ function must still be defined, but can be passed using 'pass'. In this example, we are defining a variable 'my_variable' and setting it to 10. This is a simple example, but you can define any variables you wish. Now for the 'next' function:

import BDPO

class Strategy(BDPO.Strategy):

    params = {
        'length': 4,
        'deviation': 2
        'max_trades': 1
    }


    def __init__(self, data):
        self.my_variable = 10


    def next(self, data):

        self.rsi = BDPO.rsi(data[0], self.params['length'])['data']

        if self.total_open_positions() < self.params['max_trades']:

            if self.rsi[-1, -1] > 70:
                result = self.trade(
                    trade_type="SELL",
                    trade_lots=0.01,
                )

            elif self.rsi[-1, -1] < 30:
                result = self.trade(
                    trade_type="BUY",
                    trade_lots=0.01,
                )

        elif self.total_open_positions() == self.params['max_trades'] and (self.rsi[-1, -1] > 45 and self.rsi[-1, -1] < 55):
            self.close_all()

Here we have defined a few things so lets go through them one by one:

self.rsi = BDPO.rsi(data[0], self.params['length'])['data'] This line of code is calculating the RSI of the data that is passed in. The RSI is calculated using the 'BDPO.rsi' function, which takes in the data and the length of the RSI as input arguments. This will return a dictionary with the RSI data, which we then access using ['data']. The RSI is then stored in the 'self.rsi' variable.

if self.total_open_positions() < self.params['max_trades']: This line of code is checking if the absolute value of the number of open positions is less than the maximum number of trades allowed (self.params['max_trades']).

if self.rsi[-1, -1] > 70: This line of code is checking if the RSI is greater than 70. The BDPO.rsi function returns a 2D array [timestamp, rsi value], and we are accessing the -1 index, (the last row of the rsi data, and also the most recent rsi value for the given data), as well as the -1 element in the row (the last element which is the rsi value).

result = self.trade(trade_type="SELL", trade_lots=0.01) This line of code is executing a trade. The 'self.trade' function is used to execute a trade, and takes in the trade type and the trade lots as input arguments as well as others. In this case, we are selling 0.01 lots. The built in functions such as self.trade are defined in the Strategy Functions section of this documentation

self.close_all() The 'self.close_all' function is used to close all open positions. The strategy logic runs this close_all function when the number of open positions is equal to the maximum number of trades allowed, and the RSI is between 45 and 55.

The backtester will run with the given data, and the job of the next() function is to execute trading logic based on the conditions that we set. The next() function evalutes the trading conditions at each datapoint, and is the main function that we will be using to execute trades. In this example above, the rsi values are re-calculated on each new datapoint received, as is anything defined in the next() function. Here we have now defined a basic set of rules for our strategy to follow. Next up, we can test our strategy for potential errors, and run in the backtester.


Strategy Functions

Below are the built-in functions defined in the BDPO library to help create, manage, execute and optimise strategies:



  • self.log(message)

The 'self.log' function is used to log messages to the console. This can be useful for debugging (similar to the python print() function)

self.log("Hello World")



  • self.get_current_close()

Most commonly used in the next() function, this function returns the current close price of the current candle. The return of this function is a float value.

self.get_current_close()



  • self.get_current_open()

Most commonly used in the next() function, this function returns the current open price of the current candle. The return of this function is a float value.

self.get_current_open()



  • self.get_current_high()

Most commonly used in the next() function, this function returns the current high price of the current candle. The return of this function is a float value.

self.get_current_high()



  • self.get_current_low()

Most commonly used in the next() function, this function returns the current low price of the current candle. The return of this function is a float value.

self.get_current_low()



  • self.get_current_time()

Most commonly used in the next() function, this function returns the current time of the current candle. The return of this function is a datetime value.

self.get_current_time()



  • self.get_current_volume()

Most commonly used in the next() function, this function returns the current volume of the current candle. The return of this function is an integer.

self.get_current_volume()



  • self.get_data(timeframe)

This function returns the data of the current symbol and timeframe provided, up until the latest candle. The return of this function is a numpy array.

self.get_data(timeframe)



  • self.get_capital()

This function returns the current capital of the account at time of calling.

self.get_capital()



  • self.get_equity()

This function returns the current equity of the account at time of calling.

self.get_equity()



  • self.get_open_positions()

This function returns a list of open positions at time of calling.

self.get_open_positions()



  • self.get_pending_positions()

This function returns a list of pending positions at time of calling.

self.get_pending_positions()



  • self.total_open_positions()

This function returns the number of positions open in total (not including pending trades) and returns an integer.

self.total_open_positions()



  • self.symbol_info()

This function returns a dictionary of the symbol's information.

self.symbol_info()



  • self.trade()

This function is used to execute market and pending orders.

self.trade(
    trade_type,
    trade_lots,
    trade_price,
    trade_stop_loss,
    trade_take_profit,
    trade_hash_number
)

trade_type:
This could be any of the following:

  • BUY or 0
  • SELL or 1
  • BUY_LIMIT or 2
  • SELL_LIMIT or 3
  • BUY_STOP or 4
  • SELL_STOP or 5

trade_lots:
This is the lots to be traded. Min lots = 0.01 and max lots = 20.00

trade_price:
This is only applicable for pending positions, and will be ignored for market orders. For BUYSTOP the price must be above the current price, and for SELLSTOP the price must be below the current price. For BUYLIMIT the price must be below the current price, and for SELLLIMIT the price must be above the current price.

trade_stop_loss:
This is optional and is the stop loss for the trade.

trade_take_profit:
This is optional and is the take profit for the trade.

trade_hash_number:
This is optional and is a unique identifying number for each trade. If not provided, it will be generated automatically.

Note: All open and pending trades will be assigned an ID (incremental) which is also returned when executing a successful self.trade()



  • self.cancel_pending_position_by_id(id)

This function is used to cancel pending orders by their ID.

self.cancel_pending_position_by_id(id)



  • self.cancel_all_pending_positions()

This function is used to cancel all pending orders.

self.cancel_all_pending_positions()



  • self.close_by_id(id)

This function is used to close an open order by it's ID (integer).

self.close_by_id(id)



  • self.close_all()

This function is used to close all open orders.

self.close_all()


Structure

Also build using the python framework, custom indicators should be structured in a specific way in order to be compatible and deployable on your charts. The structure of a custom indicator is different to custom stategies, in the fact that indicators are python functions. The structure of a custom indicator is as follows:

  • Library Imports
  • Indicator Function
  • Indicator Logic
  • Returning the Indicator Overlay

Here is a skeleton structure of a strategy script:

import BDPO

def MyIndicator(data, length: int=10):

    datetime, open, high, low, close, volume = BDPO.data_to_pandas(data)

    # define your indicator logic here

    overlay = {
        "type": "Spline",
        "data": data,
        "props": {"color": "#f52f07"},
    }

    return overlay



Within this indicator structure there are three main components. The first being the library imports. Secondly, the indicator function. This is where you define the logic of your indicator. Finally, the returning the indicator overlay. This is where you define the overlay that will be displayed on the chart when the indicator is applied.

The overlay dictionary is used to define the type of the indicator plot (eg. line plot, area plot...). It also contains the data, which should be in the format of a pandas DataFrame, or Numpy array.

You'll notice that 'data' is passed as an argument to function. This 'data' object contains the OHLCV data for the asset that your indicator is running on and is needed for the strategy to run.


Getting Started

Let's create a simple custom indicator that calculates the moving average of the close price of an asset (Simple Moving Average). The first step is to create a new indicator script, and import the BDPO library and any other libraries that are included in the whitelist in which you may need in your script. Next we will define the indicator function:

import BDPO
import pandas as pd
import numpy as np

def MyIndicator(data, length: int=10):

...

So far we have imported the BDPO library, and the pandas and numpy libraries. We have also defined the indicator function 'MyIndicator'. As previously mentioned, we must pass 'data' to the function in order to access the OHLCV data of the asset that the indicator is running on.

In this function we have also declared the 'length' parameter, which is the number of periods that the moving average will be calculated over. It is important to declare each variable type (int, float etc...) as well as a default value. Any variables declared here will be customisable when deploying the indicator on the charting page

Variable types must be one of the following:

  • int
  • float
  • str
  • bool
  • list

After defining the type of the variable, a default value must be assigned to the variable.


Next, we will define the body of the function, where the logic of the indicator will be implemented. In this case, we will calculate the simple moving average of the close price of the asset.

import BDPO
import pandas as pd
import numpy as np

def MyIndicator(data, length: int=10):

    datetime, open, high, low, close, volume = BDPO.data_to_pandas(data)

    sma = close.rolling(window=length).mean()
...

In our indicator body, we have defined the simple calculations for the moving average (the average of the last n periods). We have also included the BDPO.data_to_pandas function to handle the data into the Indicator function. The data_to_pandas function is used to convert and return the OHLCV components of the data, into a pandas dataframe. This make it easier to work with when coding up your indicator. Also available is the BDPO.data_to_numpy function, which will convert the data into a numpy array.

Also available is the BDPO.data_to_numpy function, which will convert the data into a numpy array.

The final step in defining the function is to format the indicator. This is done by ensuring that the datetimes are in the first column:

import BDPO
import pandas as pd
import numpy as np

def MyIndicator(data, length: int=10):

    datetime, open, high, low, close, volume = BDPO.data_to_pandas(data)

    sma = close.rolling(window=length).mean()

    combined = pd.DataFrame({'datetime': datetime, 'sma': sma})
...

We now have a dataframe with columns 'datetime' and 'sma'. The 'datetime' column is the first column in the dataframe. The 'sma' column is the moving average of the close prices. It is now ready to be formatted for the chart.


Function Overlay:

Now that we have defined the body of the function, we can define the 'overlay' to prepare it for our charting. The overlay is a python dictionary containing the indicator details.

The overlay dictionary must contain:

  • type: the type of plot to be used (see Custom Indicators: Configuration)
  • data: the data to be plotted
  • props: the properties of the plot (including color, linewidth etc.) see Indicator Configuration for more details
  • settings: the settings of the plot (including decimal precision). see Indicator Configuration for more details

import BDPO
import pandas as pd
import numpy as np

def MyIndicator(data, length: int=10):

    datetime, open, high, low, close, volume = BDPO.data_to_pandas(data)

    sma = close.rolling(window=length).mean()

    overlay = {
        "type": "Spline",
        "data": combined,
        "props": {"color": "#f52f07"},
        "settings": {
            "precision": 1
        }
    }

    return overlay

The key things to note here are:

  • overlay: this is a dictionary, with keys and values
  • There are 4 main keys to return within the overlay: ("type", "data", "props", "settings")
  • type: this is the type of plot. In this case, we are using a spline (line) plot
  • data: this is the data that will be plotted. In this case, we are using the SMA data (this is either in the format of a pandas dataframe, numpy array, or list of lists)
  • props: these are the properties of the plot. In this case, we are defining the colour of the plot
  • settings: these are the settings of the plot. In this case, we are defining the decimal precision of the data

Configuration

Above, we have seen how to create and return an indicator. Now, we will look at the options you have when returning the indicator overlay. The indicator overlay is a dictionary with 4 keys: "type", "data", "props" and "settings".The 'type' key is the type of plot that will be used. These are the built-in options available:

  • Area
    • [Series] the area under the Series' spline is shaded
    • Props:
      • color
        • Type: color
          Default: #31ce31
      • lineWidth
        • Type: number
          Default: 1.25
      • back1
        • Type: color
          Default: color + '15'
      • back2
        • Type: color
          Default: color + '1'
  • Spline
    • [Series] a basic line plot of a series
    • Props:
      • color
        • Type: color
          Default: #31ce31
      • lineWidth
        • Type: number
          Default: 1
  • Splines
    • [Series, Dataframe] line plot(s) for each column in the dataframe
    • Props:
      • colors
        • Type: list
          Default: []
      • lineWidth
        • Type: number
          Default: 1
      • widths
        • Type: list
          Default: []
  • Sparse
    • [Series] a dotted line plot
    • Props:
      • color
        • Type: color
          Default: #898989
      • size
        • Type: number
          Default: 3
  • Band
    • [Dataframe of columns <"high">, <"mid">, <"low">] a band similar to Bollinger Bands
    • Props:
      • color
        • Type: color
          Default: #b41d70
      • backColor
        • Type: color
          Default: color + 11
      • lineWidth
        • Type: number
          Default: 1
      • showMid
        • Type: boolean
          Default: 'true'
  • Superbands
    • [Dataframe of columns <"high1">, <"mid1">, <"low1">, <"high2">, <"mid2">, <"low2">] Two bands: above and below the price
    • Props:
      • color1
        • Type: color
          Default: #d80d3848
      • color1dark
        • Type: color
          Default: #d80d3824
      • color2
        • Type: color
          Default: #1edbbe33
      • color2dark
        • Type: color
          Default: #1edbbe15
  • Cloud
    • [Dataframe of columns <"line1">, <"line2">] Cloud
    • Props:
      • color
        • Type: color
          Default: #55d7b0aa
      • color2
        • Type: color
          Default: #d94d64aa
      • back1
        • Type: color
          Default: #79ffde22
      • back2
        • Type: color
          Default: #ff246c22
  • Histogram
    • [Dataframe of columns <"hist">, <"?value">, <"?signal">] Colored histogram, can be used for MACD
    • Props:
      • barWidth
        • Type: number
          Default: 4
      • lineWidth
        • Type: number
          Default: 1
      • colorUp
        • Type: color
          Default: #35a776
      • colorDw
        • Type: color
          Default: #e54150
      • colorSemiUp
        • Type: color
          Default: #79e0b3
      • colorSemiDw
        • Type: color
          Default: #ea969e
      • colorValue
        • Type: color
          Default: #3782f2
      • colorSignal
        • Type: color
          Default: #f48709
  • Range
    • [Series <"value">] Ranging indicator, e.g. RSI
    • Props:
      • color
        • Type: color
          Default: #ec206e
      • backColor
        • Type: color
          Default: #381e9c16
      • bandColor
        • Type: color
          Default: #535559
      • lineWidth
        • Type: number
          Default: 1
      • upperBand
        • Type: number
          Default: 70
      • lowerBand
        • Type: number
          Default: 30
  • Trades
    • [Dataframe <"dir">, <"price">, <"?label">] Simple trades: <"dir"> :: 1 for buy -1 for sell <"price"> :: trade price <"?label"> :: trade label
    • Props:
      • buyColor
        • Type: color
          Default: #08b2c6
      • sellColor
        • Type: color
          Default: #e42633
      • radius
        • Type: number
          Default: 4
      • showLabels
        • Type: boolean
          Default: 'true'
      • markerOutline
        • Type: boolean
          Default: 'true'
      • outlineWidth
        • Type: number
          Default: 4
  • PriceLabels
    • [Dataframe <"labelObject">] Price labels that stick to candles <"LabelObject"> { text :: string, text of the label dir :: direction, 1 = points up, -1 = points down pin :: "open" | "high" | "low" | "close" ?color :: color, text color ?back :: color, background ?stroke :: stroke color ?offset, px, offest from the pin }
    • Props:
      • color
        • Type: color
          Default: #adadad
      • back
        • Type: color
          Default: #14151c
      • borderRadius
        • Type: number
          Default: 3
      • offset
        • Type: number
          Default: 5

Built-In Charting Indicators

Below is a list of built-in charting indicators that can be applied to your chart, as well as referenced in your strategy scripts (by importing the BDPO library and referencing the indicator).


  • BDPO.ht_dcperiod (Hilbert Transform - Dominant Cycle Period)
    • data: [np.ndarray]

  • BDPO.ht_dcphase (Hilbert Transform - Dominant Cycle Phase)
    • data: [np.ndarray]

  • BDPO.ht_phasor (Hilbert Transform - Phasor Components)
    • data: [np.ndarray]

  • BDPO.ht_sine (Hilbert Transform - SineWave)
    • data: [np.ndarray]

  • BDPO.ht_trendmode (Hilbert Transform - Trend vs Cycle Mode)
    • data: [np.ndarray]

  • BDPO.add (Vector Arithmetic Add)
    • data: [np.ndarray]

  • BDPO.div (Vector Arithmetic Div)
    • data: [np.ndarray]

  • BDPO.minmax (Lowest and highest values over a specified period)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 30)

  • BDPO.mult (Vector Arithmetic Mult)
    • data: [np.ndarray]

  • BDPO.sub (Vector Arithmetic Subtraction)
    • data: [np.ndarray]

  • BDPO.summation (Summation)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 30)

  • BDPO.ceil (Vector Ceil)
    • data: [np.ndarray]

  • BDPO.cos (Vector Trigonometric Cos)
    • data: [np.ndarray]

  • BDPO.floor (Vector Floor)
    • data: [np.ndarray]

  • BDPO.ln (Vector Log Natural)
    • data: [np.ndarray]

  • BDPO.log10 (Vector Log10)
    • data: [np.ndarray]

  • BDPO.sin (Vector Trigonometric Sin)
    • data: [np.ndarray]

  • BDPO.adx (Average Directional Movement Index)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.adxr (Average Directional Movement Index Rating)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.apo (Absolute Price Oscillator)
    • data: [np.ndarray]
    • fastperiod: [int] (default: 12)
    • slowperiod: [int] (default: 26)
    • matype: [int] (default: 0)

  • BDPO.aroon (Aroon)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.aroonosc (Aroon Oscillator)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.bop (Balance Of Power)
    • data: [np.ndarray]

  • BDPO.cci (Commodity Channel Index)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.cmo (Chande Momentum Oscillator)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.dx (Directional Movement Index)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.macd (Moving Average Convergence/Divergence)
    • data: [np.ndarray]
    • fastperiod: [int] (default: 12)
    • slowperiod: [int] (default: 26)
    • signalperiod: [int] (default: 9)

  • BDPO.minus_di (Minus Directional Indicator)
    • data: [np.ndarray]
    • timeperiod: [int] (default: 14)

  • BDPO.minus_dm (Minus Directional Movement)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.mom (Momentum)
    • data: [np.ndarray]
    • timeperiod: [int] (default=10)

  • BDPO.plus_di (Plus Directional Indicator)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.plus_dm (Plus Directional Movement)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.ppo (Percentage Price Oscillator)
    • data: [np.ndarray]
    • fastperiod: [int] (default=12)
    • slowperiod: [int] (default=26)
    • matype: [int] (default=0)

  • BDPO.roc (Rate of change)
    • data: [np.ndarray]
    • timeperiod: [int] (default=10)

  • BDPO.rocp (Rate of change Percentage)
    • data: [np.ndarray]
    • timeperiod: [int] (default=10)

  • BDPO.rocr (Rate of change ratio)
    • data: [np.ndarray]
    • timeperiod: [int] (default=10)

  • BDPO.rsi (Relative Strength Index)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.stoch (Stochastic)
    • data: [np.ndarray]
    • fastk_period: [int] (default=5)
    • slowk_period: [int] (default=3)
    • slowk_matype: [int] (default=0)
    • slowd_period: [int] (default=3)
    • slowd_matype: [int] (default=0)

  • BDPO.stochf (Stochastic Fast)
    • data: [np.ndarray]
    • fastk_period: [int] (default=5)
    • fastd_period: [int] (default=3)
    • fastd_matype: [int] (default=0)

  • BDPO.stochrsi (Stochastic Relative Strength Index)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)
    • fastk_period: [int] (default=5)
    • fastd_period: [int] (default=3)
    • fastd_matype: [int] (default=0)

  • BDPO.trix (1-day Rate-Of-Change (ROC) of a Triple Smooth EMA)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.ultosc (Ultimate Oscillator)
    • data: [np.ndarray]
    • timeperiod1: [int] (default=7)
    • timeperiod2: [int] (default=14)
    • timeperiod3: [int] (default=28)

  • BDPO.willr (Williams' %R)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.bbands (Bollinger Bands)
    • data: [np.ndarray]
    • timeperiod: [int] (default=5)
    • nbdevup: [float] (default=2)
    • nbdevdn: [float] (default=2)
    • matype: [int] (default=0)

  • BDPO.dema (Double Exponential Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.ema (Exponential Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.ht_trendline (Hilbert Transform - Instantaneous Trendline)
    • data: [np.ndarray]

  • BDPO.kama (Kaufman Adaptive Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.ma (Moving average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)
    • matype: [int] (default=0)

  • BDPO.midpoint (MidPoint over period)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.midprice (Midpoint Price over period)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.sma (Simple Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.t3 (Triple Exponential Moving Average (T3))
    • data: [np.ndarray]
    • timeperiod: [int] (default=5)
    • vfactor: [float] (default=0)

  • BDPO.tema (Triple Exponential Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.trima (Triangular Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.wma (Weighted Moving Average)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.avgprice (Average Price)
    • data: [np.ndarray]

  • BDPO.medprice (Median Price)
    • data: [np.ndarray]

  • BDPO.typprice (Typical Price)
    • data: [np.ndarray]

  • BDPO.wclprice (Weighted Close Price)
    • data: [np.ndarray]

  • BDPO.beta (Beta)
    • data: [np.ndarray]
    • timeperiod: [int] (default=5)

  • BDPO.correl (Pearson's Correlation Coefficient)
    • data: [np.ndarray]
    • timeperiod: [int] (default=30)

  • BDPO.linearreg (Linear Regression)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.linearreg_angle (Linear Regression Angle)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.linearreg_intercept (Linear Regression Intercept)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.linearreg_slope (Linear Regression Slope)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.stddev (Standard Deviation)
    • data: [np.ndarray]
    • timeperiod: [int] (default=5)
    • nbdev: [int] (default=1)

  • BDPO.tsf (Time Series Forecast)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.var (Variance)
    • data: [np.ndarray]
    • timeperiod: [int] (default=5)
    • nbdev: [int] (default=1)

  • BDPO.atr (Average True Range)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.natr (Normalized Average True Range)
    • data: [np.ndarray]
    • timeperiod: [int] (default=14)

  • BDPO.trange (True Range)
    • data: [np.ndarray]