Package com.opengamma.analytics.financial.model.finitedifference.applications

Source Code of com.opengamma.analytics.financial.model.finitedifference.applications.CoupledPDEDataBundleProvider

/**
* Copyright (C) 2011 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.finitedifference.applications;

import org.apache.commons.lang.Validate;

import com.opengamma.analytics.financial.model.finitedifference.ConvectionDiffusionPDE1DCoupledCoefficients;
import com.opengamma.analytics.financial.model.finitedifference.ExtendedCoupledPDEDataBundle;
import com.opengamma.analytics.financial.model.interestrate.curve.ForwardCurve;
import com.opengamma.analytics.financial.model.volatility.local.AbsoluteLocalVolatilitySurface;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.statistics.distribution.NormalDistribution;
import com.opengamma.analytics.math.surface.ConstantDoublesSurface;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;

/**
*
*/
@SuppressWarnings("deprecation")
public class CoupledPDEDataBundleProvider {

  /**
   * Set up a backwards coupled PDE for a model where the underlying follows the SDE $ds = \mu(t)sdt + \sigma_i s^{\beta} dW$, with local volatility overlay
   *  $\sigma(t,s)$ and level $\sigma_i $ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain. The
   *  resulting pair of PDEs is $$\begin{eqnarray}
   *  \frac{\partial V_1}{\partial \tau} - \frac{\sigma_1^2 s^{2\beta}}{2} \frac{\partial^2 V_1}{\partial s^2}
   *  -\mu(t)s \frac{\partial V_1}{\partial s} + (\mu(t) + \lambda_{12})V_1 - \lambda_{12} V_2= 0 \\
   *  \frac{\partial V_2}{\partial \tau} - \frac{\sigma_2^2 s^{2\beta}}{2} \frac{\partial^2 V_2}{\partial s^2} -\mu(t)s \frac{\partial V_2}{\partial s}
   *  + (\mu(t) + \lambda_{21})V_2 - \lambda_{21} V_1= 0
   *  \end{eqnarray}$$
   *  As usual with the backwards PDEs, 'time' is time-to-maturity ($\tau$) and thus starts at zero (i.e. at maturity). The initial condition is a call payoff (so
   *  $V_1(0,s) = V_2(0,s) = (s-k)^+$). Real (i.e. calendar) time, $t$, appears in the drift term with $t = T - \tau$ where $T$
   *  is the maturity. The solution at $t=0$ $(\tau=T)$ for $V_1$ and $V_2$ is the option price if the Markov chain started in state 1 or 2. If the
   *  initial state of the Markov chain is unknown (but the probability of being in a state is known), then the option price is the probability weighting of the two solutions.
   * @param forward The forward curve
   * @param maturity The option maturity (in years)
   * @param data Data relating to the Markov chain
   * @return a pair of convection diffusion data bundles
   */
  public ConvectionDiffusionPDE1DCoupledCoefficients[] getCoupledBackwardsPair(final ForwardCurve forward, final double maturity, final TwoStateMarkovChainDataBundle data) {
    final AbsoluteLocalVolatilitySurface localVolOverlay = new AbsoluteLocalVolatilitySurface(ConstantDoublesSurface.from(1.0));
    return getCoupledBackwardsPair(forward, maturity, data, localVolOverlay);
  }

  /**
   * Set up a backwards coupled PDE for a model where the underlying follows the SDE $ ds = \mu(t)sdt + \sigma(t,s)\sigma_i s^{\beta} dW$, with local volatility overlay
   *  $\sigma(t,s)$ and level $\sigma_i $ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain. The
   *  resulting pair of PDEs is $$\begin{eqnarray}
   *  \frac{\partial V_1}{\partial \tau} - \sigma(t,s)\frac{\sigma_1^2 s^{2\beta}}{2} \frac{\partial^2 V_1}{\partial s^2}
   *  -\mu(t)s \frac{\partial V_1}{\partial s} + (\mu(t) + \lambda_{12})V_1 - \lambda_{12} V_2= 0 \\
   * \frac{\partial V_2}{\partial \tau} - \sigma(t,s)\frac{\sigma_2^2 s^{2\beta}}{2} \frac{\partial^2 V_2}{\partial s^2} -\mu(t)s \frac{\partial V_2}{\partial s}
   * + (\mu(t) + \lambda_{21})V_2 - \lambda_{21} V_1= 0
   * \end{eqnarray}$$
   *  As usual with the backwards PDEs, 'time' is time-to-maturity ($\tau$) and thus starts at zero (i.e. at maturity). The initial condition is a call payoff (so
   *  $V_1(0,s) = V_2(0,s) = (s-k)^+$). Real (i.e. calendar) time, $t$, appears in the local volatility and drift terms with $t = T - \tau$ where $T$
   *  is the maturity. The solution at $t = 0$ $(\tau=T)$ for $V_1$ and $V_2$ is the option price if the Markov chain started in state 1 or 2. If the
   *  initial state of the Markov chain is unknown (but the probability of being in a state is know), then the option price is the probability weighting of the two solutions.
   * @param forward The forward curve
   * @param maturity The option maturity (in years)
   * @param data Data relating to the Markov chain
   * @param localVolOverlay The local vol term
   * @return a pair of convection diffusion data bundles
   */
  public ConvectionDiffusionPDE1DCoupledCoefficients[] getCoupledBackwardsPair(final ForwardCurve forward, final double maturity, final TwoStateMarkovChainDataBundle data,
      final AbsoluteLocalVolatilitySurface localVolOverlay) {
    Validate.notNull(forward, "null forward");
    Validate.notNull(data, "null data");
    Validate.notNull(localVolOverlay, "null localVolOverlay");

    final ConvectionDiffusionPDE1DCoupledCoefficients[] res = new ConvectionDiffusionPDE1DCoupledCoefficients[2];
    res[0] = getCoupledBackwardsPDE(forward, data.getVol1(), maturity, data.getLambda12(), data.getBeta1(), localVolOverlay);
    res[1] = getCoupledBackwardsPDE(forward, data.getVol2(), maturity, data.getLambda21(), data.getBeta2(), localVolOverlay);
    return res;
  }

  /**
   *  Set up a forward coupled PDE for a model where the underlying follows the SDE $ds = \mu(t)sdt + \sigma_i s^{\beta} dW$, with
   *  level  $\sigma_i$ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain,
   *  and the payoff is a standard European call. The coupled PDEs are in maturity ($T$) and strike ($k$) coordinates and read
   *   $$\begin{eqnarray}\frac{\partial V_1}{\partial T}  - \frac{\sigma_1^2 k^{2\beta}}{2}
   *   \frac{\partial^2 V_1}{\partial k^2} -\mu(T)k \frac{\partial V_1}{\partial k} + \lambda_{12}V_1 - \lambda_{21} V_2= 0 \\
   *   \frac{\partial V_2}{\partial T}  - \frac{\sigma_2^2 k^{2\beta}}{2}
   *  \frac{\partial^2 V_2}{\partial k^2} -\mu(T)k \frac{\partial V_2}{\partial k} + \lambda_{21}V_2 - \lambda_{12} V_1= 0
   *  \end{eqnarray}$$
   *  The initial condition is $V_1(0,k) = p_1(0)(s_0-k)^+$ and $V_2(0,k) = p_2(0)(s_0-k)^+$ where $p_1(0)$ and $p_2(0)$ are the probabilities
   *  of the Markov chain starting in a given state and $s_0$ is the spot. The option value at a particular maturity ($T$) and strike ($k$) is given by
   *   $V(T,k) = V_1(T,k) + V_2(T,k)$
   * @param forward  The forward curve
   * @param data Data relating to the Markov chain
   * @return a pair of convection diffusion data bundles
   */
  public ConvectionDiffusionPDE1DCoupledCoefficients[] getCoupledForwardPair(final ForwardCurve forward, final TwoStateMarkovChainDataBundle data) {
    final AbsoluteLocalVolatilitySurface localVolOverlay = new AbsoluteLocalVolatilitySurface(ConstantDoublesSurface.from(1.0));
    return getCoupledForwardPair(forward, data, localVolOverlay);
  }

  /**
   *  Set up a forward coupled PDE for a model where the underlying follows the SDE $ ds = \mu(t)sdt + \sigma(t,s)\sigma_i s^{\beta} dW$, with local volatility overlay
   *  $\sigma(t,s)$ and level $\sigma_i $ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain,
   *  and the payoff is a standard European call. The coupled PDEs are in maturity (T) and strike (k) coordinates and read
   *   $$\begin{eqnarray}\frac{\partial V_1}{\partial T}  - \sigma(T,k)\frac{\sigma_1^2 k^{2\beta}}{2}
   *   \frac{\partial^2 V_1}{\partial k^2} -\mu(T)k \frac{\partial V_1}{\partial k} + \lambda_{12}V_1 - \lambda_{21} V_2= 0 \\
   *   \frac{\partial V_2}{\partial T}  - \sigma(T,k)\frac{\sigma_2^2 k^{2\beta}}{2}
   *  \frac{\partial^2 V_2}{\partial k^2} -\mu(T)k \frac{\partial V_2}{\partial k} + \lambda_{21}V_2 - \lambda_{12} V_1= 0 \end{eqnarray}$$
   *  The initial condition is $V_1(0,k) = p_1(0)(s_0-k)^+$ and $V_2(0,k) = p_2(0)(s_0-k)^+$ where $p_1(0)$ and $p_2(0)$ are the probabilities
   *  of the Markov chain starting in a given state and $s_0$ is the spot. The option value at a particular maturity ($T$) and strike ($k$) is given by
   *   $V(T,k) = V_1(T,k) + V_2(T,k)$
   * @param forward  The forward curve
   * @param data Data relating to the Markov chain
   * @param localVolOverlay The local vol term
   * @return a pair of convection diffusion data bundles
   */
  public ConvectionDiffusionPDE1DCoupledCoefficients[] getCoupledForwardPair(final ForwardCurve forward, final TwoStateMarkovChainDataBundle data,
      final AbsoluteLocalVolatilitySurface localVolOverlay) {
    Validate.notNull(forward, "null forward");
    Validate.notNull(data, "null data");
    Validate.notNull(localVolOverlay, "null localVolOverlay");

    final ConvectionDiffusionPDE1DCoupledCoefficients[] res = new ConvectionDiffusionPDE1DCoupledCoefficients[2];
    res[0] = getCoupledForwardPDE(forward, data.getVol1(), data.getLambda12(), data.getLambda21(), data.getBeta1(), localVolOverlay);
    res[1] = getCoupledForwardPDE(forward, data.getVol2(), data.getLambda21(), data.getLambda12(), data.getBeta2(), localVolOverlay);
    return res;
  }

  /**
   * Set up a coupled Fokker-Plank PDE for a model where the underlying follows the SDE $ ds = \mu(t)sdt + \sigma_i s^{\beta} dW$, with  level
   *  $\sigma_i$ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain. The resultant PDE is
   *  $$\begin{eqnarray}\frac{\partial \rho_1}{\partial t}  -  \frac{\partial^2 }{\partial s^2}\left[\frac{\sigma_1^2 s^{2\beta}}{2}\rho_1 \right] -
   *  \frac{\partial}{\partial s}\left[\mu(t)s\rho_1\right] + \lambda_{12}\rho_1 - \lambda_{21}\rho_2= 0 \\
   *  \frac{\partial \rho_2}{\partial t}  - \frac{\partial^2 }{\partial s^2}\left[\frac{\sigma_2^2 s^{2\beta}}{2}\rho_2 \right] -
   *  \frac{\partial }{\partial s}\left[\mu(t)s\rho_2\right] + \lambda_{21}\rho_2 - \lambda_{12} \rho_1= 0
   *  \end{eqnarray}$$ where $\rho_i(t,s)$ is the probabilty density
   *  of being in state $i$ with a value of the underlying $s$ at time $t$. The inital state is $\rho_i(0,s) = p_i(0)\delta(s-s_0)$ where $p_i(0)$
   *  is the probability of the Markov chain starting in state $i$ and $s_0$ is the spot. Since a delta function cannot be used directly it is replaced with a
   *  log-normal distrubution (of $s/s_0$) with a standard deviation of 0.01;
   * @param forward The forward curve
   * @param data Data relating to the Markov chain
   * @return a pair of extended convection diffusion data bundles
   */
  public ExtendedCoupledPDEDataBundle[] getCoupledFokkerPlankPair(final ForwardCurve forward, final TwoStateMarkovChainDataBundle data) {
    final AbsoluteLocalVolatilitySurface localVolOverlay = new AbsoluteLocalVolatilitySurface(ConstantDoublesSurface.from(1.0));
    return getCoupledFokkerPlankPair(forward, data, localVolOverlay);
  }

  /**
   * Set up a coupled Fokker-Plank PDE for a model where the underlying follows the SDE $ ds = \mu(t)sdt + \sigma(t,s)\sigma_i s^{\beta} dW$, with local volatility overlay
   *  $\sigma(t,s)$ and level $\sigma_i $ which takes on one of two values depending on the state of the continuous 2-state hidden Markov chain.
   *  The resultant PDE is
   *  $$\begin{eqnarray}\frac{\partial \rho_1}{\partial t} - \frac{\partial^2 }{\partial s^2}\left[ \sigma(t,s)\frac{\sigma_1^2 s^{2\beta}}{2}\rho_1 \right] -
   *  \frac{\partial}{\partial s}\left[\mu(t)s\rho_1\right] + \lambda_{12}\rho_1 - \lambda_{21}\rho_2= 0 \\
   *  \frac{\partial \rho_2}{\partial t} - \frac{\partial^2 }{\partial s^2}\left[ \sigma(t,s)\frac{\sigma_2^2 s^{2\beta}}{2}\rho_2 \right] -
   *  \frac{\partial }{\partial s}\left[\mu(t)s\rho_2\right] + \lambda_{21}\rho_2 - \lambda_{12} \rho_1= 0
   *  \end{eqnarray}$$ where $\rho_i(t,s)$ is the probabilty density
   *  of being in state $i$ with a value of the underlying $s$ at time $t$. The initial state is $\rho_i(0,s) = p_i(0)\delta(s-s_0)$ where $p_i(0)$
   *  is the probability of the Markov chain starting in state $i$ and $s_0$ is the spot. Since a delta function cannot be used directly it is replaced with a
   *  log-normal distrubution (of $s/s_0$) with a standard deviation of 0.01;
   * @param forward The forward curve
   * @param data Data relating to the Markov chain
   * @param localVolOverlay  The local vol term
   * @return a pair of extended convection diffusion data bundles
   */
  public ExtendedCoupledPDEDataBundle[] getCoupledFokkerPlankPair(final ForwardCurve forward, final TwoStateMarkovChainDataBundle data, final AbsoluteLocalVolatilitySurface localVolOverlay) {
    Validate.notNull(forward, "null forward");
    Validate.notNull(data, "null data");
    Validate.notNull(localVolOverlay, "null localVolOverlay");

    final ExtendedCoupledPDEDataBundle[] res = new ExtendedCoupledPDEDataBundle[2];
    res[0] = getCoupledFokkerPlank(forward, data.getVol1(), data.getLambda12(), data.getLambda21(), data.getP0(), data.getBeta1(), localVolOverlay);
    res[1] = getCoupledFokkerPlank(forward, data.getVol2(), data.getLambda21(), data.getLambda12(), 1.0 - data.getP0(), data.getBeta2(), localVolOverlay);

    return res;
  }

  private ConvectionDiffusionPDE1DCoupledCoefficients getCoupledBackwardsPDE(final ForwardCurve forward, final double vol, final double maturity, final double lambda, final double beta,
      final AbsoluteLocalVolatilitySurface localVol) {

    final Function<Double, Double> a = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double tau = ts[0];
        final double s = ts[1];
        final double t = maturity - tau;
        final double temp = vol * Math.pow(s, beta) * localVol.getVolatility(t, s);
        return -0.5 * temp * temp;
      }
    };

    final Function<Double, Double> b = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double tau = ts[0];
        final double s = ts[1];
        final double t = maturity - tau;
        return -s * forward.getDrift(t);
      }
    };

    final Function<Double, Double> c = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double tau = ts[0];
        final double t = maturity - tau;
        return forward.getDrift(t) + lambda;
      }
    };

    return new ConvectionDiffusionPDE1DCoupledCoefficients(FunctionalDoublesSurface.from(a), FunctionalDoublesSurface.from(b), FunctionalDoublesSurface.from(c), -lambda);
  }

  private ConvectionDiffusionPDE1DCoupledCoefficients getCoupledForwardPDE(final ForwardCurve forward, final double vol, final double lambda1, final double lambda2,
      final double beta,
      final AbsoluteLocalVolatilitySurface localVol) {

    final Function<Double, Double> a = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... tk) {
        Validate.isTrue(tk.length == 2);
        final double t = tk[0];
        final double k = tk[1];
        final double temp = vol * Math.pow(k, beta) * localVol.getVolatility(t, k);
        return -0.5 * temp * temp;
      }
    };

    final Function<Double, Double> b = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... tk) {
        Validate.isTrue(tk.length == 2);
        final double k = tk[1];
        return k * forward.getDrift(beta);
      }
    };

    final Function<Double, Double> c = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        return lambda1;
      }
    };

    return new ConvectionDiffusionPDE1DCoupledCoefficients(FunctionalDoublesSurface.from(a), FunctionalDoublesSurface.from(b), FunctionalDoublesSurface.from(c), -lambda2);
  }

  private ExtendedCoupledPDEDataBundle getCoupledFokkerPlank(final ForwardCurve forward, final double vol, final double lambda1, final double lambda2, final double initialProb, final double beta,
      final AbsoluteLocalVolatilitySurface localVol) {

    final Function<Double, Double> a = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        return -1.0;
      }
    };

    final Function<Double, Double> aStar = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double t = ts[0];
        final double s = ts[1];
        final double temp = localVol.getVolatility(t, s) * vol * Math.pow(s, beta);

        return 0.5 * temp * temp;
      }
    };

    final Function<Double, Double> b = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double t = ts[0];
        final double s = ts[1];
        return s * forward.getDrift(t);
      }
    };

    final Function<Double, Double> bStar = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        return 1.0;
      }
    };

    final Function<Double, Double> c = new Function<Double, Double>() {
      @Override
      public Double evaluate(final Double... ts) {
        Validate.isTrue(ts.length == 2);
        final double t = ts[0];

        return forward.getDrift(t) + lambda1;
      }
    };

    //using a log-normal distribution with a very small Standard deviation as a proxy for a Dirac delta
    final Function1D<Double, Double> initialCondition = new Function1D<Double, Double>() {
      private final double _volRootTOffset = 0.01;

      @Override
      public Double evaluate(final Double s) {
        if (s == 0) {
          return 0.0;
        }
        final double x = Math.log(s / forward.getSpot());
        final NormalDistribution dist = new NormalDistribution(0, _volRootTOffset);
        return initialProb * dist.getPDF(x) / s;
      }
    };

    return new ExtendedCoupledPDEDataBundle(FunctionalDoublesSurface.from(a), FunctionalDoublesSurface.from(b), FunctionalDoublesSurface.from(c), FunctionalDoublesSurface.from(aStar),
        FunctionalDoublesSurface.from(bStar), -lambda2, initialCondition);

  }

}
TOP

Related Classes of com.opengamma.analytics.financial.model.finitedifference.applications.CoupledPDEDataBundleProvider

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.