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