Skip to content

Instantly share code, notes, and snippets.

View MatthewCaseres's full-sized avatar
😹

Matthew Caseres MatthewCaseres

😹
View GitHub Profile
from functools import wraps
from collections import defaultdict
import pandas as pd
import torch
from dataclasses import dataclass
from torch import optim
@dataclass(eq=False)
class Ctx:
net_premium_pp: torch.Tensor

Introduce yourself

I worked as an actuary for about 2 years in life insurance. Actuaries work with regulators to make sure the insurance company can pay for any insurance claims.

It is a technical profession but a lot of processes are done in Microsoft Excel or proprietary software. I got my first actuarial job in 2018 and published my first actuarial software package in 2019 - https://www.soa.org/globalassets/assets/library/newsletters/the-modeling-platform/2019/november/mp-2019-is10-caseres.pdf

After about 2 years of working I was having problems with my mental health and took an extended break from work. I wasn’t sure when it would feel right to return to the workforce, and I wasn’t sure I wanted to continue actuarial work. So I was just writing open source educational software, I wanted to make free interactive electronic books.

One day Alec Loudenback the creator of the JuliaActuary GitHub organization invited me to join Fumito Hamamura’s (creator of LifeLib) LinkedIn group/Github Org for open sour

# we need to read the CSV file at ../data/census_dat.csv
# and then create a DataFrame from it
using DataFrames
using CSV
using Dates
using BenchmarkTools
using ExperienceAnalysis
using DayCounts
using Dates
""" difference in months between dates """
function get_timestep_diff(timestep::Month, start_date::Date, end_date::Date)::Month
return Month(Year(end_date) - Year(start_date)) + (Month(end_date) - Month(start_date))
end
""" difference in years between dates """
function get_timestep_diff(timestep::Year, start_date::Date, end_date::Date)::Year
return Year(end_date) - Year(start_date)
@MatthewCaseres
MatthewCaseres / exposure_intervals.jl
Last active September 22, 2022 19:47
Creating exposure intervals for policy/calendar intervals
### A Pluto.jl notebook ###
# v0.19.11
using Markdown
using InteractiveUtils
# ╔═╡ fb2b4952-3a91-11ed-116b-db769de7e1cc
begin
using Dates
end
# net present value (NPV) of claims cashflows
discounted_expected_claims_NPV_per_policy = jnp.sum(discounted_claims_cashflows, axis=0)
# this is the formula for the "break even" premium
fair_premium = discounted_expected_claims_NPV_per_policy / jnp.sum(npx * discounts, 0)
print(fair_premium)
# [ 20.07074 224.05087 322.295 ]
npx = jnp.concatenate([jnp.ones((1, q.shape[1])), jnp.cumprod(1 - q, axis=0)[:-1]])
face = jnp.array([1000 * x for x in [100, 500, 250]])
discount_factor = 1/(1.02)
# discount factors for payments by policyholder starting at t = 0
discounts = discount_factor ** jnp.arange(timesteps)[:, jnp.newaxis]
# discounts factors for payments from insurer starting at t = 1 (payouts are at end of year of death)
discounts_lagged = discounts * discount_factor
discounted_claims_cashflows = discounts_lagged * npx * q * face
# Expected present value of claims per policyholder at each point in time
print(discounted_claims_cashflows)
# we have three policies, each belonging to a separate mortality table
mortality_table_index = jnp.array([0, 1, 2])
issue_age = jnp.array([30, 40, 50])
duration = jnp.array([0, 0, 0]) # new business
timesteps = 5 # The policy is a 5-year policy
time_axis = jnp.arange(timesteps)[:, jnp.newaxis] # broadcasting trick
duration_projected = time_axis + duration
assert jnp.all(
duration_projected
import jax.numpy as jnp
from pymort import getIdGroup, MortXML
ids = getIdGroup(3299).ids
select = jnp.array([MortXML(id).Tables[0].Values.unstack().values for id in ids])
ultimate = jnp.array([MortXML(id).Tables[1].Values.unstack().values for id in ids])
assert select.shape == (10, 78, 25) # tableIds [3299, 3308], issue_ages [18, 95], durations [1, 25]
assert ultimate.shape == (10, 103) # tableIds [3299, 3308], attained_ages [18, 120]
from dataclasses import dataclass
from typing import Literal
import numpy as np
from statistics import mean
np.random.seed(6420)
GradeType = Literal['A', 'B', '<=C']
@dataclass(frozen=True)