@Test public void testHashCodeAndEquals() { VasicekDataBundle other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, SPEED); assertEquals(other, DATA); assertEquals(other.hashCode(), DATA.hashCode()); other = new VasicekDataBundle( new YieldCurve(ConstantDoublesCurve.from(SHORT_RATE.getInterestRate(0.) + 1)), SIGMA, DATE, LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle( SHORT_RATE, new VolatilityCurve(ConstantDoublesCurve.from(SIGMA.getVolatility(0.) + 0.2)), DATE, LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE.plusDays(10), LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE + 1, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, SPEED + 1); assertFalse(other.equals(DATA)); }
public class ProductOptionModelTest { private static final double S1 = 100; private static final double S2 = 105; private static final YieldAndDiscountCurve R = new YieldCurve(ConstantDoublesCurve.from(0.07)); private static final double B1 = 0.02; private static final double B2 = 0.05; private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1); private static final ProductOptionModel MODEL = new ProductOptionModel(); private static final Expiry EXPIRY1 = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.1)); private static final Expiry EXPIRY2 = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.5)); private static final double EPS = 1e-4; @Test(expectedExceptions = IllegalArgumentException.class) public void testNullDefinition() { MODEL.getPricingFunction(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullData() { MODEL .getPricingFunction(new ProductOptionDefinition(0.1, EXPIRY1, true)) .evaluate((StandardTwoAssetOptionDataBundle) null); } @Test public void test() { ProductOptionDefinition option = new ProductOptionDefinition(15000, EXPIRY1, true); StandardTwoAssetOptionDataBundle data = new StandardTwoAssetOptionDataBundle( R, B1, B2, new VolatilitySurface(ConstantDoublesSurface.from(0.2)), new VolatilitySurface(ConstantDoublesSurface.from(0.3)), S1, S2, -0.5, DATE); assertEquals(MODEL.getPricingFunction(option).evaluate(data), 0.0028, EPS); data = data.withFirstVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from(0.3))) .withCorrelation(0); assertEquals(MODEL.getPricingFunction(option).evaluate(data), 2.4026, EPS); option = new ProductOptionDefinition(15000, EXPIRY2, true); assertEquals(MODEL.getPricingFunction(option).evaluate(data), 266.1594, EPS); } }
@Test(enabled = false) /** * Test the present value vs a external system. "enabled = false" for the standard testing: the * external system is using a TimeCalculator with ACT/365. */ public void presentValueExternal() { G2ppPiecewiseConstantParameters parametersCst = G2ppTestsDataSet.createG2ppCstParameters(); final YieldAndDiscountCurve curve5 = new YieldCurve(ConstantDoublesCurve.from(0.05)); final YieldCurveBundle curves = new YieldCurveBundle(); curves.setCurve(FUNDING_CURVE_NAME, curve5); curves.setCurve(FORWARD_CURVE_NAME, curve5); G2ppPiecewiseConstantDataBundle bundleCst = new G2ppPiecewiseConstantDataBundle(parametersCst, curves); CurrencyAmount pv = METHOD_G2PP_APPROXIMATION.presentValue(SWAPTION_PAYER_LONG, bundleCst); double pvExternal = 6885626.28245924; // ! TimeCalculator with ACT/365 assertEquals( "Swaption physical - G2++ - present value - external system", pvExternal, pv.getAmount(), 1E-2); }
public class FloatingStrikeLookbackOptionDefinitionTest { private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 6, 1); private static final Expiry EXPIRY = new Expiry(DATE); private static final FloatingStrikeLookbackOptionDefinition CALL = new FloatingStrikeLookbackOptionDefinition(EXPIRY, true); private static final FloatingStrikeLookbackOptionDefinition PUT = new FloatingStrikeLookbackOptionDefinition(EXPIRY, false); private static final double SPOT = 100; private static final double DIFF = 10; private static final DoubleTimeSeries<?> HIGH_TS = new FastArrayIntDoubleTimeSeries( DateTimeNumericEncoding.DATE_DDMMYYYY, new int[] {20100529, 20100530, 20100531}, new double[] {SPOT, SPOT + DIFF, SPOT}); private static final DoubleTimeSeries<?> LOW_TS = new FastArrayIntDoubleTimeSeries( DateTimeNumericEncoding.DATE_DDMMYYYY, new int[] {20100529, 20100530, 20100531}, new double[] {SPOT, SPOT - DIFF, SPOT}); private static final StandardOptionWithSpotTimeSeriesDataBundle HIGH_DATA = new StandardOptionWithSpotTimeSeriesDataBundle( new YieldCurve(ConstantDoublesCurve.from(0.1)), 0.05, new VolatilitySurface(ConstantDoublesSurface.from(0.2)), SPOT, DateUtils.getUTCDate(2010, 6, 1), HIGH_TS); private static final StandardOptionWithSpotTimeSeriesDataBundle LOW_DATA = new StandardOptionWithSpotTimeSeriesDataBundle( new YieldCurve(ConstantDoublesCurve.from(0.1)), 0.05, new VolatilitySurface(ConstantDoublesSurface.from(0.2)), SPOT, DateUtils.getUTCDate(2010, 6, 1), LOW_TS); @Test(expectedExceptions = IllegalArgumentException.class) public void testNullDataBundle() { CALL.getPayoffFunction().getPayoff(null, null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullTS() { CALL.getPayoffFunction().getPayoff(HIGH_DATA.withSpotTimeSeries(null), null); } @Test public void testExercise() { assertFalse(CALL.getExerciseFunction().shouldExercise(HIGH_DATA, null)); assertFalse(CALL.getExerciseFunction().shouldExercise(LOW_DATA, null)); assertFalse(PUT.getExerciseFunction().shouldExercise(HIGH_DATA, null)); assertFalse(PUT.getExerciseFunction().shouldExercise(LOW_DATA, null)); } @Test public void testPayoff() { final double eps = 1e-15; OptionPayoffFunction<StandardOptionWithSpotTimeSeriesDataBundle> payoff = CALL.getPayoffFunction(); assertEquals(payoff.getPayoff(LOW_DATA, 0.), DIFF, eps); assertEquals(payoff.getPayoff(HIGH_DATA, 0.), 0, eps); payoff = PUT.getPayoffFunction(); assertEquals(payoff.getPayoff(LOW_DATA, 0.), 0, eps); assertEquals(payoff.getPayoff(HIGH_DATA, 0.), DIFF, eps); } @Test public void testEqualsAndHashCode() { final OptionDefinition call1 = new FloatingStrikeLookbackOptionDefinition(EXPIRY, true); final OptionDefinition put1 = new FloatingStrikeLookbackOptionDefinition(EXPIRY, false); final OptionDefinition call2 = new FloatingStrikeLookbackOptionDefinition( new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 3)), true); final OptionDefinition put2 = new FloatingStrikeLookbackOptionDefinition( new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 3)), false); assertFalse(CALL.equals(PUT)); assertEquals(call1, CALL); assertEquals(put1, PUT); assertEquals(call1.hashCode(), CALL.hashCode()); assertEquals(put1.hashCode(), PUT.hashCode()); assertFalse(call2.equals(CALL)); assertFalse(put2.equals(PUT)); } }
public class AsymmetricPowerOptionModelTest { private static final double B = 0.02; private static final double SPOT = 10; private static final double STRIKE = 100; private static final ZonedDateTime DATE = DateUtils.getUTCDate(2009, 1, 1); private static final Expiry EXPIRY = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.5)); private static final YieldAndDiscountCurve CURVE = new YieldCurve(ConstantDoublesCurve.from(0.08)); private static final VolatilitySurface SURFACE = new VolatilitySurface(ConstantDoublesSurface.from(0.1)); private static final StandardOptionDataBundle BUNDLE = new StandardOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE); private static final AnalyticOptionModel< AsymmetricPowerOptionDefinition, StandardOptionDataBundle> MODEL = new AsymmetricPowerOptionModel(); private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BS_MODEL = new BlackScholesMertonModel(); private static final Set<Greek> REQUIRED_GREEKS = Collections.singleton(Greek.FAIR_PRICE); private static final double EPS = 1e-4; @Test(expectedExceptions = IllegalArgumentException.class) public void testNullDefinition() { MODEL.getPricingFunction(null); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullData() { MODEL .getPricingFunction(new AsymmetricPowerOptionDefinition(STRIKE, EXPIRY, 1, true)) .evaluate((StandardOptionDataBundle) null); } @Test public void test() { assertEquals(getPrice(1.9, true), 0.3102, EPS); assertEquals(getPrice(1.95, true), 1.9320, EPS); assertEquals(getPrice(2., true), 6.7862, EPS); assertEquals(getPrice(2.05, true), 15.8587, EPS); assertEquals(getPrice(2.1, true), 28.4341, EPS); assertEquals(getPrice(1.9, false), 18.2738, EPS); assertEquals(getPrice(1.95, false), 10.2890, EPS); assertEquals(getPrice(2., false), 4.3539, EPS); assertEquals(getPrice(2.05, false), 1.3089, EPS); assertEquals(getPrice(2.1, false), 0.2745, EPS); for (int i = 0; i < 5; i++) { final double power = 1.9 + 0.05 * i; assertEquals(getPrice(power, true), getBSPrice(power, true), EPS); assertEquals(getPrice(power, false), getBSPrice(power, false), EPS); } } private double getPrice(final double power, final boolean isCall) { return MODEL .getGreeks(getDefinition(power, isCall), BUNDLE, REQUIRED_GREEKS) .get(Greek.FAIR_PRICE); } private double getBSPrice(final double power, final boolean isCall) { final StandardOptionDataBundle bsBundle = getModifiedDataBundle(BUNDLE, power); return BS_MODEL .getGreeks(getDefinition(power, isCall), bsBundle, REQUIRED_GREEKS) .get(Greek.FAIR_PRICE); } private AsymmetricPowerOptionDefinition getDefinition(final double power, final boolean isCall) { return new AsymmetricPowerOptionDefinition(STRIKE, EXPIRY, power, isCall); } private StandardOptionDataBundle getModifiedDataBundle( final StandardOptionDataBundle data, final double p) { final double t = DateUtils.getDifferenceInYears(DATE, EXPIRY); final double spot = Math.pow(data.getSpot(), p); double sigma = data.getVolatility(t, STRIKE); final double b = p * (data.getCostOfCarry() + (p - 1) * sigma * sigma * 0.5); sigma *= p; return new StandardOptionDataBundle( CURVE, b, new VolatilitySurface(ConstantDoublesSurface.from(sigma)), spot, DATE); } }
@Test @SuppressWarnings("unused") public class SABRFiniteDifferenceTest { private static final PDEDataBundleProvider PDE_DATA_PROVIDER = new PDEDataBundleProvider(); private static final BlackPriceFunction BLACK_PRICE_FUNCTION = new BlackPriceFunction(); private static final BlackImpliedVolatilityFormula BLACK_IMPLIED_VOL = new BlackImpliedVolatilityFormula(); private static final SABRHaganVolatilityFunction SABR = new SABRHaganVolatilityFunction(); private static final double SPOT = 0.04; private static final double STRIKE; private static final double ATM_VOL = 0.2; private static final double ALPHA; private static final double BETA = 0.5; private static final double RHO = -0.6; private static final double NU = 0.3; private static final double RATE = 0.00; private static final double T = 5.0; private static final ForwardCurve FORWARD = new ForwardCurve(SPOT); private static final YieldAndDiscountCurve YIELD_CURVE = new YieldCurve(ConstantDoublesCurve.from(RATE)); private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1); private static final EuropeanVanillaOption OPTION; private static final ConvectionDiffusionPDEDataBundle DATA; private static BoundaryCondition LOWER; private static BoundaryCondition UPPER; private static final PriceSurface SABR_PRICE_SURFACE; private static final BlackVolatilitySurface SABR_VOL_SURFACE; private static final AbsoluteLocalVolatilitySurface SABR_LOCAL_VOL; /** */ static { ALPHA = ATM_VOL * Math.pow(SPOT, 1 - BETA); final Function<Double, Double> sabrSurface = new Function<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double... x) { final double t = x[0]; final double k = x[1]; final SABRFormulaData sabrdata = new SABRFormulaData(SPOT * Math.exp(RATE * t), ALPHA, BETA, NU, RHO); final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true); final Function1D<SABRFormulaData, Double> func = SABR.getVolatilityFunction(option); return func.evaluate(sabrdata); } }; SABR_VOL_SURFACE = new BlackVolatilitySurface(FunctionalDoublesSurface.from(sabrSurface)); final Function<Double, Double> priceSurface = new Function<Double, Double>() { @SuppressWarnings("synthetic-access") @Override public Double evaluate(final Double... x) { final double t = x[0]; final double k = x[1]; final double sigma = sabrSurface.evaluate(x); final double df = YIELD_CURVE.getDiscountFactor(t); final BlackFunctionData data = new BlackFunctionData(SPOT / df, df, sigma); final EuropeanVanillaOption option = new EuropeanVanillaOption(k, t, true); final Function1D<BlackFunctionData, Double> pfunc = BLACK_PRICE_FUNCTION.getPriceFunction(option); final double price = pfunc.evaluate(data); return price; } }; SABR_PRICE_SURFACE = new PriceSurface(FunctionalDoublesSurface.from(priceSurface)); final DupireLocalVolatilityCalculator cal = new DupireLocalVolatilityCalculator(); SABR_LOCAL_VOL = cal.getAbsoluteLocalVolatilitySurface(SABR_VOL_SURFACE, SPOT, RATE); STRIKE = SPOT / YIELD_CURVE.getDiscountFactor(T); OPTION = new EuropeanVanillaOption(STRIKE, T, true); LOWER = new DirichletBoundaryCondition(0, 0.0); UPPER = new FixedSecondDerivativeBoundaryCondition(0.0, 5.0 * SPOT, false); DATA = PDE_DATA_PROVIDER.getBackwardsLocalVol(FORWARD, STRIKE, T, 0.0, true, SABR_LOCAL_VOL); } public void test() { final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(0.5, false); final int tNodes = 20; final int xNodes = 101; final PDEGrid1D grid = new PDEGrid1D(tNodes, xNodes, T, LOWER.getLevel(), UPPER.getLevel()); final PDEResults1D res = solver.solve(DATA, grid, LOWER, UPPER); final int i = (int) (xNodes * SPOT / UPPER.getLevel()); final double spot = res.getSpaceValue(i); final double price = res.getFunctionValue(i); final double df = YIELD_CURVE.getDiscountFactor(T); assertEquals(SPOT, spot, 1e-9); assertEquals(SABR_PRICE_SURFACE.getPrice(T, STRIKE), price, price * 2e-3); final BlackFunctionData data = new BlackFunctionData(spot / df, df, 0.0); double impVol; try { impVol = BLACK_IMPLIED_VOL.getImpliedVolatility(data, OPTION, price); } catch (final Exception e) { impVol = 0.0; } assertEquals(SABR_VOL_SURFACE.getVolatility(T, STRIKE), impVol, 1e-3); } }
public class GapOptionDefinitionTest { private static final double DELTA = 10; private static final double STRIKE = 50; private static final Expiry EXPIRY = new Expiry(DateUtils.getUTCDate(2010, 1, 1)); private static final boolean IS_CALL = true; private static final double PAYOFF_STRIKE = 55; private static final GapOptionDefinition CALL = new GapOptionDefinition(STRIKE, EXPIRY, true, PAYOFF_STRIKE); private static final GapOptionDefinition PUT = new GapOptionDefinition(STRIKE, EXPIRY, false, PAYOFF_STRIKE); private static final StandardOptionDataBundle DATA = new StandardOptionDataBundle( new YieldCurve(ConstantDoublesCurve.from(0.03)), 0.03, new VolatilitySurface(ConstantDoublesSurface.from(0.2)), STRIKE, DateUtils.getUTCDate(2009, 1, 1)); @Test(expectedExceptions = IllegalArgumentException.class) public void testNegativePayoffStrike() { new GapOptionDefinition(STRIKE, EXPIRY, IS_CALL, -PAYOFF_STRIKE); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullData() { CALL.getPayoffFunction().getPayoff(null, null); } @Test public void test() { GapOptionDefinition other = new GapOptionDefinition(STRIKE, EXPIRY, true, PAYOFF_STRIKE); assertEquals(other, CALL); assertEquals(other.hashCode(), CALL.hashCode()); other = new GapOptionDefinition(STRIKE + 1, EXPIRY, true, PAYOFF_STRIKE); assertFalse(other.equals(CALL)); other = new GapOptionDefinition( STRIKE, new Expiry(DateUtils.getUTCDate(2010, 3, 1)), true, PAYOFF_STRIKE); assertFalse(other.equals(CALL)); other = new GapOptionDefinition(STRIKE, EXPIRY, false, PAYOFF_STRIKE); assertFalse(other.equals(CALL)); other = new GapOptionDefinition(STRIKE, EXPIRY, true, PAYOFF_STRIKE + 1); assertFalse(other.equals(CALL)); } @Test public void testExerciseFunction() { StandardOptionDataBundle data = DATA.withSpot(STRIKE + DELTA); assertFalse(CALL.getExerciseFunction().shouldExercise(data, null)); assertFalse(PUT.getExerciseFunction().shouldExercise(data, null)); data = DATA.withSpot(STRIKE - DELTA); assertFalse(CALL.getExerciseFunction().shouldExercise(data, null)); assertFalse(PUT.getExerciseFunction().shouldExercise(data, null)); } @Test public void testPayoffFunction() { assertEquals(CALL.getPayoffFunction().getPayoff(DATA, null), 0, 0); assertEquals(PUT.getPayoffFunction().getPayoff(DATA, null), 0, 0); double spot = STRIKE + DELTA; StandardOptionDataBundle data = DATA.withSpot(spot); assertEquals(CALL.getPayoffFunction().getPayoff(data, null), spot - PAYOFF_STRIKE, 0); assertEquals(PUT.getPayoffFunction().getPayoff(data, null), 0, 0); spot = STRIKE - DELTA; data = DATA.withSpot(spot); assertEquals(CALL.getPayoffFunction().getPayoff(data, null), 0, 0); assertEquals(PUT.getPayoffFunction().getPayoff(data, null), PAYOFF_STRIKE - spot, 0); } }
public class VasicekDataBundleTest { private static final YieldCurve SHORT_RATE = new YieldCurve(ConstantDoublesCurve.from(0.02)); private static final double LONG_RATE = 0.05; private static final double SPEED = 0.1; private static final VolatilityCurve SIGMA = new VolatilityCurve(ConstantDoublesCurve.from(0.4)); private static final ZonedDateTime DATE = DateUtil.getUTCDate(2010, 1, 1); private static final VasicekDataBundle DATA = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, SPEED); @Test(expectedExceptions = IllegalArgumentException.class) public void testNullShortRate() { new VasicekDataBundle(null, SIGMA, DATE, LONG_RATE, SPEED); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullVolatility() { new VasicekDataBundle(SHORT_RATE, null, DATE, LONG_RATE, SPEED); } @Test(expectedExceptions = IllegalArgumentException.class) public void testNullDate() { new VasicekDataBundle(SHORT_RATE, SIGMA, null, LONG_RATE, SPEED); } @Test(expectedExceptions = IllegalArgumentException.class) public void testZeroSpeed() { new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, 0); } @Test public void testGetters() { final double t = Math.random(); assertEquals(DATA.getShortRateCurve(), SHORT_RATE); assertEquals(DATA.getShortRate(t), SHORT_RATE.getInterestRate(t), 0); assertEquals(DATA.getLongTermInterestRate(), LONG_RATE, 0); assertEquals(DATA.getReversionSpeed(), SPEED, 0); assertEquals(DATA.getShortRateVolatilityCurve(), SIGMA); assertEquals(DATA.getShortRateVolatility(t), SIGMA.getVolatility(t), 0); assertEquals(DATA.getDate(), DATE); } @Test public void testHashCodeAndEquals() { VasicekDataBundle other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, SPEED); assertEquals(other, DATA); assertEquals(other.hashCode(), DATA.hashCode()); other = new VasicekDataBundle( new YieldCurve(ConstantDoublesCurve.from(SHORT_RATE.getInterestRate(0.) + 1)), SIGMA, DATE, LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle( SHORT_RATE, new VolatilityCurve(ConstantDoublesCurve.from(SIGMA.getVolatility(0.) + 0.2)), DATE, LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE.plusDays(10), LONG_RATE, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE + 1, SPEED); assertFalse(other.equals(DATA)); other = new VasicekDataBundle(SHORT_RATE, SIGMA, DATE, LONG_RATE, SPEED + 1); assertFalse(other.equals(DATA)); } }