Overall Statistics
# region imports
from AlgorithmImports import *
import itertools
# endregion

class ComboLegLimitOrderDemoAlgorithm(QCAlgorithm):

    def Initialize(self):
        self.SetStartDate(2015, 12, 24) 
        self.SetEndDate(2015, 12, 24)
        self.SetCash(100000) 
        option = self.AddOption("GOOG")
        option.SetFilter(minStrike=-2, maxStrike=2, minExpiry=timedelta(days=0), maxExpiry=timedelta(days=180))
        
        self.tickets = []

    def OnData(self, slice: Slice):
        if len(self.tickets) == 0:
            for canonical_symbol, chain in slice.OptionChains.items():
                # Select contracts
                contracts = [contract for contract in chain if contract.Right == OptionRight.Call]
                contracts = [(key, list(group)) for key, group in itertools.groupby(contracts, key=lambda x: x.Expiry)]
                contracts.sort(key=lambda x: x[0])
                contracts = contracts[0][1]
                contracts.sort(key=lambda x: x.Strike)

                if len(contracts) < 2:
                    return

                # Create order legs   
                quantities = [1, -2]
                legs = []
                for i, contract in enumerate(contracts[:2]):
                    legs.append(Leg.Create(contract.Symbol, quantities[i], slice[contract.Symbol].Close * .999))

                # Place order
                self.tickets = self.ComboLegLimitOrder(legs, 1)
        else:
            if self.Time.hour == 10 and self.Time.minute == 45:
                self.Quit()
                return

            for ticket in self.tickets:
                order_direction = np.sign(ticket.Quantity)
                limit_price = ticket.Get(OrderField.LimitPrice)

                # Log the limit prices and contract prices
                quote_bar = slice.QuoteBars[ticket.Symbol]
                current_price = quote_bar.Ask.Low if order_direction == 1 else quote_bar.Bid.High
                ready_to_fill = current_price < limit_price if order_direction == 1 else current_price > limit_price
                self.Log(f"{self.Time} - {ticket.Symbol}. Current price: {current_price}; Limit price: {round(limit_price, 2)}; Direction: {order_direction}; Ready to fill: {ready_to_fill}")

                # Update the leg orders
                update_settings = UpdateOrderFields()
                update_settings.Quantity = 2 * order_direction
                update_settings.LimitPrice = limit_price + 0.01 * order_direction
                update_settings.Tag = f"Update #{len(ticket.UpdateRequests) + 1}"
                response = ticket.Update(update_settings)

    def OnOrderEvent(self, orderEvent: OrderEvent) -> None:
        if orderEvent.Status == OrderStatus.Filled:
            self.Log(f"{self.Time} -- Order {orderEvent.OrderId} filled at {orderEvent.FillPrice}")