/**
* 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;
/**
* Payoff of capped power option is min( max( S^i - K , 0 ) , C ) for call and min( max( K - S^i , 0 ) , C ) for put with i > 0, K > C > 0
*/
public class CappedPowerOptionFunctionProvider extends OptionFunctionProvider1D {
private double _power;
private double _cap;
/**
* @param strike Strike price, K
* @param timeToExpiry Time to expiry
* @param steps Number of steps
* @param isCall True if call, false if put
* @param power Power, i
* @param cap Cap, C
*/
public CappedPowerOptionFunctionProvider(final double strike, final double timeToExpiry, final int steps, final boolean isCall, final double power, final double cap) {
super(strike, timeToExpiry, steps, isCall);
ArgumentChecker.isTrue(power > 0., "power should be positive");
ArgumentChecker.isTrue(Doubles.isFinite(power), "power should be finite");
ArgumentChecker.isTrue(cap > 0., "cap should be positive");
ArgumentChecker.isTrue(Doubles.isFinite(cap), "cap should be finite");
if (!isCall) {
ArgumentChecker.isTrue(cap < strike, "cap should be smaller than strike for put");
}
_power = power;
_cap = cap;
}
@Override
public double[] getPayoffAtExpiry(final double assetPrice, final double downFactor, final double upOverDown) {
final double strike = getStrike();
final int nSteps = getNumberOfSteps();
final int nStepsP = nSteps + 1;
final double sign = getSign();
final double[] values = new double[nStepsP];
double priceTmp = assetPrice * Math.pow(downFactor, nSteps);
for (int i = 0; i < nStepsP; ++i) {
values[i] = Math.min(Math.max(sign * (Math.pow(priceTmp, _power) - strike), 0.), _cap);
priceTmp *= upOverDown;
}
return values;
}
@Override
public double[] getPayoffAtExpiryTrinomial(final double assetPrice, final double downFactor, final double middleOverDown) {
final double strike = getStrike();
final int nSteps = getNumberOfSteps();
final int nNodes = 2 * getNumberOfSteps() + 1;
final double sign = getSign();
final double[] values = new double[nNodes];
double priceTmp = assetPrice * Math.pow(downFactor, nSteps);
for (int i = 0; i < nNodes; ++i) {
values[i] = Math.min(Math.max(sign * (Math.pow(priceTmp, _power) - strike), 0.), _cap);
priceTmp *= middleOverDown;
}
return values;
}
/**
* Access power
* @return _power
*/
public double getPower() {
return _power;
}
/**
* Access cap
* @return _cap
*/
public double getCap() {
return _cap;
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(_cap);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_power);
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 CappedPowerOptionFunctionProvider)) {
return false;
}
CappedPowerOptionFunctionProvider other = (CappedPowerOptionFunctionProvider) obj;
if (Double.doubleToLongBits(_cap) != Double.doubleToLongBits(other._cap)) {
return false;
}
if (Double.doubleToLongBits(_power) != Double.doubleToLongBits(other._power)) {
return false;
}
return true;
}
}