Skip to content
Snippets Groups Projects
Commit ba38b54a authored by Reinhold Kainhofer's avatar Reinhold Kainhofer
Browse files

Implement contract$addExtension to add a contract extension after maturity...

Implement contract$addExtension to add a contract extension after maturity (both premium-free and with regular premiums)

* Allow premiumPeriod=0, indicating no premiums are paid (so an initial capital must be given)
* Fix aggregating values of child-blocks that go beyond the main contract's duration
* move sumInsured calculation to its own function for cleaner premium calculation. That function will be called earlier, so the CF data frames already use the correct sumInsured
* The additional_capital cash flow is no longer relative to the sumInsured, but gives the absolute capital
parent 0115e8e9
Branches
Tags
No related merge requests found
...@@ -227,7 +227,9 @@ InsuranceContract = R6Class( ...@@ -227,7 +227,9 @@ InsuranceContract = R6Class(
#' \code{policyPeriod} for regular premium payments for the whole #' \code{policyPeriod} for regular premium payments for the whole
#' contract period, while other premium payment durations indicate #' contract period, while other premium payment durations indicate
#' premium payments only for shorter periods than the whole contract #' premium payments only for shorter periods than the whole contract
#' duration). Default is equal to \code{policyPeriod} #' duration. Contract extensions without any premium payments are
#' indicated by \code{premiumPeriod}=0). Default is equal to
#' \code{policyPeriod}
#' * \code{sumInsured} ... The sum insured (i.e. survival benefit for #' * \code{sumInsured} ... The sum insured (i.e. survival benefit for
#' endowments, death benefit for whole/term life insurances, #' endowments, death benefit for whole/term life insurances,
#' annuity payments for annuities) #' annuity payments for annuities)
...@@ -375,6 +377,8 @@ InsuranceContract = R6Class( ...@@ -375,6 +377,8 @@ InsuranceContract = R6Class(
#' the child's values need to be translated to the parent contracts's #' the child's values need to be translated to the parent contracts's
#' time frame using this parameter #' time frame using this parameter
#' @param comment The comment to use in the history snapshot. #' @param comment The comment to use in the history snapshot.
#' @param blockType The type of block to be added (e.g. Dynamics, Extension,
#' etc.). Can be any (short) string.
#' @param ... parameters to be passed to \ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}{\code{InsuranceContract$new()()}} when #' @param ... parameters to be passed to \ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}{\code{InsuranceContract$new()()}} when
#' \code{block} is not given and a copy of the parent should be #' \code{block} is not given and a copy of the parent should be
#' created with overrides. #' created with overrides.
...@@ -469,7 +473,7 @@ InsuranceContract = R6Class( ...@@ -469,7 +473,7 @@ InsuranceContract = R6Class(
if (is.null(params)) params = list() if (is.null(params)) params = list()
if (!is.null(params$age)) params$age = params$age + t if (!is.null(params$age)) params$age = params$age + t
if (!is.null(params$policyPeriod)) params$policyPeriod = params$policyPeriod - t if (!is.null(params$policyPeriod)) params$policyPeriod = params$policyPeriod - t
if (!is.null(params$premiumPeriod)) params$premiumPeriod = max(1, params$premiumPeriod - t) if (!is.null(params$premiumPeriod)) params$premiumPeriod = max(0, params$premiumPeriod - t)
if (!is.null(params$deferralPeriod)) params$deferralPeriod = max(0, params$deferralPeriod - t) if (!is.null(params$deferralPeriod)) params$deferralPeriod = max(0, params$deferralPeriod - t)
if (!is.null(params$contractClosing)) params$contractClosing = params$contractClosing + years(t) if (!is.null(params$contractClosing)) params$contractClosing = params$contractClosing + years(t)
params$initialCapital = NULL params$initialCapital = NULL
...@@ -498,6 +502,88 @@ InsuranceContract = R6Class( ...@@ -498,6 +502,88 @@ InsuranceContract = R6Class(
arguments = list(...) arguments = list(...)
params[names(arguments)] = arguments[names(arguments)] params[names(arguments)] = arguments[names(arguments)]
params$comment = sprintf("Dynamic increase at time %d to sum %0.2f", t, NewSumInsured) params$comment = sprintf("Dynamic increase at time %d to sum %0.2f", t, NewSumInsured)
params$blockType = "Dynamics";
do.call(self$addBlock, params)
},
#' @description Add a contract extension after the contract has ended
#' (existing reserve is used as initial capital of the follow-up contract).
#'
#' @details When a contract expires, this function adds a follow-up contract
#' (with either the same or a different tariff), using the existing
#' reserve as `additionalCapital` at inception.
#' Technically, a child block using the new contract data of the extension
#' is added to the original contract. The over-all contract values are then
#' the sum of the original contract (providing values until expiration)
#' and the extension (providing values after the extension).
#'
#'
#' @param id The identifier of the child block to be inserted
#' @param t The time of the extension (relative to the parent block),
#' by default contract expiration of the parent block.
#' The extension is calculated independently (with time 0
#' describing its own start), but using the existing reserve as
#' initialCapital and the parent's parameters as fall-back values.
#' @param comment The comment to use in the history snapshot.
#' @param ... Additional parameters to be passed to
#' \ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}
#' {\code{InsuranceContract$new()()}} to create the contract
#' extension object.
#'
#' @examples
#' # TODO
addExtension = function(id = NULL, t = NULL, comment = paste0("Contract extension at time t=", t), ...) {
if (getOption('LIC.debug.addExtension', FALSE)) {
browser();
}
if (missing(id) | is.null(id)) {
# numbering extensions: Use nr. of blocks (except main) as a
# simplification => numbering is withint all dynamics,
# extensions, riders, etc.!
id = paste0("dyn", max(1, length(self$blocks)))
}
if (missing(t) | is.null(t)) {
# By default, use the parent's expiration, so the extension
# is appended after the original contract has ended.
t = self$Parameters$ContractData$policyPeriod
}
# TODO: Override only the required parameters
params = private$initParams
if (is.null(params)) params = list()
if (!is.null(params$age)) params$age = params$age + t
# Remaining premium period is kept, can be overwritten in the
# arguments to this method. If premiumPeriod has already ended,
# a premium-free extension is added by default
if (!is.null(params$premiumPeriod)) params$premiumPeriod = max(0, params$premiumPeriod - t)
if (!is.null(params$deferralPeriod)) params$deferralPeriod = max(0, params$deferralPeriod - t)
if (!is.null(params$contractClosing)) params$contractClosing = params$contractClosing + years(t)
# Use the existing reserve as initialCapital, reset premium parameter and sumInsured of the old contract
params$initialCapital = self$Values$reserves[t + 1, "contractual"]
params$sumInsured = NULL
params$premium = NULL
# TODO: Adjust non-constant parameters (e.g. profit rates or benefits given as vector) to the later start time
params$t = t
params$id = id
# Override with arguments explicitly given
arguments = list(...)
params[names(arguments)] = arguments[names(arguments)]
params$comment = comment
params$blockType = "Contract Extension"
# Two cases:
# 1) extension with premium => either premium or sumInsured must be given
# 2) premium-free extension => no premium, no sumInsured given => set premium to 0, calculate sumInsured
noPremiums = (is.null(params$sumInsured) || (params$sumInsured == 0)) && (is.null(params$premium) || (params$premium == 0));
if (noPremiums) {
params$premium = 0;
}
do.call(self$addBlock, params) do.call(self$addBlock, params)
}, },
...@@ -587,7 +673,7 @@ InsuranceContract = R6Class( ...@@ -587,7 +673,7 @@ InsuranceContract = R6Class(
t = valuesFrom); t = valuesFrom);
if (additionalCapital > 0) { if (additionalCapital > 0) {
self$values$cashFlows[as.character(premiumCalculationTime), "additional_capital"] = additionalCapital / self$values$ContractData$sumInsured self$Values$cashFlows[as.character(premiumCalculationTime), "additional_capital"] = additionalCapital
} }
if (recalculatePremiumSum) { if (recalculatePremiumSum) {
...@@ -626,6 +712,13 @@ InsuranceContract = R6Class( ...@@ -626,6 +712,13 @@ InsuranceContract = R6Class(
} }
if (calculate == "presentvalues") return(invisible(self)); if (calculate == "presentvalues") return(invisible(self));
# If we have the premium given, determine the sumInsured from it
# Since the cash flows depend on the sumInsured (in particular, )
if (is.null(self$Parameters$ContractData$sumInsured)) {
self$Parameters$ContractData$sumInsured = private$calculateSumInsured(calculationTime = premiumCalculationTime)
}
# the premiumCalculation function returns the premiums AND the cofficients, # the premiumCalculation function returns the premiums AND the cofficients,
# so we have to extract the coefficients and store them in a separate variable # so we have to extract the coefficients and store them in a separate variable
if (recalculatePremiums) { if (recalculatePremiums) {
...@@ -754,12 +847,31 @@ InsuranceContract = R6Class( ...@@ -754,12 +847,31 @@ InsuranceContract = R6Class(
self$Values$reservesBalanceSheet = consolidateField("reservesBalanceSheet", keyed = TRUE) self$Values$reservesBalanceSheet = consolidateField("reservesBalanceSheet", keyed = TRUE)
# TODO: Basic Data cannot simply be summed, e.g. the interest rate! # TODO: Basic Data cannot simply be summed, e.g. the interest rate!
self$Values$basicData = consolidateField("basicData") self$Values$basicData = consolidateField("basicData")
# self$Values$basicData[,c("InterestRate", "PolicyDuration", "PremiumPeriod")] = NULL
# Some fields can NOT be summed, but have to be left untouched. # Some fields can NOT be summed, but have to be left untouched.
# Hard-code these to use the values from the main contract part: # Hard-code these to use the values from the main contract part:
self$Values$reservesBalanceSheet[,c("date", "time")] = self$blocks[[1]]$Values$reservesBalanceSheet[,c("date", "time")] rows = nrow(self$Values$reservesBalanceSheet)
self$Values$basicData[,c("InterestRate", "PolicyDuration", "PremiumPeriod")] = self$blocks[[1]]$Values$basicData[,c("InterestRate", "PolicyDuration", "PremiumPeriod")] colDt = rep(as.Date(NA), rows)
colTime = rep(NA_real_, rows)
colIntR = rep(NA_real_, rows)
colDur = rep(NA_real_, rows)
colPrem = rep(NA_real_, rows)
for (b in self$blocks) {
start = b$Parameters$ContractData$blockStart
colDt = coalesce(colDt, pad0(b$Values$reservesBalanceSheet[,"date"], start = start, value = as.Date(NA), value.start = as.Date(NA), l = rows))
colTime = coalesce(colTime, pad0(b$Values$reservesBalanceSheet[,"time"] + start, start = start, value = NA, value.start = NA, l = rows))
colIntR = coalesce(colIntR, pad0(b$Values$basicData[,"InterestRate"], start = start, value = NA, value.start = NA, l = rows))
colDur = coalesce(colDur, pad0(b$Values$basicData[,"PolicyDuration"], start = start, value = NA, value.start = NA, l = rows))
colPrem = coalesce(colPrem, pad0(b$Values$basicData[,"PremiumPeriod"], start = start, value = NA, value.start = NA, l = rows))
}
self$Values$reservesBalanceSheet[,"date"] = colDt;
self$Values$reservesBalanceSheet[,"time"] = colTime;
self$Values$basicData[,"InterestRate"] = colIntR
self$Values$basicData[,"PolicyDuration"] = colDur
self$Values$basicData[,"PremiumPeriod"] = colPrem
self$Values$int$l = rows
invisible(self) invisible(self)
}, },
...@@ -958,10 +1070,10 @@ InsuranceContract = R6Class( ...@@ -958,10 +1070,10 @@ InsuranceContract = R6Class(
self$Parameters$ContractData$premiumPeriod = valueOrFunction( self$Parameters$ContractData$premiumPeriod = valueOrFunction(
self$Parameters$ContractData$premiumPeriod, self$Parameters$ContractData$premiumPeriod,
params = self$Parameters, values = self$Values); params = self$Parameters, values = self$Values);
# At least 1 year premium period, at most contract duration! # premium period is at most contract duration!
self$Parameters$ContractData$premiumPeriod = self$Parameters$ContractData$premiumPeriod =
min( min(
max(self$Parameters$ContractData$premiumPeriod, 1), self$Parameters$ContractData$premiumPeriod,
self$Parameters$ContractData$policyPeriod self$Parameters$ContractData$policyPeriod
); );
...@@ -1066,6 +1178,9 @@ InsuranceContract = R6Class( ...@@ -1066,6 +1178,9 @@ InsuranceContract = R6Class(
calculatePresentValuesCosts = function(...) { calculatePresentValuesCosts = function(...) {
self$tarif$presentValueCashFlowsCosts(params = self$Parameters, values = self$Values, ...); self$tarif$presentValueCashFlowsCosts(params = self$Parameters, values = self$Values, ...);
}, },
calculateSumInsured = function(...) {
self$tarif$sumInsuredCalculation(params = self$Parameters, values = self$Values, ...)
},
calculatePremiums = function(...) { calculatePremiums = function(...) {
self$tarif$premiumCalculation(params = self$Parameters, values = self$Values, ...); self$tarif$premiumCalculation(params = self$Parameters, values = self$Values, ...);
}, },
......
This diff is collapsed.
...@@ -39,6 +39,7 @@ for single-premium contracts. ...@@ -39,6 +39,7 @@ for single-premium contracts.
contracts with multiple parts, e.g. dynamic increases), contracts with multiple parts, e.g. dynamic increases),
default = "Hauptvertrag"} default = "Hauptvertrag"}
\item{\code{$sumInsured}}{Sum insured, default = 100,000} \item{\code{$sumInsured}}{Sum insured, default = 100,000}
\item{\code{$premium}}{Premium, given to determine the sumInsured (default: NULL)}
\item{\code{$initialCapital}}{Reserve/Capital that is already available \item{\code{$initialCapital}}{Reserve/Capital that is already available
at contract inception, e.g. from a previous contract. No tax at contract inception, e.g. from a previous contract. No tax
or acquisition costs are applied to this capital.} or acquisition costs are applied to this capital.}
......
...@@ -159,7 +159,9 @@ for single-premium contracts, \code{premiumPeriod} equals ...@@ -159,7 +159,9 @@ for single-premium contracts, \code{premiumPeriod} equals
\code{policyPeriod} for regular premium payments for the whole \code{policyPeriod} for regular premium payments for the whole
contract period, while other premium payment durations indicate contract period, while other premium payment durations indicate
premium payments only for shorter periods than the whole contract premium payments only for shorter periods than the whole contract
duration). Default is equal to \code{policyPeriod} duration. Contract extensions without any premium payments are
indicated by \code{premiumPeriod}=0). Default is equal to
\code{policyPeriod}
\item \code{sumInsured} ... The sum insured (i.e. survival benefit for \item \code{sumInsured} ... The sum insured (i.e. survival benefit for
endowments, death benefit for whole/term life insurances, endowments, death benefit for whole/term life insurances,
annuity payments for annuities) annuity payments for annuities)
...@@ -212,6 +214,14 @@ as its own \code{sumInsured}. ...@@ -212,6 +214,14 @@ as its own \code{sumInsured}.
total values of the overall contract. total values of the overall contract.
}\if{html}{\out{</div>}} }\if{html}{\out{</div>}}
When a contract expires, this function adds a follow-up contract
(with either the same or a different tariff), using the existing
reserve as \code{additionalCapital} at inception.
Technically, a child block using the new contract data of the extension
is added to the original contract. The over-all contract values are then
the sum of the original contract (providing values until expiration)
and the extension (providing values after the extension).
This method calculates all contract values (potentially This method calculates all contract values (potentially
starting from and preserving all values before a later time starting from and preserving all values before a later time
\code{valuesFrom}). This function is not meant to be called \code{valuesFrom}). This function is not meant to be called
...@@ -279,6 +289,12 @@ are stored in a list of profit scenarios inside the contract. ...@@ -279,6 +289,12 @@ are stored in a list of profit scenarios inside the contract.
# TODO # TODO
## ------------------------------------------------
## Method `InsuranceContract$addExtension`
## ------------------------------------------------
# TODO
## ------------------------------------------------ ## ------------------------------------------------
## Method `InsuranceContract$premiumWaiver` ## Method `InsuranceContract$premiumWaiver`
## ------------------------------------------------ ## ------------------------------------------------
...@@ -349,6 +365,7 @@ contract state and its values before the change).} ...@@ -349,6 +365,7 @@ contract state and its values before the change).}
\item \href{#method-InsuranceContract-addHistorySnapshot}{\code{InsuranceContract$addHistorySnapshot()}} \item \href{#method-InsuranceContract-addHistorySnapshot}{\code{InsuranceContract$addHistorySnapshot()}}
\item \href{#method-InsuranceContract-addBlock}{\code{InsuranceContract$addBlock()}} \item \href{#method-InsuranceContract-addBlock}{\code{InsuranceContract$addBlock()}}
\item \href{#method-InsuranceContract-addDynamics}{\code{InsuranceContract$addDynamics()}} \item \href{#method-InsuranceContract-addDynamics}{\code{InsuranceContract$addDynamics()}}
\item \href{#method-InsuranceContract-addExtension}{\code{InsuranceContract$addExtension()}}
\item \href{#method-InsuranceContract-calculateContract}{\code{InsuranceContract$calculateContract()}} \item \href{#method-InsuranceContract-calculateContract}{\code{InsuranceContract$calculateContract()}}
\item \href{#method-InsuranceContract-consolidateBlocks}{\code{InsuranceContract$consolidateBlocks()}} \item \href{#method-InsuranceContract-consolidateBlocks}{\code{InsuranceContract$consolidateBlocks()}}
\item \href{#method-InsuranceContract-premiumWaiver}{\code{InsuranceContract$premiumWaiver()}} \item \href{#method-InsuranceContract-premiumWaiver}{\code{InsuranceContract$premiumWaiver()}}
...@@ -467,6 +484,7 @@ Add a child contract block (e.g. a dynamic increase or a rider) to an insurance ...@@ -467,6 +484,7 @@ Add a child contract block (e.g. a dynamic increase or a rider) to an insurance
block = NULL, block = NULL,
t = block$Values$int$blockStart, t = block$Values$int$blockStart,
comment = paste0("Additional block at time t=", t), comment = paste0("Additional block at time t=", t),
blockType = "Dynamics",
... ...
)}\if{html}{\out{</div>}} )}\if{html}{\out{</div>}}
} }
...@@ -489,6 +507,9 @@ time frame using this parameter} ...@@ -489,6 +507,9 @@ time frame using this parameter}
\item{\code{comment}}{The comment to use in the history snapshot.} \item{\code{comment}}{The comment to use in the history snapshot.}
\item{\code{blockType}}{The type of block to be added (e.g. Dynamics, Extension,
etc.). Can be any (short) string.}
\item{\code{...}}{parameters to be passed to \ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}{\code{InsuranceContract$new()()}} when \item{\code{...}}{parameters to be passed to \ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}{\code{InsuranceContract$new()()}} when
\code{block} is not given and a copy of the parent should be \code{block} is not given and a copy of the parent should be
created with overrides.} created with overrides.}
...@@ -555,6 +576,50 @@ they can be overridden per dynamic increase block.} ...@@ -555,6 +576,50 @@ they can be overridden per dynamic increase block.}
} }
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-InsuranceContract-addExtension"></a>}}
\if{latex}{\out{\hypertarget{method-InsuranceContract-addExtension}{}}}
\subsection{Method \code{addExtension()}}{
Add a contract extension after the contract has ended
(existing reserve is used as initial capital of the follow-up contract).
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{InsuranceContract$addExtension(
id = NULL,
t = NULL,
comment = paste0("Contract extension at time t=", t),
...
)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{id}}{The identifier of the child block to be inserted}
\item{\code{t}}{The time of the extension (relative to the parent block),
by default contract expiration of the parent block.
The extension is calculated independently (with time 0
describing its own start), but using the existing reserve as
initialCapital and the parent's parameters as fall-back values.}
\item{\code{comment}}{The comment to use in the history snapshot.}
\item{\code{...}}{Additional parameters to be passed to
\ifelse{html}{\href{#method-new}{\code{InsuranceContract$new()}}}
{\code{InsuranceContract$new()()}} to create the contract
extension object.}
}
\if{html}{\out{</div>}}
}
\subsection{Examples}{
\if{html}{\out{<div class="r example copy">}}
\preformatted{# TODO
}
\if{html}{\out{</div>}}
}
} }
\if{html}{\out{<hr>}} \if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-InsuranceContract-calculateContract"></a>}} \if{html}{\out{<a id="method-InsuranceContract-calculateContract"></a>}}
......
...@@ -821,6 +821,40 @@ array has NOT yet been filled! Instead, all premiums already calculated ...@@ -821,6 +821,40 @@ array has NOT yet been filled! Instead, all premiums already calculated
argument. argument.
} }
}
\if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-InsuranceTarif-sumInsuredCalculation"></a>}}
\if{latex}{\out{\hypertarget{method-InsuranceTarif-sumInsuredCalculation}{}}}
\subsection{Method \code{sumInsuredCalculation()}}{
Calculate the sumInsured of the InsuranceContract given the
parameters and premiums given and teh , present values already calculated and
stored in the \code{params} and \code{values} lists.
\subsection{Usage}{
\if{html}{\out{<div class="r">}}\preformatted{InsuranceTarif$sumInsuredCalculation(
params,
values,
calculationTime = values$int$premiumCalculationTime
)}\if{html}{\out{</div>}}
}
\subsection{Arguments}{
\if{html}{\out{<div class="arguments">}}
\describe{
\item{\code{params}}{Contract-specific, full set of parameters of the contract
(merged parameters of the defaults, the tariff, the profit participation
scheme and the contract)}
\item{\code{values}}{Contract values calculated so far (in the \code{contract$Values}
list) then this method is called by the contract object}
\item{\code{calculationTime}}{the time when the sumInsured should be recalculated from the given premium}
}
\if{html}{\out{</div>}}
}
\subsection{Details}{
Not to be called directly, but implicitly by the \link{InsuranceContract} object.
}
} }
\if{html}{\out{<hr>}} \if{html}{\out{<hr>}}
\if{html}{\out{<a id="method-InsuranceTarif-premiumCalculation"></a>}} \if{html}{\out{<a id="method-InsuranceTarif-premiumCalculation"></a>}}
......
...@@ -4,12 +4,14 @@ ...@@ -4,12 +4,14 @@
\alias{head0} \alias{head0}
\title{Set all entries of the given vector to 0 up until index 'start'} \title{Set all entries of the given vector to 0 up until index 'start'}
\usage{ \usage{
head0(v, start = 0) head0(v, start = 0, value.start = 0)
} }
\arguments{ \arguments{
\item{v}{the vector to modify} \item{v}{the vector to modify}
\item{start}{how many leading elements to zero out} \item{start}{how many leading elements to zero out}
\item{value.start}{the value to insert before the start index.}
} }
\value{ \value{
the vector \code{v} with the first \code{start} elements replaced by 0. the vector \code{v} with the first \code{start} elements replaced by 0.
......
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
\alias{pad0} \alias{pad0}
\title{Pad a vector with 0 to a desired length} \title{Pad a vector with 0 to a desired length}
\usage{ \usage{
pad0(v, l, value = 0, start = 0) pad0(v, l, value = 0, start = 0, value.start = 0)
} }
\arguments{ \arguments{
\item{v}{the vector to pad with 0} \item{v}{the vector to pad with 0}
...@@ -14,9 +14,12 @@ pad0(v, l, value = 0, start = 0) ...@@ -14,9 +14,12 @@ pad0(v, l, value = 0, start = 0)
\item{value}{the value to pad with (if padding is needed). Default to 0, but \item{value}{the value to pad with (if padding is needed). Default to 0, but
can be overridden to pad with any other value.} can be overridden to pad with any other value.}
\item{start}{the first \code{start} values are always set to 0 (default is 0), \item{start}{the first \code{start} values are always set to 0 (default is 0,
can be changed using the \code{value.start} argument),
the vector \code{v} starts only after these leading zeroes. The number of the vector \code{v} starts only after these leading zeroes. The number of
leading zeroes counts towards the desired length} leading zeroes counts towards the desired length}
\item{value.start}{the value to insert before the start index.}
} }
\value{ \value{
returns the vector \code{v} padded to length \code{l} with value \code{value} (default 0). returns the vector \code{v} padded to length \code{l} with value \code{value} (default 0).
......
...@@ -5,19 +5,16 @@ ...@@ -5,19 +5,16 @@
\title{Pad the vector \code{v} to length \code{l} by repeating the last entry of the \title{Pad the vector \code{v} to length \code{l} by repeating the last entry of the
vector.} vector.}
\usage{ \usage{
padLast(v, l, start = 0) padLast(v, ...)
} }
\arguments{ \arguments{
\item{v}{the vector to pad by repeating the last element} \item{v}{the vector to pad by repeating the last element}
\item{l}{the desired (resulting) length of the vector} \item{...}{arguments passed through to \code{pad0}}
\item{start}{the first \code{start} values are always set to 0 (default is 0),
the vector \code{v} starts only after these leading zeroes. The number of
leading zeroes counts towards the desired length}
} }
\description{ \description{
This function callc \code{\link[=pad0]{pad0()}} with the last element of the vector as padding value This function is just a trivial wrapper around \code{pad0} and only calls \code{\link[=pad0]{pad0()}}
with the last element of the vector as padding value instead of the default 0.
} }
\examples{ \examples{
padLast(1:5, 7) # 5 is repeated twice padLast(1:5, 7) # 5 is repeated twice
......
test_that("Extend contract by $addExtension", {
library(MortalityTables)
mortalityTables.load("Austria_Census")
Tarif.EndowmentA = InsuranceTarif$new(
name = "Example Tariff - Endowment 1981",
type = "endowment",
tarif = "E1-RP81",
desc = "An endowment with regular premiums (standard tariff)",
mortalityTable = mort.AT.census.1981.male,
cost = initializeCosts(alpha = 0.04, gamma.contract = 0.0005, unitcosts = 10),
i = 0.03
)
Tarif.EndowmentB = Tarif.EndowmentA$createModification(
name = "Example Tariff - Endowment 2001",
tarif = "E1-RP01",
mortalityTable = mort.AT.census.2001.male,
cost = initializeCosts(alpha = 0.024, gamma.contract = 0.00075, unitcosts = 20),
i = 0.01)
ContractA = InsuranceContract$new(
tarif = Tarif.EndowmentA,
age = 40, policyPeriod = 20,
sumInsured = 10000,
contractClosing = as.Date("2000-07-01")
)
# premium-free extension
ContractB = ContractA$clone()$addExtension(id = "Verlängerung1", contractPeriod = 5, premiumPeriod = 0)
expect_equal(ContractB$blocks$Verlängerung1$Parameters$ContractData$sumInsured, 15117.03896)
# extension with given sumInsured resulting in 0 premiums
ContractC = ContractA$clone()$addExtension(id = "Verlängerung1", contractPeriod = 5, sumInsured = 15117.03896)
expect_equal(ContractC$blocks$Verlängerung1$Values$premiums[["gross"]], 0, tolerance = 1e-06)
# extension with increased sumInsured: real premiums are charged, reserves start from the existing reserve:
ContractD = ContractA$clone()$addExtension(id = "Verlängerung1", contractPeriod = 5, sumInsured = 20000)
expect_equal(ContractD$blocks$Verlängerung1$Values$premiums[["written"]], 315.109)
expect_equal(ContractD$blocks$Verlängerung1$Values$reserves[["0", "contractual"]], 10000)
})
...@@ -1342,6 +1342,192 @@ One can give a base name and an extra name to distinguish different calculations ...@@ -1342,6 +1342,192 @@ One can give a base name and an extra name to distinguish different calculations
in the file names. in the file names.
# Contracts combining multiple contract layers / slices
In real life, an insurance contract is not merely signed initially and then left
untouched until it expires or is surrendered. Rather, some contracts already have
an automatic increase of the sumInsured or the premium (depending usually on some
kind of observed consumer price index) included in the contract. Other contracts
have additional biometric riders like an additional death or disability cover.
Other contracts are extended after their expiration, using the existing reserve
as a one-time payment (`initialCapital`) for the follow-up contract.
In all these cases, the original contract can be calculated as an `InsuranceContract`,
but the additional dynamic increases, additional riders or extensions are mathematically
calculated as separate contracts (potentiall using different tariffs / types of
insurance), although most parameters are shared from the original main contract.
In addition to modelling one particular tariff, the LifeInsuranceContract class
can also act as a wrapper to bundle multiple related contracts / contract slices
together. The class provides several methods for this:
* `$addDynamics(t, NewSumInsured, SumInsuredDelta, id, ...)`:
Include (at time `t`) a dynamic increase of premium or sumInsured, but
with the same basic parameters (age, tariff, maturity,
interest rate, etc.) as the main contract. The increase can
be given either as the new total sumInsured or as the
increase in the sumInsured caused by that one increase. Other parameters
given as `...` are passed on to the `InsuranceContract$new` constructor
of the layer for the dynamic increase. This also means that one can
potentially override all parameters for the increase, including the
tariff or the interest rate.
* `$addExtension(t = NULL, policyPeriod, ...)`
After the original contracts maturity, append a follow-up contract (by
default paid-up, i.e. no new premiums are paid) that uses the existing
reserve as initial capital. By default, no further premiums are paid
and the sumInsured is calculated from the existing reserve and the tariff
of the extension. One can, however, also provide either a sumInsured or
a premium of the contract extension. In that case, the premium or the sumInsured
will be calculated, using the existing reserves as initialCapital.
* `$addBlock(id = NULL, block = NULL, t, ...)`
Generic function to add a child block to the contract. If a block (object
of type `LifeInsuranceContract` is passed, it is inserted and flagged as
starting at time `t`. If no block is passed, a new insurance contract
is created using the arguments passed as `...`, combined with the
parameters of the main contract. If `t>0`, the child block starts later
than the original contract. It is also possible that the child block extends
beyond the maturity of the original contract (e.g. contract extensions
are implemented this way).
In these case, the main contract will have several child blocks (also
LifeInsuranceContract objects), and the values of the main contract object will
be the aggregated values of all its children, rather than the results of a
calculation from an underlying tariff.
## Dynamic increases
To increase the sum insured or premium by a given value ()
```{r contractLayers}
# Contract with initial capital of 5.000 EUR
ctr.dynInc = InsuranceContract$new(
tarif = Tarif.Endowment,
sumInsured = 10000,
age = 40, policyPeriod = 10,
contractClosing = as.Date("2020-09-01")
)$
addDynamics(t = 1, SumInsuredDelta = 1000)$
addDynamics(t = 5, NewSumInsured = 15000)$
addDynamics(t = 8, SumInsuredDelta = 4000)
ctr.dynInc$Values$basicData
```
As seen in this table, the sum insured increases and the premium with it. The
`PremiumPayment` column is no longer a 0/1-column indicating whether a premium is
paid or not, but rather is the number of blocks/layers where a premium is paid.
The individual blocks can be accessed with the `contract$blocks` list:
```{r contractLayers.blocks}
for (b in ctr.dynInc$blocks) {
cat(paste0("Block: ", b$Parameters$ContractData$id, ", starts at t=", b$Parameters$ContractData$blockStart, ", policyPeriod=", b$Parameters$ContractData$policyPeriod, "\n"))
}
```
Each block is formally handled like a separate contract, each starting at its own time `t=0`.
The over-all contract then takes care to correctly shift the child blocks to the
time relative to the parent block, before aggregating the data:
```{r contractLayers.blocks.data}
ctr.dynInc$blocks$Hauptvertrag$Values$basicData
ctr.dynInc$blocks$dyn1$Values$basicData
ctr.dynInc$blocks$dyn2$Values$basicData
ctr.dynInc$blocks$dyn3$Values$basicData
```
## General biometric riders
Instead of adding a dynamic increase, which typically uses the same tariff as
the main contract, it is also possible to bundle e.g. a protection rider to a
saving product. The savings product and the protection rider are calculated
individually as child blocks, and the overall values of the contract are
obtained by aggregating the values from the two children (savings and protection
part). Of course, in this scenario, the combined sumInsured of the overall contract
is not meaningful, but the sumInsured of the individual blocks is.
```{r addBlock.rider}
ctr.main = InsuranceContract$new(
tarif = Tarif.Endowment,
sumInsured = 10000,
age = 40, policyPeriod = 10,
contractClosing = as.Date("2020-09-01")
)
ctr.Rider = InsuranceContract$new(
tarif = Tarif.L71U,
sumInsured = 100000,
age = 40, policyPeriod = 10,
contractClosing = as.Date("2020-09-01")
)
ctr.main$addBlock(block = ctr.Rider)
ctr.withRider = InsuranceContract$new(
tarif = Tarif.Endowment,
sumInsured = 10000,
age = 40, policyPeriod = 10,
contractClosing = as.Date("2020-09-01")
)$
addBlock(tarif = Tarif.L71U, sumInsured = 100000,
age = 40, policyPeriod = 10,
contractClosing = as.Date("2020-09-01"))
```
## Extending a contract beyond its maturity
When a contract expires, many companies offer premium-free contract extensions,
where the existing reserve is used as initial reserve for a follow-up contract
(possibly with new terms and parameters like interest rate or mortalities).
Instead of modifying the original contract and re-calculating it, it is easier
to model the extension as a new block with the existing reserve given as
\code{initialCapital}. The extension will be calculated like a standalone-contract
and the overall contract will aggregate the values from the original contract
and the extension. As the extension is a separate contract object, one can pass
all contract parameters to the \code{$addExtension} method.
The original premiumPeriod of the main contract is used, so by default the extension
will be a premium-free extension, where the sumInsured is calculated from the
existing reserve and the benefits and costs of the extensions' tariff.
To create a premium-free extension explicitly, one can pass \code{premiumPeriod=0} (which
is the default anyway). To create an extension with regular (or single) premium
payments, one can pass either a \code{sumInsured} or a \code{premium} to provide
the sum insured and the premium and calculate the other from the given value
```{r contractExtension}
# original contract, expiring after 20 years
ContractA = InsuranceContract$new(
tarif = Tarif.Endowment,
age = 40, policyPeriod = 20,
sumInsured = 10000,
contractClosing = as.Date("2000-07-01")
)
# premium-free extension
ContractB = ContractA$clone()$
addExtension(id = "Verlängerung1", contractPeriod = 5, premiumPeriod = 0)
# sumInsured calculated from existing reserve:
ContractB$blocks$Verlängerung1$Parameters$ContractData$sumInsured
ContractB$Values$basicData
# extension with given sumInsured resulting in 0 (gross) premiums
ContractC = ContractA$clone()$
addExtension(id = "Verlängerung1", contractPeriod = 5, sumInsured = 10723.07973354)
ContractC$blocks$Verlängerung1$Values$premiums[["gross"]]
ContractC$Values$basicData
# extension with increased sumInsured: real premiums are charged, reserves start from the existing reserve:
ContractD = ContractA$clone()$
addExtension(id = "Verlängerung1", contractPeriod = 5, sumInsured = 20000)
ContractD$Values$basicData
# extension with regular premiums, which are given: sumInsured is calculated from it, reserves start from the existing reserve:
ContractD = ContractA$clone()$
addExtension(id = "Verlängerung1", contractPeriod = 5, premium = 597.8771)
ContractD$Values$basicData
```
# Handling contracts with increases # Handling contracts with increases
While many insurance contracts have a fixed sum insured and constant premium, While many insurance contracts have a fixed sum insured and constant premium,
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment