/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.model.option.pricing.fourier;
import static com.opengamma.analytics.math.ComplexMathUtils.add;
import static com.opengamma.analytics.math.ComplexMathUtils.divide;
import static com.opengamma.analytics.math.ComplexMathUtils.exp;
import static com.opengamma.analytics.math.ComplexMathUtils.multiply;
import static com.opengamma.analytics.math.ComplexMathUtils.subtract;
import static com.opengamma.analytics.math.number.ComplexNumber.MINUS_I;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.BlackFunctionData;
import com.opengamma.analytics.financial.model.option.pricing.analytic.formula.EuropeanVanillaOption;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.number.ComplexNumber;
/**
*
*/
public class EuropeanPriceIntegrand {
private final MartingaleCharacteristicExponent _ce;
private final double _alpha;
private final boolean _useVarianceReduction;
public EuropeanPriceIntegrand(final MartingaleCharacteristicExponent ce, final double alpha, final boolean useVarianceReduction) {
Validate.notNull(ce, "characteristic exponent");
_ce = ce;
_alpha = alpha;
_useVarianceReduction = useVarianceReduction;
}
public Function1D<Double, Double> getFunction(final BlackFunctionData data, final EuropeanVanillaOption option) {
Validate.notNull(data, "data");
Validate.notNull(option, "option");
final double t = option.getTimeToExpiry();
final Function1D<ComplexNumber, ComplexNumber> characteristicFunction = _ce.getFunction(t);
final double k = Math.log(option.getStrike() / data.getForward());
final double blackVol = data.getBlackVolatility();
final CharacteristicExponent gaussian;
final Function1D<ComplexNumber, ComplexNumber> gaussianFunction;
if (_useVarianceReduction) {
gaussian = new GaussianCharacteristicExponent(-0.5 * blackVol * blackVol, blackVol);
gaussianFunction = gaussian.getFunction(t);
} else {
gaussian = null;
gaussianFunction = null;
}
return new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double x) {
@SuppressWarnings("synthetic-access")
final ComplexNumber res = getIntegrand(x, characteristicFunction, gaussianFunction, k);
return res.getReal();
}
};
}
private ComplexNumber getIntegrand(final double x, final Function1D<ComplexNumber, ComplexNumber> ce, final Function1D<ComplexNumber, ComplexNumber> gaussian,
final double k) {
final ComplexNumber z = new ComplexNumber(x, -1 - _alpha);
final ComplexNumber num1 = exp(add(new ComplexNumber(0, -x * k), ce.evaluate(z)));
final ComplexNumber num2 = gaussian == null ? new ComplexNumber(0.0) : exp(add(new ComplexNumber(0, -x * k), gaussian.evaluate(z)));
final ComplexNumber denom = multiply(z, subtract(MINUS_I, z));
final ComplexNumber res = divide(subtract(num1, num2), denom);
return res;
}
public MartingaleCharacteristicExponent getCharacteristicExponent() {
return _ce;
}
public double getAlpha() {
return _alpha;
}
public boolean useVarianceReduction() {
return _useVarianceReduction;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(_alpha);
result = prime * result + (int) (temp ^ (temp >>> 32));
result = prime * result + _ce.hashCode();
result = prime * result + (_useVarianceReduction ? 1231 : 1237);
return result;
}
@Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final EuropeanPriceIntegrand other = (EuropeanPriceIntegrand) obj;
if (Double.doubleToLongBits(_alpha) != Double.doubleToLongBits(other._alpha)) {
return false;
}
if (!ObjectUtils.equals(_ce, other._ce)) {
return false;
}
return _useVarianceReduction == other._useVarianceReduction;
}
}