All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.opengamma.strata.pricer.impl.volatility.smile.SmileModelFitter Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (C) 2015 - present by OpenGamma Inc. and the OpenGamma group of companies
 *
 * Please see distribution for license.
 */
package com.opengamma.strata.pricer.impl.volatility.smile;

import java.util.BitSet;
import java.util.function.Function;

import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;
import com.opengamma.strata.collect.array.DoubleMatrix;
import com.opengamma.strata.math.impl.linearalgebra.DecompositionFactory;
import com.opengamma.strata.math.impl.matrix.MatrixAlgebra;
import com.opengamma.strata.math.impl.matrix.OGMatrixAlgebra;
import com.opengamma.strata.math.impl.minimization.NonLinearParameterTransforms;
import com.opengamma.strata.math.impl.minimization.NonLinearTransformFunction;
import com.opengamma.strata.math.impl.statistics.leastsquare.LeastSquareResults;
import com.opengamma.strata.math.impl.statistics.leastsquare.LeastSquareResultsWithTransform;
import com.opengamma.strata.math.impl.statistics.leastsquare.NonLinearLeastSquare;

/**
 * Smile model fitter.
 * 

* Attempts to calibrate a smile model to the implied volatilities of European vanilla options, by minimising the sum of * squares between the market and model implied volatilities. *

* All the options must be for the same expiry and (implicitly) on the same underlying. * * @param the data of smile model to be calibrated */ public abstract class SmileModelFitter { private static final MatrixAlgebra MA = new OGMatrixAlgebra(); private static final NonLinearLeastSquare SOLVER = new NonLinearLeastSquare(DecompositionFactory.SV_COMMONS, MA, 1e-12); private static final Function UNCONSTRAINED = new Function() { @Override public Boolean apply(DoubleArray x) { return true; } }; private final VolatilityFunctionProvider model; private final Function volFunc; private final Function volAdjointFunc; private final DoubleArray marketValues; private final DoubleArray errors; /** * Constructs smile model fitter from forward, strikes, time to expiry, implied volatilities and error values. *

* {@code strikes}, {@code impliedVols} and {@code error} should be the same length and ordered coherently. * * @param forward the forward value of the underlying * @param strikes the ordered values of strikes * @param timeToExpiry the time-to-expiry * @param impliedVols the market implied volatilities * @param error the 'measurement' error to apply to the market volatility of a particular option * TODO: Review should this be part of EuropeanOptionMarketData? * @param model the volatility function provider */ public SmileModelFitter( double forward, DoubleArray strikes, double timeToExpiry, DoubleArray impliedVols, DoubleArray error, VolatilityFunctionProvider model) { ArgChecker.notNull(strikes, "strikes"); ArgChecker.notNull(impliedVols, "implied vols"); ArgChecker.notNull(error, "errors"); ArgChecker.notNull(model, "model"); int n = strikes.size(); ArgChecker.isTrue(n == impliedVols.size(), "vols not the same length as strikes"); ArgChecker.isTrue(n == error.size(), "errors not the same length as strikes"); this.marketValues = impliedVols; this.errors = error; this.model = model; this.volFunc = new Function() { @Override public DoubleArray apply(DoubleArray x) { final T data = toSmileModelData(x); double[] res = new double[n]; for (int i = 0; i < n; ++i) { res[i] = model.volatility(forward, strikes.get(i), timeToExpiry, data); } return DoubleArray.copyOf(res); } }; this.volAdjointFunc = new Function() { @Override public DoubleMatrix apply(DoubleArray x) { final T data = toSmileModelData(x); double[][] resAdj = new double[n][]; for (int i = 0; i < n; ++i) { DoubleArray deriv = model.volatilityAdjoint(forward, strikes.get(i), timeToExpiry, data).getDerivatives(); resAdj[i] = deriv.subArray(2).toArrayUnsafe(); } return DoubleMatrix.copyOf(resAdj); } }; } /** * Solves using the default NonLinearParameterTransforms for the concrete implementation. *

* This returns {@link LeastSquareResults}. * * @param start the first guess at the parameter values * @return the calibration results */ public LeastSquareResultsWithTransform solve(DoubleArray start) { return solve(start, new BitSet()); } /** * Solve using the default NonLinearParameterTransforms for the concrete implementation with some parameters fixed * to their initial values (indicated by fixed). *

* This returns {@link LeastSquareResults}. * * @param start the first guess at the parameter values * @param fixed the parameters are fixed * @return the calibration results */ public LeastSquareResultsWithTransform solve(DoubleArray start, BitSet fixed) { NonLinearParameterTransforms transform = getTransform(start, fixed); return solve(start, transform); } /** * Solve using a user supplied NonLinearParameterTransforms. *

* This returns {@link LeastSquareResults}. * * @param start the first guess at the parameter values * @param transform transform from model parameters to fitting parameters, and vice versa * @return the calibration results */ public LeastSquareResultsWithTransform solve(DoubleArray start, NonLinearParameterTransforms transform) { NonLinearTransformFunction transFunc = new NonLinearTransformFunction(volFunc, volAdjointFunc, transform); LeastSquareResults solRes = SOLVER.solve(marketValues, errors, transFunc.getFittingFunction(), transFunc.getFittingJacobian(), transform.transform(start), getConstraintFunction(transform), getMaximumStep()); return new LeastSquareResultsWithTransform(solRes, transform); } /** * Obtains volatility function of the smile model. *

* The function is defined in {@link VolatilityFunctionProvider}. * * @return the function */ protected Function getModelValueFunction() { return volFunc; } /** * Obtains Jacobian function of the smile model. *

* The function is defined in {@link VolatilityFunctionProvider}. * * @return the function */ protected Function getModelJacobianFunction() { return volAdjointFunc; } /** * Obtains the maximum number of iterations. * * @return the maximum number. */ protected abstract DoubleArray getMaximumStep(); /** * Obtains the nonlinear transformation of parameters from the initial values. * * @param start the initial values * @return the nonlinear transformation */ protected abstract NonLinearParameterTransforms getTransform(DoubleArray start); /** * Obtains the nonlinear transformation of parameters from the initial values with some parameters fixed. * * @param start the initial values * @param fixed the parameters are fixed * @return the nonlinear transformation */ protected abstract NonLinearParameterTransforms getTransform(DoubleArray start, BitSet fixed); /** * Obtains {@code SmileModelData} instance from the model parameters. * * @param modelParameters the model parameters * @return the smile model data */ public abstract T toSmileModelData(DoubleArray modelParameters); /** * Obtains the constraint function. *

* This is defaulted to be "unconstrained". * * @param t the nonlinear transformation * @return the constraint function */ protected Function getConstraintFunction( @SuppressWarnings("unused") final NonLinearParameterTransforms t) { return UNCONSTRAINED; } /** * Obtains the volatility function provider. * * @return the volatility function provider */ public VolatilityFunctionProvider getModel() { return model; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy