[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 5adcb60 2/2: Add list-bill calculations
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 5adcb60 2/2: Add list-bill calculations |
Date: |
Sun, 11 Jun 2017 21:16:24 -0400 (EDT) |
branch: master
commit 5adcb60ebd08d91a45a8c9b11b9c1b5a1fb71a0e
Author: Gregory W. Chicares <address@hidden>
Commit: Gregory W. Chicares <address@hidden>
Add list-bill calculations
The list-bill task is substantially complete. The final step will be to
use unrounded rather than rounded monthly deductions in this premium
calculation.
---
account_value.hpp | 6 ++++
basic_values.hpp | 15 +++++++++
ihs_acctval.cpp | 96 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
ihs_avmly.cpp | 6 ++++
ihs_basicval.cpp | 87 +++++++++++++++++++++++++++++++++++++++++++++++++
5 files changed, 210 insertions(+)
diff --git a/account_value.hpp b/account_value.hpp
index 441ca09..8793371 100644
--- a/account_value.hpp
+++ b/account_value.hpp
@@ -290,6 +290,9 @@ class LMI_SO AccountValue
double MinInitPrem() const;
double ModalMinInitPremShortfall() const;
+ void set_list_bill_year_and_month();
+ void set_list_bill_premium();
+
void SetMaxLoan ();
void SetMaxWD ();
double GetRefundableSalesLoad () const;
@@ -539,6 +542,9 @@ class LMI_SO AccountValue
bool SplitMinPrem;
bool UnsplitSplitMinPrem;
+ int list_bill_year_ {methuselah};
+ int list_bill_month_ {13};
+
bool TermCanLapse;
bool TermRiderActive;
double ActualSpecAmt;
diff --git a/basic_values.hpp b/basic_values.hpp
index 8e54768..f9c5b9d 100644
--- a/basic_values.hpp
+++ b/basic_values.hpp
@@ -238,6 +238,21 @@ class LMI_SO BasicValues
,mcenum_mode a_mode
,double a_specamt
) const;
+ double GetListBillPremMlyDed
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const;
+ double GetListBillPremMlyDedEe
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const;
+ double GetListBillPremMlyDedEr
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const;
double GetModalSpecAmtMax (double annualized_pmt) const;
double GetModalSpecAmtTgt (double annualized_pmt) const;
double GetModalSpecAmtMinNonMec(double annualized_pmt) const;
diff --git a/ihs_acctval.cpp b/ihs_acctval.cpp
index 6d6bef5..c0dfd92 100644
--- a/ihs_acctval.cpp
+++ b/ihs_acctval.cpp
@@ -164,6 +164,8 @@ AccountValue::AccountValue(Input const& input)
);
}
+ set_list_bill_year_and_month();
+
OverridingEePmts .resize(12 * BasicValues::GetLength());
OverridingErPmts .resize(12 * BasicValues::GetLength());
@@ -1132,6 +1134,100 @@ double AccountValue::ModalMinInitPremShortfall() const
}
}
+/// Set duration at which list-bill premium is to be determined.
+///
+/// The year and month of determination correspond to the first
+/// monthiversary on or after the list-bill date. If there is no
+/// such monthiversary, then harmless default values are used.
+///
+/// SOMEDAY !! Add a calendar_date function to return 'b' directly
+/// instead of incrementing the number of months conditionally.
+
+void AccountValue::set_list_bill_year_and_month()
+{
+ auto const& cert_date = yare_input_.EffectiveDate;
+ auto const& bill_date = yare_input_.ListBillDate;
+ if(bill_date < cert_date) return;
+
+ auto z = years_and_months_since(cert_date, bill_date);
+ auto const a = add_years_and_months(cert_date, z.first, z.second, true);
+ if(a < bill_date)
+ {
+ ++z.second;
+ }
+ auto const b = add_years_and_months(cert_date, z.first, z.second, true);
+ LMI_ASSERT(cert_date <= b);
+ list_bill_year_ = z.first;
+ list_bill_month_ = z.second;
+
+ if(!contains(yare_input_.Comments, "idiosyncrasyL")) return;
+
+ // Temporary supplemental code for acceptance testing.
+ int const inforce_months_mod_12 = years_and_months_since
+ (cert_date, bill_date).second
+ ;
+ // Number of delta months in the twelvemonth starting on bill date.
+ int const months_ante = 12 - inforce_months_mod_12;
+ warning()
+ << yare_input_.EffectiveDate.str() << " yare_input_.EffectiveDate\n"
+ << yare_input_.ListBillDate.str() << " yare_input_.ListBillDate\n"
+ << list_bill_year_ << " list_bill_year_\n"
+ << list_bill_month_ << " list_bill_month_\n"
+ << a.str() << " a = speculative determination date\n"
+ << b.str() << " b = actual determination date\n"
+ << months_ante << " months_ante\n"
+ << "List-bill premium will be set in monthiversary processing on "
+ << b.str() << ", which is "
+ << list_bill_year_ << " years and " << list_bill_month_ << " months"
+ << " after the issue date. An annual-mode list bill will reflect this"
+ << " premium for "
+ << months_ante << " months,"
+ << " and a premium determined on the same date but at the next higher"
+ << " age for "
+ << (12 - months_ante) << " months. Other modes will use an appropriate"
+ << " number of initial elements of that twelve-month premium stream."
+ << LMI_FLUSH;
+}
+
+void AccountValue::set_list_bill_premium()
+{
+ bool const the_time_is_now =
+ Year == list_bill_year_
+ && Month == list_bill_month_
+ && mce_run_gen_curr_sep_full == RunBasis_
+ ;
+ if(!the_time_is_now) return;
+
+ if(!SplitMinPrem)
+ {
+ InvariantValues().ListBillPremium = GetListBillPremMlyDed
+ (Year
+ ,InvariantValues().ErMode[Year].value()
+ ,InvariantValues().SpecAmt[Year]
+ );
+ InvariantValues().ErListBillPremium =
+ InvariantValues().ListBillPremium
+ ;
+ }
+ else
+ {
+ InvariantValues().EeListBillPremium = GetListBillPremMlyDedEe
+ (Year
+ ,InvariantValues().ErMode[Year].value()
+ ,InvariantValues().TermSpecAmt[Year]
+ );
+ InvariantValues().ErListBillPremium = GetListBillPremMlyDedEr
+ (Year
+ ,InvariantValues().ErMode[Year].value()
+ ,InvariantValues().SpecAmt[Year]
+ );
+ InvariantValues().ListBillPremium =
+ InvariantValues().EeListBillPremium
+ + InvariantValues().ErListBillPremium
+ ;
+ }
+}
+
//============================================================================
void AccountValue::AddSurrChgLayer(int year, double delta_specamt)
{
diff --git a/ihs_avmly.cpp b/ihs_avmly.cpp
index 7e5179b..1c5e0ad 100644
--- a/ihs_avmly.cpp
+++ b/ihs_avmly.cpp
@@ -172,6 +172,12 @@ void AccountValue::DoMonthDR()
NetMaxNecessaryPremium = Irc7702A_->DebugGetNetMaxNecPm ();
GrossMaxNecessaryPremium = Irc7702A_->DebugGetGrossMaxNecPm();
+ // Determine list-bill premiums only after transactions that
+ // might change specamt have been processed.
+ // SOMEDAY !! Should InvariantValues().ModalMinimumPremium be
+ // set here for that reason?
+ set_list_bill_premium();
+
TxAscertainDesiredPayment();
TxLimitPayment(max_non_mec_premium);
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index f906382..41d43ae 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -31,6 +31,7 @@
#include "database.hpp"
#include "death_benefits.hpp"
#include "et_vector.hpp"
+#include "financial.hpp" // list_bill_premium()
#include "fund_data.hpp"
#include "global_settings.hpp"
#include "gpt_specamt.hpp"
@@ -1338,6 +1339,92 @@ double BasicValues::GetModalPremMlyDedEr
return round_min_premium()(z);
}
+/// Possibly off-anniversary premium to be shown on list bill.
+///
+/// Implemented in terms of list_bill_premium(), q.v.
+///
+/// Ascertain deductions at the current age, and then again at the
+/// next age iff that is less than the maturity age, otherwise
+/// assuming that deductions are zero after maturity.
+///
+/// The discounting specified in all GetModalPremMlyDed* functions
+/// results in an annuity factor of unity for monthly mode, so call
+/// those functions with monthly mode for the nonce to get
+/// undiscounted deductions. This isn't quite what's wanted because
+/// those functions perform rounding.
+
+double BasicValues::GetListBillPremMlyDed
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const
+{
+ double const p0 = GetModalPremMlyDed(year, mce_monthly, specamt);
+ int const next_year = 1 + year;
+ double const p1 =
+ (next_year < GetLength())
+ ? GetModalPremMlyDed(next_year, mce_monthly, specamt)
+ : 0.0
+ ;
+ double const z = list_bill_premium
+ (p0
+ ,p1
+ ,mode
+ ,yare_input_.EffectiveDate
+ ,yare_input_.ListBillDate
+ ,mly_ded_discount_factor(year, mode)
+ );
+ return round_min_premium()(z);
+}
+
+double BasicValues::GetListBillPremMlyDedEe
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const
+{
+ double const p0 = GetModalPremMlyDedEe(year, mce_monthly, specamt);
+ int const next_year = 1 + year;
+ double const p1 =
+ (next_year < GetLength())
+ ? GetModalPremMlyDedEe(next_year, mce_monthly, specamt)
+ : 0.0
+ ;
+ double const z = list_bill_premium
+ (p0
+ ,p1
+ ,mode
+ ,yare_input_.EffectiveDate
+ ,yare_input_.ListBillDate
+ ,DBDiscountRate[year]
+ );
+ return round_min_premium()(z);
+}
+
+double BasicValues::GetListBillPremMlyDedEr
+ (int year
+ ,mcenum_mode mode
+ ,double specamt
+ ) const
+{
+ double const p0 = GetModalPremMlyDedEr(year, mce_monthly, specamt);
+ int const next_year = 1 + year;
+ double const p1 =
+ (next_year < GetLength())
+ ? GetModalPremMlyDedEr(next_year, mce_monthly, specamt)
+ : 0.0
+ ;
+ double const z = list_bill_premium
+ (p0
+ ,p1
+ ,mode
+ ,yare_input_.EffectiveDate
+ ,yare_input_.ListBillDate
+ ,DBDiscountRate[year]
+ );
+ return round_min_premium()(z);
+}
+
//============================================================================
double BasicValues::GetModalSpecAmtMax(double annualized_pmt) const
{