/** * Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.volatilityswap; import java.util.LinkedHashMap; import com.opengamma.analytics.financial.forex.method.FXMatrix; import com.opengamma.analytics.financial.instrument.index.IborIndex; import com.opengamma.analytics.financial.instrument.index.IndexON; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter; import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderDiscount; import com.opengamma.analytics.financial.provider.description.interestrate.MulticurveProviderInterface; import com.opengamma.analytics.financial.provider.description.volatilityswap.CarrLeeFXData; import com.opengamma.util.ArgumentChecker; /** * Compute delta of forward volatility using finite difference approximation */ public class CarrLeeFXVolatilitySwapDeltaCalculator extends InstrumentDerivativeVisitorAdapter<CarrLeeFXData, Double> { private static final double DEFAULT_BUMP = 1.0e-5; private final CarrLeeFXVolatilitySwapCalculator _cal; private final double _bumpSpot; /** * Constructor using default bump amount */ public CarrLeeFXVolatilitySwapDeltaCalculator() { this(DEFAULT_BUMP); } /** * Constructor specifying bump amount * @param bump The bump amount */ public CarrLeeFXVolatilitySwapDeltaCalculator(final double bump) { _bumpSpot = bump; _cal = new CarrLeeFXVolatilitySwapCalculator(); } /** * Constructor specifying bump amount and base calculator * @param bump The bump amount * @param cal Base calculator */ public CarrLeeFXVolatilitySwapDeltaCalculator(final double bump, final CarrLeeFXVolatilitySwapCalculator cal) { ArgumentChecker.notNull(cal, "cal"); _bumpSpot = bump; _cal = cal; } /** * Delta calculator for FX volatility swap based on "bump and reprice" using {@link VolatilitySwapCalculatorResultWithStrikes}, * i.e., assuming the fair value has been already calculated. * @param result {@link VolatilitySwapCalculatorResultWithStrikes} * @param swap The FX volatility swap * @param data The FX data for Carr-Lee * @return Delta */ public Double getFXVolatilitySwapDelta(final VolatilitySwapCalculatorResultWithStrikes result, final FXVolatilitySwap swap, final CarrLeeFXData data) { ArgumentChecker.notNull(result, "result"); ArgumentChecker.notNull(swap, "swap"); ArgumentChecker.notNull(data, "data"); final double baseFV = result.getFairValue(); final CarrLeeFXData spotBumpedData = getSpotBumpedData(data); final VolatilitySwapCalculatorResult spotBumpedRes = _cal.visitFXVolatilitySwap(swap, spotBumpedData); final double spotBumpedFV = spotBumpedRes.getFairValue(); return (spotBumpedFV - baseFV) / _bumpSpot; } @Override public Double visitFXVolatilitySwap(final FXVolatilitySwap swap, final CarrLeeFXData data) { ArgumentChecker.notNull(swap, "swap"); ArgumentChecker.notNull(data, "data"); final VolatilitySwapCalculatorResultWithStrikes result = _cal.visitFXVolatilitySwap(swap, data); return getFXVolatilitySwapDelta(result, swap, data); } private CarrLeeFXData getSpotBumpedData(final CarrLeeFXData data) { final FXMatrix spotBumpedfxMatrix = new FXMatrix(data.getCurrencyPair().getFirst(), data.getCurrencyPair().getSecond(), data.getSpot() + _bumpSpot); final MulticurveProviderInterface provider = data.getMulticurveProvider(); final MulticurveProviderDiscount spotBumpedCurves; if (provider instanceof MulticurveProviderDiscount) { final MulticurveProviderDiscount discountCurves = (MulticurveProviderDiscount) data.getMulticurveProvider(); spotBumpedCurves = new MulticurveProviderDiscount(discountCurves.getDiscountingCurves(), new LinkedHashMap<IborIndex, YieldAndDiscountCurve>(), new LinkedHashMap<IndexON, YieldAndDiscountCurve>(), spotBumpedfxMatrix); } else { throw new IllegalArgumentException("Multi-curve provider should be an instance of MulticurveProviderDiscount"); } if (data.getRealizedVariance() == null) { return new CarrLeeFXData(data.getCurrencyPair(), data.getVolatilityData(), spotBumpedCurves); } return new CarrLeeFXData(data.getCurrencyPair(), data.getVolatilityData(), spotBumpedCurves, data.getRealizedVariance()); } @Override public int hashCode() { final int prime = 31; int result = 1; long temp; temp = Double.doubleToLongBits(_bumpSpot); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + ((_cal == null) ? 0 : _cal.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (obj == null) { return false; } if (!(obj instanceof CarrLeeFXVolatilitySwapDeltaCalculator)) { return false; } CarrLeeFXVolatilitySwapDeltaCalculator other = (CarrLeeFXVolatilitySwapDeltaCalculator) obj; if (Double.doubleToLongBits(_bumpSpot) != Double.doubleToLongBits(other._bumpSpot)) { return false; } if (_cal == null) { if (other._cal != null) { return false; } } else if (!_cal.equals(other._cal)) { return false; } return true; } }