Skip to content

research.research_strategies.bollinger_band_mean_reversion.strategy

research.research_strategies.bollinger_band_mean_reversion.strategy

BollingerBandMeanReversion

BollingerBandMeanReversion(bollinger_bands_period: int, bollinger_bands_stdev: float, allocation: float, symbol: str)

Bases: Strategy

A bare-bones bollinger band mean reversion strategy.

Buys long upon the closing price crossing below the lower band. Sells upon the closing price reverting to above the middle band. A fixed allocation of the portfolio is traded. No pyramiding is allowed (so only one trade at a time), and only one ticker symbol can be traded.

Initializes BollingerBandMeanReversion with the bollinger bands indicator.

Source code in src\contango\research\research_strategies\bollinger_band_mean_reversion\strategy.py
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def __init__(
    self,
    bollinger_bands_period: int,
    bollinger_bands_stdev: float,
    allocation: float,
    symbol: str
) -> None:
    """
    Initializes `BollingerBandMeanReversion` with the bollinger bands indicator.
    """
    self._bollinger_bands = BollingerBands(bollinger_bands_period, bollinger_bands_stdev)
    self._allocation = allocation
    self._symbol = symbol

    self._previous_snapshot: BollingerBandSnapshot | None = None
    self._previous_event: MarketDataEvent | None = None

on_end

on_end() -> None

Method called after all bars are finished - sells any persisting orders at the end, if any.

Source code in src\contango\research\research_strategies\bollinger_band_mean_reversion\strategy.py
113
114
115
116
117
118
119
120
121
122
123
124
125
def on_end(self) -> None:
    """
    Method called after all bars are finished - sells any persisting orders at the end, if any.
    """
    holding = self.portfolio_snapshot.position > 0
    final_event = self._previous_event

    if final_event is None:
        raise ValueError("The final market data event was never set.")

    if holding:
        units_to_sell = self.portfolio_snapshot.position
        self.order_api.submit_order(final_event, self._symbol, -units_to_sell)

on_market_event

on_market_event(event: MarketDataEvent) -> None

Method called every market event (bar) - main execution logic should go here.

Source code in src\contango\research\research_strategies\bollinger_band_mean_reversion\strategy.py
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
def on_market_event(self, event: MarketDataEvent) -> None:
    """
    Method called every market event (bar) - main execution logic should go here.
    """
    close = event.close
    snapshot = self._bollinger_bands.update(close)

    if self._previous_event is None or self._previous_snapshot is None or snapshot is None:
        self._previous_event = event
        self._previous_snapshot = snapshot
        return

    prev_close = self._previous_event.close
    holding = self.portfolio_snapshot.position > 0
    prev_snapshot = self._previous_snapshot

    if self._should_buy(prev_close, close, prev_snapshot, snapshot, holding):
        units_to_buy = int(self._allocation * self.portfolio_snapshot.cash / close)
        self.order_api.submit_order(event, self._symbol, units_to_buy)
    elif self._should_sell(prev_close, close, prev_snapshot, snapshot, holding):
        units_to_sell = self.portfolio_snapshot.position
        self.order_api.submit_order(event, self._symbol, -units_to_sell)

    self._previous_snapshot = snapshot
    self._previous_event = event