📐

# Equations for Black Scholes & Greeks

``````import math
import QuantLib as ql

def black_scholes_euro_price(spot, strike, rfr, vol, maturity_days, tenor = 365, option_type='call'):
"""
Calculate the Black-Scholes price for a European call or put option.

Parameters:
- spot: Current stock price (S)
- strike: Strike price (K)
- rfr: Risk-free interest rate (r) as a decimal (e.g., 0.05 for 5%)
- vol: Volatility of the underlying stock (σ) as a decimal (e.g., 0.2 for 20%)
- maturity_days: Time to maturity in days (T)
- tenor: Number of days in a year (e.g., 365 for daily)
- option_type: 'call' or 'put'

Returns:
- Option price
"""
# Convert maturity from days to years
maturity = maturity_days / tenor

# Calculate d1 and d2
d1 = (math.log(spot / strike) + (rfr + 0.5 * vol ** 2) * maturity) / (vol * math.sqrt(maturity))
d2 = d1 - vol * math.sqrt(maturity)

# Calculate N(d1) and N(d2) for call, or N(-d1) and N(-d2) for put
cdf = ql.CumulativeNormalDistribution()
if option_type.lower() == 'call':
N_d1 = cdf(d1)
N_d2 = cdf(d2)
# Call option price
price = spot * N_d1 - strike * math.exp(-rfr * maturity) * N_d2
elif option_type.lower() == 'put':
N_minus_d1 = cdf(-d1)
N_minus_d2 = cdf(-d2)
# Put option price
price = strike * math.exp(-rfr * maturity) * N_minus_d2 - spot * N_minus_d1
else:
raise ValueError("option_type must be 'call' or 'put'")

return price
def black_scholes_euro_delta(spot, strike, rfr, vol, maturity_days, tenor = 365, option_type='call'):
"""
Calculate the Black-Scholes delta for a European call or put option.

Parameters:
- spot: Current stock price (S)
- strike: Strike price (K)
- rfr: Risk-free interest rate (r) as a decimal (e.g., 0.05 for 5%)
- vol: Volatility of the underlying stock (σ) as a decimal (e.g., 0.2 for 20%)
- tenor: Number of days in a year (e.g., 365 for daily)
- maturity_days: Time to maturity in days (T)
- option_type: 'call' or 'put'

Returns:
- Option delta
"""
# Convert maturity from days to years
maturity = maturity_days / tenor

# Calculate d1
d1 = (math.log(spot / strike) + (rfr + 0.5 * vol ** 2) * maturity) / (vol * math.sqrt(maturity))

# Calculate delta
cdf = ql.CumulativeNormalDistribution()
if option_type.lower() == 'call':
delta = cdf(d1)
elif option_type.lower() == 'put':
delta = cdf(d1) - 1
else:
raise ValueError("option_type must be 'call' or 'put'")

return delta

def black_scholes_euro_gamma(spot, strike, rfr, vol, maturity_days, tenor = 365):
"""
Calculate the Black-Scholes gamma for a European call or put option.

Parameters:
- spot: Current stock price (S)
- strike: Strike price (K)
- rfr: Risk-free interest rate (r) as a decimal (e.g., 0.05 for 5%)
- vol: Volatility of the underlying stock (σ) as a decimal (e.g., 0.2 for 20%)
- tenor: Number of days in a year (e.g., 365 for daily)
- maturity_days: Time to maturity in days (T)

Returns:
- Option gamma
"""
# Convert maturity from days to years
maturity = maturity_days / tenor

# Calculate d1
d1 = (math.log(spot / strike) + (rfr + 0.5 * vol ** 2) * maturity) / (vol * math.sqrt(maturity))

# Calculate gamma
pdf = ql.NormalDistribution()
gamma = pdf(d1) / (spot * vol * math.sqrt(maturity))

return gamma

def black_scholes_euro_theta(spot, strike, rfr, vol, maturity_days, tenor = 365, option_type='call'):
"""
Calculate the Black-Scholes theta for a European call or put option.

Parameters:
- spot: Current stock price (S)
- strike: Strike price (K)
- rfr: Risk-free interest rate (r) as a decimal (e.g., 0.05 for 5%)
- vol: Volatility of the underlying stock (σ) as a decimal (e.g., 0.2 for 20%)
- maturity_days: Time to maturity in days (T)
- tenor: Number of days in a year (e.g., 365 for daily)
- option_type: 'call' or 'put'

Returns:
- Option theta
"""
# Convert maturity from days to years
maturity = maturity_days / tenor

# Calculate d1 and d2
d1 = (math.log(spot / strike) + (rfr + 0.5 * vol ** 2) * maturity) / (vol * math.sqrt(maturity))
d2 = d1 - vol * math.sqrt(maturity)

# Calculate N'(d1) and N'(d2) for call, or N'(-d1) and N'(-d2) for put
pdf = ql.NormalDistribution()
N_prime_d1 = pdf(d1)
N_prime_d2 = pdf(d2)
N_prime_minus_d1 = pdf(-d1)
N_prime_minus_d2 = pdf(-d2)

if option_type.lower() == 'call':
# Call option theta
theta = (-spot * N_prime_d1 * vol / (2 * math.sqrt(maturity)) - rfr * strike * math.exp(-rfr * maturity) * ql.CumulativeNormalDistribution()(d2)) / tenor
elif option_type.lower() == 'put':
# Put option theta
theta = (-spot * N_prime_d1 * vol / (2 * math.sqrt(maturity)) + rfr * strike * math.exp(-rfr * maturity) * ql.CumulativeNormalDistribution()(-d2)) / tenor
else:
raise ValueError("option_type must be 'call' or 'put'")

return theta

def black_scholes_euro_vega(spot, strike, rfr, vol, maturity_days, tenor = 365):
"""
Calculate the Black-Scholes vega for a European call or put option.

Parameters:
- spot: Current stock price (S)
- strike: Strike price (K)
- rfr: Risk-free interest rate (r) as a decimal (e.g., 0.05 for 5%)
- vol: Volatility of the underlying stock (σ) as a decimal (e.g., 0.2 for 20%)
- maturity_days: Time to maturity in days (T)
- tenor: Number of days in a year (e.g., 365 for daily)

Returns:
- Option vega
"""
# Convert maturity from days to years
maturity = maturity_days / tenor

# Calculate d1
d1 = (math.log(spot / strike) + (rfr + 0.5 * vol ** 2) * maturity) / (vol * math.sqrt(maturity))

# Calculate vega
pdf = ql.NormalDistribution()
vega = spot * math.sqrt(maturity) * pdf(d1) / 100

return vega``````