/** * 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 com.google.common.primitives.Doubles; import com.opengamma.analytics.financial.interestrate.InstrumentDerivativeVisitorAdapter; import com.opengamma.analytics.financial.provider.description.volatilityswap.CarrLeeFXData; import com.opengamma.util.ArgumentChecker; /** * Compute theta of forward volatility based on finite difference method */ public class CarrLeeFXVolatilitySwapThetaCalculator extends InstrumentDerivativeVisitorAdapter<CarrLeeFXData, Double> { private final CarrLeeFXVolatilitySwapCalculator _cal; /** * Constructor using default calculator */ public CarrLeeFXVolatilitySwapThetaCalculator() { _cal = new CarrLeeFXVolatilitySwapCalculator(); } /** * Constructor specifying base calculator * @param cal Base calculator */ public CarrLeeFXVolatilitySwapThetaCalculator(final CarrLeeFXVolatilitySwapCalculator cal) { ArgumentChecker.notNull(cal, "cal"); _cal = cal; } /** * Theta calculator for FX volatility swap based on "bump and reprice" using {@link VolatilitySwapCalculatorResultWithStrikes}, * i.e., assuming the fair value has been already calculated. For theta the bump amount is 1 working day. * @param result {@link VolatilitySwapCalculatorResultWithStrikes} * @param swap The FX volatility swap * @param data The FX data for Carr-Lee * @return theta */ public Double getFXVolatilitySwapTheta(final VolatilitySwapCalculatorResultWithStrikes result, final FXVolatilitySwap swap, final CarrLeeFXData data) { ArgumentChecker.notNull(result, "result"); ArgumentChecker.notNull(swap, "swap"); ArgumentChecker.notNull(data, "data"); final double spot = data.getSpot(); final double timeToExpiry = swap.getTimeToMaturity(); ArgumentChecker.isTrue(Doubles.isFinite(timeToExpiry), "timeToExpiry should be finite"); ArgumentChecker.isTrue(timeToExpiry > 0., "timeToExpiry should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(spot), "spot should be finite"); ArgumentChecker.isTrue(spot > 0., "spot should be positive"); final double domesticDF = data.getMulticurveProvider().getDiscountFactor(swap.getBaseCurrency(), timeToExpiry); final double foreignDF = data.getMulticurveProvider().getDiscountFactor(swap.getCounterCurrency(), timeToExpiry); final double domesticRate = -Math.log(domesticDF) / timeToExpiry; final double foreignRate = -Math.log(foreignDF) / timeToExpiry; ArgumentChecker.isTrue(Doubles.isFinite(domesticRate), "domestic rate should be finite"); ArgumentChecker.isTrue(Doubles.isFinite(foreignRate), "foreign rate should be finite"); final double baseFV = result.getFairValue(); final double aFac = swap.getAnnualizationFactor(); final double timeBumpAmount = 1.0 / aFac; final double bumpedTimeToObservationStart = swap.getTimeToObservationStart() == 0. ? 0. : swap.getTimeToObservationStart() - timeBumpAmount; final FXVolatilitySwap timeBumpedSwap = new FXVolatilitySwap(bumpedTimeToObservationStart, swap.getTimeToObservationEnd() - timeBumpAmount, swap.getObservationFrequency(), swap.getTimeToMaturity() - timeBumpAmount, swap.getVolatilityStrike(), swap.getVolatilityNotional(), swap.getCurrency(), swap.getBaseCurrency(), swap.getCounterCurrency(), aFac); final VolatilitySwapCalculatorResult timeBumpedRes = _cal.visitFXVolatilitySwap(timeBumpedSwap, data); final double timeBumpedFV = timeBumpedRes.getFairValue(); return timeBumpedFV - baseFV; } @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 getFXVolatilitySwapTheta(result, swap, data); } @Override public int hashCode() { final int prime = 31; int result = 1; 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 CarrLeeFXVolatilitySwapThetaCalculator)) { return false; } CarrLeeFXVolatilitySwapThetaCalculator other = (CarrLeeFXVolatilitySwapThetaCalculator) obj; if (_cal == null) { if (other._cal != null) { return false; } } else if (!_cal.equals(other._cal)) { return false; } return true; } }