Level Term Pricing

Share on:

Overview

Introduction

The purpose of this article is to provide a step-by-step demonstration of how you can implement a level term pricing modeling project by using Rgogo Framework.

In the project, we will define and implement two level term insurance products. We will set pricing assumptions including mortality, lapse, expense and interest assumptions. Finally, we will run the model to solve the premium rates of the term products based on the pricing assumptions and the required expected profit margin.

You can follow this article to create the project from scratch, or simply download the source codes from GitHub by following the steps below:

  1. Visit GitHub repository: https://github.com/ActPersp/LTPricing
  2. Click Code green button. Click Download ZIP. The download process starts.
  3. Unzip the downloaded folder and move it to the location where you want to keep the sample project.
  4. Launch RStudio and open the project.

Software Prerequisites

Make sure the following softwares are installed in your computer:

  1. R: version 4.0.0 or above
  2. RStudio
  3. Rgogo package
  4. MortTables.CA package

To install the most recent versions of Rgogo and MortTables.CA packages if you have not done so, execute the following commands in RStudio console:

1library(devtools)
2install_github(repo = "ActPersp/Rgogo")
3install_github(repo = "ActPersp/MortTables.CA")

MortTables.CA is a package containing commonly used mortality tables published by Canadian Institute Actuaries. It is not required for an Rgogo modeling project, but is included here because this project uses Canadian mortality tables to set its pricing mortality assumption.

Model Specification

Product Features

In this project, we are going to develop the premium rate tables for the following two products:

  1. 20-year level term.
  2. Level term to age 65.

Both products have the following features:

  1. Premium rates are gender-distinct (male and female). In other words, each product has two premium rate tables, one for male and the other for female.

  2. There is a policy fee $100 per year regardless of face amount of the policy.

  3. The premium can be payable annually, semiannually, quarterly or monthgly. The modal premiums are determined by multiplying the annual premium by a modal factor as follows:

Mode Modal Premium
Semiannual Annual Premium x 0.51
Quarterly Annual Premium x 0.26
Monthly Annual Premium x 0.09
  1. Commission schedule is as follows:
Policy Year Percentage of Premium
1 25%
2 15%
3 - 5 10%
6 and thereafter No commission
  1. Manager override is 50% of the first-year commission.

Pricing Assumptions

The pricing assumptions are summarized below:

1. Mortality assumption

90% of Canadia Institute of Actuaries 97-04 mortality tables (by age last birthday), male and female.

2. Lapse assumption

Lapse rates vary by policy year as follows:

Policy Year Lapse Rate
1 15%
2 10%
3 7.5%
4 5%
5 and thereafter 2.5%

3. Expense assumption

The pricing expense assumption is set as follows:

  • Policy acquisition expense. Policy acquisition expense is an upfront expense incurred for marketing, selling, underwriting and issuing a new policy. In this pricing exercise, I assume that the per-policy acquisition expense is $500.

  • Policy maintenance expense. Policy maintenance expense is an ongoing expesne incurred by an insurance company to administer and service a policy. In this pricing exercise, I assume that the annual per-policy maintenance expense is $100 initially. This expense increases by 1% every year in subsequent years due to inflation.

4. Interest assumption

A level rate of 5% is used.

Pricing Methodology

The pricing method employs a discounted cash flow approach. Policy cash flows are projected during the coverage period according to the product features and pricing assumptions described above. A profit margin measurement is defined as the ratio of the present value of net cash inflows to the present value of premiums. The premium rate for each issue age is calculated such that the target profit margin is met.

Note that the expected profit margin above is conceptually the same as the contractual service margin under IFRS 17.

Model Implementation

Creating Project

The easiest way to create an Rgogo project is to use CreateProject function provided by Rgogo Framework. To do so, run the following scripts in RStudio console:

1library(Rgogo)
2CreateProject("LTPricing", "~/RProjects/")

There are two arguments in the above CreateProject function. The first argument is a string that represents the name of the project. To be consistent with the project that you can download from GitHub, the new project is named "LTPricing" (meaning level term pricing). If you would like to give it a different name, it is also fine.

The second argument is also a string. It is the location where the project folder will be created. The argument value in the above snippet is just for illustration. You should replace it with the path name that you would like to store the project.

Once CreateProject is executed successfully, open the newly created project using RStudio menu by clicking File > Open Project..., and select the folder of the new project.

Implementing Products

We need to implement two level term products: a 20-year level term and a level term to age 65.

To implement a 20-year level term plan:

  1. In RStudio, create a new R script file.
  2. Type (or copy and paste) the following codes:
 1New.Plan.LT20 <- function() {
 2   object <- IPlan.LT(
 3      covYears = 20,
 4      premTable = c(M = "Prem.LT20.M", F = "Prem.LT20.F"),
 5      polFee = 100,
 6      modFactor = c("1" = 1, "2" = 0.51, "4" = 0.26, "12" = 0.09),
 7      commSchd = c(0.25, 0.15, 0.1, 0.1, 0.1),
 8      ovrdOnCommSchd = 0.5
 9   )
10   return(object)
11}
  1. Save the R script file as Plan.LT20.R under R subfolder.

The code snippet above actually only does one thing: to define a function named New.Plan.LT20. Rgogo Framework has a term for this type of function. It is called a deployer of a plan object.

Generally speaking, a deployer is a special type of function in Rgogo Framework. It is used to deploy a model component. Conceptually, a model component can be a plan, an assumption, an actuarial methodology, etc. All components of an actuarial model must be deployed before you can run the model. The job of a deployer function is to save the component object in a special format that allows R to load back at a later time efficiently.

The name of a deployer function always starts with New., followed by the name of the object that you are going to deploy. In this case, the object to be deployed is a plan object called Plan.LT20, which is a 20-year level term plan.

Inside the definition of a deployer function, there is always a constructor of a modeling component. In this example, I used IPlan.LT constructor to create a level term plan object with the specified product fetures, then the deployer returns the created object.

Similarly, we can also create a level term to age 65 product with the following steps:

  1. In RStudio, create another new R script file.
  2. Type (or copy and paste) the following codes:
 1New.Plan.LT65 <- function() {
 2   object <- IPlan.LT(
 3      covToAge = 65,
 4      premTable = c(M = "Prem.LT65.M", F = "Prem.LT65.F"),
 5      polFee = 100,
 6      modFactor = c("1" = 1, "2" = 0.51, "4" = 0.26, "12" = 0.09),
 7      commSchd = c(0.25, 0.15, 0.1, 0.1, 0.1),
 8      ovrdOnCommSchd = 0.5
 9   )
10   return(object)
11}
  1. Save the R script file as Plan.LT65.R under R subfolder.

Up to this point, we have completed the setup of the products that we are going to price. Next, we are going to implement pricing assumptions.

Implementing Pricing Assumptions

Mortality Assumption

The pricing mortality assumption in this project is based on Canadian Institute of Actuaries 1997-04 (CIA 97-04) age-last-birthday motality tables for male and female. CIA 97-04 mortality tables are select and ultimate tables in which the select period is 15 years. In order to use these tables, make sure that you have installed MortTables.CA package from GitHub.

The assumption used in this pricing exercise is set at 90% of CIA 97-04 mortality male table for male and female table for female.

To implement the mortality assumption:

  1. In RStudio, create a new R script file.
  2. Type (or copy and paste) the following codes:
1New.MortAssump.LT <- function() {
2   object <- MortAssump(
3      mortTable = c(M = "Mort.CIA9704L.M", F = "Mort.CIA9704L.F"),
4      mortTableMult = 0.9
5   )
6   return(object)
7}
  1. Save the R script file as MortAssump.R under R subfolder.

In the above code snippet, we encountered a second type of deployer function, the deployer for a mortality assumption. As mentioned earlier, the name of the deployer starts with New., followed by the name of the mortality assumption object MortAssump.LT. Inside the definition of the deployer function, a mortality assumption object is created by calling a mortality assumption constructor MortAssump. The pricing assumption is set by assinging values to the constructor arguments. The created mortality assumption object is then returned by the deployer.

Lapse Assumption

The assumed lapse rates are 15% in the first policy year, 10% in the second year, 7.5% in the third year, 5% in the fourth year, and 2.5% in the fifth year and thereafter.

To implement the lapse assumption:

  1. In RStudio, create a new R script file.
  2. Type (or copy and paste) the following codes:
1New.LapseAssump.LT <- function() {
2   object <- LapseAssump(
3      lapseRate = RepeatTail(c(0.15, 0.1, 0.075, 0.05, 0.025), len = 100)
4   )
5   return(object)
6}
  1. Save the R script file as LapseAssump.R under R subfolder.

Expense Assumption

According to the expense assumption specified above:

  • Per-policy acquisition expense is $500.
  • Per-policy maintenance expense is $100 initially and increases by 1% every year in subsequent years due to inflation.

To implement this expense assumption:

  1. In RStudio, create a new R script file.
  2. Type (or copy and paste) the following codes:
1New.ExpnsAssump.LT <- function() {
2   object <- ExpnsAssump(
3      mePerPol = 100,              
4      mePerPolInflRate = 0.01,     
5      aePerPol = 500               
6   )
7   return(object)
8}
  1. Save the R script file as ExpnsAssump.R under R subfolder.

Here is another deployer function New.ExpnsAssump.LT for the deployment of expense assumtpion object. Again, its name starts with New., and what it does is to use a constructor ExpnsAssump to create an expense assumption object and return the object.

Interest Assumption

The pricing interest rate is 5%. To do so:

  1. In RStudio, create a new R script file.
  2. Type (or copy and paste) the following codes:
1New.IntrAssump.LT <- function() {
2   object <- IntrAssump(
3      rate = 0.05
4   )
5   return(object)
6}
  1. Save the R script file as IntrAssump.R under R subfolder.

Some observations on the above code snippet:

  • New.IntrAssump.LT is a deployer function to deploy the interest assumption IntrAssump.LT.
  • Inside the definition of the object deployer, we created the interest assumption object using a constructor IntrAssump. We set a level interest rate by assigning the value to rate argument of the constructor.
  • Finally, the created interest assumption object was return by the deployer.

Implementing Pricing Methodology

Rgogo Framework provides a pricing model Model.PremSolver. Model.PremSolver solves the premium rates of a product using discounted cash flow approach. For each issue age and risk class (e.g. gender, smoking status), it projects cash flows of the product according to pricing assumptions. It calculates the premium rates such that the expected profit margins are met. The profit margin in the model is defined as the ratio of the present value of net cash inflows to the present value of premiums during the entire coverage period.

The code snippet below sets up the pricing model:

 1# Create an argument set named ArgSet.LTPricing for the pricing model.
 2# An argument set contains all the input argument values required by a model.
 3New.ArgSet.LTPricing <- function() {
 4   object <- ArgSet.PremSolver(
 5      projStartDate = as.Date("2022-01-01"),
 6      pricIssAge = c(20L, 55L),
 7      pricFaceAmt = 500000,
 8      pricPremMode = 1L,
 9      unitFaceAmt = 1000,
10      targProfitMargin = 0.1,
11      digits = 2L,
12      mortAssump = "MortAssump.LT",
13      lapseAssump = "LapseAssump.LT",
14      intrAssump = "IntrAssump.LT",
15      expnsAssump = "ExpnsAssump.LT"
16   )
17   return(object)
18}
19
20# Create a pricing model and assigin the argument set ArgSet.LTPricing to it.
21New.Model.LTPricing <- function() {
22   object <- Model.PremSolver(args = "ArgSet.LTPricing")
23   return(object)
24}

Here are some observations of the above code snippet:

  • In the first block of the snippet, New.ArgSet.LTPricing is a deployer function of an argument set named ArgSet.LTPricing. In Rgogo Framework, an argument set contains all the settings of a model. Different models require different settings.

  • Inside the deployer, another function ArgSet.PremSolver was called to create an argument set for the pricing model Model.PremSolver. ArgSet.PremSolver is the constructor of the argument set of the pricing model. All model settings are specified in the constructor. The settings are described below.

  • projStartDate = as.Date("2022-01-01") sets the pricing projection starting date. This is the assumed issue date of a policy when projecting future cash flows.

  • pricIssAge = c(20L, 55L) sets the range of the possible issue ages of a product. In this case, the pricing model will calculate premium rates for issue ages from 20 to 55.

  • pricFaceAmt = 500000 sets the average face amount of a policy.

  • pricPremMode = 1L specifies the mode of the premium rates. In this example, the value of the mode is 1L (ingeger 1) which represents annual model. Therefore, the premium rates calculated by the pricing model will be annual premium rates. If you would like the model to calculate monthly premium rates, you can change the argument value to pricPremMode = 12L. Other possible modes include 2L for semiannual mode and 4L for quarterly mode. (Note that you have to change product modal factors in the product settings if you change the value of pricPremMode.)

  • unitFaceAmt = 1000 specifies the unit face amount that a premium rate is based on. In this example, the premium rates calculated by the model will be rates per thousand face amount.

  • targProfitMargin = 0.1 sets the pricing target profit margin to 10%. The target profit margin here is defined as the ratio of present value of net cash inflows to the present value of premiums.

  • digits = 2L specifies the number of decimal places of the solved premium rates.

  • The arguments mortAssump = "MortAssump.LT", lapseAssump = "LapseAssump.LT", intrAssump = "IntrAssump.LT" and expnsAssump = "ExpnsAssump.LT" specifies the pricing mortality, lapse, interest and expense assumptions respectively.

  • In the second block of the snippet, New.Model.LTPricing is the deloyer of the pricing model Model.LTPricing. Inside the function, it simply creates the pricing model using a model constructor Model.PremSolver, assigns the argument set to the model and returns it.

Running Model

Deploying Project

After you have completed all the settings of products, assumptions and methodology, you have to deploy the project before you can run the model calculation. Deployment is also needed every time you make changes in the above implementation.

To deploy the project, execute the following script in RStudio console:

1Rgogo::DeployProject("LTPricing", overwrite = TRUE)

DeployProject is a function provided by Rgogo Framework. It accepts two arguments. The first argument is the name of the modeling project that you are currently working on, which is "LTPricing" in this example.

The second argument is a logical value indicating if you would like to overwrite the existing modeling components that you deployed previously. To update the settings of existing components, set overwrite to TRUE. To add new components (e.g. adding another level term product) without changing existing ones, set overwrite to FALSE. (Note: It is recommended to always set overwrite to TRUE to ensure that all model components are updated.)

By deploying a project, Rgogo will utilize the deployer functions to create modeling components and save them in the "rda" (R data) format under "data" subfolder.

The deployment process must be completed successfully before you can run a model.

Running Calculation

Running the model calculation involves three steps:

  1. Attaching all R packages required by the model.

  2. Creating a batch job.

  3. Running the batch job.

The R scrips are as follows:

 1library(Rgogo)
 2library(MortTables.CA)
 3library(LTPricing)
 4
 5job <- Job.PremSolver(
 6   inpVars = list(Plan.LT20, Plan.LT65),
 7   dispatcher = function(plan) {return(Model.LTPricing)},
 8   exportToRda = TRUE,
 9   exportToExcel = "export/LTPremTables.xlsx"
10)
11
12Run(job)

In the above R scripts:

  • Three required packages are attached: Rgogo, MortTables.CA and LTPricing.

  • The variable job is an object created by the constructor Job.PremSolver. In the above script, it takes four arguments:

  • inpVars (input variables) contains a list of plans that you would like to price, which includes a 20-year level term plan and a level term to age 65 plan in this sample project.

  • dispatcher is an R function that takes a plan as input argument and returns a model object. The purpose of this dispatcher function is to specify the model to be used for each input variable. In the above scripts, both plans use the same model Model.LTPricing.

  • exportToRda specifies whether you would like to save the premium table objects generated by the model in rda (R data) format. All premium table objects are saved under data subfolder.

  • exportToExcel specifies the path of an Excel file if you would like to save the pricing result in Excel format.

  • Use method Run to run the batch job.

Save the above R scripts as a file under batch subfolder so that you can rerun the it at a later time if needed.

Inspecting Results

In the above scripts for running the model, we specified that we would like to save the premium table objects in rda format. We would also like to export the pricing results to an Excel file named "LTPremTables.xlsx" under "export" subfolder.

Assume that you have run the job successfully. Look for the following four files under "data" subfolder:

File name Description
Prem.LT20.M.rda Premium table for 20-year level term, male.
Prem.LT20.F.rda Premium table for 20-year level term, female.
Prem.LT65.M.rda Premium table for level term to age 65, male.
Prem.LT65.F.rda Premium table for level term to age 65, female.

To inspect the content of the 20-year level term male premium table, you can execute the following commands in RStudio console:

1Prem.LT20.M

The above allows you to view Prem.LT20.M premium table object from RStudio console. You can change table name to view other premium table objects.

To inspect the pricing results in Excel format, simply use Excel to open the file "LTPremTables.xlsx" located under export subfolder

Conclusion

The above pricing exercise is carried out with less than one hundred lines of R codes. By using Rgogo Framework, you do not need to be an R expert to build and run a model. It is also easy to tweak the product settings or assumptions to meet your customization needs. Feel free to experiment by changing the model and apply it to your actual work.

From this sample project, I hope that you have gained an insight into what Rgogo Framework can offer.

  1. LTPricing sample project source codes:

https://github.com/ActPersp/LTPricing

  1. Rgogo Framework source codes:

https://github.com/ActPersp/Rgogo

  1. MortTables.CA (Canadian Institute of Actuaries mortality tables) source codes:

https://github.com/ActPersp/MortTables.CA

  1. MortTables.US (US CSO mortality tables) source codes:

https://github.com/ActPersp/MortTables.US

  1. Have questions or report issues:

Email Edward Kuo at ekuo@actuarialperspective.com