Overall Statistics |
Total Trades 1334 Average Win 1.14% Average Loss -0.83% Compounding Annual Return 19.210% Drawdown 33.700% Expectancy 0.274 Net Profit 332.724% Sharpe Ratio 0.78 Probabilistic Sharpe Ratio 18.432% Loss Rate 46% Win Rate 54% Profit-Loss Ratio 1.37 Alpha 0.018 Beta 1.312 Annual Standard Deviation 0.242 Annual Variance 0.058 Information Ratio 0.417 Tracking Error 0.141 Treynor Ratio 0.144 Total Fees $3779.06 |
import operator from math import ceil,floor class CoarseFineFundamentalComboAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2009,1,2) # Set Start Date self.SetEndDate(2017,5,2) # Set End Date self.SetCash(50000) # Set Strategy Cash self.flag1 = 1 self.flag2 = 0 self.flag3 = 0 self.last_rebalance=self.Time self.UniverseSettings.Resolution = Resolution.Minute self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.AddEquity("SPY") self.numberOfSymbols = 300 self.numberOfSymbolsFine = 10 self.num_portfolios = 6 self._changes = None self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY"), Action(self.Rebalancing)) def CoarseSelectionFunction(self, coarse): if self.flag1: CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData] sortedByDollarVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True) top = sortedByDollarVolume[:self.numberOfSymbols] selection=[i.Symbol for i in top] return selection else: return [] def FineSelectionFunction(self, fine): if self.flag1: self.flag1 = 0 self.flag2 = 1 filtered_fine = [x for x in fine if x.EarningReports.TotalDividendPerShare.ThreeMonths and x.ValuationRatios.PriceChange1M and x.ValuationRatios.BookValuePerShare and x.ValuationRatios.FCFYield] sortedByfactor1 = sorted(filtered_fine, key=lambda x: x.EarningReports.TotalDividendPerShare.ThreeMonths, reverse=True) sortedByfactor2 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PriceChange1M, reverse=False) sortedByfactor3 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.BookValuePerShare, reverse=True) sortedByfactor4 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.FCFYield, reverse=True) num_stocks = floor(len(filtered_fine)/self.num_portfolios) stock_dict = {} for i,ele in enumerate(sortedByfactor1): rank1 = i rank2 = sortedByfactor2.index(ele) rank3 = sortedByfactor3.index(ele) rank4 = sortedByfactor4.index(ele) score = [ceil(rank1/num_stocks), ceil(rank2/num_stocks), ceil(rank3/num_stocks), ceil(rank4/num_stocks)] score = sum(score) stock_dict[ele] = score #self.Log("score" + str(score)) self.sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=True) sorted_symbol = [self.sorted_stock[i][0] for i in range(len(self.sorted_stock))] topFine = sorted_symbol[:self.numberOfSymbolsFine] self.flag3 = self.flag3 + 1 selection=[i.Symbol for i in topFine] tickers=[i.Value for i in selection] return selection else: return [] def OnData(self, data): if self.flag3 > 0: if self.flag2 == 1: self.flag2 = 0 # if we have no changes, do nothing if self._changes == None: return # liquidate removed securities for security in self._changes.RemovedSecurities: if security.Invested: self.Liquidate(security.Symbol) for security in self._changes.AddedSecurities: if security.Symbol.Value!='SPY': self.SetHoldings(security.Symbol, 0.8/float(len(self._changes.AddedSecurities))) self._changes = None # this event fires whenever we have changes to our universe def OnSecuritiesChanged(self, changes): self._changes = changes def Rebalancing(self): if self.Time-self.last_rebalance>timedelta(days=20): self.last_rebalance=self.Time self.flag1 = 1