Overall Statistics
Total Trades
235
Average Win
0.51%
Average Loss
-1.09%
Compounding Annual Return
10.825%
Drawdown
19.100%
Expectancy
-0.076
Net Profit
10.825%
Sharpe Ratio
0.506
Probabilistic Sharpe Ratio
28.262%
Loss Rate
37%
Win Rate
63%
Profit-Loss Ratio
0.47
Alpha
0.145
Beta
-0.107
Annual Standard Deviation
0.232
Annual Variance
0.054
Information Ratio
-0.531
Tracking Error
0.263
Treynor Ratio
-1.1
Total Fees
$1318.32
import pandas as pd
class HighDebtUniverse(QCAlgorithm):
    
    def Initialize(self):
        self.SetStartDate(2019, 1, 1)
        self.SetEndDate(2020, 1, 1)
        self.SetCash(100000)
        self.UniverseSettings.Resolution = Resolution.Daily
        self.AddUniverse(self.CoarseSelectionFunction, self.SelectFine)
        self.SetBrokerageModel(InteractiveBrokersBrokerageModel())
        self.SetExecution(ImmediateExecutionModel())
        self.AddEquity("SPY",Resolution.Daily).Symbol
        self.Fast = SimpleMovingAverage("SPY",10)
        self.Slow = SimpleMovingAverage("SPY", 100)
        self.stops = {}        # Keep track of stop loss orders so we can update them
        self.stoplevel=0.70
        self.FirstFilter = 60
        self.SecondFilter = 5
        self.WeekDay = 3
        self.numberOfSymbolsCoarse = 4000
        self.numberOfSymbolsFine = 3000
        self.dollarVolumeBySymbol = {}

    def CoarseSelectionFunction(self, coarse):  
        selected = []
        if datetime.weekday(self.Time) != self.WeekDay:
            return Universe.Unchanged

        sortedByDollarVolume = sorted([x for x in coarse if x.HasFundamentalData and x.DollarVolume > 3000000 and x.Price >0],
                                     key = lambda x: x.DollarVolume, reverse=True)[:self.numberOfSymbolsCoarse]
        self.dollarVolumeBySymbol = {x.Symbol:x.DollarVolume for x in sortedByDollarVolume}
        return list(self.dollarVolumeBySymbol.keys())
        
    def SelectFine(self, fine):
        if datetime.weekday(self.Time) != self.WeekDay:
            return Universe.Unchanged
        DERatio = lambda x: x.OperationRatios.LongTermDebtEquityRatio.ThreeMonths
        fine = ([x for x in fine if DERatio(x) and x.CompanyReference.CountryId == "USA"
                                        and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"]
                                        and (self.Time - x.SecurityReference.IPODate).days > 180 and x.MarketCap > 3e8])

        if len(fine) == 0:
            return Universe.Unchanged
        sortedByDEratio = sorted(fine, key=DERatio, reverse=True)[:self.FirstFilter]
        symbols = [x.Symbol for x in sortedByDEratio]
        averages = dict()
        history = self.History(symbols, 200, Resolution.Daily).close.unstack(0)
        for symbol in symbols:
            if symbol in history:
                df = history[symbol].dropna()
            if df.empty or len(df)<130:
                continue
            mom=df[:-2].pct_change(126) .iloc[-1]
            if pd.notnull(mom):
                averages[symbol] = mom
        sortedbyMomentum = sorted(averages.items(), key=lambda x: x[1], reverse=True)
        #for x, mom in sortedbyMomentum[:5]:
            #self.Log('Post -sort: symbol' + "   " + str(x.Value) +"   "'mom' + "   " + str(mom))
        return [x[0] for x in sortedbyMomentum[:self.SecondFilter]]
        
    def OnSecuritiesChanged(self, changes):
        if datetime.weekday(self.Time) != self.WeekDay:
            return Universe.Unchanged
        result = {}
        history = self.History(["SPY"], 110, Resolution.Daily)
        for time, row in history.loc["SPY"].iterrows():
            self.Fast.Update(time, row["close"])
            self.Slow.Update(time, row["close"])
        trend = self.Fast.Current.Value >= self.Slow.Current.Value
        count = self.SecondFilter
        percent = 0 if count == 0 else 1 / (count)
        for instrument in changes.AddedSecurities:
            #self.Log('AddedSecurities' + "   " + str(instrument)+ "   " + str(instrument.Symbol.Value))
            if(trend) and (not instrument.Symbol.Value == "SPY"): 
                result[instrument.Symbol] = percent
            #if (not self.Portfolio[security.Symbol].Invested) and not trend:
            else:
                result[instrument.Symbol]=0 

        invested = [ x.Symbol for x in self.Portfolio.Values if x.Invested]  
        test = [x for x in self.Portfolio.Values]  
        for stock in invested:
            #self.Log('Invested' + "   " + str(stock)+ "   " + str(stock.Value))
            a=self.Portfolio[stock].HoldingsValue
            b=self.Portfolio.TotalPortfolioValue
            exisiting_pcnt=a/b
            #result[stock] = exisiting_pcnt
            result[stock] = percent
        for share in changes.RemovedSecurities:
            #self.Log('RemovedSecurities' + "   " + str(share)+ "   " + str(share.Symbol.Value))
            result.pop(share.Symbol, None)
            if share.Invested:
                self.Liquidate(share.Symbol)

        if sum(result.values())>1:
            stocks_norm = 1/sum(result.values())
            for key, val in result.items():
                new_val = val * stocks_norm
                result[key]= new_val
        #for key, val in result.items():
            #self.Log('result' + "   " + str(key)+ "   " + str(val))
        
        #for security in changes.RemovedSecurities:
            #if security.Invested:
                #CancelledOrders = self.Transactions.CancelOpenOrders(security.Symbol, "Weekly Liquidation")
                #self.Liquidate(security.Symbol) 
                #self.Transactions.CancelOpenOrders()
       
        for security in result:
            self.SetHoldings(security, result[security])
                #if trend:
                    #self.SetHoldings(security, 0.20)
                    # Set stop loss
                    
                    #quantity = self.CalculateOrderQuantity(security, 0.2)
                    #if quantity>1:
                        #self.stops[security] = self.StopMarketOrder(security, -quantity, self.Portfolio[security].Price * self.stoplevel)
                        #updateSettings = UpdateOrderFields()
                        #updateSettings.Tag = "stopped out"
                        #self.stops[security].Update(updateSettings)
                #else:
                    #self.SetHoldings(security, 0.00)