Package com.opengamma.analytics.financial.forex.provider

Source Code of com.opengamma.analytics.financial.forex.provider.ForexOptionDigitalCallSpreadBlackSmileMethod

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.forex.provider;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.forex.derivative.Forex;
import com.opengamma.analytics.financial.forex.derivative.ForexOptionDigital;
import com.opengamma.analytics.financial.forex.derivative.ForexOptionVanilla;
import com.opengamma.analytics.financial.forex.method.PresentValueForexBlackVolatilityNodeSensitivityDataBundle;
import com.opengamma.analytics.financial.forex.method.PresentValueForexBlackVolatilitySensitivity;
import com.opengamma.analytics.financial.model.volatility.VolatilityAndBucketedSensitivities;
import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation;
import com.opengamma.analytics.financial.provider.description.forex.BlackForexSmileProviderInterface;
import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface;
import com.opengamma.analytics.financial.provider.sensitivity.multicurve.MultipleCurrencyMulticurveSensitivity;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
import com.opengamma.analytics.math.matrix.DoubleMatrix2D;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.money.CurrencyAmount;
import com.opengamma.util.money.MultipleCurrencyAmount;
import com.opengamma.util.tuple.DoublesPair;

/**
* Pricing method for digital Forex option transactions as a call or put spread option.
* The underlying vanilla options are priced with the ForexOptionVanillaBlackSmileMethod.
*/
public class ForexOptionDigitalCallSpreadBlackSmileMethod {

  /**
   * The relative spread used in the call-spread pricing. The call spread strikes are (for an original strike K), K*(1-spread) and K*(1+spread).
   */
  private final double _spread;

  /**
   * The base method for the pricing of standard vanilla options.
   */
  private static final ForexOptionVanillaBlackSmileMethod BASE_METHOD = ForexOptionVanillaBlackSmileMethod.getInstance();

  /**
   * Constructor of the digital pricing method.
   * @param spread The relative spread used in the call-spread pricing. The call spread strikes are (for an original strike K), K*(1-spread) and K*(1+spread).
   */
  public ForexOptionDigitalCallSpreadBlackSmileMethod(final double spread) {
    _spread = spread;
  }

  /**
   * Computes the present value of a digital Forex option by call-spread.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The present value.
   */
  public MultipleCurrencyAmount presentValue(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    ForexOptionVanilla[] callSpread = callSpread(optionDigital, _spread);
    // Spread value
    MultipleCurrencyAmount pvM = BASE_METHOD.presentValue(callSpread[0], smileMulticurves);
    MultipleCurrencyAmount pvP = BASE_METHOD.presentValue(callSpread[1], smileMulticurves);
    return pvM.plus(pvP);
  }

  /**
   * Computes the currency exposure of a digital Forex option by call-spread.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The currency exposure.
   */
  public MultipleCurrencyAmount currencyExposure(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    ForexOptionVanilla[] callSpread = callSpread(optionDigital, _spread);
    // Spread value
    MultipleCurrencyAmount ceM = BASE_METHOD.currencyExposure(callSpread[0], smileMulticurves);
    MultipleCurrencyAmount ceP = BASE_METHOD.currencyExposure(callSpread[1], smileMulticurves);
    return ceM.plus(ceP);
  }

  /**
   * Computes the curve sensitivity of a digital Forex option by call-spread.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The curve sensitivity.
   */
  public MultipleCurrencyMulticurveSensitivity presentValueCurveSensitivity(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    ForexOptionVanilla[] callSpread = callSpread(optionDigital, _spread);
    // Spread value
    MultipleCurrencyMulticurveSensitivity pvcsM = BASE_METHOD.presentValueCurveSensitivity(callSpread[0], smileMulticurves);
    MultipleCurrencyMulticurveSensitivity pvcsP = BASE_METHOD.presentValueCurveSensitivity(callSpread[1], smileMulticurves);
    return pvcsM.plus(pvcsP);
  }

  /**
   * Computes the relative gamma of the Forex option. The relative gamma is the second order derivative of the pv relative to the option notional.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The gamma.
   */
  public double gammaRelative(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    final CurrencyAmount gamma = gamma(optionDigital, smileMulticurves);
    return gamma.getAmount() / Math.abs(optionDigital.getUnderlyingForex().getPaymentCurrency2().getAmount());
  }

  /**
   * Computes the gamma of the Forex option. The relative is the second order derivative of the pv.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The gamma.
   */
  public CurrencyAmount gamma(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread());
    // Spread value
    final CurrencyAmount gammaM = BASE_METHOD.gamma(callSpread[0], smileMulticurves, optionDigital.payDomestic());
    final CurrencyAmount gammaP = BASE_METHOD.gamma(callSpread[1], smileMulticurves, optionDigital.payDomestic());
    return gammaM.plus(gammaP);
  }

  /**
   * Computes the gamma of the Forex option multiplied by the spot rate. The gamma is the second order derivative of the pv.
   * The reason to multiply by the spot rate is to be able to compute the change of delta for a relative increase of e of the spot rate (from X to X(1+e)).
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The gamma.
   */
  public CurrencyAmount gammaSpot(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread());
    // Spread value
    final CurrencyAmount gammaM = BASE_METHOD.gammaSpot(callSpread[0], smileMulticurves, optionDigital.payDomestic());
    final CurrencyAmount gammaP = BASE_METHOD.gammaSpot(callSpread[1], smileMulticurves, optionDigital.payDomestic());
    return gammaM.plus(gammaP);
  }

  /**
   * Computes the volatility sensitivity of the vanilla option with the Black function and a volatility from a volatility surface. The sensitivity
   * is computed with respect to the computed Black implied volatility and not with respect to the volatility surface input.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The volatility sensitivity. The sensitivity figures are, like the present value, in the domestic currency (currency 2).
   */
  public PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final ForexOptionDigital optionDigital, final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread());
    // Spread value
    final PresentValueForexBlackVolatilitySensitivity pvbsM = BASE_METHOD.presentValueBlackVolatilitySensitivity(callSpread[0], smileMulticurves);
    final PresentValueForexBlackVolatilitySensitivity pvbsP = BASE_METHOD.presentValueBlackVolatilitySensitivity(callSpread[1], smileMulticurves);
    return pvbsM.plus(pvbsP);
  }

  /**
   * Computes the volatility sensitivity with respect to input data for a digital option. The sensitivity
   * is computed with respect to each node in the volatility surface.
   * @param optionDigital The option.
   * @param smileMulticurves The curve and smile data.
   * @return The volatility node sensitivity. The sensitivity figures are, like the present value, in the domestic currency (currency 2).
   */
  public PresentValueForexBlackVolatilityNodeSensitivityDataBundle presentValueBlackVolatilityNodeSensitivity(final ForexOptionDigital optionDigital,
      final BlackForexSmileProviderInterface smileMulticurves) {
    ArgumentChecker.notNull(optionDigital, "Forex option");
    Validate.notNull(smileMulticurves, "Smile");
    Validate.isTrue(smileMulticurves.checkCurrencies(optionDigital.getCurrency1(), optionDigital.getCurrency2()), "Option currencies not compatible with smile data");
    MulticurveProviderInterface multicurves = smileMulticurves.getMulticurveProvider();
    final PresentValueForexBlackVolatilitySensitivity pointSensitivity = presentValueBlackVolatilitySensitivity(optionDigital, smileMulticurves); // In ccy2
    final double df = multicurves.getDiscountFactor(optionDigital.getCurrency2(), optionDigital.getUnderlyingForex().getPaymentTime());
    final double spot = multicurves.getFxRate(optionDigital.getCurrency1(), optionDigital.getCurrency2());
    final double forward = spot * multicurves.getDiscountFactor(optionDigital.getCurrency1(), optionDigital.getUnderlyingForex().getPaymentTime()) / df;
    final SmileDeltaTermStructureParametersStrikeInterpolation volatilityModel = smileMulticurves.getVolatility();
    final double[][] vega = new double[volatilityModel.getNumberExpiration()][volatilityModel.getNumberStrike()];
    for (final DoublesPair point : pointSensitivity.getVega().getMap().keySet()) {
      final VolatilityAndBucketedSensitivities volAndSensitivities = smileMulticurves.getVolatilityAndSensitivities(optionDigital.getCurrency1(), optionDigital.getCurrency2(),
          optionDigital.getExpirationTime(), point.second, forward);
      final double[][] nodeWeight = volAndSensitivities.getBucketedSensitivities();
      for (int loopexp = 0; loopexp < volatilityModel.getNumberExpiration(); loopexp++) {
        for (int loopstrike = 0; loopstrike < volatilityModel.getNumberStrike(); loopstrike++) {
          vega[loopexp][loopstrike] += nodeWeight[loopexp][loopstrike] * pointSensitivity.getVega().getMap().get(point);
        }
      }
    }
    return new PresentValueForexBlackVolatilityNodeSensitivityDataBundle(optionDigital.getUnderlyingForex().getCurrency1(), optionDigital.getUnderlyingForex().getCurrency2(), new DoubleMatrix1D(
        volatilityModel.getTimeToExpiration()), new DoubleMatrix1D(volatilityModel.getDeltaFull()), new DoubleMatrix2D(vega));
  }

  protected ForexOptionVanilla[] callSpread(final ForexOptionDigital optionDigital, final double spread) {
    ForexOptionVanilla[] callSpread = new ForexOptionVanilla[2];
    double strike = optionDigital.getStrike();
    double strikeM = strike * (1 - spread);
    double strikeP = strike * (1 + spread);
    double amountPaid;
    double strikeRelM;
    double strikeRelP;
    if (optionDigital.payDomestic()) {
      amountPaid = Math.abs(optionDigital.getUnderlyingForex().getPaymentCurrency2().getAmount());
      strikeRelM = strikeM;
      strikeRelP = strikeP;
      double amount = amountPaid / (strikeRelP - strikeRelM);
      Forex forexM = new Forex(optionDigital.getUnderlyingForex().getPaymentCurrency1().withAmount(amount), optionDigital.getUnderlyingForex().getPaymentCurrency2().withAmount(-strikeRelM * amount));
      Forex forexP = new Forex(optionDigital.getUnderlyingForex().getPaymentCurrency1().withAmount(amount), optionDigital.getUnderlyingForex().getPaymentCurrency2().withAmount(-strikeRelP * amount));
      callSpread[0] = new ForexOptionVanilla(forexM, optionDigital.getExpirationTime(), optionDigital.isCall(), (optionDigital.isLong() == optionDigital.isCall()));
      callSpread[1] = new ForexOptionVanilla(forexP, optionDigital.getExpirationTime(), optionDigital.isCall(), !(optionDigital.isLong() == optionDigital.isCall()));
    } else {
      amountPaid = Math.abs(optionDigital.getUnderlyingForex().getPaymentCurrency1().getAmount());
      strikeRelM = 1.0 / strikeP;
      strikeRelP = 1.0 / strikeM;
      double amount = amountPaid / (strikeRelP - strikeRelM);
      Forex forexM = new Forex(optionDigital.getUnderlyingForex().getPaymentCurrency2().withAmount(amount), optionDigital.getUnderlyingForex().getPaymentCurrency1().withAmount(-strikeRelM * amount));
      Forex forexP = new Forex(optionDigital.getUnderlyingForex().getPaymentCurrency2().withAmount(amount), optionDigital.getUnderlyingForex().getPaymentCurrency1().withAmount(-strikeRelP * amount));
      callSpread[0] = new ForexOptionVanilla(forexM, optionDigital.getExpirationTime(), !optionDigital.isCall(), !(optionDigital.isLong() == optionDigital.isCall()));
      callSpread[1] = new ForexOptionVanilla(forexP, optionDigital.getExpirationTime(), !optionDigital.isCall(), (optionDigital.isLong() == optionDigital.isCall()));
    }
    return callSpread;
  }

  /**
   * Gets the spread used for call spread.
   * @return The spread.
   */
  public double getSpread() {
    return _spread;
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.forex.provider.ForexOptionDigitalCallSpreadBlackSmileMethod

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.