/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.option.pricing.tree;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.model.option.definition.GeneralLogNormalOptionDataBundle;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.rootfinding.BracketRoot;
import com.opengamma.analytics.math.rootfinding.BrentSingleRootFinder;
import com.opengamma.analytics.math.rootfinding.RealSingleRootFinder;
import com.opengamma.util.tuple.DoublesPair;
/**
* Builds a binomial tree where the nodes are set to locally match a log-normal process. The process that the tree is emulating is of the form df/f = mu(f,t)dt + sigma(f,t)dw.
* From a node at (f,t) the two daughter nodes f+ and f- (at time t + dt) are set such that p*(1-p)*(ln(f+/f-))^2 = dt*sigma(f,t)^2, where p is the probability of reaching f+ from f.
* The forwarding condition is p*f+ + (1-p)*f- = f*exp(mu(f,t)*dt). This is adapted from the paper Derman and Kani, The Volatility Smile and Its Implied Tree
* @param <T> A GeneralLogNormalOptionDataBundle or anything that extends it
*/
public class LogNormalBinomialTreeBuilder<T extends GeneralLogNormalOptionDataBundle> extends BinomialTreeBuilder<T> {
private static final double EPS = 1e-8;
private static final RealSingleRootFinder s_root = new BrentSingleRootFinder();
private static BracketRoot s_bracketRoot = new BracketRoot();
@Override
protected double[] getForwards(double[] spots, T data, double t, double dt) {
int n = spots.length;
double[] forwards = new double[n];
for (int i = 0; i < n; i++) {
double drift = data.getLocalDrift(spots[i], t);
forwards[i] = spots[i] * Math.exp(drift * dt);
}
return forwards;
}
@Override
protected DoublesPair getCentralNodePair(double dt, double sigma, double forward, double centreLevel) {
Function1D<Double, Double> func = new CentreNode(dt, sigma, forward, centreLevel);
double[] limits = s_bracketRoot.getBracketedPoints(func, forward, forward * Math.exp(sigma * Math.sqrt(dt)));
double upper = s_root.getRoot(func, limits[0], limits[1]);
double lower = centreLevel * centreLevel / upper;
return DoublesPair.of(lower, upper);
}
@Override
protected double getNextHigherNode(double dt, double sigma, double forward, double lowerNode) {
Function1D<Double, Double> func = new UpperNodes(dt, sigma, forward, lowerNode);
double fTry = forward * Math.exp(sigma * Math.sqrt(dt));
//ensure we do not get p = 1 and thus a divide by zero
double[] limits = s_bracketRoot.getBracketedPoints(func, (forward - lowerNode) / 0.6 + lowerNode, (forward - lowerNode) / 0.4 + lowerNode, forward * (1 + EPS), 10 * fTry);
return s_root.getRoot(func, limits[0], limits[1]);
}
@Override
protected double getNextLowerNode(double dt, double sigma, double forward, double higherNode) {
if (forward == 0.0) {
return 0.0;
}
Function1D<Double, Double> func = new LowerNodes(dt, sigma, forward, higherNode);
double[] limits = s_bracketRoot.getBracketedPoints(func, forward * Math.exp(-sigma * Math.sqrt(dt)), forward);
return s_root.getRoot(func, limits[0], limits[1]);
}
/**
* The root of this function gives the next node above the currently know one
*/
private class UpperNodes extends Function1D<Double, Double> {
private double _rootdt;
private double _sigma;
private double _f;
private double _s;
public UpperNodes(final double dt, final double sigma, final double forward, final double s) {
_rootdt = Math.sqrt(dt);
_sigma = sigma;
_f = forward;
_s = s;
}
@Override
public Double evaluate(Double x) {
double p = (_f - _s) / (x - _s);
double res = _s * Math.exp(_rootdt * _sigma / Math.sqrt(p * (1 - p))) - x;
return res;
}
}
private class LowerNodes extends Function1D<Double, Double> {
private double _rootdt;
private double _sigma;
private double _f;
private double _s;
public LowerNodes(final double dt, final double sigma, final double forward, final double s) {
_rootdt = Math.sqrt(dt);
_sigma = sigma;
_f = forward;
_s = s;
}
@Override
public Double evaluate(Double x) {
double p = (_f - x) / (_s - x);
double res = _s * Math.exp(-_rootdt * _sigma / Math.sqrt(p * (1 - p))) - x;
return res;
}
}
private class CentreNode extends Function1D<Double, Double> {
private double _rootdt;
private double _sigma;
private double _f;
private double _spot;
public CentreNode(final double dt, final double sigma, final double forward, final double spot) {
_rootdt = Math.sqrt(dt);
_sigma = sigma;
_f = forward;
_spot = spot;
}
@Override
public Double evaluate(Double x) {
double p;
if (_f == _spot) {
p = _f / (x + _f);
} else {
Validate.isTrue(x != _spot, "invalide x");
p = (x * _f - _spot * _spot) / (x * x - _spot * _spot);
}
double res = _spot * _spot * Math.exp(_rootdt * _sigma / Math.sqrt(p * (1 - p))) - x * x;
return res;
}
}
}