com.opengamma.analytics.financial.model.option.pricing.analytic.JuZhongModel.java Source code

Java tutorial

Introduction

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

import java.util.Collections;
import java.util.Set;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.greeks.Greek;
import com.opengamma.analytics.financial.greeks.GreekResultCollection;
import com.opengamma.analytics.financial.model.option.definition.AmericanVanillaOptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.OptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.StandardOptionDataBundle;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.rootfinding.BisectionSingleRootFinder;
import com.opengamma.analytics.math.rootfinding.RealSingleRootFinder;
import com.opengamma.analytics.math.statistics.distribution.NormalDistribution;
import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution;

/**
 * 
 */
public class JuZhongModel extends AnalyticOptionModel<AmericanVanillaOptionDefinition, StandardOptionDataBundle> {
    private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1);
    private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM = new BlackScholesMertonModel();
    private static final Set<Greek> PRICE = Collections.singleton(Greek.FAIR_PRICE);
    private static final RealSingleRootFinder FINDER = new BisectionSingleRootFinder();

    @Override
    public Function1D<StandardOptionDataBundle, Double> getPricingFunction(
            final AmericanVanillaOptionDefinition definition) {
        Validate.notNull(definition);
        final double phi = definition.isCall() ? 1 : -1;
        final Function1D<StandardOptionDataBundle, Double> pricingFunction = new Function1D<StandardOptionDataBundle, Double>() {

            @SuppressWarnings("synthetic-access")
            @Override
            public Double evaluate(final StandardOptionDataBundle data) {
                Validate.notNull(data);
                final GreekResultCollection bsmResult = BSM.getGreeks(definition, data, PRICE);
                final double bsmPrice = bsmResult.get(Greek.FAIR_PRICE);
                final double s = data.getSpot();
                final double k = definition.getStrike();
                final double t = definition.getTimeToExpiry(data.getDate());
                final double r = data.getInterestRate(t);
                final double b = data.getCostOfCarry();
                final double sigma = data.getVolatility(t, k);
                final double sigmaSq = sigma * sigma;
                final double h = getH(r, t);
                final double alpha = getAlpha(r, sigmaSq);
                final double beta = getBeta(r, b, sigmaSq);
                final double lambda = getLambda(phi, alpha, beta, h);
                final double lambdaDash = getLambdaDash(phi, alpha, beta, h);
                final Function1D<Double, Double> function = getFunction(phi, Math.exp(-b * t), k, t, sigmaSq, b,
                        lambda, definition, data);
                final double sEstimate = FINDER.getRoot(function, 0., s * 2);
                if (phi * (sEstimate - s) <= 0) {
                    return phi * (s - k);
                }
                final double estimatePrice = BSM.getGreeks(definition, data.withSpot(sEstimate), PRICE)
                        .get(Greek.FAIR_PRICE);
                final double hA = phi * (sEstimate - k) - estimatePrice;
                final double derivative = getDerivative(k, r, b, t, sigma, phi, sEstimate);
                final double c = getC(h, alpha, lambdaDash, lambda, beta);
                final double d = getD(h, alpha, derivative, hA, lambdaDash, lambda, beta);
                final double ratio = Math.log(s / sEstimate);
                final double chi = c * Math.pow(ratio, 2) + d * ratio;
                return bsmPrice + hA * Math.pow(s / sEstimate, lambda) / (1 - chi);
            }

        };
        return pricingFunction;
    }

    protected double getH(final double r, final double t) {
        return 1 - Math.exp(-r * t);
    }

    protected double getAlpha(final double r, final double sigmaSq) {
        return 2 * r / sigmaSq;
    }

    protected double getBeta(final double r, final double b, final double sigmaSq) {
        return 2 * (r - b) / sigmaSq;
    }

    protected double getLambda(final double phi, final double alpha, final double beta, final double h) {
        final double beta1 = beta - 1;
        return (-beta + phi * Math.sqrt(beta1 * beta1 + 4 * alpha / h)) / 2;
    }

    protected double getLambdaDash(final double phi, final double alpha, final double beta, final double h) {
        return phi * alpha / (h * h * Math.sqrt((beta - 1) * (beta - 1) + 4 * alpha / h));
    }

    protected double getC(final double h, final double alpha, final double lambdaDash, final double lambda,
            final double beta) {
        return (1 - h) * alpha * lambdaDash / (2 * (2 * lambda + beta - 1));
    }

    protected double getD(final double h, final double alpha, final double derivative, final double hA,
            final double lambdaDash, final double lambda, final double beta) {
        final double denom = 2 * lambda + beta - 1;
        return (1 - h) * alpha * (derivative / hA + 1 / h + lambdaDash / denom) / denom;
    }

    protected double getDerivative(final double k, final double r, final double b, final double t,
            final double sigma, final double phi, final double sEstimate) {
        final double df = Math.exp(t * (r - b));
        final double d1 = getD1(sEstimate, k, t, sigma, b);
        final double d2 = getD2(d1, sigma, t);
        return sEstimate * NORMAL.getPDF(d1) * sigma * df / (2 * r * Math.sqrt(t))
                - phi * b * sEstimate * NORMAL.getCDF(phi * d1) * df / r + phi * k * NORMAL.getCDF(phi * d2);
    }

    protected Function1D<Double, Double> getFunction(final double phi, final double df, final double k,
            final double t, final double sigma, final double b, final double lambda,
            final OptionDefinition definition, final StandardOptionDataBundle data) {
        return new Function1D<Double, Double>() {

            @SuppressWarnings("synthetic-access")
            @Override
            public Double evaluate(final Double x) {
                final GreekResultCollection bsmPrice = BSM.getGreeks(definition, data.withSpot(x), PRICE);
                final double price = bsmPrice.get(Greek.FAIR_PRICE);
                return phi * (df * NORMAL.getCDF(phi * getD1(x, k, t, sigma, b))
                        + lambda * (phi * (x - k) - price) / x - 1);
            }

        };
    }
}