---
title: "Long Box Spread"
description: "A Long Box Spread is an arbitration strategy that combines a bull call spread and a bear put spread."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/long-box-spread
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/long-box-spread.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/22%20Trading%20and%20Orders/08%20Option%20Strategies/30%20Long%20Box%20Spread
modified: 2026-10-29
index: https://www.quantconnect.com/llms.txt
---

# Long Box Spread

[Documentation](https://www.quantconnect.com/docs/v2.md) > [Writing Algorithms](https://www.quantconnect.com/docs/v2/writing-algorithms.md) > Trading and Orders > [Option Strategies](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies.md) > Long Box Spread

> Code examples are shown in Python. Append `?lang=csharp` to this URL for the C# version of this page.

## Introduction

A long **Box Spread** is the combination of a [bull call spread](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/bull-call-spread.md) and a [bear put spread](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/bear-put-spread.md). It consist of buying an ITM call at strike $A$, selling an OTM put at strike $A$, buying an ITM put at strike $B < A$, and selling an OTM call at strike $B$, where all of the contracts have the same expiry date. This strategy serves as an delta-neutral arbitration from Option mispricing. Note that it only attains a true profit when the risk-free return is greater than the [risk-free interest rate](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/risk-free-interest-rate/key-concepts.md).

## Implementation

Follow these steps to implement the long box spread strategy:

1. In the `initialize` method, set the start date, set the end date, [subscribe to the underlying Equity](https://www.quantconnect.com/docs/v2/writing-algorithms/securities/asset-classes/us-equity/requesting-data.md#02-Create-Subscriptions), and create an [Option universe](https://www.quantconnect.com/docs/v2/writing-algorithms/universes/equity-options.md).
   ```python
   def initialize(self) -> None:
       self.set_start_date(2024, 9, 1)
       self.set_end_date(2024, 12, 31)
       self.set_cash(100000)

       self.universe_settings.asynchronous = True
       option = self.add_option("GOOG", Resolution.MINUTE)
       self._symbol = option.symbol
       option.set_filter(lambda universe: universe.box_spread(30, 5))
   ```
   The `box_spread` filter narrows the universe down to just the four contracts you need to form a box spread.
2. In the `on_data` method, select the expiry and strikes of the contracts in the strategy legs.
   ```python
   def on_data(self, slice: Slice) -> None:
       if self.portfolio.invested:
           return

       # Get the OptionChain
       chain = slice.option_chains.get(self._symbol, None)
       if not chain:
           return

       # Select an expiry date and ITM & OTM strike prices
       expiry = max([x.expiry for x in chain])
       contracts = [x for x in chain if x.expiry == expiry]
       lower_strike = min([x.strike for x in contracts])
       higher_strike = max([x.strike for x in contracts])
   ```
3. In the `on_data` method, select the contracts and place the order.
   **Approach A:** Call the `OptionStrategies.box_spread` method with the details of each leg and then pass the result to the `buy` method.
   ```python
   box_spread = OptionStrategies.box_spread(self._symbol, higher_strike, lower_strike, expiry)
   self.buy(box_spread, 1)
   ```
   **Approach B:** Create a list of `Leg` objects and then call the [combo_market_order](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-market-orders.md), [combo_limit_order](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-limit-orders.md), or [combo_leg_limit_order](https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/order-types/combo-leg-limit-orders.md) method.
   ```python
   # Select the call and put contracts
   itm_call = next(filter(lambda x: x.right == OptionRight.CALL and x.strike == lower_strike, contracts))
   otm_call = next(filter(lambda x: x.right == OptionRight.CALL and x.strike == higher_strike, contracts))
   itm_put = next(filter(lambda x: x.right == OptionRight.PUT and x.strike == higher_strike, contracts))
   otm_put = next(filter(lambda x: x.right == OptionRight.PUT and x.strike == lower_strike, contracts))

   legs = [
       Leg.create(itm_call.symbol, 1),
       Leg.create(itm_put.symbol, 1),
       Leg.create(otm_call.symbol, -1),
       Leg.create(otm_put.symbol, -1),
   ]
   self.combo_market_order(legs, 1)
   ```

## Strategy Payoff

This is a fixed payoff, delta-neutral strategy. The payoff is

$$ \begin{array}{rcll} C_T^{ITM} & = & (S_T - K_{-})^{+}\\ C_T^{OTM} & = & (S_T - K_{+})^{+}\\ P_T^{ITM} & = & (K_{+} - S_T)^{+}\\ P_T^{OTM} & = & (K_{-} - S_T)^{+}\\ Payoff_T & = & (C_T^{ITM} - C_{T_0}^{ITM} + P_T^{ITM} - P_{T_0}^{ITM} - C_T^{OTM} + C_{T_0}^{OTM} - P_T^{OTM} + P_{T_0}^{OTM})\times m - fee\\ & = & (K_{+} - K_{-} + C_{T_0}^{OTM} + P_{T_0}^{OTM} - C_{T_0}^{ITM} - P_{T_0}^{ITM})\times m - fee \end{array} $$ $$ \begin{array}{rcll} \textrm{where} & C_T^{ITM} & = & \textrm{ITM Call value at time T}\\ & C_T^{OTM} & = & \textrm{OTM Call value at time T}\\ & P_T^{ITM} & = & \textrm{ITM Put value at time T}\\ & P_T^{OTM} & = & \textrm{OTM Put value at time T}\\ & S_T & = & \textrm{Underlying asset price at time T}\\ & K_{+} & = & \textrm{Higher strike price}\\ & K_{-} & = & \textrm{Lower strike price}\\ & Payoff_{T_1} & = & \textrm{Payout total at time T1}\\ & C_{T_0}^{ITM} & = & \textrm{ITM Call price when the trade opened (debit paid)}\\ & C_{T_0}^{OTM} & = & \textrm{OTM Call price when the trade opened (credit received)}\\ & P_{T_0}^{ITM} & = & \textrm{ITM Put price when the trade opened (debit paid)}\\ & P_{T_0}^{OTM} & = & \textrm{OTM Put price when the trade opened (credit received)}\\ & m & = & \textrm{Contract multiplier}\\ & T & = & \textrm{Time of expiration} \end{array} $$

In this example, you traded an ITM call at $810.00 for $27.30, an OTM call at $857.50 for $1.05, an ITM put at $857.50 for $28.00, and an OTM put at $810.00 for $1.50.

The following chart shows the payoff at expiration:

![Long Box Spread strategy payoff at expiration](https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/option-strategies/long-box-spread.png)

The payoff is only dependent on the strike price and the initial asset prices.

If the Option is American Option, there is a risk of [early assignment](https://www.quantconnect.com/docs/v2/writing-algorithms/reality-modeling/options-models/assignment.md) on the contracts you sell.

## Example

The following table shows the price details of the assets in the algorithm:

| Asset | Price ($) | Strike ($) |
| --- | --- | --- |
| ITM Call | 27.30 | 810.00 |
| ITM Put | 28.00 | 857.50 |
| OTM Call | 1.05 | 857.50 |
| OTM Put | 1.50 | 810.00 |
| Underlying Equity at expiration | 843.25 | - |

Therefore, the payoff is

$$ \begin{array}{rcll} Payoff_T & = & (K_{+} - K_{-} + C_0^{OTM} + P_0^{OTM} - C_0^{ITM} - P_0^{ITM})\times m - fee\\ & = & (857.50 - 810.00 + 1.05 + 1.50 - 27.30 - 28.00)\times100 - 1.00\times4\\ & = & -529.00\\ \end{array} $$

So, the strategy loses $529.

The following algorithm implements a long box spread Option strategy:

```python
class BoxSpreadStrategy(QCAlgorithm):
    def initialize(self) -> None:
        self.set_start_date(2024, 9, 1)
        self.set_end_date(2024, 12, 31)
        self.set_cash(100000)

        self.universe_settings.asynchronous = True

        option = self.add_option("GOOG", Resolution.MINUTE)
        self._symbol = option.symbol
        option.set_filter(lambda universe: universe.box_spread(30, 5))

    def on_data(self, slice: Slice) -> None:
        if self.portfolio.invested:
            return

        # Get the OptionChain
        chain = slice.option_chains.get(self._symbol, None)
        if not chain:
            return

        # Select an expiry date
        expiry = max([x.expiry for x in chain])

        # Select the strike prices of the contracts
        contracts = [x for x in chain if x.expiry == expiry]
        higher_strike = max([x.strike for x in contracts])
        lower_strike = min([x.strike for x in contracts])

        box_spread = OptionStrategies.box_spread(self._symbol, higher_strike, lower_strike, expiry)
        self.buy(box_spread, 1)

    def on_end_of_day(self, symbol: Symbol) -> None:
        if symbol == self._symbol.underlying:
            self.log(f"{self.time}::{symbol}::{self.securities[symbol].price}")
```
