BlackScholesAlgorithm.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>BlackScholesAlgorithm</i> implements the Black Scholes based European Call and Put Options Pricer.
  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/pricer/README.md">Custom Pricing Algorithms and the Derivative Fokker Planck Trajectory Generators</a></li>
  87.  *      <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>
  88.  *  </ul>
  89.  * <br><br>
  90.  *
  91.  * @author Lakshmi Krishnamurthy
  92.  */

  93. public class BlackScholesAlgorithm extends org.drip.pricer.option.FokkerPlanckGenerator {

  94.     /**
  95.      * Empty BlackScholesAlgorithm Constructor - nothing to be filled in with
  96.      */

  97.     public BlackScholesAlgorithm()
  98.     {
  99.     }

  100.     @Override public double payoff (
  101.         final double dblStrike,
  102.         final double dblTimeToExpiry,
  103.         final double dblRiskFreeRate,
  104.         final double dblUnderlier,
  105.         final boolean bIsPut,
  106.         final boolean bIsForward,
  107.         final double dblVolatility,
  108.         final boolean bAsPrice)
  109.         throws java.lang.Exception
  110.     {
  111.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblStrike) ||
  112.             !org.drip.numerical.common.NumberUtil.IsValid (dblUnderlier) ||
  113.                 !org.drip.numerical.common.NumberUtil.IsValid (dblVolatility) ||
  114.                     !org.drip.numerical.common.NumberUtil.IsValid (dblTimeToExpiry) ||
  115.                         !org.drip.numerical.common.NumberUtil.IsValid (dblRiskFreeRate))
  116.             throw new java.lang.Exception ("BlackScholesAlgorithm::payoff => Invalid Inputs");

  117.         double dblD1D2Diff = dblVolatility * java.lang.Math.sqrt (dblTimeToExpiry);

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

  119.         double dblD1 = java.lang.Double.NaN;
  120.         double dblD2 = java.lang.Double.NaN;
  121.         double dblForward = bIsForward ? dblUnderlier : dblUnderlier / dblDF;

  122.         if (0. != dblVolatility) {
  123.             dblD1 = (java.lang.Math.log (dblForward / dblStrike) + dblTimeToExpiry * (dblRiskFreeRate + (0.5
  124.                 * dblVolatility * dblVolatility))) / dblD1D2Diff;

  125.             dblD2 = dblD1 - dblD1D2Diff;
  126.         } else {
  127.             dblD1 = dblForward > dblStrike ? java.lang.Double.POSITIVE_INFINITY :
  128.                 java.lang.Double.NEGATIVE_INFINITY;
  129.             dblD2 = dblD1;
  130.         }

  131.         double dblCallPayoff = dblForward * org.drip.measure.gaussian.NormalQuadrature.CDF (dblD1) - dblStrike *
  132.             org.drip.measure.gaussian.NormalQuadrature.CDF (dblD2);

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

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

  136.     @Override public org.drip.pricer.option.Greeks greeks (
  137.         final double dblStrike,
  138.         final double dblTimeToExpiry,
  139.         final double dblRiskFreeRate,
  140.         final double dblUnderlier,
  141.         final boolean bIsPut,
  142.         final boolean bIsForward,
  143.         final double dblVolatility)
  144.     {
  145.         if (!org.drip.numerical.common.NumberUtil.IsValid (dblStrike) ||
  146.             !org.drip.numerical.common.NumberUtil.IsValid (dblUnderlier) ||
  147.                 !org.drip.numerical.common.NumberUtil.IsValid (dblVolatility) ||
  148.                     !org.drip.numerical.common.NumberUtil.IsValid (dblTimeToExpiry) ||
  149.                         !org.drip.numerical.common.NumberUtil.IsValid (dblRiskFreeRate))
  150.             return null;

  151.         double dblTimeRoot = java.lang.Math.sqrt (dblTimeToExpiry);

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

  153.         double dblVega = java.lang.Double.NaN;
  154.         double dblVeta = java.lang.Double.NaN;
  155.         double dblCharm = java.lang.Double.NaN;
  156.         double dblColor = java.lang.Double.NaN;
  157.         double dblGamma = java.lang.Double.NaN;
  158.         double dblSpeed = java.lang.Double.NaN;
  159.         double dblVanna = java.lang.Double.NaN;
  160.         double dblVomma = java.lang.Double.NaN;
  161.         double dblUltima = java.lang.Double.NaN;
  162.         double dblCallProb1 = java.lang.Double.NaN;
  163.         double dblCallProb2 = java.lang.Double.NaN;
  164.         double dblTimeDecay = java.lang.Double.NaN;
  165.         double dblATMCallProb1 = java.lang.Double.NaN;
  166.         double dblATMCallProb2 = java.lang.Double.NaN;
  167.         double dblD1D2Diff = dblVolatility * dblTimeRoot;
  168.         double dblForward = bIsForward ? dblUnderlier : dblUnderlier / dblDF;

  169.         double dblATMD1 = dblTimeToExpiry * (dblRiskFreeRate + (0.5 * dblVolatility * dblVolatility)) /
  170.             dblD1D2Diff;
  171.         double dblATMD2 = dblATMD1 - dblD1D2Diff;

  172.         double dblD1 = dblATMD1 + (java.lang.Math.log (dblForward / dblStrike)) / dblD1D2Diff;

  173.         double dblD2 = dblD1 - dblD1D2Diff;
  174.         double dblD1D2 = dblD1 * dblD2;

  175.         try {
  176.             dblCallProb1 = org.drip.measure.gaussian.NormalQuadrature.CDF (dblD1);

  177.             dblCallProb2 = org.drip.measure.gaussian.NormalQuadrature.CDF (dblD2);

  178.             dblATMCallProb1 = org.drip.measure.gaussian.NormalQuadrature.CDF (dblATMD1);

  179.             dblATMCallProb2 = org.drip.measure.gaussian.NormalQuadrature.CDF (dblATMD2);

  180.             double dblD1Density = org.drip.measure.gaussian.NormalQuadrature.Density (dblD1);

  181.             dblVega = dblForward * dblD1Density * dblTimeRoot;
  182.             dblVomma = dblVega * dblD1 * dblD2 / dblVolatility;
  183.             dblGamma = dblD1Density / (dblForward * dblD1D2Diff);
  184.             dblUltima = -1. * dblVega * (dblD1D2 * (1. - dblD1D2) + dblD1 * dblD1 + dblD2 * dblD2) /
  185.                 (dblVolatility * dblVolatility);
  186.             dblSpeed = -1. * dblGamma / dblForward * (1. + (dblD1 / dblD1D2Diff));
  187.             dblTimeDecay = -0.5 * dblForward * dblD1Density * dblVolatility / dblTimeRoot;
  188.             dblVanna = dblVega / dblForward * (1. - (dblD1 / dblD1D2Diff));
  189.             dblCharm = dblD1Density * (2. * dblRiskFreeRate * dblTimeToExpiry - dblD2 * dblD1D2Diff) / (2. *
  190.                 dblVolatility * dblD1D2Diff);
  191.             dblVeta = dblForward * dblD1Density * dblTimeRoot * ((dblRiskFreeRate * dblD1 / (dblD1D2Diff))
  192.                 - ((1. + dblD1D2) / (2. * dblTimeToExpiry)));
  193.             dblColor = -0.5 * dblD1Density / (dblForward * dblTimeToExpiry * dblD1D2Diff) * (1. + dblD1 *
  194.                 (2. * dblRiskFreeRate * dblTimeToExpiry - dblD2 * dblD1D2Diff) / dblD1D2Diff);
  195.         } catch (java.lang.Exception e) {
  196.             e.printStackTrace();

  197.             return null;
  198.         }

  199.         double dblExpectedCallPayoff = dblForward * dblCallProb1 - dblStrike * dblCallProb2;
  200.         double dblExpectedATMCallPayoff = dblStrike * (dblATMCallProb1 - dblATMCallProb2);
  201.         double dblCallRho = dblStrike * dblTimeToExpiry * dblCallProb2;
  202.         double dblCallPrice = dblDF * dblExpectedCallPayoff;

  203.         try {
  204.             if (!bIsPut)
  205.                 return new org.drip.pricer.option.Greeks (
  206.                     dblDF,
  207.                     dblVolatility,
  208.                     dblExpectedCallPayoff,
  209.                     dblExpectedATMCallPayoff,
  210.                     dblCallPrice,
  211.                     dblCallProb1,
  212.                     dblCallProb2,
  213.                     dblCallProb1,
  214.                     dblVega,
  215.                     dblTimeDecay - dblRiskFreeRate * dblStrike * dblCallProb2,
  216.                     dblCallRho,
  217.                     dblGamma,
  218.                     dblVanna,
  219.                     dblVomma,
  220.                     dblCharm,
  221.                     dblVeta,
  222.                     dblColor,
  223.                     dblSpeed,
  224.                     dblUltima
  225.                 );

  226.             double dblPutProb1 = org.drip.measure.gaussian.NormalQuadrature.CDF (-1. * dblD1);

  227.             double dblPutProb2 = org.drip.measure.gaussian.NormalQuadrature.CDF (-1. * dblD2);

  228.             return new org.drip.pricer.option.PutGreeks (
  229.                 dblDF,
  230.                 dblVolatility,
  231.                 dblExpectedCallPayoff + dblStrike - dblForward,
  232.                 dblExpectedATMCallPayoff,
  233.                 dblDF * (dblStrike * dblPutProb2 - dblForward * dblPutProb1),
  234.                 dblCallPrice + dblDF * (dblStrike - dblForward),
  235.                 dblPutProb1,
  236.                 dblPutProb2,
  237.                 -1. * dblPutProb1,
  238.                 dblVega,
  239.                 dblTimeDecay + dblRiskFreeRate * dblStrike * dblPutProb2,
  240.                 -1. * dblStrike * dblTimeToExpiry * dblPutProb2,
  241.                 dblGamma,
  242.                 dblVanna,
  243.                 dblVomma,
  244.                 dblCharm,
  245.                 dblVeta,
  246.                 dblColor,
  247.                 dblSpeed,
  248.                 dblUltima
  249.             );
  250.         } catch (java.lang.Exception e) {
  251.             e.printStackTrace();
  252.         }

  253.         return null;
  254.     }
  255. }