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

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.volatility.smile.function.SABRBerestyckiVolatilityFunction.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 java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.util.CompareUtils;

/**
 *  This is the form given in Obloj (2008), "<i>Fine-Tune Your Smile</i>", and supposedly corresponds to that given in Berestycki (2004),
 *  "<i>Computing the implied volatility in stochastic volatility models</i>". However, appears to be the same as Hagan's.
 */
public class SABRBerestyckiVolatilityFunction extends VolatilityFunctionProvider<SABRFormulaData> {
    private static final Logger s_logger = LoggerFactory.getLogger(SABRBerestyckiVolatilityFunction.class);

    private static final double CUTOFF_MONEYNESS = 1e-6;
    private static final double EPS = 1e-15;

    @Override
    public Function1D<SABRFormulaData, Double> getVolatilityFunction(final EuropeanVanillaOption option,
            final double forward) {
        Validate.notNull(option, "option");
        final double strike = option.getStrike();

        final double cutoff = forward * CUTOFF_MONEYNESS;
        final double k;
        if (strike < cutoff) {
            s_logger.info("Given strike of " + strike + " is less than cutoff at " + cutoff
                    + ", therefore the strike is taken as " + cutoff);
            k = cutoff;
        } else {
            k = strike;
        }

        final double t = option.getTimeToExpiry();
        return new Function1D<SABRFormulaData, Double>() {

            @Override
            public final Double evaluate(final SABRFormulaData data) {
                Validate.notNull(data, "data");
                final double alpha = data.getAlpha();
                final double beta = data.getBeta();
                final double rho = data.getRho();
                final double nu = data.getNu();
                double i0;
                final double beta1 = 1 - beta;

                if (CompareUtils.closeEquals(forward, k, EPS)) {
                    i0 = alpha / Math.pow(k, beta1);
                } else {

                    final double x = Math.log(forward / k);

                    if (CompareUtils.closeEquals(nu, 0, EPS)) {
                        if (CompareUtils.closeEquals(beta, 1.0, EPS)) {
                            return alpha; // this is just log-normal
                        }
                        i0 = x * alpha * beta1 / (Math.pow(forward, beta1) - Math.pow(k, beta1));
                    } else {

                        double z;
                        if (beta == 1.0) {
                            z = nu * x / alpha;

                        } else {
                            z = nu * (Math.pow(forward, beta1) - Math.pow(k, beta1)) / alpha / beta1;
                        }
                        final double temp = (Math.sqrt(1 + z * (z - 2 * rho)) + z - rho) / (1 - rho);
                        i0 = nu * x / Math.log(temp);

                    }
                }

                final double f1sqrt = Math.pow(forward * k, beta1 / 2);
                final double i1 = beta1 * beta1 * alpha * alpha / 24 / f1sqrt / f1sqrt
                        + rho * alpha * beta * nu / 4 / f1sqrt + nu * nu * (2 - 3 * rho * rho) / 24;

                return i0 * (1 + i1 * t);
            }
        };
    }

    @Override
    public Function1D<SABRFormulaData, double[]> getVolatilityFunction(final double forward, final double[] strikes,
            final double timeToExpiry) {

        final int n = strikes.length;
        final List<Function1D<SABRFormulaData, Double>> funcs = new ArrayList<Function1D<SABRFormulaData, Double>>(
                n);
        for (int i = 0; i < n; i++) {
            funcs.add(getVolatilityFunction(new EuropeanVanillaOption(strikes[i], timeToExpiry, true), forward));
        }
        return new Function1D<SABRFormulaData, double[]>() {
            @Override
            public double[] evaluate(final SABRFormulaData data) {
                final double[] res = new double[n];
                for (int i = 0; i < n; i++) {
                    res[i] = funcs.get(i).evaluate(data);
                }
                return res;
            }

        };

    }

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

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

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