lmi-commits
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[lmi-commits] [lmi] master 718ef64 6/6: Enforce a minimum single premium


From: Greg Chicares
Subject: [lmi-commits] [lmi] master 718ef64 6/6: Enforce a minimum single premium for "corridor" strategy
Date: Thu, 22 Apr 2021 11:57:26 -0400 (EDT)

branch: master
commit 718ef646313d7207737a114361be06ffc845b544
Author: Gregory W. Chicares <gchicares@sbcglobal.net>
Commit: Gregory W. Chicares <gchicares@sbcglobal.net>

    Enforce a minimum single premium for "corridor" strategy
    
    See the preceding commit for the rationale.
    
    Incidentally changed a nearby error message from
      "for " << yare_input_.InsuredName
    to
      "for " << yare_input_.InsuredName
    in case no name is entered, because a quoted empty string
      ...error message...for ''
    is confusing, whereas
      ...error message...for insured ''
    more clearly means that the insured's name is unspecified.
---
 basic_values.hpp |  2 ++
 ihs_avstrtgy.cpp | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 ihs_basicval.cpp |  2 ++
 3 files changed, 60 insertions(+), 1 deletion(-)

diff --git a/basic_values.hpp b/basic_values.hpp
index 13d2381..12bed55 100644
--- a/basic_values.hpp
+++ b/basic_values.hpp
@@ -338,6 +338,8 @@ class LMI_SO BasicValues
     oenum_modal_prem_type        TgtPremType;
     bool                         TgtPremFixedAtIssue;
     currency                     TgtPremMonthlyPolFee;
+    oenum_min_single_prem_type   MinSinglePremiumType;
+    double                       MinSinglePremiumMult;
     currency                     CurrCoiTable0Limit;
     currency                     CurrCoiTable1Limit;
     e_actuarial_table_method     CoiInforceReentry;
diff --git a/ihs_avstrtgy.cpp b/ihs_avstrtgy.cpp
index 83a445f..65e6542 100644
--- a/ihs_avstrtgy.cpp
+++ b/ihs_avstrtgy.cpp
@@ -30,6 +30,8 @@
 #include "outlay.hpp"
 
 #include <algorithm>
+#include <cmath>                        // ceil()
+#include <iomanip>
 #include <utility>
 
 /// Set specamt according to selected strategy in a non-solve year.
@@ -145,6 +147,59 @@ void AccountValue::PerformSpecAmtStrategy()
             strategy = mce_sa_input_scalar;
             }
         currency z = CalculateSpecAmtFromStrategy(j, 0, explicit_value, 
strategy);
+        if
+            (  0 == j
+            && yare_input_.EffectiveDate == yare_input_.InforceAsOfDate
+            && oe_min_single_premium_corr_mult == MinSinglePremiumType
+            && mce_sa_corridor == strategy
+            && !Solving
+            )
+            {
+            // SOMEDAY !! Duplicated above--refactor.
+            currency annualized_pmt =
+                    Outlay_->ee_premium_modes ()[0]
+                  * Outlay_->ee_modal_premiums()[0]
+                +   Outlay_->er_premium_modes ()[0]
+                  * Outlay_->er_modal_premiums()[0]
+                ;
+            double special_spec_amt =
+                  annualized_pmt
+                * GetCorridorFactor()[0]
+                / MinSinglePremiumMult
+                ;
+            // "0.01 + ": err on the conservative side for finicky users
+            double special_min_prem = std::ceil
+                (0.01 + MinSinglePremiumMult * m / (GetCorridorFactor()[0])
+                );
+            if(special_spec_amt < dblize(m))
+                {
+                alarum()
+                    << std::fixed << std::setprecision(2)
+                    << "For insured '"
+                    << yare_input_.InsuredName
+                    << "', premium "
+                    << annualized_pmt
+                    << " would correspond to a specified amount of "
+                    << std::setprecision(12)
+                    << special_spec_amt
+                    << std::setprecision(2)
+                    << ", which is premium "
+                    << annualized_pmt
+                    << " times corridor factor "
+                    << GetCorridorFactor()[0]
+                    << " divided by "
+                    << MinSinglePremiumMult
+                    << ", but "
+                    << m
+                    << " is the product's minimum specified amount."
+                    << " If the client is willing to pay more, a premium of "
+                    << std::setprecision(0)
+                    << special_min_prem
+                    << " would satisfy that product rule."
+                    << std::flush
+                    ;
+                }
+            }
         DeathBfts_->set_specamt(std::max(m, z), j, 1 + j);
         if
             (  j == InforceYear
@@ -159,7 +214,7 @@ void AccountValue::PerformSpecAmtStrategy()
                 << inforce_specamt
                 << " increased to the "
                 << m
-                << " minimum for '"
+                << " minimum for insured '"
                 << yare_input_.InsuredName
                 << "'."
                 << std::flush
diff --git a/ihs_basicval.cpp b/ihs_basicval.cpp
index 1b94fc1..4ec98fa 100644
--- a/ihs_basicval.cpp
+++ b/ihs_basicval.cpp
@@ -552,6 +552,8 @@ void BasicValues::SetPermanentInvariants()
     LMI_ASSERT(round_gross_premium().c(TgtPremMonthlyPolFee) == 
TgtPremMonthlyPolFee);
     // Assertion: see comments on GetModalPremTgtFromTable().
     LMI_ASSERT(C0 == TgtPremMonthlyPolFee || oe_modal_table == TgtPremType);
+    database().query_into(DB_MinSinglePremiumType , MinSinglePremiumType);
+    database().query_into(DB_MinSinglePremiumMult , MinSinglePremiumMult);
     database().query_into(DB_CurrCoiTable0Limit   , CurrCoiTable0Limit);
     database().query_into(DB_CurrCoiTable1Limit   , CurrCoiTable1Limit);
     LMI_ASSERT(C0                 <= CurrCoiTable0Limit);



reply via email to

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