@Test
 public void test() {
   assertEquals(DATA.getDate(), DATE);
   assertEquals(DATA.getForward(), F, 0);
   assertEquals(DATA.getVolatilitySurface(), SURFACE);
   assertEquals(DATA.getInterestRateCurve(), CURVE);
   final double t = Math.random();
   assertEquals(DATA.getDiscountFactor(t), Math.exp(-R * t), 0);
   BlackOptionDataBundle other = new BlackOptionDataBundle(F, CURVE, SURFACE, DATE);
   assertEquals(other, DATA);
   assertEquals(other.hashCode(), DATA.hashCode());
   other = new BlackOptionDataBundle(DATA);
   assertEquals(other, DATA);
   assertEquals(other.hashCode(), DATA.hashCode());
   other = new BlackOptionDataBundle(F + 1, CURVE, SURFACE, DATE);
   assertFalse(other.equals(DATA));
   other =
       new BlackOptionDataBundle(
           F, YieldCurve.from(ConstantDoublesCurve.from(0.06)), SURFACE, DATE);
   assertFalse(other.equals(DATA));
   other =
       new BlackOptionDataBundle(
           F, CURVE, new VolatilitySurface(ConstantDoublesSurface.from(0.6)), DATE);
   assertFalse(other.equals(DATA));
   other = new BlackOptionDataBundle(F, CURVE, SURFACE, DATE.plusDays(1));
   assertFalse(other.equals(DATA));
 }
 @Test
 public void test() {
   boolean isCall;
   double spot, strike, b, price;
   Expiry expiry;
   YieldAndDiscountCurve curve;
   EuropeanVanillaOptionDefinition definition;
   StandardOptionDataBundle initialData, data;
   double sigma = 0.01;
   for (int i = 0; i < 100; i++) {
     expiry = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, RANDOM.nextDouble() * 2));
     sigma += 0.03;
     spot = 2 * RANDOM.nextDouble() + 10;
     strike = 2 * RANDOM.nextDouble() + 10;
     curve = YieldCurve.from(ConstantDoublesCurve.from(RANDOM.nextDouble() / 10));
     b = 0; // RANDOM.nextDouble() / 20;
     isCall = RANDOM.nextDouble() < 0.5 ? true : false;
     definition = new EuropeanVanillaOptionDefinition(strike, expiry, isCall);
     initialData = new StandardOptionDataBundle(curve, b, null, spot, DATE);
     data =
         new StandardOptionDataBundle(
             curve, b, new VolatilitySurface(ConstantDoublesSurface.from(sigma)), spot, DATE);
     price = BSM.getPricingFunction(definition).evaluate(data);
     assertEquals(
         sigma,
         MODEL
             .getSurface(
                 Collections.<OptionDefinition, Double>singletonMap(definition, price),
                 initialData)
             .getVolatility(DoublesPair.of(0., 0.)),
         EPS);
   }
 }
Example #3
0
 static {
   FORWARD_CURVE = new ForwardCurve(SPOT, DRIFT);
   LOCAL_VOL =
       new LocalVolatilitySurfaceMoneyness(ConstantDoublesSurface.from(FLAT_VOL), FORWARD_CURVE);
   PDE = PDE_DATA_PROVIDER.getLogBackwardsLocalVol(EXPIRY, LOCAL_VOL);
   INITIAL_COND = INT_COND_PROVIDER.getLogContractPayoffInLogCoordinate();
 }
/** Test. */
@Test(groups = TestGroup.UNIT)
public class ForwardStartOptionModelTest {
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1);
  private static final double R = 0.08;
  private static final YieldCurve CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
  private static final VolatilitySurface SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(0.3));
  private static final double B = 0.04;
  private static final double SPOT = 60;
  private static final double PERCENT = 0.1;
  private static final ZonedDateTime START = DateUtils.getDateOffsetWithYearFraction(DATE, 0.25);
  private static final ZonedDateTime EXPIRY = DateUtils.getDateOffsetWithYearFraction(DATE, 1);
  private static final StandardOptionDataBundle DATA =
      new StandardOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE);
  private static final ForwardStartOptionDefinition FORWARD =
      new ForwardStartOptionDefinition(
          new Expiry(EXPIRY), true, new Expiry(START), PERCENT, Moneyness.OTM);
  private static final ForwardStartOptionDefinition NOW =
      new ForwardStartOptionDefinition(
          new Expiry(EXPIRY), true, new Expiry(DATE), PERCENT, Moneyness.OTM);
  private static final ForwardStartOptionDefinition END =
      new ForwardStartOptionDefinition(
          new Expiry(EXPIRY), true, new Expiry(EXPIRY), PERCENT, Moneyness.OTM);
  private static final EuropeanVanillaOptionDefinition VANILLA =
      new EuropeanVanillaOptionDefinition(SPOT * (1 + PERCENT), new Expiry(EXPIRY), true);
  private static final AnalyticOptionModel<ForwardStartOptionDefinition, StandardOptionDataBundle>
      MODEL = new ForwardStartOptionModel();
  private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM =
      new BlackScholesMertonModel();

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDefinition() {
    MODEL.getPricingFunction(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    MODEL.getPricingFunction(FORWARD).evaluate((StandardOptionDataBundle) null);
  }

  @Test
  public void test() {
    assertEquals(MODEL.getPricingFunction(END).evaluate(DATA), 0, 0);
    assertEquals(
        MODEL
            .getPricingFunction(FORWARD)
            .evaluate(
                DATA.withVolatilitySurface(
                    new VolatilitySurface(ConstantDoublesSurface.from(1e-9)))),
        0,
        0);
    assertEquals(
        MODEL.getPricingFunction(NOW).evaluate(DATA),
        BSM.getPricingFunction(VANILLA).evaluate(DATA),
        1e-4);
    assertEquals(MODEL.getPricingFunction(FORWARD).evaluate(DATA), 4.4064, 1e-4);
  }
}
public class RelativeOutperformanceOptionModelTest {
  private static final double S1 = 130;
  private static final double S2 = 100;
  private static final YieldAndDiscountCurve R = YieldCurve.from(ConstantDoublesCurve.from(0.07));
  private static final double B1 = 0.05;
  private static final double B2 = 0.03;
  private static final VolatilitySurface SIGMA1 =
      new VolatilitySurface(ConstantDoublesSurface.from(0.3));
  private static final VolatilitySurface SIGMA2 =
      new VolatilitySurface(ConstantDoublesSurface.from(0.4));
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1);
  private static final RelativeOutperformanceOptionModel MODEL =
      new RelativeOutperformanceOptionModel();
  private static final Expiry EXPIRY =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.25));
  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 RelativeOutperformanceOptionDefinition(0.1, EXPIRY, true))
        .evaluate((StandardTwoAssetOptionDataBundle) null);
  }

  @Test
  public void test() {
    RelativeOutperformanceOptionDefinition option =
        new RelativeOutperformanceOptionDefinition(0.1, EXPIRY, true);
    StandardTwoAssetOptionDataBundle data =
        new StandardTwoAssetOptionDataBundle(R, B1, B2, SIGMA1, SIGMA2, S1, S2, -0.5, DATE);
    assertEquals(MODEL.getPricingFunction(option).evaluate(data), 1.2582, EPS);
    option = new RelativeOutperformanceOptionDefinition(0.5, EXPIRY, true);
    data = data.withCorrelation(0);
    assertEquals(MODEL.getPricingFunction(option).evaluate(data), 0.8449, EPS);
    option = new RelativeOutperformanceOptionDefinition(1, EXPIRY, true);
    data = data.withCorrelation(0.5);
    assertEquals(MODEL.getPricingFunction(option).evaluate(data), 0.3382, EPS);
  }
}
/** Test. */
@Test(groups = TestGroup.UNIT)
public class BlackOptionDataBundleTest {
  private static final double R = 0.05;
  private static final YieldAndDiscountCurve CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
  private static final VolatilitySurface SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(0.35));
  private static final double F = 100;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 5, 1);
  private static final BlackOptionDataBundle DATA =
      new BlackOptionDataBundle(F, CURVE, SURFACE, DATE);

  @Test
  public void test() {
    assertEquals(DATA.getDate(), DATE);
    assertEquals(DATA.getForward(), F, 0);
    assertEquals(DATA.getVolatilitySurface(), SURFACE);
    assertEquals(DATA.getInterestRateCurve(), CURVE);
    final double t = Math.random();
    assertEquals(DATA.getDiscountFactor(t), Math.exp(-R * t), 0);
    BlackOptionDataBundle other = new BlackOptionDataBundle(F, CURVE, SURFACE, DATE);
    assertEquals(other, DATA);
    assertEquals(other.hashCode(), DATA.hashCode());
    other = new BlackOptionDataBundle(DATA);
    assertEquals(other, DATA);
    assertEquals(other.hashCode(), DATA.hashCode());
    other = new BlackOptionDataBundle(F + 1, CURVE, SURFACE, DATE);
    assertFalse(other.equals(DATA));
    other =
        new BlackOptionDataBundle(
            F, YieldCurve.from(ConstantDoublesCurve.from(0.06)), SURFACE, DATE);
    assertFalse(other.equals(DATA));
    other =
        new BlackOptionDataBundle(
            F, CURVE, new VolatilitySurface(ConstantDoublesSurface.from(0.6)), DATE);
    assertFalse(other.equals(DATA));
    other = new BlackOptionDataBundle(F, CURVE, SURFACE, DATE.plusDays(1));
    assertFalse(other.equals(DATA));
  }

  @Test
  public void testBuilders() {
    final ZonedDateTime newDate = DATE.plusDays(1);
    assertEquals(DATA.withDate(newDate), new BlackOptionDataBundle(F, CURVE, SURFACE, newDate));
    final double newForward = F + 1;
    assertEquals(
        DATA.withForward(newForward), new BlackOptionDataBundle(newForward, CURVE, SURFACE, DATE));
    final YieldCurve newCurve = YieldCurve.from(ConstantDoublesCurve.from(0.05));
    assertEquals(
        DATA.withInterestRateCurve(newCurve),
        new BlackOptionDataBundle(F, newCurve, SURFACE, DATE));
    final VolatilitySurface newSurface = new VolatilitySurface(ConstantDoublesSurface.from(0.9));
    assertEquals(
        DATA.withVolatilitySurface(newSurface),
        new BlackOptionDataBundle(F, CURVE, newSurface, DATE));
  }
}
 @Test
 public void testBuilders() {
   final ZonedDateTime newDate = DATE.plusDays(1);
   assertEquals(DATA.withDate(newDate), new BlackOptionDataBundle(F, CURVE, SURFACE, newDate));
   final double newForward = F + 1;
   assertEquals(
       DATA.withForward(newForward), new BlackOptionDataBundle(newForward, CURVE, SURFACE, DATE));
   final YieldCurve newCurve = YieldCurve.from(ConstantDoublesCurve.from(0.05));
   assertEquals(
       DATA.withInterestRateCurve(newCurve),
       new BlackOptionDataBundle(F, newCurve, SURFACE, DATE));
   final VolatilitySurface newSurface = new VolatilitySurface(ConstantDoublesSurface.from(0.9));
   assertEquals(
       DATA.withVolatilitySurface(newSurface),
       new BlackOptionDataBundle(F, CURVE, newSurface, DATE));
 }
 @Test
 public void test() {
   assertEquals(MODEL.getPricingFunction(END).evaluate(DATA), 0, 0);
   assertEquals(
       MODEL
           .getPricingFunction(FORWARD)
           .evaluate(
               DATA.withVolatilitySurface(
                   new VolatilitySurface(ConstantDoublesSurface.from(1e-9)))),
       0,
       0);
   assertEquals(
       MODEL.getPricingFunction(NOW).evaluate(DATA),
       BSM.getPricingFunction(VANILLA).evaluate(DATA),
       1e-4);
   assertEquals(MODEL.getPricingFunction(FORWARD).evaluate(DATA), 4.4064, 1e-4);
 }
Example #9
0
  public void testFlatSurface() {
    final double theta = 0.5;
    final double ft = FORWARD_CURVE.getForward(EXPIRY);

    final double fL = Math.log(ft / 5.0);
    final double fH = Math.log(5.0 * ft);
    final ConvectionDiffusionPDESolver solver = new ThetaMethodFiniteDifference(theta, false);

    final BoundaryCondition lower = new NeumannBoundaryCondition(1.0, fL, true);
    final BoundaryCondition upper = new NeumannBoundaryCondition(1.0, fH, false);

    final MeshingFunction timeMesh = new ExponentialMeshing(0, EXPIRY, 100, 0.0);
    final MeshingFunction spaceMesh = new ExponentialMeshing(fL, fH, 101, 0.0);

    final PDEGrid1D grid = new PDEGrid1D(timeMesh, spaceMesh);
    final PDE1DDataBundle<ConvectionDiffusionPDE1DCoefficients> db =
        new PDE1DDataBundle<>(PDE, INITIAL_COND, lower, upper, grid);
    final PDEResults1D res = solver.solve(db);

    final int n = res.getNumberSpaceNodes();

    final double kVol = Math.sqrt(-2 * (res.getFunctionValue(n / 2) - Math.log(ft)) / EXPIRY);

    assertEquals(FLAT_VOL, kVol, 1e-6);

    final YieldAndDiscountCurve yieldCurve =
        new YieldCurve("test", ConstantDoublesCurve.from(DRIFT));
    final AffineDividends ad = AffineDividends.noDividends();

    final EquityVarianceSwapBackwardsPurePDE backSolver = new EquityVarianceSwapBackwardsPurePDE();
    final PureLocalVolatilitySurface plv =
        new PureLocalVolatilitySurface(ConstantDoublesSurface.from(FLAT_VOL));

    final double[] res2 = backSolver.expectedVariance(SPOT, yieldCurve, ad, EXPIRY, plv);
    final double kVol2 = Math.sqrt(res2[0] / EXPIRY);
    assertEquals(FLAT_VOL, kVol2, 1e-6);
  }
public class ComplexChooserOptionModelTest {
  private static final YieldAndDiscountCurve CURVE =
      YieldCurve.from(ConstantDoublesCurve.from(0.1));
  private static final double B = 0.05;
  private static final VolatilitySurface SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(0.35));
  private static final double SPOT = 50;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1);
  private static final double CHOOSE_TIME = 0.25;
  private static final double CALL_LIFE = 0.5;
  private static final double PUT_LIFE = 7. / 12;
  private static final Expiry CHOOSE_DATE =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, CHOOSE_TIME));
  private static final Expiry CALL_EXPIRY =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, CALL_LIFE));
  private static final Expiry PUT_EXPIRY =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, PUT_LIFE));
  private static final double CALL_STRIKE = 55;
  private static final double PUT_STRIKE = 48;

  @SuppressWarnings("unused")
  private static final OptionDefinition CALL =
      new EuropeanVanillaOptionDefinition(CALL_STRIKE, CALL_EXPIRY, true);

  @SuppressWarnings("unused")
  private static final OptionDefinition PUT =
      new EuropeanVanillaOptionDefinition(PUT_STRIKE, PUT_EXPIRY, false);

  private static final ComplexChooserOptionDefinition CHOOSER =
      new ComplexChooserOptionDefinition(
          CHOOSE_DATE, CALL_STRIKE, CALL_EXPIRY, PUT_STRIKE, PUT_EXPIRY);
  private static final StandardOptionDataBundle DATA =
      new StandardOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE);
  private static final AnalyticOptionModel<ComplexChooserOptionDefinition, StandardOptionDataBundle>
      MODEL = new ComplexChooserOptionModel();

  @SuppressWarnings("unused")
  private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM =
      new BlackScholesMertonModel();

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDefinition() {
    MODEL.getPricingFunction(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    MODEL.getPricingFunction(CHOOSER).evaluate((StandardOptionDataBundle) null);
  }

  @Test
  public void test() {
    // TODO test wrt BSM
    // final double spot = 2;
    // final StandardOptionDataBundle data = DATA.withSpot(spot);
    // final ComplexChooserOptionDefinition chooser = new ComplexChooserOptionDefinition(new
    // Expiry(DATE), CALL_STRIKE, CALL_EXPIRY, PUT_STRIKE, PUT_EXPIRY);
    // assertEquals(MODEL.getPricingFunction(chooser).evaluate(data), BSM.getPricingFunction(
    // new EuropeanVanillaOptionDefinition(CALL_STRIKE, new
    // Expiry(DateUtil.getDateOffsetWithYearFraction(DATE, CALL_LIFE)), true)).evaluate(data), 0);
    assertEquals(MODEL.getPricingFunction(CHOOSER).evaluate(DATA), 6.0508, 1e-4);
  }
}
/** Test. */
@Test
public class SkewKurtosisOptionDataBundleTest {
  private static final double R = 0.03;
  private static final double SIGMA = 0.25;
  private static final YieldAndDiscountCurve CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
  private static final double B = 0.03;
  private static final VolatilitySurface SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(SIGMA));
  private static final double SPOT = 100;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 5, 1);
  private static final double SKEW = 1.2;
  private static final double KURTOSIS = 4.5;
  private static final YieldAndDiscountCurve OTHER_CURVE =
      YieldCurve.from(ConstantDoublesCurve.from(R + 1));
  private static final double OTHER_B = B + 1;
  private static final VolatilitySurface OTHER_SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(SIGMA + 1));
  private static final double OTHER_SPOT = SPOT + 1;
  private static final ZonedDateTime OTHER_DATE = DateUtils.getDateOffsetWithYearFraction(DATE, 1);
  private static final double OTHER_SKEW = 0.1;
  private static final double OTHER_KURTOSIS = 3;
  private static final SkewKurtosisOptionDataBundle DATA =
      new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, SKEW, KURTOSIS);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullBundle() {
    new SkewKurtosisOptionDataBundle(null);
  }

  @Test
  public void testGetters() {
    assertEquals(DATA.getInterestRateCurve(), CURVE);
    assertEquals(DATA.getCostOfCarry(), B, 0);
    assertEquals(DATA.getDate(), DATE);
    assertEquals(DATA.getSpot(), SPOT, 0);
    assertEquals(DATA.getVolatilitySurface(), SURFACE);
  }

  @Test
  public void testGetInterestRate() {
    for (int i = 0; i < 10; i++) {
      assertEquals(DATA.getInterestRate(Math.random()), R, 1e-15);
    }
  }

  @Test
  public void testGetVolatility() {
    for (int i = 0; i < 10; i++) {
      assertEquals(DATA.getVolatility(Math.random(), Math.random()), SIGMA, 1e-15);
    }
  }

  @Test
  public void testEqualsAndHashCode() {
    final SkewKurtosisOptionDataBundle data1 =
        new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, SKEW, KURTOSIS);
    final SkewKurtosisOptionDataBundle data2 =
        new SkewKurtosisOptionDataBundle(
            new StandardOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE), SKEW, KURTOSIS);
    final SkewKurtosisOptionDataBundle data3 =
        new SkewKurtosisOptionDataBundle(
            new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, SKEW, KURTOSIS));
    assertEquals(DATA, data1);
    assertEquals(DATA.hashCode(), data1.hashCode());
    assertEquals(DATA, data2);
    assertEquals(DATA.hashCode(), data2.hashCode());
    assertEquals(DATA, data3);
    assertEquals(DATA.hashCode(), data3.hashCode());
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(OTHER_CURVE, B, SURFACE, SPOT, DATE, SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, OTHER_B, SURFACE, SPOT, DATE, SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, B, OTHER_SURFACE, SPOT, DATE, SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, OTHER_SPOT, DATE, SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, OTHER_DATE, SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, OTHER_SKEW, KURTOSIS)));
    assertFalse(
        DATA.equals(
            new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, SKEW, OTHER_KURTOSIS)));
  }

  @Test
  public void testBuilders() {
    assertEquals(
        new SkewKurtosisOptionDataBundle(OTHER_CURVE, B, SURFACE, SPOT, DATE, SKEW, KURTOSIS),
        DATA.withInterestRateCurve(OTHER_CURVE));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, OTHER_B, SURFACE, SPOT, DATE, SKEW, KURTOSIS),
        DATA.withCostOfCarry(OTHER_B));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, B, OTHER_SURFACE, SPOT, DATE, SKEW, KURTOSIS),
        DATA.withVolatilitySurface(OTHER_SURFACE));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, OTHER_SPOT, DATE, SKEW, KURTOSIS),
        DATA.withSpot(OTHER_SPOT));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, OTHER_DATE, SKEW, KURTOSIS),
        DATA.withDate(OTHER_DATE));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, OTHER_SKEW, KURTOSIS),
        DATA.withSkew(OTHER_SKEW));
    assertEquals(
        new SkewKurtosisOptionDataBundle(CURVE, B, SURFACE, SPOT, DATE, SKEW, OTHER_KURTOSIS),
        DATA.withKurtosis(OTHER_KURTOSIS));
  }
}
 private StandardOptionDataBundle getBundle(final double sigma) {
   return new StandardOptionDataBundle(
       CURVE, B, new VolatilitySurface(ConstantDoublesSurface.from(sigma)), SPOT, DATE);
 }
  static {
    PURE_LOG_PAY_OFF =
        new Function1D<Double, Double>() {
          final double fT = DIV_CURVES.getF(EXPIRY);
          final double dT = DIV_CURVES.getD(EXPIRY);

          @Override
          public Double evaluate(final Double x) {
            final double s = (fT - dT) * Math.exp(x) + dT;
            return Math.log(s);
          }
        };

    final Function<Double, Double> localVol =
        new Function<Double, Double>() {
          @Override
          public Double evaluate(final Double... ts) {
            final double t = ts[0];
            final double s = ts[1];
            final double d = DIV_CURVES.getD(t);
            if (s < d) {
              return 0.0;
            }
            return PURE_VOL * (s - d) / s;
          }
        };

    LOCAL_VOL = new LocalVolatilitySurfaceStrike(FunctionalDoublesSurface.from(localVol));

    final Function<Double, Double> localVolSpecial =
        new Function<Double, Double>() {
          @Override
          public Double evaluate(final Double... tf) {
            final double t = tf[0];
            final double f = tf[1];
            final double rtT = DIV_CURVES.getR(t);
            final double dtT = DIV_CURVES.getD(t);
            final double ftT = DIV_CURVES.getF(t);
            //        if (f < d) {
            //          return 0.0;
            //        }
            final double x = f / rtT / (ftT - dtT);
            return PURE_LOCAL_VOL.getVolatility(t, x);
          }
        };

    LOCAL_VOL_SPECIAL =
        new LocalVolatilitySurfaceStrike(FunctionalDoublesSurface.from(localVolSpecial));

    final Function<Double, Double> pureLocalVol =
        new Function<Double, Double>() {
          @Override
          public Double evaluate(final Double... tx) {
            final double t = tx[0];
            final double x = tx[1];
            final double f = DIV_CURVES.getF(t);
            final double d = DIV_CURVES.getD(t);
            return VOL * ((f - d) * x + d) / (f - d) / x;
          }
        };

    PURE_LOCAL_VOL =
        new LocalVolatilitySurfaceMoneyness(
            FunctionalDoublesSurface.from(pureLocalVol), new ForwardCurve(1.0));

    PURE_LOCAL_VOL_FLAT =
        new LocalVolatilitySurfaceMoneyness(
            ConstantDoublesSurface.from(PURE_VOL), new ForwardCurve(1.0));
    LOCAL_VOL_FLAT = new LocalVolatilitySurfaceStrike(ConstantDoublesSurface.from(VOL));
  }
/** Test. */
@Test(groups = TestGroup.UNIT)
public class BlackScholesMertonImpliedVolatilitySurfaceModelTest {
  private static final RandomEngine RANDOM = new MersenneTwister64(MersenneTwister.DEFAULT_SEED);
  private static final BlackScholesMertonImpliedVolatilitySurfaceModel MODEL =
      new BlackScholesMertonImpliedVolatilitySurfaceModel();
  private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM =
      new BlackScholesMertonModel();
  private static final StandardOptionDataBundle DATA =
      new StandardOptionDataBundle(
          YieldCurve.from(ConstantDoublesCurve.from(0.01)),
          0.1,
          new VolatilitySurface(ConstantDoublesSurface.from(0.01)),
          100.,
          DateUtils.getUTCDate(2010, 1, 1));
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2009, 1, 1);
  private static final double EPS = 1e-3;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPrices() {
    MODEL.getSurface(null, DATA);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testEmptyPrices() {
    MODEL.getSurface(Collections.<OptionDefinition, Double>emptyMap(), DATA);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    MODEL.getSurface(
        Collections.<OptionDefinition, Double>singletonMap(
            new EuropeanVanillaOptionDefinition(RANDOM.nextDouble(), new Expiry(DATE), true), 2.3),
        null);
  }

  @Test
  public void test() {
    boolean isCall;
    double spot, strike, b, price;
    Expiry expiry;
    YieldAndDiscountCurve curve;
    EuropeanVanillaOptionDefinition definition;
    StandardOptionDataBundle initialData, data;
    double sigma = 0.01;
    for (int i = 0; i < 100; i++) {
      expiry = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, RANDOM.nextDouble() * 2));
      sigma += 0.03;
      spot = 2 * RANDOM.nextDouble() + 10;
      strike = 2 * RANDOM.nextDouble() + 10;
      curve = YieldCurve.from(ConstantDoublesCurve.from(RANDOM.nextDouble() / 10));
      b = 0; // RANDOM.nextDouble() / 20;
      isCall = RANDOM.nextDouble() < 0.5 ? true : false;
      definition = new EuropeanVanillaOptionDefinition(strike, expiry, isCall);
      initialData = new StandardOptionDataBundle(curve, b, null, spot, DATE);
      data =
          new StandardOptionDataBundle(
              curve, b, new VolatilitySurface(ConstantDoublesSurface.from(sigma)), spot, DATE);
      price = BSM.getPricingFunction(definition).evaluate(data);
      assertEquals(
          sigma,
          MODEL
              .getSurface(
                  Collections.<OptionDefinition, Double>singletonMap(definition, price),
                  initialData)
              .getVolatility(DoublesPair.of(0., 0.)),
          EPS);
    }
  }
}
/** Test. */
@Test
public class FFTOptionModelTest {
  private static final HashSet<Greek> GREEKS = Sets.newHashSet(Greek.FAIR_PRICE);
  private static final double R = 0.005;
  private static final YieldCurve YIELD_CURVE = YieldCurve.from(ConstantDoublesCurve.from(R));
  private static final double BLACK_VOL = 0.34;
  private static final VolatilitySurface VOLATILITY_SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(BLACK_VOL));
  private static final double FORWARD = 100;
  private static final double T = 2;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2011, 1, 1);
  private static final ZonedDateTime MATURITY = DATE.plusYears((int) T);
  private static final Expiry EXPIRY = new Expiry(MATURITY);
  private static final EuropeanVanillaOptionDefinition ITM_CALL =
      new EuropeanVanillaOptionDefinition(99, EXPIRY, true);
  private static final EuropeanVanillaOptionDefinition OTM_CALL =
      new EuropeanVanillaOptionDefinition(101, EXPIRY, true);
  private static final EuropeanVanillaOptionDefinition ITM_PUT =
      new EuropeanVanillaOptionDefinition(101, EXPIRY, false);
  private static final EuropeanVanillaOptionDefinition OTM_PUT =
      new EuropeanVanillaOptionDefinition(99, EXPIRY, false);
  private static final MartingaleCharacteristicExponent GAUSSIAN =
      new GaussianMartingaleCharacteristicExponent(BLACK_VOL);
  private static final StandardOptionDataBundle BSM_DATA =
      new StandardOptionDataBundle(
          YIELD_CURVE, R, VOLATILITY_SURFACE, Math.exp(-R * T) * FORWARD, DATE);
  private static final BlackOptionDataBundle BLACK_DATA =
      new BlackOptionDataBundle(FORWARD, YIELD_CURVE, VOLATILITY_SURFACE, DATE);
  private static final OptionModel<EuropeanVanillaOptionDefinition, BlackOptionDataBundle>
      FFT_MODEL = new FFTOptionModel(GAUSSIAN);
  private static final OptionModel<OptionDefinition, StandardOptionDataBundle> BSM_MODEL =
      new BlackScholesMertonModel();
  private static final double EPS = 1e-2;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCharacteristicExponent1() {
    new FFTOptionModel(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullCharacteristicExponent2() {
    new FFTOptionModel(null, 100, 10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeNStrikes() {
    new FFTOptionModel(GAUSSIAN, -100, 10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeDelta() {
    new FFTOptionModel(GAUSSIAN, 100, -10, -0.5, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testZeroAlpha() {
    new FFTOptionModel(GAUSSIAN, 100, 10, 0, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testAlpha() {
    new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNegativeTolerance() {
    new FFTOptionModel(GAUSSIAN, 100, 10, -1, 1e-8);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDefinition() {
    FFT_MODEL.getGreeks(null, BLACK_DATA, GREEKS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    FFT_MODEL.getGreeks(ITM_CALL, null, GREEKS);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullGreeks() {
    FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, null);
  }

  @Test(expectedExceptions = UnsupportedOperationException.class)
  public void testWrongGreeks() {
    FFT_MODEL.getGreeks(ITM_CALL, BLACK_DATA, Sets.newHashSet(Greek.DELTA, Greek.GAMMA));
  }

  @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);
  }
}
/** Test. */
@Test(groups = TestGroup.UNIT)
public class ExtremeSpreadOptionDefinitionTest {
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2010, 7, 1);
  private static final Expiry EXPIRY = new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 1));
  private static final Expiry PERIOD_END =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.275));
  private static final ExtremeSpreadOptionDefinition PUT =
      new ExtremeSpreadOptionDefinition(EXPIRY, false, PERIOD_END, false);
  private static final ExtremeSpreadOptionDefinition PUT_REVERSE =
      new ExtremeSpreadOptionDefinition(EXPIRY, false, PERIOD_END, true);
  private static final ExtremeSpreadOptionDefinition CALL =
      new ExtremeSpreadOptionDefinition(EXPIRY, true, PERIOD_END, false);
  private static final ExtremeSpreadOptionDefinition CALL_REVERSE =
      new ExtremeSpreadOptionDefinition(EXPIRY, true, PERIOD_END, true);
  private static final DoubleTimeSeries<?> SPOT_SERIES =
      ImmutableZonedDateTimeDoubleTimeSeries.ofUTC(
          new ZonedDateTime[] {
            DateUtils.getUTCDate(2010, 7, 1),
            DateUtils.getUTCDate(2010, 8, 1),
            DateUtils.getUTCDate(2010, 9, 1),
            DateUtils.getUTCDate(2010, 10, 1),
            DateUtils.getUTCDate(2010, 11, 1),
            DateUtils.getUTCDate(2010, 12, 1),
            DateUtils.getUTCDate(2011, 1, 1),
            DateUtils.getUTCDate(2011, 2, 1),
            DateUtils.getUTCDate(2011, 3, 1),
            DateUtils.getUTCDate(2011, 4, 1),
            DateUtils.getUTCDate(2011, 5, 1),
            DateUtils.getUTCDate(2011, 6, 1)
          },
          new double[] {1, 2, 0, 1, 4, 15, 4, 4, 0, 4, 4, 4});
  private static final StandardOptionWithSpotTimeSeriesDataBundle DATA =
      new StandardOptionWithSpotTimeSeriesDataBundle(
          YieldCurve.from(ConstantDoublesCurve.from(0.)),
          0,
          new VolatilitySurface(ConstantDoublesSurface.from(0)),
          2,
          DATE,
          SPOT_SERIES);

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullPeriodEnd() {
    new ExtremeSpreadOptionDefinition(EXPIRY, true, null, true);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testPeriodEndAfterExpiry() {
    new ExtremeSpreadOptionDefinition(
        EXPIRY, false, new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 2)), false);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDate() {
    PUT.getTimeFromPeriodEnd(null);
  }

  @Test
  public void test() {
    assertEquals(PUT.getPeriodEnd(), PERIOD_END);
    assertFalse(PUT.isReverse());
    ExtremeSpreadOptionDefinition other =
        new ExtremeSpreadOptionDefinition(EXPIRY, false, PERIOD_END, false);
    assertEquals(other, PUT);
    assertEquals(other.hashCode(), PUT.hashCode());
    other =
        new ExtremeSpreadOptionDefinition(
            EXPIRY, false, new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.15)), false);
    assertFalse(other.equals(PUT));
    other = new ExtremeSpreadOptionDefinition(EXPIRY, false, PERIOD_END, true);
    assertFalse(other.equals(PUT));
    assertEquals(PUT.getTimeFromPeriodEnd(EXPIRY.getExpiry()), 0.725, 0);
    assertEquals(PUT.getTimeFromPeriodEnd(DATE), -0.275, 0);
  }

  @Test
  public void testExercise() {
    assertFalse(PUT.getExerciseFunction().shouldExercise(DATA, null));
    assertFalse(PUT_REVERSE.getExerciseFunction().shouldExercise(DATA, null));
  }

  @Test
  public void testPayoff() {
    assertEquals(CALL.getPayoffFunction().getPayoff(DATA, null), 13, 0);
    assertEquals(CALL_REVERSE.getPayoffFunction().getPayoff(DATA, null), 0, 0);
    assertEquals(PUT.getPayoffFunction().getPayoff(DATA, null), 0, 0);
    assertEquals(PUT_REVERSE.getPayoffFunction().getPayoff(DATA, null), 13, 0);
  }
}
/** Test. */
@Test
public class BatesGeneralizedJumpDiffusionModelTest {
  private static final AnalyticOptionModel<
          OptionDefinition, BatesGeneralizedJumpDiffusionModelDataBundle>
      MODEL = new BatesGeneralizedJumpDiffusionModel();
  private static final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> BSM =
      new BlackScholesMertonModel();
  private static final YieldAndDiscountCurve CURVE =
      YieldCurve.from(ConstantDoublesCurve.from(0.08));
  private static final double B = 0.08;
  private static final VolatilitySurface SURFACE =
      new VolatilitySurface(ConstantDoublesSurface.from(0.25));
  private static final double SPOT = 100;
  private static final ZonedDateTime DATE = DateUtils.getUTCDate(2009, 1, 1);
  private static final Expiry EXPIRY1 =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.1));
  private static final Expiry EXPIRY2 =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.25));
  private static final Expiry EXPIRY3 =
      new Expiry(DateUtils.getDateOffsetWithYearFraction(DATE, 0.5));
  private static final double EPS1 = 1e-2;
  private static final double EPS2 = 1e-9;

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullDefinition() {
    MODEL.getPricingFunction(null);
  }

  @Test(expectedExceptions = IllegalArgumentException.class)
  public void testNullData() {
    MODEL
        .getPricingFunction(new EuropeanVanillaOptionDefinition(100, EXPIRY1, true))
        .evaluate((BatesGeneralizedJumpDiffusionModelDataBundle) null);
  }

  @Test
  public void test() {
    OptionDefinition call = new EuropeanVanillaOptionDefinition(80, EXPIRY1, true);
    BatesGeneralizedJumpDiffusionModelDataBundle data =
        new BatesGeneralizedJumpDiffusionModelDataBundle(
            CURVE, B, SURFACE, SPOT, DATE, 0., -0.04, 0.);
    assertEquals(
        BSM.getPricingFunction(call).evaluate(data),
        MODEL.getPricingFunction(call).evaluate(data),
        EPS2);
    call = new EuropeanVanillaOptionDefinition(80, EXPIRY1, true);
    data = data.withLambda(1.).withDelta(0.1);
    assertEquals(20.67, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(90, EXPIRY2, true);
    data = data.withLambda(5.);
    assertEquals(14.13, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(100, EXPIRY3, true);
    data = data.withLambda(10.);
    assertEquals(13.62, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    data = data.withDelta(0.25);
    data = data.withLambda(1.);
    call = new EuropeanVanillaOptionDefinition(90, EXPIRY1, true);
    assertEquals(11.57, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(100, EXPIRY2, true);
    data = data.withLambda(5.);
    assertEquals(12.25, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(110, EXPIRY3, true);
    data = data.withLambda(10.);
    assertEquals(20.43, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    data = data.withDelta(0.5);
    data = data.withLambda(1.);
    call = new EuropeanVanillaOptionDefinition(100, EXPIRY1, true);
    assertEquals(5.18, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(110, EXPIRY2, true);
    data = data.withLambda(5.);
    assertEquals(16.52, MODEL.getPricingFunction(call).evaluate(data), EPS1);
    call = new EuropeanVanillaOptionDefinition(120, EXPIRY3, true);
    data = data.withLambda(10.);
    assertEquals(37.03, MODEL.getPricingFunction(call).evaluate(data), EPS1);
  }
}
  @Test
  /**
   * Tests the comparison with the other implementation. This test may be removed when only one
   * version remains.
   */
  public void comparison() {
    final AnalyticOptionModel<EuropeanStandardBarrierOptionDefinition, StandardOptionDataBundle>
        model = new EuropeanStandardBarrierOptionModel();
    final StandardOptionDataBundle data =
        new StandardOptionDataBundle(
            YieldCurve.from(ConstantDoublesCurve.from(RATE_DOM)),
            COST_OF_CARRY,
            new VolatilitySurface(ConstantDoublesSurface.from(VOLATILITY)),
            SPOT,
            REFERENCE_DATE);
    final Expiry expiry = new Expiry(EXPIRY_DATE);

    final double priceDI1 =
        BARRIER_FUNCTION.getPrice(
            VANILLA_CALL_K100, BARRIER_DOWN_IN, REBATE, SPOT, COST_OF_CARRY, RATE_DOM, VOLATILITY);
    final EuropeanStandardBarrierOptionDefinition optionBarrierDI =
        new EuropeanStandardBarrierOptionDefinition(
            STRIKE_MID, expiry, IS_CALL, BARRIER_DOWN_IN, REBATE);
    final double priceDI2 = model.getPricingFunction(optionBarrierDI).evaluate(data);
    assertEquals("Comparison Down In", priceDI2, priceDI1, 1.0E-10);

    final double priceDO1 =
        BARRIER_FUNCTION.getPrice(
            VANILLA_CALL_K100, BARRIER_DOWN_OUT, REBATE, SPOT, COST_OF_CARRY, RATE_DOM, VOLATILITY);
    final EuropeanStandardBarrierOptionDefinition optionBarrierDO =
        new EuropeanStandardBarrierOptionDefinition(
            STRIKE_MID, expiry, IS_CALL, BARRIER_DOWN_OUT, REBATE);
    final double priceDO2 = model.getPricingFunction(optionBarrierDO).evaluate(data);
    assertEquals("Comparison Down Out", priceDO2, priceDO1, 1.0E-10);

    final double priceUI1 =
        BARRIER_FUNCTION.getPrice(
            VANILLA_CALL_K100, BARRIER_UP_IN, REBATE, SPOT, COST_OF_CARRY, RATE_DOM, VOLATILITY);
    final EuropeanStandardBarrierOptionDefinition optionBarrierUI =
        new EuropeanStandardBarrierOptionDefinition(
            STRIKE_MID, expiry, IS_CALL, BARRIER_UP_IN, REBATE);
    final double priceUI2 = model.getPricingFunction(optionBarrierUI).evaluate(data);
    assertEquals("Comparison Up In", priceUI2, priceUI1, 1.0E-10);

    final double priceUO1 =
        BARRIER_FUNCTION.getPrice(
            VANILLA_CALL_K100, BARRIER_UP_OUT, REBATE, SPOT, COST_OF_CARRY, RATE_DOM, VOLATILITY);
    final EuropeanStandardBarrierOptionDefinition optionBarrierUO =
        new EuropeanStandardBarrierOptionDefinition(
            STRIKE_MID, expiry, IS_CALL, BARRIER_UP_OUT, REBATE);
    final double priceUO2 = model.getPricingFunction(optionBarrierUO).evaluate(data);
    assertEquals("Comparison Up Out", priceUO2, priceUO1, 1.0E-10);

    final double vol0 = 0.0;
    final double priceVol01 =
        BARRIER_FUNCTION.getPrice(
            VANILLA_CALL_K100, BARRIER_DOWN_IN, REBATE, SPOT, COST_OF_CARRY, RATE_DOM, vol0);
    final StandardOptionDataBundle data0 =
        new StandardOptionDataBundle(
            YieldCurve.from(ConstantDoublesCurve.from(RATE_DOM)),
            COST_OF_CARRY,
            new VolatilitySurface(ConstantDoublesSurface.from(vol0)),
            SPOT,
            REFERENCE_DATE);
    final double priceVol02 = model.getPricingFunction(optionBarrierDI).evaluate(data0);
    assertEquals(priceVol02, priceVol01, 1.0E-10);
  }