| Overall Statistics |
|
Total Trades 28 Average Win 2.64% Average Loss -2.01% Compounding Annual Return 21.623% Drawdown 4.500% Expectancy 0.780 Net Profit 21.604% Sharpe Ratio 1.844 Probabilistic Sharpe Ratio 79.947% Loss Rate 23% Win Rate 77% Profit-Loss Ratio 1.31 Alpha 0.023 Beta 0.632 Annual Standard Deviation 0.081 Annual Variance 0.007 Information Ratio -0.845 Tracking Error 0.058 Treynor Ratio 0.235 Total Fees $192.94 Estimated Strategy Capacity $61000000.00 Lowest Capacity Asset ES XZDYPWUWC7I9 Portfolio Turnover 3.84% |
# region imports
from AlgorithmImports import *
# endregion
class SquareMagentaHamster(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.symbol = self.future.Symbol
self.Vix = self.AddFuture(Futures.Indices.VIX, extendedMarketHours= True)
self.Vix.SetFilter(0, 182)
self.Vixsymbol = self.Vix.Symbol
self.Longentry_ticket = None
self.ESstopTicket = None
self.ESprofitTicket = None
self.LongcontractSymbol = None
self.Esprice = None
self.Vixentry_ticket = None
self.VixstopTicket = None
self.VixprofitTicket = None
self.VixcontractSymbol = None
self.VixPrice = None
def OnData(self, data: Slice):
if self.Longentry_ticket is None and self.Vixentry_ticket is None:
self.BuyFuture(data)
self.BuyVix(data)
if self.Portfolio.Invested:
if self.LongcontractSymbol == None or self.VixcontractSymbol == None:
return
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
def BuyFuture(self, data: Slice):
chain = data.FuturesChains.get(self.symbol)
if chain:
self.LongcontractSymbol = sorted(chain, key=lambda contract: contract.Expiry, reverse=True)[0]
self.Esprice = self.Securities[self.LongcontractSymbol.Symbol].Price
self.Longentry_ticket = self.LimitOrder(self.LongcontractSymbol.Symbol, 2, self.Esprice)
self.ESprofitTicket = self.LimitOrder(self.LongcontractSymbol.Symbol, -2, self.Esprice*1.05)
self.ESstopTicket = self.StopMarketOrder(self.LongcontractSymbol.Symbol, -2, self.Esprice*0.95)
return
def BuyVix(self, data: Slice):
Vixchain = data.FuturesChains.get(self.Vixsymbol)
if Vixchain:
self.VixcontractSymbol = sorted(Vixchain, key=lambda contract: contract.Expiry, reverse=True)[0]
self.VixPrice = self.Securities[self.VixcontractSymbol.Symbol].Price
self.Vixentry_ticket = self.LimitOrder(self.VixcontractSymbol.Symbol, 4, self.VixPrice)
self.VixprofitTicket = self.LimitOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*1.05)
self.VixstopTicket = self.StopMarketOrder(self.VixcontractSymbol.Symbol, -4, self.VixPrice*0.95)
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
return
if orderEvent.Status != OrderStatus.Filled:
return
if self.LongcontractSymbol is None:
return
# Otherwise, one of the exit orders was filled, so cancel the open orders
if orderEvent.OrderId == self.ESprofitTicket.OrderId or orderEvent.OrderId == self.ESstopTicket.OrderId:
self.Transactions.CancelOpenOrders(self.LongcontractSymbol.Symbol)
self.Longentry_ticket = None
return
if self.VixcontractSymbol is None:
return
# Otherwise, one of the exit orders was filled, so cancel the open orders
if orderEvent.OrderId == self.VixstopTicket.OrderId or orderEvent.OrderId == self.VixprofitTicket.OrderId:
self.Transactions.CancelOpenOrders(self.VixcontractSymbol.Symbol)
self.Vixentry_ticket = None
return