/** * 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 static org.testng.Assert.assertEquals; import static org.testng.AssertJUnit.assertFalse; import static org.testng.AssertJUnit.assertTrue; import org.testng.annotations.Test; import com.opengamma.analytics.financial.greeks.Greek; import com.opengamma.analytics.financial.greeks.GreekResultCollection; import com.opengamma.analytics.financial.model.volatility.BlackScholesFormulaRepository; import com.opengamma.analytics.math.statistics.distribution.NormalDistribution; import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution; import com.opengamma.util.test.TestGroup; /** * American type of single barrier option */ @Test(groups = TestGroup.UNIT) public class AmericanSingleBarrierOptionFunctionProviderTest { private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1); private static final BinomialTreeOptionPricingModel _model = new BinomialTreeOptionPricingModel(); private static final TrinomialTreeOptionPricingModel _modelTrinomial = new TrinomialTreeOptionPricingModel(); private static final double SPOT = 105.; private static final double[] STRIKES = new double[] {97., 105., 114. }; private static final double TIME = 4.2; private static final double[] VOLS = new double[] {0.05, 0.1, 0.5 }; private static final double[] INTERESTS = new double[] {0.01, 0.05 }; private static final double[] DIVIDENDS = new double[] {0.005, 0.02 }; /** * */ @Test public void putCallSymmetryTest() { /* * Two sample lattices are checked */ final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new LeisenReimerLatticeSpecification() }; final int steps = 251; final double[] barrierSet = new double[] {92, 116 }; AmericanSingleBarrierOptionFunctionProvider.BarrierTypes dao = AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.valueOf("DownAndOut"); AmericanSingleBarrierOptionFunctionProvider.BarrierTypes uao = AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.valueOf("UpAndOut"); for (final double strike : STRIKES) { for (final double barrier : barrierSet) { final OptionFunctionProvider1D functionCall = new AmericanSingleBarrierOptionFunctionProvider(strike, TIME, steps, true, barrier, dao); final OptionFunctionProvider1D functionPut = new AmericanSingleBarrierOptionFunctionProvider(SPOT * SPOT / strike, TIME, steps, false, SPOT * SPOT / barrier, uao); for (final double interest : INTERESTS) { for (final double vol : VOLS) { for (final double dividend : DIVIDENDS) { for (final LatticeSpecification lattice : lattices) { final GreekResultCollection greekCall = _model.getGreeks(lattice, functionCall, SPOT, vol, interest, dividend); final GreekResultCollection greekPut = _model.getGreeks(lattice, functionPut, SPOT, vol, dividend, interest); final double priceCall = greekCall.get(Greek.FAIR_PRICE); final double thetaCall = greekCall.get(Greek.THETA); final double pricePut = greekPut.get(Greek.FAIR_PRICE); final double thetaPut = greekPut.get(Greek.THETA); final double refPrice = strike * pricePut / SPOT; final double refTheta = strike * thetaPut / SPOT; assertEquals(priceCall, refPrice, Math.max(refPrice, 1.) * 1.e-5); assertEquals(thetaCall, refTheta, Math.max(Math.abs(refTheta), 1.) * 1.e-2); } } } } } } } /** * Check the case when analytic approximation is available */ @Test public void priceTest() { final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(), new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification(), new LeisenReimerLatticeSpecification() }; final double[] vols = new double[] {0.1, 0.15 }; final double time = 0.1; final int nSteps = 511; final double[] barrierSet = new double[] {90, 121 }; final String[] typeSet = new String[] {"DownAndOut", "UpAndOut" }; final boolean[] tfSet = new boolean[] {true, false }; for (final double barrier : barrierSet) { for (final String type : typeSet) { for (final LatticeSpecification lattice : lattices) { for (final boolean isCall : tfSet) { for (final double strike : STRIKES) { for (final double interest : INTERESTS) { for (final double vol : vols) { for (final double dividend : DIVIDENDS) { final OptionFunctionProvider1D function = new AmericanSingleBarrierOptionFunctionProvider(strike, time, nSteps, isCall, barrier, AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.valueOf(type)); if (type == "DownAndOut") { if (strike > barrier) { double exact = isCall ? getA(SPOT, strike, time, vol, interest, dividend, 1.) - getC(SPOT, strike, time, vol, interest, dividend, barrier, 1., 1.) : getA( SPOT, strike, time, vol, interest, dividend, -1.) - getB(SPOT, strike, time, vol, interest, dividend, barrier, -1.) + getC(SPOT, strike, time, vol, interest, dividend, barrier, -1., 1.) - getD(SPOT, strike, time, vol, interest, dividend, barrier, -1., 1.); exact = exact < 0. ? 0. : exact; final double res = _model.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(res, exact, Math.max(exact, 1.) * 1.e-1); if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) { final double resTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(resTrinomial, exact, Math.max(exact, 1.) * 1.e-1); } } else { double exact = isCall ? getB(SPOT, strike, time, vol, interest, dividend, barrier, 1.) - getD(SPOT, strike, time, vol, interest, dividend, barrier, 1., 1.) : 0.; exact = exact < 0. ? 0. : exact; final double res = _model.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(res, exact, Math.max(exact, 1.) * 1.e-1); if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) { final double resTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(resTrinomial, exact, Math.max(exact, 1.) * 1.e-2); } } } else { if (strike < barrier) { double exact = !isCall ? getA(SPOT, strike, time, vol, interest, dividend, -1.) - getC(SPOT, strike, time, vol, interest, dividend, barrier, -1., -1.) : getA( SPOT, strike, time, vol, interest, dividend, 1.) - getB(SPOT, strike, time, vol, interest, dividend, barrier, 1.) + getC(SPOT, strike, time, vol, interest, dividend, barrier, 1., -1.) - getD(SPOT, strike, time, vol, interest, dividend, barrier, 1., -1.); exact = exact < 0. ? 0. : exact; final double res = _model.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(res, exact, Math.max(exact, 1.) * 1.e-1); if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) { final double resTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(resTrinomial, exact, Math.max(exact, 1.) * 1.e-1); } } else { double exact = !isCall ? getB(SPOT, strike, time, vol, interest, dividend, barrier, -1.) - getD(SPOT, strike, time, vol, interest, dividend, barrier, -1., -1.) : 0.; exact = exact < 0. ? 0. : exact; final double res = _model.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(res, exact, Math.max(exact, 1.) * 1.e-1); if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) { final double resTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, dividend); assertEquals(resTrinomial, exact, Math.max(exact, 1.) * 1.e-2); } } } } } } } } } } } } /** * */ @Test public void discreteDividendsPriceTest() { final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(), new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification(), new LeisenReimerLatticeSpecification() }; final double eps = 1.e-1; final double[] propDividends = new double[] {0.002, 0.004, 0.001 }; final double[] cashDividends = new double[] {.2, .3, .2 }; final double time = 0.05; final double[] dividendTimes = new double[] {time / 6., time / 3., time / 2. }; final double[] vols = new double[] {0.1, 0.15 }; final double[] barrierSet = new double[] {90, 121 }; final String[] typeSet = new String[] {"DownAndOut", "UpAndOut" }; final boolean[] tfSet = new boolean[] {true, false }; for (final double barrier : barrierSet) { for (final String type : typeSet) { for (final LatticeSpecification lattice : lattices) { for (final boolean isCall : tfSet) { for (final double strike : STRIKES) { for (final double interest : INTERESTS) { for (final double vol : vols) { final int nSteps = 311; final OptionFunctionProvider1D function = new AmericanSingleBarrierOptionFunctionProvider(strike, time, nSteps, isCall, barrier, AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.valueOf(type)); final double resSpot = SPOT * (1. - propDividends[0]) * (1. - propDividends[1]) * (1. - propDividends[2]); final double modSpot = SPOT - cashDividends[0] * Math.exp(-interest * dividendTimes[0]) - cashDividends[1] * Math.exp(-interest * dividendTimes[1]) - cashDividends[2] * Math.exp(-interest * dividendTimes[2]); final DividendFunctionProvider cashDividend = new CashDividendFunctionProvider(dividendTimes, cashDividends); final DividendFunctionProvider propDividend = new ProportionalDividendFunctionProvider(dividendTimes, propDividends); final double resMod = _model.getPrice(lattice, function, SPOT, vol, interest, cashDividend); final double resRes = _model.getPrice(lattice, function, SPOT, vol, interest, propDividend); double resModTrinomial = 0.; double resResTrinomial = 0.; /** * In at-the-money case trinomial tree produces poor approximation, excluded */ final boolean canBeTrinomial = (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) && strike != STRIKES[1]; if (canBeTrinomial) { resModTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, cashDividend); resResTrinomial = _modelTrinomial.getPrice(lattice, function, SPOT, vol, interest, propDividend); final GreekResultCollection greekMod = _model.getGreeks(lattice, function, SPOT, vol, interest, cashDividend); final GreekResultCollection greekRes = _model.getGreeks(lattice, function, SPOT, vol, interest, propDividend); final GreekResultCollection greekModTrinomial = _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, cashDividend); final GreekResultCollection greekResTrinomial = _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, propDividend); assertEquals(resModTrinomial, resMod, Math.max(resMod, 1.) * eps * eps); assertEquals(resResTrinomial, resRes, Math.max(resRes, 1.) * eps * eps); assertEquals(greekModTrinomial.get(Greek.FAIR_PRICE), greekMod.get(Greek.FAIR_PRICE), Math.max(Math.abs(greekMod.get(Greek.FAIR_PRICE)), 1.) * eps * eps); assertEquals(greekModTrinomial.get(Greek.DELTA), greekMod.get(Greek.DELTA), Math.max(Math.abs(greekMod.get(Greek.DELTA)), 1.) * eps * eps); assertEquals(greekModTrinomial.get(Greek.GAMMA), greekMod.get(Greek.GAMMA), Math.max(Math.abs(greekMod.get(Greek.GAMMA)), 1.) * eps * eps); assertEquals(greekModTrinomial.get(Greek.THETA), greekMod.get(Greek.THETA), Math.max(Math.abs(greekMod.get(Greek.THETA)), 1.) * eps * eps); assertEquals(greekResTrinomial.get(Greek.FAIR_PRICE), greekRes.get(Greek.FAIR_PRICE), Math.max(Math.abs(greekRes.get(Greek.FAIR_PRICE)), 1.) * eps * eps); assertEquals(greekResTrinomial.get(Greek.DELTA), greekRes.get(Greek.DELTA), Math.max(Math.abs(greekRes.get(Greek.DELTA)), 1.) * eps * eps); assertEquals(greekResTrinomial.get(Greek.GAMMA), greekRes.get(Greek.GAMMA), Math.max(Math.abs(greekRes.get(Greek.GAMMA)), 1.) * eps * eps); assertEquals(greekResTrinomial.get(Greek.THETA), greekRes.get(Greek.THETA), Math.max(Math.abs(greekRes.get(Greek.THETA)), 1.) * eps * eps); } if (type == "DownAndOut") { if (strike > barrier) { double exactMod = isCall ? getA(modSpot, strike, time, vol, interest, 0., 1.) - getC(modSpot, strike, time, vol, interest, 0., barrier, 1., 1.) : getA( modSpot, strike, time, vol, interest, 0., -1.) - getB(modSpot, strike, time, vol, interest, 0., barrier, -1.) + getC(modSpot, strike, time, vol, interest, 0., barrier, -1., 1.) - getD(modSpot, strike, time, vol, interest, 0., barrier, -1., 1.); exactMod = barrier >= SPOT ? 0. : exactMod; assertEquals(resMod, exactMod, Math.max(exactMod, 1.) * eps); double exactRes = isCall ? getA(resSpot, strike, time, vol, interest, 0., 1.) - getC(resSpot, strike, time, vol, interest, 0., barrier, 1., 1.) : getA( resSpot, strike, time, vol, interest, 0., -1.) - getB(resSpot, strike, time, vol, interest, 0., barrier, -1.) + getC(resSpot, strike, time, vol, interest, 0., barrier, -1., 1.) - getD(resSpot, strike, time, vol, interest, 0., barrier, -1., 1.); exactRes = barrier >= SPOT ? 0. : exactRes; assertEquals(resRes, exactRes, Math.max(exactRes, 1.) * eps); } else { double exactMod = isCall ? getB(modSpot, strike, time, vol, interest, 0., barrier, 1.) - getD(modSpot, strike, time, vol, interest, 0., barrier, 1., 1.) : 0.; exactMod = barrier >= SPOT ? 0. : exactMod; assertEquals(resMod, exactMod, Math.max(exactMod, 1.) * eps); double exactRes = isCall ? getB(resSpot, strike, time, vol, interest, 0., barrier, 1.) - getD(resSpot, strike, time, vol, interest, 0., barrier, 1., 1.) : 0.; exactRes = barrier >= SPOT ? 0. : exactRes; assertEquals(resRes, exactRes, Math.max(exactRes, 1.) * eps); } } else { if (strike < barrier) { double exactMod = !isCall ? getA(modSpot, strike, time, vol, interest, 0., -1.) - getC(modSpot, strike, time, vol, interest, 0., barrier, -1., -1.) : getA( modSpot, strike, time, vol, interest, 0., 1.) - getB(modSpot, strike, time, vol, interest, 0., barrier, 1.) + getC(modSpot, strike, time, vol, interest, 0., barrier, 1., -1.) - getD(modSpot, strike, time, vol, interest, 0., barrier, 1., -1.); exactMod = barrier <= SPOT ? 0. : exactMod; assertEquals(resMod, exactMod, Math.max(exactMod, 1.) * eps); double exactRes = !isCall ? getA(resSpot, strike, time, vol, interest, 0., -1.) - getC(resSpot, strike, time, vol, interest, 0., barrier, -1., -1.) : getA( resSpot, strike, time, vol, interest, 0., 1.) - getB(resSpot, strike, time, vol, interest, 0., barrier, 1.) + getC(resSpot, strike, time, vol, interest, 0., barrier, 1., -1.) - getD(resSpot, strike, time, vol, interest, 0., barrier, 1., -1.); exactRes = exactRes < 0. ? 0. : exactRes; exactRes = barrier <= SPOT ? 0. : exactRes; assertEquals(resRes, exactRes, Math.max(exactRes, 1.) * eps); } else { double exactMod = !isCall ? getB(modSpot, strike, time, vol, interest, 0., barrier, -1.) - getD(modSpot, strike, time, vol, interest, 0., barrier, -1., -1.) : 0.; exactMod = barrier <= SPOT ? 0. : exactMod; assertEquals(resMod, exactMod, Math.max(exactMod, 1.) * eps); double exactRes = !isCall ? getB(resSpot, strike, time, vol, interest, 0., barrier, -1.) - getD(resSpot, strike, time, vol, interest, 0., barrier, -1., -1.) : 0.; exactRes = exactRes < 0. ? 0. : exactRes; exactRes = barrier <= SPOT ? 0. : exactRes; assertEquals(resRes, exactRes, Math.max(exactRes, 1.) * eps); } } } } } } } } } } /** * Greeks test for trinomial is also included */ @Test public void timeVaryingVolTest() { final LatticeSpecification lattice1 = new TimeVaryingLatticeSpecification(); final double[] time_set = new double[] {0.5, 1.2 }; final int steps = 797; final double[] vol = new double[steps]; final double[] rate = new double[steps]; final double[] dividend = new double[steps]; final int stepsTri = 727; final double[] volTri = new double[stepsTri]; final double[] rateTri = new double[stepsTri]; final double[] dividendTri = new double[stepsTri]; final double constA = 0.01; final double constB = 0.001; final double constC = 0.1; final double constD = 0.05; final boolean[] tfSet = new boolean[] {true, false }; for (final boolean isCall : tfSet) { for (final double strike : STRIKES) { for (final double time : time_set) { for (int i = 0; i < steps; ++i) { rate[i] = constA + constB * i * time / steps; vol[i] = constC + constD * Math.sin(i * time / steps); dividend[i] = 0.005; } for (int i = 0; i < stepsTri; ++i) { rateTri[i] = constA + constB * i * time / steps; volTri[i] = constC + constD * Math.sin(i * time / steps); dividendTri[i] = 0.005; } final double rateRef = constA + 0.5 * constB * time; final double volRef = Math.sqrt(constC * constC + 0.5 * constD * constD + 2. * constC * constD / time * (1. - Math.cos(time)) - constD * constD * 0.25 / time * Math.sin(2. * time)); final double[] barrierSet = new double[] {SPOT * 0.9, SPOT * 1.15 }; for (final double barrier : barrierSet) { final OptionFunctionProvider1D functionBarrierDown = new AmericanSingleBarrierOptionFunctionProvider(strike, time, steps, isCall, barrier, AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.DownAndOut); final OptionFunctionProvider1D functionBarrierUp = new AmericanSingleBarrierOptionFunctionProvider(strike, time, steps, isCall, barrier, AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.UpAndOut); final double resPriceBarrierDown = _model.getPrice(functionBarrierDown, SPOT, vol, rate, dividend); final GreekResultCollection resGreeksBarrierDown = _model.getGreeks(functionBarrierDown, SPOT, vol, rate, dividend); final double resPriceConstBarrierDown = _model.getPrice(lattice1, functionBarrierDown, SPOT, volRef, rateRef, dividend[0]); final GreekResultCollection resGreeksConstBarrierDown = _model.getGreeks(lattice1, functionBarrierDown, SPOT, volRef, rateRef, dividend[0]); assertEquals(resPriceBarrierDown, resPriceConstBarrierDown, Math.max(Math.abs(resPriceConstBarrierDown), 0.1) * 1.e-1); assertEquals(resGreeksBarrierDown.get(Greek.FAIR_PRICE), resGreeksConstBarrierDown.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals(resGreeksBarrierDown.get(Greek.DELTA), resGreeksConstBarrierDown.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.DELTA)), 0.1) * 0.1); assertEquals(resGreeksBarrierDown.get(Greek.GAMMA), resGreeksConstBarrierDown.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals(resGreeksBarrierDown.get(Greek.THETA), resGreeksConstBarrierDown.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.THETA)), 0.1)); final double resPriceBarrierUp = _model.getPrice(functionBarrierUp, SPOT, vol, rate, dividend); final GreekResultCollection resGreeksBarrierUp = _model.getGreeks(functionBarrierUp, SPOT, vol, rate, dividend); final double resPriceConstBarrierUp = _model.getPrice(lattice1, functionBarrierUp, SPOT, volRef, rateRef, dividend[0]); final GreekResultCollection resGreeksConstBarrierUp = _model.getGreeks(lattice1, functionBarrierUp, SPOT, volRef, rateRef, dividend[0]); assertEquals(resPriceBarrierUp, resPriceConstBarrierUp, Math.max(Math.abs(resPriceConstBarrierUp), 0.1) * 1.e-1); assertEquals(resGreeksBarrierUp.get(Greek.FAIR_PRICE), resGreeksConstBarrierUp.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals(resGreeksBarrierUp.get(Greek.DELTA), resGreeksConstBarrierUp.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.DELTA)), 0.1) * 0.1); assertEquals(resGreeksBarrierUp.get(Greek.GAMMA), resGreeksConstBarrierUp.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals(resGreeksBarrierUp.get(Greek.THETA), resGreeksConstBarrierUp.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.THETA)), 0.1)); final OptionFunctionProvider1D functionBarrierDownTri = new AmericanSingleBarrierOptionFunctionProvider(strike, time, stepsTri, isCall, barrier, EuropeanSingleBarrierOptionFunctionProvider.BarrierTypes.DownAndOut); final OptionFunctionProvider1D functionBarrierUpTri = new AmericanSingleBarrierOptionFunctionProvider(strike, time, stepsTri, isCall, barrier, EuropeanSingleBarrierOptionFunctionProvider.BarrierTypes.UpAndOut); final double resPriceBarrierDownTri = _modelTrinomial.getPrice(functionBarrierDownTri, SPOT, volTri, rateTri, dividendTri); final GreekResultCollection resGreeksBarrierDownTri = _modelTrinomial.getGreeks(functionBarrierDownTri, SPOT, volTri, rateTri, dividendTri); assertEquals(resPriceBarrierDownTri, resPriceConstBarrierDown, Math.max(Math.abs(resPriceConstBarrierDown), 1.) * 1.e-1); assertEquals(resGreeksBarrierDownTri.get(Greek.FAIR_PRICE), resGreeksConstBarrierDown.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.FAIR_PRICE)), 1.) * 0.1); assertEquals(resGreeksBarrierDownTri.get(Greek.DELTA), resGreeksConstBarrierDown.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.DELTA)), 1.) * 0.1); assertEquals(resGreeksBarrierDownTri.get(Greek.GAMMA), resGreeksConstBarrierDown.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.GAMMA)), 1.) * 0.1); assertEquals(resGreeksBarrierDownTri.get(Greek.THETA), resGreeksConstBarrierDown.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.THETA)), 1.)); final double resPriceBarrierUpTri = _modelTrinomial.getPrice(functionBarrierUpTri, SPOT, volTri, rateTri, dividendTri); final GreekResultCollection resGreeksBarrierUpTri = _modelTrinomial.getGreeks(functionBarrierUpTri, SPOT, volTri, rateTri, dividendTri); assertEquals(resPriceBarrierUpTri, resPriceConstBarrierUp, Math.max(Math.abs(resPriceConstBarrierUp), 1.) * 1.e-1); assertEquals(resGreeksBarrierUpTri.get(Greek.FAIR_PRICE), resGreeksConstBarrierUp.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.FAIR_PRICE)), 1.) * 0.1); assertEquals(resGreeksBarrierUpTri.get(Greek.DELTA), resGreeksConstBarrierUp.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.DELTA)), 1.) * 0.1); assertEquals(resGreeksBarrierUpTri.get(Greek.GAMMA), resGreeksConstBarrierUp.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.GAMMA)), 1.) * 0.1); assertEquals(resGreeksBarrierUpTri.get(Greek.THETA), resGreeksConstBarrierUp.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.THETA)), 1.)); final LatticeSpecification[] lattices = new LatticeSpecification[] {new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(), new TianLatticeSpecification() }; for (final LatticeSpecification lattice : lattices) { final GreekResultCollection resGreeksBarrierDownTriRe = _modelTrinomial.getGreeks(lattice, functionBarrierDown, SPOT, volRef, rateRef, dividend[0]); assertEquals(resGreeksBarrierDownTriRe.get(Greek.FAIR_PRICE), resGreeksConstBarrierDown.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals(resGreeksBarrierDownTriRe.get(Greek.DELTA), resGreeksConstBarrierDown.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.DELTA)), 0.1) * 0.1); assertEquals(resGreeksBarrierDownTriRe.get(Greek.GAMMA), resGreeksConstBarrierDown.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals(resGreeksBarrierDownTriRe.get(Greek.THETA), resGreeksConstBarrierDown.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierDown.get(Greek.THETA)), 0.1)); final GreekResultCollection resGreeksBarrierUpTriRe = _modelTrinomial.getGreeks(lattice, functionBarrierUp, SPOT, volRef, rateRef, dividend[0]); assertEquals(resGreeksBarrierUpTriRe.get(Greek.FAIR_PRICE), resGreeksConstBarrierUp.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals(resGreeksBarrierUpTriRe.get(Greek.DELTA), resGreeksConstBarrierUp.get(Greek.DELTA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.DELTA)), 0.1) * 0.1); assertEquals(resGreeksBarrierUpTriRe.get(Greek.GAMMA), resGreeksConstBarrierUp.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals(resGreeksBarrierUpTriRe.get(Greek.THETA), resGreeksConstBarrierUp.get(Greek.THETA), Math.max(Math.abs(resGreeksConstBarrierUp.get(Greek.THETA)), 0.1)); } } } } } } /** * */ @Test public void hashCodeEqualsTest() { final AmericanSingleBarrierOptionFunctionProvider.BarrierTypes type = AmericanSingleBarrierOptionFunctionProvider.BarrierTypes.valueOf("DownAndOut"); final OptionFunctionProvider1D ref = new AmericanSingleBarrierOptionFunctionProvider(100., 1., 53, true, 90., type); final OptionFunctionProvider1D[] function = new OptionFunctionProvider1D[] {ref, new AmericanSingleBarrierOptionFunctionProvider(100., 1., 53, true, 90., type), new EuropeanVanillaOptionFunctionProvider(100., 1., 53, true), null }; final int len = function.length; for (int i = 0; i < len; ++i) { if (ref.equals(function[i])) { assertTrue(ref.hashCode() == function[i].hashCode()); } } for (int i = 0; i < len - 1; ++i) { assertTrue(function[i].equals(ref) == ref.equals(function[i])); } assertFalse(ref.equals(new EuropeanSpreadOptionFunctionProvider(100., 1., 53, true))); } private double getA(final double spot, final double strike, final double time, final double vol, final double interest, final double dividend, final double phi) { final boolean isCall = (phi == 1.); return BlackScholesFormulaRepository.price(spot, strike, time, vol, interest, interest - dividend, isCall); } private double getB(final double spot, final double strike, final double time, final double vol, final double interest, final double dividend, final double barrier, final double phi) { final double sigmaRootT = vol * Math.sqrt(time); final double x2 = (Math.log(spot / barrier) + interest * time - dividend * time) / sigmaRootT + 0.5 * sigmaRootT; final double x2M = x2 - sigmaRootT; return phi * (spot * Math.exp(-dividend * time) * NORMAL.getCDF(phi * x2) - strike * Math.exp(-interest * time) * NORMAL.getCDF(phi * x2M)); } private double getC(final double spot, final double strike, final double time, final double vol, final double interest, final double dividend, final double barrier, final double phi, final double eta) { final boolean isCall = (eta == 1.); final double mu = (interest - dividend) / vol / vol - 0.5; return phi * eta * BlackScholesFormulaRepository.price(barrier * barrier / spot, strike, time, vol, interest, interest - dividend, isCall) * Math.pow(barrier / spot, 2. * mu); } private double getD(final double spot, final double strike, final double time, final double vol, final double interest, final double dividend, final double barrier, final double phi, final double eta) { final double sigmaRootT = vol * Math.sqrt(time); final double y2 = (Math.log(barrier / spot) + interest * time - dividend * time) / sigmaRootT + 0.5 * sigmaRootT; final double y2M = y2 - sigmaRootT; final double mu = (interest - dividend) / vol / vol - 0.5; return phi * (spot * Math.exp(-dividend * time) * Math.pow(barrier / spot, 2. * mu + 2.) * NORMAL.getCDF(eta * y2) - strike * Math.exp(-interest * time) * Math.pow(barrier / spot, 2. * mu) * NORMAL.getCDF(eta * y2M)); } }