Eleonora Priori, Jack Birner, Marco Mazzoli, and Pietro Terna
Report on the development of an ABM stock-flow consistent model, a framework capable of handling micro-founded macro research questions.
Comments welcome. Please do not quote.
Design and development of the model by Eleonora Priori and Pietro Terna.
Last updated: July 18, 2022
%%javascript
// to avoid scroll in windows
IPython.OutputArea.prototype._should_scroll = function(lines) {
return false;
}
%matplotlib inline
import random as r
import matplotlib.pyplot as plt
import commonVar as cmv
import numpy as np
from tools import *
from metaActions import *
from generateSeeds import *
from plot import *
from initSeries import *
import sys
We observe both the real and monetary sides of the economy.
We consider loans and deposits, with their interests.
Enterprises have initial endowments.
When agents abstein from consuming, their savings increase liquidity.
Investments are uniquely for replacement, without technical progress.
We use specific random sequences for both each agent and each function.
symbol table in $\LaTeX$
$a_i$ - with $a_i \in \mathbf{A}$; agent number $N=|\mathbf{A}|$, agentList
andagentNum
$a^e_i$ - with $a^e_i \in \mathbf{A^e}$ and $\mathbf{A^e} \subset \mathbf{A}$; employer number $N^e=|\mathbf{A^e}|$ in range $[N^e_{min},N^e_{max}]$, employerList
$\mathbf{F}$ - firms' set, with $f_j \in \mathbf{F}$ being $N^f = |\mathbf{F}|$, with $N^f = |\mathbf{F}| = |\mathbf{A^e}|$ , firmList
$\mathbf{A}^w$ - working agents' set, being $\mathbf{A}^w \subseteq \mathbf{A}$, with $N^w_{i,t}=|\mathbf{A}^w_i|$ number of working agents employed by employer $i$ at time $t$, also including self-employed employers, with $a_i \in \mathbf{A}^e$
$\mathbf{B}$ - banks' set, with $b_j \in \mathbf{B}$ being $N^b = |\mathbf{B}|$, bankList
$x^d$ - interest rate on deposits, interestRateOnDeposits
$x^{l^a}$ - interest rate on loans to (private) agents, interestRateOnLoansVsAgents
$x^{l^f}$ - interest rate on loans to firms, interestRateOnLoansVsFirms
$X^d_{a|f,b}$ - amount of positive interests on deposits for a given interval $t$ for agents ($a$) or firms ($f$), and negative for banks ($b$), interestOnDeposits
$X^l_{a|f,b}$ - amount of negative interests on loans for a given interval $t$ for agents ($a$) or firms ($f$), and positive for banks ($b$), interestOnLoans
$p$ - price price
$u$ - unemployment rate unemploymentRate
$dimensional~heterogeneity$ is a $true/false$ chooser, forcing increasing firms to attract more workers. dimensionalHeterogeneity
$\pi_{i,t}$ - labor productivity, a uniformly distributed decimal number in range $[\pi_{min},\pi_{max}]$,productivity
$\Delta\pi_{i,t}$ - uniperiodal additive productivity correction in range $[\Delta\pi_{min},\Delta\pi_{max}]$, productivityDelta
$q_{i,t}$ - production in quantity, production
$\Pi_{i,t}$ - profit, profit
$\rho$ - profit distribution share, rho
$\delta_{i,t}$ - dividend $\rho\Pi_{i,t}$, dividend
or perceivedDividend
$W$ - wage wage
$R_{i,t}$ - revenues, revenues
, including both sales revenues, salesRevenues
, and active interests
$s_{i,t}$ - sales in quantity, sales
$v_{i,t}$ - inventories (final, initial), initialInventories
, finalInventories
$d_{i}$ - deperibility share of the production, deperibilityShare
, setting $d_{max}$
$c_{i,t}$ - consumption rate, a uniformly distributed decimal number in range $[c_{min},c_{max}]$,consumptionRate
$C_{i,t}$ - consumption of $i$ in $t$
$I_{i,t}$ - investment plan of $i$ in $t$, a uniformly distributed realization in range $[I_{min},I_{max}]$,investmentProgram
$\lambda$ -parameter limiting the investment plan, in $I_{i,t} \le \lambda\Pi_{i,t-1}$ , Lambda
$H_{i,t}$ - high powered money (cash) held by individuals (also acting as employers), cashMoney
$Q_{i,t}$ - checking account money deposits held by $a_i$ at time $t$, eventually also negative checkingAccount
$Q^f_{i,t}$ - firm's bank account (with positive or negative balance), bankAccount
$Q^b_{i,t}$ - bank's account (with positive or negative balance) mantained with the central bank, centralBankAccount
$Q^T_{i,t}$ - bank treasury account at central bank, bankTreasuryAccountAtCentralBank
$\alpha$ - parameter determining the mean of the random normal distribution of the initial endowments of both firms and banks as $\alpha N^w_i$, being $i$ a firm or a bank, alphaF
or alphaB
$\beta$ - parameter determining the standard deviation $\sigma$ of the random normal distribution of the initial endowments of both firms and banks, with $\sigma=\frac{\alpha}{\beta}N^w_i$, being $i$ a firm or a bank, beta
the investment and consumption actions are repeated in each cycle, looking around randomly for the sellers; currently nOfConsumptionActions
$=30$ and nOfInvestmentActions
$=10$; each consumption buy action is at maximum the 20% of the planned consumptions in that cycle; instead, each investment buy action can reach the whole amount of the investment program of the cycle; each buy action is limited by the residual capabilty of the seller
magically, the same good can be a consumption item or an investment one
$T$ - number of cycles ncycles
$t$ - current cycle cycle
The structure of an agent: it can represent an entrepreneur, a worker, an unemployed person.
When an agent is created, the initialization process defines:
num
entrepreneur
, set to $false$myEmployer
, set to $0$myFirm
, set to $0$revenues
, initial value $0$sales
, initial value $0$initialInventories
, set to $0$finalInventories
, set to $0$deperibilityShare
production
. production with $t>0$revenues
, initial value $0$each agent has the function:
buyConsumptionGoods
$C_{i,t}=c_{i,t} (W+D_{i,t-1}+X^d_{i,t-1}-X^l_{i,t-1})$; using $D_{i,t-1},X^d_{i,t-1},X^l_{i,t-1}$ we introduce lags with (possible) cyclical effect
being $bu$ the buyer and $se$ the seller (firm), for each fraction $C_{i,t}/k$
($k$ is the number of buying actions in each cycle with random share [0,maxConsumptionShareInSubstep
))
$\Delta Q^f_{se,t}=C_{bu,t}/k$
$\Delta Q_{bu,t}=-C_{bu,t}/k$
each firm has the functions:
produce function (production in quantity), with:
$\pi_{i,t}=\pi_{i,t-1}+\Delta\pi_{i,t}$
$q_{i,t}=N^w_{i,t} \pi_{i,t}$
payWages
paying $W$ to each worker in each time $t$
$\Delta Q_{i,t}=W$ for $a_i \in \mathbf{A}^w$
$\Delta Q^f_{i,t}=-W \mathbf{N}^w_i$ for $a_i \in \mathbf{A}^e$
buyInvestmentGoods
$I_{j,t}$ for $f_j \in \mathbf{F}$ ($I_{j,t}$ is exogenously set), , with $I_{i,t} \le \lambda\Pi_{i,t-1}$, being $\lambda\Pi_{i,t-1}$ a proxy of investment sustainability, introducing a lag with (possible) cyclical effect
being $bu$ the buyer (firm) and $se$ the seller (firm), for each fraction $I_{j,t}/k$
($k$ is the number of investment actions in each cycle, with random share [0,maxInvestmentShareInSubstep
))
$\Delta Q^f_{se,t}=I_{bu,t}/k$
$\Delta Q^f_{bu,t}=-I_{bu,t}/k$
makeBalanceSheet
$v^f_{i,t}=v^i_{i,t}+(q_{i,t}-s_{i,t}) (1 - d_{i})$
$R_{i,t}=p s_{i,t}+X^d_{i,t}$
$\Pi_{i,t}=R_{i,t}-W N^w_{i,t}-X^l_{i,t}+p(v^f_{i,t}-v^i_{i,t})$
reordering, we have:
$\underbrace{\Pi_{i,t}+W N^w_{i,t}+X^l_{i,t}}_{\textrm{direct added value}}=\underbrace{R_{i,t}+p(v^f_{i,t}-v^i_{i,t})}_{\textrm{indirect added value (*)}}$
(*) the cost of bought-in materials and components is missing by construction in this version of the model
distributeDividend
$\delta_{i,t}=\rho\Pi_{i,t}$
$\Delta Q_{i,t}=\delta_{i,t}$
$\Delta Q^f_{i,t}=-\delta_{i,t}$
each bank has the functions:
produce function (production of bank services in quantity), analogously with the firm one
payWages
paying $W$ to each worker in each time $t$
$\Delta Q_{i,t}=W$ for $a_i \in \mathbf{A}^w$
$\Delta Q^f_{i,t}=-W \mathbf{N}^w_i$ for $a_i \in \mathbf{A}^e$
buyInvestmentGoods
$I_{j,t}$ for $f_j \in \mathbf{F}$ ($I_{j,t}$ is exogenously set), , with $I_{i,t} \le \lambda\Pi_{i,t-1}$, being $\lambda\Pi_{i,t-1}$ a proxy of investment sustainability, introducing a lag with (possible) cyclical effect
being $bu$ the buyer (firm) and $se$ the seller (firm), for each fraction $I_{j,t}/k$
($k$ is the number of investment actions in each cycle, with random share [0,maxInvestmentShareInSubstep
))
$\Delta Q^f_{se,t}=I_{bu,t}/k$
$\Delta Q^b_{bu,t}=-I_{bu,t}/k$
distributeDividend
$\delta_{i,t}=\rho\Pi_{i,t}$
$\Delta Q_{i,t}=\delta_{i,t}$
$\Delta Q^b_{i,t}=-\delta_{i,t}$
makeBalanceSheet, with:
being $d_{i}=1$ we have $v^f_{i,t}=v^i_{i,t}=0$
$R_{i,t}=p s_{i,t}+\sum_{a_i}X^l_{i,t}+\sum_{f_i}X^l_{i,t}$
$\Pi_{i,t}=R_{i,t}-W N^w_{i,t}-\sum_{a_i}X^d_{i,t}-\sum_{f_i}X^d_{i,t}$
reordering, we have:
$\underbrace{\Pi_{i,t}+W N^w_{i,t}+\sum_{a_i}X^d_{i,t}}_{\textrm{direct added value}}=\underbrace{R_{i,t}-\sum_{f_i}X^d_{i,t}}_{\textrm{indirect added value (*)}}$
(*) the cost of bought-in materials and components is missing by construction in this version of the model, excepted the interests on deposits paid to firms
Every time we observe a transaction between an agent (or a firm) and its bank, we record the corresponding financial flow on the checking account (or bank account) of the agent (or firm) and on that mantained by the bank with the central bank
debitingCheckingAccount with $\mathcal{L}$ measuring the part which is a loan, if any
For the amount $\mathcal{M} > 0$, debiting the account of agent $i$ at bank $j$
$\Delta Q_i=-\mathcal{M}$
With $\mathcal{L}=\begin{cases}
0,& \text{if } Q_{i,t-1} \geq 0 \land \mathcal{M} \leq Q_{i,t-1}\ \mathcal{M}- Q_{i,t-1},& \text{if } Q_{i,t-1} \geq 0 \land \mathcal{M} \gt Q_{i,t-1}\ \mathcal{M}, & \text{if } Q_{i,t-1} \lt 0 \end{cases}$
modifying the correspondent bank $j$ deposit at the central bank
$\Delta Q^b_j=-\mathcal{M} + \mathcal{L}$
The account $Q_i$ can be positive or negative (in case, also accounted into the loans).
debitingBankAccount with $\mathcal{L}$ measuring the part which is a loan, if any
For the amount $\mathcal{M}$, debiting the account of firm $i$ at bank $j$
$\Delta Q^f_i=-\mathcal{M}$
With $\mathcal{L}=\begin{cases}
0,& \text{if } Q^f_{i,t-1} \geq 0 \land \mathcal{M} \leq Q^f_{i,t-1}\ \mathcal{M}- Q^f_{i,t-1},& \text{if } Q^f_{i,t-1} \geq 0 \land \mathcal{M} \gt Q^f_{i,t-1}\ \mathcal{M}, & \text{if } Q^f_{i,t-1} \lt 0 \end{cases}$
modifying the correspondent bank $j$ deposit at the central bank
$\Delta Q^b_j=-\mathcal{M} + \mathcal{L}$
The account $Q^f_i$ can be positive or negative (in case, also accounted into the loans).
bankDebitingCentralBankAccount
For the amount $\mathcal{M}$, debiting the account of bank $j$ at the central bank
$\Delta Q^b_j=-\mathcal{M}$
being the amount $\mathcal{M}$ a payment on charge of the bank, considering also the specific treasury account of bank $j$
$\Delta Q^T_j=-\mathcal{M}$
The account $Q^b_j$ can be positive or negative (in case, also accounted into the loans of the central bank).
creditingCheckingAccount with $\mathcal{L}$ measuring the part which is a loan reinbursement, if any
For the amount $\mathcal{M} > 0$, crediting the account of agent $i$ at bank $j$
$\Delta Q_i=\mathcal{M}$
With $\mathcal{L}=\begin{cases}
\mathcal{M},& \text{if } Q_{i,t-1} \leq 0 \land \mathcal{M} \leq |Q_{i,t-1}|\ |Q_{i,t-1}|,& \text{if } Q_{i,t-1} \leq 0 \land \mathcal{M} \gt |Q_{i,t-1}|\ 0, & \text{if } Q_{i,t-1} \gt 0 \end{cases}$
modifying the correspondent bank $j$ deposit at the central bank
$\Delta Q^b_j=\mathcal{M} - \mathcal{L}$
The account $Q_i$ can be positive or negative (in case, also accounted into the loans).
creditingBankAccount with $\mathcal{L}$ measuring the part which is a loan reinbursement, if any
For the amount $\mathcal{M}$, crediting the account of firm $i$ at bank $j$
$\Delta Q^f_i=-\mathcal{M}$
With $\mathcal{L}=\begin{cases}
\mathcal{M},& \text{if } Q^f_{i,t-1} \leq 0 \land \mathcal{M} \leq |Q^f_{i,t-1}|\ |Q^f_{i,t-1}|,& \text{if } Q^f_{i,t-1} \leq 0 \land \mathcal{M} \gt |Q^f_{i,t-1}|\ 0, & \text{if } Q^f_{i,t-1} \gt 0 \end{cases}$
modifying the correspondent bank $j$ deposit at the central bank
$\Delta Q^b_j=\mathcal{M} - \mathcal{L}$
The account $Q^f_i$ can be positive or negative (in case, also accounted into the loans).
bankCreditingCentralBankAccount
For the amount $\mathcal{M}$, crediting the account of bank $j$ at the central bank
$\Delta Q^b_j=\mathcal{M}$
being the amount $\mathcal{M}$ a payment on charge of the bank, considering also the specific treasury account of bank $j$
$\Delta Q^T_j=\mathcal{M}$
The account $Q^b_j$ can be positive or negative (in case, also accounted into the loans of the central bank).
computeAndApplyInterests
interests on Loans to Firms (firm $i$ and bank $j$)
we use $Q^f_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^l_{i,j}= Q^f_{i,t} x^{l^f}$
$\Delta Q^f_{i,t}=-X^l_{i,j}$
$\Delta Q^b_j = X^l_{i,j}$
$\Delta Q^T_j = X^l_{i,j}$
interests on Loans to Agents (agent $i$ and bank $j$)
we use $Q^a_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^l_{i,j}= Q^a_{i,t} x^{l^a}$
$\Delta Q^a_{i,t}=-X^l_{i,j}$
$\Delta Q^b_j = X^l_{i,j}$
$\Delta Q^T_j = X^l_{i,j}$
interests on Deposits by Firms (firm $i$ and bank $j$)
we use $Q^f_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^d_{i,j}= Q^f_{i,t} x^{d^f}$
$\Delta Q^f_{i,t}=X^d_{i,j}$
$\Delta Q^b_j = -X^d_{i,j}$
$\Delta Q^T_j = -X^d_{i,j}$
interests on Deposits by Agents (agent $i$ and bank $j$)
we use $Q^a_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^d_{i,j}= Q^a_{i,t} x^{d^a}$
$\Delta Q^a_{i,t}=X^d_{i,j}$
$\Delta Q^b_j = -X^d_{i,j}$
$\Delta Q^T_j = -X^d_{i,j}$
computeAndApplyInterests
interests on Loans to Firms (firm $i$ and bank $j$)
we use $Q^f_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^l_{i,j}= Q^f_{i,t} x^{l^f}$
$\Delta Q^f_{i,t}=-X^l_{i,j}$
$\Delta Q^b_j = X^l_{i,j}$
$\Delta Q^T_j = X^l_{i,j}$
interests on Loans to Agents (agent $i$ and bank $j$)
we use $Q^a_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^l_{i,j}= Q^a_{i,t} x^{l^a}$
$\Delta Q^a_{i,t}=-X^l_{i,j}$
$\Delta Q^b_j = X^l_{i,j}$
$\Delta Q^T_j = X^l_{i,j}$
interests on Deposits by Firms (firm $i$ and bank $j$)
we use $Q^f_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^d_{i,j}= Q^f_{i,t} x^{d^f}$
$\Delta Q^f_{i,t}=X^d_{i,j}$
$\Delta Q^b_j = -X^d_{i,j}$
$\Delta Q^T_j = -X^d_{i,j}$
interests on Deposits by Agents (agent $i$ and bank $j$)
we use $Q^a_{i,t}$, final balance of the interval, as if it had been constant throughout the period
$X^d_{i,j}= Q^a_{i,t} x^{d^a}$
$\Delta Q^a_{i,t}=X^d_{i,j}$
$\Delta Q^b_j = -X^d_{i,j}$
$\Delta Q^T_j = -X^d_{i,j}$
class Agent():
def __init__(self, num,r,seed):
self.num=num
self.entrepreneur=False
#self.myFirm=0
self.myEnterprise=0
self.myEmployer=0
self.consumptionRate=0
self.cashMoney=0
self.checkingAccountTminus1=0
self.checkingAccount=0
self.perceivedWage=0
self.perceivedDividend=0
self.myBank=0
self.interestOnDeposits=0
self.interestOnLoans=0
self.r=r.Random()
self.r.seed(seed)
self.myFirmBankList=[]
def copyCheckingAccountBalance(self):
self.checkingAccountTminus1=self.checkingAccount
def buyConsumptionGoods(self,k):
if k==0:
self.consumptionRate=self.r.uniform(cmv.consumptionRateMin,cmv.consumptionRateMax)
self.consumption=(self.perceivedWage+self.perceivedDividend+\
self.interestOnDeposits-self.interestOnLoans)*self.consumptionRate
if self.consumption < 0: self.consumption=0
self.interestOnDeposits=0
self.interestOnLoans=0
self.perceivedWage=0
self.perceivedDividend=0
self.madeConsumption=0
if self.myFirmBankList==[]: self.myFirmBankList=cmv.firmList+cmv.bankList
self.r.shuffle(self.myFirmBankList)
mySeller=self.myFirmBankList[0]
self.purchase=self.r.uniform(0,cmv.maxConsumptionShareInSubstep)*self.consumption
# mean value should be calibrated with thenumber of buy action
self.purchase=min(self.purchase,self.consumption-self.madeConsumption)
self.purchase=min(self.purchase,cmv.price*(mySeller.production+\
mySeller.initialInventories-mySeller.sales))
if self.purchase > 0:
mySeller.sales+=self.purchase/cmv.price
if mySeller.__class__.__name__=="Firm": mySeller.myBank.creditingBankAccount(mySeller,self.purchase)
if mySeller.__class__.__name__=="Bank": \
mySeller.bankCreditingCentralBankAccount(self.purchase) #mySeller is a bank
self.myBank.debitingCheckingAccount(self,self.purchase)
self.madeConsumption+=self.purchase
class Firm():
def __init__(self, num, r,seed):
self.num=num
self.myWorkers=[]
self.myEntrepreneur=0
self.productivity=0
self.initialInventories=0
self.finalInventories=0
self.bankAccount=0
self.bankAccountTminus1=0
self.salesRevenues=0 #sales*price
self.revenues=0
self.sales=0
self.deperibilityShare=r.uniform(0,cmv.maxDeperibilityShare)
self.investmentProgram=0
self.profit=0
self.madeInvestment=0
self.interestOnDeposits=0
self.interestOnLoans=0
self.addedValue=0
self.myBank=0
self.r=r.Random()
self.r.seed(seed)
def copyBankAccountBalance(self):
self.bankAccountTminus1=self.bankAccount
def produce(self):
# clean interests values while starting this cycle
self.interestOnLoans=0
self.interestOnDeposits=0
self.initialInventories=self.finalInventories
self.productivity+=self.r.uniform(cmv.productivityDeltaMin,cmv.productivityDeltaMax)
self.productivity=max(self.productivity,0)
self.production=len(self.myWorkers)*self.productivity
self.sales=0
def payWages(self):
for anAgent in self.myWorkers:
anAgent.perceivedWage=cmv.wage
anAgent.myBank.creditingCheckingAccount(anAgent,cmv.wage)
#anAgent.checkingAccount+=cmv.wage
#anAgent.myBank.centralBankAccount+=cmv.wage
self.myBank.debitingBankAccount(self,cmv.wage*len(self.myWorkers))
#self.bankAccount-=cmv.wage*len(self.myWorkers)
#self.myBank.centralBankAccount-=cmv.wage*len(self.myWorkers)
def buyInvestmentGoods(self,k):
if k==0:
profitControl=max(0,self.profit)
self.investmentProgram=\
min(r.uniform(cmv.investmentMin,cmv.investmentMax),cmv.Lambda*profitControl)
self.madeInvestment=0
self.r.shuffle(cmv.firmList)
mySeller=cmv.firmList[0]
self.myInvestment=self.r.uniform(0,cmv.maxInvestmentShareInSubstep)*self.investmentProgram
self.myInvestment=min(self.myInvestment,cmv.price*(mySeller.production+\
mySeller.initialInventories-mySeller.sales))
if self.myInvestment > 0:
mySeller.sales+=self.myInvestment/cmv.price
mySeller.myBank.creditingBankAccount(mySeller,self.myInvestment)
self.myBank.debitingBankAccount(self,self.myInvestment)
self.investmentProgram-=self.myInvestment
self.madeInvestment+=self.myInvestment
def makeBalanceSheet(self):
self.lostProduction=0
if self.production - self.sales > 0:
self.lostProduction=(self.production - self.sales)*self.deperibilityShare
#print(self.num, lostProduction,self.productivity)
self.finalInventories=self.initialInventories+self.production-\
self.sales-self.lostProduction
self.salesRevenues=self.sales*cmv.price
self.revenues=self.salesRevenues+self.interestOnDeposits
self.profit=self.revenues - len(self.myWorkers)*cmv.wage\
- self.interestOnLoans + \
(self.finalInventories-self.initialInventories)*cmv.price
self.addedValue=self.profit+self.interestOnLoans+len(self.myWorkers)*cmv.wage
def distributeDividend(self):
if self.profit > 0:
dividend=cmv.rho*self.profit
self.myEntrepreneur.perceivedDividend=dividend
self.myEntrepreneur.myBank.creditingCheckingAccount(self.myEntrepreneur,dividend)
self.myBank.debitingBankAccount(self,dividend)
class Bank(Firm):
def __init__(self, num, r,seed):
super().__init__(num,r,seed)
self.myPrivateClients=[]
self.myCommercialClients=[]
self.myDebtsVsAgents=0
self.myDebtsVsFirms=0
self.myCreditsVsAgents=0
self.myCreditsVsFirms=0
self.centralBankAccountTminus1=0
self.centralBankAccount=0
self.bankTreasuryAccountAtCentralBankTminus1=0
self.bankTreasuryAccountAtCentralBank=0
# attribute deletions
del self.bankAccount
del self.bankAccountTminus1
del self.myBank
self.myPrivateClientsTotalInterestOnDeposits=0
self.myPrivateClientsTotalInterestOnLoans=0
self.myCommercialClientsTotalInterestOnDeposits=0
self.myCommercialClientsTotalInterestOnLoans=0
self.r=r.Random()
self.r.seed(seed)
def copyAccountsAtCentralBank(self):
self.centralBankAccountTminus1=self.centralBankAccount
self.bankTreasuryAccountAtCentralBankTminus1=self.bankTreasuryAccountAtCentralBank
def debitingCheckingAccount(self,aClient,amount): # agents' accounts
if aClient.checkingAccount >= 0 and amount <= aClient.checkingAccount: L = 0
if aClient.checkingAccount >= 0 and amount > aClient.checkingAccount: L = amount - aClient.checkingAccount
if aClient.checkingAccount < 0: L = amount
aClient.checkingAccount-=amount
self.centralBankAccount+=-amount + L # look at central bank operation in debiting checking account formulas
def debitingBankAccount(self,aClient,amount): # firms' accounts
if aClient.bankAccount >= 0 and amount <= aClient.bankAccount: L = 0
if aClient.bankAccount >= 0 and amount > aClient.bankAccount: L = amount - aClient.bankAccount
if aClient.bankAccount < 0: L = amount
aClient.bankAccount-=amount
self.centralBankAccount+=-amount + L # look at central bank operation in debiting bank account formulas
def bankDebitingCentralBankAccount(self,amount):
self.centralBankAccount-=amount
self.bankTreasuryAccountAtCentralBank-=amount
def creditingCheckingAccount(self,aClient,amount): # agents' accounts
if aClient.checkingAccount <= 0 and amount <= abs(aClient.checkingAccount): L = amount
if aClient.checkingAccount <= 0 and amount > abs(aClient.checkingAccount): L = abs(aClient.checkingAccount)
if aClient.checkingAccount > 0: L = 0
aClient.checkingAccount+=amount
self.centralBankAccount+=amount - L # look at central bank operation in crediting checking account formulas
def creditingBankAccount(self,aClient,amount): # firms' accounts
if aClient.bankAccount <= 0 and amount <= abs(aClient.bankAccount): L = amount
if aClient.bankAccount <= 0 and amount > abs(aClient.bankAccount): L = abs(aClient.bankAccount)
if aClient.bankAccount > 0: L = 0
aClient.bankAccount+=amount
self.centralBankAccount+=amount - L # look at central bank operation in crediting bank account formulas
def bankCreditingCentralBankAccount(self,amount):
self.centralBankAccount+=amount
self.bankTreasuryAccountAtCentralBank+=amount
def payWages(self):
for anAgent in self.myWorkers:
anAgent.perceivedWage=cmv.wage
anAgent.myBank.creditingCheckingAccount(anAgent,cmv.wage)
self.bankDebitingCentralBankAccount(cmv.wage*len(self.myWorkers))
def buyInvestmentGoods(self,k):
if k==0:
profitControl=max(0,self.profit)
self.investmentProgram=\
min(r.uniform(cmv.investmentMin,cmv.investmentMax),cmv.Lambda*profitControl)
self.madeInvestment=0
self.r.shuffle(cmv.firmList)
mySeller=cmv.firmList[0]
self.myInvestment=self.r.uniform(0,cmv.maxInvestmentShareInSubstep)*self.investmentProgram
self.myInvestment=min(self.myInvestment,cmv.price*(mySeller.production+\
mySeller.initialInventories-mySeller.sales))
if self.myInvestment > 0:
mySeller.sales+=self.myInvestment/cmv.price
mySeller.myBank.creditingBankAccount(mySeller,self.myInvestment)
self.bankDebitingCentralBankAccount(self.myInvestment)
self.investmentProgram-=self.myInvestment
self.madeInvestment+=self.myInvestment
def makeBalanceSheet(self):
self.lostProduction=0
#if self.production - self.sales > 0:
# self.lostProduction=self.production - self.sales
self.finalInventories=0
self.salesRevenues=self.sales*cmv.price
self.revenues=self.salesRevenues + self.myPrivateClientsTotalInterestOnLoans\
+ self.myCommercialClientsTotalInterestOnLoans
self.profit=self.revenues - len(self.myWorkers)*cmv.wage\
- self.myPrivateClientsTotalInterestOnDeposits - self.myCommercialClientsTotalInterestOnDeposits
self.addedValue=self.profit+len(self.myWorkers)*cmv.wage\
- self.myPrivateClientsTotalInterestOnLoans - self.myCommercialClientsTotalInterestOnLoans \
+ self.myPrivateClientsTotalInterestOnDeposits
def distributeDividend(self):
if self.profit > 0:
dividend=cmv.rho*self.profit
self.myEntrepreneur.perceivedDividend=dividend
self.myEntrepreneur.myBank.creditingCheckingAccount(self.myEntrepreneur,dividend)
self.bankDebitingCentralBankAccount(dividend)
def computeAndApplyInterests(self):
#interest are always calculate as positive values, then we add or subctract them
#to and from the accounts and we add them to revenues or costs
for aPrivateClient in self.myPrivateClients:
if aPrivateClient.checkingAccount >=0: #interests on Deposits by Agents
interests=aPrivateClient.checkingAccount*cmv.interestRateOnDeposits
aPrivateClient.checkingAccount+=interests
aPrivateClient.interestOnDeposits=interests
self.bankCreditingCentralBankAccount(interests)
else: #aPrivateClient.checkingAccount < 0 #interests on Loans to Agents
interests=abs(aPrivateClient.checkingAccount*cmv.interestRateOnLoansVsAgents)
aPrivateClient.checkingAccount-=interests
aPrivateClient.interestOnLoans=interests
self.bankDebitingCentralBankAccount(interests)
for aCommercialClient in self.myCommercialClients:
if aCommercialClient.bankAccount >=0: #interests on Deposits by Firms
interests=aCommercialClient.bankAccount*cmv.interestRateOnDeposits
aCommercialClient.bankAccount+=interests
aCommercialClient.interestOnDeposits=interests
self.bankDebitingCentralBankAccount(interests)
else: #aCommercialClient.bankAccount < 0 #interests on Loans to Firms
interests=abs(aCommercialClient.bankAccount*cmv.interestRateOnLoansVsFirms)
aCommercialClient.bankAccount-=interests
aCommercialClient.interestOnLoans=interests
self.bankCreditingCentralBankAccount(interests)
self.myPrivateClientsTotalInterestOnDeposits=\
sum(list(self.myPrivateClients[i].interestOnDeposits for i \
in range(len(self.myPrivateClients))))
self.myPrivateClientsTotalInterestOnLoans=\
sum(list(self.myPrivateClients[i].interestOnLoans for i \
in range(len(self.myPrivateClients))))
self.myCommercialClientsTotalInterestOnDeposits=\
sum(list(self.myCommercialClients[i].interestOnDeposits for i \
in range(len(self.myCommercialClients))))
self.myCommercialClientsTotalInterestOnLoans=\
sum(list(self.myCommercialClients[i].interestOnLoans for i \
in range(len(self.myCommercialClients))))
def makeFinancialAccounts(self):
self.myDebtsVsAgents=0
self.myDebtsVsFirms=0
self.myCreditsVsAgents=0
self.myCreditsVsFirms=0
for aPrivateClient in self.myPrivateClients:
if aPrivateClient.checkingAccount>=0: \
self.myDebtsVsAgents+=aPrivateClient.checkingAccount
if aPrivateClient.checkingAccount<0: \
self.myCreditsVsAgents+=abs(aPrivateClient.checkingAccount)
for aCommercialClient in self.myCommercialClients:
if aCommercialClient.bankAccount>=0: \
self.myDebtsVsFirms+=aCommercialClient.bankAccount
if aCommercialClient.bankAccount<0: \
self.myCreditsVsFirms+=abs(aCommercialClient.bankAccount)
agent basic creation
creation of entrepreneur list
selecting entrepreneurs and creating their firms or their banks
with a given (heterogeneous) productivity
linking the firm or the bank to its entrepreneur, considering the entrepreneur itself as a worker in its firm or bank
creation of a temporary workforce list of to-be-employed agent, escluding entrepreneurs (already self employed)
applying the unemployement rate to exclude agents
assigning workforce (to-be-employed agents) to firms or banks, with a reinforcement mechanism, gradually giving more attraction/hiring capability to firms or banks growing the most
assigning agents and firms to banks in a random way
endowments provided to the enterprises are proportional to the initial workforce, being extracted from a random-normal distribution with $\mu=\alpha N^w_i$ and $\sigma=\frac{\alpha}{\beta}N^w_i$ (substituting $\alpha$ with $\alpha^f$ for the firms, or with $\alpha^b$ for the banks)
def setup(r,seed):
seedManager(r,seed,'setup',setup)
#print(r.random(),setup.r.random())
cmv.agentList=[]
for n in range(cmv.agentNum):
anAgent=Agent(n+1,r,cmv.agentSeedList[n])
cmv.agentList.append(anAgent)
# creation of: entrepreneur list; firm list; bank list
cmv.entrepreneurNum=setup.r.randint(cmv.entrepreneurMin, cmv.entrepreneurMax)
cmv.bankNum=setup.r.randint(cmv.bankMin, cmv.bankMax)
cmv.entrepreneurList=[]
cmv.firmList=[]
cmv.bankList=[]
entrepreneurCandidates=cmv.agentList.copy()
for n in range(cmv.entrepreneurNum):
i=setup.r.randint(0,len(entrepreneurCandidates)-1)
entrepreneurCandidates[i].entrepreneur=True
if len(cmv.bankList) < cmv.bankNum:
newEnterprise=Bank(entrepreneurCandidates[i].num,\
r,cmv.bankSeedList[len(cmv.bankList)])
else:
newEnterprise=Firm(entrepreneurCandidates[i].num,\
r,cmv.firmSeedList[len(cmv.firmList)])
entrepreneurCandidates[i].myEnterprise=newEnterprise
entrepreneurCandidates[i].myEmployer=newEnterprise
newEnterprise.myEntrepreneur=entrepreneurCandidates[i]
newEnterprise.myWorkers.append(entrepreneurCandidates[i])
newEnterprise.productivity=\
setup.r.uniform(cmv.productivityMin,cmv.productivityMax)
cmv.entrepreneurList.append(entrepreneurCandidates.pop(i))
if newEnterprise.__class__.__name__=="Bank": cmv.bankList.append(newEnterprise)
if newEnterprise.__class__.__name__=="Firm": cmv.firmList.append(newEnterprise)
cmv.firmNum=len(cmv.firmList)
# creation of workforce list
toBeEmployed=[]
for anAgent in cmv.agentList:
if not anAgent.entrepreneur: toBeEmployed.append(anAgent)
for k in range(round(cmv.unemploymentRate*cmv.agentNum)):
toBeEmployed.pop(setup.r.randint(0,len(toBeEmployed)))
#len(toBeEmployed)
# assigning workforce to firms and banks
tmpEnterpriseListWithDuplications=cmv.firmList+cmv.bankList
for anAgent in toBeEmployed:
choice=setup.r.choice(tmpEnterpriseListWithDuplications)
anAgent.myEmployer=choice
choice.myWorkers.append(anAgent)
if cmv.dimensionalHeterogeneity: tmpEnterpriseListWithDuplications.append(choice)
# assigning agents to firms and banks
if len(cmv.bankList)>0:
for anAgent in cmv.agentList:
anAgent.myBank=setup.r.choice(cmv.bankList)
anAgent.myBank.myPrivateClients.append(anAgent)
for aFirm in cmv.firmList:
aFirm.myBank=setup.r.choice(cmv.bankList)
aFirm.myBank.myCommercialClients.append(aFirm)
# assigning endowments to firms and banks
cmv.totalInitFirmEndowments=0
for aFirm in cmv.firmList:
aFirm.initEn=setup.r.gauss(cmv.alphaF*len(aFirm.myWorkers),\
(cmv.alphaF/cmv.beta)*len(aFirm.myWorkers))
aFirm.myBank.creditingBankAccount(aFirm,aFirm.initEn)
cmv.totalInitFirmEndowments+=aFirm.initEn
cmv.totalInitBankEndowments=0
for aBank in cmv.bankList:
aBank.initEn=setup.r.gauss(cmv.alphaB*len(aBank.myWorkers),\
(cmv.alphaB/cmv.beta)*len(aBank.myWorkers))
aBank.bankCreditingCentralBankAccount(aBank.initEn)
cmv.totalInitBankEndowments+=aBank.initEn
initSeries()
metaActions.py
)¶copyAccounts is only used to keep note of financial account balances of agents, firms, and banks in previous cycle, i.e., $t-1$
produceAll orders to the firms to produce and to collect the results
payWagesAll orders to the firms to pay wages, also to the entrepreneurs
buyConsumptionGoodsAll orders to the agents to buy consumption goods
buyInvestmentGoodsAll orders to the firms to buy investment goods
buyConsumptionOrInvestmentGoodsAll orders to the agents and to the firms to buy consumption or investment goods
makeBalanceSheetAll with firm making accounts
distributeDividendAll attributing the $\rho$ share of firm profits to the entrepreneurs
accountCashMoneyAll summarizing eveyone cash money at the end of a cycle
accountCheckingAccountAll summarizing eveyone checking accounts at the end of a cycle
accountBankingAccountAll summarizing firm banking accounts at the end of a cycle
computeAndApplyInterestsAll calculating the interests on deposits and loans for each agent and firm (and symmetrically for banks) and updatating accounts
makeBankFinancialAccountsAll summmarinzing all the checking and bank accounts
model parameters
¶cmv.agentNum=100
cmv.entrepreneurMin=6
cmv.entrepreneurMax=20
cmv.bankMin=2
cmv.bankMax=3
if cmv.bankMax > cmv.entrepreneurMin:
print ("Bank maximum number cannot exceed the minimum number of firms!")
sys.exit(0)
cmv.price=1
cmv.unemploymentRate=0
cmv.dimensionalHeterogeneity=True
cmv.productivityMin=0.8
cmv.productivityMax=1.2
cmv.productivityDeltaMin=cmv.productivityMin-1
cmv.productivityDeltaMax=cmv.productivityMax-1
cmv.maxDeperibilityShare=0.8
cmv.wage=1
cmv.rho=0.35
cmv.consumptionRateMin=0.7
cmv.consumptionRateMax=1
cmv.investmentMin=1
cmv.investmentMax=15
cmv.Lambda=3
cmv.nOfConsumptionActions=30
cmv.maxConsumptionShareInSubstep=0.3
cmv.nOfInvestmentActions=10
cmv.maxInvestmentShareInSubstep=0.3
cmv.interestRateOnDeposits=0.005
cmv.interestRateOnLoansVsAgents=0.03
cmv.interestRateOnLoansVsFirms=0.08
cmv.alphaF=25
cmv.alphaB=10
cmv.beta=5
cmv.ncycles=100
cmv.cycle=0
Bank maximum number cannot exceed the minimum number of firms!
An exception has occurred, use %tb to see the full traceback. SystemExit: 0
C:\Users\Lenovo\AppData\Local\Packages\PythonSoftwareFoundation.Python.3.10_qbz5n2kfra8p0\LocalCache\local-packages\Python310\site-packages\IPython\core\interactiveshell.py:3348: UserWarning: To exit: use 'exit', 'quit', or Ctrl-D. warn("To exit: use 'exit', 'quit', or Ctrl-D.", stacklevel=1)
model machine
¶a random seed determining the random number sequences
a list of actions (meta ones)
an engine excecuting the meta actions (their code in metaAcions,py
file, in the same folder of the notebook; online, look a the model GitHub
random seed sequence, to have independent each class instance or function using random number, based on generateSeed()
in generateSeeds.py
file, in the same folder of the notebook; online, look a the model GitHub
display tools; their code is hidden into the file tools.py
, in the same folder of the notebook; online, look a the model GitHub
# the seed must be in range -2147483648 to 2147483647
r.seed(12345)
generateSeeds()
setup(r,cmv.functionSeedList[0])
cmv.actionList=["copyAccounts()","produceAll()","payWagesAll()",\
"buyConsumptionOrInvestmentGoodsAll(r,cmv.functionSeedList[3])",\
"computeAndApplyInterestsAll()","makeBalanceSheetAll()",\
"distributeDividendAll()","accountCashMoneyAll()",\
"accountCheckingAccountAll()","accountBankAccountAll()",\
"makeBankFinancialAccountsAll()"\
]
for cmv.cycle in range(cmv.ncycles):
for anAction in cmv.actionList:
exec(anAction)
makeHist()
nationalAccounts()
makePlots()
%run -i test