Skip to content

Instantly share code, notes, and snippets.

@0xJchen
Last active September 27, 2023 10:11
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save 0xJchen/79142dd6e85feccd3fc4a6a25e303b00 to your computer and use it in GitHub Desktop.
Save 0xJchen/79142dd6e85feccd3fc4a6a25e303b00 to your computer and use it in GitHub Desktop.
chatgpt-sabr
import numpy as np
from scipy.optimize import minimize
from math import log, sqrt
import matplotlib.pyplot as plt
def sabr_iv(alpha, beta, rho, nu, F, K, T):
"""
Returns the implied volatility using the SABR model formula.
"""
X = K
if F == K:
numer1 = (((1 - beta)**2)/24)*alpha*alpha/(F**(2 - 2*beta))
numer2 = 0.25*rho*beta*nu*alpha/(F**(1 - beta))
numer3 = ((2 - 3*rho*rho)/24)*nu*nu
vol_atm = alpha*(1 + (numer1 + numer2 + numer3)*T)/(F**(1-beta))
return vol_atm
else:
z = nu/alpha*(F*X)**(0.5*(1-beta))*log(F/X)
zhi = log((sqrt(1-2*rho*z+z*z)+z-rho)/(1-rho))
numer1 = (((1 - beta)**2)/24)*((alpha*alpha)/((F*X)**(1 - beta)))
numer2 = 0.25*rho*beta*nu*alpha/((F*X)**((1 - beta)/2))
numer3 = ((2 - 3*rho*rho)/24)*nu*nu
denom1 = (1 + (((1 - beta)**2)/24)*log(F/X)**2 + (((1 - beta)**4)/1920)*(log(F/X)**4))
return alpha*(1 + (numer1 + numer2 + numer3)*T)*z/(zhi*(F*X)**((1-beta)/2)*denom1)
def sabr_error(params, F, K, T, mkt_vol, beta):
"""
Error function to minimize. The difference between SABR implied vol and market vol.
"""
alpha, rho, nu = params
# beta = 0.8 # Assuming a fixed beta, but you can calibrate it as well.
model_vol = sabr_iv(alpha, beta, rho, nu, F, K, T)
error = (model_vol - mkt_vol)**2
return error
# Calibration function
def calibrate_sabr(F, K, T, mkt_vol, beta=0.8):
"""
Calibrate the SABR model and return the optimal parameters.
"""
initial_guess = [0.2, 0.2, 0.2]
bounds = [(0.001, 5), (-0.999, 0.999), (0.001, 5)]
result = minimize(sabr_error, initial_guess, args=(F, K, T, mkt_vol, beta), bounds=bounds, method='L-BFGS-B')
return result.x
# Example calibration
F = 1600
K = 1600
T = 0.25
mkt_vol = 0.4
alpha, rho, nu = calibrate_sabr(F, K, T, mkt_vol)
print(f"Alpha: {alpha}, Rho: {rho}, Nu: {nu}")
def compute_iv_sabr(alpha, beta, rho, nu, F_new, K_new, T):
"""
Compute the implied volatility using the SABR model for a new asset.
"""
return sabr_iv(alpha, beta, rho, nu, F_new, K_new, T)
# Calibrated parameters
alpha_calibrated = 1.74
rho_calibrated = 0.2
nu_calibrated = 0.22
beta = 0.6 # Assuming a fixed beta, but you can change it.
# New asset details
F_new = 3 # New forward price
K_news = np.linspace(1,5,num=1000) # New strike price
T = 0.25 # Time to maturity
ivs=[]
# Compute implied volatility for the new asset
for K_new in K_news:
ivs.append(compute_iv_sabr(alpha_calibrated, beta, rho_calibrated, nu_calibrated, F_new, K_new, T))
# iv_new = compute_iv_sabr(alpha_calibrated, beta, rho_calibrated, nu_calibrated, F_new, K_new, T)
# print(f"Implied Volatility for new asset: {iv_new}")
plt.plot(K_news,ivs)
plt.show()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment