public static double modifiedDuration(List <CashFlow> cashflows, InterestRate y, Date settlementDate)
{
if (cashflows.Count == 0)
{
return(0.0);
}
double P = 0.0;
double dPdy = 0.0;
double r = y.rate();
int N = (int)y.frequency();
DayCounter dc = y.dayCounter();
foreach (CashFlow cf in cashflows.Where(cf => !cf.hasOccurred(settlementDate)))
{
double t = dc.yearFraction(settlementDate, cf.date());
double c = cf.amount();
double B = y.discountFactor(t);
P += c * B;
switch (y.compounding())
{
case Compounding.Simple:
dPdy -= c * B * B * t;
break;
case Compounding.Compounded:
dPdy -= c * t * B / (1 + r / N);
break;
case Compounding.Continuous:
dPdy -= c * B * t;
break;
case Compounding.SimpleThenCompounded:
if (t <= 1.0 / N)
{
dPdy -= c * B * B * t;
}
else
{
dPdy -= c * t * B / (1 + r / N);
}
break;
default:
throw new ArgumentException("unknown compounding convention (" + y.compounding() + ")");
}
}
if (P == 0.0) // no cashflows
{
return(0.0);
}
return(-dPdy / P); // reverse derivative sign
}