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);
 }