/** * 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.BoundaryCondition; import com.opengamma.analytics.financial.model.finitedifference.DirichletBoundaryCondition; import com.opengamma.analytics.financial.model.finitedifference.ExtendedCoupledFiniteDifference; import com.opengamma.analytics.financial.model.finitedifference.ExtendedCoupledPDEDataBundle; import com.opengamma.analytics.financial.model.finitedifference.NeumannBoundaryCondition; import com.opengamma.analytics.financial.model.finitedifference.PDEFullResults1D; import com.opengamma.analytics.financial.model.finitedifference.PDEGrid1D; import com.opengamma.analytics.financial.model.finitedifference.PDEResults1D; 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.FunctionalDoublesSurface; /** * */ @SuppressWarnings("deprecation") public class TwoStateMarkovChainWithLocalVolDensity { private static final double THETA = 1.0; private final ExtendedCoupledPDEDataBundle _data1; private final ExtendedCoupledPDEDataBundle _data2; public TwoStateMarkovChainWithLocalVolDensity(final ForwardCurve forward, final TwoStateMarkovChainDataBundle data, final AbsoluteLocalVolatilitySurface localVolOverlay) { Validate.notNull(forward, "null forward"); Validate.notNull(data, "null data"); Validate.notNull(localVolOverlay, "null localVolOverlay"); // _data1 = getCoupledPDEDataBundle(forward, data.getVol1(), data.getLambda12(), data.getLambda21(), data.getP0(), data.getBeta1(), localVol); // _data2 = getCoupledPDEDataBundle(forward, data.getVol2(), data.getLambda21(), data.getLambda12(), 1.0 - data.getP0(), data.getBeta2(), localVol); _data1 = getExtendedCoupledPDEDataBundle(forward, data.getVol1(), data.getLambda12(), data.getLambda21(), data.getP0(), data.getBeta1(), localVolOverlay); _data2 = getExtendedCoupledPDEDataBundle(forward, data.getVol2(), data.getLambda21(), data.getLambda12(), 1.0 - data.getP0(), data.getBeta2(), localVolOverlay); } PDEFullResults1D[] solve(final PDEGrid1D grid) { final BoundaryCondition lower = new NeumannBoundaryCondition(0.0, grid.getSpaceNode(0), true); //BoundaryCondition lower = new DirichletBoundaryCondition(0.0, 0.0);//TODO for beta < 0.5 zero is accessible and thus there will be non-zero //density there final BoundaryCondition upper = new DirichletBoundaryCondition(0.0, grid.getSpaceNode(grid.getNumSpaceNodes() - 1)); final ExtendedCoupledFiniteDifference solver = new ExtendedCoupledFiniteDifference(THETA); final PDEResults1D[] res = solver.solve(_data1, _data2, grid, lower, upper, lower, upper, null); //handle this with generics final PDEFullResults1D res1 = (PDEFullResults1D) res[0]; final PDEFullResults1D res2 = (PDEFullResults1D) res[1]; return new PDEFullResults1D[] {res1, res2 }; } private ExtendedCoupledPDEDataBundle getExtendedCoupledPDEDataBundle(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); } }