net.finmath.marketdata.calibration.CalibratedCurves Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of finmath-lib Show documentation
Show all versions of finmath-lib Show documentation
finmath lib is a Mathematical Finance Library in Java.
It provides algorithms and methodologies related to mathematical finance.
/*
* (c) Copyright Christian P. Fries, Germany. All rights reserved. Contact: [email protected].
*
* Created on 30.11.2012
*/
package net.finmath.marketdata.calibration;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.Vector;
import net.finmath.marketdata.model.AnalyticModel;
import net.finmath.marketdata.model.AnalyticModelInterface;
import net.finmath.marketdata.model.curves.CurveInterface;
import net.finmath.marketdata.model.curves.DiscountCurve;
import net.finmath.marketdata.model.curves.DiscountCurveInterface;
import net.finmath.marketdata.model.curves.ForwardCurve;
import net.finmath.marketdata.model.curves.ForwardCurveFromDiscountCurve;
import net.finmath.marketdata.model.curves.ForwardCurveInterface;
import net.finmath.marketdata.products.AnalyticProductInterface;
import net.finmath.marketdata.products.Swap;
import net.finmath.marketdata.products.SwapLeg;
import net.finmath.optimizer.SolverException;
import net.finmath.time.RegularSchedule;
import net.finmath.time.ScheduleInterface;
import net.finmath.time.TimeDiscretization;
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products.
*
* @author Christian Fries
*/
public class CalibratedCurves {
/**
* Specification of calibration product.
*
* @author Christian Fries
*/
public static class CalibrationSpec {
private String type;
private ScheduleInterface swapTenorDefinitionReceiver;
private String forwardCurveReceiverName;
private double spreadReceiver;
private String discountCurveReceiverName;
private ScheduleInterface swapTenorDefinitionPayer;
private String forwardCurvePayerName;
private double spreadPayer;
private String discountCurvePayerName;
private String calibrationCurveName;
private double calibrationTime;
/**
* Calibration specification.
*
* @param type The type of the calibration product.
* @param swapTenorDefinitionReceiver The schedule of periods of the receiver leg.
* @param forwardCurveReceiverName The forward curve of the receiver leg (may be null).
* @param spreadReceiver The spread or fixed coupon of the receiver leg.
* @param discountCurveReceiverName The discount curve of the receiver leg.
* @param swapTenorDefinitionPayer The schedule of periods of the payer leg.
* @param forwardCurvePayerName The forward curve of the payer leg (may be null).
* @param spreadPayer The spread or fixed coupon of the payer leg.
* @param discountCurvePayerName The discount curve of the payer leg.
* @param calibrationCurveName The curve to calibrate, by this product.
* @param calibrationTime The time point in calibrationCurveName used to calibrate, by this product.
*/
public CalibrationSpec(
String type,
ScheduleInterface swapTenorDefinitionReceiver,
String forwardCurveReceiverName, double spreadReceiver,
String discountCurveReceiverName,
ScheduleInterface swapTenorDefinitionPayer,
String forwardCurvePayerName, double spreadPayer,
String discountCurvePayerName,
String calibrationCurveName,
double calibrationTime) {
super();
this.type = type;
this.swapTenorDefinitionReceiver = swapTenorDefinitionReceiver;
this.forwardCurveReceiverName = forwardCurveReceiverName;
this.spreadReceiver = spreadReceiver;
this.discountCurveReceiverName = discountCurveReceiverName;
this.swapTenorDefinitionPayer = swapTenorDefinitionPayer;
this.forwardCurvePayerName = forwardCurvePayerName;
this.spreadPayer = spreadPayer;
this.discountCurvePayerName = discountCurvePayerName;
this.calibrationCurveName = calibrationCurveName;
this.calibrationTime = calibrationTime;
}
/**
* Calibration specification.
*
* @param type The type of the calibration product.
* @param swapTenorDefinitionReceiver The schedule of periods of the receiver leg.
* @param forwardCurveReceiverName The forward curve of the receiver leg (may be null).
* @param spreadReceiver The spread or fixed coupon of the receiver leg.
* @param discountCurveReceiverName The discount curve of the receiver leg.
* @param swapTenorDefinitionPayer The schedule of periods of the payer leg.
* @param forwardCurvePayerName The forward curve of the payer leg (may be null).
* @param spreadPayer The spread or fixed coupon of the payer leg.
* @param discountCurvePayerName The discount curve of the payer leg.
* @param calibrationCurveName The curve to calibrate, by this product.
* @param calibrationTime The time point in calibrationCurveName used to calibrate, by this product.
*/
public CalibrationSpec(
String type,
double[] swapTenorDefinitionReceiver,
String forwardCurveReceiverName, double spreadReceiver,
String discountCurveReceiverName,
double[] swapTenorDefinitionPayer,
String forwardCurvePayerName, double spreadPayer,
String discountCurvePayerName,
String calibrationCurveName,
double calibrationTime) {
super();
this.type = type;
this.swapTenorDefinitionReceiver = new RegularSchedule(new TimeDiscretization(swapTenorDefinitionReceiver[0] /* initial */, swapTenorDefinitionReceiver[1] /* numberOfTimeSteps */, swapTenorDefinitionReceiver[2] /* deltaT */, TimeDiscretization.ShortPeriodLocation.SHORT_PERIOD_AT_START));
this.forwardCurveReceiverName = forwardCurveReceiverName;
this.spreadReceiver = spreadReceiver;
this.discountCurveReceiverName = discountCurveReceiverName;
this.swapTenorDefinitionPayer = new RegularSchedule(new TimeDiscretization(swapTenorDefinitionPayer[0] /* initial */, swapTenorDefinitionPayer[1] /* numberOfTimeSteps */, swapTenorDefinitionPayer[2] /* deltaT */, TimeDiscretization.ShortPeriodLocation.SHORT_PERIOD_AT_START));
this.forwardCurvePayerName = forwardCurvePayerName;
this.spreadPayer = spreadPayer;
this.discountCurvePayerName = discountCurvePayerName;
this.calibrationCurveName = calibrationCurveName;
this.calibrationTime = calibrationTime;
}
/**
* Calibration specification.
*
* @param type The type of the calibration product.
* @param swapTenorDefinitionReceiver The schedule of periods of the receiver leg.
* @param forwardCurveReceiverName The forward curve of the receiver leg (may be null).
* @param spreadReceiver The spread or fixed coupon of the receiver leg.
* @param discountCurveReceiverName The discount curve of the receiver leg.
* @param calibrationCurveName The curve to calibrate, by this product.
* @param calibrationTime The time point in calibrationCurveName used to calibrate, by this product.
*/
public CalibrationSpec(
String type,
double[] swapTenorDefinitionReceiver,
String forwardCurveReceiverName, double spreadReceiver,
String discountCurveReceiverName,
String calibrationCurveName,
double calibrationTime) {
super();
this.type = type;
this.swapTenorDefinitionReceiver = new RegularSchedule(new TimeDiscretization(swapTenorDefinitionReceiver[0] /* initial */, swapTenorDefinitionReceiver[1] /* numberOfTimeSteps */, swapTenorDefinitionReceiver[2] /* deltaT */, TimeDiscretization.ShortPeriodLocation.SHORT_PERIOD_AT_START));
this.forwardCurveReceiverName = forwardCurveReceiverName;
this.spreadReceiver = spreadReceiver;
this.discountCurveReceiverName = discountCurveReceiverName;
this.calibrationCurveName = calibrationCurveName;
this.calibrationTime = calibrationTime;
}
@Override
public String toString() {
return "CalibrationSpec [type=" + type
+ ", swapTenorDefinitionReceiver="
+ swapTenorDefinitionReceiver
+ ", forwardCurveReceiverName=" + forwardCurveReceiverName
+ ", spreadReceiver=" + spreadReceiver
+ ", discountCurveReceiverName="
+ discountCurveReceiverName + ", swapTenorDefinitionPayer="
+ swapTenorDefinitionPayer + ", forwardCurvePayerName="
+ forwardCurvePayerName + ", spreadPayer=" + spreadPayer
+ ", discountCurvePayerName=" + discountCurvePayerName
+ ", calibrationCurveName=" + calibrationCurveName
+ ", calibrationTime=" + calibrationTime + "]";
}
}
private AnalyticModelInterface model = new AnalyticModel();
private Set curvesToCalibrate = new LinkedHashSet();
private Vector calibrationProducts = new Vector();
private double evaluationTime = 0.0; // Default value. Should be changed if depending on the context.
private int lastNumberOfInterations;
private double lastAccuracy;
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products and a given model.
*
* If the model already contains a curve referenced as calibration curve that
* curve is replaced by a clone, retaining the given curve information and
* adding a new calibration point.
*
* If the model does not contain the curve referenced as calibration curve, the
* curve will be added to the model.
*
* Use case: You already have a discount curve as part of the model and like
* to calibrate an additional curve to an additional set of instruments.
*
* @param calibrationSpecs Array of calibration specs.
* @param calibrationModel A given model used to value the calibration products.
* @param evaluationTime Evaluation time applied to the calibration products.
* @param calibrationAccuracy Error tolerance of the solver. Set to 0 if you need machine precision.
* @throws net.finmath.optimizer.SolverException May be thrown if the solver does not cannot find a solution of the calibration problem.
* @throws CloneNotSupportedException Thrown, when a curve could not be cloned.
*/
public CalibratedCurves(CalibrationSpec[] calibrationSpecs, AnalyticModel calibrationModel, double evaluationTime, double calibrationAccuracy) throws SolverException, CloneNotSupportedException {
if(calibrationModel != null) model = calibrationModel.getCloneForParameter(null);
this.evaluationTime = evaluationTime;
for(CalibrationSpec calibrationSpec : calibrationSpecs) {
add(calibrationSpec);
}
lastNumberOfInterations = calibrate(calibrationAccuracy);
}
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products and a given model.
*
* If the model already contains a curve referenced as calibration curve that
* curve is replaced by a clone, retaining the given curve information and
* adding a new calibration point.
*
* If the model does not contain the curve referenced as calibration curve, the
* curve will be added to the model.
*
* Use case: You already have a discount curve as part of the model and like
* to calibrate an additional curve to an additional set of instruments.
*
* @param calibrationSpecs Array of calibration specs.
* @param calibrationModel A given model used to value the calibration products.
* @param calibrationAccuracy Error tolerance of the solver. Set to 0 if you need machine precision.
* @throws net.finmath.optimizer.SolverException May be thrown if the solver does not cannot find a solution of the calibration problem.
* @throws CloneNotSupportedException Thrown, when a curve could not be cloned.
*/
public CalibratedCurves(CalibrationSpec[] calibrationSpecs, AnalyticModel calibrationModel, double calibrationAccuracy) throws SolverException, CloneNotSupportedException {
this(calibrationSpecs, calibrationModel, 0.0, calibrationAccuracy);
}
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products and a given model.
*
* If the model already contains a curve referenced as calibration curve that
* curve is replaced by a clone, retaining the given curve information and
* adding a new calibration point.
*
* If the model does not contain the curve referenced as calibration curve, the
* curve will be added to the model.
*
* Use case: You already have a discount curve as part of the model and like
* to calibrate an additional curve to an additional set of instruments.
*
* @param calibrationSpecs Array of calibration specs.
* @param calibrationModel A given model used to value the calibration products.
* @throws net.finmath.optimizer.SolverException May be thrown if the solver does not cannot find a solution of the calibration problem.
* @throws CloneNotSupportedException Thrown, when a curve could not be cloned.
*/
public CalibratedCurves(CalibrationSpec[] calibrationSpecs, AnalyticModel calibrationModel) throws SolverException, CloneNotSupportedException {
this(calibrationSpecs, calibrationModel, 0.0);
}
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products.
*
* @param calibrationSpecs Array of calibration specs.
* @throws net.finmath.optimizer.SolverException May be thrown if the solver does not cannot find a solution of the calibration problem.
* @throws CloneNotSupportedException Thrown, when a curve could not be cloned.
*/
public CalibratedCurves(Collection calibrationSpecs) throws SolverException, CloneNotSupportedException {
this(calibrationSpecs.toArray(new CalibrationSpec[calibrationSpecs.size()]), null);
}
/**
* Generate a collection of calibrated curves (discount curves, forward curves)
* from a vector of calibration products.
*
* @param calibrationSpecs Array of calibration specs.
* @throws net.finmath.optimizer.SolverException May be thrown if the solver does not cannot find a solution of the calibration problem.
* @throws CloneNotSupportedException Thrown, when a curve could not be cloned.
*/
public CalibratedCurves(CalibrationSpec[] calibrationSpecs) throws SolverException, CloneNotSupportedException {
this(calibrationSpecs, null, 0.0);
}
public AnalyticProductInterface getCalibrationProductForSpec(CalibrationSpec calibrationSpec) {
createDiscountCurve(calibrationSpec.discountCurveReceiverName);
createDiscountCurve(calibrationSpec.discountCurvePayerName);
String forwardCurveReceiverName = createForwardCurve(calibrationSpec.swapTenorDefinitionReceiver, calibrationSpec.forwardCurveReceiverName);
String forwardCurvePayerName = createForwardCurve(calibrationSpec.swapTenorDefinitionPayer, calibrationSpec.forwardCurvePayerName);
ScheduleInterface tenorReceiver = calibrationSpec.swapTenorDefinitionReceiver;
ScheduleInterface tenorPayer = calibrationSpec.swapTenorDefinitionPayer;
AnalyticProductInterface product = null;
if(calibrationSpec.type.toLowerCase().equals("swap")) {
product = new Swap(tenorReceiver, forwardCurveReceiverName, calibrationSpec.spreadReceiver, calibrationSpec.discountCurveReceiverName, tenorPayer, forwardCurvePayerName, calibrationSpec.spreadPayer, calibrationSpec.discountCurvePayerName);
}
else if(calibrationSpec.type.toLowerCase().equals("swapleg")) {
product = new SwapLeg(tenorReceiver, forwardCurveReceiverName, calibrationSpec.spreadReceiver, calibrationSpec.discountCurveReceiverName, true);
}
else {
throw new RuntimeException("Product of type " + calibrationSpec.type + " unknown.");
}
return product;
}
/**
* Return the calibrated model, i.e., the model maintaining a collection of curves calibrated to the
* given calibration specifications.
*
* @return The calibrated model.
*/
public AnalyticModelInterface getModel() {
return model;
}
/**
* Get a curve for a given name.
*
* @param name Name of the curve
* @return The curve model.
*/
public CurveInterface getCurve(String name) {
return model.getCurve(name);
}
/**
* Return the number of iterations needed to calibrate the model.
*
* @return The number of iterations needed to calibrate the model.
*/
public int getLastNumberOfInterations() {
return lastNumberOfInterations;
}
/**
* Return the accuracy achieved in the last calibration.
*
* @return The accuracy achieved in the last calibration.
*/
public double getLastAccuracy() {
return lastAccuracy;
}
private int calibrate(double accuracy) throws SolverException {
Solver solver = new Solver(model, calibrationProducts, evaluationTime, accuracy);
model = solver.getCalibratedModel(curvesToCalibrate);
lastAccuracy = solver.getAccuracy();
return solver.getIterations();
}
/**
* Add a calibration product to the set of calibration instruments.
*
* @param calibrationSpec The spec of the calibration product.
* @throws CloneNotSupportedException Thrown if a curve could not be cloned / created.
*/
private String add(CalibrationSpec calibrationSpec) throws CloneNotSupportedException
{
/*
* Add one point to the calibration curve and one new objective function
*/
// Create calibration product (will also create the curve if necessary)
calibrationProducts.add(getCalibrationProductForSpec(calibrationSpec));
// Create parameter to calibrate
// Remove old curve
CurveInterface calibrationCurveOld = model.getCurve(calibrationSpec.calibrationCurveName);
curvesToCalibrate.remove(calibrationCurveOld);
// Create and add new curve
CurveInterface calibrationCurve = null;
if(DiscountCurveInterface.class.isInstance(calibrationCurveOld)) {
@SuppressWarnings("unused")
double paymentTime = calibrationSpec.swapTenorDefinitionReceiver.getPayment(calibrationSpec.swapTenorDefinitionReceiver.getNumberOfPeriods()-1);
// Build new curve with one additional point
calibrationCurve = calibrationCurveOld
.getCloneBuilder()
.addPoint(calibrationSpec.calibrationTime, 1.0, true)
.build();
}
else if(ForwardCurveInterface.class.isInstance(calibrationCurveOld)) {
// Build new curve with one additional point
calibrationCurve = calibrationCurveOld
.getCloneBuilder()
.addPoint(calibrationSpec.calibrationTime, 0.1, true)
.build();
}
else {
// Build new curve with one additional point
calibrationCurve = calibrationCurveOld
.getCloneBuilder()
.addPoint(calibrationSpec.calibrationTime, 1.0, true)
.build();
}
model.setCurve(calibrationCurve);
curvesToCalibrate.add(calibrationCurve);
return calibrationSpec.type;
}
/**
* Get a discount curve from the model, if not existing create a discount curve.
*
* @param discountCurveName The name of the discount curve to create.
* @return The discount factor curve associated with the given name.
*/
private DiscountCurveInterface createDiscountCurve(String discountCurveName) {
DiscountCurveInterface discountCurve = model.getDiscountCurve(discountCurveName);
if(discountCurve == null) {
discountCurve = DiscountCurve.createDiscountCurveFromDiscountFactors(discountCurveName, new double[] { 0.0 }, new double[] { 1.0 });
model.setCurve(discountCurve);
}
return discountCurve;
}
/**
* Get a forward curve from the model, if not existing create a forward curve.
*
* @param swapTenorDefinition The swap tenor associated with the forward curve.
* @param forwardCurveName The name of the forward curve to create.
* @return The forward curve associated with the given name.
*/
private String createForwardCurve(ScheduleInterface swapTenorDefinition, String forwardCurveName) {
/*
* Temporary "hack" - we try to infer index maturity codes from curve name.
*/
String indexMaturityCode = null;
if(forwardCurveName.contains("_12M") || forwardCurveName.contains("-12M") || forwardCurveName.contains(" 12M")) indexMaturityCode = "12M";
if(forwardCurveName.contains("_1M") || forwardCurveName.contains("-1M") || forwardCurveName.contains(" 1M")) indexMaturityCode = "1M";
if(forwardCurveName.contains("_6M") || forwardCurveName.contains("-6M") || forwardCurveName.contains(" 6M")) indexMaturityCode = "6M";
if(forwardCurveName.contains("_3M") || forwardCurveName.contains("-3M") || forwardCurveName.contains(" 3M")) indexMaturityCode = "3M";
if(forwardCurveName == null || forwardCurveName.isEmpty()) return null;
// Check if the curves exists, if not create it
CurveInterface curve = model.getCurve(forwardCurveName);
CurveInterface forwardCurve = null;
if(curve == null) {
// Create a new forward curve
boolean isUseForwardCurve = true;
if(isUseForwardCurve) {
curve = new ForwardCurve(forwardCurveName, swapTenorDefinition.getReferenceDate(), indexMaturityCode, ForwardCurve.InterpolationEntityForward.FORWARD, null);
}
else {
// Alternative: Model the forward curve through an underlying discount curve.
curve = DiscountCurve.createDiscountCurveFromDiscountFactors(forwardCurveName, new double[] { 0.0 }, new double[] { 1.0 });
model.setCurve(curve);
}
}
// Check if the curve is a discount curve, if yes - create a forward curve wrapper.
if(DiscountCurveInterface.class.isInstance(curve)) {
/*
* If the specified forward curve exits as a discount curve, we generate a forward curve
* by wrapping the discount curve and calculating the
* forward from discount factors using the formula (df(T)/df(T+Delta T) - 1) / Delta T).
*
* If no index maturity is used, the forward curve is interpreted "single curve", i.e.
* T+Delta T is always the payment.
*/
forwardCurve = new ForwardCurveFromDiscountCurve(curve.getName(), swapTenorDefinition.getReferenceDate(), indexMaturityCode);
}
else {
// Use a given forward curve
forwardCurve = curve;
}
model.setCurve(forwardCurve);
return forwardCurve.getName();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy