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

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

There is a newer version: 2.12.46
Show 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.function.Function;

import com.opengamma.strata.basics.value.ValueDerivatives;
import com.opengamma.strata.collect.ArgChecker;
import com.opengamma.strata.collect.array.DoubleArray;

/**
 * Provides functions that return volatility and its sensitivity to volatility model parameters.
 * 
 * @param  Type of the data needed for the volatility function
 */
public abstract class VolatilityFunctionProvider {

  private static final double EPS = 1.0e-6;

  /**
   * Calculates the volatility.
   * 
   * @param forward  the forward value of the underlying
   * @param strike  the strike value of the option
   * @param timeToExpiry  the time to expiry of the option
   * @param data  the model data
   * @return the volatility
   */
  public abstract double volatility(double forward, double strike, double timeToExpiry, T data);

  /**
   * Calculates volatility and the adjoint (volatility sensitivity to forward, strike and model parameters). 
   * 

* By default the derivatives are computed by central finite difference approximation. * This should be overridden in each subclass. * * @param forward the forward value of the underlying * @param strike the strike value of the option * @param timeToExpiry the time to expiry of the option * @param data the model data * @return the volatility and associated derivatives */ public ValueDerivatives volatilityAdjoint(double forward, double strike, double timeToExpiry, T data) { ArgChecker.isTrue(forward >= 0.0, "forward must be greater than zero"); double[] res = new double[2 + data.getNumberOfParameters()]; // fwd, strike, the model parameters double volatility = volatility(forward, strike, timeToExpiry, data); res[0] = forwardBar(forward, strike, timeToExpiry, data); res[1] = strikeBar(forward, strike, timeToExpiry, data); Function func = getVolatilityFunction(forward, strike, timeToExpiry); double[] modelAdjoint = paramBar(func, data); System.arraycopy(modelAdjoint, 0, res, 2, data.getNumberOfParameters()); return ValueDerivatives.of(volatility, DoubleArray.ofUnsafe(res)); } /** * Computes the first and second order derivatives of the volatility. *

* The first derivative values will be stored in the input array {@code volatilityD} * The array contains, [0] Derivative w.r.t the forward, [1] the derivative w.r.t the strike, then followed by model * parameters. * Thus the length of the array should be 2 + (number of model parameters). *

* The second derivative values will be stored in the input array {@code volatilityD2}. * Only the second order derivative with respect to the forward and strike must be implemented. * The array contains [0][0] forward-forward; [0][1] forward-strike; [1][1] strike-strike. * Thus the size should be 2 x 2. * * @param forward the forward value of the underlying * @param strike the strike value of the option * @param timeToExpiry the time to expiry of the option * @param data the model data * @param volatilityD the array used to return the first order derivative * @param volatilityD2 the array of array used to return the second order derivative * @return the volatility */ public abstract double volatilityAdjoint2( double forward, double strike, double timeToExpiry, T data, double[] volatilityD, double[][] volatilityD2); //------------------------------------------------------------------------- private double forwardBar(double forward, double strike, double timeToExpiry, T data) { double volUp = volatility(forward + EPS, strike, timeToExpiry, data); double volDown = volatility(forward - EPS, strike, timeToExpiry, data); return 0.5 * (volUp - volDown) / EPS; } private double strikeBar(double forward, double strike, double timeToExpiry, T data) { double volUp = volatility(forward, strike + EPS, timeToExpiry, data); double volDown = volatility(forward, strike - EPS, timeToExpiry, data); return 0.5 * (volUp - volDown) / EPS; } private Function getVolatilityFunction(double forward, double strike, double timeToExpiry) { return new Function() { @Override public Double apply(T data) { ArgChecker.notNull(data, "data"); return volatility(forward, strike, timeToExpiry, data); } }; } private double[] paramBar(Function func, T data) { int n = data.getNumberOfParameters(); double[] res = new double[n]; for (int i = 0; i < n; i++) { res[i] = paramBar(func, data, i); } return res; } @SuppressWarnings("unchecked") private double paramBar(Function func, T data, int index) { double mid = data.getParameter(index); double up = mid + EPS; double down = mid - EPS; if (data.isAllowed(index, down)) { if (data.isAllowed(index, up)) { T dUp = (T) data.with(index, up); T dDown = (T) data.with(index, down); return 0.5 * (func.apply(dUp) - func.apply(dDown)) / EPS; } T dDown = (T) data.with(index, down); return (func.apply(data) - func.apply(dDown)) / EPS; } ArgChecker.isTrue(data.isAllowed(index, up), "No values and index {} = {} are allowed", index, mid); T dUp = (T) data.with(index, up); return (func.apply(dUp) - func.apply(data)) / EPS; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy