HestonStochasticVolatilityAlgorithm.java

  1. package org.drip.pricer.option;

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

  79. /**
  80.  * <i>HestonStochasticVolatilityAlgorithm</i> implements the Heston 1993 Stochastic Volatility European Call
  81.  * and Put Options Pricer.
  82.  *
  83.  *  <br><br>
  84.  *  <ul>
  85.  *      <li><b>Module </b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/ProductCore.md">Product Core Module</a></li>
  86.  *      <li><b>Library</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/FixedIncomeAnalyticsLibrary.md">Fixed Income Analytics</a></li>
  87.  *      <li><b>Project</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/pricer/README.md">Custom Pricing Algorithms and the Derivative Fokker Planck Trajectory Generators</a></li>
  88.  *      <li><b>Package</b> = <a href = "https://github.com/lakshmiDRIP/DROP/tree/master/src/main/java/org/drip/pricer/option/README.md">Deterministic/Stochastic Volatility Settings/Greeks</a></li>
  89.  *  </ul>
  90.  * <br><br>
  91.  *
  92.  * @author Lakshmi Krishnamurthy
  93.  */

  94. public class HestonStochasticVolatilityAlgorithm extends org.drip.pricer.option.FokkerPlanckGenerator {

  95.     /**
  96.      * Payoff Transformation Type - The Original Heston 1993 Scheme
  97.      */

  98.     public static final int PAYOFF_TRANSFORM_SCHEME_HESTON_1993 = 1;

  99.     /**
  100.      * Payoff Transformation Type - The Albrecher, Mayer, Schoutens, and Tistaert Scheme
  101.      */

  102.     public static final int PAYOFF_TRANSFORM_SCHEME_AMST_2007 = 1;

  103.     private static final double FOURIER_FREQ_INIT = 0.01;
  104.     private static final double FOURIER_FREQ_INCREMENT = 0.1;
  105.     private static final double FOURIER_FREQ_FINAL = 25.;

  106.     private org.drip.param.pricer.HestonOptionPricerParams _fphp = null;

  107.     class PhaseCorrectedF {
  108.         double _dblCorrectedPhase = java.lang.Double.NaN;
  109.         org.drip.function.definition.CartesianComplexNumber _cnF = null;

  110.         PhaseCorrectedF (
  111.             final double dblCorrectedPhase,
  112.             final org.drip.function.definition.CartesianComplexNumber cnF)
  113.         {
  114.             _cnF = cnF;
  115.             _dblCorrectedPhase = dblCorrectedPhase;
  116.         }
  117.     }

  118.     private PhaseCorrectedF fourierTransformHeston93 (
  119.         final double dblStrike,
  120.         final double dbTimeToExpiry,
  121.         final double dblRiskFreeRate,
  122.         final double dblSpot,
  123.         final double dblInitialVolatility,
  124.         final double dblA,
  125.         final double dblFreq,
  126.         final double dblB,
  127.         final double dblU,
  128.         final org.drip.numerical.fourier.RotationCountPhaseTracker rcpt)
  129.     {
  130.         try {
  131.             org.drip.function.definition.CartesianComplexNumber cnSmallDLHS = new org.drip.function.definition.CartesianComplexNumber (dblB,
  132.                 -1. * _fphp.rho() * _fphp.sigma() * dblFreq);

  133.             org.drip.function.definition.CartesianComplexNumber cnSmallD = org.drip.function.definition.CartesianComplexNumber.Square
  134.                 (cnSmallDLHS);

  135.             if (null == cnSmallD) return null;

  136.             double dblSigmaScaler = _fphp.sigma() * _fphp.sigma();

  137.             if (null == (cnSmallD = org.drip.function.definition.CartesianComplexNumber.Add (cnSmallD, new
  138.                 org.drip.function.definition.CartesianComplexNumber (dblSigmaScaler * dblFreq * dblFreq, -2. * dblSigmaScaler
  139.                     * dblFreq * dblU))))
  140.                 return null;

  141.             if (null == (cnSmallD = org.drip.function.definition.CartesianComplexNumber.SquareRoot (cnSmallD))) return null;

  142.             org.drip.function.definition.CartesianComplexNumber cnGNumerator = org.drip.function.definition.CartesianComplexNumber.Subtract
  143.                 (cnSmallDLHS, cnSmallD);

  144.             if (null == cnGNumerator) return null;

  145.             org.drip.function.definition.CartesianComplexNumber cnG = org.drip.function.definition.CartesianComplexNumber.Add (cnSmallDLHS,
  146.                 cnSmallD);

  147.             if (null == cnG) return null;

  148.             if (null == (cnG = org.drip.function.definition.CartesianComplexNumber.Divide (cnGNumerator, cnG))) return null;

  149.             int iM = 0;
  150.             int iN = 0;

  151.             if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_POWER_PHASE_TRACKER_KAHL_JACKEL ==
  152.                 _fphp.phaseTrackerType()) {
  153.                 iM = (int) ((cnG.argument() + java.lang.Math.PI) / (2. * java.lang.Math.PI));

  154.                 iN = (int) ((cnG.argument() + (dbTimeToExpiry * cnSmallD.argument()) + java.lang.Math.PI) /
  155.                     (2. * java.lang.Math.PI));
  156.             }

  157.             org.drip.function.definition.CartesianComplexNumber cnExpTTEScaledSmallD =
  158.                 org.drip.function.definition.CartesianComplexNumber.Scale (cnSmallD, -1. * dbTimeToExpiry);

  159.             if (null == cnExpTTEScaledSmallD) return null;

  160.             if (null == (cnExpTTEScaledSmallD = org.drip.function.definition.CartesianComplexNumber.Exponentiate
  161.                 (cnExpTTEScaledSmallD)))
  162.                 return null;

  163.             org.drip.function.definition.CartesianComplexNumber cnD = new org.drip.function.definition.CartesianComplexNumber (1. -
  164.                 cnExpTTEScaledSmallD.real(), -1. * cnExpTTEScaledSmallD.imaginary());

  165.             org.drip.function.definition.CartesianComplexNumber cnInvGExpTTEScaledSmallD =
  166.                 org.drip.function.definition.CartesianComplexNumber.Multiply (cnExpTTEScaledSmallD, cnG);

  167.             if (null == cnInvGExpTTEScaledSmallD) return null;

  168.             cnInvGExpTTEScaledSmallD = new org.drip.function.definition.CartesianComplexNumber (1. -
  169.                 cnInvGExpTTEScaledSmallD.real(), -1. * cnInvGExpTTEScaledSmallD.imaginary());

  170.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Divide (cnD, cnInvGExpTTEScaledSmallD)))
  171.                 return null;

  172.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Multiply (cnGNumerator, cnD)))
  173.                 return null;

  174.             dblSigmaScaler = 1. / dblSigmaScaler;

  175.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Scale (cnD, dblSigmaScaler))) return null;

  176.             org.drip.function.definition.CartesianComplexNumber cnC = new org.drip.function.definition.CartesianComplexNumber (1. -
  177.                 cnG.real(), -1. * cnG.imaginary());

  178.             if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_POWER_PHASE_TRACKER_KAHL_JACKEL ==
  179.                 _fphp.phaseTrackerType()) {
  180.                 if (null == (cnC = org.drip.numerical.fourier.PhaseAdjuster.PowerLogPhaseTracker
  181.                     (cnInvGExpTTEScaledSmallD, cnC, iN, iM)))
  182.                     return null;
  183.             } else if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT
  184.                 == _fphp.phaseTrackerType()) {
  185.                 if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Logarithm (cnC))) return null;

  186.                 cnC = new org.drip.function.definition.CartesianComplexNumber (cnC.real(), rcpt.updateAndApply
  187.                     (cnC.argument(), true));
  188.             }

  189.             double dblCorrectedPhase = cnC.argument();

  190.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Scale (cnC, -2.))) return null;

  191.             org.drip.function.definition.CartesianComplexNumber cnTTEScaledGNumerator =
  192.                 org.drip.function.definition.CartesianComplexNumber.Scale (cnGNumerator, dbTimeToExpiry);

  193.             if (null == cnTTEScaledGNumerator) return null;

  194.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Add (cnTTEScaledGNumerator, cnC)))
  195.                 return null;

  196.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Scale (cnC, dblA * dblSigmaScaler)))
  197.                 return null;

  198.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Add (new
  199.                 org.drip.function.definition.CartesianComplexNumber (0., dblRiskFreeRate * dbTimeToExpiry * dblFreq),
  200.                     cnC)))
  201.                 return null;

  202.             org.drip.function.definition.CartesianComplexNumber cnF = org.drip.function.definition.CartesianComplexNumber.Scale (cnD,
  203.                 dblInitialVolatility);

  204.             if (null == cnF) return null;

  205.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, new
  206.                 org.drip.function.definition.CartesianComplexNumber (0., java.lang.Math.log (dblSpot) * dblFreq))))
  207.                 return null;

  208.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, cnC))) return null;

  209.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, new
  210.                 org.drip.function.definition.CartesianComplexNumber (0., -1. * java.lang.Math.log (dblStrike) * dblFreq))))
  211.                 return null;

  212.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Exponentiate (cnF))) return null;

  213.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Divide (cnF, new
  214.                 org.drip.function.definition.CartesianComplexNumber (0., dblFreq))))
  215.                 return null;

  216.             return new PhaseCorrectedF (dblCorrectedPhase, cnF);
  217.         } catch (java.lang.Exception e) {
  218.             e.printStackTrace();
  219.         }

  220.         return null;
  221.     }

  222.     private PhaseCorrectedF fourierTransformAMST07 (
  223.         final double dblStrike,
  224.         final double dbTimeToExpiry,
  225.         final double dblRiskFreeRate,
  226.         final double dblSpot,
  227.         final double dblInitialVolatility,
  228.         final double dblA,
  229.         final double dblFreq,
  230.         final double dblB,
  231.         final double dblU,
  232.         final org.drip.numerical.fourier.RotationCountPhaseTracker rcpt)
  233.     {
  234.         try {
  235.             org.drip.function.definition.CartesianComplexNumber cnSmallDLHS = new org.drip.function.definition.CartesianComplexNumber (dblB,
  236.                 -1. * _fphp.rho() * _fphp.sigma() * dblFreq);

  237.             org.drip.function.definition.CartesianComplexNumber cnSmallD = org.drip.function.definition.CartesianComplexNumber.Square
  238.                 (cnSmallDLHS);

  239.             if (null == cnSmallD) return null;

  240.             double dblSigmaScaler = _fphp.sigma() * _fphp.sigma();

  241.             if (null == (cnSmallD = org.drip.function.definition.CartesianComplexNumber.Add (cnSmallD, new
  242.                 org.drip.function.definition.CartesianComplexNumber (dblSigmaScaler * dblFreq * dblFreq, -2. * dblSigmaScaler
  243.                     * dblFreq * dblU))))
  244.                 return null;

  245.             if (null == (cnSmallD = org.drip.function.definition.CartesianComplexNumber.SquareRoot (cnSmallD))) return null;

  246.             org.drip.function.definition.CartesianComplexNumber cnGNumerator = org.drip.function.definition.CartesianComplexNumber.Add
  247.                 (cnSmallDLHS, cnSmallD);

  248.             if (null == cnGNumerator) return null;

  249.             org.drip.function.definition.CartesianComplexNumber cnG = org.drip.function.definition.CartesianComplexNumber.Subtract
  250.                 (cnSmallDLHS, cnSmallD);

  251.             if (null == cnG) return null;

  252.             if (null == (cnG = org.drip.function.definition.CartesianComplexNumber.Divide (cnGNumerator, cnG))) return null;

  253.             int iM = 0;
  254.             int iN = 0;

  255.             if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_POWER_PHASE_TRACKER_KAHL_JACKEL ==
  256.                 _fphp.phaseTrackerType()) {
  257.                 iM = (int) ((cnG.argument() + java.lang.Math.PI) / (2. * java.lang.Math.PI));

  258.                 iN = (int) ((cnG.argument() + (dbTimeToExpiry * cnSmallD.argument()) + java.lang.Math.PI) /
  259.                     (2. * java.lang.Math.PI));
  260.             }

  261.             org.drip.function.definition.CartesianComplexNumber cnExpTTEScaledSmallD =
  262.                 org.drip.function.definition.CartesianComplexNumber.Scale (cnSmallD, dbTimeToExpiry);

  263.             if (null == cnExpTTEScaledSmallD) return null;

  264.             if (null == (cnExpTTEScaledSmallD = org.drip.function.definition.CartesianComplexNumber.Exponentiate
  265.                 (cnExpTTEScaledSmallD)))
  266.                 return null;

  267.             org.drip.function.definition.CartesianComplexNumber cnD = new org.drip.function.definition.CartesianComplexNumber (1. -
  268.                 cnExpTTEScaledSmallD.real(), -1. * cnExpTTEScaledSmallD.imaginary());

  269.             org.drip.function.definition.CartesianComplexNumber cnInvGExpTTEScaledSmallD =
  270.                 org.drip.function.definition.CartesianComplexNumber.Multiply (cnG, cnExpTTEScaledSmallD);

  271.             if (null == cnInvGExpTTEScaledSmallD) return null;

  272.             cnInvGExpTTEScaledSmallD = new org.drip.function.definition.CartesianComplexNumber (1. -
  273.                 cnInvGExpTTEScaledSmallD.real(), -1. * cnInvGExpTTEScaledSmallD.imaginary());

  274.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Divide (cnD, cnInvGExpTTEScaledSmallD)))
  275.                 return null;

  276.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Multiply (cnGNumerator, cnD)))
  277.                 return null;

  278.             dblSigmaScaler = 1. / dblSigmaScaler;

  279.             if (null == (cnD = org.drip.function.definition.CartesianComplexNumber.Scale (cnD, dblSigmaScaler))) return null;

  280.             org.drip.function.definition.CartesianComplexNumber cnC = new org.drip.function.definition.CartesianComplexNumber (1. -
  281.                 cnG.real(), -1. * cnG.imaginary());

  282.             if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_POWER_PHASE_TRACKER_KAHL_JACKEL ==
  283.                 _fphp.phaseTrackerType()) {
  284.                 if (null == (cnC = org.drip.numerical.fourier.PhaseAdjuster.PowerLogPhaseTracker
  285.                     (cnInvGExpTTEScaledSmallD, cnC, iN, iM)))
  286.                     return null;
  287.             } else if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT
  288.                 == _fphp.phaseTrackerType()) {
  289.                 if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Logarithm (cnC))) return null;

  290.                 cnC = new org.drip.function.definition.CartesianComplexNumber (cnC.real(), rcpt.updateAndApply
  291.                     (cnC.argument(), true));
  292.             }

  293.             double dblCorrectedPhase = cnC.argument();

  294.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Scale (cnC, -2.))) return null;

  295.             org.drip.function.definition.CartesianComplexNumber cnTTEScaledGNumerator =
  296.                 org.drip.function.definition.CartesianComplexNumber.Scale (cnGNumerator, dbTimeToExpiry);

  297.             if (null == cnTTEScaledGNumerator) return null;

  298.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Add (cnTTEScaledGNumerator, cnC)))
  299.                 return null;

  300.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Scale (cnC, dblA * dblSigmaScaler)))
  301.                 return null;

  302.             if (null == (cnC = org.drip.function.definition.CartesianComplexNumber.Add (new
  303.                 org.drip.function.definition.CartesianComplexNumber (0., dblRiskFreeRate * dbTimeToExpiry * dblFreq),
  304.                     cnC)))
  305.                 return null;

  306.             org.drip.function.definition.CartesianComplexNumber cnF = org.drip.function.definition.CartesianComplexNumber.Scale (cnD,
  307.                 dblInitialVolatility);

  308.             if (null == cnF) return null;

  309.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, new
  310.                 org.drip.function.definition.CartesianComplexNumber (0., java.lang.Math.log (dblSpot) * dblFreq))))
  311.                 return null;

  312.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, cnC))) return null;

  313.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Add (cnF, new
  314.                 org.drip.function.definition.CartesianComplexNumber (0., -1. * java.lang.Math.log (dblStrike) * dblFreq))))
  315.                 return null;

  316.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Exponentiate (cnF))) return null;

  317.             if (null == (cnF = org.drip.function.definition.CartesianComplexNumber.Divide (cnF, new
  318.                 org.drip.function.definition.CartesianComplexNumber (0., dblFreq))))
  319.                 return null;

  320.             return new PhaseCorrectedF (dblCorrectedPhase, cnF);
  321.         } catch (java.lang.Exception e) {
  322.             e.printStackTrace();
  323.         }

  324.         return null;
  325.     }

  326.     private PhaseCorrectedF payoffTransform (
  327.         final double dblStrike,
  328.         final double dbTimeToExpiry,
  329.         final double dblRiskFreeRate,
  330.         final double dblSpot,
  331.         final double dblInitialVolatility,
  332.         final double dblA,
  333.         final double dblFreq,
  334.         final double dblB,
  335.         final double dblU,
  336.         final org.drip.numerical.fourier.RotationCountPhaseTracker rcpt)
  337.     {
  338.         if (org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  339.             _fphp.phaseTrackerType() && null == rcpt)
  340.         {
  341.             return null;
  342.         }

  343.         if (PAYOFF_TRANSFORM_SCHEME_HESTON_1993 == _fphp.payoffTransformScheme())
  344.             return fourierTransformHeston93 (dblStrike, dbTimeToExpiry, dblRiskFreeRate, dblSpot,
  345.                 dblInitialVolatility, dblA, dblFreq, dblB, dblU, rcpt);

  346.         if (PAYOFF_TRANSFORM_SCHEME_AMST_2007 == _fphp.payoffTransformScheme())
  347.             return fourierTransformAMST07 (dblStrike, dbTimeToExpiry, dblRiskFreeRate, dblSpot,
  348.                 dblInitialVolatility, dblA, dblFreq, dblB, dblU, rcpt);

  349.         return null;
  350.     }

  351.     /**
  352.      * HestonStochasticVolatilityAlgorithm constructor
  353.      *
  354.      * @param fphp The Heston Algorithm Parameters
  355.      *
  356.      * @throws java.lang.Exception Thrown if the Inputs are Invalid
  357.      */

  358.     public HestonStochasticVolatilityAlgorithm (
  359.         final org.drip.param.pricer.HestonOptionPricerParams fphp)
  360.         throws java.lang.Exception
  361.     {
  362.         if (null == (_fphp = fphp))
  363.             throw new java.lang.Exception ("HestonStochasticVolatilityAlgorithm ctr: Invalid Inputs");
  364.     }

  365.     /**
  366.      * Record the Details of a Single Phase Adjustment Run
  367.      *
  368.      * @param dblStrike Strike
  369.      * @param dbTimeToExpiry TTE
  370.      * @param dblRiskFreeRate Risk Free Rate
  371.      * @param dblSpot Spot
  372.      * @param dblInitialVolatility Initial Volatility
  373.      * @param bLeft TRUE - Phase Correction applied to Left
  374.      *
  375.      * @return Map of the Phase Correction Record
  376.      */

  377.     public java.util.Map<java.lang.Double, java.lang.Double> recordPhase (
  378.         final double dblStrike,
  379.         final double dbTimeToExpiry,
  380.         final double dblRiskFreeRate,
  381.         final double dblSpot,
  382.         final double dblInitialVolatility,
  383.         final boolean bLeft)
  384.     {
  385.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblStrike) ||!org.drip.numerical.common.NumberUtil.IsValid
  386.             (dblSpot) ||!org.drip.numerical.common.NumberUtil.IsValid (dblInitialVolatility) ||
  387.                 !org.drip.numerical.common.NumberUtil.IsValid (dbTimeToExpiry) ||
  388.                     !org.drip.numerical.common.NumberUtil.IsValid (dblRiskFreeRate))
  389.             return null;

  390.         int i = 0;
  391.         double dblU1 = 0.5;
  392.         double dblU2 = -0.5;
  393.         double dblPreviousPhase = 0.;

  394.         org.drip.numerical.fourier.RotationCountPhaseTracker rcpt =
  395.             org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  396.                 _fphp.phaseTrackerType() ? new org.drip.numerical.fourier.RotationCountPhaseTracker() : null;

  397.         double dblA = _fphp.kappa() * _fphp.theta();

  398.         double dblB2 = _fphp.kappa() + _fphp.lambda();

  399.         double dblB1 = dblB2 - _fphp.rho() * _fphp.sigma();

  400.         java.util.Map<java.lang.Double, java.lang.Double> mapPhaseRun = new
  401.             java.util.TreeMap<java.lang.Double, java.lang.Double>();

  402.         for (double dblFreq = FOURIER_FREQ_INIT; dblFreq <= FOURIER_FREQ_FINAL; dblFreq +=
  403.             FOURIER_FREQ_INCREMENT, ++i) {
  404.             PhaseCorrectedF pcf = bLeft ? payoffTransform (dblStrike, dbTimeToExpiry, dblRiskFreeRate,
  405.                 dblSpot, dblInitialVolatility, dblA, dblFreq, dblB1, dblU1, rcpt) : payoffTransform
  406.                     (dblStrike, dbTimeToExpiry, dblRiskFreeRate, dblSpot, dblInitialVolatility, dblA,
  407.                         dblFreq, dblB2, dblU2, rcpt);

  408.             if (null != rcpt) {
  409.                 if (0 == i)
  410.                     dblPreviousPhase = rcpt.getPreviousPhase();
  411.                 else if (1 == i) {
  412.                     double dblCurrentPhase = rcpt.getPreviousPhase();

  413.                     if (dblCurrentPhase < dblPreviousPhase) {
  414.                         if (!rcpt.setDirection
  415.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_BACKWARD))
  416.                             return null;
  417.                     } else if (dblCurrentPhase > dblPreviousPhase) {
  418.                         if (!rcpt.setDirection
  419.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_FORWARD))
  420.                             return null;
  421.                     } else
  422.                         return null;
  423.                 }
  424.             }

  425.             mapPhaseRun.put (dblFreq, pcf._dblCorrectedPhase);
  426.         }

  427.         return mapPhaseRun;
  428.     }

  429.     @Override public double payoff (
  430.         final double dblStrike,
  431.         final double dblTimeToExpiry,
  432.         final double dblRiskFreeRate,
  433.         final double dblUnderlier,
  434.         final boolean bIsPut,
  435.         final boolean bIsForward,
  436.         final double dblInitialVolatility,
  437.         final boolean bAsPrice)
  438.         throws java.lang.Exception
  439.     {
  440.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblStrike) ||
  441.             !org.drip.numerical.common.NumberUtil.IsValid (dblUnderlier) ||
  442.                 !org.drip.numerical.common.NumberUtil.IsValid (dblInitialVolatility) ||
  443.                     !org.drip.numerical.common.NumberUtil.IsValid (dblTimeToExpiry) ||
  444.                         !org.drip.numerical.common.NumberUtil.IsValid (dblRiskFreeRate))
  445.             throw new java.lang.Exception ("HestonStochasticVolatilityAlgorithm::payoff => Invalid Inputs");

  446.         org.drip.numerical.fourier.RotationCountPhaseTracker rcpt1 =
  447.             org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  448.                 _fphp.phaseTrackerType() ? new org.drip.numerical.fourier.RotationCountPhaseTracker() : null;

  449.         org.drip.numerical.fourier.RotationCountPhaseTracker rcpt2 =
  450.             org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  451.                 _fphp.phaseTrackerType() ? new org.drip.numerical.fourier.RotationCountPhaseTracker() : null;

  452.         double dblA = _fphp.kappa() * _fphp.theta();

  453.         double dblB2 = _fphp.kappa() + _fphp.lambda();

  454.         double dblB1 = dblB2 - _fphp.rho() * _fphp.sigma();

  455.         double dblDF = java.lang.Math.exp (-1. * dblRiskFreeRate * dblTimeToExpiry);

  456.         int i = 0;
  457.         double dblU1 = 0.5;
  458.         double dblU2 = -0.5;
  459.         double dblCallProb1 = 0.;
  460.         double dblCallProb2 = 0.;
  461.         double dblPreviousPhase = 0.;
  462.         double dblSpot = bIsForward ? dblUnderlier * dblDF : dblUnderlier;

  463.         for (double dblFreq = FOURIER_FREQ_INIT; dblFreq <= FOURIER_FREQ_FINAL; dblFreq +=
  464.             FOURIER_FREQ_INCREMENT, ++i) {
  465.             PhaseCorrectedF pcf1 = payoffTransform (dblStrike, dblTimeToExpiry, dblRiskFreeRate, dblSpot,
  466.                 dblInitialVolatility, dblA, dblFreq, dblB1, dblU1, rcpt1);

  467.             if (null != rcpt1) {
  468.                 if (0 == i)
  469.                     dblPreviousPhase = rcpt1.getPreviousPhase();
  470.                 else if (1 == i) {
  471.                     double dblCurrentPhase = rcpt1.getPreviousPhase();

  472.                     if (dblCurrentPhase < dblPreviousPhase) {
  473.                         if (!rcpt1.setDirection
  474.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_BACKWARD))
  475.                             throw new java.lang.Exception
  476.                                 ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  477.                     } else if (dblCurrentPhase > dblPreviousPhase) {
  478.                         if (!rcpt1.setDirection
  479.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_FORWARD))
  480.                             throw new java.lang.Exception
  481.                                 ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  482.                     } else
  483.                         throw new java.lang.Exception
  484.                             ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  485.                 }
  486.             }

  487.             PhaseCorrectedF pcf2 = payoffTransform (dblStrike, dblTimeToExpiry, dblRiskFreeRate, dblSpot,
  488.                 dblInitialVolatility, dblA, dblFreq, dblB2, dblU2, rcpt2);

  489.             if (null != rcpt2) {
  490.                 if (0 == i)
  491.                     dblPreviousPhase = rcpt2.getPreviousPhase();
  492.                 else if (1 == i) {
  493.                     double dblCurrentPhase = rcpt2.getPreviousPhase();

  494.                     if (dblCurrentPhase < dblPreviousPhase) {
  495.                         if (!rcpt2.setDirection
  496.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_BACKWARD))
  497.                             throw new java.lang.Exception
  498.                                 ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  499.                     } else if (dblCurrentPhase > dblPreviousPhase) {
  500.                         if (!rcpt2.setDirection
  501.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_FORWARD))
  502.                             throw new java.lang.Exception
  503.                                 ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  504.                     } else
  505.                         throw new java.lang.Exception
  506.                             ("HestonStochasticVolatilityAlgorithm::payoff => Cannot compute payoff");
  507.                 }
  508.             }

  509.             dblCallProb1 += pcf1._cnF.real() * FOURIER_FREQ_INCREMENT;

  510.             dblCallProb2 += pcf2._cnF.real() * FOURIER_FREQ_INCREMENT;
  511.         }

  512.         double dblForward = dblSpot / dblDF;
  513.         double dblPIScaler = 1. / java.lang.Math.PI;
  514.         double dblCallPayoff = dblForward * (0.5 + dblCallProb1 * dblPIScaler) - dblStrike * (0.5 +
  515.             dblCallProb2 * dblPIScaler);

  516.         if (!bAsPrice) return bIsPut ? dblCallPayoff + dblStrike - dblForward : dblCallPayoff;

  517.         return bIsPut ? dblDF * (dblCallPayoff + dblStrike - dblForward) : dblDF * dblCallPayoff;
  518.     }

  519.     @Override public org.drip.pricer.option.Greeks greeks (
  520.         final double dblStrike,
  521.         final double dblTimeToExpiry,
  522.         final double dblRiskFreeRate,
  523.         final double dblUnderlier,
  524.         final boolean bIsPut,
  525.         final boolean bIsForward,
  526.         final double dblInitialVolatility)
  527.     {
  528.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblStrike) ||
  529.             !org.drip.numerical.common.NumberUtil.IsValid (dblUnderlier) ||
  530.                 !org.drip.numerical.common.NumberUtil.IsValid (dblInitialVolatility) ||
  531.                     !org.drip.numerical.common.NumberUtil.IsValid (dblTimeToExpiry) ||
  532.                         !org.drip.numerical.common.NumberUtil.IsValid (dblRiskFreeRate))
  533.             return null;

  534.         org.drip.numerical.fourier.RotationCountPhaseTracker rcpt1 =
  535.             org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  536.                 _fphp.phaseTrackerType() ? new org.drip.numerical.fourier.RotationCountPhaseTracker() : null;

  537.         org.drip.numerical.fourier.RotationCountPhaseTracker rcpt2 =
  538.             org.drip.numerical.fourier.PhaseAdjuster.MULTI_VALUE_BRANCH_PHASE_TRACKER_ROTATION_COUNT ==
  539.                 _fphp.phaseTrackerType() ? new org.drip.numerical.fourier.RotationCountPhaseTracker() : null;

  540.         double dblA = _fphp.kappa() * _fphp.theta();

  541.         double dblB2 = _fphp.kappa() + _fphp.lambda();

  542.         double dblB1 = dblB2 - _fphp.rho() * _fphp.sigma();

  543.         double dblDF = java.lang.Math.exp (-1. * dblRiskFreeRate * dblTimeToExpiry);

  544.         int i = 0;
  545.         double dblU1 = 0.5;
  546.         double dblU2 = -0.5;
  547.         double dblCallProb1 = 0.;
  548.         double dblCallProb2 = 0.;
  549.         double dblPreviousPhase = 0.;
  550.         double dblSpot = bIsForward ? dblUnderlier * dblDF : dblUnderlier;

  551.         for (double dblFreq = FOURIER_FREQ_INIT; dblFreq <= FOURIER_FREQ_FINAL; dblFreq +=
  552.             FOURIER_FREQ_INCREMENT, ++i) {
  553.             PhaseCorrectedF pcf1 = payoffTransform (dblStrike, dblTimeToExpiry, dblRiskFreeRate, dblSpot,
  554.                 dblInitialVolatility, dblA, dblFreq, dblB1, dblU1, rcpt1);

  555.             if (null != rcpt1) {
  556.                 if (0 == i)
  557.                     dblPreviousPhase = rcpt1.getPreviousPhase();
  558.                 else if (1 == i) {
  559.                     double dblCurrentPhase = rcpt1.getPreviousPhase();

  560.                     if (dblCurrentPhase < dblPreviousPhase) {
  561.                         if (!rcpt1.setDirection
  562.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_BACKWARD))
  563.                             return null;
  564.                     } else if (dblCurrentPhase > dblPreviousPhase) {
  565.                         if (!rcpt1.setDirection
  566.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_FORWARD))
  567.                             return null;
  568.                     } else
  569.                         return null;
  570.                 }
  571.             }

  572.             PhaseCorrectedF pcf2 = payoffTransform (dblStrike, dblTimeToExpiry, dblRiskFreeRate, dblSpot,
  573.                 dblInitialVolatility, dblA, dblFreq, dblB2, dblU2, rcpt2);

  574.             if (null != rcpt2) {
  575.                 if (0 == i)
  576.                     dblPreviousPhase = rcpt2.getPreviousPhase();
  577.                 else if (1 == i) {
  578.                     double dblCurrentPhase = rcpt2.getPreviousPhase();

  579.                     if (dblCurrentPhase < dblPreviousPhase) {
  580.                         if (!rcpt2.setDirection
  581.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_BACKWARD))
  582.                             return null;
  583.                     } else if (dblCurrentPhase > dblPreviousPhase) {
  584.                         if (!rcpt2.setDirection
  585.                             (org.drip.numerical.fourier.RotationCountPhaseTracker.APPLY_FORWARD))
  586.                             return null;
  587.                     } else
  588.                         return null;
  589.                 }
  590.             }

  591.             dblCallProb1 += pcf1._cnF.real() * FOURIER_FREQ_INCREMENT;

  592.             dblCallProb2 += pcf2._cnF.real() * FOURIER_FREQ_INCREMENT;
  593.         }

  594.         double dblForward = dblSpot / dblDF;
  595.         double dblPIScaler = 1. / java.lang.Math.PI;
  596.         dblCallProb1 = 0.5 + dblCallProb1 * dblPIScaler;
  597.         dblCallProb2 = 0.5 + dblCallProb2 * dblPIScaler;
  598.         double dblATMCallPayoff = dblForward * (dblCallProb1 - dblCallProb2);
  599.         double dblCallPrice = dblSpot * dblCallProb1 - dblStrike * dblDF * dblCallProb2;
  600.         double dblExpectedCallPayoff = dblForward * dblCallProb1 - dblStrike * dblDF * dblCallProb2;

  601.         try {
  602.             if (!bIsPut)
  603.                 return new org.drip.pricer.option.Greeks (
  604.                     dblDF,
  605.                     dblInitialVolatility,
  606.                     dblExpectedCallPayoff,
  607.                     dblATMCallPayoff,
  608.                     dblCallPrice,
  609.                     dblCallProb1,
  610.                     dblCallProb2,
  611.                     dblCallProb1,
  612.                     java.lang.Double.NaN,
  613.                     java.lang.Double.NaN,
  614.                     java.lang.Double.NaN,
  615.                     java.lang.Double.NaN,
  616.                     java.lang.Double.NaN,
  617.                     java.lang.Double.NaN,
  618.                     java.lang.Double.NaN,
  619.                     java.lang.Double.NaN,
  620.                     java.lang.Double.NaN,
  621.                     java.lang.Double.NaN,
  622.                     java.lang.Double.NaN
  623.                 );

  624.             double dblPutPriceFromParity = dblCallPrice + dblStrike * dblDF - dblSpot;

  625.             return new org.drip.pricer.option.PutGreeks (
  626.                 dblDF,
  627.                 dblInitialVolatility,
  628.                 dblExpectedCallPayoff + dblStrike - dblSpot,
  629.                 dblATMCallPayoff,
  630.                 dblPutPriceFromParity,
  631.                 dblPutPriceFromParity,
  632.                 java.lang.Double.NaN,
  633.                 java.lang.Double.NaN,
  634.                 java.lang.Double.NaN,
  635.                 java.lang.Double.NaN,
  636.                 java.lang.Double.NaN,
  637.                 java.lang.Double.NaN,
  638.                 java.lang.Double.NaN,
  639.                 java.lang.Double.NaN,
  640.                 java.lang.Double.NaN,
  641.                 java.lang.Double.NaN,
  642.                 java.lang.Double.NaN,
  643.                 java.lang.Double.NaN,
  644.                 java.lang.Double.NaN,
  645.                 java.lang.Double.NaN
  646.             );
  647.         } catch (java.lang.Exception e) {
  648.             e.printStackTrace();
  649.         }

  650.         return null;
  651.     }
  652. }