Skip to content

Commit

Permalink
Merge pull request #2 from EconomicSL/master
Browse files Browse the repository at this point in the history
Update to last version (reinsurance implementation by jsabuco)
  • Loading branch information
x0range authored Oct 9, 2017
2 parents f10f67b + 1f0d268 commit 3f1e534
Show file tree
Hide file tree
Showing 7 changed files with 503 additions and 80 deletions.
25 changes: 18 additions & 7 deletions insurancecontract.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import numpy as np

class InsuranceContract():
def __init__(self, insurer, properties, time, premium, runtime, deductible = 0, excess = None):
def __init__(self, insurer, properties, time, premium, runtime, deductible=0, excess=None, reinsurance=0,
reinrisk=None):
self.insurer = insurer
self.risk_factor = properties["risk_factor"]
self.category = properties["category"]
Expand All @@ -12,19 +13,29 @@ def __init__(self, insurer, properties, time, premium, runtime, deductible = 0,
self.expiration = runtime + time
self.deductible = deductible
self.excess = excess if excess != None else self.value
self.reinsurance = reinsurance
self.reinrisk = reinrisk
self.reinsurer = None
self.reincontract = None
self.property_holder.receive_obligation(premium * (self.excess - self.deductible), self.insurer, time)


def explode(self, expire_immediately, time, uniform_value, damage_extent):
#np.mean(np.random.beta(1, 1./mu -1, size=90000))
#if np.random.uniform(0, 1) < self.risk_factor:
# np.mean(np.random.beta(1, 1./mu -1, size=90000))
# if np.random.uniform(0, 1) < self.risk_factor:
if uniform_value < self.risk_factor:
#if True:
# if True:
claim = damage_extent * self.excess - self.deductible
self.insurer.receive_obligation(claim, self.property_holder, time)
if (self.reincontract != None):
self.reinsurer.reinsurer_receive_obligation(claim, self.insurer, time)
self.reincontract.explode(True, time)
self.insurer.receive_obligation(claim, self.property_holder, time + 2)
if expire_immediately:
self.expiration = time

def mature(self):
self.property_holder.return_risks([self.properties])

def reinsure(self, percentage):
self.reinsurance = self.value * percentage/100

47 changes: 45 additions & 2 deletions insurancefirm.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import scipy.stats
from insurancecontract import InsuranceContract
import sys, pdb
import uuid

class InsuranceFirm():
def __init__(self, simulation, simulation_parameters, agent_parameters):
Expand All @@ -28,6 +29,8 @@ def __init__(self, simulation, simulation_parameters, agent_parameters):
def iterate(self, time):
#"""realize income: not necessary"""
#pass

self.ans_reinsurance()

"""realize due payments"""
self.effect_payments(time)
Expand Down Expand Up @@ -62,9 +65,9 @@ def iterate(self, time):


"""make underwriting decisions, category-wise"""
underwritten_risks = [{"excess": contract.excess, "category": contract.category, \
underwritten_risks = [{"excess": contract.value, "category": contract.category, \
"risk_factor": contract.risk_factor, "deductible": contract.deductible, \
"runtime": contract.runtime} for contract in self.underwritten_contracts]
"runtime": contract.runtime} for contract in self.underwritten_contracts if contract.reincontract != None]
expected_profit, acceptable_by_category = self.riskmodel.evaluate(underwritten_risks, self.cash)

#if expected_profit * 1./self.cash < self.profit_target:
Expand Down Expand Up @@ -99,6 +102,9 @@ def iterate(self, time):

#return unacceptables
#print(self.id, " now has ", len(self.underwritten_contracts), " & returns ", len(not_accepted_risks))

self.ask_reinsurance()

self.simulation.return_risks(not_accepted_risks)

#not implemented
Expand Down Expand Up @@ -149,3 +155,40 @@ def receive(self, amount):
# Non-ABCE style
"""Method to accept cash payments."""
self.cash += amount

def ask_reinsurance(self):
nonreinsured = [contract
for contract in self.underwritten_contracts
if contract.reinrisk == None]
counter = 0
limitrein = 0.1 * len(nonreinsured)
for contract in nonreinsured:
if counter < limitrein:
reinvalue = 0
risk = {"value": contract.value, "category": contract.category, "firm": self,
"identifier": uuid.uuid1(),
"runtime": contract.expiration, "contract": contract}
contract.reinsure(100) # TODO percentage to floating point number
contract.reinrisk = risk["identifier"]
self.simulation.append_reinrisks(risk)
counter += 1
else:
break

def ans_reinsurance(self):
to_remove = []
print(self.simulation.reinrisks)
for rein in self.simulation.get_reinrisks():
for contract in self.underwritten_contracts:
if (rein["identifier"] == contract.reinrisk):
contract.reinsure(0)
contract.reinrisk = None
contract.reinsurer = None
contract.reincontract = None
to_remove.append(rein)

for item in to_remove:
self.simulation.remove_reinrisks(item)



155 changes: 122 additions & 33 deletions insurancesimulation.py
Original file line number Diff line number Diff line change
@@ -1,31 +1,35 @@

from insurancefirm import InsuranceFirm
from riskmodel import RiskModel
from reinsurancefirm import ReinsuranceFirm
from reinriskmodel import ReinriskModel
import numpy as np
import scipy.stats
import math
import matplotlib.pyplot as plt
import pdb

class InsuranceSimulation():
def __init__(self, simulation_parameters = {"no_categories": 2,\
"no_insurancefirms": 20, \
"no_riskmodels": 2, \
"norm_profit_markup": 0.15, \
"mean_contract_runtime": 30, \
"contract_runtime_halfspread": 10, \
"max_time": 600, \
"money_supply": 2000000000, \
"event_time_mean_separation": 200/1., \
"expire_immediately": True, \
"risk_factors_present": False, \
"risk_factor_lower_bound": 0.4, \
"risk_factor_upper_bound": 0.6, \
"initial_acceptance_threshold": 0.5, \
"acceptance_threshold_friction": 0.9, \
"initial_agent_cash": 10000, \
"no_risks": 20000 }):

def __init__(self, simulation_parameters={"no_categories": 1, \
"no_insurancefirms": 2, \
"no_reinsurancefirms": 1, \
"no_riskmodels": 1, \
"no_reinriskmodels": 1, \
"norm_profit_markup": 0.15, \
"rein_norm_profit_markup": 0.15, \
"mean_contract_runtime": 50, \
"contract_runtime_halfspread": 10, \
"max_time": 1000, \
"money_supply": 2000000000, \
"event_time_mean_separation": 100 / 0.3, \
"expire_immediately": True, \
"risk_factors_present": False, \
"risk_factor_lower_bound": 0.4, \
"risk_factor_upper_bound": 0.6, \
"initial_acceptance_threshold": 0.5, \
"acceptance_threshold_friction": 0.9, \
"initial_agent_cash": 100000, \
"initial_reinagent_cash": 50000, \
"no_risks": 2000}):

# save parameters
self.simulation_parameters = simulation_parameters

Expand Down Expand Up @@ -110,16 +114,48 @@ def __init__(self, simulation_parameters = {"no_categories": 2,\
self.insurancefirms.append(insurer)
self.insurancefirm_weights = [1 for i in self.insurancefirms]
self.insurancefirm_new_weights = [0 for i in self.insurancefirms]


# set up reinsurance risk models
self.reinriskmodels = [ReinriskModel(self.damage_distribution, self.simulation_parameters["expire_immediately"], \
self.cat_separation_distribution, self.norm_premium,
self.simulation_parameters["no_categories"], \
risk_value_mean, \
self.simulation_parameters["rein_norm_profit_markup"]) \
for i in range(self.simulation_parameters["no_reinriskmodels"])]

# set up reinsurance firms
self.reinsurancefirms = []
for i in range(self.simulation_parameters["no_reinsurancefirms"]):
reinriskmodel = self.reinriskmodels[i % len(self.reinriskmodels)]
agent_parameters = {'id': i, 'initial_cash': simulation_parameters["initial_reinagent_cash"], \
'reinriskmodel': reinriskmodel, 'norm_premium': self.norm_premium, \
'profit_target': simulation_parameters["rein_norm_profit_markup"], \
'initial_acceptance_threshold': simulation_parameters["initial_acceptance_threshold"], \
'acceptance_threshold_friction': simulation_parameters["acceptance_threshold_friction"]}
reinsurer = ReinsuranceFirm(self, simulation_parameters, agent_parameters)
self.reinsurancefirms.append(reinsurer)
self.reinsurancefirm_weights = [1 for i in self.reinsurancefirms]
self.reinsurancefirm_new_weights = [simulation_parameters["initial_reinagent_cash"] for i in self.reinsurancefirms]




# some output variables
self.history_total_cash = []
self.history_total_contracts = []
self.history_individual_contracts = [[] for _ in range(simulation_parameters["no_insurancefirms"])]
self.history_total_operational = []

self.history_total_reincash = []
self.history_total_reincontracts = []
self.history_total_reinoperational = []

wfile = open("data/rc_event_schedule.dat","a")
wfile.write(str(self.rc_event_schedule)+"\n")
wfile.close()

self.reinrisks = []

def run(self):
for t in range(self.simulation_parameters["max_time"]):
Expand Down Expand Up @@ -149,6 +185,20 @@ def run(self):
[contract.explode(self.simulation_parameters["expire_immediately"], t, uniformvalues[i], damagevalues[i]) for i, contract in enumerate(affected_contracts)]
else:
print("Next peril ", self.rc_event_schedule[categ_id])


# reset reinweights
self.reinsurancefirm_weights = np.asarray(self.reinsurancefirm_new_weights) / sum(
self.reinsurancefirm_new_weights) * len(self.reinrisks)
self.reinsurancefirm_weights = np.int64(np.floor(self.reinsurancefirm_weights))
self.reinsurancefirm_new_weights = [0 for i in self.reinsurancefirms]
np.random.shuffle(self.reinrisks)

# iterate reinagents
for reinagent in self.reinsurancefirms:
reinagent.iterate(t)


# reset weights
self.insurancefirm_weights = np.asarray(self.insurancefirm_new_weights) / sum(self.insurancefirm_new_weights) * len(self.risks)
self.insurancefirm_weights = np.int64(np.floor(self.insurancefirm_weights))
Expand All @@ -162,23 +212,39 @@ def run(self):
# collect data
total_cash_no = sum([insurancefirm.cash for insurancefirm in self.insurancefirms])
total_contracts_no = sum([len(insurancefirm.underwritten_contracts) for insurancefirm in self.insurancefirms])
individual_contracts_no = [len(insurancefirm.underwritten_contracts) for insurancefirm in self.insurancefirms]
total_reincash_no = sum([reinsurancefirm.cash for reinsurancefirm in self.reinsurancefirms])
total_reincontracts_no = sum([len(reinsurancefirm.rein_underwritten_contracts) for reinsurancefirm in self.reinsurancefirms])
operational_no = sum([insurancefirm.operational for insurancefirm in self.insurancefirms])
reinoperational_no = sum([reinsurancefirm.operational for reinsurancefirm in self.reinsurancefirms])
self.history_total_cash.append(total_cash_no)
self.history_total_contracts.append(total_contracts_no)
self.history_total_operational.append(operational_no)
self.history_total_reincash.append(total_reincash_no)
self.history_total_reincontracts.append(total_reincontracts_no)
self.history_total_reinoperational.append(reinoperational_no)

individual_contracts_no = [len(insurancefirm.underwritten_contracts) for insurancefirm in self.insurancefirms]
for i in range(len(individual_contracts_no)):
self.history_individual_contracts[i].append(individual_contracts_no[i])

wfile = open("data/two_operational.dat","a")
wfile = open("data/operational.dat","w")
wfile.write(str(self.history_total_operational)+"\n")
wfile.close()
wfile = open("data/two_contracts.dat","a")
wfile = open("data/contracts.dat","w")
wfile.write(str(self.history_total_contracts)+"\n")
wfile.close()
wfile = open("data/two_cash.dat","a")
wfile = open("data/cash.dat","w")
wfile.write(str(self.history_total_cash)+"\n")
wfile.close()
wfile = open("data/reinoperational.dat","w")
wfile.write(str(self.history_total_reinoperational)+"\n")
wfile.close()
wfile = open("data/reincontracts.dat","w")
wfile.write(str(self.history_total_reincontracts)+"\n")
wfile.close()
wfile = open("data/reincash.dat","w")
wfile.write(str(self.history_total_reincash)+"\n")
wfile.close()

#fig = plt.figure()
#ax0 = fig.add_subplot(311)
Expand All @@ -194,15 +260,6 @@ def run(self):
#ax2.set_xlabel("Time")
#plt.show()

def return_risks(self, not_accepted_risks):
self.risks += not_accepted_risks

def solicit_insurance_requests(self, id, cash):
self.insurancefirm_new_weights[id] = cash
risks_to_be_sent = self.risks[:self.insurancefirm_weights[id]]
self.risks = self.risks[self.insurancefirm_weights[id]:]
return risks_to_be_sent

def receive_obligation(self, amount, recipient, due_time):
obligation = {"amount": amount, "recipient": recipient, "due_time": due_time}
self.obligations.append(obligation)
Expand Down Expand Up @@ -237,6 +294,38 @@ def adjust_market_premium(self):
def get_market_premium(self):
return self.market_premium

def append_reinrisks(self, item):
if(len(item) > 0):
self.reinrisks.append(item)

def remove_reinrisks(self,risko):
if(risko != None):
self.reinrisks.remove(risko)

def get_reinrisks(self):
np.random.shuffle(self.reinrisks)
return self.reinrisks

def solicit_insurance_requests(self, id, cash):
self.insurancefirm_new_weights[id] = cash
risks_to_be_sent = self.risks[:self.insurancefirm_weights[id]]
self.risks = self.risks[self.insurancefirm_weights[id]:]
print("Number of risks", len(risks_to_be_sent))
return risks_to_be_sent

def return_risks(self, not_accepted_risks):
self.risks += not_accepted_risks

def solicit_reinsurance_requests(self, id, cash):
self.reinsurancefirm_new_weights[id] = cash
reinrisks_to_be_sent = self.reinrisks[:self.reinsurancefirm_weights[id]]
self.reinrisks = self.reinrisks[self.reinsurancefirm_weights[id]:]
print("Number of risks",len(reinrisks_to_be_sent))
return reinrisks_to_be_sent

def return_reinrisks(self, not_accepted_risks):
self.reinrisks += not_accepted_risks

# main entry point
if __name__ == "__main__":
S = InsuranceSimulation()
Expand Down
Loading

0 comments on commit 3f1e534

Please sign in to comment.