Overall Statistics
Total Trades
1412
Average Win
2.34%
Average Loss
-2.67%
Compounding Annual Return
-40.017%
Drawdown
93.600%
Expectancy
-0.007
Net Profit
-63.359%
Sharpe Ratio
0.278
Probabilistic Sharpe Ratio
9.747%
Loss Rate
47%
Win Rate
53%
Profit-Loss Ratio
0.88
Alpha
0.114
Beta
1.201
Annual Standard Deviation
1.155
Annual Variance
1.335
Information Ratio
0.132
Tracking Error
1.128
Treynor Ratio
0.267
Total Fees
$112228.26
Estimated Strategy Capacity
$2000000.00
Lowest Capacity Asset
ONON XRV6S79HAOO5
class PensiveRedOrangeCaribou(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2020, 1, 1)  # Set Start Date
        self.SetCash(1000000)  # Set Strategy Cash
        self.AddUniverse(self.CoarseSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Minute
        self.UniverseSettings.DataNormalizationMode = DataNormalizationMode.Raw
        self.symbol_data_by_symbol={}
        
    def CoarseSelectionFilter(self, coarse):
        
        sortedByDollarVolume = sorted(coarse,  key=lambda c: c.DollarVolume, reverse=True)
        return [ x.Symbol for x in sortedByDollarVolume if x.Price > 10 and x.HasFundamentalData][:500]
        
        
    def OnSecuritiesChanged(self, changes):
        for security in changes.RemovedSecurities:
            symbol = security.Symbol
            if security.Invested:
                self.Liquidate(symbol)
            symbol_data = self.symbol_data_by_symbol.pop(symbol, None)
            if symbol_data:
                symbol_data.dispose()

        for security in changes.AddedSecurities:
            symbol = security.Symbol
            self.symbol_data_by_symbol[symbol] = SymbolData(self, symbol)
            
        
    def OnData(self, data):
        bestGain = None
        bestGainValue = 0
        numPositions = 0
        
        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if not (data.ContainsKey(symbol) and data[symbol] is not None and symbol_data.openingBar is not None and symbol_data.fhmin is not None):
                return
            if (self.Time.hour==12 and self.Time.minute ==0):
                if (self.Portfolio[symbol].Invested):
                    numPositions = numPositions +1
                
                if (bestGainValue == 0):
                    bestGainValue = symbol_data.percentChange
                    bestGain = symbol
                else:
                    if (bestGainValue < symbol_data.percentChange):
                        bestGainValue = symbol_data.percentChange
                        bestGain = symbol

        for symbol, symbol_data in self.symbol_data_by_symbol.items():
            if not (data.ContainsKey(symbol) and data[symbol] is not None and symbol_data.openingBar is not None and symbol_data.fhmin is not None):
                return
            
            # if current price greater than open at 1% - open long position
            if not self.Portfolio[symbol].Invested:
                if (self.Time.hour==12 and self.Time.minute ==0):
                    if (data[symbol].Close > symbol_data.openingBar.Open*(1+3/100) and not symbol_data.wastrade and symbol == bestGain):
                        self.SetHoldings(symbol, 1/(numPositions+1))
                        symbol_data.wastrade = True
            else: 
                # modify
                if (self.Time.hour==12 and self.Time.minute ==0):
                    self.SetHoldings(symbol, 1/(numPositions+1))
                
                # close if current price less than 1HMin. 
                if ((self.Time.hour==10 and self.Time.minute >=30) or 
                (self.Time.hour>10)):
                    if (data[symbol].Low < symbol_data.fhmin):
                        self.Liquidate(symbol)
        
class SymbolData:
    openingBar = None
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        self.fhmin = None
        self.wastrade = False
        self.percentChange = None
        
        # Setup minute consolidator
        self.five_minute_consolidator = TradeBarConsolidator(timedelta(minutes=5))
        self.five_minute_consolidator.DataConsolidated += self.five_minute_consolidation_handler
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.five_minute_consolidator)
        
    def five_minute_consolidation_handler(self, sender, bar):
        if bar.Time.hour == 9 and bar.Time.minute == 30:
            self.openingBar = bar
            self.fhmin = bar.Low
            self.wastrade = False
        else:
            if (bar.Time.hour == 9 and bar.Time.minute >30) or (bar.Time.hour==10 and bar.Time.minute <=30):
                if (self.fhmin!= None and bar.Low < self.fhmin):
                    self.fhmin = bar.Low
            if (bar.Time.hour == 11 and bar.Time.minute ==30):
                if (self.openingBar!=None):
                    self.percentChange = bar.Close/self.openingBar.Open-1
                
    def dispose(self):
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.five_minute_consolidator)