Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
* In its default case the class specifies a multi-factor LIBOR market model in its log-normal formulation, that is
* Lj = exp(Yj) where
* \[
* dY_{j} = \mu_{j} dt + \lambda_{1,j} dW_{1} + \ldots + \lambda_{m,j} dW_{m}
* \]
*
* The model uses an {@link net.finmath.montecarlo.interestrate.models.covariance.LIBORCovarianceModel} for the specification of
* (λ1,j,...,λm,j) as a covariance model.
* See {@link net.finmath.montecarlo.model.ProcessModel} for details on the implemented interface
*
* However, the class is more general:
*
*
* The model may be log-normal or normal specification with a given local volatility.
*
*
* The class implements different measure(drift) / numeraire pairs: terminal measure and spot measure.
*
*
* The class allows to configure a discounting curve (e.g. for "OIS discounting") using a simple deterministic zero spread.
* In this case, the numeraire \( N(t) \) is adjusted by \( \exp( \int_0^t -\lambda(\tau) d\tau ) \).
*
*
*
*
* The class specifies a LIBOR market model, that is
* Lj = f(Yj) where
*
*
* f is f(x) = exp(x) (default, log-normal LIBOR Market Model) or
*
*
* f is f(x) = x (normal model, used if property.set("stateSpace","NORMAL"))
*
*
* and
*
* dYj = μj dt + λ1,j dW1 + ... + λm,j dWm
*
* see {@link net.finmath.montecarlo.model.ProcessModel} for details on the implemented interface.
*
* The model uses an AbstractLIBORCovarianceModel as a covariance model.
* If the covariance model is of type AbstractLIBORCovarianceModelParametric
* a calibration to swaptions can be performed.
*
* Note that λ may still depend on L, hence generating a log-normal dynamic for L even
* if the stateSpace property has been set to NORMAL.
*
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT: Simulate under spot measure. In this case, the single curve numeraire
* is \( N(T_{i}) = \prod_{j=0}^{i-1} (1 + L(T_{j},T_{j+1};T_{j}) (T_{j+1}-T_{j})) \).
*
*
* TERMINAL: Simulate under terminal measure. In this case, the single curve numeraire
* is \( N(T_{i}) = P(T_{n};T_{i}) = \prod_{j=i}^{n-1} (1 + L(T_{j},T_{j+1};T_{i}) (T_{j+1}-T_{j}))^{-1} \).
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL: The state space transform is set to exp, i.e., L = exp(Y). When the covariance model is deterministic, then this is the classical lognormal LIBOR market model. Note that the covariance model may still provide a local volatility function.
*
*
* NORMAL: The state space transform is set to identity, i.e., L = Y. When the covariance model is deterministic, then this is a normal LIBOR market model. Note that the covariance model may still provide a local volatility function.
*
*
*
*
* simulationTimeInterpolationMethod: Possible values:
*
*
* ROUND_DOWN: \( L(S,T;t) \) is mapped to \( L(S,T,t_{j}) \) with \( t_{j} \) being the largest time in the time discretization such that \( t_{j} \leq t \).
*
*
* ROUND_NEAREST: \( L(S,T;t) \) is mapped to \( L(S,T,t_{j}) \) with \( t_{j} \) being the nearest time in the time discretization.
*
*
*
*
* liborCap: An optional Double value applied as a cap to the LIBOR rates.
* May be used to limit the simulated valued to prevent values attaining POSITIVE_INFINITY and
* numerical problems. To disable the cap, set liborCap to Double.POSITIVE_INFINITY.
*
*
*
* The main task of this class is to calculate the risk-neutral drift and the
* corresponding numeraire given the covariance model.
*
* The calibration of the covariance structure is not part of this class. For the calibration
* of parametric models of the instantaneous covariance see
* {@link net.finmath.montecarlo.interestrate.models.covariance.AbstractLIBORCovarianceModelParametric#getCloneCalibrated(LIBORMarketModel, CalibrationProduct[], Map)}.
*
* @author Christian Fries
* @version 1.2
* @see net.finmath.montecarlo.process.MonteCarloProcess The interface for numerical schemes.
* @see net.finmath.montecarlo.model.ProcessModel The interface for models provinding parameters to numerical schemes.
* @see net.finmath.montecarlo.interestrate.models.covariance.AbstractLIBORCovarianceModel The abstract covariance model plug ins.
* @see net.finmath.montecarlo.interestrate.models.covariance.AbstractLIBORCovarianceModelParametric A parametic covariance model including a generic calibration algorithm.
*/
public class LIBORMarketModelFromCovarianceModel extends AbstractProcessModel implements LIBORMarketModel, Serializable {
private static final long serialVersionUID = 4166077559001066615L;
public enum Measure { SPOT, TERMINAL }
public enum StateSpace { NORMAL, LOGNORMAL }
public enum Driftapproximation { EULER, LINE_INTEGRAL, PREDICTOR_CORRECTOR }
public enum InterpolationMethod { LINEAR, LOG_LINEAR_UNCORRECTED, LOG_LINEAR_CORRECTED }
public enum SimulationTimeInterpolationMethod { ROUND_DOWN, ROUND_NEAREST }
private final TimeDiscretization liborPeriodDiscretization; // tenor discretization T_{0} < T_{1} < ...
// Initial value
private final AnalyticModel curveModel;
private final ForwardCurve forwardRateCurve;
private final DiscountCurve discountCurve;
private final RandomVariableFactory randomVariableFactory;
// Factor Loadings (covariance - volatility and correlation
private LIBORCovarianceModel covarianceModel;
private SwaptionMarketData swaptionMarketData;
// Measure / Drift (and default values)
private final Driftapproximation driftApproximationMethod = Driftapproximation.EULER;
private Measure measure = Measure.SPOT;
private StateSpace stateSpace = StateSpace.LOGNORMAL;
// Interpolation
private SimulationTimeInterpolationMethod simulationTimeInterpolationMethod = SimulationTimeInterpolationMethod.ROUND_NEAREST;
private InterpolationMethod interpolationMethod = InterpolationMethod.LOG_LINEAR_UNCORRECTED;
private double liborCap = 1E5;
// This is a cache of the integrated covariance.
private double[][][] integratedLIBORCovariance;
private transient Object integratedLIBORCovarianceLazyInitLock = new Object();
// Cache for the numeraires, needs to be invalidated if process changes - move out of the object (to process?)
private transient MonteCarloProcess numerairesProcess = null;
private transient ConcurrentHashMap numeraires = new ConcurrentHashMap<>();
private transient ConcurrentHashMap numeraireDiscountFactorForwardRates = new ConcurrentHashMap<>();
private transient ConcurrentHashMap numeraireDiscountFactors = new ConcurrentHashMap<>();
private transient Vector interpolationDriftAdjustmentsTerminal = new Vector<>();
/**
* Creates a LIBOR Market Model for given covariance with a calibration (if calibration items are given).
*
* If calibrationItems in non-empty and the covariance model is a parametric model,
* the covariance will be replaced by a calibrate version of the same model, i.e.,
* the LIBOR Market Model will be calibrated. Note: Calibration is not lazy.
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT (String): Simulate under spot measure.
*
*
* TERMINAL (String): Simulate under terminal measure.
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL (String): Simulate L = exp(Y).
*
*
* NORMAL (String): Simulate L = Y.
*
*
*
*
* simulationTimeInterpolationMethod: Possible values:
*
*
* ROUND_DOWN: \( L(S,T;t) \) is mapped to \( L(S,T,t_{j}) \) with \( t_{j} \) being the largest time in the time discretization such that \( t_{j} \leq t \).
*
*
* ROUND_NEAREST: \( L(S,T;t) \) is mapped to \( L(S,T,t_{j}) \) with \( t_{j} \) being the nearest time in the time discretization.
*
*
*
*
* liborCap: An optional Double value applied as a cap to the LIBOR rates.
* May be used to limit the simulated valued to prevent values attaining POSITIVE_INFINITY and
* numerical problems. To disable the cap, set liborCap to Double.POSITIVE_INFINITY.
*
*
* calibrationParameters: Possible values:
*
*
* Map<String,Object> a parameter map with the following key/value pairs:
*
*
* accuracy: Double specifying the required solver accuracy.
*
*
* maxIterations: Integer specifying the maximum iterations for the solver.
*
*
*
*
*
*
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param analyticModel The associated analytic model of this model (containing the associated market data objects like curve).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param randomVariableFactory The random variable factory used to create the initial values of the model.
* @param covarianceModel The covariance model to use.
* @param calibrationProducts The vector of calibration items (a union of a product, target value and weight) for the objective function sum weight(i) * (modelValue(i)-targetValue(i).
* @param properties Key value map specifying properties like measure and stateSpace.
* @return A new instance of LIBORMarketModelFromCovarianceModel, possibly calibrated.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public static LIBORMarketModelFromCovarianceModel of(
final TimeDiscretization liborPeriodDiscretization,
final AnalyticModel analyticModel,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final RandomVariableFactory randomVariableFactory,
final LIBORCovarianceModel covarianceModel,
final CalibrationProduct[] calibrationProducts,
final Map properties
) throws CalculationException {
final LIBORMarketModelFromCovarianceModel model = new LIBORMarketModelFromCovarianceModel(liborPeriodDiscretization, analyticModel, forwardRateCurve, discountCurve, randomVariableFactory, covarianceModel, properties);
// Perform calibration, if data is given
if(calibrationProducts != null && calibrationProducts.length > 0) {
Map calibrationParameters = null;
if(properties != null && properties.containsKey("calibrationParameters")) {
@SuppressWarnings("unchecked")
Map calibrationParametersProperty = (Map)properties.get("calibrationParameters");
calibrationParameters = calibrationParametersProperty;
}
LIBORCovarianceModelCalibrateable covarianceModelParametric = null;
try {
covarianceModelParametric = (LIBORCovarianceModelCalibrateable)covarianceModel;
}
catch(final Exception e) {
throw new ClassCastException("Calibration restricted to covariance models implementing LIBORCovarianceModelCalibrateable.");
}
final LIBORCovarianceModel covarianceModelCalibrated = covarianceModelParametric.getCloneCalibrated(model, calibrationProducts, calibrationParameters);
final LIBORMarketModelFromCovarianceModel modelCalibrated = model.getCloneWithModifiedCovarianceModel(covarianceModelCalibrated);
return modelCalibrated;
}
else {
return model;
}
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* If calibrationItems in non-empty and the covariance model is a parametric model,
* the covariance will be replaced by a calibrate version of the same model, i.e.,
* the LIBOR Market Model will be calibrated.
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT (String): Simulate under spot measure.
*
*
* TERMINAL (String): Simulate under terminal measure.
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL (String): Simulate L = exp(Y).
*
*
* NORMAL (String): Simulate L = Y.
*
*
*
*
* liborCap: An optional Double value applied as a cap to the LIBOR rates.
* May be used to limit the simulated valued to prevent values attaining POSITIVE_INFINITY and
* numerical problems. To disable the cap, set liborCap to Double.POSITIVE_INFINITY.
*
*
* calibrationParameters: Possible values:
*
*
* Map<String,Object> a parameter map with the following key/value pairs:
*
*
* accuracy: Double specifying the required solver accuracy.
*
*
* maxIterations: Integer specifying the maximum iterations for the solver.
*
*
*
*
*
*
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param analyticModel The associated analytic model of this model (containing the associated market data objects like curve).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param randomVariableFactory The random variable factory used to create the initial values of the model.
* @param covarianceModel The covariance model to use.
* @param calibrationProducts The vector of calibration items (a union of a product, target value and weight) for the objective function sum weight(i) * (modelValue(i)-targetValue(i).
* @param properties Key value map specifying properties like measure and stateSpace.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final AnalyticModel analyticModel,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final RandomVariableFactory randomVariableFactory,
final LIBORCovarianceModel covarianceModel,
final CalibrationProduct[] calibrationProducts,
final Map properties
) throws CalculationException {
// Set some properties
if(properties != null && properties.containsKey("measure")) {
measure = Measure.valueOf(((String)properties.get("measure")).toUpperCase());
}
if(properties != null && properties.containsKey("stateSpace")) {
stateSpace = StateSpace.valueOf(((String)properties.get("stateSpace")).toUpperCase());
}
if(properties != null && properties.containsKey("interpolationMethod")) {
interpolationMethod = InterpolationMethod.valueOf(((String)properties.get("interpolationMethod")).toUpperCase());
}
if(properties != null && properties.containsKey("simulationTimeInterpolationMethod")) {
simulationTimeInterpolationMethod = SimulationTimeInterpolationMethod.valueOf(((String)properties.get("simulationTimeInterpolationMethod")).toUpperCase());
}
if(properties != null && properties.containsKey("liborCap")) {
liborCap = (Double)properties.get("liborCap");
}
Map calibrationParameters = null;
if(properties != null && properties.containsKey("calibrationParameters")) {
@SuppressWarnings("unchecked")
Map calibrationParametersProperty = (Map)properties.get("calibrationParameters");
calibrationParameters = calibrationParametersProperty;
}
this.liborPeriodDiscretization = liborPeriodDiscretization;
curveModel = analyticModel;
this.forwardRateCurve = forwardRateCurve;
this.discountCurve = discountCurve;
this.randomVariableFactory = randomVariableFactory;
// Perform calibration, if data is given
if(calibrationProducts != null && calibrationProducts.length > 0) {
LIBORCovarianceModelCalibrateable covarianceModelParametric = null;
try {
covarianceModelParametric = (LIBORCovarianceModelCalibrateable)covarianceModel;
}
catch(final Exception e) {
throw new ClassCastException("Calibration restricted to covariance models implementing LIBORCovarianceModelCalibrateable.");
}
this.covarianceModel = covarianceModelParametric.getCloneCalibrated(this, calibrationProducts, calibrationParameters);
}
else {
this.covarianceModel = covarianceModel;
}
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT (String): Simulate under spot measure.
*
*
* TERMINAL (String): Simulate under terminal measure.
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL (String): Simulate L = exp(Y).
*
*
* NORMAL (String): Simulate L = Y.
*
*
*
*
* liborCap: An optional Double value applied as a cap to the LIBOR rates.
* May be used to limit the simulated valued to prevent values attaining POSITIVE_INFINITY and
* numerical problems. To disable the cap, set liborCap to Double.POSITIVE_INFINITY.
*
*
* calibrationParameters: Possible values:
*
*
* Map<String,Object> a parameter map with the following key/value pairs:
*
*
* accuracy: Double specifying the required solver accuracy.
*
*
* maxIterations: Integer specifying the maximum iterations for the solver.
*
*
*
*
*
*
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param analyticModel The associated analytic model of this model (containing the associated market data objects like curve).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param randomVariableFactory The random variable factory used to create the initial values of the model.
* @param covarianceModel The covariance model to use.
* @param properties Key value map specifying properties like measure and stateSpace.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final AnalyticModel analyticModel,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final RandomVariableFactory randomVariableFactory,
final LIBORCovarianceModel covarianceModel,
final Map properties
) throws CalculationException {
this(liborPeriodDiscretization, analyticModel, forwardRateCurve, discountCurve, randomVariableFactory, covarianceModel, null, properties);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* If calibrationItems in non-empty and the covariance model is a parametric model,
* the covariance will be replaced by a calibrate version of the same model, i.e.,
* the LIBOR Market Model will be calibrated.
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT (String): Simulate under spot measure.
*
*
* TERMINAL (String): Simulate under terminal measure.
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL (String): Simulate L = exp(Y).
*
*
* NORMAL (String): Simulate L = Y.
*
*
*
*
* liborCap: An optional Double value applied as a cap to the LIBOR rates.
* May be used to limit the simulated valued to prevent values attaining POSITIVE_INFINITY and
* numerical problems. To disable the cap, set liborCap to Double.POSITIVE_INFINITY.
*
*
* calibrationParameters: Possible values:
*
*
* Map<String,Object> a parameter map with the following key/value pairs:
*
*
* accuracy: Double specifying the required solver accuracy.
*
*
* maxIterations: Integer specifying the maximum iterations for the solver.
*
*
*
*
*
*
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param analyticModel The associated analytic model of this model (containing the associated market data objects like curve).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param covarianceModel The covariance model to use.
* @param calibrationItems The vector of calibration items (a union of a product, target value and weight) for the objective function sum weight(i) * (modelValue(i)-targetValue(i).
* @param properties Key value map specifying properties like measure and stateSpace.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
* @deprecated Use LIBORMarketModelFromCovarianceModel.of() instead.
*/
@Deprecated
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final AnalyticModel analyticModel,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final LIBORCovarianceModel covarianceModel,
final CalibrationProduct[] calibrationItems,
final Map properties
) throws CalculationException {
this(liborPeriodDiscretization, analyticModel, forwardRateCurve, discountCurve, new RandomVariableFromArrayFactory(), covarianceModel, calibrationItems, properties);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param covarianceModel The covariance model to use.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final LIBORCovarianceModel covarianceModel
) throws CalculationException {
this(liborPeriodDiscretization, forwardRateCurve, new DiscountCurveFromForwardCurve(forwardRateCurve), covarianceModel, new CalibrationProduct[0], null);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param covarianceModel The covariance model to use.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final LIBORCovarianceModel covarianceModel
) throws CalculationException {
this(liborPeriodDiscretization, forwardRateCurve, discountCurve, covarianceModel, new CalibrationProduct[0], null);
}
/**
* Creates a LIBOR Market Model using a given covariance model and calibrating this model
* to given swaption volatility data.
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param covarianceModel The covariance model to use.
* @param swaptionMarketData The set of swaption values to calibrate to.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final LIBORCovarianceModel covarianceModel,
final SwaptionMarketData swaptionMarketData
) throws CalculationException {
this(liborPeriodDiscretization, forwardRateCurve, new DiscountCurveFromForwardCurve(forwardRateCurve), covarianceModel, swaptionMarketData, null);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param covarianceModel The covariance model to use.
* @param swaptionMarketData The set of swaption values to calibrate to.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final LIBORCovarianceModel covarianceModel,
final SwaptionMarketData swaptionMarketData
) throws CalculationException {
this(liborPeriodDiscretization, forwardRateCurve, discountCurve, covarianceModel, swaptionMarketData, null);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param covarianceModel The covariance model to use.
* @param swaptionMarketData The set of swaption values to calibrate to.
* @param properties Key value map specifying properties like measure and stateSpace.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final LIBORCovarianceModel covarianceModel,
final SwaptionMarketData swaptionMarketData,
final Map properties
) throws CalculationException {
this(
liborPeriodDiscretization,
forwardRateCurve,
discountCurve,
covarianceModel,
getCalibrationItems(
liborPeriodDiscretization,
forwardRateCurve,
swaptionMarketData,
// Condition under which we use analytic approximation
(properties == null || properties.get("stateSpace") == null || ((String)properties.get("stateSpace")).toUpperCase().equals(StateSpace.LOGNORMAL.name()))
&& AbstractLIBORCovarianceModelParametric.class.isAssignableFrom(covarianceModel.getClass())
),
properties
);
}
/**
* Creates a LIBOR Market Model for given covariance.
*
* If calibrationItems in non-empty and the covariance model is a parametric model,
* the covariance will be replaced by a calibrate version of the same model, i.e.,
* the LIBOR Market Model will be calibrated.
*
* The map properties allows to configure the model. The following keys may be used:
*
*
* measure: Possible values:
*
*
* SPOT (String): Simulate under spot measure.
*
*
* TERMINAL (String): Simulate under terminal measure.
*
*
*
*
* stateSpace: Possible values:
*
*
* LOGNORMAL (String): Simulate L = exp(Y).
*
*
* NORMAL (String): Simulate L = Y.
*
*
*
*
* calibrationParameters: Possible values:
*
*
* Map<String,Object> a parameter map with the following key/value pairs:
*
*
* accuracy: Double specifying the required solver accuracy.
*
*
* maxIterations: Integer specifying the maximum iterations for the solver.
*
*
*
*
*
*
*
* @param liborPeriodDiscretization The discretization of the interest rate curve into forward rates (tenor structure).
* @param forwardRateCurve The initial values for the forward rates.
* @param discountCurve The discount curve to use. This will create an LMM model with a deterministic zero-spread discounting adjustment.
* @param covarianceModel The covariance model to use.
* @param calibrationItems The vector of calibration items (a union of a product, target value and weight) for the objective function sum weight(i) * (modelValue(i)-targetValue(i).
* @param properties Key value map specifying properties like measure and stateSpace.
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
* @deprecated Use LIBORMarketModelFromCovarianceModel.of() instead.
*/
@Deprecated
public LIBORMarketModelFromCovarianceModel(
final TimeDiscretization liborPeriodDiscretization,
final ForwardCurve forwardRateCurve,
final DiscountCurve discountCurve,
final LIBORCovarianceModel covarianceModel,
final CalibrationProduct[] calibrationItems,
final Map properties
) throws CalculationException {
this(liborPeriodDiscretization, null, forwardRateCurve, discountCurve, covarianceModel, calibrationItems, properties);
}
private static CalibrationProduct[] getCalibrationItems(final TimeDiscretization liborPeriodDiscretization, final ForwardCurve forwardCurve, final SwaptionMarketData swaptionMarketData, final boolean isUseAnalyticApproximation) {
if(swaptionMarketData == null) {
return null;
}
final TimeDiscretization optionMaturities = swaptionMarketData.getOptionMaturities();
final TimeDiscretization tenor = swaptionMarketData.getTenor();
final double swapPeriodLength = swaptionMarketData.getSwapPeriodLength();
final ArrayList calibrationProducts = new ArrayList<>();
for(int exerciseIndex=0; exerciseIndex<=optionMaturities.getNumberOfTimeSteps(); exerciseIndex++) {
for(int tenorIndex=0; tenorIndex<=tenor.getNumberOfTimeSteps()-exerciseIndex; tenorIndex++) {
// Create a swaption
final double exerciseDate = optionMaturities.getTime(exerciseIndex);
final double swapLength = tenor.getTime(tenorIndex);
if(liborPeriodDiscretization.getTimeIndex(exerciseDate) < 0) {
continue;
}
if(liborPeriodDiscretization.getTimeIndex(exerciseDate+swapLength) <= liborPeriodDiscretization.getTimeIndex(exerciseDate)) {
continue;
}
final int numberOfPeriods = (int)(swapLength / swapPeriodLength);
final double[] fixingDates = new double[numberOfPeriods];
final double[] paymentDates = new double[numberOfPeriods];
final double[] swapTenorTimes = new double[numberOfPeriods+1];
for(int periodStartIndex=0; periodStartIndext for which the numeraire should be returned N(t).
* @return The numeraire at the specified time as RandomVariable
* @throws net.finmath.exception.CalculationException Thrown if the valuation fails, specific cause may be available via the cause() method.
*/
@Override
public RandomVariable getNumeraire(final MonteCarloProcess process, double time) throws CalculationException {
if(time < 0) {
return randomVariableFactory.createRandomVariable(discountCurve.getDiscountFactor(curveModel, time));
}
RandomVariable numeraire = getNumerairetUnAdjusted(process, time);
/*
* Adjust for discounting, i.e. funding or collateralization
*/
if (discountCurve != null) {
final RandomVariable defaultableZeroBondAsOfTimeZero = getNumeraireDefaultableZeroBondAsOfTimeZero(process, time);
final double nonDefaultableZeroBond = numeraire.invert().mult(getNumerairetUnAdjusted(process, 0.0)).getAverage();
numeraire = numeraire.mult(nonDefaultableZeroBond).div(defaultableZeroBondAsOfTimeZero);
}
return numeraire;
}
/*
* Calculate the numeraire adjustment, that is, the adjustment between the forward curve and the discount curve.
*
* This methods performs the interpolation only, if the numeraire adjustment is not on the time grid.
*/
private RandomVariable getNumeraireDefaultableZeroBondAsOfTimeZero(final MonteCarloProcess process, final double time) {
final boolean isInterpolateDiscountFactorsOnLiborPeriodDiscretization = true;
final TimeDiscretization timeDiscretizationForCurves = isInterpolateDiscountFactorsOnLiborPeriodDiscretization ? liborPeriodDiscretization : process.getTimeDiscretization();
final int timeIndex = timeDiscretizationForCurves.getTimeIndex(time);
if(timeIndex >= 0) {
return getNumeraireDefaultableZeroBondAsOfTimeZero(process, timeIndex);
}
else {
// Interpolation
final int timeIndexPrev = Math.min(-timeIndex-2, getLiborPeriodDiscretization().getNumberOfTimes()-2);
final int timeIndexNext = timeIndexPrev+1;
final double timePrev = timeDiscretizationForCurves.getTime(timeIndexPrev);
final double timeNext = timeDiscretizationForCurves.getTime(timeIndexNext);
final RandomVariable numeraireAdjustmentPrev = getNumeraireDefaultableZeroBondAsOfTimeZero(process, timeIndexPrev);
final RandomVariable numeraireAdjustmentNext = getNumeraireDefaultableZeroBondAsOfTimeZero(process, timeIndexNext);
return numeraireAdjustmentPrev.mult(numeraireAdjustmentNext.div(numeraireAdjustmentPrev).pow((time-timePrev)/(timeNext-timePrev)));
}
}
/*
* Calculate the numeraire adjustment, that is, the adjustment of the between the forward curve and the discount curve.
*
* The numeraire adjustment is the ratio of the time-0 discount factor from the given discount curve P^d(T;0)
* and the discount factor P(T;0) calculated from the forward curve constituting the forward rates.
*
* P^d(T;0) is a given curve.
*
* P(T;0) is calculated as product (1+L_i(0) (T_{i+1}-T_{i}))
*
*/
private RandomVariable getNumeraireDefaultableZeroBondAsOfTimeZero(final MonteCarloProcess process, final int timeIndex) {
final boolean isInterpolateDiscountFactorsOnLiborPeriodDiscretization = true;
final TimeDiscretization timeDiscretizationForCurves = isInterpolateDiscountFactorsOnLiborPeriodDiscretization ? liborPeriodDiscretization : process.getTimeDiscretization();
final double time = timeDiscretizationForCurves.getTime(timeIndex);
synchronized(numeraireDiscountFactorForwardRates) {
ensureCacheConsistency(process);
RandomVariable deterministicNumeraireAdjustment = numeraireDiscountFactors.get(time);
if(deterministicNumeraireAdjustment == null) {
final double dfInitial = discountCurve.getDiscountFactor(curveModel, timeDiscretizationForCurves.getTime(0));
deterministicNumeraireAdjustment = randomVariableFactory.createRandomVariable(dfInitial);
numeraireDiscountFactors.put(timeDiscretizationForCurves.getTime(0), deterministicNumeraireAdjustment);
for(int i=0; i getNumeraireAdjustments() {
return Collections.unmodifiableMap(numeraireDiscountFactorForwardRates);
}
@Override
public RandomVariable[] getInitialState(MonteCarloProcess process) {
final double[] liborInitialStates = new double[liborPeriodDiscretization.getNumberOfTimeSteps()];
for(int timeIndex=0; timeIndexMeasure.SPOT or Measure.TERMINAL - depending how the
* model object was constructed. For Measure.TERMINAL the j-th entry of the return value is the random variable
* \[
* \mu_{j}^{\mathbb{Q}^{P(T_{n})}}(t) \ = \ - \mathop{\sum_{l\geq j+1}}_{l\leq n-1} \frac{\delta_{l}}{1+\delta_{l} L_{l}(t)} (\lambda_{j}(t) \cdot \lambda_{l}(t))
* \]
* and for Measure.SPOT the j-th entry of the return value is the random variable
* \[
* \mu_{j}^{\mathbb{Q}^{N}}(t) \ = \ \sum_{m(t) < l\leq j} \frac{\delta_{l}}{1+\delta_{l} L_{l}(t)} (\lambda_{j}(t) \cdot \lambda_{l}(t))
* \]
* where \( \lambda_{j} \) is the vector for factor loadings for the j-th component of the stochastic process (that is, the diffusion part is
* \( \sum_{k=1}^m \lambda_{j,k} \mathrm{d}W_{k} \)).
*
* Note: The scalar product of the factor loadings determines the instantaneous covariance. If the model is written in log-coordinates (using exp as a state space transform), we find
* \(\lambda_{j} \cdot \lambda_{l} = \sum_{k=1}^m \lambda_{j,k} \lambda_{l,k} = \sigma_{j} \sigma_{l} \rho_{j,l} \).
* If the model is written without a state space transformation (in its orignial coordinates) then \(\lambda_{j} \cdot \lambda_{l} = \sum_{k=1}^m \lambda_{j,k} \lambda_{l,k} = L_{j} L_{l} \sigma_{j} \sigma_{l} \rho_{j,l} \).
*
*
* @see net.finmath.montecarlo.interestrate.models.LIBORMarketModelFromCovarianceModel#getNumeraire(MonteCarloProcess, double) The calculation of the drift is consistent with the calculation of the numeraire in getNumeraire.
* @see net.finmath.montecarlo.interestrate.models.LIBORMarketModelFromCovarianceModel#getFactorLoading(MonteCarloProcess, int, int, RandomVariable[]) The factor loading \( \lambda_{j,k} \).
*
* @param process The discretization process generating this model. The process provides call backs for TimeDiscretization and allows calls to getProcessValue for timeIndices less or equal the given one.
* @param timeIndex Time index i for which the drift should be returned μ(ti).
* @param realizationAtTimeIndex Time current forward rate vector at time index i which should be used in the calculation.
* @return The drift vector μ(ti) as RandomVariableFromDoubleArray[]
*/
@Override
public RandomVariable[] getDrift(final MonteCarloProcess process, final int timeIndex, final RandomVariable[] realizationAtTimeIndex, final RandomVariable[] realizationPredictor) {
final double time = process.getTime(timeIndex); // t - current simulation time
int firstForwardRateIndex = this.getLiborPeriodIndex(time)+1; // m(t)+1 - the end of the current period
if(firstForwardRateIndex<0) {
firstForwardRateIndex = -firstForwardRateIndex-1 + 1;
}
final RandomVariable zero = Scalar.of(0.0);
// Allocate drift vector and initialize to zero (will be used to sum up drift components)
final RandomVariable[] drift = new RandomVariable[getNumberOfComponents()];
for(int componentIndex=firstForwardRateIndex; componentIndex=firstForwardRateIndex; componentIndex--) {
final double periodLength = getLiborPeriodDiscretization().getTimeStep(componentIndex);
final RandomVariable forwardRate = realizationAtTimeIndex[componentIndex];
RandomVariable oneStepMeasureTransform = Scalar.of(-periodLength).discount(forwardRate, periodLength);
if(stateSpace == StateSpace.LOGNORMAL) {
oneStepMeasureTransform = oneStepMeasureTransform.mult(forwardRate);
}
final RandomVariable[] factorLoading = getFactorLoading(process, timeIndex, componentIndex, realizationAtTimeIndex);
drift[componentIndex] = drift[componentIndex].addSumProduct(factorLoadingsSums, factorLoading);
for(int factorIndex=0; factorIndex process.getTime(timeIndex+1)-time) {
timeIndex++;
}
}
// The forward rates are provided on fractional tenor discretization points using linear interpolation. See ISBN 0470047224.
// Interpolation on tenor using interpolationMethod
if(periodEndIndex < 0) {
final int previousEndIndex = (-periodEndIndex-1)-1;
final double nextEndTime = getLiborPeriod(previousEndIndex+1);
// Interpolate forward rate from periodStart to periodEnd on periodEnd
final RandomVariable onePlusLongLIBORdt = getForwardRate(process, time, periodStart, nextEndTime).mult(nextEndTime - periodStart).add(1.0);
final RandomVariable onePlusInterpolatedLIBORDt = getOnePlusInterpolatedLIBORDt(process, timeIndex, periodEnd, previousEndIndex);
return onePlusLongLIBORdt.div(onePlusInterpolatedLIBORDt).sub(1.0).div(periodEnd - periodStart);
}
// Interpolation on tenor using interpolationMethod
if(periodStartIndex < 0) {
final int previousStartIndex = (-periodStartIndex-1)-1;
final double nextStartTime = getLiborPeriod(previousStartIndex+1);
if(nextStartTime > periodEnd) {
throw new AssertionError("Interpolation not possible.");
}
if(nextStartTime == periodEnd) {
return getOnePlusInterpolatedLIBORDt(process, timeIndex, periodStart, previousStartIndex).sub(1.0).div(periodEnd - periodStart);
}
final RandomVariable onePlusLongLIBORdt = getForwardRate(process, time, nextStartTime, periodEnd).mult(periodEnd - nextStartTime).add(1.0);
final RandomVariable onePlusInterpolatedLIBORDt = getOnePlusInterpolatedLIBORDt(process, timeIndex, periodStart, previousStartIndex);
return onePlusLongLIBORdt.mult(onePlusInterpolatedLIBORDt).sub(1.0).div(periodEnd - periodStart);
}
if(periodStartIndex < 0 || periodEndIndex < 0) {
throw new AssertionError("LIBOR requested outside libor discretization points and interpolation was not performed.");
}
// If this is a model primitive then return it
if(periodStartIndex+1 == periodEndIndex) {
return getLIBOR(process, timeIndex, periodStartIndex);
}
// The requested LIBOR is not a model primitive. We need to calculate it (slow!)
RandomVariable accrualAccount = null;
// Calculate the value of the forward bond
for(int periodIndex = periodStartIndex; periodIndex= liborPeriodDiscretization.getNumberOfTimes() || timeIndex < 0) {
throw new ArrayIndexOutOfBoundsException("Index for LIBOR period discretization out of bounds: " + timeIndex + ".");
}
return liborPeriodDiscretization.getTime(timeIndex);
}
@Override
public int getLiborPeriodIndex(final double time) {
return liborPeriodDiscretization.getTimeIndex(time);
}
@Override
public TimeDiscretization getLiborPeriodDiscretization() {
return liborPeriodDiscretization;
}
/**
* @return Returns the LIBOR rates interpolation method. See {@link InterpolationMethod}.
*/
public InterpolationMethod getInterpolationMethod() {
return interpolationMethod;
}
/**
* @return Returns the measure. See {@link Measure}.
*/
public Measure getMeasure() {
return measure;
}
@Override
public double[][][] getIntegratedLIBORCovariance(TimeDiscretization simulationTimeDiscretization) {
synchronized (integratedLIBORCovarianceLazyInitLock) {
if(integratedLIBORCovariance == null) {
final TimeDiscretization liborPeriodDiscretization = getLiborPeriodDiscretization();
integratedLIBORCovariance = new double[simulationTimeDiscretization.getNumberOfTimeSteps()][liborPeriodDiscretization.getNumberOfTimeSteps()][liborPeriodDiscretization.getNumberOfTimeSteps()];
for(int timeIndex = 0; timeIndex < simulationTimeDiscretization.getNumberOfTimeSteps(); timeIndex++) {
final double dt = simulationTimeDiscretization.getTime(timeIndex+1) - simulationTimeDiscretization.getTime(timeIndex);
final RandomVariable[][] factorLoadings = new RandomVariable[liborPeriodDiscretization.getNumberOfTimeSteps()][];
// Prefetch factor loadings
for(int componentIndex = 0; componentIndex < liborPeriodDiscretization.getNumberOfTimeSteps(); componentIndex++) {
factorLoadings[componentIndex] = covarianceModel.getFactorLoading(simulationTimeDiscretization.getTime(timeIndex), liborPeriodDiscretization.getTime(componentIndex), null);
}
for(int componentIndex1 = 0; componentIndex1 < liborPeriodDiscretization.getNumberOfTimeSteps(); componentIndex1++) {
final RandomVariable[] factorLoadingOfComponent1 = factorLoadings[componentIndex1];
// Sum the libor cross terms (use symmetry)
for(int componentIndex2 = componentIndex1; componentIndex2 < liborPeriodDiscretization.getNumberOfTimeSteps(); componentIndex2++) {
double integratedLIBORCovarianceValue = 0.0;
if(getLiborPeriod(componentIndex1) > simulationTimeDiscretization.getTime(timeIndex)) {
final RandomVariable[] factorLoadingOfComponent2 = factorLoadings[componentIndex2];
for(int factorIndex = 0; factorIndex < factorLoadingOfComponent2.length; factorIndex++) {
integratedLIBORCovarianceValue += factorLoadingOfComponent1[factorIndex].doubleValue() * factorLoadingOfComponent2[factorIndex].doubleValue() * dt;
}
}
integratedLIBORCovariance[timeIndex][componentIndex1][componentIndex2] = integratedLIBORCovarianceValue;
}
}
}
// Integrate over time (i.e. sum up).
for(int timeIndex = 1; timeIndex < simulationTimeDiscretization.getNumberOfTimeSteps(); timeIndex++) {
final double[][] prevIntegratedLIBORCovariance = integratedLIBORCovariance[timeIndex-1];
final double[][] thisIntegratedLIBORCovariance = integratedLIBORCovariance[timeIndex];
for(int componentIndex1 = 0; componentIndex1 < liborPeriodDiscretization.getNumberOfTimeSteps(); componentIndex1++) {
for(int componentIndex2 = componentIndex1; componentIndex2 < liborPeriodDiscretization.getNumberOfTimeSteps(); componentIndex2++) {
thisIntegratedLIBORCovariance[componentIndex1][componentIndex2] = prevIntegratedLIBORCovariance[componentIndex1][componentIndex2] + thisIntegratedLIBORCovariance[componentIndex1][componentIndex2];
thisIntegratedLIBORCovariance[componentIndex2][componentIndex1] = thisIntegratedLIBORCovariance[componentIndex1][componentIndex2];
}
}
}
}
}
return integratedLIBORCovariance;
}
@Override
public AnalyticModel getAnalyticModel() {
return curveModel;
}
@Override
public DiscountCurve getDiscountCurve() {
return discountCurve;
}
@Override
public ForwardCurve getForwardRateCurve() {
return forwardRateCurve;
}
/**
* Return the swaption market data used for calibration (if any, may be null).
*
* @return The swaption market data used for calibration (if any, may be null).
*/
public SwaptionMarketData getSwaptionMarketData() {
return swaptionMarketData;
}
@Override
public LIBORCovarianceModel getCovarianceModel() {
return covarianceModel;
}
@Override
public Object clone() {
try {
final Map properties = new HashMap<>();
properties.put("measure", measure.name());
properties.put("stateSpace", stateSpace.name());
properties.put("interpolationMethod", interpolationMethod.name());
properties.put("liborCap", liborCap);
return LIBORMarketModelFromCovarianceModel.of(getLiborPeriodDiscretization(), getAnalyticModel(), getForwardRateCurve(), getDiscountCurve(), randomVariableFactory, covarianceModel, null, properties);
} catch (final CalculationException e) {
return null;
}
}
/**
* @param covarianceModel A covariance model
* @return A new LIBORMarketModelFromCovarianceModel using the specified covariance model.
*/
@Override
public LIBORMarketModelFromCovarianceModel getCloneWithModifiedCovarianceModel(final LIBORCovarianceModel covarianceModel) {
final LIBORMarketModelFromCovarianceModel model = (LIBORMarketModelFromCovarianceModel)this.clone();
model.covarianceModel = covarianceModel;
return model;
}
@Override
public LIBORMarketModelFromCovarianceModel getCloneWithModifiedData(final Map dataModified) throws CalculationException {
RandomVariableFactory randomVariableFactory = this.randomVariableFactory;
TimeDiscretization liborPeriodDiscretization = this.liborPeriodDiscretization;
AnalyticModel analyticModel = curveModel;
ForwardCurve forwardRateCurve = this.forwardRateCurve;
DiscountCurve discountCurve = this.discountCurve;
LIBORCovarianceModel covarianceModel = this.covarianceModel;
final Map properties = new HashMap<>();
properties.put("measure", measure.name());
properties.put("stateSpace", stateSpace.name());
properties.put("interpolationMethod", interpolationMethod.name());
properties.put("liborCap", liborCap);
if(dataModified != null) {
randomVariableFactory = (RandomVariableFactory)dataModified.getOrDefault("randomVariableFactory", randomVariableFactory);
liborPeriodDiscretization = (TimeDiscretization)dataModified.getOrDefault("liborPeriodDiscretization", liborPeriodDiscretization);
analyticModel = (AnalyticModel)dataModified.getOrDefault("analyticModel", analyticModel);
forwardRateCurve = (ForwardCurve)dataModified.getOrDefault("forwardRateCurve", forwardRateCurve);
discountCurve = (DiscountCurve)dataModified.getOrDefault("discountCurve", discountCurve);
covarianceModel = (LIBORCovarianceModel)dataModified.getOrDefault("covarianceModel", covarianceModel);
if(dataModified.containsKey("swaptionMarketData")) {
throw new RuntimeException("Swaption market data as input for getCloneWithModifiedData not supported.");
}
if(dataModified.containsKey("forwardRateShift")) {
try {
final double[] forwardCurveValues = getForwardRateCurve().getParameter();
final double[] forwardCurveValuesShift = (double[])dataModified.get("forwardRateShift");
final double[] forwardCurveValuesShifted = new double[forwardCurveValues.length];
for(int i=0; i getModelParameters() {
// Using process from cache
final MonteCarloProcess process = numerairesProcess;
final Map modelParameters = new TreeMap<>();
// Add initial values
for(int liborIndex=0; liborIndex numeraireAdjustment : numeraireDiscountFactorForwardRates.entrySet()) {
modelParameters.put("NUMERAIREADJUSTMENT("+ numeraireAdjustment.getKey() + ")", numeraireAdjustment.getValue());
}
return modelParameters;
}
private void readObject(final ObjectInputStream in) throws IOException, ClassNotFoundException {
in.defaultReadObject();
/*
* Init transient fields
*/
integratedLIBORCovarianceLazyInitLock = new Object();
numeraires = new ConcurrentHashMap<>();
numeraireDiscountFactorForwardRates = new ConcurrentHashMap<>();
numeraireDiscountFactors = new ConcurrentHashMap<>();
interpolationDriftAdjustmentsTerminal = new Vector<>();
}
@Override
public String toString() {
return "LIBORMarketModelFromCovarianceModel [liborPeriodDiscretization="
+ liborPeriodDiscretization + ", curveModel=" + curveModel
+ ", forwardRateCurve=" + forwardRateCurve + ", discountCurve="
+ discountCurve + ", covarianceModel=" + covarianceModel
+ ", driftApproximationMethod=" + driftApproximationMethod
+ ", measure=" + measure + ", stateSpace=" + stateSpace + "]";
}
}