Skip to content

Estrade
Estrade

Backtest and run your trading strategies

Estrade is a python library that allows you to easily backtest and run stock trading strategies at tick level.

Estrade focus on providing tools so you mainly focus on your strategy definition.

WARNING: Estrade is still in an alpha state of developpement and very unmature. Do not use it for other purposes than testing.

Features

Estrade provides a environnement, so you do not have to worry about:

  • Trades result calculation
  • Indicators building & calculation (candle sets, graph indicators etc.)

Estrade is build to be extended so you can define your own:

  • Strategies
  • Tick provider (to feed your backtests and/or live trading)
  • Indicators
  • Reporting
  • Trade provider

What Estrade does NOT provides

  • Data: You have to define your own data provider (live or static)
  • Strategies: Although some very basic (and useless) strategies are provided as examples in samples, Estrade does not provide any financially relevant strategy.
  • Brokers connexion: For legal reasons Estrade will never include any broker connection. Anyway Estrade provides the required tools to define it yourself easily.

Basic usage example

import arrow

from estrade import BaseStrategy, Epic, Tick, BaseTickProvider
from estrade.enums import Unit, TradeDirection
from estrade.graph import CandleSet, FrameSet, SimpleMovingAverage
from estrade.reporting import ReportingCSV

if __name__ == "__main__":
    # create an epic called "MY_EPIC"
    epic = Epic(ref="MY_EPIC")

    # create a FrameSet
    frameset_5mn = FrameSet(ref="FS5MN", unit=Unit.MINUTE, unit_quantity=5)
    epic.add_frame_set(frameset_5mn)

    # add a CandleSet on FrameSet
    candle_set5mn = CandleSet(ref="CS5MN")
    frameset_5mn.add_indicator(candle_set5mn)

    # add a SimpleMoving Average on FrameSet
    sma5mn = SimpleMovingAverage(ref="SMA5MN", max_periods=20)
    frameset_5mn.add_indicator(sma5mn)

    # define a strategy that will use your indicator to open/close trades
    class MyStrategy(BaseStrategy):
        def on_every_tick(self, epic):
            # get sma20 and the last candle
            sma20 = epic.get_indicator_value(
                frame_set_ref="FS5MN",
                indicator_ref="SMA5MN",
            ).get_value(periods=20)
            current_candle = epic.get_indicator_value(
                frame_set_ref="FS5MN",
                indicator_ref="CS5MN",
            )

            # check that SMA is not None
            # before having 20 candles in memory, the SMA is None
            if not sma20 or not current_candle:
                return

            # if candle crosses the sma20, then open a new trade
            # else if sma20 > current candle high, then close all opened trades
            if current_candle.open < sma20 < current_candle.last:
                self.open_trade(
                    epic=epic,
                    quantity=1,
                    direction=TradeDirection.BUY,
                )
            elif sma20 > current_candle.high:
                self.close_opened_trades()


    # register strategy on epic
    strategy = MyStrategy()
    epic.add_strategy(strategy)

    # define a tick Provider that will dispatch ticks to your epic
    class MyTickProvider(BaseTickProvider):
        def run(self):
            # dispatch all ticks to epic
            epic = self.epics.get("MY_EPIC")
            for tick in [
                Tick(bid=99, ask=101, datetime=arrow.get("2020-01-01 12:34:56.456")),
                Tick(bid=100, ask=102, datetime=arrow.get("2020-01-01 12:34:57.319")),
                # ...
            ]:
                epic.on_new_tick(tick)

    tick_provider = MyTickProvider(epics=[epic])

    # run your tick provider
    tick_provider.run()

    # report results
    reporting = ReportingCSV()
    reporting.report(strategies=[strategy], trade_details=True)
    # In ./reports/ folder, two files will be created
    #   - A file listing strategies result, trades count, profit factor
    #   - A file per strategy detailing trades