Overall Statistics
Total Trades
2
Average Win
3.74%
Average Loss
0%
Compounding Annual Return
3.741%
Drawdown
3.500%
Expectancy
0
Net Profit
3.738%
Sharpe Ratio
0.747
Probabilistic Sharpe Ratio
37.912%
Loss Rate
0%
Win Rate
100%
Profit-Loss Ratio
0
Alpha
0.004
Beta
0.111
Annual Standard Deviation
0.035
Annual Variance
0.001
Information Ratio
-1.685
Tracking Error
0.102
Treynor Ratio
0.238
Total Fees
$8.60
Estimated Strategy Capacity
$49000000.00
Lowest Capacity Asset
ES XPFJZVPGHL35
Portfolio Turnover
0.41%
# region imports
from AlgorithmImports import *
# endregion


class EnergeticAsparagusCormorant(QCAlgorithm):


    def Initialize(self):
        self.SetStartDate(2021, 1, 1)  # Set Start Date
        self.SetEndDate(2022, 1, 1) # Set End Date
        self.SetCash(500000)  # Set Strategy Cash

        self.future = self.AddFuture(Futures.Indices.SP500EMini, extendedMarketHours= True)
        self.future.SetFilter(0, 182)
        #self.future.SetFilter(lambda future_filter_universe: future_filter_universe.FrontMonth())
        self.symbol = self.future.Symbol


        self.Vix = self.AddFuture(Futures.Indices.VIX, extendedMarketHours= True)
        self.Vix.SetFilter(0, 182)
        #self.Vix.SetFilter(lambda future_filter_universe: future_filter_universe.FrontMonth())
        self.Vixsymbol = self.Vix.Symbol

        # ES vars
        self.Longentry_ticket = None
        self.Shortentry_ticket = None
        self.ESstopTicket = None
        self.ESprofitTicket = None
        self.LongcontractSymbol = None
        self.ShortcontractSymbol = None
        self.Esprice = None
        self.ShortEsprice = None

        # VIX vars
        self.Vixentry_ticket = None
        self.ShortVixentry_ticket = None
        self.VixstopTicket = None
        self.VixprofitTicket = None
        self.VixcontractSymbol = None
        self.ShortVixcontractSymbol = None
        self.VixPrice = None
        self.ShortVixPrice = None


        self.sma = SimpleMovingAverage(200)
        self.RegisterIndicator(self.symbol, self.sma, Resolution.Daily)

    def OnData(self, data: Slice):



        if (self.Longentry_ticket is None and self.Vixentry_ticket is None) and (self.Shortentry_ticket == None and self.ShortVixentry_ticket == None):
            if self.Securities[self.symbol].Price > self.sma.Current.Value:
                self.BuyFuture(data)


            elif self.Securities[self.symbol].Price < self.sma.Current.Value:
                self.ShortFuture(data)


        if self.Portfolio.Invested:

            # avoids error
            if self.LongcontractSymbol == None or self.VixcontractSymbol == None or self.ShortVixcontractSymbol == None or self.ShortcontractSymbol == None:
                return

            # will sell before an expiration or delisting:
            if self.Portfolio[self.LongcontractSymbol.Symbol].IsLong:
                if self.Time + timedelta(1) > self.LongcontractSymbol.Expiry:
                    self.Liquidate(self.LongcontractSymbol.Symbol, "Future too close to expiration.")
                    self.Longentry_ticket = None
                   
            if self.Portfolio[self.VixcontractSymbol.Symbol].IsLong:
                if self.Time + timedelta(1) > self.VixcontractSymbol.Expiry:
                    self.Liquidate(self.VixcontractSymbol.Symbol, "Future too close to expiration.")
                    self.Vixentry_ticket = None
              
            if self.Portfolio[self.ShortVixcontractSymbol.Symbol].IsShort:
                if self.Time + timedelta(1) > self.ShortVixcontractSymbol.Expiry:
                    self.Liquidate(self.ShortVixcontractSymbol.Symbol, "Future too close to expiration.")
                    self.ShortVixentry_ticket = None
                   

            if self.Portfolio[self.ShortcontractSymbol.Symbol].IsShort:
                if self.Time + timedelta(1) > self.ShortcontractSymbol.Expiry:
                    self.Liquidate(self.ShortcontractSymbol.Symbol, "Future too close to expiration.")
                    self.Shortentry_ticket = None
            
    def BuyFuture(self, data: Slice):

        # get the ES chain
        chain = data.FuturesChains.get(self.symbol)
        if chain:
           
            self.LongcontractSymbol = sorted(chain, key=lambda contract: contract.Expiry, reverse=True)[0]

            # save price and enter with limit order
            self.Esprice = self.Securities[self.LongcontractSymbol.Symbol].Price
            self.Longentry_ticket = self.LimitOrder(self.LongcontractSymbol.Symbol, 2, self.Esprice)

            # send out bracket order
            self.ESprofitTicket = self.LimitOrder(self.LongcontractSymbol.Symbol, -2, self.Esprice*1.05)
            self.ESstopTicket = self.StopMarketOrder(self.LongcontractSymbol.Symbol, -2, self.Esprice*0.95)
 
        # get the Vix chain
        Vixchain = data.FuturesChains.get(self.Vixsymbol)
        if Vixchain:
           
            self.VixcontractSymbol = sorted(Vixchain, key=lambda Vixcontract: Vixcontract.Expiry, reverse=True)[0]
   
            # save price and enter with limit order
            self.VixPrice = self.Securities[self.VixcontractSymbol.Symbol].Price
            self.Vixentry_ticket = self.LimitOrder(self.VixcontractSymbol.Symbol, 4, self.VixPrice)

            # send out bracket order
            self.VixprofitTicket = self.LimitOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*1.05)
            self.VixstopTicket = self.StopMarketOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*0.95)
       
        else:
            self.Log("failed to get Vix chain")

        return


    def BuyVix(self, data: Slice):

        # get the Vix chain
        Vixchain = data.FuturesChains.get(self.Vixsymbol)
        if Vixchain:
           
            self.VixcontractSymbol = sorted(Vixchain, key=lambda Vixcontract: Vixcontract.Expiry, reverse=True)[0]
   
            # save price and enter with limit order
            self.VixPrice = self.Securities[self.VixcontractSymbol.Symbol].Price
            self.Vixentry_ticket = self.LimitOrder(self.VixcontractSymbol.Symbol, 4, self.VixPrice)

            # send out bracket order
            self.VixprofitTicket = self.LimitOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*1.05)
            self.VixstopTicket = self.StopMarketOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*0.95)

        else:
            self.Log("failed to get Vix chain")


        return
   
    def ShortFuture(self, data: Slice):


        chain = data.FuturesChains.get(self.symbol)
        if chain:
           
            self.ShortcontractSymbol = sorted(chain, key=lambda contract: contract.Expiry, reverse=True)[0]
 
            # save price and enter with limit order
            self.Esprice = self.Securities[self.ShortcontractSymbol.Symbol].Price
            self.Shortentry_ticket = self.LimitOrder(self.ShortcontractSymbol.Symbol, -2, self.Esprice)

            # send out bracket order
            self.ESprofitTicket = self.LimitOrder(self.ShortcontractSymbol.Symbol, 2, self.Esprice*0.95)
            self.ESstopTicket = self.StopMarketOrder(self.ShortcontractSymbol.Symbol, 2, self.Esprice*1.05)
 
        Vixchain = data.FuturesChains.get(self.Vixsymbol)
        if Vixchain:
           
            self.ShortVixcontractSymbol = sorted(chain, key=lambda Vixcontract: Vixcontract.Expiry, reverse=True)[0]
   
            # save price and enter with limit order
            self.VixPrice = self.Securities[self.ShortVixcontractSymbol.Symbol].Price
            self.ShortVixentry_ticket = self.LimitOrder(self.ShortVixcontractSymbol.Symbol, -4, self.VixPrice)

            # send out bracket order
            self.VixprofitTicket = self.LimitOrder(self.ShortVixcontractSymbol.Symbol, 4, self.VixPrice*0.95)
            self.VixstopTicket = self.StopMarketOrder(self.ShortVixcontractSymbol.Symbol, 4, self.VixPrice*1.05)

        else:
            self.Log("failed to get Vix chain")

        return


    def ShortVix(self, data: Slice):


        Vixchain = data.FuturesChains.get(self.Vixsymbol)
        if Vixchain:
           
            self.ShortVixcontractSymbol = sorted(chain, key=lambda Vixcontract: Vixcontract.Expiry, reverse=True)[0]
   
            # save price and enter with limit order
            self.VixPrice = self.Securities[self.ShortVixcontractSymbol.Symbol].Price
            self.ShortVixentry_ticket = self.LimitOrder(self.ShortVixcontractSymbol.Symbol, -4, self.VixPrice)

            # send out bracket order
            self.VixprofitTicket = self.LimitOrder(self.ShortVixcontractSymbol.Symbol, 4, self.VixPrice*0.95)
            self.VixstopTicket = self.StopMarketOrder(self.ShortVixcontractSymbol.Symbol, 4, self.VixPrice*1.05)
 
        else:
            self.Log("failed to get Vix chain")

        return

    def OnOrderEvent(self, orderEvent):
 
        #self.Log(str(orderEvent))


        # Invalid order is blocking new orders
        if orderEvent.Status == OrderStatus.Invalid:
            self.Longentry_ticket = None
            self.Vixentry_ticket = None
            self.Shortentry_ticket = None
            self.ShortVixentry_ticket = None
            return

        if orderEvent.Status != OrderStatus.Filled:
            return


        # avoids error
        if self.LongcontractSymbol is None or self.ShortcontractSymbol is None:
            return


        #if orderEvent.OrderId == self.Longentry_ticket.OrderId:
            #return
           
        # cancel the other ES order after one gets hit
        if orderEvent.Symbol == self.LongcontractSymbol.Symbol:
            if orderEvent.OrderId == self.ESprofitTicket.OrderId or orderEvent.OrderId == self.ESstopTicket.OrderId:
                self.Transactions.CancelOpenOrders(self.LongcontractSymbol.Symbol)
                self.Longentry_ticket = None
                return

        elif orderEvent.Symbol == self.ShortcontractSymbol.Symbol:
            if orderEvent.OrderId == self.ESprofitTicket.OrderId or orderEvent.OrderId == self.ESstopTicket.OrderId:
                self.Transactions.CancelOpenOrders(self.ShortcontractSymbol.Symbol)
                self.Shortentry_ticket = None
                return

        # avoids error
        if self.VixcontractSymbol is None or self.ShortVixcontractSymbol is None:
            return


        #if orderEvent.OrderId == self.Vixentry_ticket.OrderId:
            #return
           
        # cancel the other Vix order after one gets hit
        if orderEvent.Symbol == self.VixcontractSymbol.Symbol:
            if orderEvent.OrderId == self.VixstopTicket.OrderId or orderEvent.OrderId == self.VixprofitTicket.OrderId:
                self.Transactions.CancelOpenOrders(self.VixcontractSymbol.Symbol)
                self.Vixentry_ticket = None
                return


        elif orderEvent.Symbol == self.ShortVixcontractSymbol.Symbol:
            if orderEvent.OrderId == self.VixstopTicket.OrderId or orderEvent.OrderId == self.VixprofitTicket.OrderId:
                self.Transactions.CancelOpenOrders(self.ShortVixcontractSymbol.Symbol)
                self.ShortVixentry_ticket = None
                return