com.opengamma.analytics.financial.model.volatility.smile.function.SVIVolatilityFunction.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.volatility.smile.function.SVIVolatilityFunction.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.function;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.lang.annotation.ExternalFunction;

/**
 * Gatheral's Stochastic Volatility Inspired (SVI) model
 */
public class SVIVolatilityFunction extends VolatilityFunctionProvider<SVIFormulaData> {

    @Override
    public Function1D<SVIFormulaData, Double> getVolatilityFunction(final EuropeanVanillaOption option,
            final double forward) {
        Validate.notNull(option, "option");
        Validate.isTrue(forward > 0, "Need forward >= 0");
        final double strike = option.getStrike();
        Validate.isTrue(strike > 0, "Need strike >= 0");
        final double kappa = Math.log(strike / forward);

        return new Function1D<SVIFormulaData, Double>() {
            @SuppressWarnings("synthetic-access")
            @Override
            public Double evaluate(final SVIFormulaData data) {
                return getVolatility(kappa, data);
            }
        };
    }

    @ExternalFunction
    public double getVolatility(final double forward, final double strike, final double a, final double b,
            final double rho, final double nu, final double m) {

        final SVIFormulaData data = new SVIFormulaData(a, b, rho, nu, m);
        return getVolatility(forward, strike, data);
    }

    public double getVolatility(final double forward, final double strike, final SVIFormulaData data) {
        Validate.isTrue(forward > 0, "Need forward >= 0");
        Validate.isTrue(strike > 0, "Need strike >= 0");
        Validate.notNull(data, "null SVI parameters");

        final double kappa = Math.log(strike / forward);
        return getVolatility(kappa, data);
    }

    private double getVolatility(final double kappa, final SVIFormulaData data) {
        Validate.notNull(data, "null SVI parameters");
        final double d = kappa - data.getM();
        final double nu = data.getNu();
        return Math.sqrt(data.getA() + data.getB() * (data.getRho() * d + Math.sqrt(d * d + nu * nu)));
    }

    @Override
    public Function1D<SVIFormulaData, double[]> getVolatilityAdjointFunction(final EuropeanVanillaOption option,
            final double forward) {
        Validate.notNull(option, "option");
        Validate.isTrue(forward > 0, "Need forward >= 0");
        final double strike = option.getStrike();
        Validate.isTrue(strike > 0, "Need strike >= 0");
        final double kappa = Math.log(strike / forward);

        return new Function1D<SVIFormulaData, double[]>() {
            @SuppressWarnings("synthetic-access")
            @Override
            public double[] evaluate(final SVIFormulaData data) {
                return getVolatilityAdjoint(forward, strike, kappa, data);
            }
        };
    }

    @Override
    public Function1D<SVIFormulaData, double[][]> getVolatilityAdjointFunction(final double forward,
            final double[] strikes, final double timeToExpiry) {
        return getVolatilityAdjointFunctionByCallingSingleStrikes(forward, strikes, timeToExpiry);
    }

    @Override
    public Function1D<SVIFormulaData, double[]> getModelAdjointFunction(final EuropeanVanillaOption option,
            final double forward) {
        Validate.notNull(option, "option");
        Validate.isTrue(forward > 0, "Need forward >= 0");
        final double strike = option.getStrike();
        Validate.isTrue(strike > 0, "Need strike >= 0");
        final double kappa = Math.log(strike / forward);

        return new Function1D<SVIFormulaData, double[]>() {
            @SuppressWarnings("synthetic-access")
            @Override
            public double[] evaluate(final SVIFormulaData data) {
                return getModelAdjoint(kappa, data);
            }
        };
    }

    @Override
    public Function1D<SVIFormulaData, double[][]> getModelAdjointFunction(final double forward,
            final double[] strikes, final double timeToExpiry) {
        return getModelAdjointFunctionByCallingSingleStrikes(forward, strikes, timeToExpiry);
    }

    @ExternalFunction
    public double[] getVolatilityAjoint(final double forward, final double strike, final double a, final double b,
            final double rho, final double nu, final double m) {
        final SVIFormulaData data = new SVIFormulaData(a, b, rho, nu, m);
        return getVolatilityAjoint(forward, strike, data);

    }

    public double[] getVolatilityAjoint(final double forward, final double strike, final SVIFormulaData data) {
        Validate.isTrue(forward > 0, "Need forward >= 0");
        Validate.isTrue(strike > 0, "Need strike >= 0");

        final double kappa = Math.log(strike / forward);
        return getVolatilityAdjoint(forward, strike, kappa, data);
    }

    private double[] getVolatilityAdjoint(final double forward, final double strike, final double kappa,
            final SVIFormulaData data) {
        Validate.notNull(data, "null data");

        final double b = data.getB();
        final double rho = data.getRho();
        final double nu = data.getNu();

        final double d = kappa - data.getM();
        final double r = Math.sqrt(d * d + nu * nu);
        final double s = rho * d + r;
        final double sigma = Math.sqrt(data.getA() + b * s);

        final double kappaBar = b * (rho + d / r) / 2 / sigma;

        final double[] res = new double[8];
        res[0] = sigma;
        res[1] = -kappaBar / forward; //fBar
        res[2] = kappaBar / strike; //strikebar
        res[3] = 1. / 2. / sigma; //aBar
        res[4] = s / 2 / sigma; //bBar
        res[5] = b * d / 2 / sigma; //rhoBar
        res[6] = nu * b / r / 2 / sigma; //nuBar
        res[7] = -kappaBar; //mBar

        return res;
    }

    private double[] getModelAdjoint(final double kappa, final SVIFormulaData data) {
        Validate.notNull(data, "null data");

        final double b = data.getB();
        final double rho = data.getRho();
        final double nu = data.getNu();

        final double d = kappa - data.getM();
        final double r = Math.sqrt(d * d + nu * nu);
        final double s = rho * d + r;
        final double sigma = Math.sqrt(data.getA() + b * s);

        final double kappaBar = b * (rho + d / r) / 2 / sigma;

        final double[] res = new double[5];

        res[0] = 1. / 2. / sigma; //aBar
        res[1] = s / 2 / sigma; //bBar
        res[2] = b * d / 2 / sigma; //rhoBar
        res[3] = nu * b / r / 2 / sigma; //nuBar
        res[4] = -kappaBar; //mBar

        return res;
    }

    @Override
    public int hashCode() {
        return toString().hashCode();
    }

    @Override
    public boolean equals(final Object obj) {
        if (obj == null) {
            return false;
        }
        if (this == obj) {
            return true;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "SVI";
    }
}