def test_FinSABR(): strikes = np.linspace(0.01, 0.06, 100) alpha = 0.060277 beta = 0.5 rho = 0.2097 nu = 0.75091 model1 = FinModelSABR(alpha, beta, rho, nu) alpha = 0.058484 beta = 0.5 rho = 0.20568 nu = 0.79647 model2 = FinModelSABR(alpha, beta, rho, nu) f = 0.0350 T = 1.0 vols1 = model1.blackVol(f, strikes, T) vols2 = model2.blackVol(f, strikes, T) if PLOT_GRAPHS: plt.figure() plt.plot(strikes, vols1) plt.plot(strikes, vols2) plt.title("SABR")
def test_SABR_Calibration(): beta = 0.5 rho = -0.09 nu = 0.1 strikeVol = 0.1 f = 0.043 k = 0.050 r = 0.03 texp = 1.0 callOptionType = FinOptionTypes.EUROPEAN_CALL putOptionType = FinOptionTypes.EUROPEAN_PUT df = np.exp(-r * texp) testCases.header("TEST", "CALIBRATION ERROR") # Make SABR equivalent to lognormal (Black) model # (i.e. alpha = 0, beta = 1, rho = 0, nu = 0, shift = 0) modelSABR_01 = FinModelSABR(0.0, 1.0, 0.0, 0.0) modelSABR_01.setAlphaFromBlackVol(strikeVol, f, k, texp) impliedLognormalVol = modelSABR_01.blackVol(f, k, texp) impliedATMLognormalVol = modelSABR_01.blackVol(k, k, texp) impliedLognormalSmile = impliedLognormalVol - impliedATMLognormalVol assert impliedLognormalSmile == 0.0, "In lognormal model, smile should be flat" calibrationError = round(strikeVol - impliedLognormalVol, 12) testCases.print("LOGNORMAL CASE", calibrationError) # Volatility: pure SABR dynamics modelSABR_02 = FinModelSABR(alpha, beta, rho, nu) modelSABR_02.setAlphaFromBlackVol(strikeVol, f, k, texp) impliedLognormalVol = modelSABR_02.blackVol(f, k, texp) impliedATMLognormalVol = modelSABR_02.blackVol(k, k, texp) impliedLognormalSmile = impliedLognormalVol - impliedATMLognormalVol calibrationError = round(strikeVol - impliedLognormalVol, 12) testCases.print("SABR CASE", calibrationError) # Valuation: pure SABR dynamics valueCall = modelSABR_02.value(f, k, texp, df, callOptionType) valuePut = modelSABR_02.value(f, k, texp, df, putOptionType) assert round(valueCall - valuePut, 12) == round(df*(f - k), 12), \ "The method called 'value()' doesn't comply with Call-Put parity"