Overall Statistics |
Total Trades 1979 Average Win 0.21% Average Loss -0.20% Compounding Annual Return -1.795% Drawdown 19.000% Expectancy -0.024 Net Profit -5.720% Sharpe Ratio -0.115 Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.04 Alpha 0.045 Beta -3.041 Annual Standard Deviation 0.101 Annual Variance 0.01 Information Ratio -0.298 Tracking Error 0.101 Treynor Ratio 0.004 Total Fees $2022.14 |
#This is a Template of dynamic stock selection. #You can try your own fundamental factor and ranking method by editing the CoarseSelectionFunction and FineSelectionFunction from QuantConnect.Data.UniverseSelection import * from clr import AddReference AddReference("System") AddReference("QuantConnect.Algorithm") AddReference("QuantConnect.Common") from System import * from QuantConnect import * from QuantConnect.Algorithm import * from QuantConnect.Indicators import * from QuantConnect.Data.Market import TradeBar class BasicTemplateAlgorithm(QCAlgorithm): def __init__(self): # set the flag for rebalance self.reb = 1 # Number of stocks to pass CoarseSelection process self.num_coarse = 100 # Number of stocks to long/short self.num_fine = 20 self.symbols = None self.first_month = 0 self.topFine = None def Initialize(self): self.SetCash(100000) self.SetStartDate(2007,1,1) # if not specified, the Backtesting EndDate would be today self.SetEndDate(2010,4,1) self.Portfolio.MarginCallModel = MarginCallModel.Null; ############Trying to chart rolling 30 day performance################ #self.rollingPerformanceWindow = RollingWindow[decimal](30) #self.rollingPerformanceWindow.Add(self.Portfolio.TotalPortfolioValue) #self.Plot("Rolling Performance","Rolling Strategy Performance",(self.rollingPerformanceWindow[29] -self.rollingPerformanceWindow[0])/self.rollingPerformanceWindow[29]) self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol self.UniverseSettings.Resolution = Resolution.Daily self.UniverseSettings.Leverage = 4.0 self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction) # Schedule the rebalance function to execute at the begining of each month self.Schedule.On(self.DateRules.MonthStart(self.spy), self.TimeRules.AfterMarketOpen(self.spy,5), Action(self.rebalance)) def CoarseSelectionFunction(self, coarse): # if the rebalance flag is not 1, return null list to save time. if self.reb != 1: return self.topFine if self.topFine is not None else [] # make universe selection once a month # drop stocks which have no fundamental data or have too low prices selected = [x for x in coarse if (x.HasFundamentalData) and (float(x.Price) > 5)] sortedByDollarVolume = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) top = sortedByDollarVolume[:self.num_coarse] return [i.Symbol for i in top] def FineSelectionFunction(self, fine): # return null list if it's not time to rebalance if self.reb != 1: return self.topFine if self.topFine is not None else [] self.reb = 0 # drop stocks which don't have the information we need. # you can try replacing those factor with your own factors here filtered_fine = [x for x in fine if x.ValuationRatios.FCFRatio] #and x.ValuationRatios.PERatio] self.Log('remained to select %d'%(len(filtered_fine))) # rank stocks by three factor. sortedByfactor1 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.FCFRatio) #sortedByfactor2 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PERatio) #sortedByfactor1 = sorted(filtered_fine, key=lambda x: x.OperationRatios.ROE.Value,reverse=True) #sortedByfactor2 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PSRatio) #sortedByfactor3 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.BookValueYield) #sortedByfactor3 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.FCFRatio) stock_dict = {} # assign a score to each stock, you can also change the rule of scoring here. for i,ele in enumerate(sortedByfactor1): rank1 = i #rank2 = sortedByfactor2.index(ele) #rank3 = sortedByfactor3.index(ele) score = sum([rank1])#*0.5+rank2*0.5]) stock_dict[ele] = score # sort the stocks by their scores self.sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=False) sorted_symbol = [x[0] for x in self.sorted_stock] # sotre the top stocks into the long_list and the bottom ones into the short_list self.long = [x for x in sorted_symbol[:self.num_fine]] self.short = [x for x in sorted_symbol[-self.num_fine:]] self.topFine = [i.Symbol for i in self.long + self.short] return self.topFine def OnData(self, data): pass def rebalance(self): if self.first_month == 0: self.first_month += 1 return # if this month the stock are not going to be long/short, liquidate it. long_short_list = self.topFine for i in self.Portfolio.Values: if (i.Invested) and (i.Symbol not in long_short_list): self.Liquidate(i.Symbol) # Alternatively, you can liquidate all the stocks at the end of each month. # Which method to choose depends on your investment philosiphy # if you prefer to realized the gain/loss each month, you can choose this method. #self.Liquidate() # #self.SetHoldings("SPY",1) # Assign each stock equally. Alternatively you can design your own portfolio construction method for i in self.long: self.SetHoldings(i.Symbol, 0.5/self.num_fine) for i in self.short: self.SetHoldings(i.Symbol, -0.5/self.num_fine) self.reb = 1