/** * standard in-out parity holds if r=0. */ public void inOutParity() { double upIn = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, 0d, VOLATILITY, BARRIER_UP_IN); double upOut = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, 0d, VOLATILITY, BARRIER_UP_OUT); double downIn = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, 0d, VOLATILITY, BARRIER_DOWN_IN); double downOut = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, 0d, VOLATILITY, BARRIER_DOWN_OUT); assertRelative(upIn + upOut, 1d); assertRelative(downIn + downOut, 1d); }
ValueDerivatives computed = PRICER.priceAdjoint( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, barrier); double spotUp = PRICER.price( SPOT + EPS_FD, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, barrier); double spotDw = PRICER.price( SPOT - EPS_FD, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, barrier); double rateUp = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM + EPS_FD, VOLATILITY, barrier); double rateDw = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM - EPS_FD, VOLATILITY, barrier); double costUp = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY + EPS_FD, RATE_DOM, VOLATILITY, barrier); double costDw = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY - EPS_FD, RATE_DOM, VOLATILITY, barrier); double volUp = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY + EPS_FD, barrier); double volDw = PRICER.price( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY - EPS_FD, barrier); double timeUp = PRICER.price( SPOT, EXPIRY_TIME + EPS_FD, COST_OF_CARRY, RATE_DOM, VOLATILITY, barrier); double timeDw = PRICER.price( SPOT, EXPIRY_TIME - EPS_FD, COST_OF_CARRY, RATE_DOM, VOLATILITY, barrier); ValueDerivatives spotUp1 = PRICER.priceAdjoint(
/** * Barrier event has occured already. */ public void illegalBarrierLevelTest() { assertThrowsIllegalArg(() -> PRICER.price(BARRIER_UP_IN.getBarrierLevel() + 0.1, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_IN)); assertThrowsIllegalArg(() -> PRICER.price(BARRIER_DOWN_OUT.getBarrierLevel() - 0.1, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_OUT)); assertThrowsIllegalArg(() -> PRICER.priceAdjoint(BARRIER_UP_IN.getBarrierLevel() + 0.1, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_IN)); assertThrowsIllegalArg(() -> PRICER.priceAdjoint(BARRIER_DOWN_OUT.getBarrierLevel() - 0.1, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_OUT)); }
/** * Upper barrier level is very high. */ public void largeBarrierTest() { SimpleConstantContinuousBarrier in = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_IN, 1.0e4); SimpleConstantContinuousBarrier out = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, 1.0e4); double upIn = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, in); double upOut = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, out); assertRelative(upIn, 0d); assertRelative(upOut, DF_DOM); }
/** * smoothly connected to limiting cases. */ public void smallsigmaTTest() { for (SimpleConstantContinuousBarrier barrier : BARRIERS) { double volUp = 2.0e-3; double volDw = 1.0e-3; double time = 1.0e-2; double optUp = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); double optDw = PRICER.price(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUp, optDw); ValueDerivatives optUpAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volUp, barrier); ValueDerivatives optDwAdj = PRICER.priceAdjoint(SPOT, time, COST_OF_CARRY, RATE_DOM, volDw, barrier); assertRelative(optUpAdj.getValue(), optDwAdj.getValue()); for (int i = 0; i < 6; ++i) { assertRelative(optUpAdj.getDerivative(i), optDwAdj.getDerivative(i)); } } }
/** * Lower barrier level is very small. */ public void smallBarrierTest() { SimpleConstantContinuousBarrier in = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_IN, 0.1d); SimpleConstantContinuousBarrier out = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, 0.1d); double dwIn = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, in); double dwOut = PRICER.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, out); assertRelative(dwIn, 0d); assertRelative(dwOut, DF_DOM); }
ValueDerivatives priceDIAdjointNew = BARRIER_PRICER.priceAdjoint(SPOT, options[j].getStrike(), EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, options[j].isCall(), BARRIER_DOWN_IN); double priceDIRb = rebate.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_OUT); ValueDerivatives priceDIAdjointRb = rebate.priceAdjoint(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_OUT); COST_OF_CARRY, RATE_DOM, VOLATILITY, options[j].isCall(), BARRIER_DOWN_OUT); double priceDORb = rebate.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_IN); ValueDerivatives priceDOAdjointRb = rebate.priceAdjoint( SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_DOWN_IN); ValueDerivatives priceUIAdjointNew = BARRIER_PRICER.priceAdjoint(SPOT, options[j].getStrike(), EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, options[j].isCall(), BARRIER_UP_IN); double priceUIRb = rebate.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_OUT); ValueDerivatives priceUIAdjointRb = rebate.priceAdjoint(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_OUT); ValueDerivatives priceUOAdjointNew = BARRIER_PRICER.priceAdjoint(SPOT, options[j].getStrike(), EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, options[j].isCall(), BARRIER_UP_OUT); double priceUORb = rebate.price(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_IN); ValueDerivatives priceUOAdjointRb = rebate.priceAdjoint(SPOT, EXPIRY_TIME, COST_OF_CARRY, RATE_DOM, VOLATILITY, BARRIER_UP_IN);
public void test_trinomialTree_up() { int nSteps = 133; LatticeSpecification lattice = new CoxRossRubinsteinLatticeSpecification(); DoubleArray rebate = DoubleArray.of(nSteps + 1, i -> REBATE_AMOUNT); double barrierLevel = 135d; double tol = 1.0e-2; for (boolean isCall : new boolean[] {true, false }) { for (double strike : STRIKES) { for (double interest : INTERESTS) { for (double vol : VOLS) { for (double dividend : DIVIDENDS) { OptionFunction function = ConstantContinuousSingleBarrierKnockoutFunction.of( strike, TIME, PutCall.ofPut(!isCall), nSteps, BarrierType.UP, barrierLevel, rebate); SimpleConstantContinuousBarrier barrier = SimpleConstantContinuousBarrier.of(BarrierType.UP, KnockType.KNOCK_OUT, barrierLevel); double exact = REBATE_AMOUNT * REBATE_PRICER.price(SPOT, TIME, interest - dividend, interest, vol, barrier.inverseKnockType()) +BARRIER_PRICER.price(SPOT, strike, TIME, interest - dividend, interest, vol, isCall, barrier); double computed = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(computed, exact, Math.max(exact, 1d) * tol); } } } } } }
public void test_trinomialTree_down() { int nSteps = 133; LatticeSpecification lattice = new CoxRossRubinsteinLatticeSpecification(); DoubleArray rebate = DoubleArray.of(nSteps + 1, i -> REBATE_AMOUNT); double barrierLevel = 76d; double tol = 1.0e-2; for (boolean isCall : new boolean[] {true, false }) { for (double strike : STRIKES) { for (double interest : INTERESTS) { for (double vol : VOLS) { for (double dividend : DIVIDENDS) { OptionFunction function = ConstantContinuousSingleBarrierKnockoutFunction.of( strike, TIME, PutCall.ofPut(!isCall), nSteps, BarrierType.DOWN, barrierLevel, rebate); SimpleConstantContinuousBarrier barrier = SimpleConstantContinuousBarrier.of(BarrierType.DOWN, KnockType.KNOCK_OUT, barrierLevel); double exact = REBATE_AMOUNT * REBATE_PRICER.price(SPOT, TIME, interest - dividend, interest, vol, barrier.inverseKnockType()) + BARRIER_PRICER.price(SPOT, strike, TIME, interest - dividend, interest, vol, isCall, barrier); double computed = TRINOMIAL_TREE.optionPrice(function, lattice, SPOT, vol, interest, dividend); assertEquals(computed, exact, Math.max(exact, 1d) * tol); } } } } } }
public void test_price_presentValue() { double computedPriceCall = PRICER.price(CALL_UKI, RATE_PROVIDER, VOLS); double computedPricePut = PRICER.price(PUT_UKO_BASE, RATE_PROVIDER, VOLS); CurrencyAmount computedPvCall = PRICER.presentValue(CALL_UKI, RATE_PROVIDER, VOLS); CurrencyAmount computedPvPut = PRICER.presentValue(PUT_UKO_BASE, RATE_PROVIDER, VOLS); double rateBase = RATE_PROVIDER.discountFactors(EUR).zeroRate(PAY_DATE); double rateCounter = RATE_PROVIDER.discountFactors(USD).zeroRate(PAY_DATE); double costOfCarry = rateCounter - rateBase; double forward = RATE_PROVIDER.fxForwardRates(CURRENCY_PAIR).rate(EUR, PAY_DATE); double volatility = VOLS.volatility(CURRENCY_PAIR, EXPIRY_DATETIME, STRIKE_RATE, forward); double timeToExpiry = VOLS.relativeTime(EXPIRY_DATETIME); double rebateRate = REBATE_AMOUNT / NOTIONAL; double expectedCash = CASH_REBATE_PRICER.price(SPOT, timeToExpiry, costOfCarry, rateCounter, volatility, BARRIER_UKO); double expectedAsset = ASSET_REBATE_PRICER.price(SPOT, timeToExpiry, costOfCarry, rateCounter, volatility, BARRIER_UKI); double expectedPriceCall = BARRIER_PRICER.price(SPOT, STRIKE_RATE, timeToExpiry, costOfCarry, rateCounter, volatility, true, BARRIER_UKI) + rebateRate * expectedCash; double expectedPricePut = BARRIER_PRICER.price(SPOT, STRIKE_RATE, timeToExpiry, costOfCarry, rateCounter, volatility, false, BARRIER_UKO) + rebateRate * expectedAsset; assertEquals(computedPriceCall, expectedPriceCall, TOL); assertEquals(computedPricePut, expectedPricePut, TOL); assertEquals(computedPvCall.getCurrency(), USD); assertEquals(computedPvPut.getCurrency(), USD); assertEquals(computedPvCall.getAmount(), expectedPriceCall * NOTIONAL, TOL); assertEquals(computedPvPut.getAmount(), -expectedPricePut * NOTIONAL, TOL); }
CurrencyAmount rebate = option.getRebate().get(); double priceRebate = rebate.getCurrency().equals(ccyCounter) ? CASH_REBATE_PRICER.price(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType()) : ASSET_REBATE_PRICER.price(todayFx, timeToExpiry, costOfCarry, rateCounter, volatility, barrier.inverseKnockType()); price += priceRebate * rebate.getAmount() / Math.abs(underlyingFx.getBaseCurrencyPayment().getAmount());