Level Term Pricing
Overview
Introduction
The purpose of this article is to provide a stepbystep 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:
 Visit GitHub repository: https://github.com/ActPersp/LTPricing
 Click Code green button. Click Download ZIP. The download process starts.
 Unzip the downloaded folder and move it to the location where you want to keep the sample project.
 Launch RStudio and open the project.
Software Prerequisites
Make sure the following softwares are installed in your computer:
 R: version 4.0.0 or above
 RStudio
 Rgogo package
 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:
 20year level term.
 Level term to age 65.
Both products have the following features:

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

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

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 
 Commission schedule is as follows:
Policy Year  Percentage of Premium 

1  25% 
2  15% 
3  5  10% 
6 and thereafter  No commission 
 Manager override is 50% of the firstyear commission.
Pricing Assumptions
The pricing assumptions are summarized below:
1. Mortality assumption
90% of Canadia Institute of Actuaries 9704 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 perpolicy 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 perpolicy 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 20year level term and a level term to age 65.
To implement a 20year level term plan:
 In RStudio, create a new R script file.
 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}
 Save the R script file as
Plan.LT20.R
underR
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 20year 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:
 In RStudio, create another new R script file.
 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}
 Save the R script file as
Plan.LT65.R
underR
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 199704 (CIA 9704) agelastbirthday motality tables for male and female. CIA 9704 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 9704 mortality male table for male and female table for female.
To implement the mortality assumption:
 In RStudio, create a new R script file.
 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}
 Save the R script file as
MortAssump.R
underR
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:
 In RStudio, create a new R script file.
 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}
 Save the R script file as
LapseAssump.R
underR
subfolder.
Expense Assumption
According to the expense assumption specified above:
 Perpolicy acquisition expense is $500.
 Perpolicy maintenance expense is $100 initially and increases by 1% every year in subsequent years due to inflation.
To implement this expense assumption:
 In RStudio, create a new R script file.
 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}
 Save the R script file as
ExpnsAssump.R
underR
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:
 In RStudio, create a new R script file.
 Type (or copy and paste) the following codes:
1New.IntrAssump.LT < function() {
2 object < IntrAssump(
3 rate = 0.05
4 )
5 return(object)
6}
 Save the R script file as
IntrAssump.R
underR
subfolder.
Some observations on the above code snippet:
New.IntrAssump.LT
is a deployer function to deploy the interest assumptionIntrAssump.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 torate
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("20220101"),
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 namedArgSet.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 modelModel.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("20220101")
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 is1L
(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 topricPremMode = 12L
. Other possible modes include2L
for semiannual mode and4L
for quarterly mode. (Note that you have to change product modal factors in the product settings if you change the value ofpricPremMode
.) 
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"
andexpnsAssump = "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 modelModel.LTPricing
. Inside the function, it simply creates the pricing model using a model constructorModel.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:

Attaching all R packages required by the model.

Creating a batch job.

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
andLTPricing
. 
The variable
job
is an object created by the constructorJob.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 20year 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 modelModel.LTPricing
. 
exportToRda
specifies whether you would like to save the premium table objects generated by the model inrda
(R data) format. All premium table objects are saved underdata
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 20year level term, male. 
Prem.LT20.F.rda  Premium table for 20year 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 20year 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.
Useful Links
 LTPricing sample project source codes:
https://github.com/ActPersp/LTPricing
 Rgogo Framework source codes:
https://github.com/ActPersp/Rgogo
 MortTables.CA (Canadian Institute of Actuaries mortality tables) source codes:
https://github.com/ActPersp/MortTables.CA
 MortTables.US (US CSO mortality tables) source codes:
https://github.com/ActPersp/MortTables.US
 Have questions or report issues:
Email Edward Kuo at ekuo@actuarialperspective.com