com.opengamma.analytics.financial.model.volatility.smile.fitting.SABRNonLinearLeastSquareFitter.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.volatility.smile.fitting.SABRNonLinearLeastSquareFitter.java

Source

/**
 * Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.model.volatility.smile.fitting;

import java.util.BitSet;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.volatility.smile.function.SABRFormulaData;
import com.opengamma.analytics.financial.model.volatility.smile.function.VolatilityFunctionProvider;
import com.opengamma.analytics.math.function.ParameterizedFunction;
import com.opengamma.analytics.math.linearalgebra.DecompositionFactory;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.MatrixAlgebraFactory;
import com.opengamma.analytics.math.minimization.DoubleRangeLimitTransform;
import com.opengamma.analytics.math.minimization.ParameterLimitsTransform;
import com.opengamma.analytics.math.minimization.ParameterLimitsTransform.LimitType;
import com.opengamma.analytics.math.minimization.SingleRangeLimitTransform;
import com.opengamma.analytics.math.minimization.UncoupledParameterTransforms;
import com.opengamma.analytics.math.statistics.leastsquare.LeastSquareResults;
import com.opengamma.analytics.math.statistics.leastsquare.LeastSquareResultsWithTransform;
import com.opengamma.analytics.math.statistics.leastsquare.NonLinearLeastSquare;
import com.opengamma.util.CompareUtils;

/**
 * @deprecated Please use SABRModelFitter
 */
@Deprecated
public class SABRNonLinearLeastSquareFitter extends LeastSquareSmileFitter {
    private static final NonLinearLeastSquare SOLVER = new NonLinearLeastSquare(DecompositionFactory.SV_COLT,
            MatrixAlgebraFactory.OG_ALGEBRA, 1e-4);
    private static final int N_PARAMETERS = 4;
    private static final ParameterLimitsTransform[] TRANSFORMS;

    static {
        TRANSFORMS = new ParameterLimitsTransform[4];
        TRANSFORMS[0] = new SingleRangeLimitTransform(0, LimitType.GREATER_THAN); // alpha > 0
        TRANSFORMS[1] = new DoubleRangeLimitTransform(0, 2.0); // 0 <= beta <= 2
        TRANSFORMS[2] = new DoubleRangeLimitTransform(-1.0, 1.0); // -1 <= rho <= 1
        TRANSFORMS[3] = new SingleRangeLimitTransform(0, LimitType.GREATER_THAN); // nu > 0

    }
    private final VolatilityFunctionProvider<SABRFormulaData> _formula;
    private final SABRATMVolatilityCalculator _atmCalculator;

    public static NonLinearLeastSquare getSolver() {
        return SOLVER;
    }

    public SABRNonLinearLeastSquareFitter(final VolatilityFunctionProvider<SABRFormulaData> formula) {
        Validate.notNull(formula, "SABR formula");
        _formula = formula;
        _atmCalculator = new SABRATMVolatilityCalculator(formula);
    }

    @Override
    public LeastSquareResultsWithTransform getFitResult(final EuropeanVanillaOption[] options,
            final BlackFunctionData[] data, final double[] initialFitParameters, final BitSet fixed) {
        return getFitResult(options, data, initialFitParameters, fixed, 0, false);
    }

    @Override
    public LeastSquareResultsWithTransform getFitResult(final EuropeanVanillaOption[] options,
            final BlackFunctionData[] data, final double[] errors, final double[] initialFitParameters,
            final BitSet fixed) {
        return getFitResult(options, data, errors, initialFitParameters, fixed, 0, false);
    }

    public LeastSquareResultsWithTransform getFitResult(final EuropeanVanillaOption[] options,
            final BlackFunctionData[] data, final double[] initialFitParameters, final BitSet fixed,
            final double atmVol, final boolean recoverATMVol) {
        return getFitResult(options, data, null, initialFitParameters, fixed, atmVol, recoverATMVol);
    }

    public LeastSquareResultsWithTransform getFitResult(final EuropeanVanillaOption[] options,
            final BlackFunctionData[] data, final double[] errors, final double[] initialFitParameters,
            final BitSet fixed, final double atmVol, final boolean recoverATMVol) {
        testData(options, data, errors, initialFitParameters, fixed, N_PARAMETERS);
        if (recoverATMVol) {
            Validate.isTrue(atmVol > 0.0, "ATM volatility must be > 0");
            fixed.set(0, true);
        }
        final int n = options.length;
        final double[] strikes = new double[n];
        final double[] blackVols = new double[n];
        final double maturity = options[0].getTimeToExpiry();
        final double forward = data[0].getForward();
        strikes[0] = options[0].getStrike();
        blackVols[0] = data[0].getBlackVolatility();
        for (int i = 1; i < n; i++) {
            Validate.isTrue(CompareUtils.closeEquals(options[i].getTimeToExpiry(), maturity),
                    "All options must have the same maturity " + maturity + "; have one with maturity "
                            + options[i].getTimeToExpiry());
            strikes[i] = options[i].getStrike();
            blackVols[i] = data[i].getBlackVolatility();
        }
        final UncoupledParameterTransforms transforms = new UncoupledParameterTransforms(
                new DoubleMatrix1D(initialFitParameters), TRANSFORMS, fixed);
        final EuropeanVanillaOption atmOption = new EuropeanVanillaOption(forward, maturity, true);
        final ParameterizedFunction<Double, DoubleMatrix1D, Double> function = new ParameterizedFunction<Double, DoubleMatrix1D, Double>() {

            @SuppressWarnings("synthetic-access")
            @Override
            public Double evaluate(final Double strike, final DoubleMatrix1D fp) {
                final DoubleMatrix1D mp = transforms.inverseTransform(fp);
                double alpha = mp.getEntry(0);
                final double beta = mp.getEntry(1);
                final double rho = mp.getEntry(2);
                final double nu = mp.getEntry(3);

                final SABRFormulaData sabrFormulaData;
                if (recoverATMVol) {
                    alpha = _atmCalculator.calculate(new SABRFormulaData(alpha, beta, rho, nu), atmOption, forward,
                            atmVol);
                    sabrFormulaData = new SABRFormulaData(alpha, beta, rho, nu);
                } else {
                    sabrFormulaData = new SABRFormulaData(alpha, beta, rho, nu);
                }
                final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, maturity, true);
                return _formula.getVolatilityFunction(option, forward).evaluate(sabrFormulaData);
            }
        };

        final DoubleMatrix1D fp = transforms.transform(new DoubleMatrix1D(initialFitParameters));
        LeastSquareResults lsRes = errors == null
                ? SOLVER.solve(new DoubleMatrix1D(strikes), new DoubleMatrix1D(blackVols), function, fp)
                : SOLVER.solve(new DoubleMatrix1D(strikes), new DoubleMatrix1D(blackVols),
                        new DoubleMatrix1D(errors), function, fp);
        final double[] mp = transforms.inverseTransform(lsRes.getFitParameters()).toArray();
        if (recoverATMVol) {
            final double beta = mp[1];
            final double nu = mp[2];
            final double rho = mp[3];
            final EuropeanVanillaOption option = new EuropeanVanillaOption(forward, maturity, true);
            final SABRFormulaData sabrFormulaData = new SABRFormulaData(mp[0], beta, rho, nu);
            final double value = _atmCalculator.calculate(sabrFormulaData, option, forward, atmVol);
            mp[0] = value;
            lsRes = new LeastSquareResults(lsRes.getChiSq(), new DoubleMatrix1D(mp), lsRes.getCovariance());
        }
        return new LeastSquareResultsWithTransform(lsRes, transforms);
        //return new LeastSquareResults(lsRes.getChiSq(), new DoubleMatrix1D(mp), new DoubleMatrix2D(new double[N_PARAMETERS][N_PARAMETERS]), lsRes.getFittingParameterSensitivityToData());
    }
}