[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
{
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [lmi-commits] [6199] Calculate special minimum premiums,
Greg Chicares <=