Skip to content

Moving-average trend strategy

This strategy declares its moving average in required_indicators(). Backtide computes it once and passes it to evaluate() under the indicator-name-first mapping.

from math import isfinite

from backtide import Order
from backtide.indicators import SimpleMovingAverage
from backtide.strategies import BaseStrategy


class MovingAverageTrend(BaseStrategy):
    """Buy above a moving average and exit below it."""

    def __init__(self, period=50, quantity=100):
        self.period = period
        self.quantity = quantity

    def required_indicators(self):
        return [SimpleMovingAverage(self.period)]

    @staticmethod
    def _last(values):
        if hasattr(values, "iloc"):
            return float(values.iloc[-1])
        return float(values[-1])

    def evaluate(self, data, portfolio, state, indicators):
        if state.is_warmup or indicators is None:
            return []

        orders = []
        averages = indicators.get(f"SMA_{self.period}", {})
        pending_symbols = {order.symbol for order in portfolio.orders}
        for symbol, frame in data.items():
            average_history = averages.get(symbol)
            if symbol in pending_symbols or average_history is None or not len(average_history):
                continue

            close = self._last(frame["close"])
            average = self._last(average_history)
            if not isfinite(close) or not isfinite(average):
                continue

            quantity = portfolio.positions.get(symbol, 0.0)
            if quantity == 0 and close > average:
                orders.append(
                    Order(symbol=symbol, order_type="market", quantity=self.quantity)
                )
            elif quantity > 0 and close < average:
                orders.append(Order(symbol=symbol, order_type="market", quantity=-quantity))

        return orders


MovingAverageTrend()

The lookup is always indicators[indicator_name][symbol][symbol]; here that is indicators["SMA_50"]["AAPL"] for the default period and symbol.