Overall Statistics
Total Trades
35
Average Win
36.03%
Average Loss
-2.31%
Compounding Annual Return
13.605%
Drawdown
27.600%
Expectancy
0.956
Net Profit
46.796%
Sharpe Ratio
0.8
Probabilistic Sharpe Ratio
32.858%
Loss Rate
88%
Win Rate
12%
Profit-Loss Ratio
15.62
Alpha
0.028
Beta
0.755
Annual Standard Deviation
0.2
Annual Variance
0.04
Information Ratio
-0.133
Tracking Error
0.116
Treynor Ratio
0.212
Total Fees
$35.00
Estimated Strategy Capacity
$350000000.00
Lowest Capacity Asset
SPY R735QTJ8XC9X
import numpy as np

class SimpleBreakoutExample(QCAlgorithm):

    def Initialize(self):
        # Set the cash for backtest
        self.SetCash(10000)
        
        # Start and end dates for backtest
        self.SetStartDate(2009,1,1)
        self.SetEndDate(2030,1,1)
        
        # Add asset
        self.symbol = self.AddEquity("SPY", Resolution.Second).Symbol
        
        # Lookback length for b/o (in days)
        self.lookback = 31
        
        # Upper/lower limit for lookback length
        self.ceiling, self.floor = 31, 1
        
        # Price offset for stop order
        self.initialStopRisk = 0.98
        self.trailingStopRisk = 0.89
        
        # Schedule function 10 minutes after every market open
        self.Schedule.On(self.DateRules.EveryDay(self.symbol), \
                        self.TimeRules.AfterMarketOpen(self.symbol, 10), \
                        Action(self.EveryMarketOpen))


    def OnData(self, data):
        # Plot security's price
        self.Plot("Data Chart", self.symbol, self.Securities[self.symbol].Close)

 
    def EveryMarketOpen(self):
        # Dynamically determine lookback length based on 30 day volatility change rate
        close = self.History(self.symbol, 31, Resolution.Second)["close"]
        todayvol = np.std(close[1:31])
        yesterdayvol = np.std(close[0:30])
        deltavol = (todayvol - yesterdayvol) / todayvol
        self.lookback = round(self.lookback * (1 + deltavol))
        
        # Account for upper/lower limit of lockback length
        if self.lookback > self.ceiling:
            self.lookback = self.ceiling
        elif self.lookback < self.floor:
            self.lookback = self.floor
        
        # List of daily highs
        self.high = self.History(self.symbol, self.lookback, Resolution.Second)["high"]
        
        # Buy in case of breakout
        if not self.Securities[self.symbol].Invested and \
                self.Securities[self.symbol].Close >= max(self.high[:-1]):
            self.SetHoldings(self.symbol, 1)
            self.breakoutlvl = max(self.high[:-1])
            self.highestPrice = self.breakoutlvl
        
        
        # Create trailing stop loss if invested 
        if self.Securities[self.symbol].Invested:
            
            # If no order exists, send stop-loss
            if not self.Transactions.GetOpenOrders(self.symbol):
                self.stopMarketTicket = self.StopMarketOrder(self.symbol, \
                                        -self.Portfolio[self.symbol].Quantity, \
                                        self.initialStopRisk * self.breakoutlvl)
            
            # Check if the asset's price is higher than highestPrice & trailing stop price not below initial stop price
            if self.Securities[self.symbol].Close > self.highestPrice and \
                    self.initialStopRisk * self.breakoutlvl < self.Securities[self.symbol].Close * self.trailingStopRisk:
                # Save the new high to highestPrice
                self.highestPrice = self.Securities[self.symbol].Close
                # Update the stop price
                updateFields = UpdateOrderFields()
                updateFields.StopPrice = self.Securities[self.symbol].Close * self.trailingStopRisk
                self.stopMarketTicket.Update(updateFields)
                
                # Print the new stop price with Debug()
                self.Debug(updateFields.StopPrice)
            
            # Plot trailing stop's price
            self.Plot("Data Chart", "Stop Price", self.stopMarketTicket.Get(OrderField.StopPrice))