In the paper, it is stated the premium of a call option implies a certain fair price for the corresponding put option (same asset, strike price and expiration date). The Put-Call Parity is used to validate option pricing models as any pricing model that produces option prices which violate the parity should be considered flawed.

Note, since American options can be exercised before the expiration date, the Put-Call Parity only applies to European options.

## The Formula

Let $C(t)$ and $P(t)$ be the call and put values at time $t$ for a European option with maturity $T$ and strike $K$ on a non-dividend paying asset with spot price $S(t)$. The Parity states:

$$P(t) + S(t) - C(t) = Ke^{-r(T - t)}$$

Rearranging the above to isolate $P(t)$ and $C(t)$ on the left-hand side for non-dividend paying assets:

$$C(t) = S(t) + P(t) - Ke^{-r(T-t)}$$ $$P(t) = C(t) - S(t) + Ke^{-r(T-t)}$$

Rearranging for continuous dividend paying assets:

$$C(t) = S(t)e^{-q(T-t)} + P(t) - Ke^{-r(T-t)}$$ $$P(t) = C(t) - S(t)e^{-q(T-t)} + Ke^{-r(T-t)}$$

With this, we can find a result for a European put option based on the corresponding call option. From the Black-Scholes formula, we can derive the call option:

$$C(S,t) = S \cdot N(d_1) - Ke^{-r(T - t)} N(d_2)$$

From the Put-Call parity statement, we can arrive at a formula for pricing European put options knowing that $1 - N(d) = N(-a)$ for any $a \in \mathbb{R}$

$$P(S,t) = Ke^{-r(T-t)} - S + C(S,t)$$ $$= Ke^{-r(T-t)} - S + (S \cdot N(d_1) - Ke^{-r(T-t)} N(d_2))$$ $$= Ke^{-r(T-t)}(1 - N(d_2)) - S(1 - N(d_1))$$

$$ P(S,t) = Ke^{-r(T-t)} N(-d_2) - S \cdot N(-d_1)$$

## Python Implementation


```python
import numpy as np
import scipy as si
import sympy as sy
import sympy.stats as systats
```


```python
def put_option_price(S, K, T, r, sigma):
    
    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset

    S = float(S)
    
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    
    put_price = K * np.exp(-r * T) * si.stats.norm.cdf(-d2, 0.0, 1.0) - S * si.stats.norm.cdf(-d1, 0.0, 1.0)
    
    return put_price
```

## Python Implementation with Sympy


```python
def put_option_price_sym(S, K, T, r, sigma):
    
    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset
    
    N = Normal('x', 0.0, 1.0)
    
    S = float(S)
    
    d1 = (sy.ln(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sy.sqrt(T))
    d2 = (sy.ln(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sy.sqrt(T))
    
    put_price = K * sy.exp(-r * T) * cdf(N)(-d2) - S * cdf(N)(-d1)
    
    return put_price
```

For dividend paying assets:

$$C(S,t) = Se^{-q(T - t)} N(d_1) - Ke^{-r(T - t)} N(d_2)$$

$$1 - N(d) = N(-a)$ for any $a \in \mathbb{R}$$

$$P(S,t) = Ke^{-r(T-t)} - Se^{-q(T-t)} + C(S,t)$$ $$= Ke^{-r(T-t)} - Se^{-q(T-t)} + (Se^{-q(T-t)} N(d_1) - Ke^{-r(T-t)} N(d_2))$$ $$= Ke^{-r(T-t)}(1 - N(d_2)) - Se^{-q(T-t)} (1 - N(d_1))$$

$$ P(S,t) = Ke^{-r(T-t)} N(-d_2) - Se^{-q(T-t)}N(-d_1)$$

## Python Implementation of Put Option Pricing for Dividend Paying Assets


```python
def put_option_price_div(S, K, T, r, sigma, q):
    
    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset
    #q: continuous dividend rate

    S = float(S)
    
    d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    d2 = (np.log(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
    
    put_price_dividend = K * np.exp(-r * T) * si.stats.norm.cdf(-d2, 0.0, 1.0) - S * np.exp(-q * T) * si.stats.norm.cdf(-d1, 0.0, 1.0)
    
    return put_price_dividend
```

## Sympy Implementation of Put Option Pricing for Dividend Paying Assets


```python
def put_option_price_div_sym(S, K, T, r, sigma, q):
    
    #S: spot price
    #K: strike price
    #T: time to maturity
    #r: interest rate
    #sigma: volatility of underlying asset
    #q: continuous dividend rate
    
    N = Normal('x', 0.0, 1.0)
    
    S = float(S)
    
    d1 = (sy.ln(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * sy.sqrt(T))
    d2 = (sy.ln(S / K) + (r - 0.5 * sigma ** 2) * T) / (sigma * sy.sqrt(T))
    
    put_price_dividend = K * sy.exp(-r * T) * cdf(N)(-d2) - S * sy.exp(-q * T) * cdf(N)(-d1)
    
    return put_price_dividend
```

## References

[Sherbin, A. (2015). How to price and trade options: identify, analyze, and execute the best trade probabilities. 
    Hoboken, NJ: John Wiley & Sons, Inc.](https://amzn.to/37ajBnM)

[Ursone, P. (2015). How to calculate options prices and their Greeks: exploring the Black Scholes model from Delta 
    to Vega. Chichester: Wiley.](https://amzn.to/2UzXDrD)

cecc3620cf03a6ee9981340238b520a688516471
ipynb
Jupyter Notebook
content/posts/Put-Call Parity of Vanilla European Options.ipynb
aschleg/aaronschlegel.me
2f2e143218445da0b6298671c67f9c4afa055d59
MIT
2018-02-19T00:18:17.000Z
2020-01-17T15:11:31.000Z
content/posts/Put-Call Parity of Vanilla European Options.ipynb
aschleg/aaronschlegel.me
2f2e143218445da0b6298671c67f9c4afa055d59
MIT
2018-01-26T00:11:30.000Z
2018-01-26T00:11:30.000Z
content/posts/Put-Call Parity of Vanilla European Options.ipynb
aschleg/aaronschlegel.me
2f2e143218445da0b6298671c67f9c4afa055d59
MIT
Qwen/Qwen-72B
1. YES
2. YES