/** * Copyright (C) 2013 - 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 org.testng.annotations.Test; import com.opengamma.util.test.TestGroup; /** * Tests below hit argumentCheckers in {@link BinomialTreeOptionPricingModel}. * Successful tests are given in test classes of respective subclasses of {@link OptionFunctionProvider1D} or {@link OptionFunctionProvider2D} */ @Test(groups = TestGroup.UNIT) public class BinomialTreeOptionPricingModelTest { private static final BinomialTreeOptionPricingModel _model = new BinomialTreeOptionPricingModel(); private static final LatticeSpecification _lattice = new CoxRossRubinsteinLatticeSpecification(); private static final int STEPS = 85; private static final OptionFunctionProvider1D _function1D = new EuropeanVanillaOptionFunctionProvider(105.1, 4.2, STEPS, false); private static final OptionFunctionProvider2D _function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 4.2, STEPS, false); private static final double SPOT = 105.; private static final double INTEREST = 0.05; private static final double VOL = 0.3; private static final double DIVIDEND = 0.02; private static final double[] INTERESTS = new double[STEPS]; private static final double[] VOLS = new double[STEPS]; private static final double[] DIVIDENDS = new double[STEPS]; static { for (int i = 0; i < STEPS; ++i) { INTERESTS[i] = INTEREST + 0.01 * Math.sin(i); VOLS[i] = VOL + 0.05 * Math.sin(i); DIVIDENDS[i] = DIVIDEND; } } private static final double[] _cashDividends = new double[] {.1, .3, .2 }; private static final double[] _dividendTimes = new double[] {4.2 / 6., 4.2 / 3., 4.2 / 2. }; private static final DividendFunctionProvider _cashDividend = new CashDividendFunctionProvider(_dividendTimes, _cashDividends); /* * Tests for getPrice with constant parameters */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetPriceTest() { _model.getPrice(_lattice, _function1D, -SPOT, VOL, INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetPriceTest() { _model.getPrice(_lattice, _function1D, SPOT, -VOL, INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetPriceTest() { _model.getPrice(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetPriceTest() { _model.getPrice(_lattice, _function1D, SPOT, 0.001, INTEREST, DIVIDEND); } /* * Tests for getPrice with time-varying parameters */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetPriceVaryingTest() { _model.getPrice(_function1D, -SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetPriceVaryingTest() { VOLS[2] = -0.6; _model.getPrice(_function1D, SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetPriceVaryingTest() { final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(105.1, 4.2e18, STEPS, false); VOLS[2] = 1.e-9; _model.getPrice(function, SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongRateLengthVaryingTest() { _model.getPrice(_function1D, SPOT, VOLS, new double[] {INTEREST }, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongDividendLengthVaryingTest() { _model.getPrice(_function1D, SPOT, VOLS, INTERESTS, new double[] {DIVIDEND }); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongVolsLengthVaryingTest() { _model.getPrice(_function1D, SPOT, new double[] {VOL }, INTERESTS, DIVIDENDS); } /* * Tests for getPrice with dividend provider */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetPriceDivTest() { _model.getPrice(_lattice, _function1D, -SPOT, VOL, INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetPriceDivTest() { _model.getPrice(_lattice, _function1D, SPOT, -VOL, INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetPriceDivTest() { _model.getPrice(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetPriceDivTest() { _model.getPrice(_lattice, _function1D, SPOT, 0.001, INTEREST, _cashDividend); } /* * Tests for getPrice on two assets */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot1GetPriceTwoAssetTest() { _model.getPrice(_function2D, -SPOT, SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot2GetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, -SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol1GetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, -VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol2GetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, -VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeUUProbability2GetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, VOL, 0.5, 100. * INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeUDProbabilityGetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, 100. * DIVIDEND, -100. * DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeUDProbability2GetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, -100. * DIVIDEND, 200. * DIVIDEND); } /** * Note that the remaining 2 branches are unlikely to be hit */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeDUProbabilityGetPriceTwoAssetTest() { final double vol = 10000.; final double vol2 = 10000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getPrice(function2D, SPOT, SPOT, vol - 1.1, vol2 - 1, 0., -vol - 0.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeDDProbabilityGetPriceTwoAssetTest() { final double vol = 10000000.; final double vol2 = 10000000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getPrice(function2D, SPOT, SPOT, vol - 1.01, vol2 - 1., 0., -vol + 2.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void smallCorrelationGetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, VOL, -21.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeCorrelationGetPriceTwoAssetTest() { _model.getPrice(_function2D, SPOT, SPOT, VOL, VOL, 11.5, INTEREST, DIVIDEND, DIVIDEND); } /* * Tests for getGreeks with constant parameters */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksTest() { _model.getGreeks(_lattice, _function1D, -SPOT, VOL, INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, -VOL, INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.001, INTEREST, DIVIDEND); } /* * Tests for getGreeks with dividend provider */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, -SPOT, VOL, INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, -VOL, INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeProbabilityGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.01, -10. * INTEREST, _cashDividend); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksDivTest() { _model.getGreeks(_lattice, _function1D, SPOT, 0.001, INTEREST, _cashDividend); } /* * Tests for getGreeks with time-varying parameters */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpotGetGreeksVaryingTest() { _model.getGreeks(_function1D, -SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVolGetGreeksVaryingTest() { VOLS[2] = -VOLS[2]; _model.getGreeks(_function1D, SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeProbabilityGetGreeksVaryingTest() { final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(105.1, 4.2e18, STEPS, false); VOLS[2] = 1.e-9; _model.getGreeks(function, SPOT, VOLS, INTERESTS, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongRateLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, VOLS, new double[] {INTEREST }, DIVIDENDS); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongDividendLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, VOLS, INTERESTS, new double[] {DIVIDEND }); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void wrongVolsLengthGreeksVaryingTest() { _model.getGreeks(_function1D, SPOT, new double[] {VOL }, INTERESTS, DIVIDENDS); } /* * Tests for getGreeks on two assets */ /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot1GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, -SPOT, SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeSpot2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, -SPOT, VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol1GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, -VOL, VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeVol2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, -VOL, 0.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeUUProbability2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, 100. * INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeUDProbabilityGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, 100. * DIVIDEND, -100. * DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeUDProbability2GetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 0.5, INTEREST, -100. * DIVIDEND, 200. * DIVIDEND); } /** * Note that the remaining 2 branches are unlikely to be hit */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeDUProbabilityGetGreeksTwoAssetTest() { final double vol = 10000.; final double vol2 = 10000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getGreeks(function2D, SPOT, SPOT, vol - 1.1, vol2 - 1, 0., -vol - 0.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void negativeDDProbabilityGetGreeksTwoAssetTest() { final double vol = 10000000.; final double vol2 = 10000000.; final OptionFunctionProvider2D function2D = new EuropeanSpreadOptionFunctionProvider(105.1, 10., 10, false); _model.getGreeks(function2D, SPOT, SPOT, vol - 1.01, vol2 - 1., 0., -vol + 2.1, -0.5 * vol * vol, -vol2 - 0.5 * vol2 * vol2); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void smallCorrelationGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, -21.5, INTEREST, DIVIDEND, DIVIDEND); } /** * */ @Test(expectedExceptions = IllegalArgumentException.class) public void largeCorrelationGetGreeksTwoAssetTest() { _model.getGreeks(_function2D, SPOT, SPOT, VOL, VOL, 11.5, INTEREST, DIVIDEND, DIVIDEND); } }