Overall Statistics |
Total Trades 9806 Average Win 0.00% Average Loss 0.00% Compounding Annual Return -25.259% Drawdown 13.000% Expectancy -0.751 Net Profit -12.956% Sharpe Ratio -5.663 Probabilistic Sharpe Ratio 0.000% Loss Rate 88% Win Rate 12% Profit-Loss Ratio 1.11 Alpha -0.215 Beta 0.015 Annual Standard Deviation 0.038 Annual Variance 0.001 Information Ratio -2.882 Tracking Error 0.112 Treynor Ratio -13.791 Total Fees $9809.46 Estimated Strategy Capacity $41000000.00 Lowest Capacity Asset FR R735QTJ8XC9X |
pass class MyDonchianChannelAlphaModel(QCAlgorithm): def __init__(self, upperBand = 55, lowerBand = 55, resolution = Resolution.Daily): self.upperBand = upperBand self.lowerBand = lowerBand self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), upperBand) self.symbolDataBySymbol = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, upperBand, lowerBand, resolutionString) def Update(self, algorithm, data): insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): if symbolData.donchian.IsReady: if symbolData.PriceOverUpper: if symbolData.Close > symbolData.donchian.UpperBand.Current.Value: insights.append(Insight.Price(symbolData.Symbol, self.predictionInterval, InsightDirection.Up)) elif symbolData.PriceUnderLower: if symbolData.Close < symbolData.donchian.LowerBand.Current.Value: insights.append(Insight.Price(symbolData.symbol, self.predictionInterval, InsightDirection.Down)) symbolData.PriceOverUpper = symbolData.Close > symbolData.donchian.UpperBand.Current.Value symbolData.PriceUnderLower = symbolData.Close < symbolData.donchian.LowerBand.Current.Value return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: symbolData = self.symbolDataBySymbol.get(added.Symbol) if symbolData is None: symbolData = self.SymbolData(added) symbolData.donchian = algorithm.DCH(added.Symbol, self.upperBand, self.lowerBand, self.resolution) self.SetWarmup(55) self.symbolDataBySymbol[added.Symbol] = symbolData else: symbolData.donchian.Reset() class SymbolData: def __init__(self, security): self.Bars = None self.Security = security self.Symbol = security.Symbol self.Close = None self.donchian = None self.PriceOverUpper = False self.PriceUnderLower = False #rolling windows!!
pass class Donchian3(AlphaModel): def __init__(self, upperBand = 55, lowerBand = 55, resolution = Resolution.Daily): self.upperBand = upperBand self.lowerBand = lowerBand self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), upperBand) self.symbolDataBySymbol = {} self.closeWindow = {} self.donchianWindow = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, upperBand, lowerBand, 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 # Generate insights on the securities in the universe. insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): if symbolData.closeWindow[0] > symbolData.donchianWindow.UpperBand[1]: insights.append(Insight.Price(symbolData.Symbol, self.predicationInterval, InsightDirection.Up)) elif symbolData.closeWindow[0] < symbolData.donchianWindow.LowerBand[1]: insights.append(Insight.Price(symbolData.Symbol, self.predicationInterval, InsightDirection.Down)) return insights def OnSecuritiesChanged(self, algorithm, changes): # Handle security changes in from your universe model. for added in changes.Securities: symbolData = self.symbolDataBySymbol.get(added.Symbol) if symbolData is none: symbolData = SymbolData(added) self.closeWindow.Add(data[added.Symbol]) self.symbolDataBySymbol[added.Symbol] = symbolData else: symbolData.donchian.Reset() class SymbolData: def __init__(self, algorithm, security): self.algorithm = algorithm self.Security = security self.Symbol = security.Symbol self.donchian = algorithm.DCH(added.Symbol, self.upperBand, self.lowerBand, self.resolution) self.donchianWindow = RollingWindow[IndicatorDataPoint](2) self.donchian.Updated += self.OnDonchianUpdated self.consolidator = TradeBarConsolidator(resolution.Daily) #self.closeWindow = RollingWindow[TradeBar](2) #self.Consolidate(self.symbol, Resolution.Daily, lambda x: self.closewindow.Add(x)) #self.closeWindow.Add(Data[self.symbol]) #init tradebars here for securities also def OnDonchianUpdated(self, sender, updated): if self.donchian.IsReady: self.donchianWindow.Add(updated) #def OnCloseWindowUpdated(self, sender, updated): #if self.closeWindow.IsReady: #self.closeWindow.Add(updated) @property def IsReady(self): return self.donchian.IsReady and self.donchianWindow.IsReady
pass
class DrawdownStops(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that limits the drawdown per holding to the specified percentage''' def __init__(self, maximumDrawdownPercent = 0.05): '''Initializes a new instance of the MaximumDrawdownPercentPerSecurity class Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for any single security holding''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' targets = [] for kvp in algorithm.Securities: security = kvp.Value if not security.Invested: continue pnl = security.Holdings.UnrealizedProfitPercent if pnl < self.maximumDrawdownPercent: # liquidate targets.append(PortfolioTarget(security.Symbol, 0)) return targets
pass
class LiquidUniverseSelection(QCAlgorithm): def __init__(self, algorithm): self.algorithm = algorithm self.securities = [] def SelectCoarse(self, coarse): # sortedByDollarVolume = sorted(coarse, key=lambda c: c.DollarVolume, reverse=True) coarseSelection = [x for x in coarse if x.HasFundamentalData and x.DollarVolume > 5000000] universe = [x.Symbol for x in coarseSelection] #self.algorithm.Securities = universe #self.Log(universe) return universe #def OnData(self, data): #if self._changes is None: return #for security in self._changes.RemovedSecurities: #if security.Invested: #self.securities.remove(security.Symbol) #for security in self._changes.AddedSecurities: #pass #self._changed = None def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: self.securities.append(added) for removed in changes.RemovedSecurities: if removed in self.securities: self.securities.remove(removed) #self.Log(f"OnSecuritiesChanged({self.UtcTime}):: {changes}")
pass class DonchianChannelAlpha(AlphaModel): def __init__(self, upperBand = 55, lowerBand = 55, resolution = Resolution.Daily): self.upperBand = upperBand self.lowerBand = lowerBand self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), upperBand) self.symbolDataBySymbol = {} self.closeWindow = None resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, upperBand, lowerBand, resolutionString) def Update(self, algorithm, data): insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): #this is all wrong, you fugged up monkey, its backwars XDDDDD previousClose = symbolData.closeWindow[1] if previousClose > symbolData.donchian.UpperBand.Current.Value: insights.append(Insight.Price(symbolData.Symbol, self, predictionInterval, InsightDirection.Up)) elif previousClose < symbolData.donchian.LowerBand.Current.Value: insights.append(Insight.Price(symbolData.Symbol, self, predictionInterval, InsightDirection.Down)) return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: symbolData = self.symbolDataBySymbol.get(added.Symbol) if symbolData is None: self.donchian = algorithm.DCH(added.Symbol, self.upperBand, self.lowerBand, self.resolution) self.donchianWindow = RollingWindow[IndicatorDataPoint](2) self.closeWindow = RollingWindow[float](2) self.consolidator = TradeBarConsolidator(2) self.consolidator.DataConsolidated += self.CloseUpdated algorithm.SubscriptionManager.AddConsolidator(Symbol, self.consolidator) symbolData = SymbolData(added) self.symbolDataBySymbol[added.Symbol] = symbolData else: symbolData.donchian.Reset() symbolData.Close.Reset() def DonchianUpdated(self, sender, updated): if self.donchian.IsReady: self.donchianWindow.Add(updated) def CloseUpdated(self, sender, bar): self.closeWindow.Add(bar.Close) @property def IsReady(self): return self.donchian.IsReady and self.closeWindowIsReady class SymbolData: def __init__(self, security): self.Security = security self.Symbol = security.Symbol self.algorithm = algorithm self.donchian = algorithm.DCH(symbol,) self.donchianWindow = None self.closeWindow = None self.consolidator = None
class MaximumSectorExposureRiskManagementModel(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that that limits the sector exposure to the specified percentage''' def __init__(self, maximumSectorExposure = 0.20): '''Initializes a new instance of the MaximumSectorExposureRiskManagementModel class Args: maximumDrawdownPercent: The maximum exposure for any sector, defaults to 20% sector exposure.''' if maximumSectorExposure <= 0: raise ValueError('MaximumSectorExposureRiskManagementModel: the maximum sector exposure cannot be a non-positive value.') self.maximumSectorExposure = maximumSectorExposure self.targetsCollection = PortfolioTargetCollection() def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance''' maximumSectorExposureValue = float(algorithm.Portfolio.TotalPortfolioValue) * self.maximumSectorExposure self.targetsCollection.AddRange(targets) risk_targets = list() # Group the securities by their sector filtered = list(filter(lambda x: x.Value.Fundamentals is not None and x.Value.Fundamentals.HasFundamentalData, algorithm.UniverseManager.ActiveSecurities)) filtered.sort(key = lambda x: x.Value.Fundamentals.CompanyReference.IndustryTemplateCode) groupBySector = groupby(filtered, lambda x: x.Value.Fundamentals.CompanyReference.IndustryTemplateCode) for code, securities in groupBySector: # Compute the sector absolute holdings value # If the construction model has created a target, we consider that # value to calculate the security absolute holding value quantities = {} sectorAbsoluteHoldingsValue = 0 for security in securities: symbol = security.Value.Symbol quantities[symbol] = security.Value.Holdings.Quantity absoluteHoldingsValue = security.Value.Holdings.AbsoluteHoldingsValue if self.targetsCollection.ContainsKey(symbol): quantities[symbol] = self.targetsCollection[symbol].Quantity absoluteHoldingsValue = (security.Value.Price * abs(quantities[symbol]) * security.Value.SymbolProperties.ContractMultiplier * security.Value.QuoteCurrency.ConversionRate) sectorAbsoluteHoldingsValue += absoluteHoldingsValue # If the ratio between the sector absolute holdings value and the maximum sector exposure value # exceeds the unity, it means we need to reduce each security of that sector by that ratio # Otherwise, it means that the sector exposure is below the maximum and there is nothing to do. ratio = float(sectorAbsoluteHoldingsValue) / maximumSectorExposureValue if ratio > 1: for symbol, quantity in quantities.items(): if quantity != 0: risk_targets.append(PortfolioTarget(symbol, float(quantity) / ratio)) return risk_targets 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''' anyFundamentalData = any([ kvp.Value.Fundamentals is not None and kvp.Value.Fundamentals.HasFundamentalData for kvp in algorithm.ActiveSecurities ]) if not anyFundamentalData: raise Exception("MaximumSectorExposureRiskManagementModel.OnSecuritiesChanged: Please select a portfolio selection model that selects securities with fundamental data.")
from Execution.ImmediateExecutionModel import ImmediateExecutionModel from universe import LiquidUniverseSelection from Alpha6 import Donchian6 from Risk.CompositeRiskManagementModel import CompositeRiskManagementModel from RiskMaximumDrawdown import DrawdownStops from RiskSectorExposure import MaximumSectorExposureRiskManagementModel from RiskTrailingStop import TrailingStopRiskManagementModel class UpgradedFluorescentYellowBat(QCAlgorithm): def Initialize(self): self.SetStartDate(2010, 12, 12) self.SetEndDate(2021, 1, 1) self.SetCash(100000) #self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage, AccountType.Margin) #self.SetWarmup(60) self.SetBenchmark("SPY") self.UniverseSettings.Resolution = Resolution.Daily self.CustomUniverseSelectionModel = LiquidUniverseSelection(self) self.AddUniverse(self.CustomUniverseSelectionModel.SelectCoarse) self.SetPortfolioConstruction(EqualWeightingPortfolioConstructionModel()) self.SetExecution(ImmediateExecutionModel()) self.SetAlpha(Donchian6()) self.SetRiskManagement(TrailingStopRiskManagementModel())
class Donchian5(AlphaModel): def __init__(self, period = 55, resolution = Resolution.Daily): self.period = period self.resolution = resolution self.predictionInterval = Time.Multiply(Extensions.ToTimeSpan(resolution), period) self.symbolDataBySymbol = {} #self.donchianWindow = {} #self._donchian = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{})'.format(self.__class__.__name__, period, resolutionString) def Update(self, algorithm, data): insights = [] return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: symbolData = self.symbolDataBySymbol.get(added.Symbol) if symbolData is None: #history = algorithm.History(added.Symbol, self.period, self.resolution) self.window = RollingWindow[TradeBar](2) symbolData = SymbolData(added) symbolData.donchian = algorithm.DCH(added.Symbol, self.period, self.period, self.resolution) self.donchianWindow = RollingWindow[IndicatorDataPoint](2) symbolData.donchian.Updated += self.DonchianUpdated symbolData._donchian["UpperBand"] = RollingWindow[float](2) symbolData._donchian["LowerBand"] = RollingWindow[float](2) self.symbolDataBySymbol[added.Symbol] = symbolData else: symbolData.donchian.Reset() self.donchianWindow.Reset() symbolData._donchian["UpperBand"].Reset() symbolData._donchian["UpperBand"].Reset() def DonchianUpdated(self, sender, updated): self.donchianWindow.Add(updated) symbolData._donchian["UpperBand"].Add(symbolData.donchian.UpperBand.Current.Value) symbolData._donchian["LowerBand"].Add(symbolData.donchian.LowerBand.Current.Value) class SymbolData: def __init__ (self, security): self.Security = security self.Symbol = security.Symbol self.donchian = None self._donchian = {}
class TrailingStopRiskManagementModel(RiskManagementModel): '''Provides an implementation of IRiskManagementModel that limits the maximum possible loss measured from the highest unrealized profit''' def __init__(self, maximumDrawdownPercent = 0.05): '''Initializes a new instance of the TrailingStopRiskManagementModel class Args: maximumDrawdownPercent: The maximum percentage drawdown allowed for algorithm portfolio compared with the highest unrealized profit, defaults to 5% drawdown''' self.maximumDrawdownPercent = -abs(maximumDrawdownPercent) self.trailingClose = dict() def ManageRisk(self, algorithm, targets): '''Manages the algorithm's risk at each time step Args: algorithm: The algorithm instance targets: The current portfolio targets to be assessed for risk''' riskAdjustedTargets = list() for kvp in algorithm.Securities: symbol = kvp.Key security = kvp.Value # Remove if not invested if not security.Invested: self.trailingClose.pop(symbol, None) continue # Add newly invested securities if symbol not in self.trailingClose: self.trailingClose[symbol] = security.Holdings.AveragePrice # Set to average holding cost continue # Check for new highs and update - set to tradebar high if self.trailingClose[symbol] < security.Close: self.trailingClose[symbol] = security.Close continue # Check for securities past the drawdown limit securityClose = self.trailingClose[symbol] drawdown = (security.Close / securityClose) - 1 if drawdown < self.maximumDrawdownPercent: # liquidate riskAdjustedTargets.append(PortfolioTarget(symbol, 0)) return riskAdjustedTargets # Your New Python File
class Donchian6(AlphaModel): def __init__(self, lowerBand = 55, upperBand = 55, resolution = Resolution.Daily): self.lowerBand = lowerBand self.upperBand = upperBand self.resolution = resolution self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(resolution), upperBand) self.symbolData = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{},{})'.format(self.__class__.__name__, lowerBand, upperBand, resolutionString) def Update(self, algorithm, data): insights = [] for key, sd in self.symbolData.items(): if sd.donchian.IsReady and sd.donchianWindow.IsReady and sd._donchian["UpperBand"].IsReady and sd._donchian["LowerBand"].IsReady: if sd._donchian["UpperBand"][1] < sd.Security.Close: insights.append(Insight.Price(sd.Security.Symbol, self.insightPeriod, InsightDirection.Up)) if sd._donchian["LowerBand"][1] > sd.Security.Close: insights.append(Insight.Price(sd.Security.Symbol, self.insightPeriod, InsightDirection.Down)) return insights def OnSecuritiesChanged(self, algorithm, changes): for added in changes.AddedSecurities: self.symbolData[added.Symbol] = SymbolData(algorithm, added, self.upperBand, self.lowerBand, self.resolution) for removed in changes.RemovedSecurities: data = self.symbolData.pop(removed.Symbol, None) if data is not None: algorithm.SubscriptionManager.RemoveConsolidator(removed.Symbol, data.Consolidator) class SymbolData: def __init__(self, algorithm, security, lowerBand, upperBand, resolution): self.Security = security self.donchian = DonchianChannel(upperBand, lowerBand) self._donchian = {} self.Consolidator = algorithm.ResolveConsolidator(security.Symbol, resolution) algorithm.RegisterIndicator(security.Symbol, self.donchian, self.Consolidator) self.donchian.Updated += self.DonchianUpdated self.donchianWindow = RollingWindow[IndicatorDataPoint](2) self._donchian["UpperBand"] = RollingWindow[float](2) self._donchian["LowerBand"] = RollingWindow[float](2) self.ema = algorithm.EMA(security.Symbol, 100) def DonchianUpdated(self, sender, updated): self.donchianWindow.Add(updated) self._donchian["UpperBand"].Add(self.donchian.UpperBand.Current.Value) self._donchian["LowerBand"].Add(self.donchian.LowerBand.Current.Value)
class Donchian4(AlphaModel): def __init__(self, period = 55, resolution = Resolution.Daily): self.period = period self.resolution = resolution self.insightPeriod = Time.Multiply(Extensions.ToTimeSpan(resolution), period) self.symbolDataBySymbol = {} self.closeWindow = {} self.lowWindow = {} self.highWindow = {} resolutionString = Extensions.GetEnumString(resolution, Resolution) self.Name = '{}({},{})'.format(self.__class__.__name__, period, resolutionString) def Update(self, algorithm, data): insights = [] for symbol, symbolData in self.symbolDataBySymbol.items(): if data.ContainsKey(symbol) and data[symbol] is not None: self.closeWindow[symbol].Add(data[symbol].Close) donchian = symbolData.Donchian #if donchian.IsReady: #pass #return insights def OnSecuritiesChanged(self, algorithm, changes): symbols = [x.Symbol for x in changes.RemovedSecurities] if len(symbols) > 0: for subscription in algorithm.SubscriptionManager.Subscriptions: if subscription.Symbol in symbols: self.symbolDataBySymbol.pop(subscription.Symbol, None) subscription.Consolidators.Clear() #init data for added securities addedSymbols = [x.Symbol for x in changes.AddedSecurities if x.Symbol not in self.symbolDataBySymbol] if len(addedSymbols) == 0: return history = algorithm.History(addedSymbols, self.period, self.resolution) for symbol in addedSymbols: donchian = algorithm.DCH(symbol, self.period, self.period, self.resolution) self.closeWindow[symbol] = RollingWindow[float](2) if not history.empty: ticker = SymbolCache.GetTicker(symbol) if ticker not in history.index.levels[0]: Log.Trace(f'Donchian4.OnSecuritiesChanged: {ticker} not found in history data frame.') continue for tuple in history.loc[ticker].itertuples(): tradeBar = TradeBar(bar.Index[1], bar.Index[0], bar.open, bar.high, bar.low, bar.close, bar.volume, timedelta(1)) donchian.Update(tradeBar) self.symbolDataBySymbol[symbol] = SymbolData(symbol, donchian) class SymbolData: def __init__(self, symbol, donchian): self.Symbol = symbol self.Donchian = donchian