Beispiel #1
0
    def issue_cat_bond(self, time, categ_id, per_value_per_period_premium=0):
        # premium is for usual reinsurance contracts paid using per value market premium
        # for the quasi-contract for the cat bond, nothing is paid, everything is already paid at the beginning.
        #per_value_reinsurance_premium = self.np_reinsurance_premium_share * risk["periodized_total_premium"] * risk["runtime"] / risk["value"]            #TODO: rename this to per_value_premium in insurancecontract.py to avoid confusion
        """ create catbond """
        total_value, avg_risk_factor, number_risks, periodized_total_premium = self.characterize_underwritten_risks_by_category(
            time, categ_id)
        if number_risks > 0:
            risk = {
                "value": total_value,
                "category": categ_id,
                "owner": self,
                #"identifier": uuid.uuid1(),
                "insurancetype": 'excess-of-loss',
                "number_risks": number_risks,
                "deductible_fraction": self.np_reinsurance_deductible_fraction,
                "excess_fraction": self.np_reinsurance_excess_fraction,
                "periodized_total_premium": 0,
                "runtime": 12,
                "expiration": time + 12,
                "risk_factor": avg_risk_factor
            }  # TODO: make runtime into a parameter
            _, _, var_this_risk, _ = self.riskmodel.evaluate([], self.cash,
                                                             risk)
            per_period_premium = per_value_per_period_premium * risk["value"]
            total_premium = sum([
                per_period_premium * ((1 / (1 + self.interest_rate))**i)
                for i in range(risk["runtime"])
            ])  # TODO: or is it range(1, risk["runtime"]+1)?
            #catbond = CatBond(self.simulation, per_period_premium)
            catbond = CatBond(
                self.simulation, per_period_premium, self.interest_rate
            )  # TODO: shift obtain_yield method to insurancesimulation, thereby making it unnecessary to drag parameters like self.interest_rate from instance to instance and from class to class
            """add contract; contract is a quasi-reinsurance contract"""
            contract = ReinsuranceContract(catbond, risk, time, 0, risk["runtime"], \
                                                      self.default_contract_payment_period, \
                                                      expire_immediately=self.simulation_parameters["expire_immediately"], \
                                                      initial_VaR=var_this_risk, \
                                                      insurancetype=risk["insurancetype"])
            # per_value_reinsurance_premium = 0 because the insurance firm does not continue to make payments to the cat bond. Only once.

            catbond.set_contract(contract)
            """sell cat bond (to self.simulation)"""
            self.simulation.receive_obligation(var_this_risk, self, time,
                                               'bond')
            catbond.set_owner(self.simulation)
            """hand cash over to cat bond such that var_this_risk is covered"""
            obligation = {
                "amount": var_this_risk + total_premium,
                "recipient": catbond,
                "due_time": time,
                "purpose": 'bond'
            }
            self.pay(obligation)  #TODO: is var_this_risk the correct amount?
            """register catbond"""
            self.simulation.accept_agents("catbond", [catbond], time=time)
Beispiel #2
0
    def issue_cat_bond(self, time: int, categ_id: int, per_value_per_period_premium: int = 0):
        """Method to issue cat bond to given firm for given category.
            Accepts:
                time: Type Integer.
                categ_id: Type Integer.
                per_value_per_period_premium: Type Integer.
            No return values.
        Method is only called by increase_capacity_by_category method when CatBond prices are lower than reinsurance. It
        then creates the CatBond as a quasi-reinsurance contract that is paid for immediately (by simulation) with no
        premium payments."""
        [total_value, avg_risk_factor, number_risks, _,] = self.underwritten_risk_characterisation[categ_id]
        if number_risks > 0:
            # TODO: make runtime into a parameter
            risk = genericclasses.RiskProperties(
                value=total_value,
                category=categ_id,
                owner=self,
                insurancetype="excess-of-loss",
                number_risks=number_risks,
                deductible_fraction=self.np_reinsurance_deductible_fraction,
                limit_fraction=self.np_reinsurance_limit_fraction,
                periodized_total_premium=0,
                runtime=12,
                expiration=time + 12,
                risk_factor=avg_risk_factor,)

            _, _, var_this_risk, _ = self.riskmodel.evaluate([], self.cash, risk)
            per_period_premium = per_value_per_period_premium * risk.value
            total_premium = sum(
                [per_period_premium * ((1 / (1 + self.interest_rate)) ** i) for i in range(risk.runtime)])
            # catbond = CatBond(self.simulation, per_period_premium)
            # TODO: shift obtain_yield method to insurancesimulation, thereby making it unnecessary to drag
            #  parameters like self.interest_rate from instance to instance and from class to class
            new_catbond = catbond.CatBond(self.simulation, per_period_premium, self.interest_rate)

            """add contract; contract is a quasi-reinsurance contract"""
            contract = ReinsuranceContract(new_catbond, risk, time, 0, risk.runtime,
                self.default_contract_payment_period,
                expire_immediately=self.simulation_parameters["expire_immediately"],
                initial_var=var_this_risk,
                insurancetype=risk.insurancetype,)
            # per_value_reinsurance_premium = 0 because the insurance firm make only one payment to catbond

            new_catbond.set_contract(contract)
            """sell cat bond (to self.simulation)"""
            self.simulation.receive_obligation(var_this_risk, self, time, "bond")
            new_catbond.set_owner(self.simulation)
            """hand cash over to cat bond such that var_this_risk is covered"""
            obligation = genericclasses.Obligation(amount=var_this_risk + total_premium, recipient=new_catbond,
                                                   due_time=time, purpose="bond",)
            self._pay(obligation)  # TODO: is var_this_risk the correct amount?
            """register catbond"""
            self.simulation.add_agents(catbond.CatBond, "catbond", [new_catbond])
Beispiel #3
0
    def process_newrisks_reinsurer(
        self, reinrisks_per_categ, number_reinrisks_categ, time
    ):  #This method processes one by one the reinrisks contained in reinrisks_per_categ in order to decide whether they should be underwritten or not.
        #It is done in this way to maintain the portfolio as balanced as possible. For that reason we process risk[C1], risk[C2], risk[C3], risk[C4], risk[C1], risk[C2], ... and so forth.
        for iterion in range(max(number_reinrisks_categ)):
            for categ_id in range(
                    self.simulation_parameters["no_categories"]
            ):  #Here we take only one risk per category at a time to achieve risk[C1], risk[C2], risk[C3], risk[C4], risk[C1], risk[C2], ... if possible.
                if iterion < number_reinrisks_categ[
                        categ_id] and reinrisks_per_categ[categ_id][
                            iterion] is not None:
                    risk_to_insure = reinrisks_per_categ[categ_id][iterion]
                    underwritten_risks = [{"value": contract.value, "category": contract.category, \
                                           "risk_factor": contract.risk_factor,
                                           "deductible": contract.deductible, \
                                           "excess": contract.excess, "insurancetype": contract.insurancetype, \
                                           "runtime_left": (contract.expiration - time)} for contract in
                                          self.underwritten_contracts if contract.insurancetype == "excess-of-loss"]
                    accept, cash_left_by_categ, var_this_risk, self.excess_capital = self.riskmodel.evaluate(
                        underwritten_risks, self.cash, risk_to_insure
                    )  # TODO: change riskmodel.evaluate() to accept new risk to be evaluated and to account for existing non-proportional risks correctly -> DONE.
                    if accept:
                        per_value_reinsurance_premium = self.np_reinsurance_premium_share * risk_to_insure[
                            "periodized_total_premium"] * risk_to_insure[
                                "runtime"] / risk_to_insure[
                                    "value"]  # TODO: rename this to per_value_premium in insurancecontract.py to avoid confusion
                        [
                            condition, cash_left_by_categ
                        ] = self.balanced_portfolio(
                            risk_to_insure, cash_left_by_categ, None
                        )  #Here it is check whether the portfolio is balanced or not if the reinrisk (risk_to_insure) is underwritten. Return True if it is balanced. False otherwise.
                        if condition:
                            contract = ReinsuranceContract(self, risk_to_insure, time, per_value_reinsurance_premium,
                                                           risk_to_insure["runtime"], \
                                                           self.default_contract_payment_period, \
                                                           expire_immediately=self.simulation_parameters[
                                                               "expire_immediately"], \
                                                           initial_VaR=var_this_risk, \
                                                           insurancetype=risk_to_insure[
                                                               "insurancetype"])  # TODO: implement excess of loss for reinsurance contracts
                            self.underwritten_contracts.append(contract)
                            self.cash_left_by_categ = cash_left_by_categ
                            reinrisks_per_categ[categ_id][iterion] = None

        not_accepted_reinrisks = []
        for categ_id in range(self.simulation_parameters["no_categories"]):
            for reinrisk in reinrisks_per_categ[categ_id]:
                if reinrisk is not None:
                    not_accepted_reinrisks.append(reinrisk)

        return reinrisks_per_categ, not_accepted_reinrisks
Beispiel #4
0
    def process_newrisks_insurer(self, risks_per_categ, number_risks_categ, acceptable_by_category, var_per_risk_per_categ, cash_left_by_categ, time): #This method processes one by one the risks contained in risks_per_categ in order to decide whether they should be underwritten or not.
                                                                                             #It is done in this way to maintain the portfolio as balanced as possible. For that reason we process risk[C1], risk[C2], risk[C3], risk[C4], risk[C1], risk[C2], ... and so forth.
        _cached_rvs = self.contract_runtime_dist.rvs()
        for iter in range(max(number_risks_categ)):
            for categ_id in range(len(acceptable_by_category)):    #Here we take only one risk per category at a time to achieve risk[C1], risk[C2], risk[C3], risk[C4], risk[C1], risk[C2], ... if possible.
                if iter < number_risks_categ[categ_id] and acceptable_by_category[categ_id] > 0 and \
                                risks_per_categ[categ_id][iter] is not None:
                    risk_to_insure = risks_per_categ[categ_id][iter]
                    if risk_to_insure.get("contract") is not None and risk_to_insure[
                        "contract"].expiration > time:  # risk_to_insure["contract"]: # required to rule out contracts that have exploded in the meantime
                        [condition, cash_left_by_categ] = self.balanced_portfolio(risk_to_insure, cash_left_by_categ, None)   #Here it is check whether the portfolio is balanced or not if the reinrisk (risk_to_insure) is underwritten. Return True if it is balanced. False otherwise.
                        if condition:
                            contract = ReinsuranceContract(self, risk_to_insure, time, \
                                                           self.simulation.get_reinsurance_market_premium(),
                                                           risk_to_insure["expiration"] - time, \
                                                           self.default_contract_payment_period, \
                                                           expire_immediately=self.simulation_parameters[
                                                               "expire_immediately"], )
                            self.underwritten_contracts.append(contract)
                            self.cash_left_by_categ = cash_left_by_categ
                            risks_per_categ[categ_id][iter] = None
                            # TODO: move this to insurancecontract (ca. line 14) -> DONE
                            # TODO: do not write into other object's properties, use setter -> DONE
                    else:
                        [condition, cash_left_by_categ] = self.balanced_portfolio(risk_to_insure, cash_left_by_categ,
                                                                                  var_per_risk_per_categ) #Here it is check whether the portfolio is balanced or not if the risk (risk_to_insure) is underwritten. Return True if it is balanced. False otherwise.
                        if condition:
                            contract = InsuranceContract(self, risk_to_insure, time, self.simulation.get_market_premium(), \
                                                         _cached_rvs, \
                                                         self.default_contract_payment_period, \
                                                         expire_immediately=self.simulation_parameters[
                                                             "expire_immediately"], \
                                                         initial_VaR=var_per_risk_per_categ[categ_id])
                            self.underwritten_contracts.append(contract)
                            self.cash_left_by_categ = cash_left_by_categ
                            risks_per_categ[categ_id][iter] = None
                    acceptable_by_category[categ_id] -= 1  # TODO: allow different values per risk (i.e. sum over value (and reinsurance_share) or exposure instead of counting)

        not_accepted_risks = []
        for categ_id in range(len(acceptable_by_category)):
            for risk in risks_per_categ[categ_id]:
                if risk is not None:
                    not_accepted_risks.append(risk)

        return risks_per_categ, not_accepted_risks
Beispiel #5
0
    def iterate(self, time):        # TODO: split function so that only the sequence of events remains here and everything else is in separate methods
        """obtain investments yield"""
        self.obtain_yield(time)

        """realize due payments"""
        self.effect_payments(time)
        if isleconfig.verbose:
            print(time, ":", self.id, len(self.underwritten_contracts), self.cash, self.operational)

        self.make_reinsurance_claims(time)

        """mature contracts"""
        if isleconfig.verbose:
            print("Number of underwritten contracts ", len(self.underwritten_contracts))
        maturing = [contract for contract in self.underwritten_contracts if contract.expiration <= time]
        for contract in maturing:
            self.underwritten_contracts.remove(contract)
            contract.mature(time)
        contracts_dissolved = len(maturing)

        """effect payments from contracts"""
        [contract.check_payment_due(time) for contract in self.underwritten_contracts]

        if self.operational:

            """request risks to be considered for underwriting in the next period and collect those for this period"""
            new_risks = []
            if self.is_insurer:
                new_risks += self.simulation.solicit_insurance_requests(self.id, self.cash)
            if self.is_reinsurer:
                new_risks += self.simulation.solicit_reinsurance_requests(self.id, self.cash)
            contracts_offered = len(new_risks)
            try:
                assert contracts_offered > 2 * contracts_dissolved
            except:
                print("Something wrong; agent {0:d} receives too few new contracts {1:d} <= {2:d}".format(self.id, contracts_offered, 2*contracts_dissolved),file=sys.stderr)
            #print(self.id, " has ", len(self.underwritten_contracts), " & receives ", contracts_offered, " & lost ", contracts_dissolved)
            
            new_nonproportional_risks = [risk for risk in new_risks if risk.get("insurancetype")=='excess-of-loss' and risk["owner"] is not self]
            new_risks = [risk for risk in new_risks if risk.get("insurancetype") in ['proportional', None] and risk["owner"] is not self]

            underwritten_risks = [{"value": contract.value, "category": contract.category, \
                            "risk_factor": contract.risk_factor, "deductible": contract.deductible, \
                            "excess": contract.excess, "insurancetype": contract.insurancetype, \
                            "runtime": contract.runtime} for contract in self.underwritten_contracts if contract.reinsurance_share != 1.0]
            
            """deal with non-proportional risks first as they must evaluate each request separatly, then with proportional ones"""
            for risk in new_nonproportional_risks:
                accept, var_this_risk, self.excess_capital = self.riskmodel.evaluate(underwritten_risks, self.cash, risk)       # TODO: change riskmodel.evaluate() to accept new risk to be evaluated and to account for existing non-proportional risks correctly -> DONE.
                if accept:
                    per_value_reinsurance_premium = self.np_reinsurance_premium_share * risk["periodized_total_premium"] * risk["runtime"] / risk["value"]            #TODO: rename this to per_value_premium in insurancecontract.py to avoid confusion
                    contract = ReinsuranceContract(self, risk, time, per_value_reinsurance_premium, risk["runtime"], \
                                                  self.default_contract_payment_period, \
                                                  expire_immediately=self.simulation_parameters["expire_immediately"], \
                                                  initial_VaR=var_this_risk, \
                                                  insurancetype=risk["insurancetype"])        # TODO: implement excess of loss for reinsurance contracts
                    self.underwritten_contracts.append(contract)
                #pass    # TODO: write this nonproportional risk acceptance decision section based on commented code in the lines above this -> DONE.
            
            """obtain risk model evaluation (VaR) for underwriting decisions and for capacity specific decisions"""
            # TODO: Enable reinsurance shares other tan 0.0 and 1.0
            expected_profit, acceptable_by_category, var_per_risk_per_categ, self.excess_capital = self.riskmodel.evaluate(underwritten_risks, self.cash)
            
            # TODO: resolve insurance reinsurance inconsistency (insurer underwrite after capacity decisions, reinsurers before). 
            #                        This is currently so because it minimizes the number of times we need to run self.riskmodel.evaluate().
            #                        It would also be more consistent if excess capital would be updated at the end of the iteration.
            """handle adjusting capacity target and capacity"""
            max_var_by_categ = self.cash - self.excess_capital
            self.adjust_capacity_target(max_var_by_categ)
            actual_capacity = self.increase_capacity(time, max_var_by_categ)
            # seek reinsurance
            #if self.is_insurer:
            #    # TODO: Why should only insurers be able to get reinsurance (not reinsurers)? (Technically, it should work) --> OBSOLETE
            #    self.ask_reinsurance(time)
            #    # TODO: make independent of insurer/reinsurer, but change this to different deductable values
            """handle capital market interactions: capital history, dividends"""
            self.cash_last_periods = [self.cash] + self.cash_last_periods[:3]
            self.adjust_dividends(time, actual_capacity)
            self.pay_dividends(time)

            """make underwriting decisions, category-wise"""
            #if expected_profit * 1./self.cash < self.profit_target:
            #    self.acceptance_threshold = ((self.acceptance_threshold - .4) * 5. * self.acceptance_threshold_friction) / 5. + .4
            #else:
            #    self.acceptance_threshold = (1 - self.acceptance_threshold_friction * (1 - (self.acceptance_threshold - .4) * 5.)) / 5. + .4

            growth_limit = max(50, 2 * len(self.underwritten_contracts) + contracts_dissolved)
            if sum(acceptable_by_category) > growth_limit:
                acceptable_by_category = np.asarray(acceptable_by_category)
                acceptable_by_category = acceptable_by_category * growth_limit / sum(acceptable_by_category)
                acceptable_by_category = np.int64(np.round(acceptable_by_category))

            not_accepted_risks = []
            for categ_id in range(len(acceptable_by_category)):
                categ_risks = [risk for risk in new_risks if risk["category"] == categ_id]
                new_risks = [risk for risk in new_risks if risk["category"] != categ_id]
                categ_risks = sorted(categ_risks, key = lambda risk: risk["risk_factor"])
                i = 0
                if isleconfig.verbose:
                    print("InsuranceFirm underwrote: ", len(self.underwritten_contracts), " will accept: ", acceptable_by_category[categ_id], " out of ", len(categ_risks), "acceptance threshold: ", self.acceptance_threshold)
                while (acceptable_by_category[categ_id] > 0 and len(categ_risks) > i): #\
                    #and categ_risks[i]["risk_factor"] < self.acceptance_threshold):
                    if categ_risks[i].get("contract") is not None: #categ_risks[i]["reinsurance"]:
                        if categ_risks[i]["contract"].expiration > time:    # required to rule out contracts that have exploded in the meantime
                            #print("ACCEPTING", categ_risks[i]["contract"].expiration, categ_risks[i]["expiration"], categ_risks[i]["identifier"], categ_risks[i].get("contract").terminating)
                            contract = ReinsuranceContract(self, categ_risks[i], time, \
                                          self.simulation.get_market_premium(), categ_risks[i]["expiration"] - time, \
                                          self.default_contract_payment_period, \
                                          expire_immediately=self.simulation_parameters["expire_immediately"], )  
                            self.underwritten_contracts.append(contract)
                            #categ_risks[i]["contract"].reincontract = contract
                            # TODO: move this to insurancecontract (ca. line 14) -> DONE
                            # TODO: do not write into other object's properties, use setter -> DONE

                            assert categ_risks[i]["contract"].expiration >= contract.expiration, "Reinsurancecontract lasts longer than insurancecontract: {0:d}>{1:d} (EXPIRATION2: {2:d} Time: {3:d})".format(contract.expiration, categ_risks[i]["contract"].expiration, categ_risks[i]["expiration"], time)
                        #else:
                        #    pass
                    else:
                        contract = InsuranceContract(self, categ_risks[i], time, self.simulation.get_market_premium(), \
                                                     self.contract_runtime_dist.rvs(), \
                                                     self.default_contract_payment_period, \
                                                     expire_immediately=self.simulation_parameters["expire_immediately"], \
                                                     initial_VaR = var_per_risk_per_categ[categ_id])
                        self.underwritten_contracts.append(contract)
                    acceptable_by_category[categ_id] -= 1   # TODO: allow different values per risk (i.e. sum over value (and reinsurance_share) or exposure instead of counting)
                    i += 1

                not_accepted_risks += categ_risks[i:]
                not_accepted_risks = [risk for risk in not_accepted_risks if risk.get("contract") is None]

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

            #not implemented
            #"""adjust liquidity, borrow or invest"""
            #pass
            
        self.estimated_var()
Beispiel #6
0
    def reinsure_tranche(
        self,
        category: int,
        deductible_fraction: float,
        limit_fraction: float,
        time: int,
        purpose: str,
    ):
        (total_value, avg_risk_factor, number_risks,
         periodized_total_premium) = (
             self.underwritten_risk_characterisation[category].total_value,
             self.underwritten_risk_characterisation[category].avg_risk_factor,
             self.underwritten_risk_characterisation[category].number_risks,
             self.underwritten_risk_characterisation[category].
             periodized_total_premium,
         )
        runtime = isleconfig.simulation_parameters[
            "reinsurance_contract_runtime"]
        risk = genericclasses.RiskProperties(
            value=total_value,
            category=category,
            owner=self,
            insurancetype="excess-of-loss",
            number_risks=number_risks,
            deductible_fraction=deductible_fraction,
            limit_fraction=limit_fraction,
            periodized_total_premium=periodized_total_premium,
            runtime=runtime,
            expiration=time + runtime,
            risk_factor=avg_risk_factor,
            deductible=deductible_fraction * total_value,
            limit=limit_fraction * total_value,
        )
        if not (risk.deductible_fraction < risk.limit_fraction <= 1):
            raise ValueError(
                "Can't reinsure invalid tranche - deductible must be < limit <= 1"
            )

        reinsurance_type = self.decide_reinsurance_type(risk)
        if reinsurance_type == "reinsurance":
            if purpose == "newrisk":
                self.simulation.append_reinrisks(risk)
                return None
            elif purpose == "rollover":
                return risk

        elif reinsurance_type == "catbond":
            # The whole premium is transfered to the bond at creation, not periodically
            # TODO: Should the premium be periodic as for any other reinsurance? Would help, probably
            # TODO: Allow for catbonds to be paid out multiple times
            risk.periodized_total_premium = 0
            total_premium = (self.get_catbond_price(risk) * risk.value *
                             self.np_reinsurance_premium_share)
            if not self.cash >= total_premium:
                # We can't actually afford to issue the catbond. Ideally this shouldn't be reached, but it is.
                return None
            per_period_premium = total_premium / risk.runtime
            new_catbond = catbond.CatBond(self.simulation, per_period_premium,
                                          self)
            """add contract; contract is a quasi-reinsurance contract"""
            # This automatically adds reinsurance to self.reinsurance_profile
            # per_value_reinsurance_premium = 0 because the insurance firm make only one payment to catbond
            contract = ReinsuranceContract(
                new_catbond,
                risk,
                time,
                0,
                risk.runtime,
                self.default_contract_payment_period,
                expire_immediately=self.
                simulation_parameters["expire_immediately"],
                insurancetype=risk.insurancetype,
            )

            new_catbond.set_contract(contract)
            """sell cat bond (to self.simulation)"""
            # amount changed from var_this_risk to total exposure
            exposure = risk.value * (risk.limit_fraction -
                                     risk.deductible_fraction)
            self.simulation.receive_obligation(exposure + 1, new_catbond, time,
                                               "bond")
            new_catbond.set_owner(self.simulation)
            """hand cash over to cat bond to cover the premium payouts"""
            # If we added this as an obligation in the normal way, there would be a risk that the firm would go under
            # before paying, which would cause the catbond to never really have been created which is confusing

            obligation = genericclasses.Obligation(
                amount=total_premium,
                recipient=new_catbond,
                due_time=time,
                purpose="bond",
            )
            self._pay(obligation)
            """register catbond"""
            self.simulation.add_agents(catbond.CatBond, "catbond",
                                       [new_catbond])
        else:
            # print(f"\nIF {self.id} attempted to get reinsurance for {risk.limit-risk.deductible:.0f} xs"
            #      f" {risk.deductible:.0f} but it was too expensive")
            return None