Overall Statistics
Total Trades
1
Average Win
0%
Average Loss
0%
Compounding Annual Return
-27.656%
Drawdown
3.600%
Expectancy
0
Net Profit
-2.453%
Sharpe Ratio
-3.474
Probabilistic Sharpe Ratio
5.163%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
-0.342
Beta
0.146
Annual Standard Deviation
0.066
Annual Variance
0.004
Information Ratio
-10.34
Tracking Error
0.097
Treynor Ratio
-1.561
Total Fees
$5.01
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