lmi-commits
[Top][All Lists]
Advanced

[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
 {



reply via email to

[Prev in Thread] Current Thread [Next in Thread]