This example evaluates the price of a European Option using two payoff strategies: Cash-or-Nothing and Vertical Spread. In the first case the payoff function is
import com.imsl.math.*;
import java.util.*;
public class FeynmanKacEx3 {
public static void main(String args[]) throws Exception {
int i;
int nxGrid = 61;
int ntGrid = 2;
int nv = 12;
// The strike price
double strikePrice = 10.0;
// The spread value
double spreadValue = 15.0;
// The Bet for the Cash-or-Nothing Call
double bet = 2.0;
// The sigma value
double sigma = 0.4;
// Time values for the options
int nt = 2;
double[] tGrid = {0.25, 0.5};
// Values of the underlying where evaluations are made
double[] evaluationPoints = new double[nv];
// Value of the interest rate and continuous dividend
double r = 0.1, dividend = 0.0;
// Values of the min and max underlying values modeled
double xMin = 0.0, xMax = 30.0;
// Define parameters for the integration step.
int nint = nxGrid - 1, n = 3 * nxGrid;
double[] xGrid = new double[nxGrid];
double dx;
// Number of left/right boundary conditions.
int nlbcd = 3, nrbcd = 3;
// Structure for the evaluation routines.
int iData;
double[] rData = new double[7];
boolean[] timeDependence = new boolean[7];
// Define an equally-spaced grid of points for the
// underlying price
dx = (xMax - xMin) / ((double) (nint));
xGrid[0] = xMin;
xGrid[nxGrid - 1] = xMax;
for (i = 2; i <= nxGrid - 1; i++) {
xGrid[i - 1] = xGrid[i - 2] + dx;
}
for (i = 1; i <= nv; i++) {
evaluationPoints[i - 1] = 2.0 + (i - 1) * 2.0;
}
rData[0] = strikePrice;
rData[1] = bet;
rData[2] = spreadValue;
rData[3] = xMax;
rData[4] = sigma;
rData[5] = r;
rData[6] = dividend;
// Flag the difference in payoff functions
// 1 for the Bet, 2 for the Vertical Spread
// In both cases, no time dependencies for
// the coefficients and the left boundary
// conditions
timeDependence[5] = true;
iData = 1;
FeynmanKac betOption = new FeynmanKac(new MyCoefficients(rData));
betOption.setTimeDependence(timeDependence);
betOption.computeCoefficients(nlbcd, nrbcd,
new MyBoundaries(rData,iData), xGrid, tGrid);
double[][] betOptionCoefficients = betOption.getSplineCoefficients();
double[][] splineValuesBetOption = new double[ntGrid][];
iData = 2;
FeynmanKac spreadOption = new FeynmanKac(new MyCoefficients(rData));
spreadOption.setTimeDependence(timeDependence);
spreadOption.computeCoefficients(nlbcd, nrbcd,
new MyBoundaries(rData,iData), xGrid, tGrid);
double[][] spreadOptionCoefficients=spreadOption.getSplineCoefficients();
double[][] splineValuesSpreadOption = new double[ntGrid][];
// Evaluate solutions at vector evaluationPoints, at each time value
// prior to expiration.
for (i = 0; i < ntGrid; i++) {
splineValuesBetOption[i] = betOption.getSplineValue(evaluationPoints,
betOptionCoefficients[i + 1], 0);
splineValuesSpreadOption[i] = spreadOption.getSplineValue(
evaluationPoints, spreadOptionCoefficients[i + 1], 0);
}
System.out.printf("%2sEuropean Option Value for A Bet%n", " ");
System.out.printf("%3sand a Vertical Spread, 3 and 6 Months " +
"Prior to Expiry%n", " ");
System.out.printf("%5sNumber of equally spaced spline knots:%4d%n",
" ", nxGrid);
System.out.printf("%5sNumber of unknowns:%4d\n", " ", n);
System.out.printf(Locale.ENGLISH,
"%5sStrike=%5.2f, Sigma=%5.2f, Interest Rate=" + "%5.2f%n", " ",
strikePrice, sigma, r);
System.out.printf(Locale.ENGLISH,
"%5sBet=%5.2f, Spread Value=%5.2f%n%n",
" ", bet, spreadValue);
System.out.printf("%17s%18s%18s%n", "Underlying", "A Bet",
"Vertical Spread");
for (i = 0; i < nv; i++) {
System.out.printf(Locale.ENGLISH,
"%8s%9.4f%9.4f%9.4f%9.4f%9.4f%n", " ",
evaluationPoints[i],
splineValuesBetOption[0][i],
splineValuesBetOption[1][i],
splineValuesSpreadOption[0][i],
splineValuesSpreadOption[1][i]);
}
}
// These routines define the coefficients, payoff, boundary conditions
// and forcing term for American and European Options.
static class MyCoefficients implements FeynmanKac.PdeCoefficients {
final double zero = 0.0;
double sigma, strikePrice, interestRate;
double spread, bet, dividend;
int dataInt;
double value = 0.0;
public MyCoefficients(double[] rData) {
this.strikePrice = rData[0];
this.bet = rData[1];
this.spread = rData[2];
this.sigma = rData[4];
this.interestRate = rData[5];
this.dividend = rData[6];
}
// The coefficient sigma(x)
public double sigma(double x, double t) {
return (sigma * x);
}
// The coefficient derivative d(sigma) / dx
public double sigmaPrime(double x, double t) {
return sigma;
}
// The coefficient mu(x)
public double mu(double x, double t) {
return ((interestRate - dividend) * x);
}
// The coefficient kappa(x)
public double kappa(double x, double t) {
return interestRate;
}
}
static class MyBoundaries implements FeynmanKac.Boundaries {
private double strikePrice, spread, bet, interestRate, df;
private int dataInt;
public MyBoundaries(double[] rData, int iData) {
this.strikePrice = rData[0];
this.bet = rData[1];
this.spread = rData[2];
this.interestRate = rData[5];
this.dataInt = iData;
}
public void leftBoundaries(double time, double[][] bndCoeffs) {
bndCoeffs[0][0] = 1.0;
bndCoeffs[0][1] = 0.0;
bndCoeffs[0][2] = 0.0;
bndCoeffs[0][3] = 0.0;
bndCoeffs[1][0] = 0.0;
bndCoeffs[1][1] = 1.0;
bndCoeffs[1][2] = 0.0;
bndCoeffs[1][3] = 0.0;
bndCoeffs[2][0] = 0.0;
bndCoeffs[2][1] = 0.0;
bndCoeffs[2][2] = 1.0;
bndCoeffs[2][3] = 0.0;
return;
}
public void rightBoundaries(double time, double[][] bndCoeffs) {
// This is the discount factor using the risk-free
// interest rate
df = Math.exp(interestRate * time);
// Use flag passed to decide on boundary condition
switch (dataInt) {
case 1:
bndCoeffs[0][0] = 1.0;
bndCoeffs[0][1] = 0.0;
bndCoeffs[0][2] = 0.0;
bndCoeffs[0][3] = bet * df;
break;
case 2:
bndCoeffs[0][0] = 1.0;
bndCoeffs[0][1] = 0.0;
bndCoeffs[0][2] = 0.0;
bndCoeffs[0][3] = (spread - strikePrice) * df;
break;
}
bndCoeffs[1][0] = 0.0;
bndCoeffs[1][1] = 1.0;
bndCoeffs[1][2] = 0.0;
bndCoeffs[1][3] = 0.0;
bndCoeffs[2][0] = 0.0;
bndCoeffs[2][1] = 0.0;
bndCoeffs[2][2] = 1.0;
bndCoeffs[2][3] = 0.0;
return;
}
public double terminal(double x) {
final double zero = 0.0;
double value = 0.0;
switch (dataInt) {
// The payoff function - Use flag passed to decide which
case 1:
// After reaching the strike price the payoff jumps
// from zero to the bet value.
value = zero;
if (x > strikePrice) {
value = bet;
}
break;
case 2:
/* Function is zero up to strike price.
Then linear between strike price and spread.
Then has constant value Spread-Strike Price after
the value Spread. */
value = Math.max(x - strikePrice,zero)-Math.max(x - spread,zero);
break;
}
return value;
}
}
}
European Option Value for A Bet
and a Vertical Spread, 3 and 6 Months Prior to Expiry
Number of equally spaced spline knots: 61
Number of unknowns: 183
Strike=10.00, Sigma= 0.40, Interest Rate= 0.10
Bet= 2.00, Spread Value=15.00
Underlying A Bet Vertical Spread
2.0000 -0.0000 0.0000 -0.0000 0.0000
4.0000 0.0000 0.0013 0.0000 0.0005
6.0000 0.0112 0.0729 0.0038 0.0452
8.0000 0.2686 0.4291 0.1486 0.3833
10.0000 0.9948 0.9781 0.8898 1.1907
12.0000 1.6103 1.4301 2.1904 2.2267
14.0000 1.8650 1.6926 3.4267 3.1567
16.0000 1.9335 1.8171 4.2274 3.8282
18.0000 1.9477 1.8696 4.6261 4.2499
20.0000 1.9501 1.8902 4.7903 4.4918
22.0000 1.9505 1.8979 4.8493 4.6222
24.0000 1.9506 1.9008 4.8685 4.6901
Link to Java source.