Overall Statistics |
Total Trades 466 Average Win 0.17% Average Loss -0.13% Compounding Annual Return 17.567% Drawdown 32.900% Expectancy 0.099 Net Profit 17.619% Sharpe Ratio 0.636 Probabilistic Sharpe Ratio 32.302% Loss Rate 52% Win Rate 48% Profit-Loss Ratio 1.30 Alpha 0.247 Beta -0.221 Annual Standard Deviation 0.317 Annual Variance 0.101 Information Ratio -0.002 Tracking Error 0.483 Treynor Ratio -0.911 Total Fees $466.05 Estimated Strategy Capacity $42000000.00 Lowest Capacity Asset AGO SY2SA4YZ4UW5 |
from AlphaModel import * class VerticalTachyonRegulators(QCAlgorithm): def Initialize(self): self.SetStartDate(2020, 1, 1) self.SetEndDate(2021, 1, 1) self.SetCash(100000) # Execution model self.SetExecution(ImmediateExecutionModel()) # Portfolio construction model self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel(rebalance=timedelta(weeks=13))) # Risk model self.SetRiskManagement(NullRiskManagementModel()) # Universe selection self.num_coarse = 500 self.rebalanceTime = datetime.min self.UniverseSettings.Resolution = Resolution.Daily self.AddUniverse(self.CoarseSelectionFunction, self.FineSelectionFunction) self.sectors = set([MorningstarSectorCode.FinancialServices, MorningstarSectorCode.RealEstate, MorningstarSectorCode.Healthcare, MorningstarSectorCode.Utilities, MorningstarSectorCode.Technology]) self.period = timedelta(weeks=13) # Alpha Model self.AddAlpha(FundamentalFactorAlphaModel(self.period, self.sectors)) def CoarseSelectionFunction(self, coarse): # If not time to rebalance, keep the same universe if self.Time <= self.rebalanceTime: return Universe.Unchanged self.rebalanceTime = self.Time + self.period # 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 given sector filtered_fine = [x.Symbol for x in fine if x.SecurityReference.IPODate + timedelta(365*5) < self.Time and x.AssetClassification.MorningstarSectorCode in self.sectors and x.OperationRatios.ROE.Value > 0 and x.OperationRatios.NetMargin.Value > 0 and x.ValuationRatios.PERatio > 0] return filtered_fine
from datetime import timedelta class FundamentalFactorAlphaModel(AlphaModel): def __init__(self, period, sectors): self.rebalanceTime = datetime.min self.sectors = {} for sector in sectors: self.sectors[sector] = set() self.period = period 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''' # Return no insights if it's not time to rebalance if algorithm.Time <= self.rebalanceTime: return [] self.rebalanceTime = algorithm.Time + self.period # Dictionary holding a dictionary of scores for each sector sector_scores = {} for sector in self.sectors: securities = self.sectors[sector] sortedByROE = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.ROE.Value, reverse=True) sortedByPM = sorted(securities, key=lambda x: x.Fundamentals.OperationRatios.NetMargin.Value, reverse=True) sortedByPE = sorted(securities, key=lambda x: x.Fundamentals.ValuationRatios.PERatio, reverse=False) scores = {} for security in securities: score = sum([sortedByROE.index(security), sortedByPM.index(security), sortedByPE.index(security)]) scores[security] = score sector_scores[sector] = scores # Set of symbols that we want to buy longs = set() for sector in self.sectors: # add best 20% of each sector to longs set (minimum 1) length = max(int(len(sector_scores[sector])/5), 1) for security in sorted(sector_scores[sector].items(), key=lambda x: x[1], reverse=False)[:length]: longs.add(security[0].Symbol) # Insights of the form: Insight(symbol, timedelta, type, direction, magnitude, confidence, sourceModel, weight) insights = [] # Close old positions if they aren't in longs set for security in algorithm.Portfolio.Values: if security.Invested and security.Symbol not in longs: insights.append(Insight(security.Symbol, Expiry.EndOfDay, InsightType.Price, InsightDirection.Flat)) # Emit buy insight for all symbols in longs set for symbol in longs: insights.append(Insight(symbol, self.period, InsightType.Price, InsightDirection.Up)) 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: 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: self.sectors[security.Fundamentals.AssetClassification.MorningstarSectorCode].add(security)