From f793230899df8340e2f4f3031d01d69d362d4358 Mon Sep 17 00:00:00 2001 From: Andrea Maggiulli Date: Wed, 13 Jun 2018 14:52:29 +0200 Subject: [PATCH] Added accrualStartDate optional parameter to CashFlows.accruedAmount function to calculate accrued over irregular periods. --- src/QLNet.Old/AssemblyInfo.cs | 4 +- src/QLNet/Cashflows/CashFlows.cs | 40 ++++++++++++++++++- .../Pricingengines/Bond/BondFunctions.cs | 4 +- src/QLNet/QLNet.csproj | 2 +- 4 files changed, 43 insertions(+), 7 deletions(-) diff --git a/src/QLNet.Old/AssemblyInfo.cs b/src/QLNet.Old/AssemblyInfo.cs index 299b8eb83..e1f6fc549 100644 --- a/src/QLNet.Old/AssemblyInfo.cs +++ b/src/QLNet.Old/AssemblyInfo.cs @@ -30,5 +30,5 @@ // // È possibile specificare tutti i valori o impostare come predefiniti i valori Numero revisione e Numero build // utilizzando l'asterisco (*) come descritto di seguito: -[assembly: AssemblyVersion("1.11.0.0")] -[assembly: AssemblyFileVersion("1.11.0.0")] +[assembly: AssemblyVersion("1.11.1.0")] +[assembly: AssemblyFileVersion("1.11.1.0")] diff --git a/src/QLNet/Cashflows/CashFlows.cs b/src/QLNet/Cashflows/CashFlows.cs index 322569246..1423a03ef 100644 --- a/src/QLNet/Cashflows/CashFlows.cs +++ b/src/QLNet/Cashflows/CashFlows.cs @@ -652,17 +652,53 @@ public static int accruedDays(Leg leg, bool includeSettlementDateFlows, Date set } return 0; } - public static double accruedAmount(Leg leg, bool includeSettlementDateFlows, Date settlementDate = null) + public static double accruedAmount(Leg leg, bool includeSettlementDateFlows, Date settlementDate = null, Date accrualStartDate = null) { + double result = 0.0; + if (settlementDate == null) settlementDate = Settings.evaluationDate(); CashFlow cf = nextCashFlow(leg, includeSettlementDateFlows, settlementDate); if (cf == null) return 0; + Date paymentDate = cf.date(); - double result = 0.0; + CashFlow cfStart = null; + Date endDate = paymentDate; + + if (accrualStartDate != null) + { + cfStart = nextCashFlow(leg, includeSettlementDateFlows, accrualStartDate); + + if (cfStart != null) + endDate = cfStart.date(); + } + + // More periods + if (endDate != paymentDate) + { + // First period + Coupon cp = cfStart as Coupon; + if (cp != null) + result += cp.accruedAmount(cp.accrualEndDate()) - cp.accruedAmount(accrualStartDate); + + + foreach (CashFlow x in leg.Where(x => x.date() <= paymentDate && + x.date() > endDate)) + { + cp = x as Coupon; + if (cp != null) + if (x.date() < paymentDate) + result += cp.accruedAmount(cp.accrualEndDate()); + else + result += cp.accruedAmount(settlementDate); + } + return result; + } + + // One period foreach (CashFlow x in leg.Where(x => x.date() == paymentDate)) { Coupon cp = x as Coupon; diff --git a/src/QLNet/Pricingengines/Bond/BondFunctions.cs b/src/QLNet/Pricingengines/Bond/BondFunctions.cs index 2746c9d4d..4cb036078 100644 --- a/src/QLNet/Pricingengines/Bond/BondFunctions.cs +++ b/src/QLNet/Pricingengines/Bond/BondFunctions.cs @@ -206,7 +206,7 @@ public static double accruedDays(Bond bond, Date settlementDate = null) return CashFlows.accruedDays(bond.cashflows(), false, settlementDate); } - public static double accruedAmount(Bond bond, Date settlementDate = null) + public static double accruedAmount(Bond bond, Date settlementDate = null, Date accrualStartDate = null) { if (settlementDate == null) settlementDate = bond.settlementDate(); @@ -215,7 +215,7 @@ public static double accruedAmount(Bond bond, Date settlementDate = null) "non tradable at " + settlementDate + " (maturity being " + bond.maturityDate() + ")"); - return CashFlows.accruedAmount(bond.cashflows(), false, settlementDate) * 100.0 / bond.notional(settlementDate); + return CashFlows.accruedAmount(bond.cashflows(), false, settlementDate, accrualStartDate) * 100.0 / bond.notional(settlementDate); } #endregion diff --git a/src/QLNet/QLNet.csproj b/src/QLNet/QLNet.csproj index ba2893441..4422628f4 100644 --- a/src/QLNet/QLNet.csproj +++ b/src/QLNet/QLNet.csproj @@ -1,7 +1,7 @@  - 1.11.0 + 1.11.1 net45;net40;netstandard2.0;netcoreapp1.1 $(DefineConstants);QL_NEGATIVE_RATES QLNet