CustomDiscountCurveBuilder.java
-
- package org.drip.sample.stretch;
- /*
- * Java Imports
- */
- import java.util.*;
- import org.drip.function.r1tor1.QuadraticRationalShapeControl;
- import org.drip.numerical.common.FormatUtil;
- import org.drip.spline.basis.*;
- import org.drip.spline.params.*;
- import org.drip.spline.stretch.*;
- /*
- * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
- */
- /*!
- * 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
- *
- * This file is part of DRIP, a free-software/open-source library for buy/side financial/trading model
- * libraries targeting analysts and developers
- * https://lakshmidrip.github.io/DRIP/
- *
- * DRIP is composed of four main libraries:
- *
- * - DRIP Fixed Income - https://lakshmidrip.github.io/DRIP-Fixed-Income/
- * - DRIP Asset Allocation - https://lakshmidrip.github.io/DRIP-Asset-Allocation/
- * - DRIP Numerical Optimizer - https://lakshmidrip.github.io/DRIP-Numerical-Optimizer/
- * - DRIP Statistical Learning - https://lakshmidrip.github.io/DRIP-Statistical-Learning/
- *
- * - DRIP Fixed Income: Library for Instrument/Trading Conventions, Treasury Futures/Options,
- * Funding/Forward/Overnight Curves, Multi-Curve Construction/Valuation, Collateral Valuation and XVA
- * Metric Generation, Calibration and Hedge Attributions, Statistical Curve Construction, Bond RV
- * Metrics, Stochastic Evolution and Option Pricing, Interest Rate Dynamics and Option Pricing, LMM
- * Extensions/Calibrations/Greeks, Algorithmic Differentiation, and Asset Backed Models and Analytics.
- *
- * - DRIP Asset Allocation: Library for model libraries for MPT framework, Black Litterman Strategy
- * Incorporator, Holdings Constraint, and Transaction Costs.
- *
- * - DRIP Numerical Optimizer: Library for Numerical Optimization and Spline Functionality.
- *
- * - DRIP Statistical Learning: Library for Statistical Evaluation and Machine Learning.
- *
- * 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.
- */
- /**
- * CustomDiscountCurveBuilder contains samples that demo how to build a discount curve from purely the cash
- * flows. It provides for elaborate curve builder control, both at the segment level and at the Stretch
- * level. In particular, it shows the following:
- * - Construct a discount curve from the discount factors available purely from the cash and the euro-dollar
- * instruments.
- * - Construct a discount curve from the cash flows available from the swap instruments.
- *
- * In addition, the sample demonstrates the following ways of controlling curve construction:
- * - Control over the type of segment basis spline
- * - Control over the polynomial basis spline order, Ck, and tension parameters
- * - Provision of custom shape controllers (in this case rational shape controller)
- * - Calculation of segment monotonicity and convexity
- *
- * @author Lakshmi Krishnamurthy
- */
- public class CustomDiscountCurveBuilder {
- /*
- * Sample API demonstrating the creation of the segment builder parameters based on Koch-Lyche-Kvasov tension spline.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final SegmentCustomBuilderControl MakeKLKTensionSCBC (
- final double dblTension)
- throws Exception
- {
- return new SegmentCustomBuilderControl (
- MultiSegmentSequenceBuilder.BASIS_SPLINE_KLK_HYPERBOLIC_TENSION, // Spline Type KLK Hyperbolic Basis Tension
- new ExponentialTensionSetParams (dblTension), // Segment Tension Parameter Value
- SegmentInelasticDesignControl.Create (2, 2), // Ck = 2; Curvature penalty (if necessary) order: 2
- new ResponseScalingShapeControl (
- true,
- new QuadraticRationalShapeControl (0.0)), // Univariate Rational Shape Controller
- null
- );
- }
- /*
- * Sample API demonstrating the creation of the segment builder parameters based on polynomial spline.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- public static final SegmentCustomBuilderControl MakePolynomialSBP (
- final int iNumDegree)
- throws Exception
- {
- return new SegmentCustomBuilderControl (
- MultiSegmentSequenceBuilder.BASIS_SPLINE_POLYNOMIAL, // Spline Type Polynomial
- new PolynomialFunctionSetParams (iNumDegree + 1), // Polynomial of degree (i.e, cubic would be 3+1; 4 basis functions - 1 "intercept")
- SegmentInelasticDesignControl.Create (2, 2), // Ck = 2; Curvature penalty (if necessary) order: 2
- new ResponseScalingShapeControl (
- true,
- new QuadraticRationalShapeControl (0.0)), // Univariate Rational Shape Controller
- null
- );
- }
- /*
- * Sample API demonstrating the creation of the segment builder parameters
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final SegmentCustomBuilderControl MakeSCBC (
- final String strBasisSpline)
- throws Exception
- {
- if (strBasisSpline.equalsIgnoreCase (MultiSegmentSequenceBuilder.BASIS_SPLINE_POLYNOMIAL)) // Polynomial Basis Spline
- return new SegmentCustomBuilderControl (
- MultiSegmentSequenceBuilder.BASIS_SPLINE_POLYNOMIAL, // Spline Type Polynomial
- new PolynomialFunctionSetParams (4), // Polynomial of order 3 (i.e, cubic - 4 basis functions - 1 "intercept")
- SegmentInelasticDesignControl.Create (2, 2), // Ck = 2; Curvature penalty (if necessary) order: 2
- new ResponseScalingShapeControl (
- true,
- new QuadraticRationalShapeControl (0.0)), // Univariate Rational Shape Controller
- null
- );
- if (strBasisSpline.equalsIgnoreCase (MultiSegmentSequenceBuilder.BASIS_SPLINE_EXPONENTIAL_TENSION)) // Exponential Tension Basis Spline
- return new SegmentCustomBuilderControl (
- MultiSegmentSequenceBuilder.BASIS_SPLINE_EXPONENTIAL_TENSION, // Spline Type Exponential Basis Tension
- new ExponentialTensionSetParams (1.), // Segment Tension Parameter Value = 1.
- SegmentInelasticDesignControl.Create (2, 2), // Ck = 2; Curvature penalty (if necessary) order: 2
- new ResponseScalingShapeControl (
- true,
- new QuadraticRationalShapeControl (0.0)), // Univariate Rational Shape Controller
- null
- );
- return null;
- }
- /*
- * Generate the sample Swap Cash Flows to a given maturity, for the frequency/coupon.
- * Cash Flow is in the form of <Date, Cash Amount> Map.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final TreeMap<Double, Double> SwapCashFlow (
- final double dblCoupon,
- final int iFreq,
- final double dblTenorInYears)
- {
- TreeMap<Double, Double> mapCF = new TreeMap<Double, Double>();
- for (double dblCFDate = 1. / iFreq; dblCFDate < dblTenorInYears; dblCFDate += 1. / iFreq)
- mapCF.put (
- dblCFDate,
- dblCoupon / iFreq
- );
- mapCF.put (
- 0.,
- -1.
- );
- mapCF.put (
- 1. * dblTenorInYears,
- 1. + dblCoupon / iFreq
- );
- return mapCF;
- }
- /**
- * Generate the DRIP linear constraint corresponding to an exclusive swap segment. This constraint is
- * used to calibrate the discount curve in this segment.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final SegmentResponseValueConstraint GenerateSegmentConstraint (
- final TreeMap<Double, Double> mapCF,
- final MultiSegmentSequence mssDF)
- throws Exception
- {
- double dblValue = 0.;
- List<Double> lsTime = new ArrayList<Double>();
- List<Double> lsWeight = new ArrayList<Double>();
- for (Map.Entry<Double, Double> me : mapCF.entrySet()) {
- double dblTime = me.getKey();
- if (null != mssDF && mssDF.in (dblTime))
- dblValue += mssDF.responseValue (dblTime) * me.getValue();
- else {
- lsTime.add (me.getKey());
- lsWeight.add (me.getValue());
- }
- }
- int iSize = lsTime.size();
- double[] adblNode = new double[iSize];
- double[] adblNodeWeight = new double[iSize];
- for (int i = 0; i < iSize; ++i) {
- adblNode[i] = lsTime.get (i);
- adblNodeWeight[i] = lsWeight.get (i);
- }
- return new SegmentResponseValueConstraint (
- adblNode,
- adblNodeWeight,
- -dblValue
- );
- }
- /**
- * The set of Par Swap Quotes.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final Map<Double, Double> SwapQuotes()
- {
- Map<Double, Double> mapSwapQuotes = new TreeMap<Double, Double>();
- mapSwapQuotes.put (4., 0.0166);
- mapSwapQuotes.put (5., 0.0206);
- mapSwapQuotes.put (6., 0.0241);
- mapSwapQuotes.put (7., 0.0269);
- mapSwapQuotes.put (8., 0.0292);
- mapSwapQuotes.put (9., 0.0311);
- mapSwapQuotes.put (10., 0.0326);
- mapSwapQuotes.put (11., 0.0340);
- mapSwapQuotes.put (12., 0.0351);
- mapSwapQuotes.put (15., 0.0375);
- mapSwapQuotes.put (20., 0.0393);
- mapSwapQuotes.put (25., 0.0402);
- mapSwapQuotes.put (30., 0.0407);
- mapSwapQuotes.put (40., 0.0409);
- mapSwapQuotes.put (50., 0.0409);
- return mapSwapQuotes;
- }
- /**
- * Sample Function illustrating the construction of the discount curve off of swap cash flows and
- * detailed segment level controls for the swap instruments.Further, the Segment Builder Parameters
- * for the cash/swap bridging stretch shown here illustrate using an exponential/hyperbolic spline with
- * very high tension (100000.) to "stitch" the cash stretch with the swaps Stretch.
- *
- * Each of the respective stretches have their own tension settings, so the "high" tension
- * ensures that there is no propagation of derivatives and therefore high locality.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final MultiSegmentSequence BuildSwapCurve (
- MultiSegmentSequence mss,
- final BoundarySettings bs,
- final int iCalibrationDetail)
- throws Exception
- {
- boolean bFirstNode = true;
- /*
- * Iterate through the swap instruments and their quotes.
- */
- for (Map.Entry<Double, Double> meSwapQuote : SwapQuotes().entrySet()) {
- double dblTenorInYears = meSwapQuote.getKey(); // Swap Maturity in Years
- double dblQuote = meSwapQuote.getValue(); // Par Swap Quote
- /*
- * Generate the Cash flow for the swap Instrument
- */
- TreeMap<Double, Double> mapCF = SwapCashFlow (
- dblQuote,
- 2,
- dblTenorInYears
- );
- /*
- * Convert the Cash flow into a DRIP segment constraint using the "prior" curve stretch
- */
- SegmentResponseValueConstraint srvc = GenerateSegmentConstraint (
- mapCF,
- mss
- );
- /*
- * If it is the head segment, create a stretch instance for the discount curve.
- */
- if (null == mss) {
- /*
- * Set the Segment Builder Parameters. This may be set on a segment-by-segment basis.
- */
- SegmentCustomBuilderControl scbc = MakeSCBC (MultiSegmentSequenceBuilder.BASIS_SPLINE_EXPONENTIAL_TENSION);
- /*
- * Start off with a single segment stretch, with the corresponding Builder Parameters
- */
- mss = MultiSegmentSequenceBuilder.CreateUncalibratedStretchEstimator (
- "SWAP",
- new double[] {0., dblTenorInYears},
- new SegmentCustomBuilderControl[] {scbc}
- );
- /*
- * Set the stretch up by carrying out a "Natural Boundary" Spline Calibration
- */
- mss.setup (
- 1.,
- new SegmentResponseValueConstraint[] {srvc},
- null,
- bs,
- iCalibrationDetail
- );
- } else {
- /*
- * The Segment Builder Parameters shown here illustrate using an exponential/hyperbolic
- * spline with high tension (15.) to "stitch" the cash stretch with the swaps stretch.
- *
- * Each of the respective stretches have their own tension settings, so the "high" tension
- * ensures that there is no propagation of derivatives and therefore high locality.
- */
- SegmentCustomBuilderControl scbcLocal = null;
- if (bFirstNode) {
- bFirstNode = false;
- scbcLocal = MakeKLKTensionSCBC (1.);
- } else
- scbcLocal = MakeKLKTensionSCBC (1.);
- /*
- * If not the head segment, just append the exclusive swap instrument segment to the tail of
- * the current stretch state, using the constraint generated from the swap cash flow.
- */
- mss = org.drip.spline.stretch.MultiSegmentSequenceModifier.AppendSegment (
- mss,
- dblTenorInYears,
- srvc,
- scbcLocal,
- bs,
- iCalibrationDetail
- );
- }
- }
- return mss;
- }
- /**
- * The set of Cash Discount Factors.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final Map<Double, Double> CashDFQuotes()
- {
- Map<Double, Double> mapDFCashQuotes = new TreeMap<Double, Double>();
- mapDFCashQuotes.put (0.005556, 0.999991);
- mapDFCashQuotes.put (0.019444, 0.999967);
- mapDFCashQuotes.put (0.038889, 0.999931);
- mapDFCashQuotes.put (0.083333, 0.999836);
- mapDFCashQuotes.put (0.166667, 0.999622);
- mapDFCashQuotes.put (0.250000, 0.999360);
- mapDFCashQuotes.put (0.500000, 0.998686);
- mapDFCashQuotes.put (0.750000, 0.997888);
- mapDFCashQuotes.put (1.000000, 0.996866);
- mapDFCashQuotes.put (1.250000, 0.995522);
- mapDFCashQuotes.put (1.500000, 0.993609);
- mapDFCashQuotes.put (1.750000, 0.991033);
- mapDFCashQuotes.put (2.000000, 0.987724);
- mapDFCashQuotes.put (2.250000, 0.983789);
- return mapDFCashQuotes;
- }
- /**
- * Sample Function illustrating the construction of the discount curve off of discount factors and
- * detailed segment level controls for the cash instruments.
- *
- * USE WITH CARE: This sample ignores errors and does not handle exceptions.
- */
- private static final MultiSegmentSequence BuildCashCurve (
- final org.drip.spline.stretch.BoundarySettings bs,
- final int iCalibrationDetail)
- throws Exception
- {
- /*
- * For the head segment, create a calibrated stretch instance for the discount curve.
- */
- MultiSegmentSequence mssCash = MultiSegmentSequenceBuilder.CreateCalibratedStretchEstimator (
- "CASH",
- new double[] {0., 0.002778}, // t0 and t1 for the segment
- new double[] {1., 0.999996}, // the corresponding discount factors
- new SegmentCustomBuilderControl[] {
- // MakeSCBC (MultiSegmentSequenceBuilder.BASIS_SPLINE_EXPONENTIAL_TENSION)
- MakeKLKTensionSCBC (1.)
- }, // Exponential Tension Basis Spline
- null,
- bs,
- iCalibrationDetail // "Natural" Spline Boundary Condition + Calibrate the full stretch
- );
- /*
- * Construct the discount curve by iterating through the cash instruments and their discount
- * factors, and inserting them as "knots" onto the existing stretch.
- */
- for (Map.Entry<Double, Double> meCashDFQuote : CashDFQuotes().entrySet()) {
- double dblTenorInYears = meCashDFQuote.getKey(); // Instrument Tenor in Years
- double dblDF = meCashDFQuote.getValue(); // Discount Factor
- /*
- * Insert the instrument/quote as a "knot" entity into the stretch. Given the "natural" spline
- */
- mssCash = MultiSegmentSequenceModifier.InsertKnot (
- mssCash,
- dblTenorInYears,
- dblDF,
- bs,
- iCalibrationDetail
- );
- }
- return mssCash;
- }
- /*
- * This sample demonstrates the usage construction and usage of Custom Curve Building. It shows the following:
- * - Construct the Cash Curve Sequence with the Standard Natural Boundary Condition.
- * - Construct the Cash Curve Sequence with the Standard Financial Boundary Condition.
- * - Construct the Cash Curve Sequence with the Standard Not-A-Knot Boundary Condition.
- * - Display the DF and the monotonicity for the cash instruments.
- * - Construct the Swap Curve Sequence with the Standard Natural Boundary Condition.
- * - Construct the Swap Curve Sequence with the Standard Financial Boundary Condition.
- * - Construct the Swap Curve Sequence with the Standard Not-A-Knot Boundary Condition.
- * - Display the DF and the monotonicity for the swap instruments.
- */
- private static final void CustomCurveBuilderTest()
- throws Exception
- {
- /*
- * Construct the Cash Curve Sequence with the Standard Natural Boundary Condition
- */
- MultiSegmentSequence mssNaturalCash = BuildCashCurve (
- BoundarySettings.NaturalStandard(),
- MultiSegmentSequence.CALIBRATE
- );
- /*
- * Construct the Cash Curve Sequence with the Standard Financial Boundary Condition
- */
- MultiSegmentSequence mssFinancialCash = BuildCashCurve (
- BoundarySettings.FinancialStandard(),
- MultiSegmentSequence.CALIBRATE
- );
- /*
- * Construct the Cash Curve Sequence with the Standard Not-A-Knot Boundary Condition
- */
- MultiSegmentSequence mssNotAKnotCash = BuildCashCurve (
- BoundarySettings.NotAKnotStandard (1, 1),
- MultiSegmentSequence.CALIBRATE
- );
- double dblXShift = 0.1 * (mssNaturalCash.getRightPredictorOrdinateEdge() - mssNaturalCash.getLeftPredictorOrdinateEdge());
- System.out.println ("\n\t\t\t---------------- <====> ------------------ <====> ------------------");
- System.out.println ("\t\t\tNATURAL BOUNDARY <====> NOT A KNOT BOUNDARY <====> FINANCIAL BOUNDARY");
- System.out.println ("\t\t\t---------------- <====> ------------------ <====> ------------------\n");
- /*
- * Display the DF and the monotonicity for the cash instruments.
- */
- for (double dblX = mssNaturalCash.getLeftPredictorOrdinateEdge(); dblX <= mssNaturalCash.getRightPredictorOrdinateEdge(); dblX = dblX + dblXShift)
- System.out.println ("Cash DF[" +
- FormatUtil.FormatDouble (dblX, 1, 3, 1.) + "Y] => " +
- FormatUtil.FormatDouble (mssNaturalCash.responseValue (dblX), 1, 6, 1.) + " | " +
- mssNaturalCash.monotoneType (dblX) + " <====> " +
- FormatUtil.FormatDouble (mssNotAKnotCash.responseValue (dblX), 1, 6, 1.) + " | " +
- mssNotAKnotCash.monotoneType (dblX) + " <====> " +
- FormatUtil.FormatDouble (mssFinancialCash.responseValue (dblX), 1, 6, 1.) + " | " +
- mssNaturalCash.monotoneType (dblX));
- System.out.println ("\n");
- /*
- * Construct the Swap Curve Sequence with the Standard Natural Boundary Condition
- */
- MultiSegmentSequence mssNaturalSwap = BuildSwapCurve (
- mssNaturalCash,
- BoundarySettings.NaturalStandard(),
- MultiSegmentSequence.CALIBRATE
- );
- /*
- * Construct the Swap Curve Sequence with the Standard Financial Boundary Condition
- */
- MultiSegmentSequence mssFinancialSwap = BuildSwapCurve (
- mssFinancialCash,
- BoundarySettings.FinancialStandard(),
- MultiSegmentSequence.CALIBRATE
- );
- /*
- * Construct the Swap Curve Sequence with the Standard Not-A-Knot Boundary Condition
- */
- MultiSegmentSequence mssNotAKnotSwap = BuildSwapCurve (
- mssNotAKnotCash,
- BoundarySettings.NotAKnotStandard (1, 1),
- MultiSegmentSequence.CALIBRATE
- );
- /*
- * Display the DF and the monotonicity for the swaps.
- */
- dblXShift = 0.05 * (mssNaturalSwap.getRightPredictorOrdinateEdge() - mssNaturalSwap.getLeftPredictorOrdinateEdge());
- for (double dblX = mssNaturalSwap.getLeftPredictorOrdinateEdge(); dblX <= mssNaturalSwap.getRightPredictorOrdinateEdge(); dblX = dblX + dblXShift)
- System.out.println (
- "Swap DF [" +
- FormatUtil.FormatDouble (dblX, 2, 0, 1.) + "Y] => " +
- FormatUtil.FormatDouble (mssNaturalSwap.responseValue (dblX), 1, 6, 1.) + " | " +
- mssNaturalSwap.monotoneType (dblX) + " <====> " +
- FormatUtil.FormatDouble (mssNotAKnotSwap.responseValue (dblX), 1, 6, 1.) + " | " +
- mssNotAKnotSwap.monotoneType (dblX) + " <====> " +
- FormatUtil.FormatDouble (mssFinancialSwap.responseValue (dblX), 1, 6, 1.) + " | " +
- mssFinancialSwap.monotoneType (dblX)
- );
- }
- public static final void main (
- final String[] astrArgs)
- throws Exception
- {
- CustomCurveBuilderTest();
- }
- }