/** * 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.model.volatility.BlackScholesFormulaRepository; import com.opengamma.analytics.financial.model.volatility.surface.SmileDeltaTermStructureParameters; import com.opengamma.analytics.financial.provider.description.volatilityswap.CarrLeeFXData; import com.opengamma.util.ArgumentChecker; import com.opengamma.util.tuple.Triple; /** * */ public class VolatilitySwapGreeksCalculator { /** * Greeks calculator for FX volatility swap based on result from Carr-Lee model * @param result {@link VolatilitySwapCalculatorResultWithStrikes} * @param swap The FX volatility swap * @param data The FX data for Carr-Lee * @return Array of {delta, gamma, vega, theta} */ public double[] getFXVolatilitySwapGreeks(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[] putStrikes = result.getPutStrikes(); final double forward = spot * Math.exp((domesticRate - foreignRate) * timeToExpiry); final double[] callStrikes = result.getCallStrikes(); final int nPuts = putStrikes.length; final int nCalls = callStrikes.length; final SmileDeltaTermStructureParameters smile = data.getVolatilityData(); final double[] putVols = new double[nPuts]; final double[] callVols = new double[nCalls]; for (int i = 0; i < nPuts; ++i) { putVols[i] = smile.getVolatility(Triple.of(timeToExpiry, putStrikes[i], forward)); } final double stdVol = smile.getVolatility(Triple.of(timeToExpiry, forward, forward)); for (int i = 0; i < nCalls; ++i) { callVols[i] = smile.getVolatility(Triple.of(timeToExpiry, callStrikes[i], forward)); } return getGreeks(result, spot, putStrikes, callStrikes, timeToExpiry, domesticRate, foreignRate, putVols, stdVol, callVols); } /** * Greeks calculator for FX volatility swap using Carr-Lee model * @param swap The FX volatility swap * @param data The FX data for Carr-Lee * @return Array of {delta, gamma, vega, theta} */ public double[] getFXVolatilitySwapGreeks(final FXVolatilitySwap swap, final CarrLeeFXData data) { ArgumentChecker.notNull(swap, "swap"); ArgumentChecker.notNull(data, "data"); final CarrLeeFXVolatilitySwapCalculator calculator = new CarrLeeFXVolatilitySwapCalculator(); final VolatilitySwapCalculatorResultWithStrikes result = calculator.visitFXVolatilitySwap(swap, data); return getFXVolatilitySwapGreeks(result, swap, data); } private double[] getGreeks(final VolatilitySwapCalculatorResult result, final double spot, final double[] putStrikes, final double[] callStrikes, final double timeToExpiry, final double interestRate, final double dividend, final double[] putVols, final double stdVol, final double[] callVols) { final int nCalls = callStrikes.length; final int nPuts = putStrikes.length; final double rate = interestRate - dividend; final double forward = spot * Math.exp(rate * timeToExpiry); final double[] putWeights = result.getPutWeights(); final double straddleWeight = result.getStraddleWeight(); final double[] callWeights = result.getCallWeights(); final int num = 4; final double[] res = new double[num]; for (int i = 0; i < nPuts; ++i) { getGreeksFraction(res, putWeights[i], spot, putStrikes[i], timeToExpiry, putVols[i], interestRate, rate, false); } if (straddleWeight != 0.) { getGreeksFraction(res, straddleWeight, spot, forward, timeToExpiry, stdVol, interestRate, rate, true); } for (int i = 0; i < nCalls; ++i) { getGreeksFraction(res, callWeights[i], spot, callStrikes[i], timeToExpiry, callVols[i], interestRate, rate, true); } return res; } private void getGreeksFraction(final double[] res, final double weight, final double spot, final double strike, final double timeToExpiry, final double volatility, final double interestRate, final double costOfCarry, final boolean isCall) { res[0] += weight * BlackScholesFormulaRepository.delta(spot, strike, timeToExpiry, volatility, interestRate, costOfCarry, isCall); res[1] += weight * BlackScholesFormulaRepository.gamma(spot, strike, timeToExpiry, volatility, interestRate, costOfCarry); res[2] += weight * BlackScholesFormulaRepository.vega(spot, strike, timeToExpiry, volatility, interestRate, costOfCarry); res[3] -= weight * BlackScholesFormulaRepository.theta(spot, strike, timeToExpiry, volatility, interestRate, costOfCarry, isCall); } }