com.opengamma.analytics.financial.model.option.pricing.tree.LogNormalBinomialTreeBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.opengamma.analytics.financial.model.option.pricing.tree.LogNormalBinomialTreeBuilder.java

Source

/**
 * 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 new DoublesPair(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;
        }
    }

}