Hi all-

I was hoping for a bit of help with my algorithm- I'm new to QuantConnect and still learning the ropes a bit! 

My strategy is simple: Every day at 10:00AM, sell a straddle and delta hedge it every 30 minutes for the remainder of the day. At 3:55 PM, liquidate everything. I would repeat this process every trading day. Executed correctly, this strategy’s P/L would solely be variance premia.

Straddle Specifics: 

- Underlying: SPY 

- Expiry: day-of (SPY has contracts expiring every day. We always want to trade the contract expiring at the end of the same day) 

- Strike: Whatever the nearest available to the current underlying price is 

- Quantity to sell: This would be dynamically calculated and rounded to the nearest whole number based on my current bankroll. 

Further Details: 

- Notification every time an order is placed, along with its specifics 

- Notification every time underlying shares are bought or sold to delta hedge and in what quantity 

- Notification when all positions are liquidated 

 

I seem to be having issues with my delta hedging and for some reason trades only seem to be placed a couple times a month in my backtest, rather than every day, and I can't seem to figure out why this is happening

All input greatly appreciated!

# region imports
from AlgorithmImports import *
# endregion

class VariancePremium(QCAlgorithm):
    def Initialize(self):
        self.SetStartDate(2023, 7, 1)
        self.SetEndDate(2023, 12, 1)
        self.SetCash(100000)
        self.spy = self.AddEquity("SPY", Resolution.Minute)
        self.option = self.AddOption("SPY", Resolution.Minute)
        self.option_symbol = self.option.Symbol
        self.option.SetFilter(-2, 2, 0, 1)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(10, 0), self.SellStraddle)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.Every(TimeSpan.FromMinutes(30)), self.DeltaHedge)
        self.Schedule.On(self.DateRules.EveryDay("SPY"), self.TimeRules.At(15, 55), self.LiquidatePositions)

    # Determine straddle order quantity
    def OrderSizing(self):
        spy_price = self.Securities["SPY"].Price
        size = int(self.Portfolio.Cash / (spy_price * 50))
        return size

    # Place short straddle order
    def SellStraddle(self):
        if not self.Portfolio.Invested:
            if self.CurrentSlice.OptionChains.ContainsKey(self.option_symbol):
                chain = self.CurrentSlice.OptionChains[self.option_symbol]
                contracts_expiring_today = [i for i in chain if i.Expiry.date() == self.Time.date()]
                if len(contracts_expiring_today) == 0:
                    contracts_expiring_today = [i for i in chain if i.Expiry.date() == self.Time.date() + timedelta(days=1)]
                if len(contracts_expiring_today) == 0:
                    return
                spy_price = self.Securities["SPY"].Price
                contract = min(contracts_expiring_today, key=lambda x: abs(x.Strike - spy_price))
                straddle = OptionStrategies.Straddle(self.option_symbol, contract.Strike, contract.Expiry)
                order_size = self.OrderSizing()
                self.Sell(straddle, order_size)
                self.Debug(f"Sold straddle: strike = {contract.Strike}, expiry = {contract.Expiry}, quantity = {order_size}")

    # Dynamically hedge straddle by adjusting position in the underlying
    def DeltaHedge(self):
        if not self.Portfolio.Invested:
            return
        total_delta = 0
        for holding in self.Portfolio.Values:
            if holding.Symbol.SecurityType == SecurityType.Option:
                if self.CurrentSlice.OptionChains.ContainsKey(holding.Symbol.Underlying):
                    option_contract = self.CurrentSlice.OptionChains[holding.Symbol.Underlying].Contracts[holding.Symbol]
                    total_delta += holding.Quantity * option_contract.Greeks.Delta
        spy_holding = self.Portfolio["SPY"]
        spy_quantity = spy_holding.Quantity
        target_spy_quantity = -total_delta
        if spy_quantity != target_spy_quantity:
            self.MarketOrder("SPY", target_spy_quantity - spy_quantity)
            self.Debug("Adjusted Underlying Hedge Position")

    # Liquidate all positions
    def LiquidatePositions(self):
        self.Liquidate()
        self.Debug("Portfolio Liquidated")