from math import ceil,floor
import pandas as pd
import numpy as np
class ResistanceOptimizedAutosequencers(QCAlgorithm):
def Initialize(self):
self.SetStartDate(2015,2,1) #Set Start Date
self.SetEndDate(2015,3,1) #Set End Date
self.SetCash(100000) #Set Strategy Cash
self.rebalance_flag = True
self.AddEquity("SPY", Resolution.Daily)
self.TF_filter = False
self.TF_lookback = 126
self.num_positions = 50
self.bond = self.AddEquity("IEF", Resolution.Daily)
self.relative_momentum_lookback = 126 #Momentum lookback
self.momentum_skip_days = 10
self.symbols = None
self.SetWarmUp(200)
self.UniverseSettings.Resolution = Resolution.Minute
self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction)
self.Schedule.On(self.DateRules.MonthStart("SPY"), self.TimeRules.AfterMarketOpen("SPY", 60), Action(self.rebalance))
def CoarseSelectionFunction(self, coarse):
if self.rebalance_flag and not self.IsWarmingUp:
CoarseWithFundamental = [x for x in coarse if x.HasFundamentalData and x.Price > 5]
sortedByDollarVolume = sorted(CoarseWithFundamental, key=lambda x: x.DollarVolume, reverse=True)[:1000]
return [i.Symbol for i in sortedByDollarVolume]
else:
return []
def FineSelectionFunction(self, fine):
if self.rebalance_flag and not self.IsWarmingUp:
filtered_fine = [x for x in fine if x.OperationRatios.ROIC.Value
and x.OperationRatios.LongTermDebtEquityRatio.Value
and x.ValuationRatios.CashReturn
and x.ValuationRatios.FCFYield
and x.MarketCap]
filtered_marketcap = sorted(filtered_fine, key=lambda x: x.MarketCap, reverse=True)[:700]
sortedByfactor1 = sorted(filtered_marketcap, key=lambda x: x.OperationRatios.ROIC.Value, reverse=True)
sortedByfactor2 = sorted(filtered_marketcap, key=lambda x: x.OperationRatios.LongTermDebtEquityRatio.Value, reverse=True)
sortedByfactor3 = sorted(filtered_marketcap, key=lambda x: x.ValuationRatios.CashReturn, reverse=True)
sortedByfactor4 = sorted(filtered_marketcap, key=lambda x: x.ValuationRatios.FCFYield, reverse=True)
num_stocks = floor(len(filtered_marketcap)/self.num_positions)
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
top_stocks = sorted(stock_dict.items(), key=lambda d:d[1],reverse=True)
top_symbols = [top_stocks[i][0] for i in range(len(top_stocks))][:100]
self.rebalance_flag = False
self.symbols = [i.Symbol for i in top_symbols]
return self.symbols
else:
return []
def rebalance(self):
if not self.IsWarmingUp:
############Trend Following Regime Filter############
spy_history = self.History(["SPY"], 200, Resolution.Daily).loc["SPY"]
spy_ma50 = spy_history["close"].iloc[:-50].mean()
spy_ma200 = spy_history["close"].mean()
if spy_ma50 > spy_ma200:
self.TF_filter = True
else:
self.TF_filter = False
if self.symbols:
prices = self.History(self.symbols, 200, Resolution.Daily).unstack(level=0)["close"]
quality_momentum = prices.iloc[:-self.momentum_skip_days].pct_change(self.relative_momentum_lookback).iloc[-1]
top_momentum_stocks = quality_momentum.sort_values(ascending=False)[:self.num_positions]
top_momentum_symbols = [self.Symbol(i) for i in top_momentum_stocks.index.values]
portfolio_holdings = [x.Key for x in self.Portfolio if x.Value.Invested]
for symbol in portfolio_holdings:
if not symbol == self.Symbol("IEF") and symbol not in top_momentum_symbols:
self.Debug(f"Liquidating {symbol}")
self.Liquidate(symbol)
if self.TF_filter:
self.Debug("Tf Filter True")
self.Liquidate(self.bond.Symbol)
for symbol in top_momentum_symbols:
self.Debug(f"Buying {symbol}")
self.SetHoldings(symbol, (1.0 / self.num_positions))
if len(portfolio_holdings) != self.num_positions:
bond_position = 1-(len(portfolio_holdings)*(1.0 / self.num_positions))
self.Debug(f"Buying Bonds - Portfolio: {len(portfolio_holdings)}, Bond Position {bond_position}")
self.SetHoldings(self.bond.Symbol, bond_position)
self.rebalance_flag = True