Closed alecloudenback closed 3 years ago
Proposed in #41:
mt = UltimateMortality([0.5,0.5])
# whole life insurance
ins = Insurance(
SingleLife(mort = mt,issue_age = 0),
Yields.Constant(0.05)
)
@test survival(ins) == [1.0,0.5]
@test discount(ins) == [1.0 / 1.05, 1 / 1.05^2]
@test benefit(ins) == [1.0,1.0]
@test probability(ins) == [0.5,0.25]
@test cashflows(ins) == [0.5,0.25]
@test cashflows(ins) == benefit(ins) .* probability(ins)
@test timepoints(ins) == [1.0,2.0]
@test present_value(ins) ≈ 0.5 / 1.05 + 0.5 * 0.5 / 1.05 ^ 2
Status Quo:
ins = LifeContingency(
SingleLife(
mort = mt,
issue_age = 0
),
Yields.Constant(0.05)
)
And then all you can do is this:
@test insurance(ins) ≈ 0.5 / 1.05 + 0.5 * 0.5 / 1.05 ^ 2
Benchmarks indicate that the new API would be slower, but that's solvable (specialize on the functions, build a pipeline that doesn't allocate the intermediate steps, etc)
julia> @benchmark present_value(Insurance($ins )) #new
BenchmarkTools.Trial:
memory estimate: 111.30 KiB
allocs estimate: 1579
--------------
minimum time: 81.200 μs (0.00% GC)
median time: 83.301 μs (0.00% GC)
mean time: 92.890 μs (6.73% GC)
maximum time: 3.461 ms (96.72% GC)
--------------
samples: 10000
evals/sample: 1
julia> @benchmark insurance($ins ) #old
BenchmarkTools.Trial:
memory estimate: 83.88 KiB
allocs estimate: 740
--------------
minimum time: 35.000 μs (0.00% GC)
median time: 48.000 μs (0.00% GC)
mean time: 48.172 μs (6.57% GC)
maximum time: 2.160 ms (96.04% GC)
--------------
samples: 10000**
Refactor to make the types of insurances, well, types instead of functions. Example:
Current:
annuity_due(ins)
currently calculates the present value of an annuity due.Alternative:
a = AnnuityDue(ins)
constructs an object, for which the following functions would operate:cashflows(a)
would produce the vector of cashflowssurvival(a)
would produce the survivorship vectortimepoints(a)
would produce the timepoints associated with the cashflowsdiscount(a)
would produce the discount vectorpresent_value(a)
would extendActuaryUtilities.present_value
and calculate the APV via thepresent_value(ins.interest,cashflows(a) .* survival(a),timepoints(a))
Advantages of this:
ActuaryUtilities
Insurance(ins) - AnnuityDue(ins)
would create a new instance of aContingencyCombination
where it combines the insurance benefit less the annuity payments, resulting in the net product cashflow.Disadvantages:
timepoints
may need to be calculated three times for an APV instead of just once.