Overall Statistics |
Total Trades 9454 Average Win 0.02% Average Loss -0.07% Compounding Annual Return -31.288% Drawdown 23.200% Expectancy -0.075 Net Profit -17.040% Sharpe Ratio -0.953 Probabilistic Sharpe Ratio 3.937% Loss Rate 29% Win Rate 71% Profit-Loss Ratio 0.29 Alpha -0.148 Beta 0.691 Annual Standard Deviation 0.213 Annual Variance 0.045 Information Ratio -0.634 Tracking Error 0.194 Treynor Ratio -0.294 Total Fees $11099.67 Estimated Strategy Capacity $710000.00 Lowest Capacity Asset SOXL UKTSIYPJHFMT |
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. # Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from AlgorithmImports import * class EmaCrossMagnitudeAlphaModel(AlphaModel): '''Alpha model that uses an EMA cross to create insights''' def __init__(self, fastPeriod = 12, slowPeriod = 26, resolution = Resolution.Daily): '''Initializes a new instance of the EmaCrossAlphaModel class Args: fastPeriod: The fast EMA period slowPeriod: The slow EMA period''' self.fastPeriod = fastPeriod self.slowPeriod = slowPeriod self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod) self.symbolDataBySymbol = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, resolutionString) 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: The new insights generated''' insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): price = symbolData.algorithm.Securities[symbol].Close magnitude = 100.0 * price * (symbolData.Fast.Current.Value - symbolData.Slow.Current.Value) / (symbolData.Fast.Current.Value + symbolData.Slow.Current.Value) direction = InsightDirection.Flat if symbolData.FastIsOverSlow: if symbolData.Slow > symbolData.Fast: direction = InsightDirection.Down magnitude = -magnitude elif symbolData.SlowIsOverFast: if symbolData.Fast > symbolData.Slow: direct = InsightDirection.Up else: direction = InsightDirection.Flat insight = Insight.Price(symbol, self.predictionInterval, direction, magnitude=magnitude) symbolData.FastIsOverSlow = symbolData.Fast > symbolData.Slow insights.append(insight) algorithm.Debug("EMA INSIGHT LENGTH " + str(len(insights))) 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''' # clean up data for removed securities for removed in changes.RemovedSecurities: symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None) if symbolData is not None: symbolData.RemoveConsolidators(algorithm) # initialize data for added securities symbols = [ x.Symbol for x in changes.AddedSecurities ] history = algorithm.History(symbols, self.resolution) if history.empty: return tickers = history.index.levels[0] for ticker in tickers: symbol = SymbolCache.GetSymbol(ticker) if symbol not in self.symbolDataBySymbol: symbolData = SymbolData(symbol, algorithm, self.slowPeriod, self.fastPeriod, self.resolution) self.symbolDataBySymbol[symbol] = symbolData algorithm.Debug("EMA LENGTH") algorithm.Debug(str(len(self.symbolDataBySymbol))) class SymbolData: '''Contains data specific to a symbol required by this model''' def __init__(self, symbol, algorithm, slowPeriod, fastPeriod, resolution): self.Symbol = symbol self.algorithm = algorithm self.slowPeriod = slowPeriod self.fastPeriod = fastPeriod self.resolution = resolution self.Slow = algorithm.EMA(self.Symbol, self.slowPeriod, self.resolution) self.Fast = algorithm.EMA(self.Symbol, self.fastPeriod, self.resolution) # True if the fast is above the slow, otherwise false. # This is used to prevent emitting the same signal repeatedly self.FastIsOverSlow = False @property def SlowIsOverFast(self): return not self.FastIsOverSlow
# QUANTCONNECT.COM - Democratizing Finance, Empowering Individuals. # Lean Algorithmic Trading Engine v2.0. Copyright 2014 QuantConnect Corporation. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. from AlgorithmImports import * class MacdMagnitudeAlphaModel(AlphaModel): '''Defines a custom alpha model that uses MACD crossovers. The MACD signal line is used to generate up/down insights if it's stronger than the bounce threshold. If the MACD signal is within the bounce threshold then a flat price insight is returned.''' def __init__(self, fastPeriod = 12, slowPeriod = 26, signalPeriod = 9, movingAverageType = MovingAverageType.Exponential, resolution = Resolution.Daily): ''' Initializes a new instance of the MacdAlphaModel class Args: fastPeriod: The MACD fast period slowPeriod: The MACD slow period</param> signalPeriod: The smoothing period for the MACD signal movingAverageType: The type of moving average to use in the MACD''' self.fastPeriod = fastPeriod self.slowPeriod = slowPeriod self.signalPeriod = signalPeriod self.movingAverageType = movingAverageType self.resolution = resolution self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(resolution), fastPeriod) self.bounceThresholdPercent = 0.01 self.symbolDataBySymbol = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) movingAverageTypeString = Extensions.GetEnumString(movingAverageType, MovingAverageType) self.Name = '{}({},{},{},{},{})'.format(self.__class__.__name__, fastPeriod, slowPeriod, signalPeriod, movingAverageTypeString, resolutionString) def Update(self, algorithm, data): ''' Determines an insight for each security based on it's current MACD signal Args: algorithm: The algorithm instance data: The new data available Returns: The new insights generated''' insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): close = symbolData.algorithm.Securities[symbol].Close direction = InsightDirection.Flat normalized_signal = symbolData.MACD.Signal.Current.Value / close magnitude = (abs(symbolData.MACD.Histogram.Current.Value * symbolData.MACD.Signal.Current.Value))**0.5 / close**2 if normalized_signal > self.bounceThresholdPercent: direction = InsightDirection.Up elif normalized_signal < -self.bounceThresholdPercent: direction = InsightDirection.Down magnitude *= -1.0 #Placeholder magnitudes # ignore signal for same direction as previous signal if direction == symbolData.PreviousDirection: magnitude/= 10.0 insight = Insight.Price(symbol, self.insightPeriod, direction, magnitude=magnitude) #Placeholder magnitudes symbolData.PreviousDirection = insight.Direction insights.append(insight) algorithm.Debug("MACD INSIGHT LENGTH " + str(len(insights))) return insights def OnSecuritiesChanged(self, algorithm, changes): '''Event fired each time the we add/remove securities from the data feed. This initializes the MACD for each added security and cleans up the indicator for each removed security. Args: algorithm: The algorithm instance that experienced the change in securities changes: The security additions and removals from the algorithm''' for removed in changes.RemovedSecurities: data = self.symbolData.pop(removed.Symbol, None) if data is not None: # clean up our consolidator algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) # clean up data for removed securities for removed in changes.RemovedSecurities: symbolData = self.symbolDataBySymbol.pop(removed.Symbol, None) # initialize data for added securities symbols = [ x.Symbol for x in changes.AddedSecurities ] history = algorithm.History(symbols,self.resolution) if history.empty: return tickers = history.index.levels[0] for ticker in tickers: symbol = SymbolCache.GetSymbol(ticker) if symbol not in self.symbolDataBySymbol: symbolData = SymbolData(algorithm, symbol, self.fastPeriod, self.slowPeriod, self.signalPeriod, self.movingAverageType, self.resolution) self.symbolDataBySymbol[symbol] = symbolData algorithm.Debug("MACD LENGTH") algorithm.Debug(str(len(self.symbolDataBySymbol))) class SymbolData: def __init__(self, algorithm, symbol, fastPeriod, slowPeriod, signalPeriod, movingAverageType, resolution): self.Symbol = symbol self.MACD = MovingAverageConvergenceDivergence(fastPeriod, slowPeriod, signalPeriod, movingAverageType) self.algorithm = algorithm self.Consolidator = algorithm.ResolveConsolidator(symbol, resolution) algorithm.RegisterIndicator(symbol, self.MACD, self.Consolidator) algorithm.WarmUpIndicator(symbol, self.MACD, resolution) self.PreviousDirection = None
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from Portfolio.BlackLittermanOptimizationPortfolioConstructionModel import BlackLittermanOptimizationPortfolioConstructionModel from Risk.MaximumDrawdownPercentPerSecurity import MaximumDrawdownPercentPerSecurity from MacdMagnitudeAlphaModel import MacdMagnitudeAlphaModel from EmaCrossMagnitudeAlphaModel import EmaCrossMagnitudeAlphaModel class BlackLittermanDebugging(QCAlgorithm): def Initialize(self): self.SetStartDate(2021, 9, 7) # Set Start Date self.SetCash(100000) # Set Strategy Cash self.SetBrokerageModel(BrokerageName.AlphaStreams) self.AddAlpha(EmaCrossMagnitudeAlphaModel(50, 200, Resolution.Minute)) self.AddAlpha(MacdMagnitudeAlphaModel(12, 26, 9, MovingAverageType.Simple, Resolution.Minute)) self.SetExecution(ImmediateExecutionModel()) self.SetPortfolioConstruction(BlackLittermanOptimizationPortfolioConstructionModel()) self.SetRiskManagement(MaximumDrawdownPercentPerSecurity(0.01)) self.UniverseSettings.Resolution = Resolution.Minute symbols = [ Symbol.Create("SPY", SecurityType.Equity, Market.USA), Symbol.Create("AAPL", SecurityType.Equity, Market.USA), Symbol.Create("UVXY", SecurityType.Equity, Market.USA), Symbol.Create("SOXL", SecurityType.Equity, Market.USA), Symbol.Create("FB", SecurityType.Equity, Market.USA) ] self.AddUniverseSelection(ManualUniverseSelectionModel(symbols)) def OnData(self, data): '''OnData event is the primary entry point for your algorithm. Each new data point will be pumped in here. Arguments: data: Slice object keyed by symbol containing the stock data '''