Overall Statistics
Total Trades
250
Average Win
0.43%
Average Loss
-0.12%
Compounding Annual Return
42.904%
Drawdown
4.700%
Expectancy
2.597
Net Profit
47.305%
Sharpe Ratio
1.383
Loss Rate
21%
Win Rate
79%
Profit-Loss Ratio
3.54
Alpha
43.952
Beta
-3174.121
Annual Standard Deviation
0.19
Annual Variance
0.036
Information Ratio
1.31
Tracking Error
0.19
Treynor Ratio
0
Total Fees
$0.00
from QuantConnect.Indicators import *
import decimal as d

### <summary>
### In this example we are looking for price to breakout above the bollinger bands
### and look to buy when we see that. We hold our position until price touches the
### middle band of the bollinger bands.
###

class BollingerBreakoutAlgorithm(QCAlgorithm):
    def Initialize(self):
        #####################
        # Backtest Settings #
        #####################
        self.SetStartDate(2016, 6, 1)  # Set Start Date
        self.SetEndDate(2017, 7, 1)  # Set End Date
        self.SetCash(10000)  # Set Strategy Cash
        self.SetBrokerageModel(BrokerageName.GDAX)

        ###########################
        # Configurable parameters #
        ###########################
        self.target_crypto = "BTCUSD" # Can be ETHUSD, LTCUSD, BTCUSD, or BCCUSD
        self.indicator_name = "bollinger"  # bollinger or momentum
        self.warmup_lookback = 20 # Number of time resolution to load
        self.time_resolution = Resolution.Minute # Resolution of periods/data to use

        # For bollinger
        self.moving_average_type = MovingAverageType.Exponential # See https://github.com/QuantConnect/Lean/blob/bc9af8784b02715000a2030e9757ef63b484378e/Indicators/MovingAverageType.cs
        self.bollinger_period = 20
        self.k = 2

        # For momentum
        self.momentum_period = 5

        ############################
        # Indicators and processes #
        ############################
        # Add Symbol
        self.AddCrypto(self.target_crypto, self.time_resolution)

        if self.indicator_name == "bollinger":
            # Create bollinger band
            self.Bolband = self.BB(self.target_crypto, self.bollinger_period, self.k, self.moving_average_type, self.time_resolution)
            # Plot Bollinger Band
            self.PlotIndicator(
                "Indicators",
                self.Bolband.LowerBand,
                self.Bolband.MiddleBand,
                self.Bolband.UpperBand,
            )
        elif self.indicator_name == "momentum":
            # Create a momentum indicator over 3 days
            self.mom = self.MOM(self.target_crypto, self.momentum_period)
            # Plot Momentum
            self.PlotIndicator(
                "Indicators",
                self.mom
            )

        # Pump historical data into the indicators before algo start
        self.SetWarmUp(self.warmup_lookback,self.time_resolution)

    def OnData(self, data):
        holdings = self.Portfolio[self.target_crypto].Quantity
        last_price = self.Securities[self.target_crypto].Close
        ask_price = self.Securities[self.target_crypto].AskPrice
        bid_price = self.Securities[self.target_crypto].BidPrice
        amount = self.Portfolio.TotalPortfolioValue / last_price

        # Check to see if there is an open order and if it is taking too long to fill. Check to see if the ask moved
        # If the ask moved by > 1%, then adjust the price to the new bid/ask price. Don't make another order while there are open orders
        if len(self.Transactions.GetOpenOrders(self.target_crypto)) > 0:
            open_order = self.Transactions.GetOpenOrders(self.target_crypto)[0]
            self.Debug("Updating order price")
            if float(open_order.Price - last_price) > abs(float(open_order.Price)*.01):
                updateOrderFields = UpdateOrderFields()
                updateOrderFields.LimitPrice = last_price
                print("ask_price: %s bid_price: %s " % (ask_price,bid_price))
                updateOrderFields.LimitPrice = ask_price if open_order.Direction > 0 else bid_price
                self.Transactions.GetOrderTicket(open_order.Id).Update(updateOrderFields)
            return

        if self.indicator_name == "bollinger":
            # buy if price closes above upper bollinger band
            if holdings == 0 and last_price > self.Bolband.LowerBand.Current.Value:
                limitOrderTicket = self.LimitOrder(self.target_crypto, amount, ask_price)
            # sell if price closes below middle bollinger band
            elif holdings > 0 and last_price < self.Bolband.MiddleBand.Current.Value:
                limitOrderTicket = self.LimitOrder(self.target_crypto, -holdings, bid_price)
        elif self.indicator_name == "momentum":
            mom = self.mom.Current.Value
            return

    def OnOrderEvent(self, orderEvent):
        order = self.Transactions.GetOrderById(orderEvent.OrderId)
        self.Debug("{0}: {1}: {2}".format(self.Time, order.Type, orderEvent))