Calendar Stock Option Spreads Call options in spread

Table of Contents

1. Calls: Sell Short-Dated and Buy Long

In this type of spread we initiate positions in options which expire on different dates. For example, say we sell a 50 call expiring in a month, and buy a 50 call expiring in 2 months. We know this will be a debit spread—net we will have to pay because the longer-dated call will have a higher price.

Let's assume:

  Strike Premium Expiration
Call Sold 50 $1.27 1 month
Call Bought 50 $1.98 2 months

The premia were determined using the Black-Scholes model with a constant volatility of 30%, a 1% risk free rate, and a $49 stock price. Implementing the spread gives us a cash flow of $1.27 - $1.98 = -$0.71 today.

Let's calculate the profit on the spread when the shorter-dated option expires (1 month), assuming we sell the longer-dated option on that date. Also assume volatility stays constant. We assume we sell the longer-dated call at the Black-Scholes value of the call.

To do this let's load a function that will calculate the Black-Scholes call option value into a Python session.

Load required libraries:

import numpy as np
from scipy.stats import norm
def black_scholes_call(stock, strike, risk_free, vol, time):
    d1 = (np.log(stock / strike) + (risk_free + vol * vol / 2) * time) / (vol * np.sqrt(time))
    d2 = d1 - vol * np.sqrt(time)
    call = stock * norm.cdf(d1) - strike * np.exp(-risk_free * time) * norm.cdf(d2)
    return(round(call, 2))

We can now create a function to value our calendar spread, and apply it to various underlying stock prices using a list comprehension:

def calendar_spread_1(stock, vol):
    profit_call_bought = black_scholes_call(stock, 50, .01, vol, 1/12) - 1.98
    profit_call_sold = 1.27 - max(stock - 50, 0)
    total_profit = profit_call_bought + profit_call_sold
    return(round(total_profit, 2))
profit_1_same_vol = [calendar_spread_1(x, 0.3) for x in range(30, 70)]

Plot the spread profit:

import plotly.express as px

fig = px.line(x = range(30, 70), y = profit_1_same_vol, template='plotly_dark', title="Profit on Calendar Spread (Constant Volatility)").update_layout(
    xaxis_title="Stock Price", yaxis_title="Spread Profit"
)

fig.add_hline(y=0)

fig.write_html("./figs/profit_same_vol.html")

Note this resembles the profit on a butterfly, except the transition to the max loss has curvature.

This is how the calendar spread is defined in textbooks, however it is not particularly realistic. Stock volatility is not constant, and will likely change. In the next few plots we'll look at the spread profit when volatility increases and decreases. Last, we'll look at the most realistic scenario: volatility decreases of the stock price increases, and volatility increases if the stock price decreases (known as the leverage effect).

1.1. What if volatility increases?

The chart below calculates the value of the unexpired call with 50% volatility (up from the 30% above). What this makes clear, is that buying the longer-dated call and selling the shorter dated makes you long volatility. That is, you are better of if the implied volatility in the options increase.

profit_1_increase_vol = [calendar_spread_1(x, 0.5) for x in range(30, 70)]

fig2 = px.line(x = range(30, 70), y = profit_1_increase_vol, template='plotly_dark', title="Profit on Calendar Spread (Increases Volatility)").update_layout(
    xaxis_title="Stock Price", yaxis_title="Spread Profit"
)

fig2.add_hline(y=0)

fig2.write_html("./figs/profit_vol_increase.html")

1.2. What if volatility decreases?

The chart below calculates the value of the unexpired call with 10% volatility.

profit_1_decrease_vol = [calendar_spread_1(x, 0.1) for x in range(30, 70)]

fig3 = px.line(x = range(30, 70), y = profit_1_decrease_vol, template='plotly_dark', title="Profit on Calendar Spread (Decreases Volatility)").update_layout(
    xaxis_title="Stock Price", yaxis_title="Spread Profit"
)

fig3.add_hline(y=0)

fig3.write_html("./figs/profit_vol_decrease.html")

1.3. Most Realistic: Taking into Account the Leverage Effect

The leverage effect is the observation that there is a negative correlation between a stock's price and its volatility.

import numpy

stock_prices = range(30, 70)
volatilities = numpy.linspace(.5, .1, num=40)

profit_1_leverage_vol = [calendar_spread_1(x, y) for x, y in zip(stock_prices, volatilities)]

fig4 = px.line(x = range(30, 70), y = profit_1_leverage_vol, template='plotly_dark', title="Profit on Calendar Spread (Leverage Effect)").update_layout(
    xaxis_title="Stock Price", yaxis_title="Spread Profit"
)

fig4.add_hline(y=0)

fig4.write_html("./figs/profit_vol_leverage.html")

1.4. Leverage Effect: Larger Volatility Range

Let's increase the volatility range to 90% if the stock is 30, and 10% if the stock is 70. This will make the shape of the spread more apparent, though the ranges are not particularly realistic (though still possible).

stock_prices = range(30, 70)
volatilities = numpy.linspace(.9, .1, num=40)

profit_1_leverage2_vol = [calendar_spread_1(x, y) for x, y in zip(stock_prices, volatilities)]

fig5 = px.line(x = range(30, 70), y = profit_1_leverage2_vol, template='plotly_dark', title="Profit on Calendar Spread (Larger Leverage Effect)").update_layout(
    xaxis_title="Stock Price", yaxis_title="Spread Profit"
)

fig5.add_hline(y=0)

fig5.write_html("./figs/profit_vol_leverage2.html")

2. Buy Short-Dated and Sell Long

Flip the charts about the x axis.

Author: Matt Brigida, Ph.D.

Created: 2022-09-03 Sat 20:48

Validate