Skip to content

Commit

Permalink
Merge pull request #4 from EconomicSL/master
Browse files Browse the repository at this point in the history
Isle ABCE
  • Loading branch information
jsabuco authored Nov 7, 2017
2 parents a0caa40 + baaae67 commit b9137fd
Show file tree
Hide file tree
Showing 12 changed files with 686 additions and 406 deletions.
7 changes: 7 additions & 0 deletions genericagent.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

class GenericAgent():
def __init__(self, *args, **kwargs):
self.init(*args, **kwargs)

def init(*args, **kwargs):
assert False, "Error: GenericAgent init method should have been overridden but was not."
4 changes: 4 additions & 0 deletions genericagentabce.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import abce

class GenericAgent(abce.Agent):
pass
36 changes: 17 additions & 19 deletions insurancecontract.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import numpy as np
import sys, pdb

#from insurancesimulation import InsuranceSimulation

class InsuranceContract():
def __init__(self, insurer, properties, time, premium, runtime, deductible=0, excess=None, reinsurance=0):
#reinrisk=None):
def __init__(self, insurer, properties, time, premium, runtime, payment_period, deductible=0, excess=None, reinsurance=0):
"""Constructor method.
Accepts arguments
insurer: Type InsuranceFirm.
properties: Type dict.
time: Type integer. The current time.
premium: Type float.
runtime: Type integer.
payment_period: Type integer.
optional:
deductible: Type float (or int)
excess: Type float (or int or None)
Expand Down Expand Up @@ -43,23 +41,32 @@ def __init__(self, insurer, properties, time, premium, runtime, deductible=0, ex
self.excess = excess if excess is not None else self.value

self.reinsurance = reinsurance
#self.rein_ID = reinrisk
self.reinsurer = None
self.reincontract = None
self.reinsurance_share = None
#self.is_reinsurancecontract = False

# Create obligation for premium payment
self.property_holder.receive_obligation(premium * (self.excess - self.deductible), self.insurer, time)
# setup payment schedule
self.payment_times = [time + i for i in range(runtime) if i % payment_period == 0]
self.payment_values = premium * (np.ones(len(self.payment_times)) / len(self.payment_times))

## Create obligation for premium payment
#self.property_holder.receive_obligation(premium * (self.excess - self.deductible), self.insurer, time)

# Embed contract in reinsurance network, if applicable
if self.contract is not None:
self.contract.reinsure(reinsurer=self.insurer, reinsurance_share=properties["reinsurance_share"], \
reincontract=self)
#self.contract.reinsurer = self.insurer #TODO: do not write into other object's attributes!
#self.contract.reinsurance_share = properties["reinsurance_share"]
#self.contract.reincontract = self

def check_payment_due(self, time):
if len(self.payment_times) > 0 and time >= self.payment_times[0]:
# Create obligation for premium payment
#self.property_holder.receive_obligation(premium * (self.excess - self.deductible), self.insurer, time)
self.property_holder.receive_obligation(self.payment_values[0] * (self.excess - self.deductible), self.insurer, time)

# Remove current payment from payment schedule
self.payment_times = self.payment_times[1:]
self.payment_values = self.payment_values[1:]

def explode(self, expire_immediately, time, uniform_value, damage_extent):
"""Explode method.
Expand Down Expand Up @@ -132,20 +139,11 @@ def reinsure(self, reinsurer, reinsurance_share, reincontract):
self.reincontract = reincontract
assert self.reinsurance_share in [None, 0.0, 1.0]

#def reinsure(self, reinsurance_share):
# self.reinsurance = self.value * reinsurance_share
# self.reinsurance_share = reinsurance_share
#
# # Values other than 0.0 and 1.0 are not implemented (will break the risk model.
# # Assert that it breaks if other values are found.
# assert self.reinsurance_share in [None, 0.0, 1.0]

def unreinsure(self):
"""Unreinsurance Method.
Accepts no arguments:
No return value.
Removes parameters for reinsurance of the current contract. To be called when reinsurance has terminated."""
#self.rein_ID = None
self.reinsurer = None
self.reincontract = None
self.reinsurance = 0
Expand Down
192 changes: 99 additions & 93 deletions insurancefirm.py

Large diffs are not rendered by default.

538 changes: 309 additions & 229 deletions insurancesimulation.py

Large diffs are not rendered by default.

38 changes: 0 additions & 38 deletions insurancesimulation_one.py

This file was deleted.

32 changes: 32 additions & 0 deletions isleconfig.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use_abce = False
oneriskmodel = False
replicating = False
force_foreground = False

simulation_parameters={"no_categories": 2,
"no_insurancefirms": 20,
"no_reinsurancefirms": 2,
"no_riskmodels": 2,
"norm_profit_markup": 0.15,
"rein_norm_profit_markup": 0.15,
"mean_contract_runtime": 36,
"contract_runtime_halfspread": 10,
"default_contract_payment_period": 12,
"max_time": 600,
"money_supply": 2000000000,
"event_time_mean_separation": 100 / 3.,
"expire_immediately": False,
"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,
"initial_reinagent_cash": 50000,
"interest_rate": 0,
"reinsurance_limit": 0.1,
"upper_price_limit": 1.2,
"lower_price_limit": 0.85,
"no_risks": 20000}


4 changes: 2 additions & 2 deletions reinsurancefirm.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@
class ReinsuranceFirm(InsuranceFirm):
"""ReinsuranceFirm class.
Inherits from InsuranceFirm."""
def __init__(self, simulation, simulation_parameters, agent_parameters):
def init(self, simulation_parameters, agent_parameters):
"""Constructor method.
Accepts arguments
Signature is identical to constructor method of parent class.
Constructor calls parent constructor and only overwrites boolean indicators of insurer and reinsurer role of
the object."""
super(ReinsuranceFirm, self).__init__(simulation, simulation_parameters, agent_parameters)
super(ReinsuranceFirm, self).init(simulation_parameters, agent_parameters)
self.is_insurer = False
self.is_reinsurer = True
88 changes: 68 additions & 20 deletions riskmodel.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import numpy as np
import sys, pdb
import scipy.stats
import numba as nb

class RiskModel():
def __init__(self, damage_distribution, expire_immediately, cat_separation_distribution, norm_premium, \
Expand All @@ -27,6 +28,52 @@ def getPPF(self, tailSize):
tailSize (float >=0, <=1): quantile
Returns value-at-risk."""
return self.damage_distribution.ppf(1-tailSize)

@nb.jit
def get_categ_risks(self, risks, categ_id):
#categ_risks2 = [risk for risk in risks if risk["category"]==categ_id]
categ_risks = []
for risk in risks:
if risk["category"]==categ_id:
categ_risks.append(risk)
#assert categ_risks == categ_risks2
return categ_risks

@nb.jit
def compute_expectation(self, categ_risks, categ_id): #TODO: more intuitive name?
#average_exposure2 = np.mean([risk["excess"]-risk["deductible"] for risk in categ_risks])
#
##average_risk_factor = np.mean([risk["risk_factor"] for risk in categ_risks])
#average_risk_factor2 = self.inaccuracy[categ_id] * np.mean([risk["risk_factor"] for risk in categ_risks])
#
## compute expected profits from category
#mean_runtime2 = np.mean([risk["runtime"] for risk in categ_risks])

exposures = []
risk_factors = []
runtimes = []
for risk in categ_risks:
exposures.append(risk["excess"]-risk["deductible"])
risk_factors.append(risk["risk_factor"])
runtimes.append(risk["runtime"])
average_exposure = np.mean(exposures)
average_risk_factor = self.inaccuracy[categ_id] * np.mean(risk_factors)
mean_runtime = np.mean(runtimes)
#assert average_exposure == average_exposure2
#assert average_risk_factor == average_risk_factor2
#assert mean_runtime == mean_runtime2

if self.expire_immediately:
incr_expected_profits = -1
# TODO: fix the norm_premium estimation
#incr_expected_profits = (self.norm_premium - (1 - scipy.stats.poisson(1 / self.cat_separation_distribution.mean() * \
# mean_runtime).pmf(0)) * self.damage_distribution.mean() * average_risk_factor) * average_exposure * len(categ_risks)
else:
incr_expected_profits = -1
# TODO: expected profits should only be returned once the expire_immediately == False case is fixed
#incr_expected_profits = (self.norm_premium - mean_runtime / self.cat_separation_distribution.mean() * self.damage_distribution.mean() * average_risk_factor) * average_exposure * len(categ_risks)

return average_risk_factor, average_exposure, incr_expected_profits

def evaluate(self, risks, cash):
acceptable_by_category = []
Expand All @@ -35,26 +82,21 @@ def evaluate(self, risks, cash):
necessary_liquidity = 0
for categ_id in range(self.category_number):
# compute number of acceptable risks of this category
categ_risks = [risk for risk in risks if risk["category"]==categ_id]

categ_risks = self.get_categ_risks(risks=risks, categ_id=categ_id)
#categ_risks = [risk for risk in risks if risk["category"]==categ_id]

if len(categ_risks) > 0:
average_exposure = np.mean([risk["excess"]-risk["deductible"] for risk in categ_risks])
#average_risk_factor = np.mean([risk["risk_factor"] for risk in categ_risks])
try:
average_risk_factor = self.inaccuracy[categ_id] * np.mean([risk["risk_factor"] for risk in categ_risks])
except:
print(sys.exc_info())
pdb.set_trace()
# compute expected profits from category
mean_runtime = np.mean([risk["runtime"] for risk in categ_risks])
if self.expire_immediately:
expected_profits += (self.norm_premium - (1 - scipy.stats.poisson(1 / self.cat_separation_distribution.mean() * \
mean_runtime).pmf(0)) * self.damage_distribution.mean() * average_risk_factor) * average_exposure * len(categ_risks)
else:
expected_profits += (self.norm_premium - mean_runtime / self.cat_separation_distribution.mean() * self.damage_distribution.mean() * average_risk_factor) * average_exposure * len(categ_risks)
average_risk_factor, average_exposure, incr_expected_profits = self.compute_expectation(categ_risks=categ_risks, categ_id=categ_id)
else:
average_risk_factor = self.init_average_risk_factor
average_exposure = self.init_average_exposure
expected_profits += 0

incr_expected_profits = -1
# TODO: expected profits should only be returned once the expire_immediately == False case is fixed
#incr_expected_profits = 0

expected_profits += incr_expected_profits
var_per_risk = self.getPPF(self.var_tail_prob) * average_risk_factor * average_exposure
necessary_liquidity += var_per_risk * len(categ_risks)
#print("RISKMODEL: ", self.getPPF(0.01) * average_risk_factor * average_exposure, " = PPF(0.01) * ", average_risk_factor, " * ", average_exposure, " vs. cash: ", cash, "TOTAL_RISK_IN_CATEG: ", self.getPPF(0.01) * average_risk_factor * average_exposure * len(categ_risks))
Expand All @@ -72,10 +114,16 @@ def evaluate(self, risks, cash):
pdb.set_trace()
acceptable_by_category.append(acceptable)
remaining_acceptable_by_category.append(remaining)
if necessary_liquidity == 0:
assert expected_profits == 0
expected_profits = self.init_profit_estimate * cash

# TODO: expected profits should only be returned once the expire_immediately == False case is fixed; the else-clause conditional statement should then be raised to unconditional
if expected_profits < 0:
expected_profits = None
else:
expected_profits / necessary_liquidity
if necessary_liquidity == 0:
assert expected_profits == 0
expected_profits = self.init_profit_estimate * cash
else:
expected_profits /= necessary_liquidity

print("RISKMODEL returns: ", expected_profits, remaining_acceptable_by_category)
return expected_profits, remaining_acceptable_by_category
Loading

0 comments on commit b9137fd

Please sign in to comment.