private void assertPriceEquals( final PoweredOptionDefinition poweredDefinition, final double sigma, final double price) { final StandardOptionDataBundle bundle = getBundle(sigma); final GreekResultCollection actual = POWERED_MODEL.getGreeks(poweredDefinition, bundle, REQUIRED_GREEKS); assertEquals(price, actual.get(Greek.FAIR_PRICE), BIG_EPS * price); }
private void assertPriceEquals( final PoweredOptionDefinition poweredDefinition, final EuropeanVanillaOptionDefinition vanillaDefinition, final double sigma) { final StandardOptionDataBundle bundle = getBundle(sigma); final GreekResultCollection actual = POWERED_MODEL.getGreeks(poweredDefinition, bundle, REQUIRED_GREEKS); final GreekResultCollection expected = BSM.getGreeks(vanillaDefinition, bundle, REQUIRED_GREEKS); assertEquals(expected.get(Greek.FAIR_PRICE), actual.get(Greek.FAIR_PRICE), SMALL_EPS); }
@Test public void greekTest() { final LatticeSpecification[] lattices = new LatticeSpecification[] { new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(), new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification() }; final boolean[] tfSet = new boolean[] {true, false}; 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[] choicesSteps = new int[] {31, 112, 301}; for (final int nSteps : choicesSteps) { for (final double dividend : DIVIDENDS) { final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall); final GreekResultCollection resDiv = _model.getGreeks(lattice, function, SPOT, vol, interest, dividend); final double priceDiv = BlackScholesFormulaRepository.price( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) / Math.sqrt(nSteps); assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv); final double deltaDiv = BlackScholesFormulaRepository.delta( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) / Math.sqrt(nSteps); assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv); final double gammaDiv = BlackScholesFormulaRepository.gamma( SPOT, strike, TIME, vol, interest, interest - dividend); final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) / Math.sqrt(nSteps); assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv); final double thetaDiv = BlackScholesFormulaRepository.theta( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) / Math.sqrt(nSteps); assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv); } } } } } } } }
@Override public GreekResultCollection visitEquityOption( final EquityOption option, final StaticReplicationDataBundle data) { ArgChecker.notNull(option, "option"); ArgChecker.notNull(data, "data"); final double k = option.getStrike(); final double t = option.getTimeToExpiry(); final boolean isCall = option.isCall(); final double volatility = data.getVolatilitySurface().getVolatility(t, k); final double r = data.getDiscountCurve().getInterestRate(t); final double spot = data.getForwardCurve().getSpot(); final double fwd = data.getForwardCurve().getForward(t); final double b; if (t > 0) { b = Math.log(fwd / spot) / t; } else { b = r; // TODO } final double[] greeks = MODEL.getPriceAdjoint(spot, k, r, b, t, volatility, isCall); final GreekResultCollection result = new GreekResultCollection(); result.put(Greek.DELTA, greeks[1]); result.put(Greek.DUAL_DELTA, greeks[2]); result.put(Greek.RHO, greeks[3]); result.put(Greek.CARRY_RHO, greeks[4]); result.put(Greek.THETA, greeks[5]); result.put(Greek.VEGA, greeks[6]); final double[] pdg = MODEL.getPriceDeltaGamma(spot, k, r, b, t, volatility, isCall); result.put(Greek.GAMMA, pdg[2]); return result; }
@Test public void greekLeisenReimerTest() { final LatticeSpecification lattice = new LeisenReimerLatticeSpecification(); final boolean[] tfSet = new boolean[] {true, false}; for (final boolean isCall : tfSet) { for (final double strike : STRIKES) { for (final double interest : INTERESTS) { for (final double vol : VOLS) { final int[] choicesSteps = new int[] {31, 109, 301}; for (final int nSteps : choicesSteps) { for (final double dividend : DIVIDENDS) { final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall); final GreekResultCollection resDiv = _model.getGreeks(lattice, function, SPOT, vol, interest, dividend); final double priceDiv = BlackScholesFormulaRepository.price( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refPriceDiv = Math.max(Math.abs(priceDiv), 1.) / nSteps; assertEquals(resDiv.get(Greek.FAIR_PRICE), priceDiv, refPriceDiv); final double deltaDiv = BlackScholesFormulaRepository.delta( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refDeltaDiv = Math.max(Math.abs(deltaDiv), 1.) / nSteps; assertEquals(resDiv.get(Greek.DELTA), deltaDiv, refDeltaDiv); final double gammaDiv = BlackScholesFormulaRepository.gamma( SPOT, strike, TIME, vol, interest, interest - dividend); final double refGammaDiv = Math.max(Math.abs(gammaDiv), 1.) / nSteps; assertEquals(resDiv.get(Greek.GAMMA), gammaDiv, refGammaDiv); final double thetaDiv = BlackScholesFormulaRepository.theta( SPOT, strike, TIME, vol, interest, interest - dividend, isCall); final double refThetaDiv = Math.max(Math.abs(thetaDiv), 1.) / nSteps; assertEquals(resDiv.get(Greek.THETA), thetaDiv, refThetaDiv * 10.); } } } } } } }
/** non-constant volatility and interest rate */ @Test public void timeVaryingVolTest() { final LatticeSpecification lattice1 = new TimeVaryingLatticeSpecification(); final double[] time_set = new double[] {0.5, 1.2}; final int steps = 701; final double[] vol = new double[steps]; final double[] rate = new double[steps]; final double[] dividend = new double[steps]; final int stepsTri = 661; 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 OptionFunctionProvider1D functionVanilla = new EuropeanVanillaOptionFunctionProvider(strike, time, steps, isCall); final double resPrice = _model.getPrice(functionVanilla, SPOT, vol, rate, dividend); final GreekResultCollection resGreeks = _model.getGreeks(functionVanilla, SPOT, vol, rate, dividend); final double resPriceConst = _model.getPrice(lattice1, functionVanilla, SPOT, volRef, rateRef, dividend[0]); final GreekResultCollection resGreeksConst = _model.getGreeks(lattice1, functionVanilla, SPOT, volRef, rateRef, dividend[0]); assertEquals(resPrice, resPriceConst, Math.max(Math.abs(resPriceConst), .1) * 1.e-1); assertEquals( resGreeks.get(Greek.FAIR_PRICE), resGreeksConst.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConst.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals( resGreeks.get(Greek.DELTA), resGreeksConst.get(Greek.DELTA), Math.max(Math.abs(resGreeksConst.get(Greek.DELTA)), 0.1) * 0.1); assertEquals( resGreeks.get(Greek.GAMMA), resGreeksConst.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConst.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals( resGreeks.get(Greek.THETA), resGreeksConst.get(Greek.THETA), Math.max(Math.abs(resGreeksConst.get(Greek.THETA)), 0.1)); final OptionFunctionProvider1D functionTri = new EuropeanVanillaOptionFunctionProvider(strike, time, stepsTri, isCall); final double resPriceTrinomial = _modelTrinomial.getPrice(functionTri, SPOT, volTri, rateTri, dividendTri); assertEquals( resPriceTrinomial, resPriceConst, Math.max(Math.abs(resPriceConst), .1) * 1.e-1); final GreekResultCollection resGreeksTrinomial = _modelTrinomial.getGreeks(functionTri, SPOT, volTri, rateTri, dividendTri); assertEquals( resGreeksTrinomial.get(Greek.FAIR_PRICE), resGreeksConst.get(Greek.FAIR_PRICE), Math.max(Math.abs(resGreeksConst.get(Greek.FAIR_PRICE)), 0.1) * 0.1); assertEquals( resGreeksTrinomial.get(Greek.DELTA), resGreeksConst.get(Greek.DELTA), Math.max(Math.abs(resGreeksConst.get(Greek.DELTA)), 0.1) * 0.1); assertEquals( resGreeksTrinomial.get(Greek.GAMMA), resGreeksConst.get(Greek.GAMMA), Math.max(Math.abs(resGreeksConst.get(Greek.GAMMA)), 0.1) * 0.1); assertEquals( resGreeksTrinomial.get(Greek.THETA), resGreeksConst.get(Greek.THETA), Math.max(Math.abs(resGreeksConst.get(Greek.THETA)), 0.1)); } } } }
/** The dividend is cash or proportional to asset price */ @Test public void greeksDiscreteDividendLatticeTest() { final LatticeSpecification[] lattices = new LatticeSpecification[] { new CoxRossRubinsteinLatticeSpecification(), new JarrowRuddLatticeSpecification(), new TrigeorgisLatticeSpecification(), new JabbourKraminYoungLatticeSpecification(), new TianLatticeSpecification(), new LeisenReimerLatticeSpecification() }; final double[] propDividends = new double[] {0.01, 0.01, 0.01}; final double[] cashDividends = new double[] {5., 10., 8.}; final double[] dividendTimes = new double[] {TIME / 420., TIME / 203., TIME / 2.}; final boolean[] tfSet = new boolean[] {true, false}; 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 = 401; 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 double exactPriceProp = BlackScholesFormulaRepository.price( resSpot, strike, TIME, vol, interest, interest, isCall); final double exactDeltaProp = BlackScholesFormulaRepository.delta( resSpot, strike, TIME, vol, interest, interest, isCall); final double exactGammaProp = BlackScholesFormulaRepository.gamma( resSpot, strike, TIME, vol, interest, interest); final double exactThetaProp = BlackScholesFormulaRepository.theta( resSpot, strike, TIME, vol, interest, interest, isCall); final double appPriceCash = BlackScholesFormulaRepository.price( modSpot, strike, TIME, vol, interest, interest, isCall); final double appDeltaCash = BlackScholesFormulaRepository.delta( modSpot, strike, TIME, vol, interest, interest, isCall); final double appGammaCash = BlackScholesFormulaRepository.gamma( modSpot, strike, TIME, vol, interest, interest); final double appThetaCash = BlackScholesFormulaRepository.theta( modSpot, strike, TIME, vol, interest, interest, isCall); final OptionFunctionProvider1D function = new EuropeanVanillaOptionFunctionProvider(strike, TIME, nSteps, isCall); final DividendFunctionProvider cashDividend = new CashDividendFunctionProvider(dividendTimes, cashDividends); final DividendFunctionProvider propDividend = new ProportionalDividendFunctionProvider(dividendTimes, propDividends); final GreekResultCollection resProp = _model.getGreeks(lattice, function, SPOT, vol, interest, propDividend); final GreekResultCollection resCash = _model.getGreeks(lattice, function, SPOT, vol, interest, cashDividend); assertEquals( resProp.get(Greek.FAIR_PRICE), exactPriceProp, Math.max(1., Math.abs(exactPriceProp)) * 1.e-2); assertEquals( resProp.get(Greek.DELTA), exactDeltaProp, Math.max(1., Math.abs(exactDeltaProp)) * 1.e-1); assertEquals( resProp.get(Greek.GAMMA), exactGammaProp, Math.max(1., Math.abs(exactGammaProp)) * 1.e-1); assertEquals( resProp.get(Greek.THETA), exactThetaProp, Math.max(1., Math.abs(exactThetaProp)) * 1.e-1); assertEquals( resCash.get(Greek.FAIR_PRICE), appPriceCash, Math.max(1., Math.abs(appPriceCash)) * 1.e-2); assertEquals( resCash.get(Greek.DELTA), appDeltaCash, Math.max(1., Math.abs(appDeltaCash)) * 1.e-1); assertEquals( resCash.get(Greek.GAMMA), appGammaCash, Math.max(1., Math.abs(appGammaCash)) * 1.e-1); assertEquals( resCash.get(Greek.THETA), appThetaCash, Math.max(1., Math.abs(appThetaCash))); if (lattice instanceof CoxRossRubinsteinLatticeSpecification || lattice instanceof JarrowRuddLatticeSpecification || lattice instanceof TrigeorgisLatticeSpecification || lattice instanceof TianLatticeSpecification) { final GreekResultCollection resPropTrinomial = _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, propDividend); final GreekResultCollection resCashTrinomial = _modelTrinomial.getGreeks(lattice, function, SPOT, vol, interest, cashDividend); assertEquals( resPropTrinomial.get(Greek.FAIR_PRICE), resProp.get(Greek.FAIR_PRICE), Math.max(1., Math.abs(resProp.get(Greek.FAIR_PRICE))) * 1.e-2); assertEquals( resPropTrinomial.get(Greek.DELTA), resProp.get(Greek.DELTA), Math.max(1., Math.abs(resProp.get(Greek.DELTA))) * 1.e-2); assertEquals( resPropTrinomial.get(Greek.GAMMA), resProp.get(Greek.GAMMA), Math.max(1., Math.abs(resProp.get(Greek.GAMMA))) * 1.e-2); assertEquals( resPropTrinomial.get(Greek.THETA), resProp.get(Greek.THETA), Math.max(1., Math.abs(resProp.get(Greek.THETA))) * 1.e-1); assertEquals( resCashTrinomial.get(Greek.FAIR_PRICE), resCash.get(Greek.FAIR_PRICE), Math.max(1., Math.abs(resCash.get(Greek.FAIR_PRICE))) * 1.e-2); assertEquals( resCashTrinomial.get(Greek.DELTA), resCash.get(Greek.DELTA), Math.max(1., Math.abs(resCash.get(Greek.DELTA))) * 1.e-2); assertEquals( resCashTrinomial.get(Greek.GAMMA), resCash.get(Greek.GAMMA), Math.max(1., Math.abs(resCash.get(Greek.GAMMA))) * 1.e-2); assertEquals( resCashTrinomial.get(Greek.THETA), resCash.get(Greek.THETA), Math.max(1., Math.abs(resCash.get(Greek.THETA))) * 1.e-1); } } } } } } }
@Test public void testPricing() { GreekResultCollection fftPrice = FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, GREEKS); GreekResultCollection bsmPrice = BSM_MODEL.getGreeks(ITM_CALL, BSM_DATA, GREEKS); assertEquals(fftPrice.size(), 1); assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS); fftPrice = FFT_MODEL.getGreeks(OTM_CALL, BLACK_DATA, GREEKS); bsmPrice = BSM_MODEL.getGreeks(OTM_CALL, BSM_DATA, GREEKS); assertEquals(fftPrice.size(), 1); assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS); fftPrice = FFT_MODEL.getGreeks(OTM_PUT, BLACK_DATA, GREEKS); bsmPrice = BSM_MODEL.getGreeks(OTM_PUT, BSM_DATA, GREEKS); assertEquals(fftPrice.size(), 1); assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS); fftPrice = FFT_MODEL.getGreeks(ITM_PUT, BLACK_DATA, GREEKS); bsmPrice = BSM_MODEL.getGreeks(ITM_PUT, BSM_DATA, GREEKS); assertEquals(fftPrice.size(), 1); assertEquals(fftPrice.get(Greek.FAIR_PRICE), bsmPrice.get(Greek.FAIR_PRICE), EPS); }
private void assertPriceEquals( final LogOptionDefinition definition, final double sigma, final double price) { final StandardOptionDataBundle bundle = getBundle(sigma); final GreekResultCollection actual = MODEL.getGreeks(definition, bundle, REQUIRED_GREEKS); assertEquals(actual.get(Greek.FAIR_PRICE), price, EPS); }