From 47fd0f5e53275780bcdbe0f4af813f953f867278 Mon Sep 17 00:00:00 2001 From: Reinhold Kainhofer <reinhold@kainhofer.com> Date: Tue, 24 Aug 2021 16:55:54 +0200 Subject: [PATCH] Add freqCharge helper function; Don't use lubridate, but seq to get yearly recurrences; Typo fixes --- R/HelperFunctions.R | 58 ++++++++++++++++++++++++++++++++++------- R/InsuranceParameters.R | 2 +- R/InsuranceTarif.R | 8 +++--- 3 files changed, 55 insertions(+), 13 deletions(-) diff --git a/R/HelperFunctions.R b/R/HelperFunctions.R index ccc0fba..b8e92c3 100644 --- a/R/HelperFunctions.R +++ b/R/HelperFunctions.R @@ -170,18 +170,58 @@ deathBenefit.linearDecreasing = function(len, params, values) { #' #' @export deathBenefit.annuityDecreasing = function(interest) { - function(len, params, values) { - protectionPeriod = params$ContractData$policyPeriod - params$ContractData$deferralPeriod; - vk = 1/(1 + interest); - if (interest == 0) { - sumInsured = (protectionPeriod:0) / protectionPeriod - } else { - sumInsured = (vk ^ (protectionPeriod:0) - 1) / (vk ^ protectionPeriod - 1) - } - pad0(sumInsured, l = len) + function(len, params, values) { + protectionPeriod = params$ContractData$policyPeriod - params$ContractData$deferralPeriod; + vk = 1/(1 + interest); + if (interest == 0) { + sumInsured = (protectionPeriod:0) / protectionPeriod + } else { + sumInsured = (vk ^ (protectionPeriod:0) - 1) / (vk ^ protectionPeriod - 1) } + pad0(sumInsured, l = len) + } } +#' Defines a frequency charge (surcharge for monthly/quarterly/semiannual) premium payments #' +#' Tariffs are typically calculated with yearly premium installments. When +#' premiums are paid more often then one a year (in advance), the insurance +#' receives part of the premium later (or not at all in case of death), so a +#' surcharge for premium payment frequencies higher than yearly is applied to +#' the premium, typically in the form of a percentage of the premium. +#' +#' This function generates the internal data structure to define surcharges for +#' monthly, quarterly and semiannual premium payments. The given surcharges can +#' be either given as percentage points (e.g. 1.5 means 1.5% = 0.015) or as +#' fractions of 1 (i.e. 0.015 also means 1.5% surcharge). The heuristics applied +#' to distinguish percentage points and fractions is that all values larger than 0.1 +#' are understood as percentage points and values 0.1 and lower are understood +#' as fractions of 1. +#' As a consequence, a frequency charge of 10% or more MUST be given as percentage points. +#' +#' Currently, the frequency charges are internally represented as a named list, +#' \code{list("1" = 0, "2" = 0.01, "4" = 0.02, "12" = 0.03)}, but that might +#' change in the future, so it is advised to use this function rather than +#' explicitly using the named list in your code. +#' +#' @param monthly Surcharge for monthly premium payments +#' @param quarterly Surcharge for quarterly premium payments +#' @param semiannually Surcharge for semi-annual premium payments +#' @param yearly Surcharge for yearly premium payments (optiona, default is no surcharge) +#' +#' @export +freqCharge = function(monthly = 0, quarterly = 0, semiannually = 0, yearly = 0) { + # Apply the heuristics to allow percentage points given + if (monthly > 0.1) monthly = monthly / 100; + if (quarterly > 0.1) quarterly = quarterly / 100; + if (semiannually > 0.1) semiannually = semiannually / 100; + if (yearly > 0.1) yearly = yearly / 100; + + # internal representation for now is a named list: + list("1" = yearly, "2" = semiannually, "4" = quarterly, "12" = monthly) +} + + + mergeValues = function(starting, ending, t) { # if either starting or ending is missing, always use the other, irrespective of t: if (missing(ending) || is.null(ending)) { diff --git a/R/InsuranceParameters.R b/R/InsuranceParameters.R index 82f3035..804ece4 100644 --- a/R/InsuranceParameters.R +++ b/R/InsuranceParameters.R @@ -248,7 +248,7 @@ InsuranceContract.Values = list( #' is aligned with $t=blockStart$ of the parent block.} #' \item{\code{$premiumPayments}}{Whether premiums are paid in advance #' (default) or arrears. Value is of type [PaymentTimeEnum] -#' with possible values "in advance" and 'in arrears"} +#' with possible values "in advance" and "in arrears"} #' \item{\code{$benefitPayments}}{Whether recurring benefits (e.g. annuities) #' are paid in advance (default) or arrears. Value is of type #' [PaymentTimeEnum] with possible values "in advance" and diff --git a/R/InsuranceTarif.R b/R/InsuranceTarif.R index ba54351..6dfc930 100644 --- a/R/InsuranceTarif.R +++ b/R/InsuranceTarif.R @@ -1078,7 +1078,7 @@ InsuranceTarif = R6Class( }, #' @description Calculate the (linear) interpolation factors for the balance - #' sheet reserve (Dec. 31) between the yearly contract clowing dates + #' sheet reserve (Dec. 31) between the yearly contract closing dates #' @details Not to be called directly, but implicitly by the [InsuranceContract] object. #' @param method The method for the balance sheet interpolation (30/360, act/act, act/360, act/365 or a function) #' @param years how many years to calculate (for some usances, the factor @@ -1090,8 +1090,10 @@ InsuranceTarif = R6Class( balanceDate = balanceDate + years(1); } - contractDates = params$ContractData$contractClosing + years(1:years); - balanceDates = balanceDate + years(1:years - 1); + # contractDates = params$ContractData$contractClosing + years(1:years); + # balanceDates = balanceDate + years(1:years - 1); + contractDates = seq(params$ContractData$contractClosing, length.out = years, by = "year") + balanceDates = seq(balanceDate, length.out = years, by = "year") if (is.function(method)) { baf = method(params = params, contractDates = contractDates, balanceDates = balanceDates) -- GitLab