/**
* 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;
/**
* The call option pays off max[S2 - X2, 0] if S1 > X1 and 0 otherwise,
* whereas the put pays off max[X2 - S2, 0] if S1 < X1 and 0 otherwise
*/
public class TwoAssetCorrelationOptionFunctionProvider extends OptionFunctionProvider2D {
private double _strike2;
/**
* @param strike1 Strike price for asset 1, X1
* @param strike2 Strike price for asset 2, X2
* @param timeToExpiry Time to expiry
* @param steps Number of steps
* @param isCall True if call, false if put
*/
public TwoAssetCorrelationOptionFunctionProvider(final double strike1, final double strike2, final double timeToExpiry, final int steps, final boolean isCall) {
super(strike1, timeToExpiry, steps, isCall);
ArgumentChecker.isTrue(strike2 > 0., "strike2 should be positive");
ArgumentChecker.isTrue(Doubles.isFinite(strike2), "strike2 should be finite");
_strike2 = strike2;
}
@Override
public double[][] getPayoffAtExpiry(final double assetPrice1, final double assetPrice2, final double upOverDown1, final double upOverDown2) {
final double strike1 = super.getStrike();
final int nStepsP = getNumberOfSteps() + 1;
final double sign = getSign();
final double[][] values = new double[nStepsP][nStepsP];
double priceTmp1 = assetPrice1;
for (int i = 0; i < nStepsP; ++i) {
double priceTmp2 = assetPrice2;
for (int j = 0; j < nStepsP; ++j) {
values[i][j] = sign * (priceTmp1 - strike1) > 0. ? Math.max(sign * (priceTmp2 - _strike2), 0.) : 0.;
priceTmp2 *= upOverDown2;
}
priceTmp1 *= upOverDown1;
}
return values;
}
@Override
public double[][] getPayoffAtExpiryTrinomial(final double assetPrice1, final double assetPrice2, final double middleOverDown1, final double middleOverDown2) {
final double strike1 = super.getStrike();
final int nNodes = 2 * getNumberOfSteps() + 1;
final double sign = getSign();
final double[][] values = new double[nNodes][nNodes];
double priceTmp1 = assetPrice1;
for (int i = 0; i < nNodes; ++i) {
double priceTmp2 = assetPrice2;
for (int j = 0; j < nNodes; ++j) {
values[i][j] = sign * (priceTmp1 - strike1) > 0. ? Math.max(sign * (priceTmp2 - _strike2), 0.) : 0.;
priceTmp2 *= middleOverDown2;
}
priceTmp1 *= middleOverDown1;
}
return values;
}
/**
* Access strike for asset 1
* @return strike1
*/
public double getStrike1() {
return super.getStrike();
}
/**
* Access strike for asset 2
* @return strike2
*/
public double getStrike2() {
return _strike2;
}
@Override
public double getStrike() {
throw new IllegalArgumentException("Specify strike for asset 1 or strike for asset 2");
}
@Override
public int hashCode() {
final int prime = 31;
int result = super.hashCode();
long temp;
temp = Double.doubleToLongBits(_strike2);
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 TwoAssetCorrelationOptionFunctionProvider)) {
return false;
}
TwoAssetCorrelationOptionFunctionProvider other = (TwoAssetCorrelationOptionFunctionProvider) obj;
if (Double.doubleToLongBits(_strike2) != Double.doubleToLongBits(other._strike2)) {
return false;
}
return true;
}
}