Overall Statistics 
Total Trades
4069
Average Win
0.45%
Average Loss
0.42%
Compounding Annual Return
3.817%
Drawdown
39.400%
Expectancy
0.071
Net Profit
73.243%
Sharpe Ratio
0.392
Loss Rate
48%
Win Rate
52%
ProfitLoss Ratio
1.06
Alpha
0.05
Beta
0.096
Annual Standard Deviation
0.106
Annual Variance
0.011
Information Ratio
0.231
Tracking Error
0.222
Treynor Ratio
0.431
Total Fees
$7544.00

# https://quantpedia.com/strategies/momentumfactorcombinedwithassetgrowtheffect/ # # The investment universe consists of NYSE, AMEX and NASDAQ stocks (data for the backtest in the source paper are from Compustat). # Stocks with a market capitalization less than the 20th NYSE percentile (smallest stocks) are removed. The asset growth variable # is defined as the yearly percentage change in balance sheet total assets. Data from year t2 to t1 are used to calculate asset # growth, and July is the cutoff month. Every month, stocks are then sorted into deciles based on asset growth and only stocks # with the highest asset growth are used. The next step is to sort stocks from the highest asset growth decile into quintiles, # based on their past 11month return (with the last month’s performance skipped in the calculation). The investor then goes long # on stocks with the strongest momentum and short on stocks with the weakest momentum. The portfolio is equally weighted and is # rebalanced monthly. The investor holds longshort portfolios only during FebruaryDecember > January is excluded as this month # has been repeatedly documented as a negative month for a momentum strategy (see “January Effect Filter and Momentum in Stocks”). import numpy as np from collections import deque class Momentum_Factor_Asset_Growth_Effect(QCAlgorithm): def Initialize(self): self.SetStartDate(2005, 1, 1) self.SetEndDate(2019, 9, 1) self.SetCash(100000) self.last_course_year = 1 self.last_traded_month = 1 self.course_count = 500 self.total_assets_history_period = 2 self.total_assets = {} self.top_by_growth = [] self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) def CoarseSelectionFunction(self, coarse): if self.last_course_year == self.Time.year or self.Time.month != 7: return Universe.Unchanged self.last_course_year = self.Time.year selected = sorted([x for x in coarse if x.HasFundamentalData and x.Price > 5], key=lambda x: x.DollarVolume, reverse=True) #volumes = [x.DollarVolume for x in selected] #percentile = np.percentile(volumes, 20) #return [x.Symbol for x in selected if x.DollarVolume > percentile] return [x.Symbol for x in selected[:self.course_count]] def FineSelectionFunction(self, fine): selected = [x for x in fine if x.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths > 0] asset_growth = {} for stock in selected: symbol = stock.Symbol if not symbol in self.total_assets: self.total_assets[symbol] = deque(maxlen = self.total_assets_history_period) if len(self.total_assets[symbol]) == self.total_assets_history_period: values = [x for x in self.total_assets[symbol]] asset_growth[symbol] = (values[1]  values[0]) / values[0] self.total_assets[symbol].append(stock.FinancialStatements.BalanceSheet.TotalAssets.TwelveMonths) sorted_by_growth = sorted(asset_growth.items(), key = lambda x: x[1], reverse = True) sorted_by_growth = [x[0] for x in sorted_by_growth] decile = int(len(sorted_by_growth) / 10) self.top_by_growth = sorted_by_growth[:decile] return self.top_by_growth def OnData(self, data): if self.last_traded_month == self.Time.month: return if self.Time.month == 1: if self.Portfolio.Invested: self.Liquidate() return returns = {} lookup_period = 11*21 for symbol in self.top_by_growth: hist = self.History([symbol], lookup_period, Resolution.Daily) if 'close' in hist.columns: hist = hist['close'] if len(hist) == lookup_period: # Return calculation hist = hist[:lookup_period  21] returns[symbol] = (hist[1]  hist[0]) / hist[0] sorted_by_ret = sorted(returns.items(), key = lambda x: x[1], reverse = True) sorted_by_ret = [x[0] for x in sorted_by_ret] quintile = int(len(sorted_by_ret) / 5) long = sorted_by_ret[:quintile] short = sorted_by_ret[quintile:] self.Liquidate() count = len(long) + len(short) if count == 0: return for symbol in long: self.SetHoldings(symbol, 1/count) for symbol in short: self.SetHoldings(symbol, 1/count) self.last_traded_month = self.Time.month