RegressionSplineCashCurve.java
- package org.drip.sample.bond;
- import java.util.*;
- import org.drip.analytics.cashflow.CompositePeriod;
- import org.drip.analytics.date.*;
- import org.drip.analytics.daycount.Convention;
- import org.drip.analytics.support.Helper;
- import org.drip.numerical.common.FormatUtil;
- import org.drip.param.creator.MarketParamsBuilder;
- import org.drip.param.market.CurveSurfaceQuoteContainer;
- import org.drip.param.valuation.ValuationParams;
- import org.drip.product.creator.BondBuilder;
- import org.drip.product.definition.Bond;
- import org.drip.service.env.EnvManager;
- import org.drip.spline.basis.PolynomialFunctionSetParams;
- import org.drip.spline.grid.OverlappingStretchSpan;
- import org.drip.spline.params.*;
- import org.drip.spline.stretch.*;
- import org.drip.state.curve.DiscountFactorDiscountCurve;
- import org.drip.state.discount.MergedDiscountForwardCurve;
- /*
- * -*- 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
- *
- * 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>RegressionSplineCashCurve</i> demonstrates the Functionality behind the Regression Spline based OLS
- * best-fit Construction of a Cash Bond Discount Curve Based on Input Price/Yield.
- *
- * <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/sample/README.md">DROP API Construction and Usage</a></li>
- * <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/sample/bond/README.md">Bullet, EOS Bond Metrics + Curve</a></li>
- * </ul>
- * <br><br>
- *
- * @author Lakshmi Krishnamurthy
- */
- public class RegressionSplineCashCurve {
- static class CashFlowYieldDF {
- double _dblCumulativeCashFlow = java.lang.Double.NaN;
- double _dblDiscountedCumulativeCashFlow = java.lang.Double.NaN;
- CashFlowYieldDF (
- final double dblCashFlow,
- final double dblYieldDF)
- {
- _dblDiscountedCumulativeCashFlow = (_dblCumulativeCashFlow = dblCashFlow) * dblYieldDF;
- }
- void accumulate (
- final double dblCashFlow,
- final double dblYieldDF)
- {
- _dblCumulativeCashFlow += dblCashFlow;
- _dblDiscountedCumulativeCashFlow += dblCashFlow * dblYieldDF;
- }
- double cumulativeCashFlow()
- {
- return _dblCumulativeCashFlow;
- }
- double discountedCumulativeCashFlow()
- {
- return _dblDiscountedCumulativeCashFlow;
- }
- double weightedDF()
- {
- return _dblDiscountedCumulativeCashFlow / _dblCumulativeCashFlow;
- }
- }
- private static final SegmentCustomBuilderControl PolynomialSplineSegmentBuilder()
- throws Exception
- {
- int iCk = 2;
- int iNumPolyBasis = 4;
- SegmentInelasticDesignControl sdic = new SegmentInelasticDesignControl (
- iCk,
- null, // SegmentFlexurePenaltyControl (iLengthPenaltyDerivativeOrder, dblLengthPenaltyAmplitude)
- null // SegmentFlexurePenaltyControl (iCurvaturePenaltyDerivativeOrder, dblCurvaturePenaltyAmplitude)
- );
- return new SegmentCustomBuilderControl (
- MultiSegmentSequenceBuilder.BASIS_SPLINE_POLYNOMIAL,
- new PolynomialFunctionSetParams (iNumPolyBasis),
- sdic,
- null,
- null
- );
- }
- private static final Bond FixedCouponBond (
- final String strName,
- final JulianDate dtEffective,
- final JulianDate dtMaturity,
- final double dblCoupon,
- final String strCurrency,
- final String strDayCount,
- final int iFreq)
- throws Exception
- {
- return BondBuilder.CreateSimpleFixed (
- strName,
- strCurrency,
- "",
- dblCoupon,
- iFreq,
- strDayCount,
- dtEffective,
- dtMaturity,
- null,
- null
- );
- }
- private static final Bond[] CalibBondSet (
- final String strCurrency,
- final String strDayCount)
- throws Exception
- {
- Bond bond1 = FixedCouponBond (
- "MBONO 8.00 12/17/2015",
- DateUtil.CreateFromYMD (
- 2006,
- DateUtil.JANUARY,
- 5
- ),
- DateUtil.CreateFromYMD (
- 2015,
- DateUtil.DECEMBER,
- 17
- ),
- 0.08,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond2 = FixedCouponBond (
- "MBONO 6.25 06/16/2016",
- DateUtil.CreateFromYMD (
- 2011,
- DateUtil.JULY,
- 22
- ),
- DateUtil.CreateFromYMD (
- 2016,
- DateUtil.JUNE,
- 16
- ),
- 0.08,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond3 = FixedCouponBond (
- "MBONO 7.25 12/15/2016",
- DateUtil.CreateFromYMD (
- 2007,
- DateUtil.FEBRUARY,
- 1
- ),
- DateUtil.CreateFromYMD (
- 2016,
- DateUtil.DECEMBER,
- 15
- ),
- 0.0725,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond4 = FixedCouponBond (
- "MBONO 5.00 06/15/2017",
- DateUtil.CreateFromYMD (
- 2012,
- DateUtil.JULY,
- 19
- ),
- DateUtil.CreateFromYMD (
- 2017,
- DateUtil.JUNE,
- 15
- ),
- 0.0500,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond5 = FixedCouponBond (
- "MBONO 7.75 12/14/2017",
- DateUtil.CreateFromYMD (
- 2008,
- DateUtil.JANUARY,
- 31
- ),
- DateUtil.CreateFromYMD (
- 2017,
- DateUtil.DECEMBER,
- 14
- ),
- 0.0775,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond6 = FixedCouponBond (
- "MBONO 4.75 06/14/2018",
- DateUtil.CreateFromYMD (
- 2013,
- DateUtil.AUGUST,
- 30
- ),
- DateUtil.CreateFromYMD (
- 2018,
- DateUtil.JUNE,
- 14
- ),
- 0.0475,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond7 = FixedCouponBond (
- "MBONO 8.50 12/13/2018",
- DateUtil.CreateFromYMD (
- 2009,
- DateUtil.FEBRUARY,
- 12
- ),
- DateUtil.CreateFromYMD (
- 2018,
- DateUtil.DECEMBER,
- 13
- ),
- 0.085,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond8 = FixedCouponBond (
- "MBONO 5.00 12/11/2019",
- DateUtil.CreateFromYMD (
- 2014,
- DateUtil.NOVEMBER,
- 7
- ),
- DateUtil.CreateFromYMD (
- 2019,
- DateUtil.DECEMBER,
- 11
- ),
- 0.05,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond9 = FixedCouponBond (
- "MBONO 8.00 06/11/2020",
- DateUtil.CreateFromYMD (
- 2010,
- DateUtil.FEBRUARY,
- 25
- ),
- DateUtil.CreateFromYMD (
- 2020,
- DateUtil.JUNE,
- 11
- ),
- 0.08,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond10 = FixedCouponBond (
- "MBONO 6.50 06/10/2021",
- DateUtil.CreateFromYMD (
- 2011,
- DateUtil.FEBRUARY,
- 3
- ),
- DateUtil.CreateFromYMD (
- 2021,
- DateUtil.JUNE,
- 10
- ),
- 0.065,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond11 = FixedCouponBond (
- "MBONO 6.50 06/09/2022",
- DateUtil.CreateFromYMD (
- 2012,
- DateUtil.FEBRUARY,
- 15
- ),
- DateUtil.CreateFromYMD (
- 2022,
- DateUtil.JUNE,
- 9
- ),
- 0.065,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond12 = FixedCouponBond (
- "MBONO 8.00 12/07/2023",
- DateUtil.CreateFromYMD (
- 2003,
- DateUtil.OCTOBER,
- 30
- ),
- DateUtil.CreateFromYMD (
- 2023,
- DateUtil.DECEMBER,
- 7
- ),
- 0.065,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond13 = FixedCouponBond (
- "MBONO 10.00 12/05/2024",
- DateUtil.CreateFromYMD (
- 2005,
- DateUtil.JANUARY,
- 20
- ),
- DateUtil.CreateFromYMD (
- 2024,
- DateUtil.DECEMBER,
- 5
- ),
- 0.1,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond14 = FixedCouponBond (
- "MBONO 7.50 06/03/2027",
- DateUtil.CreateFromYMD (
- 2007,
- DateUtil.JANUARY,
- 18
- ),
- DateUtil.CreateFromYMD (
- 2027,
- DateUtil.JUNE,
- 3
- ),
- 0.075,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond15 = FixedCouponBond (
- "MBONO 8.50 05/31/2029",
- DateUtil.CreateFromYMD (
- 2009,
- DateUtil.JANUARY,
- 15
- ),
- DateUtil.CreateFromYMD (
- 2029,
- DateUtil.MAY,
- 31
- ),
- 0.085,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond16 = FixedCouponBond (
- "MBONO 7.75 05/29/2031",
- DateUtil.CreateFromYMD (
- 2009,
- DateUtil.SEPTEMBER,
- 11
- ),
- DateUtil.CreateFromYMD (
- 2031,
- DateUtil.MAY,
- 29
- ),
- 0.0775,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond17 = FixedCouponBond (
- "MBONO 7.75 11/23/2034",
- DateUtil.CreateFromYMD (
- 2014,
- DateUtil.APRIL,
- 11
- ),
- DateUtil.CreateFromYMD (
- 2034,
- DateUtil.NOVEMBER,
- 23
- ),
- 0.0775,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond18 = FixedCouponBond (
- "MBONO 10.00 11/20/2036",
- DateUtil.CreateFromYMD (
- 2006,
- DateUtil.OCTOBER,
- 26
- ),
- DateUtil.CreateFromYMD (
- 2036,
- DateUtil.NOVEMBER,
- 20
- ),
- 0.1,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond19 = FixedCouponBond (
- "MBONO 8.50 11/18/2038",
- DateUtil.CreateFromYMD (
- 2009,
- DateUtil.JANUARY,
- 29
- ),
- DateUtil.CreateFromYMD (
- 2038,
- DateUtil.NOVEMBER,
- 18
- ),
- 0.085,
- strCurrency,
- strDayCount,
- 2
- );
- Bond bond20 = FixedCouponBond (
- "MBONO 7.75 11/13/2042",
- DateUtil.CreateFromYMD (
- 2012,
- DateUtil.APRIL,
- 20
- ),
- DateUtil.CreateFromYMD (
- 2042,
- DateUtil.NOVEMBER,
- 13
- ),
- 0.0775,
- strCurrency,
- strDayCount,
- 2
- );
- return new Bond[] {
- bond1,
- bond2,
- bond3,
- bond4,
- bond5,
- bond6,
- bond7,
- bond8,
- bond9,
- bond10,
- bond11,
- bond12,
- bond13,
- bond14,
- bond15,
- bond16,
- bond17,
- bond18,
- bond19,
- bond20
- };
- }
- private static final Map<JulianDate, CashFlowYieldDF> BondYieldFlows (
- final Bond[] aBond,
- final double[] adblYield,
- final int iValueDate)
- throws Exception
- {
- Map<JulianDate, CashFlowYieldDF> mapDateYieldDF = new TreeMap<JulianDate, CashFlowYieldDF>();
- ValuationParams valParams = new ValuationParams (
- new JulianDate (iValueDate),
- new JulianDate (iValueDate),
- ""
- );
- for (int i = 0; i < aBond.length; ++i) {
- for (CompositePeriod cp : aBond[i].couponPeriods()) {
- if (cp.payDate() <= iValueDate) continue;
- double dblCashFlow = aBond[i].couponMetrics (
- cp.endDate(),
- valParams,
- null
- ).rate() / aBond[i].freq();
- double dblYieldDF = Helper.Yield2DF (
- aBond[i].freq(),
- adblYield[i],
- Convention.YearFraction (
- iValueDate,
- cp.payDate(),
- aBond[i].couponDC(),
- false,
- null,
- aBond[i].currency()
- )
- );
- JulianDate dtPay = new JulianDate (cp.payDate());
- if (mapDateYieldDF.containsKey (dtPay))
- mapDateYieldDF.get (dtPay).accumulate (
- dblCashFlow,
- dblYieldDF
- );
- else
- mapDateYieldDF.put (
- dtPay,
- new CashFlowYieldDF (
- dblCashFlow,
- dblYieldDF
- )
- );
- }
- JulianDate dtMaturity = aBond[i].maturityDate();
- double dblYieldDF = Helper.Yield2DF (
- aBond[i].freq(),
- adblYield[i],
- Convention.YearFraction (
- iValueDate,
- dtMaturity.julian(),
- aBond[i].couponDC(),
- false,
- null,
- aBond[i].currency()
- )
- );
- if (mapDateYieldDF.containsKey (dtMaturity))
- mapDateYieldDF.get (dtMaturity).accumulate (
- 1.,
- dblYieldDF
- );
- else
- mapDateYieldDF.put (
- dtMaturity,
- new CashFlowYieldDF (
- 1.,
- dblYieldDF
- )
- );
- }
- return mapDateYieldDF;
- }
- private static final StretchBestFitResponse SBFR (
- final Map<JulianDate, CashFlowYieldDF> mapDateYieldDF)
- throws Exception
- {
- int iMapSize = mapDateYieldDF.size();
- int i = 0;
- int[] aiDate = new int[iMapSize];
- double[] adblYieldDF = new double[iMapSize];
- double[] adblWeight = new double[iMapSize];
- for (Map.Entry<JulianDate, CashFlowYieldDF> me : mapDateYieldDF.entrySet()) {
- aiDate[i] = me.getKey().julian();
- adblYieldDF[i] = me.getValue().weightedDF();
- adblWeight[i] = me.getValue().cumulativeCashFlow();
- ++i;
- }
- return StretchBestFitResponse.Create (
- aiDate,
- adblYieldDF,
- adblWeight
- );
- }
- private static final MultiSegmentSequence BondRegressionSplineStretch (
- final JulianDate dtSpot,
- final Bond[] aBondSet,
- final int iNumKnots,
- final Map<JulianDate, CashFlowYieldDF> mapDateDF)
- throws Exception
- {
- SegmentCustomBuilderControl scbc = PolynomialSplineSegmentBuilder();
- double dblXStart = dtSpot.julian();
- double dblXFinish = aBondSet[aBondSet.length - 1].maturityDate().julian();
- double adblX[] = new double[iNumKnots + 2];
- adblX[0] = dblXStart;
- for (int i = 1; i < adblX.length; ++i)
- adblX[i] = adblX[i - 1] + (dblXFinish - dblXStart) / (iNumKnots + 1);
- SegmentCustomBuilderControl[] aSCBC = new SegmentCustomBuilderControl[adblX.length - 1];
- for (int i = 0; i < adblX.length - 1; ++i)
- aSCBC[i] = scbc;
- return MultiSegmentSequenceBuilder.CreateCalibratedStretchEstimator (
- "SPLINE_STRETCH",
- adblX,
- 1.,
- null,
- aSCBC,
- SBFR (mapDateDF),
- BoundarySettings.NaturalStandard(),
- MultiSegmentSequence.CALIBRATE
- );
- }
- public static final void main (
- final String[] astrArgs)
- throws Exception
- {
- EnvManager.InitEnv (
- "",
- true
- );
- int iNumKnots = 10;
- String strCurrency = "MXN";
- String strDayCount = "30/360";
- JulianDate dtSpot = DateUtil.CreateFromYMD (
- 2015,
- DateUtil.JUNE,
- 13
- );
- double[] aCalibYield = new double[] {
- 0.0315960,
- 0.0354184,
- 0.0389543,
- 0.0412860,
- 0.0435245,
- 0.0464521,
- 0.0486307,
- 0.0524561,
- 0.0532168,
- 0.0562230,
- 0.0585227,
- 0.0606205,
- 0.0611038,
- 0.0637935,
- 0.0648727,
- 0.0661705,
- 0.0673744,
- 0.0675774,
- 0.0683684,
- 0.0684978
- };
- Bond[] aBondSet = CalibBondSet (
- strCurrency,
- strDayCount
- );
- Map<JulianDate, CashFlowYieldDF> mapDateDF = BondYieldFlows (
- aBondSet,
- aCalibYield,
- dtSpot.julian()
- );
- MultiSegmentSequence mss = BondRegressionSplineStretch (
- dtSpot,
- aBondSet,
- iNumKnots,
- mapDateDF
- );
- MergedDiscountForwardCurve dfdc = new DiscountFactorDiscountCurve (
- strCurrency,
- new OverlappingStretchSpan (mss)
- );
- System.out.println ("\n\n\t|--------------------------------------------|");
- System.out.println ("\t| Curve Stretch [" +
- new JulianDate ((int) mss.getLeftPredictorOrdinateEdge()) + " -> " +
- new JulianDate ((int) mss.getRightPredictorOrdinateEdge()) + "] |"
- );
- System.out.println ("\t|--------------------------------------------|");
- for (Map.Entry<JulianDate, CashFlowYieldDF> me : mapDateDF.entrySet()) {
- System.out.println (
- "\t|\t " + me.getKey() + " => " +
- FormatUtil.FormatDouble (me.getValue().weightedDF(), 1, 4, 1.) + " | " +
- FormatUtil.FormatDouble (dfdc.df (me.getKey().julian()), 1, 4, 1.) + " |"
- );
- }
- System.out.println ("\t|--------------------------------------------|\n\n");
- System.out.println ("\t|---------------------------------------------------------------||");
- System.out.println ("\t| Market Yield vs. Regression Curve ||");
- System.out.println ("\t|---------------------------------------------------------------||");
- System.out.println ("\t| L -> R ||");
- System.out.println ("\t| Bond Name ||");
- System.out.println ("\t| Market Yield ||");
- System.out.println ("\t| Regressed Yield (Bond Basis) ||");
- System.out.println ("\t| Regressed Yield (Yield Spread) ||");
- System.out.println ("\t| Continuous Zero To Maturity ||");
- System.out.println ("\t|---------------------------------------------------------------||");
- ValuationParams valParams = new ValuationParams (
- dtSpot,
- dtSpot,
- ""
- );
- CurveSurfaceQuoteContainer mktParams = MarketParamsBuilder.Discount (dfdc);
- for (int i = 0; i < aBondSet.length; ++i) {
- System.out.println (
- "\t| " + aBondSet[i].name() + " ==> " +
- FormatUtil.FormatDouble (aCalibYield[i], 1, 2, 100.) + "% | " +
- FormatUtil.FormatDouble (aBondSet[i].yieldFromBondBasis (
- valParams,
- mktParams,
- null,
- 0.
- ), 1, 2, 100.) + "% | " +
- FormatUtil.FormatDouble (aBondSet[i].yieldFromYieldSpread (
- valParams,
- mktParams,
- null,
- 0.
- ), 1, 2, 100.) + "% | " +
- FormatUtil.FormatDouble (dfdc.zero (
- aBondSet[i].maturityDate().julian()
- ), 1, 2, 100.) + "% || "
- );
- }
- System.out.println ("\t|---------------------------------------------------------------||\n\n");
- EnvManager.TerminateEnv();
- }
- }