---
title: "Bull Call Spread"
description: "Bull call spread, also known as long call spread, consists of buying an ITM call and selling an OTM call."
canonical: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/bull-call-spread
markdown: https://www.quantconnect.com/docs/v2/writing-algorithms/trading-and-orders/option-strategies/bull-call-spread.md
language: python
source: https://github.com/QuantConnect/Documentation/tree/master/03%20Writing%20Algorithms/22%20Trading%20and%20Orders/08%20Option%20Strategies/03%20Bull%20Call%20Spread
modified: 2026-11-01
index: https://www.quantconnect.com/llms.txt
---

# Bull Call 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) > Bull Call Spread

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

## Introduction

**Bull call spread**, also known as **long call spread**, consists of buying an ITM call and selling an OTM call. Both calls have the same underlying Equity and the same expiration date. The OTM call serves as a hedge for the ITM call. The bull call spread profits from a rise in underlying asset price.

## Implementation

Follow these steps to implement the bull call spread strategy:

1. In the `initialize` method, set the start date, end date, cash, and [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(500000)

       self.universe_settings.asynchronous = True
       option = self.add_option("GOOG", Resolution.MINUTE)
       self._symbol = option.symbol
       option.set_filter(lambda universe: universe.call_spread(30, 5))
   ```
   The `call_spread` filter narrows the universe down to just the two contracts you need to form a bull call spread.
2. In the `on_data` method, select the expiration 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 the call Option contracts with the furthest expiry
       expiry = max([x.expiry for x in chain])
       calls = [i for i in chain if i.expiry == expiry and i.right == OptionRight.CALL]
       if not calls == 0:
           return

       # Select the ITM and OTM contract strike prices from the remaining contracts
       strikes = [x.strike for x in calls]
       otm_strike = max(strikes)
       itm_strike = min(strikes)
   ```
3. In the `on_data` method, select the contracts and place the orders.
   **Approach A:** Call the `OptionStrategies.bull_call_spread` method with the details of each leg and then pass the result to the `buy` method.
   ```python
   option_strategy = OptionStrategies.bull_call_spread(self._symbol, itm_strike, otm_strike, expiry)
   self.buy(option_strategy, 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
   itm_call = [x for x in calls if x.strike == itm_strike][0]
   otm_call = [x for x in calls if x.strike == otm_strike][0]

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

## Strategy Payoff

The bull call spread is a limited-reward-limited-risk strategy. The payoff is

$$ \begin{array}{rcll} C^{OTM}_T & = & (S_T - K^{OTM})^{+}\\ C^{ITM}_T & = & (S_T - K^{ITM})^{+}\\ P_T & = & (C^{ITM}_T - C^{OTM}_T + C^{OTM}_0 - C^{ITM}_0)\times m - fee\\ \end{array} $$ $$ \begin{array}{rcll} \textrm{where} & C^{OTM}_T & = & \textrm{OTM call value at time T}\\ & C^{ITM}_T & = & \textrm{ITM call value at time T}\\ & S_T & = & \textrm{Underlying asset price at time T}\\ & K^{OTM} & = & \textrm{OTM call strike price}\\ & K^{ITM} & = & \textrm{ITM call strike price}\\ & P_T & = & \textrm{Payout total at time T}\\ & C^{ITM}_0 & = & \textrm{ITM call value at position opening (debit paid)}\\ & C^{OTM}_0 & = & \textrm{OTM call value at position opening (credit received)}\\ & m & = & \textrm{Contract multiplier}\\ & T & = & \textrm{Time of expiration} \end{array} $$

In this example, the underlying stock price is $829.08 at expiration. You sold an OTM call at a strike of $835.00 for $3.00 and bought an ITM call at a strike of $767.50 for $41.00.

The following chart shows the payoff at expiration:

![Bull Call Spread strategy payoff at expiration](https://cdn.quantconnect.com/docs/i/writing-algorithms/trading-and-orders/option-strategies/bull-call-spread.png)

The maximum profit is $K^{OTM} - K^{ITM} + C^{OTM}_0 - C^{ITM}_0$. If the underlying price increases to exceed both strikes at expiration, both calls are worth $(S_T - K)$ at expiration.

The maximum loss is the net debit you paid to open the position, $C^{OTM}_0 - C^{ITM}_0$.

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 contract you sell.

## Example

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

| Asset | Price ($) | Strike ($) |
| --- | --- | --- |
| OTM call | 3.00 | 835.00 |
| ITM call | 41.00 | 767.50 |
| Underlying Equity at expiration | 829.08 | - |

Therefore, the payoff is

$$ \begin{array}{rcll} C^{OTM}_T & = & (S_T - K^{OTM})^{+}\\ & = & (829.08-835.00)^{+}\\ & = & 0\\ C^{ITM}_T & = & (S_T - K^{ITM})^{+}\\ & = & (829.08-767.50)^{+}\\ & = & 61.58\\ P_T & = & (C^{ITM}_T - C^{OTM}_T + C^{OTM}_0 - C^{ITM}_0)\times m - fee\\ & = & (61.58-0+3.00-41.00)\times100-1.00\times2\\ & = & 2356\\ \end{array} $$

So, the strategy profits $2,356.

The following algorithm implements a bull call spread strategy:

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

        option = self.add_option("GOOG", Resolution.MINUTE)
        self.symbol = option.symbol
        option.set_filter(self.universe_func)

    def universe_func(self, universe: OptionFilterUniverse) -> OptionFilterUniverse:
        return universe.call_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

        # Get the furthest expiration date of the contracts
        expiry = sorted(chain, key = lambda x: x.expiry, reverse=True)[0].expiry

        # Select the call Option contracts with the furthest expiry
        calls = [i for i in chain if i.expiry == expiry and i.right == OptionRight.CALL]
        if len(calls) == 0: return

        # Select the ITM and OTM contract strike prices from the remaining contracts
        call_strikes = sorted([x.strike for x in calls])
        itm_strike = call_strikes[0]
        otm_strike = call_strikes[-1]

        option_strategy = OptionStrategies.bull_call_spread(self.symbol, itm_strike, otm_strike, expiry)
        self.buy(option_strategy, 1)
```

### Other Examples

For more examples, see the following algorithms:

**Demonstration Algorithm**

- [IndexOptionBullCallSpreadAlgorithm.py](https://github.com/QuantConnect/Lean/blob/master/Algorithm.Python/IndexOptionBullCallSpreadAlgorithm.py) (Python)
