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