ForwardHazardCreditCurve.java
package org.drip.state.nonlinear;
/*
* -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*/
/*!
* Copyright (C) 2020 Lakshmi Krishnamurthy
* Copyright (C) 2019 Lakshmi Krishnamurthy
* Copyright (C) 2018 Lakshmi Krishnamurthy
* Copyright (C) 2017 Lakshmi Krishnamurthy
* Copyright (C) 2016 Lakshmi Krishnamurthy
* Copyright (C) 2015 Lakshmi Krishnamurthy
* Copyright (C) 2014 Lakshmi Krishnamurthy
* Copyright (C) 2013 Lakshmi Krishnamurthy
* Copyright (C) 2012 Lakshmi Krishnamurthy
* Copyright (C) 2011 Lakshmi Krishnamurthy
*
* This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
* asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
* analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
* equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
* numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
* and computational support.
*
* https://lakshmidrip.github.io/DROP/
*
* DROP is composed of three modules:
*
* - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
* - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
* - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
*
* DROP Product Core implements libraries for the following:
* - Fixed Income Analytics
* - Loan Analytics
* - Transaction Cost Analytics
*
* DROP Portfolio Core implements libraries for the following:
* - Asset Allocation Analytics
* - Asset Liability Management Analytics
* - Capital Estimation Analytics
* - Exposure Analytics
* - Margin Analytics
* - XVA Analytics
*
* DROP Computational Core implements libraries for the following:
* - Algorithm Support
* - Computation Support
* - Function Analysis
* - Model Validation
* - Numerical Analysis
* - Numerical Optimizer
* - Spline Builder
* - Statistical Learning
*
* Documentation for DROP is Spread Over:
*
* - Main => https://lakshmidrip.github.io/DROP/
* - Wiki => https://github.com/lakshmiDRIP/DROP/wiki
* - GitHub => https://github.com/lakshmiDRIP/DROP
* - Repo Layout Taxonomy => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
* - Javadoc => https://lakshmidrip.github.io/DROP/Javadoc/index.html
* - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
* - Release Versions => https://lakshmidrip.github.io/DROP/version.html
* - Community Credits => https://lakshmidrip.github.io/DROP/credits.html
* - Issues Catalog => https://github.com/lakshmiDRIP/DROP/issues
* - JUnit => https://lakshmidrip.github.io/DROP/junit/index.html
* - Jacoco => https://lakshmidrip.github.io/DROP/jacoco/index.html
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
*
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* <i>ForwardHazardCreditCurve</i> manages the Survival Latent State, using the Hazard Rate as the State
* Response Representation. It exports the following functionality:
*
* <br><br>
* <ul>
* <li>
* Boot Methods - Set/Bump Specific Node Quantification Metric, or Set Flat Value
* </li>
* <li>
* Boot Calibration - Initialize Run, Compute Calibration Metric
* </li>
* <li>
* Compute the survival probability, recovery rate, or the hazard rate from the Hazard Rate Latent
* State
* </li>
* <li>
* Retrieve Array of the Calibration Components
* </li>
* <li>
* Retrieve the Curve Construction Input Set
* </li>
* <li>
* Synthesize scenario Latent State by parallel shifting/custom tweaking the quantification metric
* </li>
* <li>
* Synthesize scenario Latent State by parallel/custom shifting/custom tweaking the manifest measure
* </li>
* </ul>
*
* <br><br>
* <ul>
* <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ProductCore.md">Product Core Module</a></li>
* <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/FixedIncomeAnalyticsLibrary.md">Fixed Income Analytics</a></li>
* <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/state/README.md">Latent State Inference and Creation Utilities</a></li>
* <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/state/nonlinear/README.md">Nonlinear (i.e., Boot) Latent State Construction</a></li>
* </ul>
* <br><br>
*
* @author Lakshmi Krishnamurthy
*/
public class ForwardHazardCreditCurve extends org.drip.state.credit.ExplicitBootCreditCurve {
private int[] _aiHazardDate = null;
private int[] _aiRecoveryDate = null;
private double[] _adblHazardRate = null;
private double[] _adblRecoveryRate = null;
private org.drip.state.credit.CreditCurve createFromBaseMMTP (
final org.drip.param.definition.ManifestMeasureTweak mmtp)
{
double[] adblHazardBumped = org.drip.analytics.support.Helper.TweakManifestMeasure
(_adblHazardRate, mmtp);
if (null == adblHazardBumped || _adblHazardRate.length != adblHazardBumped.length) return null;
try {
return new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, adblHazardBumped,
_aiHazardDate, _adblRecoveryRate, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
return null;
}
/**
* Create a credit curve from hazard rate and recovery rate term structures
*
* @param iStartDate Curve Epoch date
* @param label Credit Curve Label
* @param strCurrency Currency
* @param adblHazardRate Matched array of hazard rates
* @param aiHazardDate Matched array of hazard dates
* @param adblRecoveryRate Matched array of recovery rates
* @param aiRecoveryDate Matched array of recovery dates
* @param iSpecificDefaultDate (Optional) Specific Default Date
*
* @throws java.lang.Exception Thrown if inputs are invalid
*/
public ForwardHazardCreditCurve (
final int iStartDate,
final org.drip.state.identifier.EntityCDSLabel label,
final java.lang.String strCurrency,
final double adblHazardRate[],
final int aiHazardDate[],
final double[] adblRecoveryRate,
final int[] aiRecoveryDate,
final int iSpecificDefaultDate)
throws java.lang.Exception
{
super (iStartDate, label, strCurrency);
if (null == adblHazardRate || 0 == adblHazardRate.length || null == aiHazardDate || 0 ==
aiHazardDate.length || adblHazardRate.length != aiHazardDate.length || null ==
adblRecoveryRate || 0 == adblRecoveryRate.length || null == aiRecoveryDate || 0 ==
aiRecoveryDate.length || adblRecoveryRate.length != aiRecoveryDate.length)
throw new java.lang.Exception ("ForwardHazardCreditCurve ctr: Invalid Params!");
_iSpecificDefaultDate = iSpecificDefaultDate;
_adblHazardRate = new double[adblHazardRate.length];
_adblRecoveryRate = new double[adblRecoveryRate.length];
_aiHazardDate = new int[aiHazardDate.length];
_aiRecoveryDate = new int[aiRecoveryDate.length];
for (int i = 0; i < adblHazardRate.length; ++i)
_adblHazardRate[i] = adblHazardRate[i];
for (int i = 0; i < _aiHazardDate.length; ++i)
_aiHazardDate[i] = aiHazardDate[i];
for (int i = 0; i < adblRecoveryRate.length; ++i)
_adblRecoveryRate[i] = adblRecoveryRate[i];
for (int i = 0; i < aiRecoveryDate.length; ++i)
_aiRecoveryDate[i] = aiRecoveryDate[i];
}
@Override public double survival (
final int iDate)
throws java.lang.Exception
{
if (iDate <= _iEpochDate) return 1.;
if (java.lang.Integer.MIN_VALUE != _iSpecificDefaultDate && iDate >= _iSpecificDefaultDate)
return 0.;
int i = 0;
double dblExpArg = 0.;
int iStartDate = _iEpochDate;
while (i < _adblHazardRate.length && iDate > _aiHazardDate[i]) {
dblExpArg -= _adblHazardRate[i] * (_aiHazardDate[i] - iStartDate);
iStartDate = _aiHazardDate[i++];
}
if (i >= _adblHazardRate.length) i = _adblHazardRate.length - 1;
dblExpArg -= _adblHazardRate[i] * (iDate - iStartDate);
return java.lang.Math.exp (dblExpArg / 365.25);
}
@Override public double recovery (
final int iDate)
throws java.lang.Exception
{
for (int i = 0; i < _aiRecoveryDate.length; ++i) {
if (iDate < _aiRecoveryDate[i]) return _adblRecoveryRate[i];
}
return _adblRecoveryRate[_aiRecoveryDate.length - 1];
}
@Override public ForwardHazardCreditCurve parallelShiftQuantificationMetric (
final double dblShift)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblShift)) return null;
double[] adblHazard = new double[_adblHazardRate.length];
for (int i = 0; i < _adblHazardRate.length; ++i)
adblHazard[i] = _adblHazardRate[i] + dblShift;
try {
return new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, adblHazard,
_aiHazardDate, _adblRecoveryRate, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
return null;
}
@Override public org.drip.analytics.definition.Curve customTweakQuantificationMetric (
final org.drip.param.definition.ManifestMeasureTweak rvtp)
{
return null;
}
@Override public ForwardHazardCreditCurve parallelShiftManifestMeasure (
final java.lang.String strManifestMeasure,
final double dblShift)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblShift)) return null;
if (null == _valParam || null == _aCalibInst || 0 == _aCalibInst.length || null == _adblCalibQuote ||
0 == _adblCalibQuote.length || null == _astrCalibMeasure || 0 == _astrCalibMeasure.length ||
_astrCalibMeasure.length != _adblCalibQuote.length || _adblCalibQuote.length !=
_aCalibInst.length)
return parallelShiftQuantificationMetric (dblShift);
ForwardHazardCreditCurve cc = null;
double[] adblCalibQuote = new double[_adblCalibQuote.length];
try {
cc = new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, _adblHazardRate,
_aiHazardDate, _adblRecoveryRate, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
for (int i = 0; i < _adblCalibQuote.length; ++i) {
try {
org.drip.state.nonlinear.NonlinearCurveBuilder.CreditCurve (_valParam, _aCalibInst[i],
adblCalibQuote[i] = _adblCalibQuote[i] + dblShift, _astrCalibMeasure[i], _bFlat, i, cc,
_dc, _gc, _pricerParam, _lsfc, _quotingParams, null);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
}
cc.setInstrCalibInputs (_valParam, _bFlat, _dc, _gc, _pricerParam, _aCalibInst, adblCalibQuote,
_astrCalibMeasure, _lsfc, _quotingParams);
return cc;
}
@Override public ForwardHazardCreditCurve shiftManifestMeasure (
final int iSpanIndex,
final java.lang.String strManifestMeasure,
final double dblShift)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblShift)) return null;
if (null == _valParam || null == _aCalibInst || 0 == _aCalibInst.length || null == _adblCalibQuote ||
0 == _adblCalibQuote.length || null == _astrCalibMeasure || 0 == _astrCalibMeasure.length ||
_astrCalibMeasure.length != _adblCalibQuote.length || _adblCalibQuote.length !=
_aCalibInst.length)
return parallelShiftQuantificationMetric (dblShift);
ForwardHazardCreditCurve cc = null;
double[] adblCalibQuote = new double[_adblCalibQuote.length];
if (iSpanIndex >= _adblCalibQuote.length) return null;
try {
cc = new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, _adblHazardRate,
_aiHazardDate, _adblRecoveryRate, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
for (int i = 0; i < _adblCalibQuote.length; ++i) {
try {
org.drip.state.nonlinear.NonlinearCurveBuilder.CreditCurve (_valParam, _aCalibInst[i],
adblCalibQuote[i] = _adblCalibQuote[i] + (i == iSpanIndex ? dblShift : 0.),
_astrCalibMeasure[i], _bFlat, i, cc, _dc, _gc, _pricerParam, _lsfc,
_quotingParams, null);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
}
cc.setInstrCalibInputs (_valParam, _bFlat, _dc, _gc, _pricerParam, _aCalibInst, adblCalibQuote,
_astrCalibMeasure, _lsfc, _quotingParams);
return cc;
}
@Override public org.drip.state.credit.CreditCurve flatCurve (
final double dblFlatNodeValue,
final boolean bSingleNode,
final double dblRecovery)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblFlatNodeValue) || 0. >= dblFlatNodeValue || null ==
_valParam || null == _aCalibInst || 0 == _aCalibInst.length || null == _adblCalibQuote || 0 ==
_adblCalibQuote.length || null == _astrCalibMeasure || 0 == _astrCalibMeasure.length ||
_astrCalibMeasure.length != _adblCalibQuote.length || _adblCalibQuote.length !=
_aCalibInst.length)
return null;
org.drip.state.credit.ExplicitBootCreditCurve cc = null;
try {
if (bSingleNode)
cc = org.drip.state.creator.ScenarioCreditCurveBuilder.Hazard (_iEpochDate,
_label.fullyQualifiedName(), _strCurrency, _adblHazardRate[0], _aiHazardDate[0],
!org.drip.numerical.common.NumberUtil.IsValid (dblRecovery) ? _adblRecoveryRate[0] :
dblRecovery);
else
cc = new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, _adblHazardRate,
_aiHazardDate, _adblRecoveryRate, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
for (int i = 0; i < _adblCalibQuote.length; ++i) {
try {
org.drip.state.nonlinear.NonlinearCurveBuilder.CreditCurve (_valParam, _aCalibInst[i],
dblFlatNodeValue, _astrCalibMeasure[i], true, i, cc, _dc, _gc, _pricerParam, _lsfc,
_quotingParams, null);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
}
if (bSingleNode)
cc.setInstrCalibInputs (_valParam, true, _dc, _gc, _pricerParam, new
org.drip.product.definition.CalibratableComponent[] {_aCalibInst[0]}, new double[]
{dblFlatNodeValue}, _astrCalibMeasure, _lsfc, _quotingParams);
else {
double[] adblCalibValue = new double[_adblCalibQuote.length];
for (int i = 0; i < _adblCalibQuote.length; ++i)
adblCalibValue[i] = dblFlatNodeValue;
cc.setInstrCalibInputs (_valParam, true, _dc, _gc, _pricerParam, _aCalibInst, adblCalibValue,
_astrCalibMeasure, _lsfc, _quotingParams);
}
return cc;
}
@Override public org.drip.state.credit.CreditCurve customTweakManifestMeasure (
final java.lang.String strManifestMeasure,
final org.drip.param.definition.ManifestMeasureTweak mmtp)
{
if (null == mmtp) return null;
if (!(mmtp instanceof org.drip.param.definition.CreditManifestMeasureTweak))
return createFromBaseMMTP (mmtp);
org.drip.param.definition.CreditManifestMeasureTweak cmmt =
(org.drip.param.definition.CreditManifestMeasureTweak) mmtp;
if (org.drip.param.definition.CreditManifestMeasureTweak.CREDIT_TWEAK_NODE_PARAM_RECOVERY.equalsIgnoreCase
(cmmt.paramType())) {
double[] adblRecoveryRateBumped = null;
if (null == (adblRecoveryRateBumped =
org.drip.analytics.support.Helper.TweakManifestMeasure (_adblRecoveryRate, cmmt)) ||
adblRecoveryRateBumped.length != _adblRecoveryRate.length)
return null;
try {
return new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency, _adblHazardRate,
_aiHazardDate, adblRecoveryRateBumped, _aiRecoveryDate, _iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
} else if
(org.drip.param.definition.CreditManifestMeasureTweak.CREDIT_TWEAK_NODE_PARAM_QUOTE.equalsIgnoreCase
(cmmt.paramType())) {
if (org.drip.param.definition.CreditManifestMeasureTweak.CREDIT_TWEAK_NODE_MEASURE_HAZARD.equalsIgnoreCase
(cmmt.measureType())) {
double[] adblHazardBumped = null;
if (null == (adblHazardBumped =
org.drip.analytics.support.Helper.TweakManifestMeasure (_adblHazardRate, cmmt))
|| adblHazardBumped.length != _adblHazardRate.length)
return null;
try {
return new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency,
adblHazardBumped, _aiHazardDate, _adblRecoveryRate, _aiRecoveryDate,
_iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
}
} else if
(org.drip.param.definition.CreditManifestMeasureTweak.CREDIT_TWEAK_NODE_MEASURE_QUOTE.equalsIgnoreCase
(cmmt.measureType())) {
double[] adblQuoteBumped = null;
if (null == (adblQuoteBumped =
org.drip.analytics.support.Helper.TweakManifestMeasure (_adblHazardRate, cmmt))
|| adblQuoteBumped.length != _adblHazardRate.length)
return null;
org.drip.state.credit.ExplicitBootCreditCurve cc = null;
try {
if (cmmt.singleNodeCalib())
cc = org.drip.state.creator.ScenarioCreditCurveBuilder.Hazard (_iEpochDate,
_strCurrency, _label.fullyQualifiedName(), _adblHazardRate[0],
_aiHazardDate[0], _adblRecoveryRate[0]);
else
cc = new ForwardHazardCreditCurve (_iEpochDate, _label, _strCurrency,
_adblHazardRate, _aiHazardDate, _adblRecoveryRate, _aiRecoveryDate,
_iSpecificDefaultDate);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
for (int i = 0; i < adblQuoteBumped.length; ++i) {
try {
org.drip.state.nonlinear.NonlinearCurveBuilder.CreditCurve (_valParam,
_aCalibInst[i], adblQuoteBumped[i], _astrCalibMeasure[i], _bFlat, i, cc, _dc,
_gc, _pricerParam, _lsfc, _quotingParams, null);
} catch (java.lang.Exception e) {
e.printStackTrace();
return null;
}
}
cc.setInstrCalibInputs (_valParam, _bFlat, _dc, _gc, _pricerParam, _aCalibInst,
adblQuoteBumped, _astrCalibMeasure, _lsfc, _quotingParams);
return cc;
}
}
return null;
}
@Override public boolean setNodeValue (
final int iNodeIndex,
final double dblValue)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblValue) || iNodeIndex > _adblHazardRate.length)
return false;
for (int i = iNodeIndex; i < _adblHazardRate.length; ++i)
_adblHazardRate[i] = dblValue;
return true;
}
@Override public boolean bumpNodeValue (
final int iNodeIndex,
final double dblValue)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblValue) || iNodeIndex > _adblHazardRate.length)
return false;
for (int i = iNodeIndex; i < _adblHazardRate.length; ++i)
_adblHazardRate[i] += dblValue;
return true;
}
@Override public boolean setFlatValue (
final double dblValue)
{
if (!org.drip.numerical.common.NumberUtil.IsValid (dblValue)) return false;
for (int i = 0; i < _adblHazardRate.length; ++i)
_adblHazardRate[i] = dblValue;
return true;
}
}