Overall Statistics
Total Trades
396
Average Win
25.18%
Average Loss
-8.71%
Compounding Annual Return
-51.829%
Drawdown
60.200%
Expectancy
0.749
Net Profit
-51.800%
Sharpe Ratio
-0.749
Loss Rate
55%
Win Rate
45%
Profit-Loss Ratio
2.89
Alpha
-1.131
Beta
44.784
Annual Standard Deviation
0.562
Annual Variance
0.316
Information Ratio
-0.777
Tracking Error
0.562
Treynor Ratio
-0.009
Total Fees
$732.60
from datetime import timedelta
import decimal
class BasicTemplateFuturesAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2018, 6, 15)
        self.SetEndDate(2019, 6, 15)
        self.SetCash(25000)
        slowperiod = 1720
        self.SetWarmUp(slowperiod)
        
        futureES = self.AddFuture(Futures.Indices.SP500EMini)
        futureES.SetFilter(timedelta(0), timedelta(182))
        futureNQ = self.AddFuture(Futures.Indices.NASDAQ100EMini)
        futureNQ.SetFilter(timedelta(0), timedelta(182))
        self.frontES = None
        self.frontNQ = None
        
        #Add the spread plot and mark the long/short spread point
        spreadPlot = Chart("Spread Plot")
        spreadPlot.AddSeries(Series("currentspread", SeriesType.Line, 0))
        spreadPlot.AddSeries(Series("Long Spread Trade", SeriesType.Scatter, 0))
        spreadPlot.AddSeries(Series("Short Spread Trade", SeriesType.Scatter, 0))
        spreadPlot.AddSeries(Series("ESNQ SMA", SeriesType.Line, 0))
        self.AddChart(spreadPlot)
        
    def OnData(self,slice):
        if (self.frontES is not None) and (self.Time > self.frontES.Expiry):
            self.frontES = None
        if (self.frontNQ is not None) and (self.Time > self.frontNQ.Expiry):
            self.frontNQ = None
            
        for chain in slice.FutureChains:
            contracts = list(filter(lambda x: x.Expiry > self.Time + timedelta(45), chain.Value))
            for contract in contracts:
                if ('ES ' in str(contract.Symbol)) and (self.frontES is None):
                    self.frontES = sorted(contracts, key=lambda x: x.OpenInterest, reverse=False)[0] #True is lowest to highest
                    self.Consolidate(contract.Symbol, timedelta(minutes=240), self.twoforty)
                    self.essma = self.SMA(self.frontES.Symbol, 400, Resolution.Minute)
                ## Same as above but for NASDAQ -- Also, be sure to wrap the Symbol object in str() when comparing it to a character string or else
                ## the comparison will fail since they won't be of the same type
                if ('NQ ' in str(contract.Symbol)) and (self.frontNQ is None):
                    self.frontNQ = sorted(contracts, key=lambda x: x.OpenInterest, reverse=False)[0]#True is lowest to highest
                    self.nqsma = self.SMA(self.frontNQ.Symbol, 400, Resolution.Minute)
                    self.esnqsma = IndicatorExtensions.Minus(self.nqsma, self.essma)
    def OnOrderEvent(self, orderEvent):
        #self.Log(str(orderEvent))
        pass
    def twoforty(self, consolidated):
        ''' This is our event handler for our 45 minute consolidated defined using the Consolidate method'''
        self.consolidated45Minute = True
        #self.Log(f"{consolidated.EndTime} >> twoforty >> {consolidated.Close}")
        currentspread = (self.Securities[self.frontNQ.Symbol].Price - self.Securities[self.frontES.Symbol].Price)
        tolerance = decimal.Decimal(18.25)
        ## Check to make sure both self.frontES and self.frontNQ are contracts that can be traded
        
        if (self.frontES is not None) and (self.frontNQ is not None):
            if not self.Portfolio.Invested and currentspread <= (self.esnqsma.Current.Value - tolerance):
                self.MarketOrder(self.frontES.Symbol , -1)
                self.MarketOrder(self.frontNQ.Symbol , 1)
                self.Plot("Spread Plot", "Long Spread Trade", currentspread)
                #self.Log("We are Long, Total Margin Used is: " + str(self.Portfolio.TotalAbsoluteHoldingsCost))
                #self.Log("currentspread is less than esnq tolerance: " + str(currentspread) + " < " + str(self.esnqsma.Current.Value - tolerance))
                #self.Log("What contracts are available??" + str(self.frontES) + " and " + str(self.frontNQ))    
                self.Notify.Sms("+test", "LONG, Paper Forex");
            if not self.Portfolio.Invested and currentspread >= (self.esnqsma.Current.Value + tolerance):
                self.MarketOrder(self.frontES.Symbol , 1)
                self.MarketOrder(self.frontNQ.Symbol , -1)
                self.Notify.Sms("+test", "Liquidate, Paper Forex");
                self.Plot("Spread Plot", "Short Spread Trade", currentspread)
                #self.Log("We are Short, Total Margin Used is: " + str(self.Portfolio.TotalAbsoluteHoldingsCost))
                #self.Log("currentspread is greater than esnq tolerance: " + str(currentspread) + " > " + str(self.esnqsma.Current.Value + tolerance))
                #self.Log("Did we purchase any contracts??" + str(self.frontES.Symbol) + " and " + str(self.frontNQ.Symbol))
            if self.Portfolio.Invested:
                if (self.esnqsma.Current.Value + 2.00) >= currentspread >= (self.esnqsma.Current.Value - 2.00):
                    self.Liquidate()
            self.Plot("Spread Plot", "ESNQ SMA", self.esnqsma.Current.Value)
            self.Plot("Spread Plot", "currentspread", currentspread)
        
    def OnEndOfDay(self):
        #self.Log("Settled Cash is: " + str(self.Portfolio.Cash))
        #self.Log("Total Margin Used is: " + str(self.Portfolio.TotalAbsoluteHoldingsCost))
        #self.Log("Total Units held is: " + str(self.Portfolio.TotalHoldingsValue))
        morning = "05:00:00.000000"
        afternoon = "11:30:00.000000"
        time = str(self.Time)
        #if not morning < time < afternoon:
        #    self.Log(str((datetime.now().time())))
        pass