Overall Statistics
Total Trades
364
Average Win
0.15%
Average Loss
-0.16%
Compounding Annual Return
6.869%
Drawdown
8.200%
Expectancy
0.264
Net Profit
9.328%
Sharpe Ratio
0.588
Probabilistic Sharpe Ratio
29.443%
Loss Rate
35%
Win Rate
65%
Profit-Loss Ratio
0.95
Alpha
0.005
Beta
0.256
Annual Standard Deviation
0.106
Annual Variance
0.011
Information Ratio
-0.743
Tracking Error
0.217
Treynor Ratio
0.244
Total Fees
$364.19
Estimated Strategy Capacity
$270000000.00
Lowest Capacity Asset
QQQ RIWIV7K5Z9LX
import datetime
import pandas
class LiquidUniverseSelection(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2020, 1, 11)
        self.SetCash(100000)
        self.AddUniverse(self.CoarseSelectionFilter)
        self.UniverseSettings.Resolution = Resolution.Minute

        # 1. Set the leverage to 2
        self.UniverseSettings.Leverage = 2
        
        self.symbol_data_by_symbol = {}

    def CoarseSelectionFilter(self, coarse):
        sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True)
        self.filteredByPrice = [c.Symbol for c in sortedByDollarVolume if c.Price > 10]
        return self.filteredByPrice[:3]

    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):
        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.yesterday_high is not None):
                continue
        
            if symbol_data.openingBar.Low > symbol_data.yesterday_high and \
                data[symbol].High > symbol_data.openingBar.High and \
                data[symbol].High > symbol_data.yesterday_high:
                    self.SetHoldings(symbol, 0.10)
                
    def EveryDayBeforeMarketClose(self):
        self.Liquidate()
        #if self.window.IsReady and window[0].Close > window[1].Close:
        
class SymbolData:
    openingBar = None
    
    def __init__(self, algorithm, symbol):
        self.algorithm = algorithm
        self.symbol = symbol
        self.yesterday_high = None
        
        # Setup minute consolidator
        self.minute_consolidator = TradeBarConsolidator(timedelta(minutes=1))
        self.minute_consolidator.DataConsolidated += self.minute_consolidation_handler
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.minute_consolidator)
        
        # Setup daily consolidator
        self.daily_consolidator = TradeBarConsolidator(timedelta(days=1))
        self.daily_consolidator.DataConsolidated += self.daily_consolidation_handler
        algorithm.SubscriptionManager.AddConsolidator(symbol, self.daily_consolidator)
        
        # Warm up yesterday high price
        history = algorithm.History(symbol, 1, Resolution.Daily)
        if history.empty or 'high' not in history.columns:
            return
        self.yesterday_high = history.loc[symbol].high[0]
        
    def minute_consolidation_handler(self, sender, bar):
        if bar.Time.hour == 9:
            if bar.Time.minute < 30:
                self.openingBar = None
            elif bar.Time.minute == 30:
                self.openingBar = bar
    
    def daily_consolidation_handler(self, sender, bar):
        self.yesterday_high = bar.High
                
    def dispose(self):
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.minute_consolidator)
        self.algorithm.SubscriptionManager.RemoveConsolidator(self.symbol, self.daily_consolidator)