Overall Statistics
Total Orders
2
Average Win
0%
Average Loss
0%
Compounding Annual Return
0%
Drawdown
0%
Expectancy
0
Start Equity
100000
End Equity
100000
Net Profit
0%
Sharpe Ratio
0
Sortino Ratio
0
Probabilistic Sharpe Ratio
0%
Loss Rate
0%
Win Rate
0%
Profit-Loss Ratio
0
Alpha
0
Beta
0
Annual Standard Deviation
0
Annual Variance
0
Information Ratio
0
Tracking Error
0
Treynor Ratio
0
Total Fees
$0.00
Estimated Strategy Capacity
$0
Lowest Capacity Asset
Portfolio Turnover
0%
# region imports
from AlgorithmImports import *
import itertools
# endregion

class ComboLegLimitOrderDemoAlgorithm(QCAlgorithm):

    def initialize(self):
        self.set_start_date(2015, 12, 24) 
        self.set_end_date(2015, 12, 24)
        self.set_cash(100000) 
        option = self.add_option("GOOG")
        option.set_filter(min_strike=-2, max_strike=2, min_expiry=timedelta(days=0), max_expiry=timedelta(days=180))
        
        self.tickets = []

    def on_data(self, slice: Slice):
        if len(self.tickets) == 0:
            for canonical_symbol, chain in slice.option_chains.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.combo_leg_limit_order(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.LIMIT_PRICE)

                # Log the limit prices and contract prices
                quote_bar = slice.quote_bars[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.limit_price = limit_price + 0.01 * order_direction
                update_settings.tag = f"Update #{len(ticket.update_requests) + 1}"
                response = ticket.update(update_settings)

    def on_order_event(self, orderEvent: OrderEvent) -> None:
        if orderEvent.status == OrderStatus.FILLED:
            self.log(f"{self.time} -- Order {orderEvent.order_id} filled at {orderEvent.fill_price}")