lmi-commits
[Top][All Lists]
Advanced

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

[lmi-commits] [6199] Calculate special minimum premiums


From: Greg Chicares
Subject: [lmi-commits] [6199] Calculate special minimum premiums
Date: Sun, 31 May 2015 17:26:33 +0000

Revision: 6199
          http://svn.sv.gnu.org/viewvc/?view=rev&root=lmi&revision=6199
Author:   chicares
Date:     2015-05-31 17:26:31 +0000 (Sun, 31 May 2015)
Log Message:
-----------
Calculate special minimum premiums

Modified Paths:
--------------
    lmi/trunk/basic_values.hpp
    lmi/trunk/ihs_acctval.cpp
    lmi/trunk/ihs_avstrtgy.cpp
    lmi/trunk/ihs_basicval.cpp

Modified: lmi/trunk/basic_values.hpp
===================================================================
--- lmi/trunk/basic_values.hpp  2015-05-31 14:43:33 UTC (rev 6198)
+++ lmi/trunk/basic_values.hpp  2015-05-31 17:26:31 UTC (rev 6199)
@@ -231,6 +231,16 @@
         ,double      a_bft_amt
         ,double      a_specamt
         ) const;
+    double GetModalPremMlyDedEe
+        (int         a_year
+        ,mcenum_mode a_mode
+        ,double      a_specamt
+        ) const;
+    double GetModalPremMlyDedEr
+        (int         a_year
+        ,mcenum_mode a_mode
+        ,double      a_specamt
+        ) const;
     double GetModalSpecAmtMax      (double annualized_pmt) const;
     double GetModalSpecAmtTgt      (double annualized_pmt) const;
     double GetModalSpecAmtMinNonMec(double annualized_pmt) const;

Modified: lmi/trunk/ihs_acctval.cpp
===================================================================
--- lmi/trunk/ihs_acctval.cpp   2015-05-31 14:43:33 UTC (rev 6198)
+++ lmi/trunk/ihs_acctval.cpp   2015-05-31 17:26:31 UTC (rev 6199)
@@ -956,19 +956,39 @@
     ActualSpecAmt       = InvariantValues().SpecAmt[Year];
     TermSpecAmt         = InvariantValues().TermSpecAmt[Year];
 
-    // This "modal minimum" premium is designed for group plans. It is
-    // intended roughly to approximate the minimum payment (at a modal
-    // frequency chosen by the employer) necessary to prevent lapse if
-    // no other premium is paid.
+    // These "modal minimum" premiums are designed for group plans.
+    // They are intended roughly to approximate the minimum payment
+    // (at a modal frequency chosen by the employer) necessary to
+    // prevent lapse if no other premium is paid.
     //
     // Most other yearly values are posted to InvariantValues() in
-    // FinalizeYear(), but it seems clearer to post this one here
-    // where it's calculated along with 'MlyNoLapsePrem'.
-    InvariantValues().ModalMinimumPremium[Year] = GetModalMinPrem
-        (Year
-        ,InvariantValues().ErMode[Year].value()
-        ,InvariantValues().SpecAmt[Year]
-        );
+    // FinalizeYear(), but it seems clearer to post these here where
+    // they're calculated along with 'MlyNoLapsePrem'.
+    if(!TermIsNotRider)
+        {
+        InvariantValues().ModalMinimumPremium[Year] = GetModalMinPrem
+            (Year
+            ,InvariantValues().ErMode[Year].value()
+            ,InvariantValues().SpecAmt[Year]
+            );
+        }
+    else
+        {
+        InvariantValues().EeModalMinimumPremium[Year] = GetModalPremMlyDedEe
+            (Year
+            ,InvariantValues().ErMode[Year].value()
+            ,InvariantValues().TermSpecAmt[Year]
+            );
+        InvariantValues().ErModalMinimumPremium[Year] = GetModalPremMlyDedEr
+            (Year
+            ,InvariantValues().ErMode[Year].value()
+            ,InvariantValues().SpecAmt[Year]
+            );
+        InvariantValues().ModalMinimumPremium[Year] =
+              InvariantValues().EeModalMinimumPremium[Year]
+            + InvariantValues().ErModalMinimumPremium[Year]
+            ;
+        }
 
     // No-lapse premium generally changes whenever specamt changes for
     // any reason (e.g., elective increases or decreases, DBO changes,

Modified: lmi/trunk/ihs_avstrtgy.cpp
===================================================================
--- lmi/trunk/ihs_avstrtgy.cpp  2015-05-31 14:43:33 UTC (rev 6198)
+++ lmi/trunk/ihs_avstrtgy.cpp  2015-05-31 17:26:31 UTC (rev 6199)
@@ -215,8 +215,35 @@
             }
         case mce_pmt_minimum:
             {
-            double sa = ActualSpecAmt + TermSpecAmt;
-            return GetModalMinPrem(Year, a_CurrentMode, sa);
+            if(TermIsNotRider)
+                {
+                if(mce_solve_ee_prem == a_SolveForWhichPrem)
+                    {
+                    // Normally, ee mode is entered to match ee mode,
+                    // which represents the payment mode chosen by the
+                    // plan sponsor; but lmi has the extra flexibility
+                    // to behave reasonably if it's not so entered.
+                    return GetModalPremMlyDedEe(Year, a_CurrentMode, 
TermSpecAmt);
+                    }
+                else if(mce_solve_er_prem == a_SolveForWhichPrem)
+                    {
+                    return GetModalPremMlyDedEr(Year, a_CurrentMode, 
ActualSpecAmt);
+                    }
+                else
+                    {
+                    fatal_error()
+                        << "Type "
+                        << a_SolveForWhichPrem
+                        << " not allowed here."
+                        << LMI_FLUSH
+                        ;
+                    }
+                }
+            else
+                {
+                double sa = ActualSpecAmt + TermSpecAmt;
+                return GetModalMinPrem(Year, a_CurrentMode, sa);
+                }
             }
         case mce_pmt_target:
             {

Modified: lmi/trunk/ihs_basicval.cpp
===================================================================
--- lmi/trunk/ihs_basicval.cpp  2015-05-31 14:43:33 UTC (rev 6198)
+++ lmi/trunk/ihs_basicval.cpp  2015-05-31 17:26:31 UTC (rev 6199)
@@ -1160,11 +1160,173 @@
     z /= 1.0 - Loads_->target_premium_load_maximum_premium_tax()[a_year];
 
     z *= GetAnnuityValueMlyDed(a_year, a_mode);
+
     z += annual_charge;
 
     return round_min_premium()(z);
 }
 
+// The "-Ee" and "-Er" variants are written with preprocessor
+// conditionals for ease of comparison to the unsuffixed original.
+
+double BasicValues::GetModalPremMlyDedEe
+    (int         a_year
+    ,mcenum_mode a_mode
+    ,double      a_specamt
+    ) const
+{
+    double z = a_specamt * DBDiscountRate[a_year];
+    z *= GetCurrentTermRates()[a_year];
+#if 0
+    if(yare_input_.AccidentalDeathBenefit)
+        {
+        double r = MortalityRates_->AdbRates()[a_year];
+        z += r * std::min(a_specamt, AdbLimit);
+        }
+#endif // 0
+    if(yare_input_.SpouseRider)
+        {
+        double r = MortalityRates_->SpouseRiderRates(mce_gen_curr)[a_year];
+        z += r * yare_input_.SpouseRiderAmount;
+        }
+
+    if(yare_input_.ChildRider)
+        {
+        double r = MortalityRates_->ChildRiderRates()[a_year];
+        z += r * yare_input_.ChildRiderAmount;
+        }
+
+#if 0
+    if(true) // Written thus for parallelism and to keep 'r' local.
+        {
+        double r = Loads_->specified_amount_load(mce_gen_curr)[a_year];
+        z += r * std::min(a_specamt, SpecAmtLoadLimit);
+        }
+
+    z += Loads_->monthly_policy_fee(mce_gen_curr)[a_year];
+
+    double annual_charge = Loads_->annual_policy_fee(mce_gen_curr)[a_year];
+#endif // 0
+
+    if(yare_input_.WaiverOfPremiumBenefit)
+        {
+        double const r = MortalityRates_->WpRates()[a_year];
+        switch(WaiverChargeMethod)
+            {
+            case oe_waiver_times_specamt:
+                {
+                z += r * std::min(a_specamt, WpLimit);
+                }
+                break;
+            case oe_waiver_times_deductions:
+                {
+                z *= 1.0 + r;
+#if 0
+                annual_charge *= 1.0 + r;
+#endif // 0
+                }
+                break;
+            default:
+                {
+                fatal_error()
+                    << "Case '"
+                    << WaiverChargeMethod
+                    << "' not found."
+                    << LMI_FLUSH
+                    ;
+                }
+            }
+        }
+
+    z /= 1.0 - Loads_->target_premium_load_maximum_premium_tax()[a_year];
+
+    double u = DBDiscountRate[a_year];
+    z *= (1.0 - std::pow(u, 12.0 / a_mode)) / (1.0 - u);
+
+#if 0
+    z += annual_charge;
+#endif // 0
+
+    return round_min_premium()(z);
+}
+
+double BasicValues::GetModalPremMlyDedEr
+    (int         a_year
+    ,mcenum_mode a_mode
+    ,double      a_specamt
+    ) const
+{
+    double z = a_specamt * DBDiscountRate[a_year];
+    z *= GetBandedCoiRates(mce_gen_curr, a_specamt)[a_year];
+
+    if(yare_input_.AccidentalDeathBenefit)
+        {
+        double r = MortalityRates_->AdbRates()[a_year];
+        z += r * std::min(a_specamt, AdbLimit);
+        }
+
+#if 0
+    if(yare_input_.SpouseRider)
+        {
+        double r = MortalityRates_->SpouseRiderRates(mce_gen_curr)[a_year];
+        z += r * yare_input_.SpouseRiderAmount;
+        }
+
+    if(yare_input_.ChildRider)
+        {
+        double r = MortalityRates_->ChildRiderRates()[a_year];
+        z += r * yare_input_.ChildRiderAmount;
+        }
+#endif // 0
+
+    if(true) // Written thus for parallelism and to keep 'r' local.
+        {
+        double r = Loads_->specified_amount_load(mce_gen_curr)[a_year];
+        z += r * std::min(a_specamt, SpecAmtLoadLimit);
+        }
+
+    z += Loads_->monthly_policy_fee(mce_gen_curr)[a_year];
+
+    double annual_charge = Loads_->annual_policy_fee(mce_gen_curr)[a_year];
+
+    if(yare_input_.WaiverOfPremiumBenefit)
+        {
+        double const r = MortalityRates_->WpRates()[a_year];
+        switch(WaiverChargeMethod)
+            {
+            case oe_waiver_times_specamt:
+                {
+                z += r * std::min(a_specamt, WpLimit);
+                }
+                break;
+            case oe_waiver_times_deductions:
+                {
+                z *= 1.0 + r;
+                annual_charge *= 1.0 + r;
+                }
+                break;
+            default:
+                {
+                fatal_error()
+                    << "Case '"
+                    << WaiverChargeMethod
+                    << "' not found."
+                    << LMI_FLUSH
+                    ;
+                }
+            }
+        }
+
+    z /= 1.0 - Loads_->target_premium_load_maximum_premium_tax()[a_year];
+
+    double u = DBDiscountRate[a_year];
+    z *= (1.0 - std::pow(u, 12.0 / a_mode)) / (1.0 - u);
+
+    z += annual_charge;
+
+    return round_min_premium()(z);
+}
+
 //============================================================================
 double BasicValues::GetModalSpecAmtMax(double annualized_pmt) const
 {




reply via email to

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