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":

  1. Input stock price, strike, expiration, rate, volatility
  2. Calculate Call and Put prices
  3. Display intrinsic value and time value separately
  4. Plot stock price vs option price curve
  5. 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.

Member Exclusive Free Tutorial

This chapter is free exclusive content for registered members! Please login or register to unlock immediately.

Login / Register Now