Overall Statistics
Total Trades
950
Average Win
0.26%
Average Loss
-0.24%
Compounding Annual Return
4.527%
Drawdown
6.200%
Expectancy
0.067
Net Profit
7.624%
Sharpe Ratio
0.682
Probabilistic Sharpe Ratio
33.308%
Loss Rate
48%
Win Rate
52%
Profit-Loss Ratio
1.06
Alpha
0.033
Beta
0.157
Annual Standard Deviation
0.07
Annual Variance
0.005
Information Ratio
-0.32
Tracking Error
0.142
Treynor Ratio
0.306
Total Fees
$951.47
Estimated Strategy Capacity
$13000000.00
Lowest Capacity Asset
TSLA UNU3P8Y3WFAD
class BootCampTask(QCAlgorithm):
    
        
    def Initialize(self):
        self.SetStartDate(2017, 10, 2)
        self.SetEndDate(2019, 5, 30)
        self.SetCash(100000)
        self.SetSecurityInitializer(self.CustomSecurityInitializer)
        
        tickers = ['SPY','TSLA']
        self.symbol_data_by_symbol = {}
        for ticker in tickers:
            openingBar = None 
            symbol = self.AddEquity(ticker, Resolution.Minute).Symbol
            self.symbol_data_by_symbol[symbol] = SymbolData()
            self.Consolidate(symbol, timedelta(minutes=30), self.OnDataConsolidated)
            self.Schedule.On(self.DateRules.EveryDay(symbol), self.TimeRules.At(13,30), self.ClosePositions)
        #3. Create a scheduled event triggered at 13:30 calling the ClosePositions function
        
        self.stopPrice = self.GetParameter("stop")
        
    def CustomSecurityInitializer(self, security):
        security.SetDataNormalizationMode(DataNormalizationMode.Raw)
            
    def OnData(self, data):
        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if symbol_data.openingBar is None: continue
        
            if not data.Bars.ContainsKey(symbol):
                continue
                  
            if data.Bars[symbol].Close > symbol_data.openingBar.High and not self.Securities[symbol].Invested:
                quantity = self.CalculateOrderQuantity(symbol, 0.45)
                self.MarketOrder(symbol, quantity) # orders 45% of portfolio
                symbol_data.stopMarketTicket = self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity, data.Bars[symbol].Close * 0.9)
                continue
                
            if self.Securities[symbol].Invested and data.Bars[symbol].Close > symbol_data.highestPrice:
                symbol_data.highestPrice = self.Securities[symbol].Close
                updateFields = UpdateOrderFields()
                updateFields.StopPrice = symbol_data.highestPrice * self.stopPrice
                symbol_data.stopMarketTicket.Update(updateFields)
            
    def OnOrderEvent(self, orderEvent):
        if orderEvent.Status != OrderStatus.Filled:
            self.symbol_data_by_symbol[orderEvent.Symbol].openingBar = None
            return
        if self.symbol_data_by_symbol[orderEvent.Symbol].stopMarketTicket is not None and self.symbol_data_by_symbol[orderEvent.Symbol].stopMarketTicket.OrderId == orderEvent.OrderId:
            self.symbol_data_by_symbol[orderEvent.Symbol].stopMarketOrderFillTime = self.Time
            
    def OnDataConsolidated(self, bar):
        self.Log(f"Bar at {self.Time} for {bar.Symbol}")
        if bar.Time.hour == 9 and bar.Time.minute == 30:
            self.symbol_data_by_symbol[bar.Symbol].openingBar = bar
            
    def ClosePositions(self):
        #2. Set self.openingBar to None, and liquidate TSLA
        for symbolData in self.symbol_data_by_symbol.values():
            symbolData.openingBar = None
        self.Liquidate() # liquidate entire portfolio

        
class SymbolData:
    def __init__(self):
        # Order ticket for our stop order, Datetime when stop order was last hit
        self.stopMarketTicket = None
        self.stopMarketOrderFillTime = datetime.min
        self.highestPrice = 0
        self.openingBar = None