/** * Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies * * Please see distribution for license. */ package com.opengamma.analytics.financial.model.volatility.smile.fitting.sabr; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve; import com.opengamma.util.ArgumentChecker; /** * */ public abstract class SmileSurfaceDataBundle { private static final Logger s_logger = LoggerFactory.getLogger(SmileSurfaceDataBundle.class); public abstract int getNumExpiries(); public abstract double[] getExpiries(); public abstract double[][] getStrikes(); public abstract double[][] getVolatilities(); public abstract double[] getForwards(); public abstract ForwardCurve getForwardCurve(); // public abstract boolean isCallData(); public abstract SmileSurfaceDataBundle withBumpedPoint(int expiryIndex, int strikeIndex, double amount); /** * Sanity check * Test that integrated variance is increasing as one moves out in expiries. This is just a proxy. * It compares various as one moves down a column, be it strike or Moneyness. * @param expiries Option expiries * @param vols Implied Volatilities */ protected void checkVolatilities(final double[] expiries, final double[][] vols) { final int nExpiries = expiries.length; final int n = vols[0].length; for (int i = 0; i < n; i++) { final double[] intVar = new double[nExpiries]; for (int j = 0; j < nExpiries; j++) { final double vol = vols[j][i]; intVar[j] = vol * vol * expiries[j]; if (j > 0) { ArgumentChecker.isTrue(intVar[j] >= intVar[j - 1], "integrated variance not increasing, have {}, {}", intVar[j - 1], intVar[j]); } } } } /** * Sanity check * Test that integrated variance is increasing as one moves out in expiries. This is just a proxy. * This version is to be used when expiry rows have different length, but share common strikes. * @param expiries Option expiries * @param strikes Available strikes for each expiry * @param vols Implied Volatilities, sharing dimension of strikes */ protected void checkVolatilities(final double[] expiries, final double[][] strikes, final double[][] vols) { final int nExpiries = expiries.length; // Build a map keyed by the strike final HashMap<Double, ArrayList<Double>> strikeVarMap = new HashMap<>(); for (int k = 0; k < strikes[0].length; k++) { final ArrayList<Double> intVar = new ArrayList<>(); intVar.add(vols[0][k] * vols[0][k] * expiries[0]); strikeVarMap.put(strikes[0][k], intVar); } // Loop over expiries for (int i = 1; i < nExpiries; i++) { final int nK = strikes[i].length; for (int k = 0; k < nK; k++) { if (strikeVarMap.containsKey(strikes[i][k])) { // Add Vol to existing key strikeVarMap.get(strikes[i][k]).add(vols[i][k] * vols[i][k] * expiries[i]); } else { // Add new key final ArrayList<Double> intVar = new ArrayList<>(); intVar.add(vols[i][k] * vols[i][k] * expiries[i]); strikeVarMap.put(strikes[i][k], intVar); } } } // Perform check by looping over strikes confirming that variance increases with expiry for (final Map.Entry<Double, ArrayList<Double>> entry : strikeVarMap.entrySet()) { final ArrayList<Double> intVar = entry.getValue(); final int nVars = intVar.size(); if (nVars > 1) { for (int t = 1; t < nVars; t++) { if (intVar.get(t) < intVar.get(t - 1)) { s_logger.error("Integrated variance not increasing, have (" + (t - 1) + "," + intVar.get(t - 1) + "),(" + t + "," + intVar.get(t) + ")"); } } } } } }