The BasicTermASL_ME Model¶
Overview¶
The BasicTermASL_ME
is an adjustable step length(ASL) model, and projects the cashflows of
in-force policies at time 0 and future new business
policies issued after time 0.
As is the case with BasicTerm_ME
,
time-dependent cells in BasicTermASL_ME
carry out
calculations for all model points, and returns values for all the model points
as pandas Series or numpy array objects.
Unlike BasicTerm_ME
, with BasicTermASL_ME
the user can specify the length of each projection step,
from 1 month to 1 year. By default, the first 60 steps are monthly
projections, while steps after that are annual.
This model reads issue date information from model point input,
and handles policy anniversaries precisely.
Space Inheritance¶
BasicTermASL_ME
has 3 spaces, namely
Base
,
Projection
and Pricing
.
Base
is the base space
of Projection
and
and Pricing
, and
most Cells and References are defined in
Base
.
Pricing
is for calculating premiums.
In Pricing
,
the issue dates of all model points are set to the projection start date
in model_point()
.
premium_pp()
calculates
premiums per 1000 sum assured per payment from
loading_prem()
and
the present values of premiums and claims.
Pricing.premium_pp()
is brought in to Projection
as pricing_premium_pp
and
referenced by Projection.premium_pp()
.
Projection Steps¶
Projection steps are indexed with i
.
Step i
starts from one day after date_(i)
and ends on date_(i+1)
.
date_(0)
is the projection start date.
The start date is specified by a date string assigned to date_init
.
date_(i)
returns a Timestamp object.
The length of each projection step can be specified by
offset()
cells. offset(i)
should return
the length of step i
as a pandas DateOffset object,
so that the object can be added to
the Timestamp values of date_(i)
.
date_(i)
should always be an end-of-month date,
so offset(i)
should return DateOffset objects
such that date_(i)
are always end-of-month dates.
YearEnd and MonthEnd objects are good examples.
By default, ‘2021-12-31’ is set to date_init
,
and the first 60 steps are monthly and steps after that are annual.
>>> BasicTermASL_ME.Base.date_(0)
Timestamp('2021-12-31 00:00:00')
>>> BasicTermASL_ME.Base.date_(60)
Timestamp('2026-12-31 00:00:00')
>>> BasicTermASL_ME.Base.date_(61)
Timestamp('2027-12-31 00:00:00')
>>> BasicTermASL_ME.Base.offset(0)
<MonthEnd>
>>> BasicTermASL_ME.Base.offset(60)
<YearEnd: month=12>
Policy Anniversary¶
When a policy’s anniversary date is in a projection step,
some cells, such as pols_lapse()
and premiums()
calculate their values by separately
calculating the parts before and after the anniversary and then adding them up.
For example, the formula of pols_lapse()
looks like below:
def pols_lapse(i, j=None):
if j is None:
return pols_lapse(i, 'LAST') + pols_lapse(i, 'NEXT')
elif j == 'LAST':
lapse = 1 - (1 - lapse_rate(i))**(last_part(i) / 12)
return (pols_if_at(i, "BEG_STEP") - pols_death(i, 'LAST')) * lapse
elif j == 'NEXT':
lapse = 1 - (1 - lapse_rate(i+1))**(next_part(i) / 12)
return (pols_if_at(i, "AFT_NB") - pols_death(i, 'NEXT')) * lapse
else:
raise ValueError('invalid j')
When the second parameter j
is not given,
pols_lapse(i)
adds pols_lapse(i, 'LAST')
and pols_lapse(i, 'NEXT')
and returns the their sum.
pols_lapse(i, 'LAST')
returns
the number of lapsed policies before the
policy anniversary in Step i
.
pols_lapse(i, 'NEXT')
returns
the number of lapsed policies during Step i
after the
policy anniversary in Step i
.
If the length of Step i
is shorter than a full year,
then there may not be an anniversary date in Step i
, in which
case pols_lapse(i, 'LAST')
should
be the entire pols_lapse(i)
and
pols_lapse(i, 'NEXT')
should be zero.
The figure below illustrates adjacent policy terms
and the policy anniversary between them occurring during Step i
.
next_anniversary(i)
returns
the first anniversary date after date_(i)
for all model points as a Series of Timestamp objects.
months_in_step(i)
returns the number of
months in Step i
as an integer.
last_part(i)
returns the length of time
from date_(i)
to next_anniversary(i)
in months.
next_part(i)
returns the length of time
from next_anniversary(i)
to date_(i+1)
in months.
The fractional portions of last_part(i)
and next_part(i)
represent residual days.
Model Specifications¶
The Base
space¶
The sole base Space in the BasicTermASL_ME
model.
Base
is the only base Space defined
in the BasicTermASL_ME
model,
and it contains logic and data commonly used in the sub spaces
of Base
.
Parameters and References
(In all the sample code below,
the global variable Projection
refers to the
Projection
Space.)
- model_point_table¶
All model points as a DataFrame. The sample model point data was generated by generate_model_points_ASL.ipynb included in the library. By default,
model_point()
returns this entiremodel_point_table
. The DataFrame has an index namedpoint_id
, and has the following columns:age_at_entry
sex
policy_term
policy_count
sum_assured
issue_date
payment_freq
payment_term
Cells with the same names as these columns return the corresponding columns.
The DataFrame is saved in the Excel file model_point_table.xlsx located in the model folder.
model_point_table
is created by Projection’s new_pandas method, so that the DataFrame is saved in the separate file.
- disc_rate_ann¶
Annual discount rates by duration as a pandas Series.
>>> Projection.disc_rate_ann year 0 0.00000 1 0.00555 2 0.00684 3 0.00788 4 0.00866 146 0.03025 147 0.03033 148 0.03041 149 0.03049 150 0.03056 Name: disc_rate_ann, Length: 151, dtype: float64
The Series is saved in the Excel file disc_rate_ann.xlsx placed in the model folder.
disc_rate_ann
is created by Projection’s new_pandas method, so that the Series is saved in the separate file.See also
- mort_table¶
Mortality table by age and duration as a DataFrame. See basic_term_sample.xlsx included in this library for how the sample mortality rates are created.
>>> Projection.mort_table 0 1 2 3 4 5 Age 18 0.000231 0.000254 0.000280 0.000308 0.000338 0.000372 19 0.000235 0.000259 0.000285 0.000313 0.000345 0.000379 20 0.000240 0.000264 0.000290 0.000319 0.000351 0.000386 21 0.000245 0.000269 0.000296 0.000326 0.000359 0.000394 22 0.000250 0.000275 0.000303 0.000333 0.000367 0.000403 .. ... ... ... ... ... ... 116 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 117 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 118 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 119 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 120 1.000000 1.000000 1.000000 1.000000 1.000000 1.000000 [103 rows x 6 columns]
The DataFrame is saved in the Excel file mort_table.xlsx placed in the model folder.
mort_table
is created by Projection’s new_pandas method, so that the DataFrame is saved in the separate file.See also
- date_init¶
The projection start date as a string in the YYYY-MM-DD format. The start date needs to be an end-of-month date. By default, ‘2021-12-31’ is assigned.
Projection parameters¶
|
Date at each projection step. |
|
Number of elapsed months |
Returns the number of months in step |
|
Returns the number of months for step |
|
The upper bound for the time index |
|
Returns step index for months |
|
|
Time interval in step |
Model point data¶
|
The attained age at |
The age at entry of the model points |
|
Issue ages of the model points |
|
Target model points |
|
|
Duration of model points at |
|
Duration of model points at period |
|
The sex of the model points |
The sum assured of the model points |
|
The policy term of the model points. |
|
Payment frequency |
|
|
Average timing of premium payments. |
Premium payment period in years |
Assumptions¶
|
Mortality rate to be applied at time t |
MultiIndexed mortality table |
|
Acquisition expense per policy |
|
Annual maintenance expense per policy |
|
The inflation factor for Period |
|
Inflation rate |
|
|
Lapse rate |
|
Projection length in months |
Discount factors. |
|
Discount factors for premiums. |
|
|
Discount rate for period |
Policy attributes¶
|
Claim per policy |
Loading per premium |
|
Premium per policy |
|
|
Indicates if model points are active. |
|
Indicates if premiums are being paid |
|
Indicates if model points are maturing in step |
|
Length of time till next anniversary in step |
|
Lentgh of time after next anniversary |
|
Nex anniversary dates |
Net premium per policy |
|
|
Number of premium payments in step |
Policy decrement¶
|
Number of death |
|
Number of policies in-force |
|
Number of policies in-force |
|
Average number of policies in-force in step |
Initial number of policies in-force |
|
|
Number of lapse in step |
Number of maturing policies |
|
|
Number of new business policies |
|
Number of policies in-force for premium payment |
Cashflows¶
|
Premium income |
|
Claims |
|
Commissions |
|
Expenses |
|
Net cashflow |
Present values¶
Present value of claims |
|
Present value of commissions |
|
Present value of expenses |
|
Present value of net cashflows. |
|
Present value of policies in-force |
|
Present value of polices in-force for premium payments |
|
Present value of premiums |
Results¶
|
Output values of a given cells |
Result table of cashflows |
|
Result table of policy decrement |
|
Result table of present value of cashflows |
Validation¶
Check |
The Pricing
space¶
Space to calculate premiums
This space is for calculating premiums.
To calculate premiums, model_point()
adjusts
the issue ages read from
model_point_table
so that all the model points become new business issued the day after
date_(0)
.
Target model points |
|
Premium per policy |
|
Net premium 1000 sum assured. |
The Projection
space¶
Space to carry out cashflow projections
This space is for carrying out cashflow projections.
The only difference from its base space,
Base
is that
Pricing.premium_pp
is assigned to pricing_premium_pp
in this space,
and premium_pp()
is overridden to reference pricing_premium_pp
and returns the values of it.
Premium per policy |