Buffer-Stock Consumption Extension#

Based on Section 3.9.4 of Delli Gatti et al. (2011)

The buffer-stock extension replaces the baseline consumption rule with a target savings-to-income ratio mechanism. Households aim to maintain savings equal to \(h\) times their income. When savings fall below the target, they cut spending; when savings exceed it, they spend more freely.

Quick Start#

import bamengine as bam
from extensions.buffer_stock import BUFFER_STOCK

sim = bam.Simulation.init(seed=42)
sim.use(BUFFER_STOCK)

results = sim.run(n_periods=1000, collect=True)

Note

The BufferStock role is registered at the household level (it tracks per-household state). The Extension bundle handles the agent count automatically; when using the manual pattern, pass n_agents=sim.n_households to use_role().

Role Fields#

Field

Description

prev_income

Previous period’s income (used to detect income changes)

propensity

Buffer-stock MPC (may exceed 1.0 when households dissave)

Events#

Event

Hook

Description

ConsumersCalcBufferStockPropensity

replaces consumers_calc_propensity

Compute MPC from income changes and savings-target gap

ConsumersDecideBufferStockSpending

replaces consumers_decide_income_to_spend

Allocate spending using buffer-stock MPC

Configuration#

Parameter

Default

Description

buffer_stock_h

2.0

Target savings-to-income ratio. Higher values mean more precautionary saving.

Expected behavior: More realistic wealth distribution, precautionary saving by low-income households, and counter-cyclical consumption smoothing.

API Reference#

Buffer-stock consumption extension (Section 3.9.4).

This extension implements Section 3.9.4 of Delli Gatti et al. (2011), replacing the baseline mean-field MPC with an individual adaptive rule based on buffer-stock saving theory.

Usage:

from extensions.buffer_stock import BUFFER_STOCK

sim = bam.Simulation.init(**config)
sim.use(BUFFER_STOCK)
results = sim.run()

Or manually:

from extensions.buffer_stock import (
    BufferStock,
    BUFFER_STOCK_EVENTS,
    BUFFER_STOCK_CONFIG,
)

sim = bam.Simulation.init(**config)
sim.use_role(BufferStock, n_agents=sim.n_households)
sim.use_events(*BUFFER_STOCK_EVENTS)
sim.use_config(BUFFER_STOCK_CONFIG)
results = sim.run()

Components#

BufferStockrole

Tracks prev_income and propensity per household.

ConsumersCalcBufferStockPropensityevent

Replaces consumers_calc_propensity.

ConsumersDecideBufferStockSpendingevent

Replaces consumers_decide_income_to_spend.

Design Decisions#

Pipeline hook strategy — Both consumers_calc_propensity and consumers_decide_income_to_spend are replaced via @event(replace=...). The buffer-stock rule changes how MPC is computed (no mean-field) and how it is applied (income-only for employed, savings-only for unemployed), so both events must be replaced. Keeping them as two separate events preserves the baseline pipeline structure (propensity -> spending).

Income trackingprev_income is stored on the BufferStock role (not on Consumer) to keep src/ untouched. con.income is still zeroed after consumption, preserving compatibility with the wage payment mechanism (workers_receive_wage adds wage to con.income in-place).

Desired savings-income ratio (h) — A single homogeneous config parameter (buffer_stock_h) for all households. The book mentions a “personal desired ratio” but does not specify a distribution. Starting homogeneous lets validation (Figure 3.8) determine if heterogeneity is needed.

MPC bounds and dissaving — No explicit c_max. The formula c_t = 1 + (d - h*g)/(1+g) naturally produces c > 1 when income drops (negative g), which is dissaving from savings. Budget is capped at total wealth (savings + income) to prevent negative savings; c is clipped at 0 minimum to prevent negative consumption.

Unemployed households — Three-case MPC logic:

Case

Condition

MPC formula

Consumption source

Normal

W > 0 and W_prev > 0

Eq. 3.20 (g clamped -0.99)

Income (c * W)

Fresh start

W > 0 and W_prev <= 0

c = 1 - h + S/W

Income (c * W)

Unemployed

W <= 0

c = 1/h

Savings (c * S)

At the target buffer S = h·W, first-period unemployment spending equals (1/h)·h·W = W — the last employed income (consumption smoothing). The drawdown is geometric: after h periods, ~37% of savings remain ((1-1/h)^h 1/e).

Dividends — Stay in savings, not counted as income W. The buffer-stock MPC is driven by labor income dynamics only. The core Shareholder role tracks per-period dividends so validation metrics can subtract the dividend artifact from MPC calculations (adjusted_c = c - D/W).

Composability — Fully composable with R&D/Growth+. RnD modifies firm behavior (productivity); BufferStock modifies consumer behavior (MPC). They operate on different agent types with no conflicts.

Distribution fitting — Wealth CCDF is fitted with Singh-Maddala (scipy.stats.burr12), Dagum (scipy.stats.mielke), and GB2 (scipy.stats.betaprime) distributions for validation against Figure 3.8. Singh-Maddala and Dagum have x^k terms in their PDFs; unconstrained MLE sometimes finds extreme k (>100), causing overflow. The validation fitting uses a profile likelihood fallback: when the default fit overflows, k is fixed at values in [5..50] and the remaining parameters are optimized, selecting the k with maximum log-likelihood.

class extensions.buffer_stock.BufferStock(prev_income, propensity)[source]#

Buffer-stock consumption state for households.

Tracks previous-period income and buffer-stock propensity for each household. Used by the buffer-stock consumption extension to compute individual MPC based on adaptive savings rules.

Parameters:
  • prev_income (Float) – Previous period income (W_{t-1}). Used to compute income growth rate for the buffer-stock MPC formula.

  • propensity (Float) – Buffer-stock MPC (c_t). May exceed 1.0 when households dissave. Separate from Consumer.propensity to avoid conflicts when the extension is not active.

prev_income#
propensity#
name = 'BufferStock'#
class extensions.buffer_stock.ConsumersCalcBufferStockPropensity[source]#

Compute individual MPC using buffer-stock adaptive rule.

Three-case logic:

  1. Normal (prev_income > 0 and income > 0): Full buffer-stock formula (Eq. 3.20).

  2. Fresh start (prev_income <= 0 and income > 0): Just re-employed: c = 1 - h + S/W.

  3. Unemployed (income <= 0): c = 1/h (gradual savings drawdown).

execute(sim)[source]#

Execute buffer-stock propensity calculation.

name = 'consumers_calc_buffer_stock_propensity'#
class extensions.buffer_stock.ConsumersDecideBufferStockSpending[source]#

Allocate spending budget using buffer-stock MPC.

Two-path consumption:

  • Employed (income > 0): budget = c * income

  • Unemployed (income <= 0): budget = c * savings

Budget is capped at total wealth (savings + income) and floored at 0. Savings are updated and floored at 0 (non-negative).

execute(sim)[source]#

Execute buffer-stock spending allocation.

name = 'consumers_decide_buffer_stock_spending'#

Buffer-stock consumption role definition.

This module defines the BufferStock role that tracks previous-period income and buffer-stock propensity for each household.

See Section 3.9.4 of Delli Gatti et al. (2011).

class extensions.buffer_stock.role.BufferStock(prev_income, propensity)[source]#

Buffer-stock consumption state for households.

Tracks previous-period income and buffer-stock propensity for each household. Used by the buffer-stock consumption extension to compute individual MPC based on adaptive savings rules.

Parameters:
  • prev_income (Float) – Previous period income (W_{t-1}). Used to compute income growth rate for the buffer-stock MPC formula.

  • propensity (Float) – Buffer-stock MPC (c_t). May exceed 1.0 when households dissave. Separate from Consumer.propensity to avoid conflicts when the extension is not active.

prev_income#
propensity#
name = 'BufferStock'#

Buffer-stock consumption events.

This module provides two replacement events for the buffer-stock consumption extension (Section 3.9.4 of Delli Gatti et al., 2011).

The extension replaces the baseline mean-field MPC with an individual adaptive rule based on buffer-stock saving theory. Each household maintains a personal desired savings-income ratio and adjusts consumption to keep that ratio constant.

Key Equations#

Buffer-Stock MPC (Equation 3.20):

\[c_t = 1 + \frac{d_t - h \cdot g_t}{1 + g_t}\]

Where: - \(h\) is the desired savings-income ratio (config parameter) - \(g_t = W_t / W_{t-1} - 1\) is the income growth rate - \(d_t = S_t / W_{t-1} - h\) is the divergence from desired ratio

Fresh Start Formula (derived):

\[c_t = 1 - h + S_t / W_t\]

Applied when a household has just been re-employed (no previous income).

class extensions.buffer_stock.events.ConsumersCalcBufferStockPropensity[source]#

Compute individual MPC using buffer-stock adaptive rule.

Three-case logic:

  1. Normal (prev_income > 0 and income > 0): Full buffer-stock formula (Eq. 3.20).

  2. Fresh start (prev_income <= 0 and income > 0): Just re-employed: c = 1 - h + S/W.

  3. Unemployed (income <= 0): c = 1/h (gradual savings drawdown).

execute(sim)[source]#

Execute buffer-stock propensity calculation.

name = 'consumers_calc_buffer_stock_propensity'#
class extensions.buffer_stock.events.ConsumersDecideBufferStockSpending[source]#

Allocate spending budget using buffer-stock MPC.

Two-path consumption:

  • Employed (income > 0): budget = c * income

  • Unemployed (income <= 0): budget = c * savings

Budget is capped at total wealth (savings + income) and floored at 0. Savings are updated and floored at 0 (non-negative).

execute(sim)[source]#

Execute buffer-stock spending allocation.

name = 'consumers_decide_buffer_stock_spending'#

See also