/* * (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: email@christian-fries.de. * * Created on 20.05.2005 */ package net.finmath.marketdata.model.volatilities; import java.io.BufferedReader; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.StringTokenizer; import org.joda.time.LocalDate; import net.finmath.marketdata.model.AnalyticModelInterface; import net.finmath.marketdata.model.curves.Curve; import net.finmath.marketdata.model.curves.CurveInterface; import net.finmath.marketdata.model.curves.DiscountCurveInterface; import net.finmath.marketdata.model.curves.ForwardCurveInterface; /** * A very simple container for Caplet volatilities. * * It performs piecewise constant interpolation (discretization) in maturity dimension on iso-moneyness lines * and uses the default interpolation from the Curve class in strike dimension. * * It allows to convert from several quoting conventions. * * It needs a forward curve and a discount curve. The tenor length of the Caplet is inferred * from the forward curve. * * @TODO: Need to add forward and discount curve to support implied vol. * @author Christian Fries */ public class CapletVolatilities extends AbstractVolatilitySurface { private Map<Double, CurveInterface> capletVolatilities = new HashMap<Double, CurveInterface>(); private transient Double[] maturities; private Object lazyInitLock = new Object(); /** * @param name The name of this volatility surface. * @param referenceDate The reference date for this volatility surface, i.e., the date which defined t=0. * @param forwardCurve The underlying forward curve. * @param maturities The vector of maturities of the quotes. * @param strikes The vector of strikes of the quotes. * @param volatilities The vector of volatilities of the quotes. * @param volatilityConvention The quoting convention of the volatilities provided. * @param discountCurve The associated discount curve. */ public CapletVolatilities(String name, LocalDate referenceDate, ForwardCurveInterface forwardCurve, double[] maturities, double[] strikes, double[] volatilities, QuotingConvention volatilityConvention, DiscountCurveInterface discountCurve) { super(name, referenceDate); this.forwardCurve = forwardCurve; this.discountCurve = discountCurve; this.quotingConvention = volatilityConvention; if(maturities.length != strikes.length || maturities.length != volatilities.length) throw new IllegalArgumentException("Length of vectors is not equal."); for(int i=0; i<volatilities.length; i++) { double maturity = maturities[i]; double strike = strikes[i]; double volatility = volatilities[i]; add(maturity, strike, volatility); } } /** * Private constructor for empty surface, to add points to it. * * @param name The name of this volatility surface. * @param referenceDate The reference date for this volatility surface, i.e., the date which defined t=0. */ private CapletVolatilities(String name, LocalDate referenceDate) { super(name, referenceDate); } /** * @param maturity * @param strike * @param volatility */ private void add(double maturity, double strike, double volatility) { CurveInterface curve = capletVolatilities.get(maturity); try { if(curve == null) curve = (new Curve.CurveBuilder()).addPoint(strike, volatility, true).build(); else curve = curve.getCloneBuilder().addPoint(strike, volatility, true).build(); } catch (CloneNotSupportedException e) { throw new RuntimeException("Unable to build curve."); } synchronized (lazyInitLock) { capletVolatilities.put(maturity, curve); maturities = null; } } @Override public double getValue(double maturity, double strike, VolatilitySurfaceInterface.QuotingConvention quotingConvention) { return getValue(null, maturity, strike, quotingConvention); } @Override public double getValue(AnalyticModelInterface model, double maturity, double strike, VolatilitySurfaceInterface.QuotingConvention quotingConvention) { if(maturity == 0) return 0; double value; if(capletVolatilities.containsKey(maturity)) { value = capletVolatilities.get(maturity).getValue(strike); } else { synchronized (lazyInitLock) { if(maturities == null) maturities = capletVolatilities.keySet().toArray(new Double[0]); Arrays.sort(maturities); } int maturityGreaterEqualIndex = Arrays.binarySearch(maturities, maturity); if(maturityGreaterEqualIndex < 0) maturityGreaterEqualIndex = -maturityGreaterEqualIndex-1; if(maturityGreaterEqualIndex > maturities.length-1) maturityGreaterEqualIndex = maturities.length-1; double maturityGreaterOfEqual = maturities[maturityGreaterEqualIndex]; // @TODO: Below we should trigger an exception if no forwardCurve is supplied but needed. // Interpolation / extrapolation is performed on iso-moneyness lines. double adjustedStrike = forwardCurve.getValue(model, maturityGreaterOfEqual) + (strike - forwardCurve.getValue(model, maturity)); value = capletVolatilities.get(maturityGreaterOfEqual).getValue(adjustedStrike); } return convertFromTo(model, maturity, strike, value, this.quotingConvention, quotingConvention); } public static AbstractVolatilitySurface fromFile(File inputFile) throws FileNotFoundException { // Read data BufferedReader dataStream = new BufferedReader(new InputStreamReader(new FileInputStream(inputFile))); ArrayList<String> datasets = new ArrayList<String>(); try { while(true) { String line = dataStream.readLine(); // Check for end of file if(line == null) break; // Ignore non caplet data if(!line.startsWith("caplet\t")) continue; datasets.add(line); } dataStream.close(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } // @TODO: Name and reference date have to be set?! CapletVolatilities capletVolatilities = new CapletVolatilities(null, null); // Parse data for(int datasetIndex=0; datasetIndex<datasets.size(); datasetIndex++) { StringTokenizer stringTokenizer = new StringTokenizer(datasets.get(datasetIndex),"\t"); try { // Skip identifier stringTokenizer.nextToken(); double maturity = Double.parseDouble(stringTokenizer.nextToken()); double strike = Double.parseDouble(stringTokenizer.nextToken()); double capletVolatility = Double.parseDouble(stringTokenizer.nextToken()); capletVolatilities.add(maturity, strike, capletVolatility); } catch(Exception e) { e.printStackTrace(); } } return capletVolatilities; } }