/**
* Copyright (C) 2014 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.capletstripping.demo;
import java.util.Arrays;
import java.util.List;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.interestrate.capletstripping.CapFloor;
import com.opengamma.analytics.financial.interestrate.capletstripping.CapletStripperDirect;
import com.opengamma.analytics.financial.interestrate.capletstripping.CapletStrippingResult;
import com.opengamma.analytics.financial.interestrate.capletstripping.CapletStrippingSetup;
import com.opengamma.analytics.financial.interestrate.capletstripping.MarketDataType;
import com.opengamma.analytics.financial.interestrate.capletstripping.MultiCapFloorPricer;
import com.opengamma.analytics.financial.interestrate.capletstripping.MultiCapFloorPricerGrid;
import com.opengamma.analytics.math.matrix.DoubleMatrix1D;
/**
* Here we calibrate simultaneously to all the caps (on a particular index) in the market, by adjusting all the underlying
* caplet volatilities. Since there are more caplets volatilities than caps, a penalty on the curvature of the caplet vols
* in both the strike and expiry direction is applied.
*/
public class GlobalDirectFitDemo extends CapletStrippingSetup {
/**
* This calibrated to all the cap volatilities (excluding ATM) at once
* <p>
* The output is this surface sampled on a grid (101 by 101), such that it can be plotted as an Excel surface plot
* (or imported into some other visualisation tool).
*/
@Test(description = "Demo of infering a caplet volatility surface")
public void globalVolFitExATMDemo() {
final double lambda = 0.03; // this is chosen to give a chi2/DoF of around 1
final MultiCapFloorPricerGrid pricer = new MultiCapFloorPricerGrid(getAllCapsExATM(), getYieldCurves());
final CapletStripperDirect stripper = new CapletStripperDirect(pricer, lambda);
final double[] capVols = getAllCapVolsExATM();
final int n = capVols.length;
final double[] errors = new double[n];
Arrays.fill(errors, 1e-4); // 1bps
final DoubleMatrix1D guess = new DoubleMatrix1D(pricer.getGridSize(), 0.7);
final CapletStrippingResult res = stripper.solve(capVols, MarketDataType.VOL, errors, guess);
System.out.println(res);
// print the caplet volatilities
System.out.println("\n");
res.printCapletVols(System.out);
System.out.println("Caplet volatility surface");
res.printSurface(System.out, 101, 101);
}
/**
* Fit the ATM caps only. Since there are only 7 such caps (in our data set), the resultant 'surface' is close to a flat plane; this
* recovers the & cap vols and satisfies the curvature penalties
*/
@Test(description = "Demo of infering a caplet volatility surface")
public void atmCapsOnlyDemo() {
final double lambda = 0.7; // this is chosen to give a chi2/DoF of around 1
final MultiCapFloorPricerGrid pricer = new MultiCapFloorPricerGrid(getATMCaps(), getYieldCurves());
final CapletStripperDirect stripper = new CapletStripperDirect(pricer, lambda);
final double[] capVols = getATMCapVols();
final int n = capVols.length;
final double[] errors = new double[n];
Arrays.fill(errors, 1e-4); // 1bps
final DoubleMatrix1D guess = new DoubleMatrix1D(pricer.getGridSize(), 0.7);
final CapletStrippingResult res = stripper.solve(capVols, MarketDataType.VOL, errors, guess);
System.out.println(res);
System.out.println("Caplet volatility surface");
res.printSurface(System.out, 101, 101);
}
/**
* Fit all the caps. Since there is some inconsistency in our data between ATM cap quotes and those at absolute strikes (cap 'smiles' show
* the ATM quotes lying off a smooth curve through the absolute strikes), we fit ATM quotes with an error of 1bps and everything else with an error
* of 10bps. However, the resultant caplet volatility surface is less smooth (in the strike direction) than that made excluding ATM.
*/
@Test(description = "Demo of infering a caplet volatility surface")
public void globalVolFitDemo() {
final double lambdaT = 0.01; // this is chosen to give a chi2/DoF of around 1
final double lambdaK = 0.0002;
final List<CapFloor> allCaps = getAllCaps();
System.out.println("number of caps :" + allCaps.size());
final List<CapFloor> atmCaps = getATMCaps();
final MultiCapFloorPricerGrid pricer = new MultiCapFloorPricerGrid(allCaps, getYieldCurves());
final CapletStripperDirect stripper = new CapletStripperDirect(pricer, lambdaK, lambdaT);
final double[] capVols = getAllCapVols();
final int n = capVols.length;
final double[] errors = new double[n];
Arrays.fill(errors, 1e-3); // 10bps
final int nATM = atmCaps.size();
for (int i = 0; i < nATM; i++) {
final int index = allCaps.indexOf(atmCaps.get(i));
errors[index] = 1e-4; // 1bps
}
final DoubleMatrix1D guess = new DoubleMatrix1D(pricer.getGridSize(), 0.7);
final CapletStrippingResult res = stripper.solve(capVols, MarketDataType.VOL, errors, guess);
System.out.println("chi2 per cap: " + res.getChiSqr() / allCaps.size());
System.out.println(res);
res.printSurface(System.out, 101, 101);
// res.printCapletVols(System.out);
}
@Test(description = "Demo to show number of (phantom) caplets")
public void sizeDemo() {
final MultiCapFloorPricer pricer1 = new MultiCapFloorPricer(getAllCapsExATM(), getYieldCurves());
System.out.println("number of caplet ex ATM " + pricer1.getNumCaplets());
final MultiCapFloorPricerGrid pricer2 = new MultiCapFloorPricerGrid(getAllCaps(), getYieldCurves());
System.out.println("number of caplet " + pricer2.getNumCaplets() + "\t" + pricer2.getGridSize());
}
}