Backtest

Backtesting utils

Strategy

class ml_investment.backtest.strategy.Strategy[source]

Bases: object

Base class for strategy backtesting. It contains overrideble method step for defining user strategy. This class incapsulate backtesting and metrics calculation process and also contains information about orders.

backtest(data_loader, date_col: str, price_col: str, return_col: str, return_format: str, step_dates: Optional[List[numpy.timedelta64]] = None, cash: float = 100000, comission: float = 0.00025, latency: numpy.timedelta64 = numpy.timedelta64(0, 'h'), allow_short: bool = False, metrics=None, preload: bool = False, verbose: bool = True)[source]

Backtest strategy on provided data and other parameters. It will create and execute orders and calculate resulted equity and metrics.

Parameters
  • data_loader – class implementing load(index) -> pd.DataFrame interface. index in this case is list of tickers to load market data for.

  • date_col – name of column containing date (time) information in market data provided by data_loader.

  • price_col – name of column containing price information in market data provided by data_loader.

  • return_col – name of column containing total return information in data provided by data_loader. It may be differ from price due to dividends, stock splits and etc.

  • return_format – format of data provided by return_col column. If return_format = 'ratio' than column should contain ratio between previous and current adjusted price. E.g. 1.2 means growth by 20% from the previous step. If return_format = 'price' than column should contain adjusted price (price, including dividends and etc.) If return_format = 'change' than column should contain relative change between current and previous step. E.g. 0.2 means growth by 20% from the previous step.

  • step_dates – dates in which all actions can be taken. Include new market prices receiving, order creation and executing. step method will iterate over all those dates. If None than all possible dates, provided by date_col column in data_loader will be used. Possible only if preload = True and data_loader have existing_index(index) -> List interface.

  • cash – initial amount of cash

  • comission – commission charged for each trade (in percent of order value)

  • latency – time between current step date and actual order posting. It emulates delays during step logic and in the Internet connection with the exchange.

  • allow_short – allow short positions or not

  • preload – load all data provided from data_loader to ram or not

  • verbose – show progress or not

calc_metrics(metrics: Dict)[source]
post_order(ticker: str, direction: int, size: float, order_type: int = 0, lifetime: numpy.timedelta64 = numpy.timedelta64(300, 'D'), allow_partial: bool = True)[source]

Post new order to backtest. It may be used inside your strategy overriden step method.

Parameters
  • ticker – ticker of company to post order for

  • direction – one of Order.BUY (1), Order.SELL (-1)

  • size – size of order in pieces

  • order_type – one of Order.MARKET (0), Order.LIMIT (1)

  • lifetime – amount of time before order closing if it can not be executed (e.g. if unsatisfactory price lasts a long time)

  • allow_partial – may order be executed with not full size or not

post_order_value(ticker: str, direction: int, value: float, order_type: int = 0, lifetime: numpy.timedelta64 = numpy.timedelta64(300, 'D'), allow_partial: bool = True)[source]

Post new order by value (instead of size) to backtest. It may be used inside your strategy overriden step method.

Parameters
  • ticker – ticker of company to post order for

  • direction – one of Order.BUY (1), Order.SELL (-1)

  • value – value of order in money

  • order_type – one of Order.MARKET (0), Order.LIMIT (1)

  • lifetime – amount of time before order closing if it can not be executed (e.g. if unsatisfactory price lasts a long time)

  • allow_partial – may order be executed with not full size or not

post_portfolio_part(ticker: str, part: float, lifetime: numpy.timedelta64 = numpy.timedelta64(300, 'D'), allow_partial: bool = True)[source]

Post order to backtest to have desired part in portfolio. It will calculate difference between current and desired part to create appropriate order. It may be used inside your strategy overriden step method.

Parameters
  • ticker – ticker of company to post order for

  • part – desired part in all equity including other stocks and cash in portfolio (value between 0 and 1)

  • lifetime – amount of time before order closing if it can not be executed (e.g. if unsatisfactory price lasts a long time)

  • allow_partial – may order be executed with not full size or not

post_portfolio_size(ticker: str, size: int, lifetime: numpy.timedelta64 = numpy.timedelta64(300, 'D'), allow_partial: bool = True)[source]

Post order to backtest to have desired size in portfolio. It will calculate difference between current and desired size to create appropriate order. It may be used inside your strategy overriden step method.

Parameters
  • ticker – ticker of company to post order for

  • size – desired size in portfolio (in pieces)

  • lifetime – amount of time before order closing if it can not be executed (e.g. if unsatisfactory price lasts a long time)

  • allow_partial – may order be executed with not full size or not

post_portfolio_value(ticker: str, value: float, lifetime: numpy.timedelta64 = numpy.timedelta64(300, 'D'), allow_partial: bool = True)[source]

Post order to backtest to have desired value in portfolio. It will calculate difference between current and desired value to create appropriate order. It may be used inside your strategy overriden step method.

Parameters
  • ticker – ticker of company to post order for

  • value – desired value in portfolio (in money)

  • lifetime – amount of time before order closing if it can not be executed (e.g. if unsatisfactory price lasts a long time)

  • allow_partial – may order be executed with not full size or not

step()[source]