The BAM Model#

The BAM (Bottom-Up Adaptive Macroeconomics) model is an agent-based macroeconomic model from the CATS (Complex Adaptive Trivial Systems) family, originally described in Macroeconomics from the Bottom-up by Delli Gatti, Gaffeo, Gallegati, Giulioni, and Palestrini (2011), Chapter 3. This page describes the economic rules implemented by BAM Engine: the behavioral equations, market mechanisms, and institutional structures that generate emergent macroeconomic dynamics.

Notation#

The following symbols are used throughout this page:

Symbol

Meaning

BAM Engine parameter / field

\(\varphi\)

Labor productivity (goods per worker)

labor_productivity

\(\theta\)

Employment contract duration (periods)

theta

\(\delta\)

Dividend payout ratio

delta

\(\beta\)

Consumption propensity exponent

beta

\(\nu\)

Bank capital requirement coefficient

v

\(\bar{r}\)

Baseline (policy) interest rate

r_bar

\(h_\rho\)

Production shock half-width

h_rho

\(h_\xi\)

Wage shock half-width

h_xi

\(h_\eta\)

Price shock half-width

h_eta

\(h_\phi\)

Bank cost shock half-width

h_phi

\(M\)

Max job applications per worker per period

max_M

\(H\)

Max loan applications per firm per period

max_H

\(Z\)

Max shops visited per consumer per period

max_Z

\(\hat{w}_t\)

Minimum wage at time \(t\)

Economy.min_wage

\(\bar{P}_t\)

Average market price at time \(t\)

Economy.avg_mkt_price

Subscripts: \(i\) indexes firms, \(j\) indexes households, \(k\) indexes banks, \(t\) indexes time periods.

Agent Types#

The model simulates three types of agents, each composed of one or more roles (see Overview for the ECS architecture):

Agent Type

Roles

Count

Key State Variables

Firms

Producer, Employer, Borrower

n_firms

price, inventory, production, wage_offer, net_worth, credit_demand

Households

Worker, Consumer, Shareholder

n_households

wage, savings, income, propensity, employer, dividends

Banks

Lender

n_banks

equity_base, credit_supply, interest_rate

Firms are the central agents: they plan production, hire workers, borrow from banks, produce goods, set prices, and sell to consumers. Their survival depends on maintaining positive net worth.

Households supply labor and demand consumption goods. They save unspent income and receive dividend income from profitable firms.

Banks are passive credit intermediaries. They supply credit up to a leverage constraint and set interest rates with a risk premium based on borrower fragility.

The Economic Cycle#

Each simulation period executes events in 8 sequential phases. This section describes the economic logic and mathematical rules of each phase.

Phase 1: Planning#

Firms decide how much to produce and how many workers to hire, based on adaptive expectations about demand.

Expected demand. Firms adjust production based on two signals: whether they have unsold inventory (\(S_{i,t-1} > 0\)) and whether their price is above or below the market average (\(P_{i,t-1} \gtrless \bar{P}_{t-1}\)):

\[\begin{split}Y^d_{i,t} = \begin{cases} Y_{i,t-1} \times (1 + \rho_{i,t}) & \text{if } S_{i,t-1} = 0 \text{ and } P_{i,t-1} \geq \bar{P}_{t-1} \\ Y_{i,t-1} \times (1 - \rho_{i,t}) & \text{if } S_{i,t-1} > 0 \text{ and } P_{i,t-1} < \bar{P}_{t-1} \\ Y_{i,t-1} & \text{otherwise} \end{cases}\end{split}\]

where \(\rho_{i,t} \sim U(0, h_\rho)\) is a random production shock. The first case (sold everything at a competitive price) triggers expansion; the second case (unsold inventory at an uncompetitive price) triggers contraction; the remaining cases maintain the status quo.

Note

The production signal \(Y_{i,t-1}\) uses actual production from the previous period, not desired production. This creates a feedback loop: if a firm’s desired contraction is absorbed by the ceil() quantization (see below), actual production stays the same, and the signal resets.

Desired labor. Firms compute the workforce needed for their production target:

\[L^d_{i,t} = \left\lceil \frac{Y^d_{i,t}}{\varphi} \right\rceil\]

The ceiling function ensures integer labor demand but creates a quantization effect: small production decreases may not reduce the workforce at all. For a firm with \(L\) workers and shock width \(h_\rho\), the probability that a decrease actually reduces workforce is \(\max(0, 1 - 1/(L \times h_\rho))\). With the default \(h_\rho = 0.10\) and typical firm size \(L \approx 5\), this probability is zero; firms effectively cannot shrink through this channel alone.

Vacancies and firing. If \(L^d_{i,t} > L^{current}_{i,t}\), the firm posts vacancies:

\[V_{i,t} = \max(0,\; L^d_{i,t} - L^{current}_{i,t})\]

If \(L^d_{i,t} < L^{current}_{i,t}\), the firm fires \(L^{current}_{i,t} - L^d_{i,t}\) workers selected at random.

Breakeven price. In the default (planning-phase) pricing, firms also compute a cost-covering price floor using the previous period’s wage bill:

\[P^b_{i,t} = \frac{WB_{i,t-1} + \sum_k r_{i,k} \cdot B_{i,k}}{Y^d_{i,t}}\]

Price adjustment. Firms then adjust their price based on inventory and market position, subject to the breakeven floor:

\[\begin{split}P_{i,t} = \begin{cases} \max(P^b_{i,t},\; P_{i,t-1} \times (1 - \eta_{i,t})) & \text{if } S_{i,t-1} > 0 \text{ and } P_{i,t-1} \geq \bar{P}_{t-1} \\ \max(P^b_{i,t},\; P_{i,t-1} \times (1 + \eta_{i,t})) & \text{if } S_{i,t-1} = 0 \text{ and } P_{i,t-1} < \bar{P}_{t-1} \\ \max(P^b_{i,t},\; P_{i,t-1}) & \text{otherwise} \end{cases}\end{split}\]

where \(\eta_{i,t} \sim U(0, h_\eta)\). The breakeven floor prevents price cuts below unit cost, ensuring every sale is profitable.

Phase 2: Labor Market#

Workers search for jobs and firms hire to fill vacancies.

Inflation and minimum wage. The economy-wide inflation rate is computed as the year-over-year change in average market price:

\[\pi_t = \frac{\bar{P}_t - \bar{P}_{t-4}}{\bar{P}_{t-4}}\]

The statutory minimum wage is revised every min_wage_rev_period periods (default: 4) to keep pace with inflation:

\[\hat{w}_{t} = \hat{w}_{t-1} \times (1 + \pi_t)\]

Wage setting. Firms with vacancies set a wage offer with a random markup above the minimum wage:

\[\begin{split}w^b_{i,t} = \begin{cases} \max\bigl(\hat{w}_t,\; w_{i,t-1}\bigr) & \text{if } V_{i,t} = 0 \\ \max\bigl(\hat{w}_t,\; w_{i,t-1} \times (1 + \xi_{i,t})\bigr) & \text{if } V_{i,t} > 0 \end{cases}\end{split}\]

where \(\xi_{i,t} \sim U(0, h_\xi)\) is a wage increase shock.

Job search. Each unemployed worker sends \(M\) applications. Workers whose contracts expired in the previous period send their first application to their former employer, then \(M - 1\) to randomly selected firms. Fully unemployed workers apply to \(M\) random firms.

Matching. Labor market matching is decentralized and batch-processed: in each of \(M\) rounds, all applications are processed simultaneously using vectorized operations. When multiple workers target the same firm, a conflict resolution step randomly selects winners based on available vacancies. Workers apply to their highest-wage firm first, so matching favors high-wage firms, a form of preferential attachment.

Contracts. Hired workers sign contracts of length \(\theta\) periods (default: 8). During the contract, the worker’s wage is fixed at the firm’s offer at the time of hiring. When the contract expires, the worker becomes unemployed and must search for a new job.

Phase 3: Credit Market#

Firms that cannot self-finance their wage bill borrow from banks.

Credit supply. Each bank’s lending capacity is constrained by its equity and the capital requirement coefficient:

\[C_{k,t} = \frac{E_{k,t}}{\nu}\]

With the default \(\nu = 0.10\), a bank with equity 5.0 can lend up to 50.0. Credit supply is reduced as loans are granted during matching rounds.

Interest rate. Banks set interest rates as a markup over the policy rate, with a random operating cost shock:

\[r_{k,t} = \bar{r} \times (1 + \phi_{k,t})\]

where \(\phi_{k,t} \sim U(0, h_\phi)\). The interest rate is further adjusted for borrower risk via the financial fragility premium (see below).

Credit demand. Firms borrow only when their net worth is insufficient to cover the wage bill:

\[B_{i,t} = \max(0,\; WB_{i,t} - A_{i,t})\]

where \(WB_{i,t}\) is the wage bill and \(A_{i,t}\) is net worth. When net worth exceeds the wage bill, the firm self-finances entirely.

Financial fragility. Each firm’s projected leverage ratio is used to prioritize loan applications:

\[\ell_{i,t} = \frac{B_{i,t}}{A_{i,t}}\]

This metric is capped at max_leverage (default: 10) for firms with very low net worth. Banks process applications in ascending fragility order: the least leveraged firms get served first.

Matching. Credit market matching mirrors the labor market: \(H\) batch matching rounds where all applications are processed simultaneously with conflict resolution. Each firm contacts \(H\) banks sorted by interest rate (lowest first). Applications are processed in ascending fragility order using grouped_cumsum to exhaust bank supply. Individual loans are capped at max_loan_to_net_worth times the borrower’s net worth (default: 2).

Post-credit firing. After credit matching, firms that still cannot cover their full wage bill fire workers until the wage bill fits within available funds (net worth + loans received).

Phase 4: Production#

Firms pay wages and produce goods.

Wage payment. Each firm pays wages to all its employees:

\[WB_{i,t} = \sum_{j \in \text{employees}_i} w_{j}\]

The wage bill is deducted from the firm’s available funds. Workers receive their wage as income.

Production. Output is determined by the production function:

\[Y_{i,t} = \varphi \times L_{i,t}\]

where \(\varphi\) is labor productivity (constant in the baseline model, endogenous in the Growth+ extension) and \(L_{i,t}\) is the current workforce. Production is added to the firm’s inventory.

Contract updates. Each employed worker’s remaining contract duration is decremented by one period. Workers whose contracts reach zero are marked as unemployed and become available for the next period’s labor market.

Phase 5: Goods Market#

Households decide how much to spend and shop for goods.

Marginal propensity to consume. Each household’s spending propensity is a decreasing function of their relative savings position:

\[c_{j,t} = \frac{1}{1 + \left[\tanh\!\left(\frac{SA_{j,t}}{\overline{SA}_t}\right)\right]^\beta}\]

where \(SA_{j,t}\) is the household’s accumulated savings, \(\overline{SA}_t\) is the economy-wide average savings, and \(\beta\) is the propensity exponent (default: 2.5). Households with below-average savings spend a larger fraction of income; those with above-average savings spend less.

Spending budget. The household allocates income for consumption:

\[\text{budget}_{j,t} = c_{j,t} \times \text{income}_{j,t}\]

Consumer search. Each consumer visits \(Z\) firms. The first visit goes to the largest producer from the previous period (preferential attachment / loyalty), and the remaining \(Z - 1\) visits go to randomly selected firms. Consumers rank their selected firms by price (lowest first) and buy sequentially until their budget is exhausted or all firms are visited.

Rationing. When a consumer’s demand exceeds a firm’s available inventory, the consumer buys only what is available and moves to the next firm. Unspent budget is returned to savings at the end of the shopping phase.

Phase 6: Revenue & Dividends#

Firms collect revenue and distribute profits.

Revenue and gross profit.

\[\begin{split}R_{i,t} &= P_{i,t} \times \text{sold}_{i,t} \\ \Pi^g_{i,t} &= R_{i,t} - WB_{i,t}\end{split}\]

Debt repayment and net profit. Firms repay principal plus interest on all outstanding loans. Loans are settled from available funds; if funds are insufficient, the shortfall becomes bad debt for the lending bank:

\[\Pi_{i,t} = \Pi^g_{i,t} - \sum_k r_{i,k} \times B_{i,k}\]

Dividends. Firms with positive net profit pay a fraction as dividends to households:

\[\begin{split}\text{div}_{i,t} &= \delta \times \max(0, \Pi_{i,t}) \\ \Pi^r_{i,t} &= \Pi_{i,t} - \text{div}_{i,t}\end{split}\]

where \(\delta\) is the dividend payout ratio (default: 0.10). Dividends are distributed equally across all households via the Shareholder role.

Phase 7: Bankruptcy#

Insolvent agents are detected and removed.

Net worth update. Firm net worth evolves according to retained profits:

\[A_{i,t} = A_{i,t-1} + \Pi^r_{i,t}\]

Insolvency condition. A firm goes bankrupt when its net worth becomes negative:

\[A_{i,t} < 0 \implies \text{firm } i \text{ exits}\]

Bankrupt firms fire all workers, and their outstanding loans become bad debt for the lending banks:

\[\text{recovery}_k = \text{clip}\!\left(\text{frac} \times A_{i,t},\; 0,\; B_{i,k}\right)\]

The actual loss for bank \(k\) is \(B_{i,k} - \text{recovery}_k\).

Bank insolvency. Banks whose equity falls below zero (from accumulated bad debt losses) also go bankrupt and are replaced.

Phase 8: Entry#

Bankrupt agents are replaced one-for-one, maintaining constant population sizes.

Replacement firms are initialized with attributes derived from the trimmed mean (excluding top and bottom 5%) of surviving firms:

Attribute

Initialization Rule

Net worth

new_firm_size_factor \(\times\) survivor mean (default: 50%)

Production capacity

new_firm_production_factor \(\times\) survivor mean (default: 50%)

Wage offer

new_firm_wage_factor \(\times\) survivor mean (default: 50%)

Price

new_firm_price_markup \(\times\) average market price (default: 1.15)

New entrants start below average size, consistent with the empirical regularity that young firms are smaller than incumbents.

Replacement banks are re-initialized with the default equity_base_init.

Market Matching#

All three markets use decentralized matching with search frictions, a key departure from Walrasian general equilibrium models where a central auctioneer clears markets instantaneously.

Batch matching rounds. Matching proceeds in multiple rounds. In each round, all applications are processed simultaneously using vectorized operations with conflict resolution. When multiple seekers target the same provider, a random selection determines winners. Early rounds reduce available capacity for later rounds, creating realistic market frictions.

Preferential attachment. In the labor and goods markets, agents have a tendency to return to previous partners: workers whose contracts expired apply first to their former employer; consumers visit their previous period’s largest producer first. This creates endogenous firm size persistence and market concentration.

Search frictions. The parameters \(M\), \(H\), and \(Z\) control how many partners each agent can contact per period. Lower values create more friction (less efficient matching); higher values approach perfect information. The defaults (\(M = 4\), \(H = 2\), \(Z = 2\)) create moderate frictions consistent with the reference model.

Key Parameters#

The following table summarizes the most important model parameters. See Configuration for the full parameter reference and The BAM Model for the economic interpretation of each phase.

Parameter

Symbol

Default

Description

n_firms

100

Number of firms in the economy

n_households

500

Number of households (recommended: \(\geq 5 \times\) n_firms)

n_banks

10

Number of banks

labor_productivity

\(\varphi\)

0.50

Goods produced per worker per period

theta

\(\theta\)

8

Employment contract length (periods)

delta

\(\delta\)

0.10

Dividend payout ratio (fraction of net profit)

beta

\(\beta\)

2.50

Consumption propensity exponent

v

\(\nu\)

0.10

Bank capital requirement coefficient (max leverage = \(1/\nu\))

r_bar

\(\bar{r}\)

0.02

Baseline (policy) interest rate

h_rho

\(h_\rho\)

0.10

Max production growth shock

h_xi

\(h_\xi\)

0.05

Max wage growth shock

h_eta

\(h_\eta\)

0.10

Max price adjustment shock

h_phi

\(h_\phi\)

0.10

Max bank operating cost shock

max_M

\(M\)

4

Job applications per unemployed worker per period

max_H

\(H\)

2

Loan applications per firm per period

max_Z

\(Z\)

2

Shops visited per consumer per period

Economy Statistics#

BAM Engine tracks several economy-wide metrics each period:

  • Average market price (\(\bar{P}_t\)): exponentially smoothed average of all firm prices, weighted by production

  • Unemployment rate: fraction of households without an employer, measured after the production phase

  • Inflation rate: year-over-year change in average market price (\(\pi_t = (\bar{P}_t - \bar{P}_{t-4}) / \bar{P}_{t-4}\))

Price and inflation histories are stored in sim.ec (the Economy object) and accessible as time series via sim.ec.avg_mkt_price_history and sim.ec.inflation_history. Unemployment rate is calculated on-demand from Worker.employed: np.mean(~sim.wrk.employed).

Further Reading#

  • Original reference: Delli Gatti, D., Gaffeo, E., Gallegati, M., Giulioni, G., & Palestrini, A. (2011). Macroeconomics from the Bottom-up. Springer. Chapter 3.

  • Extensions: The Growth+ (R&D), buffer-stock consumption, and taxation extensions add endogenous productivity, heterogeneous saving behavior, and fiscal policy. See Model Extensions.

  • Validation: BAM Engine includes a validation framework for comparing simulation output to the reference results in the book. See Validation & Analysis.

  • Configuration: For the full parameter reference with valid ranges and effects, see Configuration.

See also

Overview for the software architecture, Pipeline Customization for the event execution order, Model Extensions for model extensions.