Economics: where inequality comes from#

Two zoo models give two very different answers to “why is wealth unequal?”. In the Boltzmann exchange agents are identical and trade one unit of money at random: inequality comes from chance alone, and settles at a Gini of about one half. In the Bouchaud-Mezard model wealth also earns random returns: the richer earn more in absolute terms, and the distribution grows a power-law tail whose weight depends on how much the agents trade with each other.

Start a project from either with modelly zoo copy kinetic_wealth my_economy (the same command in bash and PowerShell).

Build and run: chance alone#

A thousand agents start with five units each. Every step, each agent is paired with another and one of the two, chosen by a coin, gives one unit if it has one.

import numpy as np
import matplotlib.pyplot as plt

from modelly.zoo.kinetic_wealth.model import KineticScenario, KineticWealth

model = KineticWealth(KineticScenario(rng=1, n=1000, money=5, steps=600))
model.run()
gini = model.datacollector.get_model_vars_dataframe()
print(f"Gini after {model.scenario.steps} steps: {gini.iloc[-1, 0]:.3f}")
print(f"Gini of the stationary law:        {model.stationary_gini():.3f}")
Gini after 600 steps: 0.558
Gini of the stationary law:        0.545

Plot: the Boltzmann-Gibbs distribution#

Every configuration of the money with the same total is equally likely in the long run, so the wealth of one agent follows a distribution close to the exponential, P(w) ~ exp(-w / 5).

exact = model.stationary_distribution()
counts = np.bincount(model.wealth, minlength=exact.shape[0]) / model.scenario.n
fig, ax = plt.subplots(figsize=(6, 3.5))
ax.bar(np.arange(30), counts[:30], color="#9ab", label="simulated, one snapshot")
ax.plot(np.arange(30), exact[:30], "k.-", label="exact stationary law")
ax.set_yscale("log")
ax.set_xlabel("wealth (units)")
ax.set_ylabel("share of agents")
ax.legend(frameon=False);
../../_images/1aae448c658910495a58f118907f356c0510601cc05d4da8acbe7f8410509d89.png

Analysis: returns on wealth create a heavy tail#

In the Bouchaud-Mezard model each agent’s wealth is multiplied by a random return of volatility sigma and flows toward the mean at rate J. The stationary distribution of wealth relative to the mean is inverse-gamma with shape 1 + 2 J / sigma^2: the larger sigma^2 / J, the heavier the tail and the higher the Gini.

from modelly.zoo.bouchaud_mezard.model import BouchaudMezard, BouchaudMezardScenario

fig, ax = plt.subplots(figsize=(6, 3.5))
for ratio in (0.5, 1.0, 1.5):
    bm = BouchaudMezard(BouchaudMezardScenario(rng=2, n=2000, volatility=np.sqrt(ratio), steps=1500))
    bm.run()
    w = np.sort(bm.wealth)[::-1]
    share = np.arange(1, w.shape[0] + 1) / w.shape[0]
    ax.loglog(w, share, label=f"sigma^2/J = {ratio}, Gini {bm.datacollector.get_model_vars_dataframe().iloc[-1, 0]:.2f}")
ax.set_xlabel("wealth relative to the mean")
ax.set_ylabel("share of agents at least this rich")
ax.legend(frameon=False);
../../_images/286a2e89b783b0965e9370cfd08443bb64ee192fff30c67476d21e50ba2c0879.png

On a log-log plot the tail of the inverse-gamma law is a straight line of slope -2 J / sigma^2: richer agents are much more common than in the Boltzmann world.

Going further#

  • Give the agents a saving propensity in the Boltzmann exchange and watch the Gini fall.

  • Make J a network: exchange only with trading partners.

  • The order book is the zoo’s market-microstructure model: its returns have fat tails too, for a different reason.