Overall Statistics
Total Trades
698
Average Win
0.10%
Average Loss
-0.12%
Compounding Annual Return
-22.656%
Drawdown
7.800%
Expectancy
-0.072
Net Profit
-4.808%
Sharpe Ratio
-1.848
Probabilistic Sharpe Ratio
6.329%
Loss Rate
50%
Win Rate
50%
Profit-Loss Ratio
0.87
Alpha
-0.155
Beta
-0.166
Annual Standard Deviation
0.1
Annual Variance
0.01
Information Ratio
-2.615
Tracking Error
0.142
Treynor Ratio
1.116
Total Fees
$734.48
Estimated Strategy Capacity
$64000000.00
Lowest Capacity Asset
KSS R735QTJ8XC9X
class EmaCrossUniverse(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2019, 11, 23)
        self.SetEndDate(2020,2,1)
        self.SetCash(100000)
        
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction)
        self.averages = {}
        
    def CoarseSelectionFunction(self,coarse):
        
        sorted_by_volume = sorted([cf for cf in coarse if cf.Price > 10],
            key = lambda cf: cf.DollarVolume, reverse=True)
            
        selected = {cf.Symbol: cf for cf in sorted_by_volume[:100]}
        symbols = list(selected.keys())
        
        new_symbols = [s for s in symbols if s not in self.averages]
        if new_symbols:
            
            # Get history for all new symbols. If empty, log and return the selected -- WOW!
            history = self.History(new_symbols, 200, Resolution.Daily)
            if history.empty:
                self.Debug(f'Empty history on {self.Time} for {new_symbols}')
                return Universe.Unchanged   # Continue with previous universe
                
            # Only need the closing prices    
            history = history.close.unstack(0)
            
            # Add new item to self.averages
            for symbol in new_symbols:
                if symbol in history:
                    self.averages[symbol] = SelectionData(history[symbol].dropna())
                    
        self.symbols = []
        
        for symbol, cf in selected.items():
            symbolData = self.averages[symbol]
            
            if symbol not in new_symbols:
                symbolData.Update(cf.EndTime, cf.AdjustedPrice) 
                
            if symbolData.IsReady and symbolData.fast.Current.Value > cf.AdjustedPrice :
                self.symbols.append(symbol)
                
        return self.symbols
        
        
    def OnSecuritiesChanged(self, changes):
        
        for security in changes.RemovedSecurities:
            self.Liquidate(security.Symbol, f'Removed from Universe')
            
        self.can_trade = True
        
        
    def OnData(self, data):
        if self.can_trade:
            lenght = len(self.symbols)
            
            for symbol in self.symbols:
                self.SetHoldings(symbol, 1 / lenght)
                
            self.can_trade = False
            
            
class SelectionData:
    def __init__(self, history):
        
        self.fast = SimpleMovingAverage(200)
        
        
        for time, price in history.items():
            self.Update(time, price)
            
    def Update(self, time, price):
        self.fast.Update(time, price)
        
        
    @property
    def IsReady(self):
        return  self.fast.IsReady