Overall Statistics
Total Trades
14185
Average Win
0.06%
Average Loss
-0.05%
Compounding Annual Return
20.962%
Drawdown
19.500%
Expectancy
0.103
Net Profit
47.930%
Sharpe Ratio
0.939
Probabilistic Sharpe Ratio
41.179%
Loss Rate
51%
Win Rate
49%
Profit-Loss Ratio
1.26
Alpha
0.211
Beta
-0.084
Annual Standard Deviation
0.207
Annual Variance
0.043
Information Ratio
0.002
Tracking Error
0.322
Treynor Ratio
-2.306
Total Fees
$16074.88
Estimated Strategy Capacity
$420000.00
Lowest Capacity Asset
FXL TSHPE3QO7TD1
class NothingNew(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2019, 5,1)  # Set Start Date
        self.SetUniverseSelection(LiquidETFUniverse())  
        self.UniverseSettings.Resolution = Resolution.Hour
        self.AddUniverse(self.Coarse)
        self.lastOrderEvent = None
        self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(lambda time:None))
        self.symbolData = {}
        #self.AddRiskManagement(MaximumDrawdownPercentPerSecurity())
        self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.02))
        #self.SetRiskManagement(MaximumDradownPercent(0.02))

        self.SetAlpha(MyAlpha())

    def Coarse(self, coarseU):
        for c in coarseU:
            if c.Symbol in self.symbolData:
                self.symbolData[c.Symbol].dvol = c.DollarVolume
        
        return []

    def OnData(self, data):

        return

    def Rebalance(self):
    
        return
    
        for symbol in tickers:
            self.SetHoldings(symbol, 1/(len(tickers)))
            #Liquidate ETF if stoploss was hit
            self.StopMarketOrder(symbol, -self.Portfolio[symbol].Quantity,0.98 * self.Securities[symbol].Close)
        
        
        
        
    
    
class MyAlpha(AlphaModel):
    def __init__(self):
        self.symbolData = {}
        self.lookback = 1

        
        
    def Update(self, algorithm, data):
        insights = []
        
        #Technically, this is top 20, but I dont want to change all the names
        top10SortedByDVol = sorted(self.symbolData.items(), key=lambda x:x[1].dvol, reverse=True)[:20]

        for symbol, sd in top10SortedByDVol:
            if not sd.IsReady:
                continue
            
            if sd.sma30.Current.Value > sd.sma50.Current.Value:
                #if sd.sma20.Current.Value > sd.sma30.Current.Value:
                        if sd.ema8.Current.Value > sd.ema20.Current.Value:
                            if sd.sma5.Current.Value > sd.sma10.Current.Value:
                                #self.Debug(symbol)
                            
                             
                                direction = InsightDirection.Flat
                                magnitude = sd.Return
                                if magnitude > 0: direction = InsightDirection.Up
                                if magnitude < 0: direction = InsightDirection.Down
                            
                                #insight = Insight.Price(symbol, timedelta(days=5), InsightDirection.Up)
                                insight = Insight.Price(symbol, timedelta(days=5), direction, magnitude, None)
                                insights.append(insight)
                            #insights.append(Insight.Price(symbol, timedelta(days=1), direction, magnitude, None, None, abs(weight)))

                
        return insights
        
    def OnSecuritiesChanged(self, algorithm, changed):
        # liquidate securities removed from universe
        for security in changed.AddedSecurities:
            self.symbolData[security.Symbol] = SymbolData(algorithm, security.Symbol)
        
        for security in changed.RemovedSecurities:
            #Pop removes keys and corresponding values 
            self.symbolData.pop(security.Symbol, None)
    

      
class SymbolData:
    def __init__(self, algorithm, symbol):
        self.dvol = 0
        self.sma5 = algorithm.SMA(symbol, 5, Resolution.Daily)
        self.sma10 = algorithm.SMA(symbol, 10, Resolution.Daily)
        self.sma20 = algorithm.SMA(symbol, 20, Resolution.Daily)
        self.sma30 = algorithm.SMA(symbol, 20, Resolution.Daily)
        self.sma50 = algorithm.SMA(symbol, 50, Resolution.Daily)
        self.ema8 = algorithm.EMA(symbol, 8, Resolution.Daily)
        self.ema20 = algorithm.EMA(symbol, 20, Resolution.Daily)
        self.ROC = algorithm.ROC(symbol, 20, Resolution.Daily)

        history = algorithm.History([symbol], 50, Resolution.Daily)
        #history = history.loc[symbol] #getting the df for the specific symbol
        if symbol not in history.index:
            return
        history = history.loc[symbol] #getting the df for the specific symbol
        
        
        # Updating daily close data
        for time,row in history.iterrows():
            self.sma5.Update(time, row['close'])
            self.sma10.Update(time, row['close'])
            self.sma20.Update(time, row['close'])
            self.sma50.Update(time, row['close'])
            self.ema8.Update(time, row['close'])
            self.ema20.Update(time, row['close'])
            #self.ema30.Update(time, row['close'])
            self.ROC.Update(time, row['close'])
            
    @property
    def Return(self):
        return float(self.ROC.Current.Value)
        
        
        
    def IsReady(self):
        return self.sma5.IsReady and self.sma10.IsReady and self.sma20.IsReady and ema8.IsReady and ema20.IsReady