/**
* Copyright (C) 2012 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.finitedifference.applications;
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;
import com.opengamma.analytics.math.surface.Surface;
import com.opengamma.util.ArgumentChecker;
/**
*
*/
public class InitialConditionsProvider {
//*********************************************************************************************************
// Backwards PDE initial conditions
//*********************************************************************************************************
/**
* The payoff of a standard call or put option
* @param strike The strike
* @param isCall true for call
* @return the payoff function
*/
public Function1D<Double, Double> getEuropeanPayoff(final double strike, final boolean isCall) {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
if (isCall) {
return Math.max(0, x - strike);
}
return Math.max(0, strike - x);
}
};
}
/**
* The payoff of a standard call or put option when the spatial variable is the log-spot
* @param strike The strike
* @param isCall true for call
* @return the payoff function
*/
public Function1D<Double, Double> getLogEuropeanPayoff(final double strike, final boolean isCall) {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
final double s = Math.exp(x);
if (isCall) {
return Math.max(0, s - strike);
}
return Math.max(0, strike - s);
}
};
}
/**
* The payoff $\log(S_T)$ where $S_T$ is the price of the underlying at expiry
* @return The initial condition for PDE with underlying as spatial variable
*/
public Function1D<Double, Double> getLogContractPayoff() {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
return Math.log(x);
}
};
}
/**
* The payoff $\log(S_T)$ where $S_T$ is the price of the underlying at expiry
* @return The initial condition for PDE with log-underlying as spatial variable coordinate
*/
public Function1D<Double, Double> getLogContractPayoffInLogCoordinate() {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
return x;
}
};
}
//*********************************************************************************************************
// forward PDE initial conditions
//*********************************************************************************************************
/**
* The initial condition for the forward PDE for standard call or put option prices
* @param spot The initial level of the underlying
* @param isCall true for call
* @return the initial condition
*/
public Function1D<Double, Double> getForwardCallPut(final double spot, final boolean isCall) {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double k) {
if (isCall) {
return Math.max(0, spot - k);
}
return Math.max(0, k - spot);
}
};
}
/**
* The initial condition for the forward PDE for standard call or put option prices, when the spatial variable is moneyness
* @param isCall true for call
* @return the initial condition as a function of <b>moneyness</b> (strike/spot)
*/
public Function1D<Double, Double> getForwardCallPut(final boolean isCall) {
return new Function1D<Double, Double>() {
@Override
public Double evaluate(Double x) {
if (isCall) {
return Math.max(0, 1.0 - x);
}
return Math.max(0, x - 1.0);
}
};
}
public Function1D<Double, Double> getLogNormalDensity(final double forward, final double t, final double vol) {
ArgumentChecker.isTrue(forward > 0, "must have forward > 0");
ArgumentChecker.isTrue(t > 0, "must have t > 0");
ArgumentChecker.isTrue(vol > 0, "must have vol > 0");
final double sigmaRootT = vol * Math.sqrt(t);
return new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double s) {
if (s == 0) {
return 0.0;
}
final double x = Math.log(s / forward);
final NormalDistribution dist = new NormalDistribution(0, sigmaRootT);
return dist.getPDF(x) / s;
}
};
}
//************
// Free boundary
//***********
public Surface<Double, Double, Double> getAmericanEarlyExcise(final double strike, final boolean isCall) {
final Function1D<Double, Double> payoff = getEuropeanPayoff(strike, isCall);
final Function<Double, Double> temp = new Function<Double, Double>() {
@Override
public Double evaluate(Double... ts) {
double s = ts[1];
return payoff.evaluate(s);
}
};
return FunctionalDoublesSurface.from(temp);
}
}