/** * Copyright (C) 2013 - 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 com.google.common.primitives.Doubles; import com.opengamma.util.ArgumentChecker; /** * Provides payoff function and option price function for one-dimensional tree model */ public abstract class OptionFunctionProvider1D { private double _strike; private double _timeToExpiry; private int _steps; private double _sign; /** * Superclass constructor * @param strike Strike price * @param timeToExpiry Time to expiry * @param steps Number of steps * @param isCall True if call, false if put */ public OptionFunctionProvider1D(final double strike, final double timeToExpiry, final int steps, final boolean isCall) { ArgumentChecker.isTrue(strike > 0., "strike should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(strike), "strike should be finite"); ArgumentChecker.isTrue(timeToExpiry > 0., "timeToExpiry should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(timeToExpiry), "timeToExpiry should be finite"); ArgumentChecker.isTrue(steps > 2, "The number of steps should be greater than 2"); _strike = strike; _timeToExpiry = timeToExpiry; _steps = steps; _sign = isCall ? 1. : -1.; } /** * @param assetPrice The base asset price: spot or modified spot * @param downFactor Down factor * @param upOverDown (up factor)/(down factor) * @return Payoff at expiry */ public abstract double[] getPayoffAtExpiry(final double assetPrice, final double downFactor, final double upOverDown); /** * Given a set of option values in the (steps+1)-th layer, derive option values in the (steps)-th layer * For an option with early exercise feature, this method should be overridden * @param discount Discount factor * @param upProbability Up probability * @param downProbability Down probability * @param values Option values in the (steps+1)-th layer * @param baseAssetPrice Asset price at (0,0), i.e., the starting point * @param sumCashDiv Sum of discounted discrete cash dividends payed after (steps+1)-th layer * @param downFactor Down factor * @param upOverDown (up factor)/(down factor) * @param steps * @return Option values in the (steps)-th layer */ public double[] getNextOptionValues(final double discount, final double upProbability, final double downProbability, final double[] values, final double baseAssetPrice, final double sumCashDiv, final double downFactor, final double upOverDown, final int steps) { final int nStepsP = steps + 1; final double[] res = new double[nStepsP]; for (int j = 0; j < nStepsP; ++j) { res[j] = discount * (upProbability * values[j + 1] + downProbability * values[j]); } return res; } /** * @param assetPrice (Modified) assetPrice at (0,0) * @param downFactor Down factor * @param middleOverDown (middle factor)/(down factor) * @return Payoff at expiry */ public abstract double[] getPayoffAtExpiryTrinomial(final double assetPrice, final double downFactor, final double middleOverDown); /** * Given a set of option values in the (steps+1)-th layer, derive option values in the (steps)-th layer * For an option with early exercise feature or barriers, this method should be overridden * @param discount Discount factor * @param upProbability Up probability * @param middleProbability Middle probability * @param downProbability Down probability * @param values Option values in the (steps+1)-th layer * @param baseAssetPrice Asset price at (0,0), i.e., the starting point * @param sumCashDiv Sum of discounted discrete cash dividends payed after (steps+1)-th layer * @param downFactor Down factor * @param middleOverDown (middle factor)/(down factor) * @param steps * @return Option values in the (steps)-th layer */ public double[] getNextOptionValues(final double discount, final double upProbability, final double middleProbability, final double downProbability, final double[] values, final double baseAssetPrice, final double sumCashDiv, final double downFactor, final double middleOverDown, final int steps) { final int nNodes = 2 * steps + 1; final double[] res = new double[nNodes]; for (int j = 0; j < nNodes; ++j) { res[j] = discount * (upProbability * values[j + 2] + middleProbability * values[j + 1] + downProbability * values[j]); } return res; } /** * Access strike price * @return _strike */ public double getStrike() { return _strike; } /** * Access time to expiry * @return _timeToExpiry */ public double getTimeToExpiry() { return _timeToExpiry; } /** * Access number of steps * @return _steps */ public int getNumberOfSteps() { return _steps; } /** * Access signature in payoff formula * @return +1 if call, -1 if put */ public double getSign() { return _sign; } @Override public int hashCode() { final int prime = 31; int result = 1; long temp; temp = Double.doubleToLongBits(_sign); result = prime * result + (int) (temp ^ (temp >>> 32)); result = prime * result + _steps; temp = Double.doubleToLongBits(_strike); result = prime * result + (int) (temp ^ (temp >>> 32)); temp = Double.doubleToLongBits(_timeToExpiry); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (!(obj instanceof OptionFunctionProvider1D)) { return false; } OptionFunctionProvider1D other = (OptionFunctionProvider1D) obj; if (Double.doubleToLongBits(_sign) != Double.doubleToLongBits(other._sign)) { return false; } if (_steps != other.getNumberOfSteps()) { return false; } if (Double.doubleToLongBits(_strike) != Double.doubleToLongBits(other._strike)) { return false; } if (Double.doubleToLongBits(_timeToExpiry) != Double.doubleToLongBits(other._timeToExpiry)) { return false; } return true; } }