AuthorJing Wu2021-03-17


Bull Call Spread is an options strategy involving two call option contracts with the same expiration but different strikes. The strategy buys one call option with a lower strike and sells another call option with a higher strike price.

This strategy creates a ceiling and floor for the profit. By purchasing a call and selling a call with higher strike simultaneously, traders can reduce the cost of just one long call option with the premium of a short call option. But the premium of ITM call is more expensive than the OTM call. The strategy limits the loss resulting from a drop in the price of the underlying stock but still creates a ceiling to the profit while the underlying price is increasing.

Take GOOG as an example. If the share price of GOOG is $950 at time 0, the premium of ITM call option is 50 with strike 900 and the premium of OTM call option is 2 with strike 1000. If we ignore the commission, dividends and other transaction fees, the payoff of Bull Call Spread strategy is as follows:

price = np.arange(800,1100,1)
k_low = 900 # lower strike price for call
k_high = 1000 # higher strike price for call
premium = 10
premium_low = 20 # premium of call option with lower strike
premium_high = 2 # premium of call option with higher strike
# long call with lower strike
payoff_long_call = [max(-premium, i-k_low-premium_low ) for i in price]
# short call with higher strike
payoff_short_call = [min(premium, -(i-k_high-premium_high)) for i in price]
payoff = np.sum([payoff_long_call, payoff_short_call], axis=0)
plt.plot(price, payoff_long_call, label = 'long call')
plt.plot(price, payoff_short_call, label = 'short call')
plt.plot(price, payoff, label = 'Bull Call Spread')
plt.legend(fontsize = 20)
plt.xlabel('Stock Price at Expiry',fontsize = 15)
plt.ylabel('payoff',fontsize = 15)
plt.title('Bull Call Spread Payoff at Expiration',fontsize = 20)


From the payoff plot we can see, the maximum payoff of the strategy is the difference between the option strike prices minus the difference between the premiums.


Step 1: First, you need to initialize the algorithm including set the start date, end date and the cash required. Then use option.SetFilter(-6, 6, 30, 60) to filter the candidate contracts which expire in 30 days to 60 days from now on. The strike price range involves both ITM and OTM options. Then we get the option chains of GOOG.

def Initialize(self):
    self.SetStartDate(2016, 5, 1)
    self.SetEndDate(2016, 10, 1)
    equity = self.AddEquity("GOOG")
    option = self.AddOption("GOOG")
    self.symbol = option.Symbol
    # set our strike/expiry filter for this option chain
    option.SetFilter(-6, 6, 30, 60)
    # use the underlying equity GOOG as the benchmark

You need to add the following rules in OnData(self,slice) method because you only need to trade options once and wait until the contracts expire. If you already had securities invested in the portfolio, then you do not need to trade new options.

if self.Portfolio.Invested:

Step 2: Choose the contracts with the same expiration date. For demonstration purpose here we sorted the contracts by their expiration dates and choose the options with the furthest expiration date in the option chain.

chain = slice.OptionChains.get(self.symbol)
# sorted the optionchain by expiration date and choose the furthest date
expiry = sorted(chain, key=lambda x: x.Expiry, reverse=True)[0].Expiry

Step 3: Filter the call options from the contracts which expire on the furthest expiration date in the option chain.

# filter the call options from the contracts expires on that date
calls = [i for i in chain if i.Expiry == expiry and i.Right == OptionRight.Call]

Step 4: Sort the call options with the same expiration date according to their strike price. Then buy the call option with the lowest strike price and sell the call with the highest strike price.

# sorted the contracts according to their strike prices 
calls = sorted(calls, key=lambda x: x.Strike)
# Buy call option contract with lower strike
self.Buy(calls[0].Symbol, 1)
# Sell call option contract with higher strike
self.Sell(calls[-1].Symbol, 1)


This strategy can be implemented when you have a moderate outlook on the stock because the payoff reaches its maximum when the price is between the strike price range of two traded options. The strategy protects the downside move of the stock price. But when the price is above the higher strike, the profit is capped.


Backtest (SetFilter)

Backtest (OptionChainProvider)

QuantConnect Logo

Try the world leading quantitative analysis platform today

Sign Up

Next: Long Strangle