/** * 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; /** * Supershare option pays S/KL if KL <= S < KH at expiry. */ public class SupershareOptionFunctionProvider extends OptionFunctionProvider1D { private double _upperBound; /** * @param timeToExpiry Time to expiry * @param lowerBound Lower bound, KL * @param upperBound Upper bound, KH * @param steps Number of steps */ public SupershareOptionFunctionProvider(final double timeToExpiry, final double lowerBound, final double upperBound, final int steps) { super(lowerBound, timeToExpiry, steps, true); ArgumentChecker.isTrue(upperBound > 0., "upperBound should be positive"); ArgumentChecker.isTrue(Doubles.isFinite(upperBound), "upperBound should be finite"); ArgumentChecker.isTrue(upperBound > lowerBound, "upperBound should be larger than lowerBound"); _upperBound = upperBound; } @Override public double[] getPayoffAtExpiry(final double assetPrice, final double downFactor, final double upOverDown) { final double lowerBound = super.getStrike(); final int nSteps = getNumberOfSteps(); final int nStepsP = nSteps + 1; final double[] values = new double[nStepsP]; double priceTmp = assetPrice * Math.pow(downFactor, nSteps); for (int i = 0; i < nStepsP; ++i) { values[i] = priceTmp >= lowerBound && priceTmp < _upperBound ? priceTmp / lowerBound : 0.; priceTmp *= upOverDown; } return values; } @Override public double[] getPayoffAtExpiryTrinomial(final double assetPrice, final double downFactor, final double middleOverDown) { final double lowerBound = super.getStrike(); final int nSteps = getNumberOfSteps(); final int nNodes = 2 * getNumberOfSteps() + 1; final double[] values = new double[nNodes]; double priceTmp = assetPrice * Math.pow(downFactor, nSteps); for (int i = 0; i < nNodes; ++i) { values[i] = priceTmp >= lowerBound && priceTmp < _upperBound ? priceTmp / lowerBound : 0.; priceTmp *= middleOverDown; } return values; } /** * Access lower bound * @return _strike in superclass */ public double getLowerBound() { return super.getStrike(); } /** * Access upper bound * @return _upperBound */ public double getUpperBound() { return _upperBound; } @Override public double getSign() { throw new IllegalArgumentException("Call/put is not relevant for this option"); } @Override public int hashCode() { final int prime = 31; int result = super.hashCode(); long temp; temp = Double.doubleToLongBits(_upperBound); result = prime * result + (int) (temp ^ (temp >>> 32)); return result; } @Override public boolean equals(Object obj) { if (this == obj) { return true; } if (!super.equals(obj)) { return false; } if (!(obj instanceof SupershareOptionFunctionProvider)) { return false; } SupershareOptionFunctionProvider other = (SupershareOptionFunctionProvider) obj; if (Double.doubleToLongBits(_upperBound) != Double.doubleToLongBits(other._upperBound)) { return false; } return true; } }