/**
* 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.multiply;
import static com.opengamma.analytics.math.ComplexMathUtils.pow;
import static com.opengamma.analytics.math.ComplexMathUtils.subtract;
import static com.opengamma.analytics.math.number.ComplexNumber.I;
import static com.opengamma.analytics.math.number.ComplexNumber.ZERO;
import org.apache.commons.lang.NotImplementedException;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.function.special.GammaFunction;
import com.opengamma.analytics.math.number.ComplexNumber;
/**
* This class represents the characteristic function of the
* Carr-Madan-Geman-Yor (CGMY) process. This process is a pure jump process
* (i.e. there is no Brownian component).
* <p>
* The characteristic function is given by:
* $$
* \begin{align*}
* \phi(u; C, G, M, Y) = \exp\left(C \Gamma(-Y)\left[(M - iu)^Y - M^Y + (G + iu)^Y - G^Y\right]\right)
* \end{align*}
* $$
*/
public class CGMYCharacteristicExponent implements CharacteristicExponent {
private static final GammaFunction GAMMA_FUNCTION = new GammaFunction();
private final double _c;
private final double _g;
private final double _m;
private final double _y;
private final double _minAlpha;
private final double _maxAlpha;
private final double _r1;
private final double _r2;
private final double _r3;
/**
* The parameters for the CGMY process
* @param c C, > 0
* @param g G, > 0
* @param m M, > 1
* @param y Y, < 2
*/
public CGMYCharacteristicExponent(final double c, final double g, final double m, final double y) {
Validate.isTrue(c > 0, "C > 0");
Validate.isTrue(g > 0, "G > 0");
Validate.isTrue(m > 1, "M > 1");
Validate.isTrue(y < 2, "Y < 2");
_c = c;
_g = g;
_m = m;
_y = y;
_minAlpha = -(_g + 1.0);
_maxAlpha = _m - 1.0;
_r1 = Math.pow(_m, _y) + Math.pow(_g, _y);
_r2 = _c * GAMMA_FUNCTION.evaluate(-_y);
_r3 = (Math.pow(_m - 1, _y) + Math.pow(_g + 1, _y) - _r1);
}
@Override
public Function1D<ComplexNumber, ComplexNumber> getFunction(final double t) {
return new Function1D<ComplexNumber, ComplexNumber>() {
@Override
public ComplexNumber evaluate(ComplexNumber u) {
return getValue(u, t);
}
};
}
@Override
public ComplexNumber getValue(ComplexNumber u, double t) {
final double r2 = t * _r2;
final ComplexNumber complexR3 = new ComplexNumber(r2 * _r3);
if (u.getReal() == 0.0) {
if (u.getImaginary() == 0.0) {
return ZERO;
}
if (u.getImaginary() == -1.0) {
return complexR3;
}
}
final ComplexNumber iu = multiply(I, u);
final ComplexNumber c1 = pow(subtract(_m, iu), _y);
final ComplexNumber c2 = pow(add(_g, iu), _y);
final ComplexNumber c3 = add(c1, c2);
final ComplexNumber c4 = subtract(c3, _r1);
final ComplexNumber res = multiply(r2, c4);
return res;
}
/**
* Gets C
* @return C
*/
public double getC() {
return _c;
}
/**
* Gets G
* @return G
*/
public double getG() {
return _g;
}
/**
* Gets M
* @return M
*/
public double getM() {
return _m;
}
/**
* Gets Y
* @return Y
*/
public double getY() {
return _y;
}
/**
*
* @return $M - 1$
*/
@Override
public double getLargestAlpha() {
return _maxAlpha;
}
/**
*
* @return $-G - 1$
*/
@Override
public double getSmallestAlpha() {
return _minAlpha;
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
long temp;
temp = Double.doubleToLongBits(_c);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_g);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_m);
result = prime * result + (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(_y);
result = prime * result + (int) (temp ^ (temp >>> 32));
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 CGMYCharacteristicExponent other = (CGMYCharacteristicExponent) obj;
if (Double.doubleToLongBits(_c) != Double.doubleToLongBits(other._c)) {
return false;
}
if (Double.doubleToLongBits(_g) != Double.doubleToLongBits(other._g)) {
return false;
}
if (Double.doubleToLongBits(_m) != Double.doubleToLongBits(other._m)) {
return false;
}
return Double.doubleToLongBits(_y) == Double.doubleToLongBits(other._y);
}
@Override
public ComplexNumber[] getCharacteristicExponentAdjoint(ComplexNumber u, double t) {
throw new NotImplementedException();
}
@Override
public Function1D<ComplexNumber, ComplexNumber[]> getAdjointFunction(double t) {
throw new NotImplementedException();
}
}