com.opengamma.analytics.financial.model.option.pricing.fourier.FourierPricer.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.option.pricing.fourier.FourierPricer.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.option.pricing.fourier;

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.BlackPriceFunction;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.integration.Integrator1D;
import com.opengamma.analytics.math.integration.RungeKuttaIntegrator1D;
import com.opengamma.analytics.math.number.ComplexNumber;

/**
 * 
 */
public class FourierPricer {
    private static final IntegralLimitCalculator LIMIT_CALCULATOR = new IntegralLimitCalculator();
    private static final BlackPriceFunction BLACK_PRICE_FUNCTION = new BlackPriceFunction();
    private final Integrator1D<Double, Double> _integrator;

    public FourierPricer() {
        this(new RungeKuttaIntegrator1D());
    }

    public FourierPricer(final Integrator1D<Double, Double> integrator) {
        Validate.notNull(integrator, "null integrator");
        _integrator = integrator;
    }

    public double price(final BlackFunctionData data, final EuropeanVanillaOption option,
            final MartingaleCharacteristicExponent ce, final double alpha, final double limitTolerance) {
        return price(data, option, ce, alpha, limitTolerance, false);
    }

    public double price(final BlackFunctionData data, final EuropeanVanillaOption option,
            final MartingaleCharacteristicExponent ce, final double alpha, final double limitTolerance,
            final boolean useVarianceReduction) {
        Validate.notNull(data, "data");
        Validate.notNull(option, "option");
        Validate.notNull(ce, "characteristic exponent");
        Validate.isTrue(limitTolerance > 0, "limit tolerance must be > 0");
        Validate.isTrue(alpha <= ce.getLargestAlpha() && alpha >= ce.getSmallestAlpha(),
                "The value of alpha is not valid for the Characteristic Exponent and will most likely lead to mispricing. Choose a value between "
                        + ce.getSmallestAlpha() + " and " + ce.getLargestAlpha());
        final EuropeanPriceIntegrand integrand = new EuropeanPriceIntegrand(ce, alpha, useVarianceReduction);
        final EuropeanCallFourierTransform psi = new EuropeanCallFourierTransform(ce);
        final double strike = option.getStrike();
        final double t = option.getTimeToExpiry();
        final boolean isCall = option.isCall();
        final double forward = data.getForward();
        final double discountFactor = data.getDiscountFactor();
        final Function1D<ComplexNumber, ComplexNumber> characteristicFunction = psi.getFunction(t);
        final double xMax = LIMIT_CALCULATOR.solve(characteristicFunction, alpha, limitTolerance);
        final Function1D<Double, Double> func = integrand.getFunction(data, option);
        final double integral = Math.exp(-alpha * Math.log(strike / forward))
                * _integrator.integrate(func, 0.0, xMax) / Math.PI;
        if (useVarianceReduction) {
            final double black = BLACK_PRICE_FUNCTION.getPriceFunction(option).evaluate(data);
            final double diff = discountFactor * forward * integral;
            return diff + black;
        }

        if (isCall) {
            if (alpha > 0.0) {
                return discountFactor * forward * integral;
            } else if (alpha < -1.0) {
                return discountFactor * (forward * (1 + integral) - strike);
            } else {
                return discountFactor * forward * (integral + 1);
            }
        }
        if (alpha > 0.0) {
            return discountFactor * (forward * (integral - 1) + strike);
        } else if (alpha < -1.0) {
            return discountFactor * forward * integral;
        }
        return discountFactor * (forward * integral + strike);
    }

    public double priceFromVol(final BlackFunctionData data, final EuropeanVanillaOption option,
            final MartingaleCharacteristicExponent ce, final double alpha, final double limitTolerance,
            final boolean useVarianceReduction) {
        final double forward = data.getForward();
        final double discountFactor = data.getDiscountFactor();
        final double t = option.getTimeToExpiry();
        final double strike = option.getStrike();

        final EuropeanPriceIntegrand integrand = new EuropeanPriceIntegrand(ce, alpha, useVarianceReduction);
        final EuropeanCallFourierTransform callFourierTransform = new EuropeanCallFourierTransform(ce);

        final Function1D<ComplexNumber, ComplexNumber> psi = callFourierTransform.getFunction(t);
        final double xMax = LIMIT_CALCULATOR.solve(psi, alpha, limitTolerance);

        final double integral = Math.exp(-alpha * Math.log(strike / forward))
                * _integrator.integrate(integrand.getFunction(data, option), 0.0, xMax) / Math.PI;
        final double black = BLACK_PRICE_FUNCTION.getPriceFunction(option).evaluate(data);
        final double diff = discountFactor * forward * integral;

        return diff + black;
    }
}