/**
* Copyright (C) 2009 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.analytics.financial.interestrate.annuity;
import org.apache.commons.lang.Validate;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.Annuity;
import com.opengamma.analytics.financial.interestrate.annuity.derivative.AnnuityCouponFixed;
import com.opengamma.analytics.financial.interestrate.payments.derivative.CouponFixed;
import com.opengamma.analytics.financial.interestrate.payments.derivative.PaymentFixed;
import com.opengamma.analytics.math.function.Function1D;
import com.opengamma.analytics.math.rootfinding.BracketRoot;
import com.opengamma.analytics.math.rootfinding.BrentSingleRootFinder;
import com.opengamma.analytics.math.rootfinding.RealSingleRootFinder;
/**
*
*/
public final class YieldSensitivityCalculator {
private static final BracketRoot BRACKETER = new BracketRoot();
private static final RealSingleRootFinder ROOT_FINDER = new BrentSingleRootFinder();
private static final YieldSensitivityCalculator INSTANCE = new YieldSensitivityCalculator();
private YieldSensitivityCalculator() {
}
public static YieldSensitivityCalculator getInstance() {
return INSTANCE;
}
/**
* For a set of future cash flows with an assumed present value (dirty price), calculates the continuously compounded constant interest rate that gives the
* same present value
* @param annuity Set of known cash flows
* @param pv The present value of the future cash flows. Also know as dirty or full price
* @return continuously compounded yield (as a fraction)
*/
public double calculateYield(final Annuity<? extends PaymentFixed> annuity, final double pv) {
Validate.notNull(annuity, "annuity");
final Function1D<Double, Double> f = new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double y) {
return calculatePriceForYield(annuity, y) - pv;
}
};
final double[] range = BRACKETER.getBracketedPoints(f, 0.0, 0.2);
return ROOT_FINDER.getRoot(f, range[0], range[1]);
}
/**
* For a set of future cash flows with an assumed present value (dirty price), calculates the continuously compounded constant interest rate that gives the
* same present value
* @param annuity Set of known cash flows
* @param pv The present value of the future cash flows. Also know as dirty or full price
* @return continuously compounded yield (as a fraction)
*/
public double calculateYield(final AnnuityCouponFixed annuity, final double pv) {
Validate.notNull(annuity, "annuity");
final Function1D<Double, Double> f = new Function1D<Double, Double>() {
@Override
public Double evaluate(final Double y) {
return calculatePriceForYield(annuity, y) - pv;
}
};
final double[] range = BRACKETER.getBracketedPoints(f, 0.0, 0.2);
return ROOT_FINDER.getRoot(f, range[0], range[1]);
}
/**
* Calculate the present value of a set of cash flows given a yield
* @param annuity Set of known cash flows
* @param yield Continuously compounded constant interest rate
* @return Present value (dirty price)
*/
public double calculatePriceForYield(final Annuity<? extends PaymentFixed> annuity, final double yield) {
Validate.notNull(annuity, "annuity");
double sum = 0;
final int n = annuity.getNumberOfPayments();
PaymentFixed temp;
for (int i = 0; i < n; i++) {
temp = annuity.getNthPayment(i);
sum += temp.getAmount() * Math.exp(-yield * temp.getPaymentTime());
}
return sum;
}
/**
* Calculate the present value of a set of cash flows given a yield
* @param annuity Set of known cash flows
* @param yield Continuously compounded constant interest rate
* @return Present value (dirty price)
*/
public double calculatePriceForYield(final AnnuityCouponFixed annuity, final double yield) {
Validate.notNull(annuity, "annuity");
double sum = 0;
final int n = annuity.getNumberOfPayments();
CouponFixed temp;
for (int i = 0; i < n; i++) {
temp = annuity.getNthPayment(i);
sum += temp.getAmount() * Math.exp(-yield * temp.getPaymentTime());
}
return sum;
}
/**
* For a set of cash flows calculates the nth derivative of its PV with respect to its continuously compounded yield multiplied by the
* factor (-1)^n which just keeps the sign positive when cash flows are positive
* @param annuity Set of known cash flows
* @param pv The present value of the future cash flows. Also know as dirty or full price
*@param order The order of the derivative
* @return nth order yield sensitivity (times (-1)^n
*/
public double calculateNthOrderSensitivity(final Annuity<? extends PaymentFixed> annuity, final double pv, final int order) {
Validate.notNull(annuity, "annuity");
final double yield = calculateYield(annuity, pv);
return calculateNthOrderSensitivityFromYield(annuity, yield, order);
}
/**
* For a set of cash flows calculates the nth derivative of its PV with respect to its continuously compounded yield multiplied by the
* factor (-1)^n which just keeps the sign positive when cash flows are positive
* @param annuity Set of known cash flows
* @param pv The present value of the future cash flows. Also know as dirty or full price
*@param order The order of the derivative
* @return nth order yield sensitivity (times (-1)^n
*/
public double calculateNthOrderSensitivity(final AnnuityCouponFixed annuity, final double pv, final int order) {
Validate.notNull(annuity, "annuity");
final double yield = calculateYield(annuity, pv);
return calculateNthOrderSensitivityFromYield(annuity, yield, order);
}
/**
* For a set of cash flows calculates the nth derivative of its PV with respect to its continuously compounded yield multiplied by the
* factor (-1)^n which just keeps the sign positive when cash flows are positive
* @param annuity Set of known cash flows
* @param yield Continuously compounded constant interest rate
* @param order The order of the derivative
* @return nth order yield sensitivity (times (-1)^n)
*/
public double calculateNthOrderSensitivityFromYield(final Annuity<? extends PaymentFixed> annuity, final double yield, final int order) {
Validate.notNull(annuity, "annuity");
Validate.isTrue(order >= 0, "order must be positive");
double sum = 0;
double t;
double tPower;
final int n = annuity.getNumberOfPayments();
PaymentFixed temp;
for (int i = 0; i < n; i++) {
temp = annuity.getNthPayment(i);
t = temp.getPaymentTime();
tPower = Math.pow(t, order);
sum += temp.getAmount() * tPower * Math.exp(-yield * t);
}
return sum;
}
/**
* For a set of cash flows calculates the nth derivative of its PV with respect to its continuously compounded yield multiplied by the
* factor (-1)^n which just keeps the sign positive when cash flows are positive
* @param annuity Set of known cash flows
* @param yield Continuously compounded constant interest rate
* @param order The order of the derivative
* @return nth order yield sensitivity (times (-1)^n)
*/
public double calculateNthOrderSensitivityFromYield(final AnnuityCouponFixed annuity, final double yield, final int order) {
Validate.notNull(annuity, "annuity");
Validate.isTrue(order >= 0, "order must be positive");
double sum = 0;
double t;
double tPower;
final int n = annuity.getNumberOfPayments();
CouponFixed temp;
for (int i = 0; i < n; i++) {
temp = annuity.getNthPayment(i);
t = temp.getPaymentTime();
tPower = Math.pow(t, order);
sum += temp.getAmount() * tPower * Math.exp(-yield * t);
}
return sum;
}
}