Black-Scholes Option Pricing Model
The Black-Scholes model is the foundation of option pricing. Developed by Fischer Black and Myron Scholes in 1973, this discovery later earned them the Nobel Prize in Economics.
๐ฅ Vibe Prompt
"Implement the Black-Scholes model in Python to calculate theoretical prices for European Call and Put options. Input parameters: stock price, strike price, time to expiration, risk-free rate, volatility. Calculate intrinsic value and time value."
The Formula
For European options (exercise only at expiration):
Call Option Price
$$C = S_0 N(d_1) - K e^{-rT} N(d_2)$$
Put Option Price
$$P = K e^{-rT} N(-d_2) - S_0 N(-d_1)$$
Where: $$d_1 = \frac{\ln(S_0/K) + (r + \sigma^2/2)T}{\sigma\sqrt{T}}$$ $$d_2 = d_1 - \sigma\sqrt{T}$$
| Variable | Description | |----------|-------------| | $S_0$ | Current stock price | | $K$ | Strike price | | $T$ | Time to expiration (years) | | $r$ | Risk-free rate | | $\sigma$ | Volatility | | $N(\cdot)$ | CDF of standard normal distribution |
Python Implementation
import math
from scipy.stats import norm
def black_scholes(S, K, T, r, sigma, option_type='call'):
d1 = (math.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * math.sqrt(T))
d2 = d1 - sigma * math.sqrt(T)
if option_type == 'call':
price = S * norm.cdf(d1) - K * math.exp(-r * T) * norm.cdf(d2)
else:
price = K * math.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return price
# Example
S, K, T, r, sigma = 100, 105, 0.5, 0.05, 0.2
call_price = black_scholes(S, K, T, r, sigma, 'call')
put_price = black_scholes(S, K, T, r, sigma, 'put')
print(f"Call Price: ${call_price:.2f}")
print(f"Put Price: ${put_price:.2f}")
print(f"Intrinsic Value (Call): ${max(S - K, 0):.2f}")
print(f"Time Value (Call): ${call_price - max(S - K, 0):.2f}")
Model Assumptions & Limitations
| Assumption | In Reality | |------------|------------| | No arbitrage opportunities | Arbitrage exists (briefly) | | Continuous trading | Trading hours limited | | Constant volatility | Volatility changes (smile) | | No transaction costs | Fees and slippage exist | | Constant risk-free rate | Interest rates change | | No dividends | Most stocks pay dividends |
Summary
- Black-Scholes is the foundational option pricing model
- Call/Put formulas use normal distribution for expected value
- Five input parameters: stock price, strike, time, rate, volatility
- Volatility Smile shows the gap between model and reality
Practice Exercise
๐ก Vibe Coding Practice: Ask AI to build an "Option Pricing Calculator":
- Input stock price, strike, expiration, rate, volatility
- Calculate Call and Put prices
- Display intrinsic value and time value separately
- Plot stock price vs option price curve
- Support multi-parameter comparison
Visualizing Option Prices
import matplotlib.pyplot as plt
import numpy as np
stock_prices = np.linspace(50, 150, 100)
prices = [black_scholes(S, 100, 0.5, 0.05, 0.2, 'call') for S in stock_prices]
plt.plot(stock_prices, prices)
plt.axvline(100, color='gray', linestyle='--', alpha=0.5)
plt.title('Call Option Price vs Stock Price')
plt.xlabel('Stock Price')
plt.ylabel('Option Price')
plt.grid(True, alpha=0.3)
plt.show()
The Formula Explained
The Black-Scholes formula calculates the theoretical price of European options.
Call Option Price
$$C = S_0 \cdot N(d_1) - K \cdot e^{-rT} \cdot N(d_2)$$
Put Option Price
$$P = K \cdot e^{-rT} \cdot N(-d_2) - S_0 \cdot N(-d_1)$$
Where
$$d_1 = \frac{\ln(S_0 / K) + (r + \sigma^2 / 2)T}{\sigma \sqrt{T}}$$
$$d_2 = d_1 - \sigma \sqrt{T}$$
| Symbol | Meaning | |--------|---------| | $S_0$ | Current stock price | | $K$ | Strike price | | $r$ | Risk-free interest rate | | $\sigma$ | Volatility (standard deviation) | | $T$ | Time to expiration (in years) | | $N(\cdot)$ | Cumulative normal distribution |
Python Implementation
import numpy as np
from scipy.stats import norm
def black_scholes(S: float, K: float, T: float, r: float, sigma: float, option_type: str = "call"):
"""Calculate Black-Scholes option price.
Args:
S: Current stock price
K: Strike price
T: Time to expiry (years)
r: Risk-free rate
sigma: Volatility
option_type: 'call' or 'put'
"""
d1 = (np.log(S / K) + (r + 0.5 * sigma ** 2) * T) / (sigma * np.sqrt(T))
d2 = d1 - sigma * np.sqrt(T)
if option_type == "call":
price = S * norm.cdf(d1) - K * np.exp(-r * T) * norm.cdf(d2)
else:
price = K * np.exp(-r * T) * norm.cdf(-d2) - S * norm.cdf(-d1)
return price
# Example: Apple call option
S = 180.0 # AAPL current price
K = 175.0 # Strike price
T = 30 / 365 # 30 days to expiry
r = 0.05 # 5% risk-free rate
sigma = 0.25 # 25% implied volatility
call_price = black_scholes(S, K, T, r, sigma, "call")
put_price = black_scholes(S, K, T, r, sigma, "put")
print(f"Call Price: ${call_price:.2f}")
print(f"Put Price: ${put_price:.2f}")
Implied Volatility
Implied volatility is the volatility that makes the theoretical price match the market price.
from scipy.optimize import brentq
def implied_volatility(market_price: float, S: float, K: float, T: float, r: float, option_type: str = "call"):
"""Find implied volatility using root-finding."""
def objective(sigma):
return black_scholes(S, K, T, r, sigma, option_type) - market_price
try:
iv = brentq(objective, 0.01, 5.0)
return iv
except ValueError:
return None
# Market price is $5.50, find IV
market_price = 5.50
iv = implied_volatility(market_price, S=180, K=175, T=30/365, r=0.05)
print(f"Implied Volatility: {iv:.2%}")
Assumptions and Limitations
| Assumption | Reality | Impact | |------------|---------|--------| | Constant volatility | Volatility changes over time | Model underprices OTM options | | Constant interest rates | Rates fluctuate | Minimal for short-dated options | | No dividends | Most stocks pay dividends | Adjust with dividend yield | | European exercise only | Most options are American | Can exercise early | | Continuous trading | Markets have gaps | Weekend/holiday effects | | No transaction costs | Broker fees, slippage | Reduce profitability | | Lognormal returns | Fat tails in reality | Underprices tail risk |
Volatility Smile
In reality, implied volatility varies by strike โ forming a "smile" or "skew."
import matplotlib.pyplot as plt
strikes = [160, 165, 170, 175, 180, 185, 190, 195, 200]
ivs = [0.35, 0.30, 0.27, 0.25, 0.24, 0.25, 0.28, 0.32, 0.38]
plt.figure(figsize=(10, 5))
plt.plot(strikes, ivs, marker='o')
plt.xlabel('Strike Price')
plt.ylabel('Implied Volatility')
plt.title('Volatility Smile (AAPL)')
plt.grid(True)
plt.show()
Summary
The Black-Scholes model is the foundation of options pricing. It calculates fair value from stock price, strike, time, rates, and volatility. Implied volatility is the market's expectation of future movement.
Key takeaways:
- Black-Scholes: $C = S \cdot N(d_1) - K \cdot e^{-rT} \cdot N(d_2)$ |
- Five inputs: S, K, T, r, sigma |
- Implied volatility: sigma that matches market price |
- Assumptions limit accuracy: constant vol, no early exercise |
- Volatility smile: OTM options have higher IV |
- Python implementation with scipy for IV calculation |
- Model works best for liquid, ATM options |
- Always validate model outputs against market prices |
What's Next: Option Greeks
The next chapter covers the Greeks โ delta, gamma, theta, vega, and rho.