def add_transaction(self, type_, asset, from_id, to_id, amount, interest, maturity, time_of_default): from src.transaction import Transaction transaction = Transaction() transaction.this_transaction(type_, asset, from_id, to_id, amount, interest, maturity, time_of_default) self.accounts.append(transaction) del transaction # append() above does make a copy so we may delete for garbage collection
def add_transaction(self, type_, asset, from_id, to_id, amount, interest, maturity, time_of_default, environment): from src.transaction import Transaction transaction = Transaction() transaction.this_transaction(type_, asset, from_id, to_id, amount, interest, maturity, time_of_default) transaction.add_transaction(environment)
def make_deposits(self, environment, time): for household in environment.households: cash = 0.0 # total of cash available for the household control_deposits = 0 # checking if the household already has deposits # We calculate the available cash for tranx in household.accounts: if tranx.type_ == "cash": cash = cash + tranx.amount tranx.amount = 0 # And the number of existing deposits if tranx.type_ == "deposits": control_deposits = control_deposits + 1 # And move all available cash to deposits at the end of the step # If there are no deposits we create one in a bank # The bank is chosen randomly if control_deposits == 0: # We choose a bank randomly random_bank = random.choice(environment.banks) # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("deposits", "", household.identifier, random_bank, amount, random_bank.interest_rate_deposits, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # If there are previous deposits we expand them linearly else: for tranx in household.accounts: if tranx.type_ == "deposits": # We add the remaining cash to the existing deposits # in equal proportions # Perhaps this can be done proportionate with regards # to the value of these deposits, but it's minor at this point tranx.amount = tranx.amount + (cash/control_deposits) logging.info(" deposits made on step: %s", time)
def endow_labour(self, environment, time): # We make sure household get their labour endowment per step for household in environment.households: # First, we set a control variable that makes sure we have exactly # one transaction with "manhours", though this should in general # be the case, this should always run through the second if check = 0 for tranx in household.accounts: if tranx.type_ == "manhours": check = check + 1 # We check how many transactions with manhours are there for the household # If there are no "manhours" transactions then we create one and add it to the household's accounts if check == 0: # The amount is equal to the parameter read from the config of the household amount = household.labour # We create the transaction transaction = Transaction() # We add the appropriate values to the transaction transaction.this_transaction("manhours", "", household.identifier, household.identifier, amount, 0, 0, -1) # It's important to add the transaction using the method # from Transaction class and not manually transaction.add_transaction(environment) else: # If we have more than one "mahhours" transaction we raise an error raise LookupError( "Labour transactions for a household haven't been properly removed." ) logging.info(" labour endowed on step: %s", time)
def endow_labour(self, environment, time): # We make sure household get their labour endowment per step for household in environment.households: # First, we set a control variable that makes sure we have exactly # one transaction with "manhours", though this should in general # be the case, this should always run through the second if check = 0 for tranx in household.accounts: if tranx.type_ == "manhours": check = check + 1 # We check how many transactions with manhours are there for the household # If there are no "manhours" transactions then we create one and add it to the household's accounts if check == 0: # The amount is equal to the parameter read from the config of the household amount = household.labour # We create the transaction transaction = Transaction() # We add the appropriate values to the transaction transaction.this_transaction("manhours", "", household.identifier, household.identifier, amount, 0, 0, -1) # It's important to add the transaction using the method # from Transaction class and not manually transaction.add_transaction(environment) else: # If we have more than one "mahhours" transaction we raise an error raise LookupError("Labour transactions for a household haven't been properly removed.") logging.info(" labour endowed on step: %s", time)
def new_transaction(self, type_, asset, from_, to, amount, interest, maturity, time_of_default): from src.transaction import Transaction transaction = Transaction() transaction.this_transaction(type_, asset, from_, to, amount, interest, maturity, time_of_default) transaction.add_transaction(self)
def transfer_required_deposits(self): transaction = Transaction() value = round(float(self.r * self.get_account("D")), 4) transaction.this_transaction("rD", self.identifier, -3, value, self.rb, 0, -1) self.accounts.append(transaction) return -1.0 * value
def transaction__add_transaction(self, args): import os from src.bank import Bank from src.household import Household from src.firm import Firm from src.environment import Environment from src.transaction import Transaction text = "This test checks transaction.add_transaction \n" self.print_info(text) # # INITIALIZATION # environment_directory = str(args[0]) identifier = str(args[1]) log_directory = str(args[2]) # Configure logging parameters so we get output while the program runs logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %H:%M:%S', filename=log_directory + identifier + ".log", level=logging.INFO) logging.info('START logging for test transaction__add_transaction in run: %s', environment_directory + identifier + ".xml") # Construct household filename environment = Environment(environment_directory, identifier) # generate a bank bank = Bank() bank.identifier = "test_bank" environment.banks.append(bank) # generate a firm firm = Firm() firm.identifier = "test_firm" environment.firms.append(firm) # generate a household household = Household() household.identifier = "test_household" environment.households.append(household) # # TESTING # print("Creating a transaction") transaction = Transaction() print("Assigning values") transaction.this_transaction("type", "asset", "test_household", "test_firm", 1, 2, 3, 4) print("Adding the transaction to the books") transaction.add_transaction(environment) print("The transaction:") print(transaction) print("The firm:") print(environment.get_agent_by_id("test_firm")) print("The household:") print(environment.get_agent_by_id("test_household"))
def transfer_required_deposits(self): from src.transaction import Transaction transaction = Transaction() value = round(float(self.parameters["r"]*self.get_account("D")), 4) transaction.this_transaction("rD", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) return -1.0*value
def transfer_excess_reserves(self): availableVolume = self.Q plannedVolume = self.gamma * (1.0 - self.lamb) * self.V transactionVolume = round(min(plannedVolume, availableVolume), 4) self.Q = round(self.Q - transactionVolume, 4) if self.Q < 0.0: logging.info("ERROR: Q negative in transfer_excess_reserves") transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, transactionVolume, self.rb, 0, -1) self.accounts.append(transaction) del transaction
def transfer_excess_reserves(self): from src.transaction import Transaction availableVolume = self.parameters["Q"] plannedVolume = self.parameters["gamma"]*(1.0-self.parameters["lamb"])*self.parameters["V"] transactionVolume = round(min(plannedVolume, availableVolume), 4) self.parameters["Q"] = round(self.parameters["Q"] - transactionVolume, 4) if (self.parameters["Q"] < 0.0): logging.info("ERROR: Q negative in transfer_excess_reserves") transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, transactionVolume, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction
def initialize_standard_bank(self, bank, environment): from src.transaction import Transaction bank.identifier = "standard_bank_id" # deposits - we get the first household from the list of households # if there are no households it will be a blank which is fine for testing amount = 250.0 transaction = Transaction() transaction.this_transaction("deposits", "", environment.households[0].identifier, bank.identifier, amount, bank.interest_rate_deposits, 0, -1) # environment.households[0] is only for testing purposes DO NOT USE IN PRODUCTION transaction.add_transaction(environment) # money - cash and equivalents amount = 100.0 transaction = Transaction() transaction.this_transaction("cash", "", bank.identifier, bank.identifier, amount, 0, 0, -1) transaction.add_transaction(environment) # loans - we get the first firm from the list of firms # if there are no firms it will be a blank which is fine for testing amount = 150.0 transaction = Transaction() transaction.this_transaction("loans", "", bank.identifier, environment.firms[0].identifier, amount, bank.interest_rate_loans, 0, -1) # environment.firms[0] is only for testing purposes DO NOT USE IN PRODUCTION transaction.add_transaction(environment)
def initialize_standard_household(self, household, environment): from src.transaction import Transaction household.identifier = "standard_household_id" # identifier household.parameters["labour"] = 24.00 # labour to sell per step household.parameters["propensity_to_save"] = 0.40 # propensity to save # percentage of income household wants to save as deposits # deposits - we get the first bank from the list of banks # if there are no banks it will be a blank which is fine for testing amount = 200.0 transaction = Transaction() transaction.this_transaction("deposits", "", household.identifier, environment.banks[0].identifier, amount, environment.banks[0].interest_rate_deposits, 0, -1) # environment.banks[0] is only for testing purposes DO NOT USE IN PRODUCTION transaction.add_transaction(environment) # money - cash and equivalents amount = 50.0 transaction = Transaction() transaction.this_transaction("cash", "", household.identifier, household.identifier, amount, 0, 0, -1) transaction.add_transaction(environment) # manhours - labour to sell amount = 250.0 transaction = Transaction() transaction.this_transaction("manhours", "", household.identifier, household.identifier, amount, 0, 0, -1) transaction.add_transaction(environment)
def initialize_standard_bank(self, bank, environment): from src.transaction import Transaction bank.identifier = "standard_bank_id" # deposits - we get the first household from the list of households # if there are no households it will be a blank which is fine for testing amount = 250.0 transaction = Transaction() transaction.this_transaction("deposits", "", environment.households[0:1][0], bank.identifier, amount, bank.interest_rate_deposits, 0, -1) # environment.households[0:1][0] is only for testing purposes DO NOT USE IN PRODUCTION # what it does is is takes the first household in environment, but if there are no # households (which happens in testing) it doesn't break down bank.accounts.append(transaction) # money - cash and equivalents amount = 100.0 transaction = Transaction() transaction.this_transaction("cash", "", bank.identifier, bank.identifier, amount, 0, 0, -1) bank.accounts.append(transaction) # loans - we get the first firm from the list of firms # if there are no firms it will be a blank which is fine for testing amount = 150.0 transaction = Transaction() transaction.this_transaction("loans", "", bank.identifier, environment.firms[0:1][0], amount, bank.interest_rate_loans, 0, -1) # environment.firms[0:1][0] is only for testing purposes DO NOT USE IN PRODUCTION # what it does is is takes the first firm in environment, but if there are no # firms (which happens in testing) it doesn't break down bank.accounts.append(transaction)
def initialize_standard_firm(self, firm, environment): from src.transaction import Transaction firm.identifier = "standard_firm_id" # identifier firm.parameters["productivity"] = 1.20 # how much goods do we get from 1 unit of labour # loans - we get the first bank from the list of banks # if there are no banks it will be a blank which is fine for testing amount = 250.0 transaction = Transaction() transaction.this_transaction( "loans", "", environment.banks[0].identifier, firm.identifier, amount, environment.banks[0].interest_rate_loans, 0, -1, ) # environment.banks[0] is only for testing purposes DO NOT USE IN PRODUCTION transaction.add_transaction(environment) # money - cash and equivalents amount = 200.0 transaction = Transaction() transaction.this_transaction("cash", "", firm.identifier, firm.identifier, amount, 0, 0, -1) transaction.add_transaction(environment) # goods - unique production amount = 50.0 transaction = Transaction() transaction.this_transaction("goods", "", firm.identifier, firm.identifier, amount, 0, 0, -1) transaction.add_transaction(environment)
def initialize_standard_household(self, household, environment): from src.transaction import Transaction household.identifier = "standard_household_id" # identifier household.parameters["labour"] = 24.00 # labour to sell per step household.parameters["propensity_to_save"] = 0.40 # propensity to save # percentage of income household wants to save as deposits # deposits - we get the first bank from the list of banks # if there are no banks it will be a blank which is fine for testing amount = 200.0 transaction = Transaction() transaction.this_transaction( "deposits", "", household.identifier, environment.banks[0:1][0], amount, environment.banks[0:1][0].interest_rate_deposits, 0, -1) # environment.banks[0:1][0] is only for testing purposes DO NOT USE IN PRODUCTION # what it does is is takes the first bank in environment, but if there are no # banks (which happens in testing) it doesn't break down household.accounts.append(transaction) # money - cash and equivalents amount = 50.0 transaction = Transaction() transaction.this_transaction("cash", "", household.identifier, household.identifier, amount, 0, 0, -1) household.accounts.append(transaction) # manhours - labour to sell amount = 250.0 transaction = Transaction() transaction.this_transaction("manhours", "", household.identifier, household.identifier, amount, 0, 0, -1) household.accounts.append(transaction)
def initialize_standard_firm(self, firm, environment): from src.transaction import Transaction firm.identifier = "standard_firm_id" # identifier firm.parameters[ "productivity"] = 1.20 # how much goods do we get from 1 unit of labour # loans - we get the first bank from the list of banks # if there are no banks it will be a blank which is fine for testing amount = 250.0 transaction = Transaction() transaction.this_transaction( "loans", "", environment.banks[0:1][0], firm.identifier, amount, environment.banks[0:1][0].interest_rate_loans, 0, -1) # environment.banks[0:1][0] is only for testing purposes DO NOT USE IN PRODUCTION # what it does is is takes the first bank in environment, but if there are no # banks (which happens in testing) it doesn't break down firm.accounts.append(transaction) # money - cash and equivalents amount = 200.0 transaction = Transaction() transaction.this_transaction("cash", "", firm.identifier, firm.identifier, amount, 0, 0, -1) firm.accounts.append(transaction) # goods - unique production amount = 50.0 transaction = Transaction() transaction.this_transaction("goods", "", firm.identifier, firm.identifier, amount, 0, 0, -1) firm.accounts.append(transaction)
def produce(self, environment, time): # We take all the labour and turn it into goods for firm in environment.firms: # We do it for every firm production_factors = 0 # Here, we count how much labour the firm has for tranx in firm.accounts: if tranx.type_ == "manhours": # We move the labour to production as a production factor # First, we move it to production factors used below # Then we will remove it from the books production_factors = production_factors + tranx.amount # Amount produced is labour * productivity in this simple model amount = production_factors * firm.productivity # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("goods", "", firm.identifier, firm.identifier, amount, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # Finally, we remove all the labour that was used in production # from the books of the firms self.remove_labour_firms(environment, time) logging.info(" goods produced on step: %s", time)
def transaction__this_transaction(self, args): import os from src.bank import Bank from src.household import Household from src.firm import Firm from src.environment import Environment from src.transaction import Transaction text = "This test checks transaction.this_transaction \n" self.print_info(text) # # INITIALIZATION # environment_directory = str(args[0]) identifier = str(args[1]) log_directory = str(args[2]) # Configure logging parameters so we get output while the program runs logging.basicConfig(format='%(asctime)s %(message)s', datefmt='%m/%d/%Y %H:%M:%S', filename=log_directory + identifier + ".log", level=logging.INFO) logging.info('START logging for test transaction__this_transaction in run: %s', environment_directory + identifier + ".xml") # Construct household filename environment = Environment(environment_directory, identifier) # # TESTING # print("Creating a transaction") transaction = Transaction() print("Assigning values") transaction.this_transaction("type", "asset", "from", "to", 1, 2, 3, 4) print("The transaction:") print(transaction)
def make_deposits(self, environment, time): for household in environment.households: cash = 0.0 # total of cash available for the household control_deposits = 0 # checking if the household already has deposits # We calculate the available cash for tranx in household.accounts: if tranx.type_ == "cash": cash = cash + tranx.amount tranx.amount = 0 # And the number of existing deposits if tranx.type_ == "deposits": control_deposits = control_deposits + 1 # And move all available cash to deposits at the end of the step # If there are no deposits we create one in a bank # The bank is chosen randomly if control_deposits == 0: # We choose a bank randomly random_bank = random.choice(environment.banks) # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction( "deposits", "", household.identifier, random_bank, amount, random_bank.interest_rate_deposits, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # If there are previous deposits we expand them linearly else: for tranx in household.accounts: if tranx.type_ == "deposits": # We add the remaining cash to the existing deposits # in equal proportions # Perhaps this can be done proportionate with regards # to the value of these deposits, but it's minor at this point tranx.amount = tranx.amount + (cash / control_deposits) logging.info(" deposits made on step: %s", time)
def initialize_standard_bank(self): self.identifier = "0" # identifier self.rb = 0.02 # refinancing costs of the bank -> tbd in environment self.rd = 0.01 # interest rate on deposits self.r = 0.05 # required reserve rate -> tbd in environment self.pReal = 0.9 # probability of credit success self.rhoReal = 0.03 # interest charged on risky investment self.xi = 1.0 # scaling parameter in CRRA self.theta = 1.5 # risk aversion parameter of bank self.gamma = 0.8 # fraction of interbank loans in overall volume assetNumber = 6.0 # number of assets available to bank numBanks = 3.0 # number of banks in the economy # first, calculate number of transactions for investments numTransactions = int(round(assetNumber / numBanks)) # # ASSETS # # finally, put them on the transaction stack for i in range(numTransactions): transaction = Transaction() value = 100.0 maturity = 50.0 timeOfDefault = -1 transaction.this_transaction("I", self.identifier, -2, value, self.rhoReal, maturity, timeOfDefault) self.accounts.append(transaction) del transaction # excess reserves value = 90.0 transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, value, self.rb, 0, -1) self.accounts.append(transaction) del transaction # required deposits to the central bank value = 10.0 transaction = Transaction() transaction.this_transaction("rD", self.identifier, -3, value, self.rb, 0, -1) self.accounts.append(transaction) del transaction # # LIABILITIES # # banking capital value = 30.0 transaction = Transaction() transaction.this_transaction("BC", self.identifier, self.identifier, value, 0.0, 0, -1) self.accounts.append(transaction) del transaction # deposits value = 260.0 transaction = Transaction() transaction.this_transaction("D", -1, self.identifier, value, self.rd, 0, -1) self.accounts.append(transaction) del transaction # central bank loans value = 10.0 transaction = Transaction() transaction.this_transaction("LC", -3, self.identifier, value, self.rb, 0, -1) self.accounts.append(transaction) del transaction
def consume(self, environment, time): # We want the consumption to be done in random pairs # So we need to randomise the households and the firms # We start with the households and create a list of order integers # the size of the number of households itrange_hh = list(range(0, int(environment.num_households))) # Then we shuffle the list random.shuffle(itrange_hh) # And use it to loop over the households randomly for h in itrange_hh: # Since we don't loop directly over households # We assign the correct household in this run over the loop household = environment.households[h] wealth = 0.0 # total of deposits and cash available for the household cash = 0.0 # total of cash available for the household # We calculate the above two values for tranx in household.accounts: # We add all deposits and all cash to the wealth if tranx.type_ == "deposits" or tranx.type_ == "cash": wealth = wealth + tranx.amount # But only cash to the available cash if tranx.type_ == "cash": cash = cash + tranx.amount # We consume the percentage of wealth determined by # the propensity to save, cash first to_consume = wealth * (1 - household.propensity_to_save) # Now we randomise firms and create a list of order integers # the size of the number of households itrange = list(range(0, int(environment.num_firms))) # Then we shuffle the list random.shuffle(itrange) # For each firm in random order for i in itrange: # For every transaction on that firm's books # We make a proxy for the cash that firm should obtain # for whatever good they've sold to the household firm = environment.firms[i] firm_cash = 0.0 for tranx in firm.accounts: # If the transaction contains goods if tranx.type_ == "goods": # We go through the household's accounts for tranx_h in household.accounts: # And look for cash if tranx_h.type_ == "cash": # We can buy for minimum of the cash and goods # in question amount_proxy = min(tranx.amount, tranx_h.amount, to_consume) # And remove the appropriate amount of cash tranx_h.amount = tranx_h.amount - amount_proxy # Lower the amount household wants to consume to_consume = to_consume - amount_proxy # And remove the goods from firm's account tranx.amount = tranx.amount - amount_proxy # And we note the cash to be added to the firm firm_cash = firm_cash + amount_proxy for tranx_h in household.accounts: # And look for deposits if tranx_h.type_ == "deposits": # We can buy for minimum of the deposits and goods # in question amount_proxy = min(tranx.amount, tranx_h.amount, to_consume) # And remove the appropriate amount of deposits tranx_h.amount = tranx_h.amount - amount_proxy # Lower the amount household wants to consume to_consume = to_consume - amount_proxy # And remove the goods from firm's account tranx.amount = tranx.amount - amount_proxy # And we note the cash to be added to the firm firm_cash = firm_cash + amount_proxy # Add cash for sold items to the firm cash_number = 0 # We calculate how many cash account the firm has for tranx in firm.accounts: if tranx.type_ == "cash": cash_number = cash_number + 1 # If the firm doesn't have any cash accounts we create a new one if cash_number == 0: # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("cash", "", firm.identifier, firm.identifier, firm_cash, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # If the firm has previous cash transactions we add the cash from sales proportionately else: # We find all cash transactions for tranx in firm.accounts: if tranx.type_ == "cash": # And add the sales proceeds proportionately tranx.amount = tranx.amount + (firm_cash / cash_number) # The sales above may have rendered some transactions worthless # So we need to purge all accounts to make sure everything is in order transaction = Transaction() transaction.purge_accounts(environment) # Finally, we remove the goods which weren't sold from firms' accounts # As they are perishable self.remove_goods_firms(environment, time) logging.info(" goods consumed on step: %s", time)
def transfer_investments(self, environment): from random import Random from src.transaction import Transaction random = Random() currentVolume = 0.0 optimalVolume = 0.0 plannedVolume = 0.0 availableVolume = 0.0 transactionVolume = 0.0 transaction = Transaction() # calculate the optimal investment volume and compare to current volume self.calculate_optimal_investment_volume(environment) optimalVolume = round(float(self.parameters["gamma"]*self.parameters["lamb"]*self.parameters["V"]), 4) currentVolume = round(self.get_account("I"), 4) # add new transactions of average size plannedVolume = currentVolume + optimalVolume availableVolume = self.parameters["lamb"]*self.parameters["Q"] # we can only spend a fraction of the available Q transactionVolume = min(plannedVolume, availableVolume) while ((transactionVolume >= self.parameters["averageTransactionSize"]) and (self.parameters["averageTransactionSize"] > 0.0)): transactionVolume = round(transactionVolume - self.parameters["averageTransactionSize"], 5) # reduce remaining transactionVolume self.parameters["Q"] = self.parameters["Q"] - self.parameters["averageTransactionSize"] # reduce available liquidity # account for different maturities of investments maturity = int(round(random.random()*environment.static_parameters["firmLoanMaturity"], 1)) # this is done very roughly and implies loans are up to 3 years # and determine whether the loan will default if (random.random() >= environment.static_parameters["successProbabilityFirms"]): # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random()*maturity)) else: timeOfDefault = -1 # and add transaction to the stack transaction = Transaction() transaction.this_transaction("I", self.identifier, -2, self.parameters["averageTransactionSize"], self.parameters["rhoReal"], maturity, timeOfDefault) self.accounts.append(transaction) del transaction transactionVolume = round(transactionVolume, 5) # finally, add the remaining transaction to the stack if the transactionVolume was positive in the first place if (transactionVolume > 0.0): self.parameters["Q"] = round(self.parameters["Q"] - transactionVolume, 4) # account for different maturities of investments maturity = int(round(random.random()*environment.static_parameters["firmLoanMaturity"], 1)) # this is done very roughly and implies loans are up to 3 years # and determine whether the loan will default if (random.random() >= environment.static_parameters["successProbabilityFirms"]): # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random()*maturity)) else: timeOfDefault = -1 transaction = Transaction() transaction.this_transaction("I", self.identifier, -2, transactionVolume, self.parameters["rhoReal"], maturity, timeOfDefault) self.accounts.append(transaction) del transaction
def sell_labour(self, environment, time): # We want the sell to be done in random pairs # So we need to randomise the households and the firms # We start with the firms and create a list of order integers # the size of the number of firms itrange = list(range(0, int(environment.num_firms))) # Then we shuffle the list random.shuffle(itrange) # And use it to loop over the firms randomly for i in itrange: # Since we don't loop directly over firms # We assign the correct firm in this run over the loop firm = environment.firms[i] # We calculate the amount of cash firm has to buy labour to_buy = 0.0 # We go through the firm's transactions for tranx in firm.accounts: # If we find cash transaction if tranx.type_ == "cash": # We add the cash to the amount of labour the firm # wants to buy, we assume 1 unit of labour costs 1 unit of cash to_buy = to_buy + tranx.amount # Now we randomise households and create a list of order integers # the size of the number of households itrange_hh = list(range(0, int(environment.num_households))) # Then we shuffle the list random.shuffle(itrange_hh) # For each household in random order for h in itrange_hh: # Since we don't loop directly over households # We assign the correct household in this run over the loop household = environment.households[h] household_cash = 0.0 # We go through household's accounts for tranx in household.accounts: # And find transactions with labour if tranx.type_ == "manhours": # We will sell them for cash # So we look through firm's accounts for tranx_f in firm.accounts: # And find cash transactions if tranx_f.type_ == "cash": # We can only buy the lowest amount from the cash the firm # has, the labour the household has, and however many units # they want to buy amount_proxy = min(tranx.amount, tranx_f.amount, to_buy) # Then we remove the appropriate amount of cash from the firm tranx_f.amount = tranx_f.amount - amount_proxy # Lower the amount firm wants to buy to_buy = to_buy - amount_proxy # And remove the goods from household's account tranx.amount = tranx.amount - amount_proxy # And we note the cash to be added to the household household_cash = household_cash + amount_proxy # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction( "manhours", "", firm.identifier, firm.identifier, amount_proxy, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # Add cash for sold items to the household cash_number = 0 # We calculate how many cash account the household has for tranx in household.accounts: if tranx.type_ == "cash": cash_number = cash_number + 1 # If there are no cash transactions on the household's books # We create a new one and put the proceeds there if cash_number == 0: # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("cash", "", household.identifier, household.identifier, household_cash, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # If the household has previous cash transactions we add the cash from sales proportionately else: # We find all cash transactions for tranx in household.accounts: if tranx.type_ == "cash": # And add the sales proceeds proportionately tranx.amount = tranx.amount + (household_cash / cash_number) # The sales above may have rendered some transactions worthless # So we need to purge all accounts to make sure everything is in order transaction = Transaction() transaction.purge_accounts(environment) logging.info(" labour sold to firms on step: %s", time)
def initialize_transactions(self, environment): from src.transaction import Transaction from random import Random random = Random() value = 0.0 # first, calculate number of transactions for investments numTransactions = int(round(self.parameters["assetNumber"] / self.parameters["numBanks"])) if (numTransactions == 0): # we want some error message if there are two few assets in the economy logging.info(" ERROR: number of assets in the economy has to be at least half the number of banks") # now, calculate value of each transaction and note that the *product* of all individual transactions # is supposed to have precision 4. Hence, each individual transaction should have precision 5 value = round(float(self.parameters["gamma"]*self.parameters["lamb"]*self.parameters["V"] / numTransactions), 5) # finally, put them on the transaction stack for i in range(numTransactions): transaction = Transaction() # # account for different maturities # maturity = int(round(random.random()*environment.static_parameters["firmLoanMaturity"], 1)) # maturity is between 0 and firmLoanMaturity # and determine whether the loan will default if (random.random() >= environment.static_parameters["successProbabilityFirms"]): # TODO this is superfluous, we could get rid of this doubling # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random()*maturity)) else: timeOfDefault = -1 # then, generate the transaction, append it to the accounts, and delete it from memory transaction.this_transaction("I", self.identifier, -2, value, self.parameters["rhoReal"], maturity, timeOfDefault) self.accounts.append(transaction) del transaction # store averageTransactionSize self.parameters["averageTransactionSize"] = value # then, calculate excess reserves value = round(float(self.parameters["gamma"]*(1.0-self.parameters["lamb"])*self.parameters["V"]), 4) transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction # on the liabilities side, banks are endowed with banking capital # (see comments in get_initial_banking_capital() for further details) value = round(float(self.get_initial_banking_capital(environment.static_parameters["requiredCapitalRatio"])), 4) transaction = Transaction() transaction.this_transaction("BC", self.identifier, self.identifier, value, 0.0, 0, -1) self.accounts.append(transaction) del transaction # now, transfer deposits from households to banks value = round(float(self.parameters["gamma"]*self.parameters["V"]-self.get_account("BC")), 4) transaction = Transaction() transaction.this_transaction("D", -1, self.identifier, value, self.parameters["rd"], 0, -1) self.accounts.append(transaction) del transaction # as well as required deposits to the central bank value = round(float(self.parameters["r"]*self.get_account("D")), 4) transaction = Transaction() transaction.this_transaction("rD", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction # finally, determine central bank loans value = round(float(self.get_account("I") + self.get_account("E") + self.get_account("rD") - self.get_account("D") - self.get_account("BC")), 4) transaction = Transaction() transaction.this_transaction("LC", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction
def add_transaction(self, type, fromID, toID, value, interest, maturity, timeOfDefault): from src.transaction import Transaction transaction = Transaction() transaction.this_transaction(type, fromID, toID, value, interest, maturity, timeOfDefault) self.accounts.append(transaction) del transaction
def initialize_standard_bank(self): from src.transaction import Transaction self.parameters["identifier"] = "0" # identifier self.parameters["V"] = 250.0 # planned optimal portfolio volume of the bank self.parameters["lamb"] = 0.5 # planned optimal portfolio structure of the bank self.parameters["rb"] = 0.02 # refinancing costs of the bank -> tbd in environment self.parameters["rd"] = 0.01 # interest rate on deposits self.parameters["r"] = 0.05 # required reserve rate -> tbd in environment self.parameters["pReal"] = 0.9 # probability of credit success self.parameters["rhoReal"] = 0.03 # interest charged on risky investment self.parameters["xi"] = 1.0 # scaling parameter in CRRA self.parameters["theta"] = 1.5 # risk aversion parameter of bank self.parameters["gamma"] = 0.8 # fraction of interbank loans in overall volume self.parameters["Q"] = 0.0 # the current liquidity position of the bank # set 0.0 as standard, but after calculate_liquidity_demand we will return the indicated values self.parameters["Ip"] = 0.0 # the planned optimal investment; (gamma * lamb * V) = (0.8 * 0.5 * 250.0) = 100.0 self.parameters["Ep"] = 0.0 # the planned excess reserves; (gamma * (1-lamb) * V) = (0.8 * 0.5 * 250.0) = 100.0 self.parameters["Lp"] = 0.0 # the planned interbank loans; Q - ((Ip-I) + (Ep-E)) = 90.0 self.parameters["assetNumber"] = 6.0 # number of assets available to bank self.parameters["numBanks"] = 3.0 # number of banks in the economy # first, calculate number of transactions for investments numTransactions = int(round(self.parameters["assetNumber"] / self.parameters["numBanks"])) # # ASSETS # # finally, put them on the transaction stack for i in range(numTransactions): transaction = Transaction() value = 100.0 maturity = 50.0 timeOfDefault = -1 transaction.this_transaction("I", self.identifier, -2, value, self.parameters["rhoReal"], maturity, timeOfDefault) self.accounts.append(transaction) del transaction # excess reserves value = 90.0 transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction # required deposits to the central bank value = 10.0 transaction = Transaction() transaction.this_transaction("rD", self.identifier, -3, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction # # LIABILITIES # # banking capital value = 40.0 transaction = Transaction() transaction.this_transaction("BC", self.identifier, self.identifier, value, 0.0, 0, -1) self.accounts.append(transaction) del transaction # deposits value = 250.0 transaction = Transaction() transaction.this_transaction("D", -1, self.identifier, value, self.parameters["rd"], 0, -1) self.accounts.append(transaction) del transaction # central bank loans value = 10.0 transaction = Transaction() transaction.this_transaction("LC", -3, self.identifier, value, self.parameters["rb"], 0, -1) self.accounts.append(transaction) del transaction
def sell_labour(self, environment, time): # We want the sell to be done in random pairs # So we need to randomise the households and the firms # We start with the firms and create a list of order integers # the size of the number of firms itrange = list(range(0, int(environment.num_firms))) # Then we shuffle the list random.shuffle(itrange) # And use it to loop over the firms randomly for i in itrange: # Since we don't loop directly over firms # We assign the correct firm in this run over the loop firm = environment.firms[i] # We calculate the amount of cash firm has to buy labour to_buy = 0.0 # We go through the firm's transactions for tranx in firm.accounts: # If we find cash transaction if tranx.type_ == "cash": # We add the cash to the amount of labour the firm # wants to buy, we assume 1 unit of labour costs 1 unit of cash to_buy = to_buy + tranx.amount # Now we randomise households and create a list of order integers # the size of the number of households itrange_hh = list(range(0, int(environment.num_households))) # Then we shuffle the list random.shuffle(itrange_hh) # For each household in random order for h in itrange_hh: # Since we don't loop directly over households # We assign the correct household in this run over the loop household = environment.households[h] household_cash = 0.0 # We go through household's accounts for tranx in household.accounts: # And find transactions with labour if tranx.type_ == "manhours": # We will sell them for cash # So we look through firm's accounts for tranx_f in firm.accounts: # And find cash transactions if tranx_f.type_ == "cash": # We can only buy the lowest amount from the cash the firm # has, the labour the household has, and however many units # they want to buy amount_proxy = min(tranx.amount, tranx_f.amount, to_buy) # Then we remove the appropriate amount of cash from the firm tranx_f.amount = tranx_f.amount - amount_proxy # Lower the amount firm wants to buy to_buy = to_buy - amount_proxy # And remove the goods from household's account tranx.amount = tranx.amount - amount_proxy # And we note the cash to be added to the household household_cash = household_cash + amount_proxy # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("manhours", "", firm.identifier, firm.identifier, amount_proxy, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # Add cash for sold items to the household cash_number = 0 # We calculate how many cash account the household has for tranx in household.accounts: if tranx.type_ == "cash": cash_number = cash_number + 1 # If there are no cash transactions on the household's books # We create a new one and put the proceeds there if cash_number == 0: # Create a transaction transaction = Transaction() # Add the appropriate values to the transaction transaction.this_transaction("cash", "", household.identifier, household.identifier, household_cash, 0, 0, -1) # And add the transaction to the books (do it through function/not manually) transaction.add_transaction(environment) # If the household has previous cash transactions we add the cash from sales proportionately else: # We find all cash transactions for tranx in household.accounts: if tranx.type_ == "cash": # And add the sales proceeds proportionately tranx.amount = tranx.amount + (household_cash / cash_number) # The sales above may have rendered some transactions worthless # So we need to purge all accounts to make sure everything is in order transaction = Transaction() transaction.purge_accounts(environment) logging.info(" labour sold to firms on step: %s", time)
def transfer_investments(self, state): currentVolume = 0.0 optimalVolume = 0.0 plannedVolume = 0.0 availableVolume = 0.0 transactionVolume = 0.0 transaction = Transaction() # calculate the optimal investment volume and compare to current volume self.calculate_optimal_investment_volume(state) optimalVolume = round(float(self.gamma * self.lamb * self.V), 4) currentVolume = round(self.get_account("I"), 4) # add new transactions of average size plannedVolume = optimalVolume - currentVolume availableVolume = self.lamb * self.Q # we can only spend a fraction of the available Q transactionVolume = min(plannedVolume, availableVolume) while (transactionVolume >= self.averageTransactionSize) and (self.averageTransactionSize > 0.0): transactionVolume = round(transactionVolume - self.averageTransactionSize, 5) # reduce remaining transactionVolume self.Q = self.Q - self.averageTransactionSize # reduce available liquidity # account for different maturities of investments maturity = int(round(random.random() * state.firmLoanMaturity, 1)) # this is done very roughly and implies loans are up to 3 years # and determine whether the loan will default if random.random() >= state.successProbabilityFirms: # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random() * maturity)) else: timeOfDefault = -1 # and add transaction to the stack transaction = Transaction() transaction.this_transaction("I", self.identifier, -2, self.averageTransactionSize, self.rhoReal, maturity, timeOfDefault) self.accounts.append(transaction) del transaction transactionVolume = round(transactionVolume, 5) # finally, add the remaining transaction to the stack if the transactionVolume was positive in the first place if transactionVolume > 0.0: self.Q = round(self.Q - transactionVolume, 4) # account for different maturities of investments maturity = int(round(random.random() * state.firmLoanMaturity, 1)) # this is done very roughly and implies loans are up to 3 years # and determine whether the loan will default if random.random() >= state.successProbabilityFirms: # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random() * maturity)) else: timeOfDefault = -1 transaction = Transaction() transaction.this_transaction("I", self.identifier, -2, transactionVolume, self.rhoReal, maturity, timeOfDefault) self.accounts.append(transaction) del transaction
def initialize_transactions(self, state): value = 0.0 # first, calculate number of transactions for investments numTransactions = int(round(self.assetNumber / self.numBanks)) # print(numTransactions) if numTransactions == 0: # we want some error message if there are two few assets in the economy logging.info(" ERROR: number of assets in the economy has to be at least half the number of banks") # now, calculate value of each transaction and note that the *product* of all individual transactions # is supposed to have precision 4. Hence, each individual transaction should have precision 5 value = round(float(self.gamma * self.lamb * self.V / numTransactions), 5) # finally, put them on the transaction stack for i in range(numTransactions): transaction = Transaction() # # account for different maturities # maturity = int( round(random.random() * state.firmLoanMaturity, 1)) # maturity is between 0 and firmLoanMaturity # and determine whether the loan will default if ( random.random() >= state.successProbabilityFirms): # TODO this is superfluous, we could get rid of this doubling # the loan defaults: determine timeOfDefault timeOfDefault = int(round(random.random() * maturity)) else: timeOfDefault = -1 # then, generate the transaction, append it to the accounts, and delete it from memory transaction.this_transaction("I", self.identifier, -2, value, self.rhoReal, maturity, timeOfDefault) self.accounts.append(transaction) del transaction # store averageTransactionSize self.averageTransactionSize = value # then, calculate excess reserves value = round(float(self.gamma * (1.0 - self.lamb) * self.V), 4) transaction = Transaction() transaction.this_transaction("E", self.identifier, -3, value, self.rb, 0, -1) self.accounts.append(transaction) del transaction # on the liabilities side, banks are endowed with banking capital # (see comments in get_initial_banking_capital() for further details) value = round(float(self.get_initial_banking_capital(state.requiredCapitalRatio)), 4) transaction = Transaction() transaction.this_transaction("BC", self.identifier, self.identifier, value, 0.0, 0, -1) self.accounts.append(transaction) del transaction # now, transfer deposits from households to banks value = round(float(self.gamma * self.V - self.get_account("BC")), 4) transaction = Transaction() transaction.this_transaction("D", -1, self.identifier, value, self.rd, 0, -1) self.accounts.append(transaction) del transaction # as well as required deposits to the central bank value = round(float(self.r * self.get_account("D")), 4) transaction = Transaction() transaction.this_transaction("rD", self.identifier, -3, value, self.rb, 0, -1) self.accounts.append(transaction) del transaction # finally, determine central bank loans value = round(float(self.get_account("I") + self.get_account("E") + self.get_account("rD") - self.get_account( "D") - self.get_account("BC")), 4) transaction = Transaction() transaction.this_transaction("LC", self.identifier, -3, value, self.rb, 0, -1) print(transaction.print_transaction()) self.accounts.append(transaction) del transaction
def add_transaction(self, type_, fromID, toID, value, interest, maturity, timeOfDefault): transaction = Transaction() transaction.this_transaction(type_, fromID, toID, value, interest, maturity, timeOfDefault) self.accounts.append(transaction) del transaction