/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.finitedifference;
import static org.testng.AssertJUnit.assertEquals;
import org.apache.commons.lang.Validate;
import org.testng.annotations.Test;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackPriceFunction;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.math.cube.Cube;
import com.opengamma.analytics.math.cube.FunctionalDoublesCube;
import com.opengamma.analytics.math.function.Function;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.surface.FunctionalDoublesSurface;
import com.opengamma.util.test.TestGroup;
/**
* @deprecated This class tests deprecated functionality
*/
@Deprecated
@Test(groups = TestGroup.UNIT)
public class SpreadOptionPDETestCase {
private static BoundaryCondition2D A_LOWER;
private static BoundaryCondition2D A_UPPER;
private static BoundaryCondition2D B_LOWER;
private static BoundaryCondition2D B_UPPER;
private static final double SPOT_A = 100;
private static final double SPOT_B = 100;
private static final double T = 1.0;
private static final double RATE = 0.05;
private static final double VOL_A = 0.20;
private static final double VOL_B = 0.30;
private static final double RHO = -0.5;// used to be -0.5
private static final ConvectionDiffusion2DPDEDataBundle DATA;
private static Cube<Double, Double, Double, Double> A;
private static Cube<Double, Double, Double, Double> B;
private static Cube<Double, Double, Double, Double> C;
private static Cube<Double, Double, Double, Double> D;
private static Cube<Double, Double, Double, Double> E;
private static Cube<Double, Double, Double, Double> F;
static {
final Function<Double, Double> bZeroBoundary = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... tx) {
Validate.isTrue(tx.length == 2);
final double x = tx[1];
return x;
}
};
A_LOWER = new DirichletBoundaryCondition2D(0.0, 0.0);
// A_UPPER = new DirichletBoundaryCondition2D(0.0, 5 * SPOT_A);
// B_LOWER = new DirichletBoundaryCondition2D(0.0, 0.0);
// B_UPPER = new DirichletBoundaryCondition2D(0.0, 5 * SPOT_B);
A_UPPER = new SecondDerivativeBoundaryCondition2D(0.0, 5 * SPOT_A);
// B_LOWER = new SecondDerivativeBoundaryCondition2D(0.0, 0);
B_LOWER = new DirichletBoundaryCondition2D(FunctionalDoublesSurface.from(bZeroBoundary), 0.0);// option value = Spot_A when Spot_B = 0
B_UPPER = new SecondDerivativeBoundaryCondition2D(0.0, 5 * SPOT_B);
final Function<Double, Double> a = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
final double x = txy[1];
return -x * x * VOL_A * VOL_A / 2;
}
};
A = FunctionalDoublesCube.from(a);
final Function<Double, Double> b = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
final double x = txy[1];
return -x * RATE;
}
};
B = FunctionalDoublesCube.from(b);
final Function<Double, Double> c = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
return RATE;
}
};
C = FunctionalDoublesCube.from(c);
final Function<Double, Double> d = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
final double y = txy[2];
return -y * y * VOL_B * VOL_B / 2;
}
};
D = FunctionalDoublesCube.from(d);
final Function<Double, Double> e = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
final double x = txy[1];
final double y = txy[2];
return -x * y * VOL_A * VOL_B * RHO;
}
};
E = FunctionalDoublesCube.from(e);
final Function<Double, Double> f = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... txy) {
Validate.isTrue(txy.length == 3);
final double y = txy[2];
return -y * RATE;
}
};
F = FunctionalDoublesCube.from(f);
final Function<Double, Double> payoff = new Function<Double, Double>() {
@Override
public Double evaluate(final Double... xy) {
Validate.isTrue(xy.length == 2);
final double x = xy[0];
final double y = xy[1];
return Math.max(x - y, 0);// debug
// return Math.max(x - SPOT_A, 0);
}
};
DATA = new ConvectionDiffusion2DPDEDataBundle(A, B, C, D, E, F, FunctionalDoublesSurface.from(payoff));
}
public void testAgaintBSPrice(final ConvectionDiffusionPDESolver2D solver, final int timeSteps, final int spotASteps, final int spotBSteps) {
final double[][] res = solver.solve(DATA, timeSteps, spotASteps, spotBSteps, T, A_LOWER, A_UPPER, B_LOWER, B_UPPER);
// for (int i = 0; i <= spotASteps; i++) {
// for (int j = 0; j <= spotBSteps; j++) {
// System.out.print(res[i][j] + "\t");
// }
// System.out.print("\n");
// }
final double vol = Math.sqrt(VOL_A * VOL_A + VOL_B * VOL_B - 2 * RHO * VOL_A * VOL_B);
final double forward = SPOT_A / SPOT_B;
final double strike = 1.0;
final BlackFunctionData data = new BlackFunctionData(forward, SPOT_B, vol);
final EuropeanVanillaOption option = new EuropeanVanillaOption(strike, T, true);
final BlackPriceFunction pricer = new BlackPriceFunction();
final Function1D<BlackFunctionData, Double> func = pricer.getPriceFunction(option);
final double price = func.evaluate(data);
final double pdfPrice = res[(int) (SPOT_A * spotASteps / (A_UPPER.getLevel() - A_LOWER.getLevel()))][(int) (SPOT_B * spotBSteps / (B_UPPER.getLevel() - B_LOWER.getLevel()))];
// System.out.println(price+"\t"+pdfPrice);
assertEquals(price, pdfPrice, 1e-1);
}
}