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)