Overall Statistics |
Total Trades 10 Average Win 2.78% Average Loss -0.55% Compounding Annual Return 0.307% Drawdown 5.200% Expectancy 0.208 Net Profit 0.309% Sharpe Ratio 0.073 Probabilistic Sharpe Ratio 15.369% Loss Rate 80% Win Rate 20% Profit-Loss Ratio 5.04 Alpha 0.004 Beta -0.03 Annual Standard Deviation 0.056 Annual Variance 0.003 Information Ratio 0.006 Tracking Error 0.16 Treynor Ratio -0.136 Total Fees $45.29 |
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(2016,2,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.Daily 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