Overall Statistics |
Total Trades 5 Average Win 0% Average Loss 0% Compounding Annual Return 0% Drawdown 0% Expectancy 0 Net Profit 0% Sharpe Ratio 0 Probabilistic Sharpe Ratio 0% Loss Rate 0% Win Rate 0% Profit-Loss Ratio 0 Alpha 0 Beta 0 Annual Standard Deviation 0 Annual Variance 0 Information Ratio 0 Tracking Error 0 Treynor Ratio 0 Total Fees $5.00 Estimated Strategy Capacity $31000000.00 Lowest Capacity Asset RNR R735QTJ8XC9X Portfolio Turnover 41.66% |
#region imports from AlgorithmImports import * #endregion class FundamentalFactorAlphaModel(AlphaModel): def __init__(self, str_period=7, str_multiplier=3): self.rebalanceTime = datetime.min # Dictionary containing set of securities in each sector # e.g. {technology: set(AAPL, TSLA, ...), healthcare: set(XYZ, ABC, ...), ... } self.sectors = {} self.symbolData = {} self.exclusions = ['SPY'] self.str_period = str_period self.str_multiplier = str_multiplier def Update(self, algorithm, data): '''Updates this alpha model with the latest data from the algorithm. This is called each time the algorithm receives data for subscribed securities Args: algorithm: The algorithm instance data: The new data available Returns: New insights''' algorithm.Plot("myPlot", "SPY", self.spy.Close) if algorithm.Time <= self.rebalanceTime: return [] # Set the rebalance time to match the insight expiry #self.rebalanceTime = Expiry.EndOfQuarter(algorithm.Time) self.rebalanceTime = Expiry.EndOfMonth(algorithm.Time) insights = [] for sector in self.sectors: securities = self.sectors[sector] sortedByROE_pos = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.ROE.Value, reverse=True) sortedByPM_pos = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.NetMargin.Value, reverse=True) sortedByPE_pos = sorted(securities, key=lambda x: x.Fundamentals.ValuationRatios.PERatio, reverse=True) sortedByROE_neg = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.ROE.Value, reverse=False) sortedByPM_neg = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.NetMargin.Value, reverse=False) sortedByPE_neg = sorted(securities, key=lambda x: x.Fundamentals.ValuationRatios.PERatio, reverse=False) # Dictionary holding a dictionary of scores for each security in the sector scores_pos = {} for security in securities: score = sum([sortedByROE_pos.index(security), sortedByPM_pos.index(security), sortedByPE_pos.index(security)]) scores_pos[security] = score scores_neg = {} for security in securities: score = sum([sortedByROE_neg.index(security), sortedByPM_neg.index(security), sortedByPE_neg.index(security)]) scores_neg[security] = score for key, sd in self.symbolData.items(): # Add best 20% of each sector to long set (minimum 1) if self.spy.Close > sd.str.Current.Value: #length = max(int(len(scores_pos)/5), 1) length = 1 for security in sorted(scores_pos.items(), key=lambda x: x[1], reverse=False)[:length]: symbol = security[0].Symbol # Use Expiry.EndOfQuarter in this case to match Universe, Alpha and PCM #insights.append(Insight.Price(symbol, Expiry.EndOfQuarter, InsightDirection.Up)) insights.append(Insight.Price(symbol, Expiry.EndOfMonth, InsightDirection.Up)) # Add worst 20% of each sector to short set (minimum 1) elif self.spy.Close < sd.str.Current.Value: #length = max(int(len(scores_neg)/5), 1) length = 1 for security in sorted(scores_neg.items(), key=lambda x: x[1], reverse=False)[:length]: symbol = security[0].Symbol # Use Expiry.EndOfQuarter in this case to match Universe, Alpha and PCM #insights.append(Insight.Price(symbol, Expiry.EndOfQuarter, InsightDirection.Down)) insights.append(Insight.Price(symbol, Expiry.EndOfMonth, InsightDirection.Down)) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' # Remove security from sector set for security in changes.RemovedSecurities: if security.Symbol.Value not in self.exclusions: for sector in self.sectors: if security in self.sectors[sector]: self.sectors[sector].remove(security) # Add security to corresponding sector set for security in changes.AddedSecurities: if security.Symbol.Value in self.exclusions: # Add SPY to symbolData self.symbolData[security.Symbol] = SymbolData(algorithm, security, self.str_period, self.str_multiplier) #self.indicators[security.Symbol] = SymbolData(algorithm, security, self.str_period, self.str_multiplier) self.spy = security if security.Symbol.Value not in self.exclusions: sector = security.Fundamentals.AssetClassification.MorningstarSectorCode if sector not in self.sectors: self.sectors[sector] = set() self.sectors[sector].add(security) class SymbolData: def __init__(self, algorithm, security, str_period, str_multiplier): self.algorithm = algorithm self.Security = security self.str = SuperTrend(str_period, str_multiplier, MovingAverageType.Wilders) #self.ema = ExponentialMovingAverage(20,0.5) #self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, Resolution.Daily) #algorithm.RegisterIndicator(security.Symbol, self.str, self.Consolidator) algorithm.RegisterIndicator(self.Security.Symbol, self.str, Resolution.Daily) algorithm.WarmUpIndicator(security.Symbol, self.str, Resolution.Daily) #algorithm.RegisterIndicator(self.Security.Symbol, self.ema, Resolution.Daily) #algorithm.WarmUpIndicator(security.Symbol, self.ema, Resolution.Daily) self.str.Updated += self.OnSTRUpdated #self.ema.Updated += self.OnEMAUpdated def OnSTRUpdated(self, sender, updated): self.algorithm.Plot("myPlot", "STR", updated) def OnEMAUpdated(self, sender, updated): self.algorithm.Plot("myPlot", "EMA", updated)
# region imports from AlgorithmImports import * import numpy as np # endregion from AlphaModel import * class VerticalTachyonRegulators(QCAlgorithm): def Initialize(self): self.SetStartDate(2023, 5, 30) self.SetEndDate(2023, 6, 1) self.SetCash(3000) self.EnableAutomaticIndicatorWarmUp = True # Universe selection self.month = 0 self.num_coarse = 500 self.UniverseSettings.Resolution = Resolution.Daily # # Add SPY to the universe # self.spy = self.AddEquity('SPY', Resolution.Daily).Symbol self.AddUniverseSelection(ManualUniverseSelectionModel(self.spy)) # # Add rest of stocks to universe # self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) # Alpha Model self.AddAlpha(FundamentalFactorAlphaModel()) # Portfolio construction model self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(self.IsRebalanceDue)) # Risk model #self.SetRiskManagement(NullRiskManagementModel()) self.SetRiskManagement(TrailingStopRiskManagementModel(0.1)) #self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.10)) # Execution model self.SetExecution(ImmediateExecutionModel()) chart = Chart("myPlot") self.AddChart(chart) # Share the same rebalance function for Universe and PCM for clarity def IsRebalanceDue(self, time): # Rebalance on the first day of the Quarter or Month #if time.month == self.month or time.month not in [1, 4, 7, 10]: #if time.month == self.month or time.month not in [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12]: if time.month == self.month or time.month not in np.arange(1,13): return None self.month = time.month return time def CoarseSelectionFunction(self, coarse): # If not time to rebalance, keep the same universe if not self.IsRebalanceDue(self.Time): return Universe.Unchanged # Select only those with fundamental data and a sufficiently large price # Sort by top dollar volume: most liquid to least liquid 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): # Filter the fine data for equities that IPO'd more than 5 years ago in selected sectors sectors = [ MorningstarSectorCode.FinancialServices, MorningstarSectorCode.RealEstate, MorningstarSectorCode.Healthcare, MorningstarSectorCode.Utilities, MorningstarSectorCode.Technology] #sectors = [ # MorningstarSectorCode.Technology] filtered_fine = [x.Symbol for x in fine if x.SecurityReference.IPODate + timedelta(365*5) < self.Time and x.AssetClassification.MorningstarSectorCode in sectors and x.OperationRatios.ROE.Value != 0 and x.OperationRatios.NetMargin.Value != 0 and x.ValuationRatios.PERatio != 0] return filtered_fine