Bollinger Bands Example

This example shows how to write an example bollinger bands strategy, and execute a backtest of it

Python source code: ../../examples/bollinger_bands.py

from boatwright import Strategy, Backtest
from boatwright.Data import CSVdatabase
from boatwright.Brokers import Broker, BacktestBroker
from boatwright.Orders  import MarketOrder, TrailingOrder
from boatwright.Indicators import bollinger_bands, crossover
from boatwright.Visualization import plot_backtest
from datetime import datetime, timedelta
import matplotlib.pyplot as plt


class BollingerBands(Strategy):
    """
    An example strategy using Bollinger Bands (BB) as a technical indicator and Trailing Orders
    """

    def __init__(self, period:int=7, std_devs:int=2, symbol:str="BTC", strategy_id="BollingerBands"):
        super().__init__(symbol, strategy_id)
        self.p["period"] = period
        self.p["std_devs"] = std_devs
        self.position = False

    def calculate_signals(self, df):
        self.df = df
        self.df["avg"], self.df["lower"], self.df["upper"] = bollinger_bands(df["close"], period=self.p["period"], n_std_dev=self.p["std_devs"])
        self.df["buy_trigger"] = crossover(self.df["close"], self.df["lower"])
        self.df["sell_trigger"] = crossover(self.df["close"], self.df["upper"])
        return self.df
    
    def calc_prerequisite_data_length(self):
        return self.p['period']
    
    def step(self, row):
        buy_trigger = row["buy_trigger"]
        sell_trigger = row["sell_trigger"]
        datetime = row["datetime"]
        price = row["close"]

        if buy_trigger == -1:
            market_buy = MarketOrder(symbol=self.symbol, side="BUY", time_opened=datetime, frac=0.25)
            # This trailing orders will execute the market order when the price increases 1% with respect to the minimum price (since order placement)
            # This should help avoid entering a trade if the price is continueing to swing down
            buy_order = TrailingOrder(market_buy, price=price, time_opened=datetime, pct_greater_than_min=0.25, time_in_force=datetime+timedelta(minutes=30))
            self.broker.place_order(buy_order)
        if sell_trigger == 1:
            market_sell = MarketOrder(symbol=self.symbol, side="SELL", time_opened=datetime, frac=0.5)
            # This trailing orders will execute the market order when the price decreases 1% with respect to the maximum price (since order placement)
            # This should help avoid exiting a trade if the price is continueing to swing up
            sell_order = TrailingOrder(market_sell, price=price, time_opened=datetime, pct_less_than_max=-0.25, time_in_force=datetime+timedelta(minutes=30))
            self.broker.place_order(sell_order)
    
    def plot_info(self):
        info = {
            "avg": {"ax_n": 2, "color":"C0", "linestyle":"-"},
            "lower": {"ax_n": 2, "color":"C0", "linestyle":"--"},
            "upper": {"ax_n": 2, "color":"C0", "linestyle":"--"},
            "buy_trigger": {"ax_n": 3, "color":"lime"},
            "sell_trigger": {"ax_n": 3, "color":"red"},
        }
        return info

# -------------------------------------------------------


# 1. define the strategy
strategy = BollingerBands(period=60, std_devs=2, symbol="BTC")

# 2. load data for the backtet (including prequisite data for necessary for signal generation)
database = CSVdatabase(source="QUICKSTART", debug=False, dir="quickstart_data/")
start = datetime(year=2024, month=1, day=1, hour=1, minute=0)
end = datetime(year=2024, month=1, day=20, hour=12, minute=0)
data = database.load(symbol=strategy.symbol, start=start, end=end, prerequisite_data_length=strategy.calc_prerequisite_data_length(), granularity=1, granularity_unit="MINUTE", verbose=True)

# 3. declare and run the backtest
broker_model = BacktestBroker(taker_fee=0, maker_fee=0, slippage=0, quote_symbol="USD")
backtest = Backtest(strategy=strategy, data=data, broker=broker_model, debug=False)
backtest.run(verbose=True)

# 4. analyze results
plot_backtest(backtest)
plt.show()
../_images/close_zoomed.png ../_images/close2.png ../_images/aum2.png