/*
 Copyright (C) 2010 Selene Makarios

 This source code is release under the BSD License.

 This file is part of JQuantLib, a free-software/open-source library
 for financial quantitative analysts and developers - http://jquantlib.org/

 JQuantLib is free software: you can redistribute it and/or modify it
 under the terms of the JQuantLib license.  You should have received a
 copy of the license along with this program; if not, please email
 . The license is also available online at
 .

 This program is distributed in the hope that it will be useful, but WITHOUT
 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 FOR A PARTICULAR PURPOSE.  See the license for more details.

 JQuantLib is based on QuantLib. http://quantlib.org/
 When applicable, the original copyright notice follows this notice.
 */


package org.jquantlib.testsuite.math.interpolations;

import static java.lang.Math.abs;
import static org.junit.Assert.assertFalse;

import java.util.ArrayList;
import java.util.List;

import org.jquantlib.QL;
import org.jquantlib.lang.annotation.Time;
import org.jquantlib.math.Constants;
import org.jquantlib.math.interpolations.SABRInterpolation;
import org.jquantlib.math.matrixutilities.Array;
import org.jquantlib.math.optimization.EndCriteria;
import org.jquantlib.math.optimization.LevenbergMarquardt;
import org.jquantlib.math.optimization.OptimizationMethod;
import org.jquantlib.math.optimization.Simplex;
import org.jquantlib.termstructures.volatilities.Sabr;
import org.junit.Ignore;
import org.junit.Test;

public class SABRInterpolationTest {

    //TODO: uncomment when Minpack.lmdif becomes available
    @Ignore
    @Test
    public void testSABRInterpolationTest() {
        QL.info("::::: " + this.getClass().getSimpleName() + " :::::");
        QL.info("Testing SABR interpolation...");

        // Test SABR function against input volatilities
        final double tolerance = 2.0e-13;
        final double[] strikes = new double[31];
        final double[] volatilities = new double[31];
        // input strikes
        strikes[0] = 0.03 ; strikes[1] = 0.032 ; strikes[2] = 0.034 ;
        strikes[3] = 0.036 ; strikes[4] = 0.038 ; strikes[5] = 0.04 ;
        strikes[6] = 0.042 ; strikes[7] = 0.044 ; strikes[8] = 0.046 ;
        strikes[9] = 0.048 ; strikes[10] = 0.05 ; strikes[11] = 0.052 ;
        strikes[12] = 0.054 ; strikes[13] = 0.056 ; strikes[14] = 0.058 ;
        strikes[15] = 0.06 ; strikes[16] = 0.062 ; strikes[17] = 0.064 ;
        strikes[18] = 0.066 ; strikes[19] = 0.068 ; strikes[20] = 0.07 ;
        strikes[21] = 0.072 ; strikes[22] = 0.074 ; strikes[23] = 0.076 ;
        strikes[24] = 0.078 ; strikes[25] = 0.08 ; strikes[26] = 0.082 ;
        strikes[27] = 0.084 ; strikes[28] = 0.086 ; strikes[29] = 0.088;
        strikes[30] = 0.09;
        // input volatilities
        volatilities[0] = 1.16725837321531 ; volatilities[1] = 1.15226075991385 ; volatilities[2] = 1.13829711098834 ;
        volatilities[3] = 1.12524190877505 ; volatilities[4] = 1.11299079244474 ; volatilities[5] = 1.10145609357162 ;
        volatilities[6] = 1.09056348513411 ; volatilities[7] = 1.08024942745106 ; volatilities[8] = 1.07045919457758 ;
        volatilities[9] = 1.06114533019077 ; volatilities[10] = 1.05226642581503 ; volatilities[11] = 1.04378614411707 ;
        volatilities[12] = 1.03567243073732 ; volatilities[13] = 1.0278968727451 ; volatilities[14] = 1.02043417226345 ;
        volatilities[15] = 1.01326171139321 ; volatilities[16] = 1.00635919013311 ; volatilities[17] = 0.999708323124949 ;
        volatilities[18] = 0.993292584155381 ; volatilities[19] = 0.987096989695393 ; volatilities[20] = 0.98110791455717 ;
        volatilities[21] = 0.975312934134512 ; volatilities[22] = 0.969700688771689 ; volatilities[23] = 0.964260766651027;
        volatilities[24] = 0.958983602256592 ; volatilities[25] = 0.953860388001395 ; volatilities[26] = 0.948882997029509 ;
        volatilities[27] = 0.944043915545469 ; volatilities[28] = 0.939336183299237 ; volatilities[29] = 0.934753341079515 ;
        volatilities[30] = 0.930289384251337;

        final Array strikeArray = new Array(strikes.length);
        final Array volatilityArray = new Array(volatilities.length);

        for (int i = 0; i < strikes.length; i++) {
            strikeArray.set(i, strikes[i]);
        }
        for (int i = 0; i < volatilities.length; i++) {
            volatilityArray.set(i, volatilities[i]);
        }

        @Time
        final double expiry = 1.0;
        final double forward = 0.039;
        // input SABR coefficients (corresponding to the vols above)
        final double initialAlpha = 0.3;
        final double initialBeta = 0.6;
        final double initialNu = 0.02;
        final double initialRho = 0.01;
        // calculate SABR vols and compare with input vols
        for(int i=0; i < strikes.length; i++){
            final double calculatedVol = (new Sabr()).sabrVolatility(strikes[i], forward, expiry,
                                                				initialAlpha, initialBeta,
                                                				initialNu, initialRho);
	        assertFalse("failed to calculate Sabr function at strike " + strikes[i]
			                + "\n    expected:   " + volatilities[i]
			                + "\n    calculated: " + calculatedVol
			                + "\n    error:      " + abs(calculatedVol-volatilities[i]),
			            abs(volatilities[i]-calculatedVol) > tolerance);
        }

        // Test SABR calibration against input parameters
        // Initial null guesses (uses default values)
        final double alphaGuess = Constants.NULL_REAL;
        final double betaGuess = Constants.NULL_REAL;
        final double nuGuess = Constants.NULL_REAL;
        final double rhoGuess = Constants.NULL_REAL;

        final boolean vegaWeighted[]= {true, false};
        final boolean isAlphaFixed[]= {true, false};
        final boolean isBetaFixed[]= {true, false};
        final boolean isNuFixed[]= {true, false};
        final boolean isRhoFixed[]= {true, false};

        final double calibrationTolerance = 5.0e-8;
        // initialize optimization methods
        final List methods_ = new ArrayList();
        methods_.add(new Simplex(0.01));
        methods_.add(new LevenbergMarquardt(1e-8, 1e-8, 1e-8));
        // Initialize end criteria
        final EndCriteria endCriteria = new EndCriteria(100000, 100, 1e-8, 1e-8, 1e-8);
        // Test looping over all possibilities
        for (int j=0; j calibrationTolerance);
                    // Beta
                    error = abs(initialBeta-calibratedBeta);
                    assertFalse("\nfailed to calibrate beta Sabr parameter:" +
                                    "\n    expected:        " + initialBeta +
                                    "\n    calibrated:      " + calibratedBeta +
                                    "\n    error:           " + error,
                                error > calibrationTolerance);
                    // Nu
                    error = abs(initialNu-calibratedNu);
                    assertFalse("\nfailed to calibrate nu Sabr parameter:" +
                                    "\n    expected:        " + initialNu +
                                    "\n    calibrated:      " + calibratedNu +
                                    "\n    error:           " + error,
                                error > calibrationTolerance);
                    // Rho
                    error = abs(initialRho-calibratedRho);
                    assertFalse("\nfailed to calibrate rho Sabr parameter:" +
                                    "\n    expected:        " + initialRho +
                                    "\n    calibrated:      " + calibratedRho +
                                    "\n    error:           " + error,
                                error > calibrationTolerance);
                  }
                }
              }
            }
          }
        }

    }

}


 

Ads help maintain this website.