/*
 * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de.
 *
 * Created on 30.03.2014
 */
package net.finmath.montecarlo.interestrate.products;

import net.finmath.montecarlo.RandomVariable;
import net.finmath.montecarlo.interestrate.LIBORMarketModelInterface;
import net.finmath.montecarlo.interestrate.LIBORModelMonteCarloSimulationInterface;
import net.finmath.montecarlo.interestrate.modelplugins.AbstractLIBORCovarianceModel;
import net.finmath.stochastic.RandomVariableInterface;

/**
 * This class implements the calculation of the curvature of the volatility surface of the forward rates.
 * 
 * 
* * The value returned by the {@link #getValue(double, LIBORModelMonteCarloSimulationInterface)} method is calculated as follows: * For each forward rate's instantaneous volatility σ(t) we calculate *
* \[ \sqrt{ \frac{1}{t_{n} - t_{1}} \sum_{i=1}^{n-1} ( f(t_{i}) )^{2} \cdot (t_{i+1} - t_{i}) } \] *
* (this is the root mean square / L2 norm of f) where *
* \[ f(t_{i}) = \frac{ x_{i+2} - 2 x_{i+1} + x_{i} }{ (t_{i+2} - t_{i+1}) (t_{i+1} - t_{i}) } \] *
* and where * * xi = σ2(ti) * is the * instantaneous variance of a specific forward rate. * * The value returned is then calculated as the average of all those curvatures for all forward rates. * * Note: A tolerance level can be specified. See the documentation of the constructor {@link #ForwardRateVolatilitySurfaceCurvature(double)}. * *
*
* * While this is not a common financial product, this class can be helpful in calibration procedures, e.g. * to put an additional constrain on the smoothness / curvature of the model surface. * *
* A rough interpretation of this product is a follows: If the value 0.25 is returned, then * - on average - the variance of the forward rate oscillates by 0.25 per year, i.e. it moves up by 0.25 and back. * This corresponds to a movement of 0.5 and back per year for the volatility. * Given that you have 100 other calibrations products, and the weight of all (including this one) is 1.0, then * 0.1% deviation of the other calibration products is considered as severe as 0.1 movement per year in the variance (0.3 movement in volatility). * Note: You can control the relation of these by weights. * * @author Christian Fries * @date 12.04.2014. */ public class ForwardRateVolatilitySurfaceCurvature extends AbstractLIBORMonteCarloProduct { private double tolerance = 0.0; /** * Create the calculation of the curvature of the volatility surface of the forward rates */ public ForwardRateVolatilitySurfaceCurvature() { super(); } /** * Create the calculation of the curvature of the volatility surface of the forward rates. * * A tolerance level may be specified. In that case, the curvature * calculated by the getValue method is approximately *
* max(curvature - tolerance, 0). *
* * A rough interpretation of the tolerance is as follows: * With a tolerance = 0.04, then * * * @param tolerance The tolerance level. */ public ForwardRateVolatilitySurfaceCurvature(double tolerance) { super(); this.tolerance = tolerance; } @Override public RandomVariableInterface getValue(double evaluationTime, LIBORModelMonteCarloSimulationInterface model) { return getValues(evaluationTime, model.getModel()); } /** * Calculates the squared curvature of the LIBOR instantaneous variance. * * @param evaluationTime Time at which the product is evaluated. * @param model A model implementing the LIBORModelMonteCarloSimulationInterface * @return The squared curvature of the LIBOR instantaneous variance (reduced a possible tolerance). The return value is ≥ 0. */ public RandomVariableInterface getValues(double evaluationTime, LIBORMarketModelInterface model) { if(evaluationTime > 0) throw new RuntimeException("Forward start evaluation currently not supported."); // Fetch the covariance model of the model AbstractLIBORCovarianceModel covarianceModel = model.getCovarianceModel(); // We sum over all forward rates int numberOfComponents = covarianceModel.getLiborPeriodDiscretization().getNumberOfTimeSteps(); // Accumulator RandomVariableInterface integratedLIBORCurvature = new RandomVariable(0.0); for(int componentIndex = 0; componentIndex < numberOfComponents; componentIndex++) { // Integrate from 0 up to the fixing of the rate double timeEnd = covarianceModel.getLiborPeriodDiscretization().getTime(componentIndex); int timeEndIndex = covarianceModel.getTimeDiscretization().getTimeIndex(timeEnd); // If timeEnd is not in the time discretization we get timeEndIndex = -insertionPoint-1. In that case, we use the index prior to the insertionPoint if(timeEndIndex < 0) timeEndIndex = -timeEndIndex - 2; // Sum squared second derivative of the variance for all components at this time step RandomVariableInterface integratedLIBORCurvatureCurrentRate = new RandomVariable(0.0); for(int timeIndex = 0; timeIndex < timeEndIndex-2; timeIndex++) { double timeStep1 = covarianceModel.getTimeDiscretization().getTimeStep(timeIndex); double timeStep2 = covarianceModel.getTimeDiscretization().getTimeStep(timeIndex+1); RandomVariableInterface covarianceLeft = covarianceModel.getCovariance(timeIndex+0, componentIndex, componentIndex, null); RandomVariableInterface covarianceCenter = covarianceModel.getCovariance(timeIndex+1, componentIndex, componentIndex, null); RandomVariableInterface covarianceRight = covarianceModel.getCovariance(timeIndex+2, componentIndex, componentIndex, null); // Calculate second derivative RandomVariableInterface curvatureSquared = covarianceRight.sub(covarianceCenter.mult(2.0)).add(covarianceLeft); curvatureSquared = curvatureSquared.div(timeStep1 * timeStep2); // Take square curvatureSquared = curvatureSquared.squared(); // Integrate over time integratedLIBORCurvatureCurrentRate = integratedLIBORCurvatureCurrentRate.add(curvatureSquared.mult(timeStep1)); } // Empty intervall - skip if(timeEnd == 0) continue; // Average over time integratedLIBORCurvatureCurrentRate = integratedLIBORCurvatureCurrentRate.div(timeEnd); // Take square root integratedLIBORCurvatureCurrentRate = integratedLIBORCurvatureCurrentRate.sqrt(); // Take max over all forward rates integratedLIBORCurvature = integratedLIBORCurvature.add(integratedLIBORCurvatureCurrentRate); } integratedLIBORCurvature = integratedLIBORCurvature.div(numberOfComponents); return integratedLIBORCurvature.sub(tolerance).floor(0.0); } }

Ads help maintain this website.