SingleFactorStateEvolver.java

  1. package org.drip.dynamics.hullwhite;

  2. /*
  3.  * -*- mode: java; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  4.  */

  5. /*!
  6.  * Copyright (C) 2020 Lakshmi Krishnamurthy
  7.  * Copyright (C) 2019 Lakshmi Krishnamurthy
  8.  * Copyright (C) 2018 Lakshmi Krishnamurthy
  9.  * Copyright (C) 2017 Lakshmi Krishnamurthy
  10.  * Copyright (C) 2016 Lakshmi Krishnamurthy
  11.  * Copyright (C) 2015 Lakshmi Krishnamurthy
  12.  *
  13.  *  This file is part of DROP, an open-source library targeting analytics/risk, transaction cost analytics,
  14.  *      asset liability management analytics, capital, exposure, and margin analytics, valuation adjustment
  15.  *      analytics, and portfolio construction analytics within and across fixed income, credit, commodity,
  16.  *      equity, FX, and structured products. It also includes auxiliary libraries for algorithm support,
  17.  *      numerical analysis, numerical optimization, spline builder, model validation, statistical learning,
  18.  *      and computational support.
  19.  *  
  20.  *      https://lakshmidrip.github.io/DROP/
  21.  *  
  22.  *  DROP is composed of three modules:
  23.  *  
  24.  *  - DROP Product Core - https://lakshmidrip.github.io/DROP-Product-Core/
  25.  *  - DROP Portfolio Core - https://lakshmidrip.github.io/DROP-Portfolio-Core/
  26.  *  - DROP Computational Core - https://lakshmidrip.github.io/DROP-Computational-Core/
  27.  *
  28.  *  DROP Product Core implements libraries for the following:
  29.  *  - Fixed Income Analytics
  30.  *  - Loan Analytics
  31.  *  - Transaction Cost Analytics
  32.  *
  33.  *  DROP Portfolio Core implements libraries for the following:
  34.  *  - Asset Allocation Analytics
  35.  *  - Asset Liability Management Analytics
  36.  *  - Capital Estimation Analytics
  37.  *  - Exposure Analytics
  38.  *  - Margin Analytics
  39.  *  - XVA Analytics
  40.  *
  41.  *  DROP Computational Core implements libraries for the following:
  42.  *  - Algorithm Support
  43.  *  - Computation Support
  44.  *  - Function Analysis
  45.  *  - Model Validation
  46.  *  - Numerical Analysis
  47.  *  - Numerical Optimizer
  48.  *  - Spline Builder
  49.  *  - Statistical Learning
  50.  *
  51.  *  Documentation for DROP is Spread Over:
  52.  *
  53.  *  - Main                     => https://lakshmidrip.github.io/DROP/
  54.  *  - Wiki                     => https://github.com/lakshmiDRIP/DROP/wiki
  55.  *  - GitHub                   => https://github.com/lakshmiDRIP/DROP
  56.  *  - Repo Layout Taxonomy     => https://github.com/lakshmiDRIP/DROP/blob/master/Taxonomy.md
  57.  *  - Javadoc                  => https://lakshmidrip.github.io/DROP/Javadoc/index.html
  58.  *  - Technical Specifications => https://github.com/lakshmiDRIP/DROP/tree/master/Docs/Internal
  59.  *  - Release Versions         => https://lakshmidrip.github.io/DROP/version.html
  60.  *  - Community Credits        => https://lakshmidrip.github.io/DROP/credits.html
  61.  *  - Issues Catalog           => https://github.com/lakshmiDRIP/DROP/issues
  62.  *  - JUnit                    => https://lakshmidrip.github.io/DROP/junit/index.html
  63.  *  - Jacoco                   => https://lakshmidrip.github.io/DROP/jacoco/index.html
  64.  *
  65.  *  Licensed under the Apache License, Version 2.0 (the "License");
  66.  *      you may not use this file except in compliance with the License.
  67.  *  
  68.  *  You may obtain a copy of the License at
  69.  *      http://www.apache.org/licenses/LICENSE-2.0
  70.  *  
  71.  *  Unless required by applicable law or agreed to in writing, software
  72.  *      distributed under the License is distributed on an "AS IS" BASIS,
  73.  *      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  74.  *  
  75.  *  See the License for the specific language governing permissions and
  76.  *      limitations under the License.
  77.  */

  78. /**
  79.  * <i>SingleFactorStateEvolver</i> provides the Hull-White One-Factor Gaussian HJM Short Rate Dynamics
  80.  * Implementation.
  81.  *
  82.  *  <br><br>
  83.  *  <ul>
  84.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ProductCore.md">Product Core Module</a></li>
  85.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/FixedIncomeAnalyticsLibrary.md">Fixed Income Analytics</a></li>
  86.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/dynamics/README.md">HJM, Hull White, LMM, and SABR Dynamic Evolution Models</a></li>
  87.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/dynamics/hullwhite/README.md">Hull White Latent State Evolution</a></li>
  88.  *  </ul>
  89.  *
  90.  * @author Lakshmi Krishnamurthy
  91.  */

  92. public class SingleFactorStateEvolver implements org.drip.dynamics.evolution.PointStateEvolver {
  93.     private double _dblA = java.lang.Double.NaN;
  94.     private double _dblSigma = java.lang.Double.NaN;
  95.     private org.drip.function.definition.R1ToR1 _auIFRInitial = null;
  96.     private org.drip.state.identifier.FundingLabel _lslFunding = null;
  97.     private org.drip.sequence.random.UnivariateSequenceGenerator _usg = null;

  98.     /**
  99.      * SingleFactorStateEvolver Constructor
  100.      *
  101.      * @param lslFunding The Funding Latent State Label
  102.      * @param dblSigma Sigma
  103.      * @param dblA A
  104.      * @param auIFRInitial The Initial Instantaneous Forward Rate Term Structure
  105.      * @param usg Univariate Random Sequence Generator
  106.      *
  107.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  108.      */

  109.     public SingleFactorStateEvolver (
  110.         final org.drip.state.identifier.FundingLabel lslFunding,
  111.         final double dblSigma,
  112.         final double dblA,
  113.         final org.drip.function.definition.R1ToR1 auIFRInitial,
  114.         final org.drip.sequence.random.UnivariateSequenceGenerator usg)
  115.         throws java.lang.Exception
  116.     {
  117.         if (null == (_lslFunding = lslFunding) || !org.drip.numerical.common.NumberUtil.IsValid (_dblSigma =
  118.             dblSigma) || !org.drip.numerical.common.NumberUtil.IsValid (_dblA = dblA) || null == (_auIFRInitial =
  119.                 auIFRInitial) || null == (_usg = usg))
  120.             throw new java.lang.Exception ("SingleFactorStateEvolver ctr: Invalid Inputs");
  121.     }

  122.     /**
  123.      * Retrieve the Funding Label
  124.      *
  125.      * @return The Funding Label
  126.      */

  127.     public org.drip.state.identifier.FundingLabel fundingLabel()
  128.     {
  129.         return _lslFunding;
  130.     }

  131.     /**
  132.      * Retrieve Sigma
  133.      *
  134.      * @return Sigma
  135.      */

  136.     public double sigma()
  137.     {
  138.         return _dblSigma;
  139.     }

  140.     /**
  141.      * Retrieve A
  142.      *
  143.      * @return A
  144.      */

  145.     public double a()
  146.     {
  147.         return _dblA;
  148.     }

  149.     /**
  150.      * Retrieve the Initial Instantaneous Forward Rate Term Structure
  151.      *
  152.      * @return The Initial Instantaneous Forward Rate Term Structure
  153.      */

  154.     public org.drip.function.definition.R1ToR1 ifrInitialTermStructure()
  155.     {
  156.         return _auIFRInitial;
  157.     }

  158.     /**
  159.      * Retrieve the Random Sequence Generator
  160.      *
  161.      * @return The Random Sequence Generator
  162.      */

  163.     public org.drip.sequence.random.UnivariateSequenceGenerator rsg()
  164.     {
  165.         return _usg;
  166.     }

  167.     /**
  168.      * Calculate the Alpha
  169.      *
  170.      * @param iSpotDate The Spot Date
  171.      * @param iViewDate The View Date
  172.      *
  173.      * @return Alpha
  174.      *
  175.      * @throws java.lang.Exception Thrown if Alpha cannot be computed
  176.      */

  177.     public double alpha (
  178.         final int iSpotDate,
  179.         final int iViewDate)
  180.         throws java.lang.Exception
  181.     {
  182.         if (iSpotDate > iViewDate)
  183.             throw new java.lang.Exception ("SingleFactorStateEvolver::alpha => Invalid Inputs");

  184.         double dblAlphaVol = _dblSigma * (1. - java.lang.Math.exp (_dblA * (iViewDate - iSpotDate) / 365.25))
  185.             / _dblA;

  186.         return _auIFRInitial.evaluate (iViewDate) + 0.5 * dblAlphaVol * dblAlphaVol;
  187.     }

  188.     /**
  189.      * Calculate the Theta
  190.      *
  191.      * @param iSpotDate The Spot Date
  192.      * @param iViewDate The View Date
  193.      *
  194.      * @return Theta
  195.      *
  196.      * @throws java.lang.Exception Thrown if Theta cannot be computed
  197.      */

  198.     public double theta (
  199.         final int iSpotDate,
  200.         final int iViewDate)
  201.         throws java.lang.Exception
  202.     {
  203.         if (iSpotDate > iViewDate)
  204.             throw new java.lang.Exception ("SingleFactorStateEvolver::theta => Invalid Inputs");

  205.         return _auIFRInitial.derivative (iViewDate, 1) + _dblA * _auIFRInitial.evaluate (iViewDate) +
  206.             _dblSigma * _dblSigma / (2. * _dblA) * (1. - java.lang.Math.exp (-2. * _dblA * (iViewDate -
  207.                 iSpotDate) / 365.25));
  208.     }

  209.     /**
  210.      * Calculate the Short Rate Increment
  211.      *
  212.      * @param iSpotDate The Spot Date
  213.      * @param iViewDate The View Date
  214.      * @param dblShortRate The Short Rate
  215.      * @param iViewTimeIncrement The View Time Increment
  216.      *
  217.      * @return The Short Rate Increment
  218.      *
  219.      * @throws java.lang.Exception Thrown if the Short Rate cannot be computed
  220.      */

  221.     public double shortRateIncrement (
  222.         final int iSpotDate,
  223.         final int iViewDate,
  224.         final double dblShortRate,
  225.         final int iViewTimeIncrement)
  226.         throws java.lang.Exception
  227.     {
  228.         if (iSpotDate > iViewDate || !org.drip.numerical.common.NumberUtil.IsValid (dblShortRate))
  229.             throw new java.lang.Exception ("SingleFactorStateEvolver::shortRateIncrement => Invalid Inputs");

  230.         double dblAnnualizedIncrement = 1. * iViewTimeIncrement / 365.25;

  231.         return (theta (iSpotDate, iViewDate) - _dblA * dblShortRate) * dblAnnualizedIncrement + _dblSigma *
  232.             java.lang.Math.sqrt (dblAnnualizedIncrement) * _usg.random();
  233.     }

  234.     @Override public org.drip.dynamics.evolution.LSQMPointUpdate evolve (
  235.         final int iSpotDate,
  236.         final int iViewDate,
  237.         final int iSpotTimeIncrement,
  238.         final org.drip.dynamics.evolution.LSQMPointUpdate lsqmPrev)
  239.     {
  240.         if (iViewDate < iSpotDate || null == lsqmPrev || !(lsqmPrev instanceof
  241.             org.drip.dynamics.hullwhite.ShortRateUpdate))
  242.             return null;

  243.         int iDate = iSpotDate;
  244.         int iTimeIncrement = 1;
  245.         int iFinalDate = iSpotDate + iSpotTimeIncrement;
  246.         double dblInitialShortRate = java.lang.Double.NaN;

  247.         try {
  248.             dblInitialShortRate = ((org.drip.dynamics.hullwhite.ShortRateUpdate)
  249.                 lsqmPrev).realizedFinalShortRate();
  250.         } catch (java.lang.Exception e) {
  251.             e.printStackTrace();

  252.             return null;
  253.         }

  254.         double dblShortRate = dblInitialShortRate;

  255.         while (iDate < iFinalDate) {
  256.             try {
  257.                 dblShortRate += shortRateIncrement (iSpotDate, iDate, dblShortRate, iTimeIncrement);
  258.             } catch (java.lang.Exception e) {
  259.                 e.printStackTrace();

  260.                 return null;
  261.             }

  262.             ++iDate;
  263.         }

  264.         double dblADF = java.lang.Math.exp (-1. * _dblA * iSpotTimeIncrement);

  265.         double dblB = (1. - dblADF) / _dblA;

  266.         try {
  267.             return org.drip.dynamics.hullwhite.ShortRateUpdate.Create (_lslFunding, iSpotDate, iFinalDate,
  268.                 iViewDate, dblInitialShortRate, dblShortRate, dblInitialShortRate * dblADF + alpha
  269.                     (iSpotDate, iFinalDate) - alpha (iSpotDate, iViewDate) * dblADF, 0.5 * _dblSigma *
  270.                         _dblSigma * (1. - dblADF * dblADF) / _dblA, java.lang.Math.exp (dblB *
  271.                             _auIFRInitial.evaluate (iViewDate) - 0.25 * _dblSigma * _dblSigma * (1. -
  272.                                 java.lang.Math.exp (-2. * _dblA * (iViewDate - iSpotDate) / 365.25)) * dblB *
  273.                                     dblB / _dblA));
  274.         } catch (java.lang.Exception e) {
  275.             e.printStackTrace();
  276.         }

  277.         return null;
  278.     }

  279.     /**
  280.      * Generate the Metrics associated with the Transition that results from using a Trinomial Tree Using the
  281.      *  Starting Node Metrics
  282.      *
  283.      * @param iSpotDate The Spot/Epoch Date
  284.      * @param iInitialDate The Initial Date
  285.      * @param iTerminalDate The Terminal Date
  286.      * @param hwnmInitial The Initial Node Metrics
  287.      *
  288.      * @return The Hull White Transition Metrics
  289.      */

  290.     public org.drip.dynamics.hullwhite.TrinomialTreeTransitionMetrics evolveTrinomialTree (
  291.         final int iSpotDate,
  292.         final int iInitialDate,
  293.         final int iTerminalDate,
  294.         final org.drip.dynamics.hullwhite.TrinomialTreeNodeMetrics hwnmInitial)
  295.     {
  296.         if (iInitialDate < iSpotDate || iTerminalDate <= iInitialDate) return null;

  297.         long lTreeTimeIndex = 0L;
  298.         double dblExpectedTerminalX = 0.;
  299.         long lTreeStochasticBaseIndex = 0L;

  300.         if (null != hwnmInitial) {
  301.             dblExpectedTerminalX = hwnmInitial.x();

  302.             lTreeTimeIndex = hwnmInitial.timeIndex() + 1;

  303.             lTreeStochasticBaseIndex = hwnmInitial.xStochasticIndex();
  304.         }

  305.         double dblADF = java.lang.Math.exp (-1. * _dblA * (iTerminalDate - iInitialDate) / 365.25);

  306.         try {
  307.             return new org.drip.dynamics.hullwhite.TrinomialTreeTransitionMetrics (iInitialDate,
  308.                 iTerminalDate, lTreeTimeIndex, lTreeStochasticBaseIndex, dblExpectedTerminalX * dblADF, 0.5 *
  309.                     _dblSigma * _dblSigma * (1. - dblADF * dblADF) / _dblA, alpha (iSpotDate,
  310.                         iTerminalDate));
  311.         } catch (java.lang.Exception e) {
  312.             e.printStackTrace();
  313.         }

  314.         return null;
  315.     }

  316.     /**
  317.      * Evolve the Trinomial Tree Sequence
  318.      *
  319.      * @param iSpotDate The Spot Date
  320.      * @param iInitialDate The Initial Date
  321.      * @param iDayIncrement The Day Increment
  322.      * @param iNumIncrement Number of Times to Increment
  323.      * @param hwnm Starting Node Metrics
  324.      * @param hwsm The Sequence Metrics
  325.      *
  326.      * @return TRUE - The Tree Successfully Evolved
  327.      */

  328.     public boolean evolveTrinomialTreeSequence (
  329.         final int iSpotDate,
  330.         final int iInitialDate,
  331.         final int iDayIncrement,
  332.         final int iNumIncrement,
  333.         final org.drip.dynamics.hullwhite.TrinomialTreeNodeMetrics hwnm,
  334.         final org.drip.dynamics.hullwhite.TrinomialTreeSequenceMetrics hwsm)
  335.     {
  336.         if (iInitialDate < iSpotDate || 0 >= iDayIncrement || null == hwsm) return false;

  337.         if (0 == iNumIncrement) return true;

  338.         org.drip.dynamics.hullwhite.TrinomialTreeTransitionMetrics hwtm = evolveTrinomialTree (iSpotDate,
  339.             iInitialDate, iInitialDate + iDayIncrement, hwnm);

  340.         if (!hwsm.addTransitionMetrics (hwtm)) return false;

  341.         org.drip.dynamics.hullwhite.TrinomialTreeNodeMetrics hwnmUp = hwtm.upNodeMetrics();

  342.         if (!hwsm.addNodeMetrics (hwnmUp) || (null != hwnm && !hwsm.setTransitionProbability (hwnm, hwnmUp,
  343.             hwtm.probabilityUp())) || !evolveTrinomialTreeSequence (iSpotDate, iInitialDate + iDayIncrement,
  344.                 iDayIncrement, iNumIncrement - 1, hwnmUp, hwsm))
  345.             return false;

  346.         org.drip.dynamics.hullwhite.TrinomialTreeNodeMetrics hwnmDown = hwtm.downNodeMetrics();

  347.         if (!hwsm.addNodeMetrics (hwnmDown) || (null != hwnm && !hwsm.setTransitionProbability (hwnm,
  348.             hwnmDown, hwtm.probabilityDown())) || !evolveTrinomialTreeSequence (iSpotDate, iInitialDate +
  349.                 iDayIncrement, iDayIncrement, iNumIncrement - 1, hwnmDown, hwsm))
  350.             return false;

  351.         org.drip.dynamics.hullwhite.TrinomialTreeNodeMetrics hwnmStay = hwtm.stayNodeMetrics();

  352.         if (!hwsm.addNodeMetrics (hwnmStay) || (null != hwnm && !hwsm.setTransitionProbability (hwnm,
  353.             hwnmStay, hwtm.probabilityStay())) || !evolveTrinomialTreeSequence (iSpotDate, iInitialDate +
  354.                 iDayIncrement, iDayIncrement, iNumIncrement - 1, hwnmStay, hwsm))
  355.             return false;

  356.         return true;
  357.     }

  358.     /**
  359.      * Evolve the Trinomial Tree Sequence
  360.      *
  361.      * @param iSpotDate The Spot Date
  362.      * @param iDayIncrement The Day Increment
  363.      * @param iNumIncrement Number of Times to Increment
  364.      *
  365.      * @return The Sequence Metrics
  366.      */

  367.     public org.drip.dynamics.hullwhite.TrinomialTreeSequenceMetrics evolveTrinomialTreeSequence (
  368.         final int iSpotDate,
  369.         final int iDayIncrement,
  370.         final int iNumIncrement)
  371.     {
  372.         org.drip.dynamics.hullwhite.TrinomialTreeSequenceMetrics hwsm = new
  373.             org.drip.dynamics.hullwhite.TrinomialTreeSequenceMetrics();

  374.         return evolveTrinomialTreeSequence (iSpotDate, iSpotDate, iDayIncrement, iNumIncrement, null, hwsm) ?
  375.             hwsm : null;
  376.     }
  377. }