/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.forex.method; import org.apache.commons.lang.Validate; import com.opengamma.analytics.financial.forex.derivative.ForexOptionDigital; import com.opengamma.analytics.financial.forex.derivative.ForexOptionVanilla; import com.opengamma.analytics.financial.forex.provider.ForexOptionDigitalCallSpreadBlackSmileMethod; import com.opengamma.analytics.financial.interestrate.InstrumentDerivative; import com.opengamma.analytics.financial.interestrate.YieldCurveBundle; import com.opengamma.analytics.financial.model.option.definition.SmileDeltaTermStructureDataBundle; import com.opengamma.analytics.financial.model.volatility.VolatilityAndBucketedSensitivities; import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParametersStrikeInterpolation; 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.tuple.DoublesPair; /** * Pricing method for digital Forex option transactions as a call or put spread option with the underlying vanilla price by a Black formula with implied volatility. * @deprecated Use {@link ForexOptionDigitalCallSpreadBlackSmileMethod} */ @Deprecated public class ForexOptionDigitalCallSpreadBlackMethod extends ForexOptionDigitalCallSpreadMethod { /** * Constructor from the spread. * @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 ForexOptionDigitalCallSpreadBlackMethod(final double spread) { super(ForexOptionVanillaBlackSmileMethod.getInstance(), spread); } /** * 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 smile The curve and smile data. * @return The gamma. */ public double gammaRelative(final ForexOptionDigital optionDigital, final SmileDeltaTermStructureDataBundle smile) { final CurrencyAmount gamma = gamma(optionDigital, smile); 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 curves The yield curve bundle. * @return The gamma. */ public CurrencyAmount gamma(final ForexOptionDigital optionDigital, final YieldCurveBundle curves) { Validate.notNull(optionDigital, "Forex option"); ArgumentChecker.notNull(curves, "Curves"); ArgumentChecker.isTrue(curves instanceof SmileDeltaTermStructureDataBundle, "Yield curve bundle should contain smile data"); final SmileDeltaTermStructureDataBundle smile = (SmileDeltaTermStructureDataBundle) curves; Validate.isTrue(smile.checkCurrencies(optionDigital.getCurrency1(), optionDigital.getCurrency2()), "Option currencies not compatible with smile data"); final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread()); // Spread value final CurrencyAmount gammaM = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).gamma(callSpread[0], smile, optionDigital.payDomestic()); final CurrencyAmount gammaP = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).gamma(callSpread[1], smile, 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 curves The yield curve bundle. * @return The gamma. */ public CurrencyAmount gammaSpot(final ForexOptionDigital optionDigital, final YieldCurveBundle curves) { Validate.notNull(optionDigital, "Forex option"); ArgumentChecker.notNull(curves, "Curves"); ArgumentChecker.isTrue(curves instanceof SmileDeltaTermStructureDataBundle, "Yield curve bundle should contain smile data"); final SmileDeltaTermStructureDataBundle smile = (SmileDeltaTermStructureDataBundle) curves; Validate.isTrue(smile.checkCurrencies(optionDigital.getCurrency1(), optionDigital.getCurrency2()), "Option currencies not compatible with smile data"); final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread()); // Spread value final CurrencyAmount gammaM = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).gammaSpot(callSpread[0], smile, optionDigital.payDomestic()); final CurrencyAmount gammaP = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).gammaSpot(callSpread[1], smile, 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 smile 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 SmileDeltaTermStructureDataBundle smile) { Validate.notNull(optionDigital, "Forex option difital"); Validate.notNull(smile, "Curve and smile data"); Validate.isTrue(smile.checkCurrencies(optionDigital.getCurrency1(), optionDigital.getCurrency2()), "Option currencies not compatible with smile data"); final ForexOptionVanilla[] callSpread = callSpread(optionDigital, getSpread()); // Spread value final PresentValueForexBlackVolatilitySensitivity pvbsM = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).presentValueBlackVolatilitySensitivity(callSpread[0], smile); final PresentValueForexBlackVolatilitySensitivity pvbsP = ((ForexOptionVanillaBlackSmileMethod) getBaseMethod()).presentValueBlackVolatilitySensitivity(callSpread[1], smile); return pvbsM.plus(pvbsP); } /** * Computes the present value volatility sensitivity with a generic instrument as argument. * @param instrument A Digital Forex option. * @param curves The volatility and curves description (SmileDeltaTermStructureDataBundle). * @return The volatility sensitivity. The sensitivity figures are, like the present value, in the domestic currency (currency 2). */ public PresentValueForexBlackVolatilitySensitivity presentValueBlackVolatilitySensitivity(final InstrumentDerivative instrument, final YieldCurveBundle curves) { Validate.isTrue(instrument instanceof ForexOptionDigital, "Digital Forex option"); Validate.isTrue(curves instanceof SmileDeltaTermStructureDataBundle, "Smile delta data bundle required"); return presentValueBlackVolatilitySensitivity((ForexOptionDigital) instrument, (SmileDeltaTermStructureDataBundle) curves); } /** * 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 curves The yield curve bundle. * @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 YieldCurveBundle curves) { Validate.notNull(optionDigital, "Forex option"); ArgumentChecker.isTrue(curves instanceof SmileDeltaTermStructureDataBundle, "Yield curve bundle should contain smile data"); final SmileDeltaTermStructureDataBundle smile = (SmileDeltaTermStructureDataBundle) curves; Validate.isTrue(smile.checkCurrencies(optionDigital.getCurrency1(), optionDigital.getCurrency2()), "Option currencies not compatible with smile data"); final PresentValueForexBlackVolatilitySensitivity pointSensitivity = presentValueBlackVolatilitySensitivity(optionDigital, smile); // In ccy2 final double df = smile.getCurve(optionDigital.getUnderlyingForex().getPaymentCurrency2().getFundingCurveName()).getDiscountFactor(optionDigital.getUnderlyingForex().getPaymentTime()); final double spot = smile.getFxRates().getFxRate(optionDigital.getCurrency1(), optionDigital.getCurrency2()); final double forward = spot * smile.getCurve(optionDigital.getUnderlyingForex().getPaymentCurrency1().getFundingCurveName()).getDiscountFactor(optionDigital.getUnderlyingForex().getPaymentTime()) / df; final SmileDeltaTermStructureParametersStrikeInterpolation volatilityModel = smile.getVolatilityModel(); final double[][] vega = new double[volatilityModel.getNumberExpiration()][volatilityModel.getNumberStrike()]; for (final DoublesPair point : pointSensitivity.getVega().getMap().keySet()) { final VolatilityAndBucketedSensitivities volAndSensitivities = FXVolatilityUtils.getVolatilityAndSensitivities(smile, 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)); } }