/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.commodity.multicurvecommodity.curve;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldAndDiscountCurve;
import com.opengamma.analytics.financial.model.interestrate.curve.YieldCurve;
import com.opengamma.analytics.math.curve.DoublesCurve;
import com.opengamma.analytics.math.curve.FunctionalDoublesCurve;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.util.serialization.InvokedSerializedForm;
import com.opengamma.util.ArgumentChecker;
/**
* A curve containing the (estimated) commodity forward value at different maturities.
*/
public class CommodityForwardCurve {
/**
* The commodity forward curve index curve.
*/
private final DoublesCurve _fwdCurve;
/**
* A small amount of time
*/
private static final double SMALL_TIME = 1.0E-6;
/**
* Constructor from a curve object.
* @param fwdCurve The curve.
*/
public CommodityForwardCurve(final DoublesCurve fwdCurve) {
Validate.notNull(fwdCurve, "curve");
_fwdCurve = fwdCurve;
}
/**
* Constructor from the spot value, a discount curve and a convenience yield curve.
* @param spot The spot.
* @param discountCurve The discount curve.
* @param convenienceYieldCurve The convenience yield curve.
*/
public CommodityForwardCurve(final double spot, final YieldAndDiscountCurve discountCurve, final YieldAndDiscountCurve convenienceYieldCurve) {
Validate.notNull(discountCurve, "curve");
Validate.notNull(convenienceYieldCurve, "curve");
_fwdCurve = getForwardCurve(spot, discountCurve, convenienceYieldCurve);
}
/**
* Gets the underlying curve object.
* @return The forward curve.
*/
public DoublesCurve getFwdCurve() {
return _fwdCurve;
}
/**
* Returns the curve name.
* @return The name.
*/
public String getName() {
return _fwdCurve.getName();
}
/**
* Returns the estimated commodity forward value for a given time.
* @param time The time
* @return The commodity forward value.
*/
public double getForwardValue(final Double time) {
return _fwdCurve.getYValue(time);
}
/**
* Returns the estimated commodity forward value for a given time.
* @return The commodity forward value.
*/
public double getSpotValue() {
return _fwdCurve.getYValue(0.0);
}
/**
* Gets the number of parameters in a curve.
* @return The number of parameters
*/
public int getNumberOfParameters() {
return _fwdCurve.size();
}
/**
* The list of underlying curves (up to one level).
* @return The list.
*/
public List<String> getUnderlyingCurvesNames() {
return new ArrayList<>();
}
/**
* Gets the sensitivities of the commodity forward to the curve parameters for a time.
* @param time The time
* @return The sensitivities. If the time is less than 1e<sup>-6</sup>, the rate is
* ill-defined and zero is returned.
*/
public double[] getCommodityForwardParameterSensitivity(final double time) {
final Double[] curveSensitivity = _fwdCurve.getYValueParameterSensitivity(time);
final double[] commodityForwardSensitivity = new double[curveSensitivity.length];
// Implementation note: if time = 0, the rate is ill-defined: return 0 sensitivity
if (Math.abs(time) < SMALL_TIME) {
return commodityForwardSensitivity;
}
for (int loopp = 0; loopp < curveSensitivity.length; loopp++) {
commodityForwardSensitivity[loopp] = curveSensitivity[loopp];
}
return commodityForwardSensitivity;
}
protected static DoublesCurve getForwardCurve(final double spot, final YieldAndDiscountCurve discountCurve, final YieldAndDiscountCurve convenienceYieldCurve) {
ArgumentChecker.notNull(discountCurve, "risk-free curve");
ArgumentChecker.notNull(convenienceYieldCurve, "cost-of-carry curve");
final Function1D<Double, Double> f = new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double t) {
return spot * convenienceYieldCurve.getDiscountFactor(t) / discountCurve.getDiscountFactor(t);
}
};
return new FunctionalDoublesCurve(f) {
public Object writeReplace() {
return new InvokedSerializedForm(CommodityForwardCurve.class, "getForwardCurve", spot, discountCurve, convenienceYieldCurve);
}
};
}
protected static YieldAndDiscountCurve getConvenienceYieldCurve(final double spot, final YieldAndDiscountCurve discountCurve, final DoublesCurve fwdCurve) {
ArgumentChecker.notNull(discountCurve, "discount curve");
ArgumentChecker.notNull(fwdCurve, "convenience yield curve");
final Function1D<Double, Double> f = new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double t) {
return -Math.log(fwdCurve.getYValue(t) / spot) / t - discountCurve.getInterestRate(t);
}
};
return YieldCurve.from(new FunctionalDoublesCurve(f));
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((_fwdCurve == null) ? 0 : _fwdCurve.hashCode());
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 CommodityForwardCurve other = (CommodityForwardCurve) obj;
if (_fwdCurve == null) {
if (other._fwdCurve != null) {
return false;
}
} else if (!_fwdCurve.equals(other._fwdCurve)) {
return false;
}
return true;
}
}