Overall Statistics |
Total Trades 14 Average Win 2.52% Average Loss -2.50% Compounding Annual Return 0.997% Drawdown 13.800% Expectancy 0.148 Net Profit 2.341% Sharpe Ratio 0.135 Loss Rate 43% Win Rate 57% Profit-Loss Ratio 1.01 Alpha 0.026 Beta -0.938 Annual Standard Deviation 0.084 Annual Variance 0.007 Information Ratio -0.052 Tracking Error 0.084 Treynor Ratio -0.012 Total Fees $25.90 |
class Nothing(QCAlgorithm): parent = None def Initialize(self): parent = self self.SetStartDate(2017, 1, 1) # Set Start Date self.SetCash(10000) # Set Strategy Cash symbols = [] symbols.append(Futures.Metals.Gold) # symbols.append(Futures.Metals.Silver) # symbols.append(Futures.Metals.Palladium) # symbols.append(Futures.Metals.Platinum) # symbols.append(Futures.Energies.CrudeOilWTI) # symbols.append(Futures.Energies.Gasoline) # symbols.append(Futures.Energies.HeatingOil) # symbols.append(Futures.Energies.NaturalGas) # symbols.append(Futures.Financials.Y30TreasuryBond) # symbols.append(Futures.Financials.Y10TreasuryNote) # symbols.append(Futures.Financials.Y5TreasuryNote) # symbols.append(Futures.Financials.Y2TreasuryNote) # symbols.append(Futures.Grains.Corn) # symbols.append(Futures.Grains.Oats) # symbols.append(Futures.Grains.SoybeanMeal) # symbols.append(Futures.Grains.SoybeanOil) # symbols.append(Futures.Grains.Soybeans) # symbols.append(Futures.Grains.Wheat) # symbols.append(Futures.Meats.FeederCattle) # symbols.append(Futures.Meats.LeanHogs) # symbols.append(Futures.Meats.LiveCattle) symbols.append(Futures.Softs.Cocoa) symbols.append(Futures.Softs.Coffee) symbols.append(Futures.Softs.Cotton2) symbols.append(Futures.Softs.OrangeJuice) symbols.append(Futures.Softs.Sugar11) # symbols.append(Futures.Indices.Dow30EMini) # symbols.append(Futures.Indices.NASDAQ100EMini) symbols.append(Futures.Indices.SP500EMini) # symbols.append(Futures.Indices.VIX) # symbols.append(Futures.Currencies.AUD) # symbols.append(Futures.Currencies.CAD) # symbols.append(Futures.Currencies.CHF) # symbols.append(Futures.Currencies.EUR) # symbols.append(Futures.Currencies.GBP) # symbols.append(Futures.Currencies.JPY) # symbols.append(Futures.Currencies.NZD) # symbols.append(Futures.Currencies.USD) # self.UniverseSettings.Resolution = Resolution.Minute # self.SetUniverseSelection(FuturesUniverseSelectionModel(self.SelectFuturesSymbols)) # self.SetUniverseSelection(FuturesUniverseSelectionModel(symbols)) # self.Debug(self.SelectFuturesSymbols) # self.SetUniverseSelection(ManualUniverseSelectionModel(self.SelectFuturesSymbols)) # ManualUniverseSelectionModel(symbols) # FuturesUniverseSelectionModel(self.SelectFuturesSymbols) # self.UniverseSettings.Resolution = Resolution.Minute # self.AddUniverse('my_universe_name', Resolution.Minute, symbols) # self.SetStartDate(2016, 1, 1) # self.SetEndDate(2016, 8, 18) # self.SetCash(100000) # fastPeriod = 20 # slowPeriod = 60 # self._tolerance = 1 + 0.001 # self.IsUpTrend = False # self.IsDownTrend = False # self.SetWarmUp(max(fastPeriod, slowPeriod)) # Adds SPY to be used in our EMA indicators # equity = self.AddEquity("SPY", Resolution.Daily) # self._fast = self.EMA(equity.Symbol, fastPeriod, Resolution.Daily) # self._slow = self.EMA(equity.Symbol, slowPeriod, Resolution.Daily) # Adds the future that will be traded and # set our expiry filter for this futures chain # future = self.AddFuture(Futures.Indices.SP500EMini) # future.SetFilter(timedelta(0), timedelta(182)) # self.Highest = {} # self.ATRs = {} # self.Symbols = {} self.Data = {} # RollingWindowSize = 52 # BarSize = TimeSpan.FromDays(1) # self.previous = {} self.consolidators = dict() self.UniverseSettings.Resolution = Resolution.Daily self.SetWarmUp(52) self.SetBrokerageModel(BrokerageName.InteractiveBrokersBrokerage) # consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1)) # self._atr = ATR(20) # self._highest = MAX(52) # self.RegisterIndicator("SPY", self._sma, consolidator) # self.SubscriptionManager.AddConsolidator("SPY", consolidator) for symbol in symbols: # self.Debug("Initializing " + symbol) future = self.AddFuture(symbol)#, Resolution.Minute) future.SetFilter(timedelta(0), timedelta(60)) # Overload 1: BuyingPowerModel( # decimal initialMarginRequirement, # decimal maintenanceMarginRequirement, # decimal requiredFreeBuyingPowerPercent) self.Securities[future.Symbol].MarginModel = BuyingPowerModel(0.1,0.1,0.2) # self.Securities[future.Symbol].SetLeverage(100) # self.Symbols[symbol] = future.Symbol # self.Data[future.Symbol] = SymbolData(future.Symbol, BarSize, RollingWindowSize) # self.Debug("Saving to self.Data as " + str(future.Symbol)) # for symbol, symbolData in self.Data.items(): # symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20) # symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52) # consolidator = QuoteBarConsolidator(BarSize) # consolidator.DataConsolidated += self.OnDataConsolidated # self.SubscriptionManager.AddConsolidator(symbolData.Symbol, consolidator) # self.ATRs[future.Symbol] = self.ATR(20, MovingAverageType.Simple) # self.Highest[future.Symbol] = self.MAX(52) # self.RegisterIndicator(future.Symbol, self.ATRs[future.Symbol], Resolution.Daily) # self.RegisterIndicator(future.Symbol, self.Highest[future.Symbol], Resolution.Daily) # self.Highest[future.Symbol] = self.MAX(future.Symbol, 52, Resolution.Daily) # self.ATRs[future.Symbol] = self.ATR(future.Symbol, 20, MovingAverageType.Simple, Resolution.Daily) # self.Plot("Highest", self.Highest[future.Symbol], SeriesType.Line) # for symbol, symbolData in self.Data.items(): # self.Debug("Initializing " + symbol) # symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20) # symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52) # consolidator = QuoteBarConsolidator(BarSize) # consolidator.DataConsolidated += self.OnDataConsolidated # self.SubscriptionManager.AddConsolidator(symbolData.FullSymbol, consolidator) def OnData(self, slice): for delisting in slice.Delistings.Keys: self.Log(f'{delisting.Value} delisting warning {slice.Delistings[delisting].ToString()}') '''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 ''' # loop through each symbol in our structure # for symbol in self.Data.keys(): # symbolData = self.Data[symbol] # # this check proves that this symbol was JUST updated prior to this OnData function being called # if symbolData.IsReady() and symbolData.WasJustUpdated(self.Time): # if not self.Portfolio[symbol].Invested: # self.MarketOrder(symbol, 1) # else: # self.Debug(str(symbol) + " already invested") # else: # # pass # self.Debug(str(symbol) + " not ready yet in " + str(slice.Time)) # self.Debug("Bars: " + str(symbolData.Bars.IsReady)) # if symbolData.ATR is not None: # self.Debug("ATR: " + str(symbolData.ATR.IsReady)) # else: # self.Debug("ATR is None") # if symbolData.Highest is not None: # self.Debug("Highest: " + str(symbolData.Highest.IsReady)) # else: # self.Debug("Highest is None") # for symbol in slice.Bars.Keys: # # self.Log("Slice key: " + str(symbol)) # # self.Log("Slice time: " + str(self.Time)) # # Let it initialize # if symbol not in self.Highest or not self.Highest[symbol].IsReady: # return # # only once per day # if self.previous[symbol] is not None and self.previous[symbol].date() == self.Time.date(): # return # if slice.Bars[symbol].Close > self.Highest[symbol] - 5*self.ATR[symbol] and not self.Portfolio[symbol].Invested: # self.MarketOrder(symbol, 1) # elif slice.Bars[symbol].Close < self.Highest[symbol] - 5*self.ATR[symbol] and self.Portfolio[symbol].Invested: # self.Liquidate(symbol) # self.previous[symbol] = self.Time # if not self.Portfolio.Invested: # self.SetHoldings("SPY", 1) # if self._slow.IsReady and self._fast.IsReady: # self.IsUpTrend = self._fast.Current.Value > self._slow.Current.Value * self._tolerance # self.IsDownTrend = self._fast.Current.Value < self._slow.Current.Value * self._tolerance # if (not self.Portfolio.Invested) and self.IsUpTrend: # for chain in slice.FuturesChains: # # find the front contract expiring no earlier than in 90 days # contracts = list(filter(lambda x: x.Expiry > self.Time + timedelta(90), chain.Value)) # # if there is any contract, trade the front contract # if len(contracts) == 0: continue # contract = sorted(contracts, key = lambda x: x.Expiry, reverse=True)[0] # self.MarketOrder(contract.Symbol , 1) # if self.Portfolio.Invested and self.IsDownTrend: # self.Liquidate() # for chain in slice.FutureChains.Values: # contracts = chain.Contracts # count = 0 # for contract in contracts: # count = count + 1 # self.Log(str(count)) # # self.Debug(contract.Symbol) # self.Log(type(slice.Bars)) # self.Log(slice.Bars) # for tradebar in slice.Bars: # self.Debug(tradebar) # for symbol in slice.Keys: # self.Log("slice.Key: " + symbol) # for symbol in slice.Bars.Keys: # self.Log("slice.Bar: " + symbol) # for chain in slice.FutureChains: # for contract in chain.Value: # self.Log("{0},Open={1} High={2} Low={3} Close={4} Volume={5}".format( # contract.Symbol.Value, # contract.Open, # contract.High, # contract.Low, # contract.Close, # contract.Volume)) # for chain in slice.Bars: # for contract in chain.Value: # self.Log("{0},Bid={1} Ask={2} Last={3} OI={4}".format( # contract.Symbol.Value, # contract.BidPrice, # contract.AskPrice, # contract.LastPrice, # contract.OpenInterest)) # for chain in slice.FutureChains: # for i in chain.Value: # askprice = i.AskPrice # openinterest = i.OpenInterest # expiry = i.Expiry # class FuturesContract: # self.Symbol # (Symbol) Symbol for contract needed to trade. # self.UnderlyingSymbol # (Symbol) Underlying futures asset. # self.Expiry # (datetime) When the future expires # self.OpenInterest # (decimal) Number of open interest. # self.LastPrice # (decimal) Last sale price. # self.Volume # (long) reported volume. # self.BidPrice # (decimal) bid quote price. # self.BidSize # (long) bid quote size. # self.AskPrice # (decimal) ask quote price. # self.AskSize # (long) ask quote size. def OnDataConsolidated(self, sender, quoteBar): # self.Log("OnDataConsolidated called on " + str(self.Time)) # self.Debug("OnDataConsolidated called on " + str(quoteBar.Symbol) + " time " + str(self.Time)) # self.Log(str(quoteBar.Close)) symbol = quoteBar.Symbol if symbol not in self.Data: self.Debug("symbol key not in self.Data") # self.Debug("-".join(self.Data.keys())) # self.Debug(self.Data[symbol].ATR) # self.Data[symbol].ATR.Update(quoteBar.Time, quoteBar.Close) self.Data[symbol].ATR.Update(quoteBar) # self.Debug(str(len(self.Data[symbol].ATR))) self.Data[symbol].Highest.Update(quoteBar.Time, quoteBar.Close) # self.Debug(self.Data[symbol]) self.Data[symbol].Bars.Add(quoteBar) symbolData = self.Data[symbol] # this check proves that this symbol was JUST updated prior to this OnData function being called if not symbolData.IsReady(): # self.Debug(str(symbol) + " not ready yet in " + str(quoteBar.Time)) return if not symbolData.WasJustUpdated(self.Time): self.Debug(str(symbol) + " wasn't updated yet " + str(quoteBar.Time)) return # else: # pass # self.Debug("Bars: " + str(symbolData.Bars.IsReady)) # if symbolData.ATR is not None: # self.Debug("ATR: " + str(symbolData.ATR.IsReady)) # else: # self.Debug("ATR is None") # if symbolData.Highest is not None: # self.Debug("Highest: " + str(symbolData.Highest.IsReady)) # else: # self.Debug("Highest is None") # # Let it initialize # if symbol not in self.Highest or not self.Highest[symbol].IsReady: # self.Debug("Not initialized yet: " + str(symbol)) # return # # only once per day # if self.previous[symbol] is not None and self.previous[symbol].date() == self.Time.date(): # self.Debug("Missing previous or already traded this day for : " + str(symbol)) # return Highest = self.Data[symbol].Highest.Current.Value ATR = self.Data[symbol].ATR.Current.Value Line = Highest - 5*ATR self.Data[symbol].Line = Line # LONG if quoteBar.Close >= Highest: # and not self.Portfolio[symbol].Invested: self.Debug("CLOSE > HIGH for " + str(symbol.Value)) # self.Debug("{0} Quantity {1}".format(self.Time, symbol)) if self.Portfolio[symbol].Quantity < 0: # self.Debug("{0} LONG {1} Quantity {1}".format(self.Time, symbol, self.Portfolio[symbol].Quantity)) # if self.Portfolio[symbol].Quantity < 0: # self.MarketOrder(symbol, 2) self.Debug("{0} CLOSE SHORT {1}, Close={2} >= {3} Invested={4}".format( self.Time, symbol.Value, quoteBar.Close, Highest, self.Portfolio[symbol].Invested )) if self.Portfolio[symbol].Quantity == 0: self.Debug("{4} OPEN LONG {0}, Close={1} >= Highest={2} Invested={3}".format( symbol.Value, quoteBar.Close, Highest, self.Portfolio[symbol].Invested, self.Time )) self.MarketOrder(symbol, 1) # SHORT elif quoteBar.Close < Line: # and self.Portfolio[symbol].Invested: self.Debug("CLOSE < Line for " + str(symbol.Value)) # self.Debug("{0} Low for {1}".format(self.Time, symbol)) # self.Debug("CLOSE {0}, Close={1} Highest={2} 5*ATR={3} Invested={4}".format( # symbol, quoteBar.Close, Highest, 5*ATR, self.Portfolio[symbol].Invested # )) if self.Portfolio[symbol].Quantity > 0: # self.Debug("{0} SHORT {1} Quantity {1}".format(self.Time, symbol, self.Portfolio[symbol].Quantity)) # self.Debug("SHORT " + str(symbol) + " quantity " + str(self.Portfolio[symbol].Quantity)) # if self.Portfolio[symbol].Quantity > 0: # self.MarketOrder(symbol, -2) self.Debug("{0} CLOSE LONG {1}, Close={2} < {3} Invested={4}".format( self.Time, symbol.Value, quoteBar.Close, Line, self.Portfolio[symbol].Invested )) if self.Portfolio[symbol].Quantity == 0: self.Debug("{5} OPEN SHORT {0}, Close={1} < {5} (Highest={2} - 5*ATR={3}) Invested={4}".format( symbol.Value, quoteBar.Close, Highest, 5*ATR, self.Portfolio[symbol].Invested, Line, self.Time )) self.MarketOrder(symbol, -1) # DO NOTHING else: # self.Debug("{5} DO NOTHING {0}, Close={1} Highest={2} Line={3} Invested={4}".format( # symbol, quoteBar.Close, Highest, Line, self.Portfolio[symbol].Invested, self.Time # )) # if self.Portfolio[symbol] is not None and self.Portfolio[symbol].Invested: # self.Debug(self.Portfolio[symbol].IsLong) # self.Debug(self.Portfolio[symbol].IsShort) pass # self.Plot("My shit", str(symbol), Line) # self.previous[symbol] = self.Time # def OnSecuritiesChanged(self, changes): # for security in changes.AddedSecurities: # # self.Log("Security changed or added: ", security) # # self.Log(security.Symbol) # # if security.Symbol == "SPY": # # continue # consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1)) # consolidator.DataConsolidated += self.OnDataConsolidated # self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator) # self.consolidators[security.Symbol] = consolidator # for security in changes.RemovedSecurities: # # if security.Symbol == "SPY": # # continue # consolidator = self.consolidators.pop(security.Symbol) # self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator) # consolidator.DataConsolidated -= self.OnDataConsolidated def OnSecuritiesChanged(self, changes): for security in changes.AddedSecurities: # self.Debug("Adding security: " + str(security.Symbol)) # self.Debug("OnSecuritiesChanged2: " + str(security.Symbol.Value)) self.Data[security.Symbol] = SymbolData(security.Symbol, TimeSpan.FromDays(1), 52) self.Data[security.Symbol].ATR = AverageTrueRange(self.CreateIndicatorName(security.Symbol, "ATR" + str(20), Resolution.Daily), 20) self.Data[security.Symbol].Highest = Maximum(self.CreateIndicatorName(security.Symbol, "MAX" + str(52), Resolution.Daily), 52) consolidator = QuoteBarConsolidator(TimeSpan.FromDays(1)) consolidator.DataConsolidated += self.OnDataConsolidated self.SubscriptionManager.AddConsolidator(security.Symbol, consolidator) self.consolidators[security.Symbol] = consolidator # symbolData = self.Data[security.Symbol] # symbolData.ATR = AverageTrueRange(self.CreateIndicatorName(symbol, "ATR" + str(20), Resolution.Daily), 20) # symbolData.Highest = Maximum(self.CreateIndicatorName(symbol, "MAX" + str(52), Resolution.Daily), 52) # self.Log("Security changed or added: ", security) # self.Log(security.Symbol) # if security.Symbol == "SPY": # continue for security in changes.RemovedSecurities: # if security.Symbol == "SPY": # continue consolidator = self.consolidators.pop(security.Symbol) self.SubscriptionManager.RemoveConsolidator(security.Symbol, consolidator) consolidator.DataConsolidated -= self.OnDataConsolidated # def OnEndOfDay(self): # if self.IsUpTrend: # self.Plot("Indicator Signal", "EOD",1) # elif self.IsDownTrend: # self.Plot("Indicator Signal", "EOD",-1) # elif self._slow.IsReady and self._fast.IsReady: # self.Plot("Indicator Signal", "EOD",0) def OnOrderEvent(self, orderEvent): self.Log(str(orderEvent)) def OnEndOfDay(self): # i = 0 for symbol in sorted(self.Data.keys()): symbolData = self.Data[symbol] # we have too many symbols to plot them all, so plot every other # i += 1 if symbolData.IsReady() and self.Portfolio[symbol].Invested: # and i%2 == 0: self.Plot("My shit", str(symbol), self.Portfolio[symbol].Quantity) else: self.Plot("My shit", str(symbol), 0) class SymbolData(object): def __init__(self, symbol, barPeriod, windowSize): self.Symbol = symbol # self.FullSymbol = fullsymbol # The period used when population the Bars rolling window self.BarPeriod = barPeriod # A rolling window of data, data needs to be pumped into Bars by using Bars.Update( tradeBar ) and can be accessed like: # mySymbolData.Bars[0] - most first recent piece of data # mySymbolData.Bars[5] - the sixth most recent piece of data (zero based indexing) self.Bars = RollingWindow[IBaseDataBar](windowSize) # The simple moving average indicator for our symbol self.ATR = None self.Highest = None self.Line = None # Returns true if all the data in this instance is ready (indicators, rolling windows, ect...) def IsReady(self): # if not self.Bars.IsReady: # parent.Debug("Bars not ready") # if not self.ATR.IsReady: # parent.Debug("ATR not ready") # if not self.Highest.IsReady: # parent.Debug("Highest not ready") return self.Bars.IsReady and self.ATR.IsReady and self.Highest.IsReady # Returns true if the most recent trade bar time matches the current time minus the bar's period, this # indicates that update was just called on this instance def WasJustUpdated(self, current): return self.Bars.Count > 0 and self.Bars[0].Time == current - self.BarPeriod