public void SABRParamToIVFacts() { //for beta==1 and zero nu and rho we get a flat surface with vol==alpha var vol = SABR.CalcImpVol_Beta1(100, 100, 1, 0.32, 0, 0); Assert.Equal(0.32, vol, 10); vol = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0); Assert.Equal(0.32, vol, 10); vol = SABR.CalcImpVol_Beta1(100, 50, 1, 0.32, 0, 0); Assert.Equal(0.32, vol, 10); //for positive rho should see upside vols > downside var volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0.5, 0.16); var volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0.5, 0.16); Assert.True(volU > volD); //for negative rho should see upside vols < downside volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, -0.5, 0.16); volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, -0.5, 0.16); Assert.True(volU < volD); //for larger nu should see upside wing vols higher volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0.16); volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0, 0.16); var wingLow = volU + volD; volU = SABR.CalcImpVol_Beta1(100, 150, 1, 0.32, 0, 0.32); volD = SABR.CalcImpVol_Beta1(100, 75, 1, 0.32, 0, 0.32); var wingHigh = volU + volD; Assert.True(wingHigh > wingLow); //for GB parameterization, should see no sensitivity to rho and nu at ATM var volA = SABR.CalcImpVol_GB(100, 100, 1, 0.32, 0, 0.16); var volB = SABR.CalcImpVol_GB(100, 100, 1, 0.32, -0.5, 0.26); Assert.Equal(volA, volB, 10); //for hagan and berestycki, should see agreement in most cases var volHa = SABR.CalcImpVol_Hagan(100, 100, 1, 0.32, 0.9, 0.5, 0.16); var volBe = SABR.CalcImpVol_Berestycki(100, 100, 1, 0.32, 0.9, 0.5, 0.16); Assert.Equal(volHa, volBe, 5); volHa = SABR.CalcImpVol_Hagan(100, 150, 1, 0.32, 0.5, 0.5, 0.16); volBe = SABR.CalcImpVol_Berestycki(100, 150, 1, 0.32, 0.5, 0.5, 0.16); Assert.Equal(volHa, volBe, 3); }
public double GetVolForAbsoluteStrike(double strike, double maturity, double forward) { var alpha = _alphaInterp.Interpolate(maturity); var beta = _betaInterp.Interpolate(maturity); var nu = _nuInterp.Interpolate(maturity); var rho = _rhoInterp.Interpolate(maturity); var fwd = forward; if (beta >= 1.0) { return(SABR.CalcImpVol_Beta1(fwd, strike, maturity, alpha, rho, nu)); } else { return(SABR.CalcImpVol_Hagan(fwd, strike, maturity, alpha, beta, rho, nu)); } }
public static double GetVolForAbsoluteStrike(double strike, double maturity, double forward, SABRParameters sabrParams) => sabrParams.Beta >= 1.0 ? SABR.CalcImpVol_Beta1(forward, strike, maturity, sabrParams.Alpha, sabrParams.Rho, sabrParams.Nu) : SABR.CalcImpVol_Hagan(forward, strike, maturity, sabrParams.Alpha, sabrParams.Beta, sabrParams.Rho, sabrParams.Nu);