Overall Statistics |
Total Trades 194 Average Win 4.80% Average Loss -1.95% Compounding Annual Return 48.521% Drawdown 17.300% Expectancy 1.219 Net Profit 777.418% Sharpe Ratio 1.921 Probabilistic Sharpe Ratio 95.192% Loss Rate 36% Win Rate 64% Profit-Loss Ratio 2.46 Alpha 0.427 Beta -0.084 Annual Standard Deviation 0.217 Annual Variance 0.047 Information Ratio 1.03 Tracking Error 0.285 Treynor Ratio -4.975 Total Fees $2176.48 |
from QuantConnect.Data.UniverseSelection import * import math import numpy as np import pandas as pd import scipy as sp import statistics class MomentumEffectAlgorithm(QCAlgorithm): def Initialize(self): self.SetStartDate(2015, 7, 1) # Set Start Date self.SetEndDate(2020, 12, 25) # Set Start Date self.SetCash(100000) # Set Strategy Cash self.UniverseSettings.Resolution = Resolution.Daily self.mom = {} # Dict of Momentum indicator keyed by Symbol self.lookback = 252 # Momentum indicator lookback period self.num_coarse = 100 # Number of symbols selected at Coarse Selection self.num_fine = 50 # Number of symbols selected at Fine Selection self.num_long = 5 # Number of symbols with open positions self.month = -1 self.rebalance = False self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) def CoarseSelectionFunction(self, coarse): '''Drop securities which have no fundamental data or have too low prices. Select those with highest by dollar volume''' if self.month == self.Time.month: return Universe.Unchanged self.rebalance = True self.month = self.Time.month selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5], key=lambda x: x.DollarVolume, reverse=True) return [x.Symbol for x in selected[:self.num_coarse]] def FineSelectionFunction(self, fine): filtered_fine = [x for x in fine if x.OperationRatios.OperationMargin.Value and x.ValuationRatios.PriceChange1M and x.ValuationRatios.BookValuePerShare] # rank stocks by three factor. sortedByfactor1 = sorted(filtered_fine, key=lambda x: x.OperationRatios.OperationMargin.Value, reverse=True) sortedByfactor2 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.PriceChange1M, reverse=True) sortedByfactor3 = sorted(filtered_fine, key=lambda x: x.ValuationRatios.BookValuePerShare, reverse=True) 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.1,rank2*0.8,rank3*0.1]) stock_dict[ele] = score # sort the stocks by their scores self.sorted_stock = sorted(stock_dict.items(), key=lambda d:d[1],reverse=True) sorted_symbol = [x[0] for x in self.sorted_stock][:20] '''Select security with highest market cap''' fine = [f for f in fine if f.ValuationRatios.PERatio > 0 and f.EarningReports.BasicEPS.TwelveMonths > 0 and f.EarningReports.BasicAverageShares.ThreeMonths > 0] lowest_market_cap= sorted(fine, key=lambda f: f.ValuationRatios.PERatio * f.EarningReports.BasicEPS.TwelveMonths * f.EarningReports.BasicAverageShares.ThreeMonths, reverse=True) turnoverss=[] for i in lowest_market_cap[:]: hist = self.History([i.Symbol], timedelta(days=10)) if not hist.empty: i.Turnover=(hist["close"].iloc[0]) i.compare= (((statistics.mean(hist["close"]))-(statistics.mean(hist["open"])))/(statistics.stdev(hist["close"]-(statistics.mean(hist["open"]))))) turnoverss.append(i.compare) else: lowest_market_cap.remove(i) lowest_market_cappp=sorted(lowest_market_cap,key=lambda f:f.compare,reverse=False) lowest_market_capp=lowest_market_cappp[:5] turnovers=turnoverss[:3] som=sum(turnovers) self.long = [x.Symbol for x in set(lowest_market_capp).intersection(sorted_symbol)] self.weights = {} for i in lowest_market_capp: self.weights[str(i.Symbol)] = i.compare return self.long def OnData(self, data): if not self.rebalance: return if self.long: stocks_invested = [x.Key for x in self.Portfolio if x.Value.Invested] # liquidate stocks not in the trading list for i in stocks_invested: if i not in self.long: self.Liquidate(i) # goes long on stocks with the lowest turnover for i in self.long: self.SetHoldings(i,-self.weights[str(i)]) # short on stocks with the highest turnover self.rebalance = False