com.opengamma.analytics.financial.model.option.pricing.tree.LogNormalBinomialTreeBuilderTest.java Source code

Java tutorial

Introduction

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

import static org.testng.AssertJUnit.assertEquals;

import org.apache.commons.lang.Validate;
import org.testng.annotations.Test;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.financial.model.option.definition.EuropeanVanillaOptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.GeneralLogNormalOptionDataBundle;
import com.opengamma.analytics.financial.model.option.definition.OptionDefinition;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.CEVFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.CEVPriceFunction;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.financial.model.tree.RecombiningBinomialTree;
import com.opengamma.analytics.financial.model.volatility.BlackImpliedVolatilityFormula;
import com.opengamma.analytics.financial.model.volatility.surface.DriftSurface;
import com.opengamma.analytics.financial.model.volatility.surface.VolatilitySurface;
import com.opengamma.analytics.math.curve.ConstantDoublesCurve;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Expiry;

/**
 *
 */
public class LogNormalBinomialTreeBuilderTest {

    private static final double SPOT = 100;
    private static final double FORWARD;
    private static final double T = 5.0;
    private static final double BETA = 0.4;
    private static final YieldAndDiscountCurve YIELD_CURVE = YieldCurve.from(ConstantDoublesCurve.from(0.05));
    private static final double ATM_VOL = 0.20;
    private static final double SIGMA_BETA;
    private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1);
    private static final OptionDefinition OPTION;
    private static final BinomialTreeBuilder<GeneralLogNormalOptionDataBundle> BUILDER = new LogNormalBinomialTreeBuilder<>();
    private static final DriftSurface DRIFTLESS;
    private static final BlackImpliedVolatilityFormula BLACK_IMPLIED_VOL = new BlackImpliedVolatilityFormula();
    private static final CEVPriceFunction CEV_PRICE = new CEVPriceFunction();

    static {
        SIGMA_BETA = ATM_VOL * Math.pow(SPOT, 1 - BETA);
        FORWARD = SPOT / YIELD_CURVE.getDiscountFactor(T);
        OPTION = new EuropeanVanillaOptionDefinition(FORWARD,
                new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, T)), true);

        final Function<Double, Double> driftless = new Function<Double, Double>() {
            @Override
            public Double evaluate(final Double... tk) {
                Validate.isTrue(tk.length == 2);
                return 0.0;
            }
        };

        DRIFTLESS = new DriftSurface(FunctionalDoublesSurface.from(driftless));
    }

    private static final Function<Double, Double> FLAT_LOCAL_VOL = new Function<Double, Double>() {
        @Override
        public Double evaluate(final Double... tk) {
            Validate.isTrue(tk.length == 2);
            return ATM_VOL;
        }
    };

    private static final Function<Double, Double> TIME_DEPENDENT_LOCAL_VOL = new Function<Double, Double>() {
        @Override
        public Double evaluate(final Double... tk) {
            Validate.isTrue(tk.length == 2);
            final double t = tk[0];
            return (2 * ATM_VOL - t * ATM_VOL / T);
        }
    };

    private static final Function<Double, Double> CEV_LOCAL_VOL = new Function<Double, Double>() {
        @SuppressWarnings("synthetic-access")
        @Override
        public Double evaluate(final Double... tk) {
            Validate.isTrue(tk.length == 2);

            final double f = tk[1];
            final double sigma = SIGMA_BETA * Math.pow(f, BETA - 1);
            // return Math.min(sigma,100*ATM_VOL);
            return sigma;
        }
    };

    private static final GeneralLogNormalOptionDataBundle DATA = new GeneralLogNormalOptionDataBundle(YIELD_CURVE,
            DRIFTLESS, new VolatilitySurface(FunctionalDoublesSurface.from(FLAT_LOCAL_VOL)), FORWARD, DATE);

    @Test
    public void testPriceFlat() {
        final RecombiningBinomialTree<BinomialTreeNode<Double>> assetPriceTree = BUILDER.buildAssetTree(T, DATA,
                200);
        RecombiningBinomialTree<BinomialTreeNode<Double>> optionPriceTree = BUILDER.buildOptionPriceTree(OPTION,
                DATA, assetPriceTree);

        EuropeanVanillaOption o = new EuropeanVanillaOption(FORWARD, T, true);
        final BlackFunctionData data = new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), 0);
        double impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(data, o, optionPriceTree.getNode(0, 0).getValue());

        //double impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, FORWARD, YIELD_CURVE.getDiscountFactor(T), T, true);
        assertEquals(ATM_VOL, impVol, 1e-3);
        for (int i = 0; i < 10; i++) {
            final double m = -1.5 + 3.0 * i / 10.0;
            final double strike = FORWARD * Math.exp(ATM_VOL * Math.sqrt(T) * m);
            final OptionDefinition option = new EuropeanVanillaOptionDefinition(strike, OPTION.getExpiry(),
                    OPTION.isCall());
            optionPriceTree = BUILDER.buildOptionPriceTree(option, DATA, assetPriceTree);
            o = new EuropeanVanillaOption(strike, T, OPTION.isCall());
            optionPriceTree = BUILDER.buildOptionPriceTree(option, DATA, assetPriceTree);
            impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(data, o, optionPriceTree.getNode(0, 0).getValue());
            //      impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, strike, YIELD_CURVE.getDiscountFactor(T), T, true);
            // System.out.println(strike+"\t"+impVol);
            assertEquals(ATM_VOL, impVol, 1e-3);
        }
    }

    @Test
    public void testPriceTimeDependent() {
        final GeneralLogNormalOptionDataBundle data = new GeneralLogNormalOptionDataBundle(YIELD_CURVE, DRIFTLESS,
                new VolatilitySurface(FunctionalDoublesSurface.from(TIME_DEPENDENT_LOCAL_VOL)), FORWARD, DATE);
        final RecombiningBinomialTree<BinomialTreeNode<Double>> assetPriceTree = BUILDER.buildAssetTree(T, data,
                200);
        RecombiningBinomialTree<BinomialTreeNode<Double>> optionPriceTree = BUILDER.buildOptionPriceTree(OPTION,
                data, assetPriceTree);
        final double vol = Math.sqrt(7.0 / 3.0) * ATM_VOL;
        EuropeanVanillaOption o = new EuropeanVanillaOption(FORWARD, T, true);
        final BlackFunctionData bfd = new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), 0);
        double impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(bfd, o, optionPriceTree.getNode(0, 0).getValue());
        //    double impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, FORWARD, df, T, true);
        assertEquals(vol, impVol, 1e-3);
        for (int i = 0; i < 10; i++) {
            final double m = -1.5 + 3.0 * i / 10.0;
            final double strike = FORWARD * Math.exp(ATM_VOL * Math.sqrt(T) * m);
            final OptionDefinition option = new EuropeanVanillaOptionDefinition(strike, OPTION.getExpiry(),
                    OPTION.isCall());
            optionPriceTree = BUILDER.buildOptionPriceTree(option, data, assetPriceTree);
            o = new EuropeanVanillaOption(strike, T, OPTION.isCall());
            optionPriceTree = BUILDER.buildOptionPriceTree(option, DATA, assetPriceTree);
            impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(bfd, o, optionPriceTree.getNode(0, 0).getValue());
            //      impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, strike, df, T, true);
            // System.out.println(strike+"\t"+impVol);
            assertEquals(vol, impVol, 1e-3);
        }
    }

    @Test
    public void testCEV() {
        final GeneralLogNormalOptionDataBundle data = new GeneralLogNormalOptionDataBundle(YIELD_CURVE, DRIFTLESS,
                new VolatilitySurface(FunctionalDoublesSurface.from(CEV_LOCAL_VOL)), FORWARD, DATE);
        final RecombiningBinomialTree<BinomialTreeNode<Double>> assetPriceTree = BUILDER.buildAssetTree(T, data,
                200);
        RecombiningBinomialTree<BinomialTreeNode<Double>> optionPriceTree = BUILDER.buildOptionPriceTree(OPTION,
                data, assetPriceTree);
        EuropeanVanillaOption o = new EuropeanVanillaOption(FORWARD, T, true);
        final CEVFunctionData cfd = new CEVFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA,
                BETA);

        for (int i = 0; i < 10; i++) {
            final double m = -1.5 + 3.0 * i / 10.0;
            final double strike = FORWARD * Math.exp(ATM_VOL * Math.sqrt(T) * m);
            final OptionDefinition option = new EuropeanVanillaOptionDefinition(strike, OPTION.getExpiry(),
                    OPTION.isCall());
            optionPriceTree = BUILDER.buildOptionPriceTree(option, data, assetPriceTree);
            o = new EuropeanVanillaOption(strike, T, true);
            final double cevPrice = CEV_PRICE.getPriceFunction(o).evaluate(cfd);
            final double cevVol = BLACK_IMPLIED_VOL.getImpliedVolatility(
                    new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA), o, cevPrice);
            final double impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(
                    new BlackFunctionData(FORWARD, YIELD_CURVE.getDiscountFactor(T), SIGMA_BETA), o,
                    optionPriceTree.getNode(0, 0).getValue());
            //      final double cevPrice = CEVFormula.optionPrice(FORWARD, strike, BETA, df, SIGMA_BETA, T, true);
            //      final double cevVol = BlackImpliedVolFormula.impliedVol(cevPrice, FORWARD, strike, df, T, true);
            //      final double impVol = BlackImpliedVolFormula.impliedVol(optionPriceTree.getNode(0, 0).getValue(), FORWARD, strike, df, T, true);
            // System.out.println(strike + "\t" + cevVol  + "\t" + impVol);
            assertEquals(cevVol, impVol, 1e-3);
        }
    }

}