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

Source Code of com.opengamma.analytics.financial.model.volatility.surface.BlackScholesMertonImpliedVolatilitySurfaceModel$MyBisectionSingleRootFinder

/**
* 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.surface;

import java.util.Map;

import org.apache.commons.lang.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.OptionPricingException;
import com.opengamma.analytics.financial.model.option.pricing.analytic.AnalyticOptionModel;
import com.opengamma.analytics.financial.model.option.pricing.analytic.BlackScholesMertonModel;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.rootfinding.SingleRootFinder;
import com.opengamma.analytics.math.surface.ConstantDoublesSurface;
import com.opengamma.util.ArgumentChecker;
import com.opengamma.util.tuple.DoublesPair;

/**
*
*/
public class BlackScholesMertonImpliedVolatilitySurfaceModel implements VolatilitySurfaceModel<Map<OptionDefinition, Double>, StandardOptionDataBundle> {
  private static final Logger s_logger = LoggerFactory.getLogger(BlackScholesMertonImpliedVolatilitySurfaceModel.class);
  private final AnalyticOptionModel<OptionDefinition, StandardOptionDataBundle> _bsm = new BlackScholesMertonModel();
  private SingleRootFinder<StandardOptionDataBundle, Double> _rootFinder;

  @Override
  public VolatilitySurface getSurface(final Map<OptionDefinition, Double> optionPrices, final StandardOptionDataBundle optionDataBundle) {
    Validate.notNull(optionPrices);
    ArgumentChecker.notEmpty(optionPrices, "option prices");
    Validate.notNull(optionDataBundle);
    if (optionPrices.size() > 1) {
      s_logger.info("Option price map had more than one entry: using the first pair to imply volatility");
    }
    final Map.Entry<OptionDefinition, Double> entry = optionPrices.entrySet().iterator().next();
    final Double price = entry.getValue();
    final Function1D<StandardOptionDataBundle, Double> pricingFunction = _bsm.getPricingFunction(entry.getKey());
    _rootFinder = new MyBisectionSingleRootFinder(optionDataBundle, price);
    return _rootFinder.getRoot(pricingFunction, optionDataBundle.withVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from(0))),
        optionDataBundle.withVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from(10)))).getVolatilitySurface();
  }

  private static class MyBisectionSingleRootFinder implements SingleRootFinder<StandardOptionDataBundle, Double> {
    private final StandardOptionDataBundle _data;
    private final double _price;
    private final DoublesPair _origin = DoublesPair.of(0., 0.);
    private static final double ACCURACY = 1e-12;
    private static final int MAX_ATTEMPTS = 10000;

    public MyBisectionSingleRootFinder(final StandardOptionDataBundle data, final double price) {
      _data = data;
      _price = price;
    }

    @Override
    public StandardOptionDataBundle getRoot(final Function1D<StandardOptionDataBundle, Double> function, final StandardOptionDataBundle... volData) {
      final StandardOptionDataBundle lowVolData = volData[0];
      final StandardOptionDataBundle highVolData = volData[1];
      final Double lowPrice = function.evaluate(lowVolData) - _price;
      if (Math.abs(lowPrice) < ACCURACY) {
        return lowVolData;
      }
      Double highPrice = function.evaluate(highVolData) - _price;
      if (Math.abs(highPrice) < ACCURACY) {
        return highVolData;
      }
      final double highVol = highVolData.getVolatilitySurface().getVolatility(_origin);
      final double lowVol = lowVolData.getVolatilitySurface().getVolatility(_origin);
      double dVol, midVol, rootVol;
      if (lowPrice < 0) {
        dVol = highVol - lowVol;
        rootVol = lowVol;
      } else {
        dVol = lowVol - highVol;
        rootVol = highVol;
      }
      StandardOptionDataBundle midVolData;
      for (int i = 0; i < MAX_ATTEMPTS; i++) {
        dVol *= 0.5;
        midVol = rootVol + dVol;
        midVolData = _data.withVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from((midVol))));
        highPrice = function.evaluate(midVolData) - _price;
        if (highPrice <= 0) {
          rootVol = midVol;
        }
        if (Math.abs(dVol) < ACCURACY) {
          return _data.withVolatilitySurface(new VolatilitySurface(ConstantDoublesSurface.from((midVol))));
        }
      }
      throw new OptionPricingException("Could not find volatility in " + MAX_ATTEMPTS + " attempts");
    }
  }
}
TOP

Related Classes of com.opengamma.analytics.financial.model.volatility.surface.BlackScholesMertonImpliedVolatilitySurfaceModel$MyBisectionSingleRootFinder

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.