<commit_before>/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.model.option.pricing.analytic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.GenericImpliedVolatiltySolver;
import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.statistics.distribution.NormalDistribution;
import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution;
import com.opengamma.util.ArgumentChecker;

/**
 * The Barone-Adesi and Whaley approximation for the price of an American Option. <b>Note:</b> The  Bjerksund and Stensland (2002) approximation ({@link BjerksundStenslandModel}) is
 * more accurate and should be used in place of this.
 */
public class BaroneAdesiWhaleyModel {
  /** A logger */
  private static final Logger s_logger = LoggerFactory.getLogger(BaroneAdesiWhaleyModel.class);
  /** Normal probability distribution */
  private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1);

  /**
   * Get the price of an American option by the Barone-Adesi & Whaley approximation. <b>Note:</b> The  Bjerksund and Stensland (2002) approximation ({@link BjerksundStenslandModel}) is
   * more accurate and should be used in place of this.
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return The American option price
   */
  public double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    //TODO handle k = 0, t = 0 and sigma = 0
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPrice();
    }

    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPrice();
  }

  /**
   * Get the price of an American option by the Barone-Adesi & Whaley approximation and all the first order Greeks
   * <ol>
   * <li> price
   * <li> delta
   * <li> dual delta
   * <li> rho
   * <li> carry rho
   * <li> theta
   * <li> vega
   * </ol>
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return length 7 arrays containing the price, then the sensitivities (Greeks): delta (spot), dual-delta (strike), rho (risk-free rate),
   *  b-rho (cost-of-carry), theta (expiry), vega (sigma)
   */
  public double[] getPriceAdjoint(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {

    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPriceAdjoint();
    }
    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPriceAdjoint();
  }

  /**
   * Get the price, delta and gamma of an American option by the Barone-Adesi & Whaley approximation
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return length 3 array of price, delta and gamma
   */
  public double[] getPriceDeltaGamma(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPriceDeltaGamma();
    }
    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPriceDeltaGamma();
  }

  /**
   * Calculates the price and vega of an option and returns them as an array, with elements
   * <ol>
   * <li> price
   * <li> vega
   * </ol>
   * @param s0 The spot
   * @param k The strike
   * @param r The interest rate
   * @param b The cost-of-carry
   * @param t The time to expiry, greater than zero
   * @param sigma The volatility
   * @param isCall is the option a call
   * @return The price and vega of the option
   */
  public double[] getPriceAndVega(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");
    final double[] temp = getPriceAdjoint(s0, k, r, b, t, sigma, isCall);
    //TODO calculate vega separate from other Greeks
    return new double[] {temp[0], temp[6] };
  }

  /**
   * Get a function for the price and vega of an American option by the Barone-Adesi & Whaley approximation in terms of the volatility (sigma).
   * This is primarily used by the GenericImpliedVolatiltySolver to find a (Barone-Adesi & Whaley) implied volatility for a given market price of an American option
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param isCall true for calls
   * @return A function from volatility (sigma) to price and vega
   */
  public Function1D<Double, double[]> getPriceAndVegaFunction(final double s0, final double k, final double r, final double b, final double t, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    return new Function1D<Double, double[]>() {
      @Override
      public double[] evaluate(final Double sigma) {
        return getPriceAndVega(s0, k, r, b, t, sigma, isCall);
      }
    };
  }

  /**
   * Get the implied volatility according to the Barone-Adesi & Whaley approximation for the price of an American option quoted in the market.  It is the number that put into the
   * Barone-Adesi & Whaley approximation gives the market price. <b>This is not the same as the Black implied volatility</b> (which is only applicable to European options),
   * although it may be numerically close. <p>
   * If the price indicates that the option should be excised immediately (price = s0-k for calls and k-s0 for puts), then implied volatility does not exist, and zero is returned
   * (with a warning)
   * @param price The market price of an American option
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param isCall true for calls
   * @return The (Barone-Adesi & Whaley) implied volatility.
   */
  public double impliedVolatility(final double price, final double s0, final double k, final double r, final double b, final double t, final boolean isCall) {

    ArgumentChecker.isTrue((isCall && price >= (s0 - k)) || (!isCall && price >= (k - s0)), "The price is less than the excised immediately price");
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");

    if ((isCall && price == (s0 - k)) || (!isCall && price == (k - s0))) {
      s_logger.warn("The price indicates that this option should be excised immediately, therefore there is no implied volatility. Zero is returned.");
      return 0.0;
    }
    final Function1D<Double, double[]> func = getPriceAndVegaFunction(s0, k, r, b, t, isCall);
    return GenericImpliedVolatiltySolver.impliedVolatility(price, func);
  }<commit_msg>Fixed typo that was popping up in Analytics tests for BaroneAdesiWhaleyModel<commit_after>/**
 * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
 * 
 * Please see distribution for license.
 */
package com.opengamma.analytics.financial.model.option.pricing.analytic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.opengamma.analytics.financial.model.volatility.BlackFormulaRepository;
import com.opengamma.analytics.financial.model.volatility.GenericImpliedVolatiltySolver;
import com.opengamma.analytics.math.MathException;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.statistics.distribution.NormalDistribution;
import com.opengamma.analytics.math.statistics.distribution.ProbabilityDistribution;
import com.opengamma.util.ArgumentChecker;

/**
 * The Barone-Adesi and Whaley approximation for the price of an American Option. <b>Note:</b> The  Bjerksund and Stensland (2002) approximation ({@link BjerksundStenslandModel}) is
 * more accurate and should be used in place of this.
 */
public class BaroneAdesiWhaleyModel {
  /** A logger */
  private static final Logger s_logger = LoggerFactory.getLogger(BaroneAdesiWhaleyModel.class);
  /** Normal probability distribution */
  private static final ProbabilityDistribution<Double> NORMAL = new NormalDistribution(0, 1);

  /**
   * Get the price of an American option by the Barone-Adesi & Whaley approximation. <b>Note:</b> The  Bjerksund and Stensland (2002) approximation ({@link BjerksundStenslandModel}) is
   * more accurate and should be used in place of this.
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return The American option price
   */
  public double price(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    //TODO handle k = 0, t = 0 and sigma = 0
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPrice();
    }

    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPrice();
  }

  /**
   * Get the price of an American option by the Barone-Adesi & Whaley approximation and all the first order Greeks
   * <ol>
   * <li> price
   * <li> delta
   * <li> dual delta
   * <li> rho
   * <li> carry rho
   * <li> theta
   * <li> vega
   * </ol>
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return length 7 arrays containing the price, then the sensitivities (Greeks): delta (spot), dual-delta (strike), rho (risk-free rate),
   *  b-rho (cost-of-carry), theta (expiry), vega (sigma)
   */
  public double[] getPriceAdjoint(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {

    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPriceAdjoint();
    }
    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPriceAdjoint();
  }

  /**
   * Get the price, delta and gamma of an American option by the Barone-Adesi & Whaley approximation
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param sigma The volatility
   * @param isCall true for calls
   * @return length 3 array of price, delta and gamma
   */
  public double[] getPriceDeltaGamma(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");

    if (isCall) {
      final CallSolver solver = new CallSolver(s0, k, r, b, t, sigma);
      return solver.getPriceDeltaGamma();
    }
    final PutSolver solver = new PutSolver(s0, k, r, b, t, sigma);
    return solver.getPriceDeltaGamma();
  }

  /**
   * Calculates the price and vega of an option and returns them as an array, with elements
   * <ol>
   * <li> price
   * <li> vega
   * </ol>
   * @param s0 The spot
   * @param k The strike
   * @param r The interest rate
   * @param b The cost-of-carry
   * @param t The time to expiry, greater than zero
   * @param sigma The volatility
   * @param isCall is the option a call
   * @return The price and vega of the option
   */
  public double[] getPriceAndVega(final double s0, final double k, final double r, final double b, final double t, final double sigma, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    ArgumentChecker.isTrue(sigma > 0.0, "sigma must be greater than zero");
    final double[] temp = getPriceAdjoint(s0, k, r, b, t, sigma, isCall);
    //TODO calculate vega separate from other Greeks
    return new double[] {temp[0], temp[6] };
  }

  /**
   * Get a function for the price and vega of an American option by the Barone-Adesi & Whaley approximation in terms of the volatility (sigma).
   * This is primarily used by the GenericImpliedVolatiltySolver to find a (Barone-Adesi & Whaley) implied volatility for a given market price of an American option
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param isCall true for calls
   * @return A function from volatility (sigma) to price and vega
   */
  public Function1D<Double, double[]> getPriceAndVegaFunction(final double s0, final double k, final double r, final double b, final double t, final boolean isCall) {
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");
    return new Function1D<Double, double[]>() {
      @Override
      public double[] evaluate(final Double sigma) {
        return getPriceAndVega(s0, k, r, b, t, sigma, isCall);
      }
    };
  }

  /**
   * Get the implied volatility according to the Barone-Adesi & Whaley approximation for the price of an American option quoted in the market.  It is the number that put into the
   * Barone-Adesi & Whaley approximation gives the market price. <b>This is not the same as the Black implied volatility</b> (which is only applicable to European options),
   * although it may be numerically close. <p>
   * If the price indicates that the option should be exercised immediately (price = s0-k for calls and k-s0 for puts), then implied volatility does not exist, and zero is returned
   * (with a warning)
   * @param price The market price of an American option
   * @param s0 The spot
   * @param k The strike
   * @param r The risk-free rate
   * @param b The cost-of-carry
   * @param t The time-to-expiry
   * @param isCall true for calls
   * @return The (Barone-Adesi & Whaley) implied volatility.
   */
  public double impliedVolatility(final double price, final double s0, final double k, final double r, final double b, final double t, final boolean isCall) {

    ArgumentChecker.isTrue((isCall && price >= (s0 - k)) || (!isCall && price >= (k - s0)), "The price is less than the exercised immediately price");
    ArgumentChecker.isTrue(s0 > 0.0, "spot must be greater than zero");
    ArgumentChecker.isTrue(k > 0.0, "strike must be greater than zero");
    ArgumentChecker.isTrue(t > 0.0, "t must be greater than zero");

    if ((isCall && price == (s0 - k)) || (!isCall && price == (k - s0))) {
      s_logger.warn("The price indicates that this option should be exercised immediately, therefore there is no implied volatility. Zero is returned.");
      return 0.0;
    }
    final Function1D<Double, double[]> func = getPriceAndVegaFunction(s0, k, r, b, t, isCall);
    return GenericImpliedVolatiltySolver.impliedVolatility(price, func);
  }
{'fraction_non_alphanumeric': 0.10062132292296695, 'fraction_numerical': 0.011656677846813658, 'mean_word_length': 3.485326757090012, 'pattern_counts': {'":': 0, '<': 51, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6083705', 'n_tokens_mistral': 5842, 'n_tokens_neox': 5583, 'n_words': 2180}