DecideTradesProtocol#

tradeexecutor.strategy.strategy_module.DecideTradesProtocol class.

class DecideTradesProtocol[source]#

Bases: Protocol

A call signature protocol for user’s decide_trades() functions.

This describes the decide_trades function parameters using Python’s callback protocol feature.

See also Strategy examples.

Example decide_trades function:

def decide_trades(
    timestamp: pd.Timestamp,
    universe: Universe,
    state: State,
    pricing_model: PricingModel,
    cycle_debug_data: Dict) -> List[TradeExecution]:

    # The pair we are trading
    pair = universe.pairs.get_single()

    # How much cash we have in the hand
    cash = state.portfolio.get_current_cash()

    # Get OHLCV candles for our trading pair as Pandas Dataframe.
    # We could have candles for multiple trading pairs in a different strategy,
    # but this strategy only operates on single pair candle.
    # We also limit our sample size to N latest candles to speed up calculations.
    candles: pd.DataFrame = universe.candles.get_single_pair_data(timestamp, sample_count=batch_size)

    # We have data for open, high, close, etc.
    # We only operate using candle close values in this strategy.
    close = candles["close"]

    # Calculate exponential moving averages based on slow and fast sample numbers.
    slow_ema_series = ema(close, length=slow_ema_candle_count)
    fast_ema_series = ema(close, length=fast_ema_candle_count)

    if slow_ema_series is None or fast_ema_series is None:
        # Cannot calculate EMA, because
        # not enough samples in backtesting
        return []

    slow_ema = slow_ema_series.iloc[-1]
    fast_ema = fast_ema_series.iloc[-1]

    # Get the last close price from close time series
    # that's Pandas's Series object
    # https://pandas.pydata.org/docs/reference/api/pandas.Series.iat.html
    current_price = close.iloc[-1]

    # List of any trades we decide on this cycle.
    # Because the strategy is simple, there can be
    # only zero (do nothing) or 1 (open or close) trades
    # decides
    trades = []

    # Create a position manager helper class that allows us easily to create
    # opening/closing trades for different positions
    position_manager = PositionManager(timestamp, universe, state, pricing_model)

    if current_price >= slow_ema:
        # Entry condition:
        # Close price is higher than the slow EMA
        if not position_manager.is_any_open():
            buy_amount = cash * position_size
            trades += position_manager.open_1x_long(pair, buy_amount)
    elif fast_ema >= slow_ema:
        # Exit condition:
        # Fast EMA crosses slow EMA
        if position_manager.is_any_open():
            trades += position_manager.close_all()

    # Visualize strategy
    # See available Plotly colours here
    # https://community.plotly.com/t/plotly-colours-list/11730/3?u=miohtama
    visualisation = state.visualisation
    visualisation.plot_indicator(timestamp, "Slow EMA", PlotKind.technical_indicator_on_price, slow_ema, colour="darkblue")
    visualisation.plot_indicator(timestamp, "Fast EMA", PlotKind.technical_indicator_on_price, fast_ema, colour="#003300")

    return trades
__init__(*args, **kwargs)#

Methods

__init__(*args, **kwargs)

__call__(timestamp, universe, state, pricing_model, cycle_debug_data)[source]#

The brain function to decide the trades on each trading strategy cycle.

  • Reads incoming execution state (positions, past trades), usually by creating a PositionManager.

  • Reads the price and volume status of the current trading universe, or OHLCV candles

  • Decides what to do next, by calling PositionManager to tell what new trading positions open or close

  • Outputs strategy thinking for visualisation and debug messages

See also Strategy examples

Parameters
  • timestamp (Timestamp) – The Pandas timestamp object for this cycle. Matches trading_strategy_cycle division. Always truncated to the zero seconds and minutes, never a real-time clock.

  • universe (Universe) – Trading universe that was constructed earlier.

  • state (State) – The current trade execution state. Contains current open positions and all previously executed trades.

  • pricing_model (PricingModel) – Position manager helps to create trade execution instructions to open and close positions.

  • cycle_debug_data (Dict) – Python dictionary for various debug variables you can read or set, specific to this trade cycle. This data is discarded at the end of the trade cycle.

Returns

List of trade instructions in the form of TradeExecution instances. The trades can be generated using position_manager but strategy could also handcraft its trades.

Return type

List[TradeExecution]

__init__(*args, **kwargs)#