Overall Statistics |
Total Trades 98 Average Win 0.09% Average Loss -0.06% Compounding Annual Return 1.665% Drawdown 2.400% Expectancy 0.594 Net Profit 0.285% Sharpe Ratio 0.331 Probabilistic Sharpe Ratio 38.140% Loss Rate 37% Win Rate 63% Profit-Loss Ratio 1.52 Alpha 0.035 Beta -0.109 Annual Standard Deviation 0.046 Annual Variance 0.002 Information Ratio -1.44 Tracking Error 0.112 Treynor Ratio -0.139 Total Fees $486.79 |
#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 sklearn.datasets import load_iris from sklearn import preprocessing import subfactors class BasicTemplateAlgorithm(QCAlgorithm): def __init__(self): # set the flag for rebalance self.reb = 1 self.months = -1 # Number of stocks to pass CoarseSelection process self.num_coarse = 400 # Number of stocks to long - not used self.symbols = None #Declare empty score lists self.long_score_q = [] def Initialize(self): self.SetCash(1000000) self.SetStartDate(2005,12,29) # if not specified, the Backtesting EndDate would be today self.SetEndDate(2006,3,1) #Set benchmark self.spy = self.AddEquity("SPY", Resolution.Daily).Symbol self.SetBenchmark("SPY") self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction,self.FineSelectionFunction) # Schedule the rebalance function to execute at the begining of each month or week #self.Schedule.On(self.DateRules.Every(DayOfWeek.Monday), #self.TimeRules.AfterMarketOpen(self.spy,20), Action(self.rebalance)) self.Schedule.On(self.DateRules.MonthStart(self.spy), self.TimeRules.AfterMarketOpen(self.spy,20), Action(self.rebalance)) def OnData(self, data): pass def CoarseSelectionFunction(self, coarse): # if the rebalance flag is not 1, return null list to save time. if self.reb != 1: return self.longq + self.shortq # 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) > 1)] sortedByDollarVolume = sorted(selected, key=lambda x: x.DollarVolume, reverse=True) top = sortedByDollarVolume[:self.num_coarse] #self.Log(top[-1].DollarVolume) 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.longq + self.shortq self.reb = 0 data_issues = {"MAA", "FR", "FRT"} filtered_fine = [x for x in fine if x.OperationRatios.DebttoAssets.Value and x.OperationRatios.ROA.Value and x.OperationRatios.ROA5YrAvg.Value and x.OperationRatios.OperationMargin.Value and x.OperationRatios.OperationIncomeGrowth.FiveYears and x.ValuationRatios.PERatio and x.OperationRatios.CurrentRatio.Value and x.AssetClassification.MorningstarIndustryGroupCode != MorningstarIndustryGroupCode.Banks and x.AssetClassification.MorningstarIndustryGroupCode != MorningstarIndustryGroupCode.REITs and (x.CompanyReference.CountryId == "USA") and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"] and (x.Symbol.Value not in data_issues) ] bankscoarse = [x for x in fine if x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.Banks and (not x.SecurityReference.IsDepositaryReceipt) and (x.CompanyReference.CountryId == "USA") and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"] and (x.Symbol.Value not in data_issues) ] banks = [x for x in bankscoarse if x.ValuationRatios.TangibleBookValuePerShare and x.FinancialStatements.TotalRiskBasedCapital.Value and x.OperationRatios.ROE.Value and x.OperationRatios.ROE5YrAvg.Value ] # put REITs in seperate category REITs_coarse = [x for x in fine if x.AssetClassification.MorningstarIndustryGroupCode == MorningstarIndustryGroupCode.REITs and (not x.SecurityReference.IsDepositaryReceipt) and (x.CompanyReference.CountryId == "USA") and x.CompanyReference.PrimaryExchangeID in ["NYS","NAS"] and (x.Symbol.Value not in data_issues) ] REITs = [x for x in REITs_coarse if x.ValuationRatios.FFOPerShare and x.OperationRatios.FinancialLeverage.Value and x.OperationRatios.ROE5YrAvg.Value ] # Here I do things #Put factors as scores REITs_score = {} bank_score = {} all_score = {} #Simplified for i,ele in enumerate(filtered_fine): all_score[ele] = i for i,ele in enumerate(banks): bank_score[ele] = i for i,ele in enumerate(REITs): REITs_score[ele] = i min_all = min(all_score.values()) max_all = max(all_score.values()) for i,ele in enumerate(all_score): all_score[ele] = (all_score[ele]-min_all) / (max_all - min_all) min_bank = min(bank_score.values()) max_bank = max(bank_score.values()) for i,ele in enumerate(bank_score): bank_score[ele] = (bank_score[ele]-min_bank) / (max_bank - min_bank) min_REIT = min(REITs_score.values()) max_REIT = max(REITs_score.values()) for i,ele in enumerate(REITs_score): REITs_score[ele] = (REITs_score[ele]-min_REIT) / (max_REIT - min_REIT) all_stocks = {**bank_score, **REITs_score, **all_score} # sort the stocks by their ranks low to high self.sorted_stockvq = sorted(all_stocks.items(), key=lambda d:d[1],reverse=False) sorted_score = [x[0] for x in self.sorted_stockvq] sorted_vq_score = [x[1] for x in self.sorted_stockvq] # sort the top stocks into each factor sliced = int(round(len(sorted_score)/10)) self.longq = [x.Symbol for x in sorted_score[:sliced]] self.long_score_q = [x for x in sorted_vq_score[:sliced]] self.shortq = [x.Symbol for x in sorted_score[-sliced:]] self.short_score_q = [x for x in sorted_vq_score[-sliced:]] return self.longq + self.shortq def rebalance(self): # if this month the stock are not going to be long, liquidate it. total_list = self.longq + self.shortq long_score = self.long_score_q total_list.clear() long_list = self.longq short_list = self.shortq short_score = self.short_score_q maxwgt = 0.2 slope = 0.55 gross_exposure = 0.85 gross_exp = gross_exposure sum_long_score =0 sum_short_score =0 total_wgts = [] #long_wgts = [] i =0 num_short =0 """while gross_exp > 0 and maxwgt-(slope*(long_score[i]**2)) > 0: #for i in range(0, len(long_score)): weight = maxwgt-(slope*(long_score[i]**2)) total_wgts.append(weight) total_list.append(long_list[i]) gross_exp -= weight i += 1""" """gross_exp = 0.85 k = len(short_score)-1 while gross_exp > 0 and maxwgt-(slope*(short_score[k]**2)) < 0: weight = maxwgt-(slope*(short_score[k]**2)) total_wgts.append(weight) total_list.append(short_list[k]) gross_exp += weight k -= 1""" #sum_short_score += max(short_score[i]**0.75,0.15) for i in range(0, len(long_score)): sum_long_score += (1/max(long_score[i]**0.75,0.15)) for i in range(0, len(long_score)): total_wgts.append((1/max(long_score[i]**0.75,0.15))/sum_long_score) """for i in range(0, len(short_score)): short_wgts.append(1/len(short_score)) #short_wgts.append(max(short_score[i]**0.75,0.15)/sum_short_score) """ total_list = long_list #+ short_list for i in self.Portfolio.Values: if (i.Invested) and (i.Symbol not in total_list) and (i.Symbol.Value != "SPY"): self.Liquidate(i.Symbol) # Assign each stock equally k = 0 for i in total_list: #self.Log(";Buying;" +str(long_wgts[k]) + ";of;"+ str(i) + ";with score;" + str(long_score[k])) self.SetHoldings(i, total_wgts[k]*gross_exposure) self.Log(i) self.Log(total_wgts[k]) self.Log(long_score[k]) k+=1 #k = 0 """for i in short_list: #self.Log(";Shorting;" +str(short_wgts[k]) + ";of;"+ str(i) + ";with score;" + str(short_score[k])) self.SetHoldings(i, -short_wgts[k]*gross_exposure) sum_short += -short_wgts[k]*gross_exposure k+=1""" self.SetHoldings("SPY", -gross_exposure) self.reb = 1
class subfactor(): def normalise(data): min_data = min(data) max_data = max(data) for i in range(0, len(data)): data[i] = (data[i]-min_data) / (max_data - min_data) return data # Your New Python File