Package com.opengamma.analytics.financial.model.volatility.local

Source Code of com.opengamma.analytics.financial.model.volatility.local.DermanKaniImpliedBinomialTreeModel

/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.volatility.local;

import org.apache.commons.lang.Validate;
import org.threeten.bp.ZonedDateTime;

import com.opengamma.analytics.financial.model.option.definition.BinomialOptionModelDefinition;
import com.opengamma.analytics.financial.model.option.definition.CoxRossRubinsteinBinomialOptionModelDefinition;
import com.opengamma.analytics.financial.model.option.definition.EuropeanVanillaOptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.OptionDefinition;
import com.opengamma.analytics.financial.model.option.definition.StandardOptionDataBundle;
import com.opengamma.analytics.financial.model.option.pricing.tree.BinomialOptionModel;
import com.opengamma.analytics.financial.model.tree.RecombiningBinomialTree;
import com.opengamma.util.time.DateUtils;
import com.opengamma.util.time.Expiry;

/**
* Implementation of the paper by Derman and Kani, The Volatility Smile and its Implied Tree (1994)
*/
public class DermanKaniImpliedBinomialTreeModel implements ImpliedTreeModel<OptionDefinition, StandardOptionDataBundle> {
  private static final BinomialOptionModelDefinition<OptionDefinition, StandardOptionDataBundle> CRR = new CoxRossRubinsteinBinomialOptionModelDefinition();
  private final int _n;

  public DermanKaniImpliedBinomialTreeModel(final int n) {
    Validate.isTrue(n > 0);
    _n = n;
  }
  @Override
  public ImpliedTreeResult getImpliedTrees(final OptionDefinition definition, final StandardOptionDataBundle data) {
    Validate.notNull(definition, "definition");
    Validate.notNull(data, "data");

    final int m1 = RecombiningBinomialTree.NODES.evaluate(_n);
    final int m2 = RecombiningBinomialTree.NODES.evaluate(_n - 1);
    final double[][] impliedTree = new double[_n + 1][m1]; //TODO this wastes space


    final double[] transitionProbabilities = new double[m2];
    double[] arrowDebreu = new double[m1];
    final double[][] localVolatilityTree = new double[_n][m2];
    final double dt = definition.getTimeToExpiry(data.getDate()) / _n;
    double t = 0;
    final double spot = data.getSpot();
    impliedTree[0][0] = spot;
    arrowDebreu[0] = 1;
    int previousNodes = 1;
    final ZonedDateTime date = data.getDate();
    for (int i = 1; i < _n + 1; i++) {
      final int nodes = RecombiningBinomialTree.NODES.evaluate(i);
      final BinomialOptionModel<StandardOptionDataBundle> crrModel = new BinomialOptionModel<>(CRR, i);
      t += dt;
      final double df1 = Math.exp(dt * data.getInterestRate(t));
      final double df2 = Math.exp(dt * data.getCostOfCarry());
      final Expiry expiry = new Expiry(DateUtils.getDateOffsetWithYearFraction(date, t));
      final int mid = i / 2;
      if (i % 2 == 0) {
        impliedTree[i][mid] = spot;
        addUpperNodes(data, impliedTree, arrowDebreu, i, crrModel, df1, df2, expiry, mid + 1);
        addLowerNodes(data, impliedTree, arrowDebreu, i, crrModel, df1, df2, expiry, mid - 1);
      } else {
        final double c = crrModel.getTreeGeneratingFunction(new EuropeanVanillaOptionDefinition(spot, expiry, true)).evaluate(data).getNode(0, 0).second;
        final double sigma = getUpperSigma(impliedTree, arrowDebreu, i - 1, df2, mid + 1);
        impliedTree[i][mid + 1] = spot * (df1 * c + arrowDebreu[mid] * spot - sigma) / (arrowDebreu[mid] * impliedTree[i - 1][mid] * df2 - df1 * c + sigma);
        impliedTree[i][mid] = spot * spot / impliedTree[i][mid + 1];
        addUpperNodes(data, impliedTree, arrowDebreu, i, crrModel, df1, df2, expiry, mid + 2);
        addLowerNodes(data, impliedTree, arrowDebreu, i, crrModel, df1, df2, expiry, mid - 1);
      }
      for (int j = 0; j < previousNodes; j++) {
        final double f = impliedTree[i - 1][j] * df2;
        transitionProbabilities[j] = (f - impliedTree[i][j]) / (impliedTree[i][j + 1] - impliedTree[i][j]);
        //TODO emcleod 31-8-10 Need to check that transition probabilities are positive - use adjustment suggested in "The Volatility Smile and its Implied Tree"
        localVolatilityTree[i - 1][j] = Math.sqrt(transitionProbabilities[j] * (1 - transitionProbabilities[j])) * Math.log(impliedTree[i][j + 1] / impliedTree[i][j]); //TODO need 1/sqrt(dt) here
      }
      final double[] temp = new double[m1];
      temp[0] = (1 - transitionProbabilities[0]) * arrowDebreu[0] / df1;
      temp[nodes - 1] = (transitionProbabilities[previousNodes - 1] * arrowDebreu[previousNodes - 1]) / df1;
      for (int j = 1; j < nodes - 1; j++) {
        temp[j] = (transitionProbabilities[j - 1] * arrowDebreu[j - 1] + (1 - transitionProbabilities[j]) * arrowDebreu[j]) / df1;
      }
      arrowDebreu = temp;
      previousNodes = nodes;
    }
    final Double[][] impliedTreeResult = new Double[_n + 1][m1];
    final Double[][] localVolResult = new Double[_n][m2];
    for (int i = 0; i < impliedTree.length; i++) {
      for (int j = 0; j < impliedTree[i].length; j++) {
        impliedTreeResult[i][j] = impliedTree[i][j];
        if (i < _n && j < m2) {
          localVolResult[i][j] = localVolatilityTree[i][j];
        }
      }
    }
    return new ImpliedTreeResult(new RecombiningBinomialTree<>(impliedTreeResult), new RecombiningBinomialTree<>(localVolResult));
  }

  private void addLowerNodes(final StandardOptionDataBundle data, final double[][] impliedTree, final double[] arrowDebreu, final int step,
      final BinomialOptionModel<StandardOptionDataBundle> crrModel, final double df1, final double df2, final Expiry expiry, final int mid) {
    double sigma = getLowerSigma(impliedTree, arrowDebreu, step - 1, df2, mid);
    for (int i = mid; i >= 0; i--) {
      final double p = crrModel.getTreeGeneratingFunction(new EuropeanVanillaOptionDefinition(impliedTree[step - 1][i], expiry, false)).evaluate(data).getNode(0, 0).second;
      final double forward = impliedTree[step - 1][i] * df2;
      impliedTree[step][i] = (impliedTree[step][i + 1] * (df1 * p - sigma) + arrowDebreu[i] * impliedTree[step - 1][i] * (forward - impliedTree[step][i + 1]))
          / (df1 * p - sigma + arrowDebreu[i] * (forward - impliedTree[step][i + 1]));
      if (i > 0) {
        sigma -= arrowDebreu[i - 1] * (impliedTree[step - 1][i] - impliedTree[step - 1][i - 1] * df2);
      }
    }
  }

  private void addUpperNodes(final StandardOptionDataBundle data, final double[][] impliedTree, final double[] arrowDebreu, final int step,
      final BinomialOptionModel<StandardOptionDataBundle> crrModel, final double df1, final double df2, final Expiry expiry, final int mid) {
    double sigma = getUpperSigma(impliedTree, arrowDebreu, step - 1, df2, mid);
    for (int i = mid; i < RecombiningBinomialTree.NODES.evaluate(step); i++) {
      final double c = crrModel.getTreeGeneratingFunction(new EuropeanVanillaOptionDefinition(impliedTree[step - 1][i - 1], expiry, true)).evaluate(data).getNode(0, 0).second;
      final double forward = impliedTree[step - 1][i - 1] * df2;
      impliedTree[step][i] = (impliedTree[step][i - 1] * (df1 * c - sigma) - arrowDebreu[i - 1] * impliedTree[step - 1][i - 1] * (forward - impliedTree[step][i - 1]))
          / (df1 * c - sigma - arrowDebreu[i - 1] * (forward - impliedTree[step][i - 1]));
      sigma -= arrowDebreu[i] * (impliedTree[step - 1][i] * df2 - impliedTree[step - 1][i - 1]);
    }
  }

  private double getLowerSigma(final double[][] impliedTree, final double[] arrowDebreu, final int previousStep, final double df2, final int start) {
    double sigma = 0;
    for (int i = start - 1; i >= 0; i--) {
      sigma += arrowDebreu[i] * (impliedTree[previousStep][start] - impliedTree[previousStep][i] * df2);
    }
    return sigma;
  }

  private double getUpperSigma(final double[][] impliedTree, final double[] arrowDebreu, final int previousStep, final double df2, final int start) {
    double sigma = 0;
    for (int i = start; i < RecombiningBinomialTree.NODES.evaluate(previousStep + 1); i++) {
      sigma += arrowDebreu[i] * (impliedTree[previousStep][i] * df2 - impliedTree[previousStep][start - 1]);
    }
    return sigma;
  }

}
TOP

Related Classes of com.opengamma.analytics.financial.model.volatility.local.DermanKaniImpliedBinomialTreeModel

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.