SPB Git

spb/wp27_uqo

Public

WP27: exchange engine, agents, LLM adapters, designs, theory, literature, pre-analysis plan (pre-pilot freeze)

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Simon-Pierre Boucher committed (Oct 27, 2026) Browse files

113 changed files +10,847 −0

113 changed files
added .env.example +5 −0
@@ -0,0 +1,5 @@
1+# Copy to .env (never committed). Keys are read by src/market_agents/llm/providers/*.py via os.environ only.
2+OPENAI_API_KEY=sk-...
3+ANTHROPIC_API_KEY=sk-ant-...
4+# Optional overrides (defaults live in configs/*.yaml)
5+# MARKET_AGENTS_LLM_USD_CAP=40
added .gitignore +46 −0
@@ -0,0 +1,46 @@
1+# Raw & processed data — never committed (see data/raw/README.md for provenance)
2+data/raw/*
3+!data/raw/README.md
4+data/processed/*
5+!data/processed/.gitkeep
6+
7+# Python
8+__pycache__/
9+*.pyc
10+.pytest_cache/
11+.venv/
12+*.egg-info/
13+
14+# LaTeX build artifacts (paper/main.pdf IS committed)
15+paper/*.aux
16+paper/*.log
17+paper/*.out
18+paper/*.toc
19+paper/*.lof
20+paper/*.lot
21+paper/*.fls
22+paper/*.fdb_latexmk
23+paper/*.bbl
24+paper/*.blg
25+paper/*.spl
26+paper/*.synctex.gz
27+paper/*.run.xml
28+paper/*.bcf
29+
30+# Logs
31+logs/
32+*.log
33+
34+# macOS
35+.DS_Store
36+
37+# WP27 — secrets, run artefacts, caches
38+.env
39+results/runs/*
40+!results/runs/.gitkeep
41+results/cache/
42+logs/
43+*.duckdb
44+*.parquet
45+uv.lock.bak
46+paper/main_anon.pdf
added Makefile +57 −0
@@ -0,0 +1,57 @@
1+# UQO WP 27 — The Invisible Hand of Machines. One-command no-API replication: `make replicate`.
2+PY ?= .venv/bin/python
3+W ?= 6
4+
5+.PHONY: all setup test smoke calibrate scale classical pilot confirmatory library figures tables paper replicate clean
6+
7+all: test classical figures tables paper
8+
9+setup:
10+ uv sync --extra dev
11+
12+test:
13+ $(PY) -m pytest tests -q
14+
15+smoke: # 100 agents, fixed seed, zero paid calls, accounting verified
16+ $(PY) scripts/smoke_test.py
17+
18+calibrate:
19+ $(PY) scripts/10_calibration_sweep.py
20+
21+scale:
22+ $(PY) scripts/11_scale_benchmark.py
23+
24+classical: # 16 cells x 30 matched seeds, no API
25+ $(PY) -m market_agents.cli design configs/classical_confirmatory.yaml --workers $(W) --root results/runs
26+ $(PY) -m market_agents.cli design configs/exploratory.yaml --workers $(W) --root results/runs
27+
28+pilot: # paid: ~3 USD (OpenAI). Requires OPENAI_API_KEY in .env
29+ $(PY) -m market_agents.cli budget configs/pilot_openai.yaml
30+ $(PY) -m market_agents.cli design configs/pilot_openai.yaml --workers 3 --cache results/cache/llm_cache.sqlite --root results/runs
31+
32+confirmatory: # paid: ~30 USD (OpenAI)
33+ $(PY) -m market_agents.cli budget configs/confirmatory_openai.yaml
34+ $(PY) -m market_agents.cli design configs/confirmatory_openai.yaml --workers 5 --cache results/cache/llm_cache.sqlite --root results/runs
35+
36+library: # frozen decision library from recorded runs + replay at N = 1,000 (no API)
37+ $(PY) scripts/60_frozen_library.py
38+
39+theory:
40+ $(PY) scripts/90_theory_checks.py
41+
42+figures:
43+ $(PY) scripts/40_figures.py
44+
45+tables:
46+ $(PY) scripts/50_tables.py
47+ mkdir -p paper/figures paper/tables
48+ cp results/figures/*.pdf paper/figures/
49+ cp results/tables/*.tex paper/tables/
50+
51+paper: tables
52+ cd paper && latexmk -pdf main.tex
53+
54+replicate: test smoke classical theory figures tables # everything that needs no API key
55+
56+clean:
57+ cd paper && latexmk -C
added README.md +3 −0
@@ -0,0 +1,3 @@
1+# The Invisible Hand of Machines
2+
3+(README written at the end of the build — see Makefile.)
added configs/baseline.yaml +49 −0
@@ -0,0 +1,49 @@
1+# Baseline classical economy (no LLM). All numbers documented in docs/assumptions.md.
2+name: baseline
3+seed: 1
4+n_ticks: 600
5+warmup: 100
6+assets: {n_assets: 1, tick_cents: 1, initial_price_cents: 20000, price_band_pct: 0.5, max_order_qty: 10000}
7+fundamentals: {div_interval: 20, r_period: 0.0025, mu: [50.0], mu_shift: 0.0, p_switch: 0.0, rho: 0.98, sigma: 2.0,
8+ jump_prob: 0.0, jump_sigma: 0.0, factor_loading: [0.0], x0: 0.0}
9+news: {rate: 0.02, noise_sd: 1.0, misleading_share: 0.0, misleading_bias: 10.0, window: 20}
10+exchange: {maker_fee_bps: 0.0, taker_fee_bps: 2.0, min_latency: 0.05, halt_threshold: null, halt_window: 10, halt_duration: 20,
11+ halt_cancel_resting: true, allow_short: false, max_short_lots: 0, margin_check: true, liquidation_fraction: 0.5, order_ttl: 50}
12+population:
13+ n_traders: 100
14+ mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.50, market_maker: 0.05, statarb: 0.0, leveraged: 0.04} # calibrated 2026-10-27 (scripts/10)
15+ activity: {fundamentalist: 0.20, trend: 0.20, meanrev: 0.20, noise: 0.30, market_maker: 0.5, statarb: 0.2, leveraged: 0.2}
16+ policy_kwargs: {fundamentalist: {aggressiveness: 20.0}, noise: {p_market: 0.6}, market_maker: {quote_qty: 20}}
17+ llm_share: 0.0
18+ llm_replace: proportional
19+ llm_keep_market_makers: true
20+ informed_share: 0.3
21+ precision: 2.0
22+ leverage_cap: 3.0
23+ maintenance_margin: 0.25
24+ endowment: {cash_cents: 2000000, shares: 100, wealth_dispersion: 0.3}
25+ latency: {min: 0.05, max: 1.0, llm_latency: null}
26+ llm:
27+ provider_mix: {mock: 1.0}
28+ models: {mock: mock-v1, openai: gpt-5.4-nano, anthropic: claude-haiku-5-5}
29+ prompt_set: single
30+ prompt_version: v1
31+ memory: 0
32+ channel: false
33+ cohort_size: 5
34+ decision_interval: 20
35+ stagger: true
36+ stagger_slots: 4
37+ informed_share: 0.3
38+ precision: 2.0
39+ max_order_qty: 50
40+ reasoning_effort: low
41+ max_output_tokens: 1200
42+ concurrency: 8
43+ usd_cap: 5.0
44+ cache: true
45+shocks:
46+ - {time: 300, kind: fundamental_jump, size: 10.0} # +10 cents on the latent deviation -> +10/(1+r-rho) = +4.4 on V (+2.2 %), revealed only through news / the next dividend
47+ - {time: 450, kind: placebo}
48+output: {events: false, trades: true, llm_log: true, lookback: 60}
49+treatment: {}
added configs/classical_confirmatory.yaml +24 −0
@@ -0,0 +1,24 @@
1+# Classical (no-API) confirmatory design: mechanism checks that do not need an LLM — 30 matched seeds.
2+# Used for (i) stylized-fact validation, (ii) the mock "shared-model" knob (herd_bias) as a controlled analogue of
3+# correlated errors, (iii) safeguards and leverage comparative statics predicted by Props 4–6, (iv) placebo controls.
4+name: classical_confirmatory
5+base: baseline.yaml
6+seeds: {start: 101, n: 30}
7+overrides: {population.llm.provider_mix: {mock: 1.0}, population.llm.usd_cap: 0.0}
8+cells:
9+ - {name: control, overrides: {}, treatment: {arm: control}}
10+ - {name: placebo_shock, overrides: {shocks: [{time: 300, kind: placebo}, {time: 450, kind: placebo}]}, treatment: {arm: placebo}}
11+ - {name: trend_heavy, overrides: {population.mix: {fundamentalist: 0.25, trend: 0.16, meanrev: 0.10, noise: 0.40, market_maker: 0.05, statarb: 0.0, leveraged: 0.04}}, treatment: {arm: feedback, trend: 0.16}}
12+ - {name: leverage_heavy, overrides: {population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.35, market_maker: 0.05, statarb: 0.0, leveraged: 0.19}}, treatment: {arm: leverage, leveraged: 0.19}}
13+ - {name: leverage_heavy_funding_shock, overrides: {population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.35, market_maker: 0.05, statarb: 0.0, leveraged: 0.19}, shocks: [{time: 300, kind: fundamental_jump, size: -10.0}, {time: 320, kind: funding, size: 0.5}]}, treatment: {arm: leverage, leveraged: 0.19, funding_shock: 0.5}}
14+ - {name: liquidity_shock, overrides: {shocks: [{time: 300, kind: fundamental_jump, size: 10.0}, {time: 300, kind: liquidity}, {time: 360, kind: liquidity_end}]}, treatment: {arm: liquidity, mm_withdrawn: 60}}
15+ - {name: info_low, overrides: {population.precision: 0.5}, treatment: {arm: information, precision: 0.5}}
16+ - {name: info_high, overrides: {population.precision: 8.0}, treatment: {arm: information, precision: 8.0}}
17+ - {name: misleading_news, overrides: {news.misleading_share: 0.5}, treatment: {arm: information, misleading: 0.5}}
18+ - {name: breaker_5, overrides: {exchange.halt_threshold: 0.05}, treatment: {arm: safeguard, breaker: 0.05}}
19+ - {name: poslimit_300, overrides: {exchange.position_limit: 300}, treatment: {arm: safeguard, position_limit: 300}}
20+ - {name: auction_5, overrides: {exchange.call_auction_interval: 5}, treatment: {arm: mechanism, auction: 5}}
21+ - {name: mock_llm_25_indep, overrides: {population.llm_share: 0.25}, treatment: {arm: mockherd, share: 0.25, herd: 0.0}}
22+ - {name: mock_llm_50_indep, overrides: {population.llm_share: 0.50}, treatment: {arm: mockherd, share: 0.50, herd: 0.0}}
23+ - {name: k2_control, overrides: {assets.n_assets: 2, fundamentals.mu: [50.0, 50.0], fundamentals.factor_loading: [0.7, 0.7], population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.45, market_maker: 0.05, statarb: 0.05, leveraged: 0.04}}, treatment: {arm: contagion, assets: 2}}
24+ - {name: k2_leverage, overrides: {assets.n_assets: 2, fundamentals.mu: [50.0, 50.0], fundamentals.factor_loading: [0.7, 0.7], population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.30, market_maker: 0.05, statarb: 0.05, leveraged: 0.19}, shocks: [{time: 300, kind: fundamental_jump, size: -10.0, asset: 0}, {time: 320, kind: funding, size: 0.5}]}, treatment: {arm: contagion, assets: 2, leveraged: 0.19, funding_shock: 0.5}}
added configs/confirmatory_openai.yaml +30 −0
@@ -0,0 +1,30 @@
1+# Phase 6 confirmatory design (live OpenAI; Anthropic cells blocked by the invalid key — see docs/model_cards.md).
2+# Matched seeds 201–207 (7 seeds, 80 % power for paired d ≈ 1.2; all primary outcomes Holm-adjusted). Frozen 2026-10-27
3+# after the pilot (same code revision as the pilot except the pre-registered bug fixes recorded in docs/research_log.md).
4+name: confirmatory_openai
5+base: baseline.yaml
6+seeds: {start: 201, n: 7}
7+overrides: {population.llm.provider_mix: {openai: 1.0}, population.llm.models: {openai: gpt-5.4-nano, openai_mini: gpt-5.4-mini, mock: mock-v1, anthropic: claude-haiku-5-5},
8+ population.llm.usd_cap: 2.0, population.llm.concurrency: 8}
9+cells:
10+ # --- A. dose–response in the share of LLM-controlled trader slots (single generalist prompt, one model) ---
11+ - {name: dose_000, overrides: {population.llm_share: 0.00}, treatment: {arm: dose, share: 0.00, model: gpt-5.4-nano, prompts: single}}
12+ - {name: dose_005, overrides: {population.llm_share: 0.05}, treatment: {arm: dose, share: 0.05, model: gpt-5.4-nano, prompts: single}}
13+ - {name: dose_010, overrides: {population.llm_share: 0.10}, treatment: {arm: dose, share: 0.10, model: gpt-5.4-nano, prompts: single}}
14+ - {name: dose_025, overrides: {population.llm_share: 0.25}, treatment: {arm: dose, share: 0.25, model: gpt-5.4-nano, prompts: single}}
15+ - {name: dose_050, overrides: {population.llm_share: 0.50}, treatment: {arm: dose, share: 0.50, model: gpt-5.4-nano, prompts: single}}
16+ - {name: dose_100, overrides: {population.llm_share: 1.00}, treatment: {arm: dose, share: 1.00, model: gpt-5.4-nano, prompts: single}}
17+ # --- B. diversity at 25 %: same model + diverse persona prompts; two-model mix (nano + mini) with diverse prompts ---
18+ - {name: div_prompts_025, overrides: {population.llm_share: 0.25, population.llm.prompt_set: diverse}, treatment: {arm: diversity, share: 0.25, model: gpt-5.4-nano, prompts: diverse}}
19+ - {name: div_models_025, overrides: {population.llm_share: 0.25, population.llm.prompt_set: diverse, population.llm.provider_mix: {openai: 0.5, openai_mini: 0.5}}, treatment: {arm: diversity, share: 0.25, model: mix-nano-mini, prompts: diverse}}
20+ # --- C. cognition channels at 25 %: bounded memory, communication channel, adaptive P&L feedback ---
21+ - {name: memory_025, overrides: {population.llm_share: 0.25, population.llm.memory: 5}, treatment: {arm: cognition, share: 0.25, memory: 5}}
22+ - {name: channel_025, overrides: {population.llm_share: 0.25, population.llm.channel: true}, treatment: {arm: cognition, share: 0.25, channel: true}}
23+ - {name: adaptive_025, overrides: {population.llm_share: 0.25, population.llm.adaptive_prompt: true}, treatment: {arm: cognition, share: 0.25, adaptive: true}}
24+ # --- D. interaction with leverage and safeguards at 25 % ---
25+ - {name: leverage_025, overrides: {population.llm_share: 0.25, population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.35, market_maker: 0.05, statarb: 0.0, leveraged: 0.19}}, treatment: {arm: leverage, share: 0.25, leveraged: 0.19}}
26+ - {name: breaker_025, overrides: {population.llm_share: 0.25, exchange.halt_threshold: 0.05}, treatment: {arm: safeguard, share: 0.25, breaker: 0.05}}
27+ - {name: poslimit_025, overrides: {population.llm_share: 0.25, exchange.position_limit: 300}, treatment: {arm: safeguard, share: 0.25, position_limit: 300}}
28+ # --- E. fairness: equal USD ≈ 25 % nano vs 5 % mini (mini costs ~5x per decision); matched latency ---
29+ - {name: fair_mini_005, overrides: {population.llm_share: 0.05, population.llm.provider_mix: {openai_mini: 1.0}}, treatment: {arm: fairness, share: 0.05, model: gpt-5.4-mini, prompts: single}}
30+ - {name: fair_latency_025, overrides: {population.llm_share: 0.25, population.latency.llm_latency: 0.05}, treatment: {arm: fairness, share: 0.25, llm_latency: 0.05}}
added configs/exploratory.yaml +18 −0
@@ -0,0 +1,18 @@
1+# Phase 5 pilot design — every cell first dry-run with the mock provider (this file), then live (pilot_openai.yaml).
2+name: exploratory_mock
3+base: baseline.yaml
4+seeds: {start: 1, n: 3}
5+overrides: {population.llm.provider_mix: {mock: 1.0}, population.llm.usd_cap: 0.0}
6+cells:
7+ - {name: share_0, overrides: {population.llm_share: 0.0}, treatment: {arm: dose, share: 0.0}}
8+ - {name: share_5, overrides: {population.llm_share: 0.05}, treatment: {arm: dose, share: 0.05}}
9+ - {name: share_25, overrides: {population.llm_share: 0.25}, treatment: {arm: dose, share: 0.25}}
10+ - {name: share_50, overrides: {population.llm_share: 0.50}, treatment: {arm: dose, share: 0.50}}
11+ - {name: diverse_25, overrides: {population.llm_share: 0.25, population.llm.prompt_set: diverse}, treatment: {arm: diversity, share: 0.25, prompts: diverse}}
12+ - {name: memory_25, overrides: {population.llm_share: 0.25, population.llm.memory: 5}, treatment: {arm: memory, share: 0.25, memory: 5}}
13+ - {name: channel_25, overrides: {population.llm_share: 0.25, population.llm.channel: true}, treatment: {arm: channel, share: 0.25, channel: true}}
14+ - {name: leverage_25, overrides: {population.llm_share: 0.25, population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.35, market_maker: 0.05, statarb: 0.0, leveraged: 0.19}}, treatment: {arm: leverage, share: 0.25, leveraged: 0.19}}
15+ - {name: breaker_25, overrides: {population.llm_share: 0.25, exchange.halt_threshold: 0.05}, treatment: {arm: safeguard, share: 0.25, breaker: 0.05}}
16+ - {name: poslimit_25, overrides: {population.llm_share: 0.25, exchange.position_limit: 300}, treatment: {arm: safeguard, share: 0.25, position_limit: 300}}
17+ - {name: auction_25, overrides: {population.llm_share: 0.25, exchange.call_auction_interval: 5}, treatment: {arm: mechanism, share: 0.25, auction: 5}}
18+ - {name: k2_25, overrides: {population.llm_share: 0.25, assets.n_assets: 2, fundamentals.mu: [50.0, 50.0], fundamentals.factor_loading: [0.7, 0.7], population.mix: {fundamentalist: 0.25, trend: 0.06, meanrev: 0.10, noise: 0.45, market_maker: 0.05, statarb: 0.05, leveraged: 0.04}}, treatment: {arm: contagion, share: 0.25, assets: 2}}
added configs/pilot_openai.yaml +10 −0
@@ -0,0 +1,10 @@
1+# Phase 5 live pilot (OpenAI only — the Anthropic key was rejected on 2026-10-27). Hard cap 5 USD.
2+name: pilot_openai
3+base: baseline.yaml
4+seeds: {start: 1, n: 3}
5+overrides: {population.llm.provider_mix: {openai: 1.0}, population.llm.models: {openai: gpt-5.4-nano, mock: mock-v1, anthropic: claude-haiku-5-5},
6+ population.llm.usd_cap: 1.5, population.llm.concurrency: 8}
7+cells:
8+ - {name: share_5, overrides: {population.llm_share: 0.05}, treatment: {arm: dose, share: 0.05, provider: openai, model: gpt-5.4-nano}}
9+ - {name: share_25, overrides: {population.llm_share: 0.25}, treatment: {arm: dose, share: 0.25, provider: openai, model: gpt-5.4-nano}}
10+ - {name: share_50, overrides: {population.llm_share: 0.50}, treatment: {arm: dose, share: 0.50, provider: openai, model: gpt-5.4-nano}}
added data/processed/.gitkeep +0 −0
added docs/DESIGN-BRIEF.md +59 −0
@@ -0,0 +1,59 @@
1+# Design brief — The Invisible Hand of Machines (UQO WP 27)
2+
3+Internal brief shared by the author and the sub-agents writing the literature review, theory and
4+pre-analysis plan. It describes what the simulator *actually* implements (src/market_agents).
5+
6+## Economy implemented in the simulator
7+- Discrete ticks t = 0..T-1 (T = 300–1000). One risky asset (optionally K = 2–5 with a common factor in
8+ dividend innovations) and cash. Prices in integer ticks (1 cent), quantities in integer lots, cash in
9+ integer cents; exact conservation checked after every fill.
10+- Dividend every `div_interval` = 20 ticks: D = mu_{s} + x + J, x_t = rho x_{t-1} + sigma eps_t (rho = 0.98,
11+ sigma = 2 cents, mu = 50 cents), optional two-state regime in mu (Markov), optional jumps.
12+ Latent fundamental value V_t = mu/r + x_t rho/(1+r-rho) with r = 0.25 % per period (so P/D ≈ 400,
13+ V ≈ 200.00). Public value V^pub_t = same formula on the Kalman/HMM posterior from announced dividends
14+ and public news. Agents never see V_t.
15+- Information: public news items (noisy reports of x_t, some deliberately biased = misleading);
16+ private signals s_i = x_t + N(0, sigma²/precision) for "informed" agents (fundamentalists and a share of
17+ LLM agents). No agent sees future draws.
18+- Exchange: continuous double auction, price–time priority, limit/market/cancel, partial fills, IOC
19+ market remainder, taker fee 2 bp, maker fee 0, per-agent latency in [0.05, 1] tick (orders arrive
20+ at decision time + latency and are processed in arrival order), order TTL 50 ticks, price band ±50 %,
21+ optional circuit breaker (halt when |10-tick move| > threshold), no short selling by default,
22+ leverage cap 3× for "leveraged" slots with maintenance margin 25 % and forced partial liquidation.
23+- Population (N = 100 / 1,000 / 10,000 trader slots): fundamentalists 25 % (30 % informed, precision 2),
24+ trend followers 15 %, mean-reverters 10 %, noise traders 35 %, market makers 5 % (bounded
25+ inventory-skewed two-sided quotes), leveraged trend followers 10 %, cross-asset arbitrageurs (multi-asset
26+ only). Endowments: cash 20,000 + 100 shares scaled by a lognormal wealth multiplier (sd 0.3).
27+- LLM treatment: a fraction `llm_share` of trader *slots* (stratified across policy types, never market
28+ makers) is replaced by an LLM policy that decides every 20 ticks (staggered offsets) from a canonical
29+ snapshot (book depth 5 levels, mid history, recent trades, last dividend, public PV, news, own private
30+ signal if any, own account and open orders). Output = strictly validated JSON (hold/place/cancel …).
31+ Invalid decisions = hold, logged. Realized LLM share of agents, orders and volume are all reported.
32+ Providers: OpenAI (Responses API, json_schema), Anthropic (Messages API, json_schema), mock (seeded
33+ rule with injected invalid answers). Treatments: provider mix, same vs diverse persona prompts,
34+ memory (0 vs 5 past decisions), communication channel (cohorts of 5 share rationales), adaptive
35+ P&L feedback, matched latency, equal token / USD / decision-opportunity budgets, frozen decision
36+ library replay vs online calls.
37+- Randomization: master seed → independent streams (fundamentals, news, slots, policy assignment, LLM
38+ slot assignment, activation, tie-breaks, per-agent RNG). Matched pairs across `llm_share` share
39+ every stream except the LLM slot draw. ≥ 30 seeds exploratory, power-based for confirmatory.
40+
41+## Stylized theoretical model (to be written up by the theory agent, must map to the above)
42+One-period, one asset, liquidation value v ~ N(0, σ_v²) around the public PV. N traders receive
43+s_i = v + ε_i with ε_i = η_{g(i)} + u_i, where g(i) is the trader's "model" (foundation model /
44+prompt family), η_g ~ N(0, σ_η²) iid across models, u_i ~ N(0, σ_u²) iid. A share φ_g of traders uses
45+model g (Σ_g φ_g ≤ 1; the remaining 1 − Σφ_g traders have fully idiosyncratic errors, i.e. their own
46+private model). Traders submit market orders x_i = β s_i (β > 0 a fixed response intensity; the
47+behavioral assumption mirrors rule-like LLM policies and is relaxed in a CARA extension). Noise
48+traders submit z ~ N(0, σ_z²). A competitive, risk-neutral market maker sets P = E[v | Y],
49+Y = Σ_i x_i + z, so P = λ Y with λ = Cov(v,Y)/Var(Y).
50+Objects: price informativeness τ = 1 − Var(v | Y)/σ_v²; pricing error Var(P − v); order-flow
51+correlation ρ_x = Corr(x_i, x_j); synchrony; effective number of models M_eff = 1/Σ_g φ_g²;
52+feedback extension with trend demand γ(P_1 − P_0) and amplification 1/(1 − λγ); leverage extension
53+with margin m, wealth W, impact λ: amplification 1/(1 − λ X/m) and spiral when λ X/m ≥ 1, where X is
54+the aggregate same-signed leveraged position (increasing in the shared-model share).
55+Hypotheses the simulator tests: H1 informativeness falls in the share using a single shared model
56+(holding information quality fixed) and rises in M_eff; H2 order-flow correlation and synchrony rise
57+in φ; H3 bubble/crash frequency and liquidity spirals rise with φ × leverage; H4 prompt/model
58+diversity restores part of the loss; H5 communication channels raise synchrony; H6 circuit breakers
59+and position limits cut crash depth at a cost in time-to-absorb.
added docs/assumptions.md +50 −0
@@ -0,0 +1,50 @@
1+# Assumption register — WP 27
2+
3+Version 1.0, 2026-10-27. Each row states the assumption *as implemented* in `src/market_agents`, its role, why it is acceptable for the research question, and the pre-specified check that probes it. Values are the defaults of `configs/baseline.yaml` unless noted. "Confirmatory base" refers to the overrides in `protocol.md` §5.1.
4+
5+## 1. Time, assets and fundamentals
6+
7+| ID | Assumption (as implemented) | Role | Justification | Robustness check |
8+|---|---|---|---|---|
9+| A1 | Discrete model time: 600 ticks, outcomes on t ≥ 100; no calendar mapping | Defines the horizon of every metric | Avoids false precision; 30 dividend periods suffice for ACF/VR estimates (≥ 500 returns) | `n_ticks` 1,000 on the control (free); report whether rankings of cells change |
10+| A2 | Dividend every 20 ticks: D = μ + x + J, x_t = 0.98 x_{t−1} + 2 ε_t (cents), μ = 50 c, r = 0.25 % per period; one asset by default | Fundamental process; V ≈ 200.00 and P/D ≈ 400 | Persistent, stationary cash-flow state with a closed-form PV (brief §Economy) | Sweep ρ ∈ {0.95, 0.98}, σ ∈ {1, 2, 4} on the control (free) |
11+| A3 | **"Efficient price" = full-information PV** V_t = μ/r + x_t·ρ/(1 + r − ρ), risk-neutral, constant discount rate, no risk premium | Benchmark for `msd_log`, `mad_pct`, bubbles, absorption | The only unambiguous benchmark in a simulated economy; the latent state is never shown to agents | Also report deviations from the *public* PV (`public_value`) and from the end-of-run mean price |
12+| A4 | Public PV = Kalman/HMM posterior on announced dividends; in the baseline (no jumps, one regime) the dividend reveals x_t exactly, so V^pub ≡ V | Information structure | Simplest case for calibration; **but it makes private signals redundant and H1 unidentified** | Confirmatory base uses noisy dividends (`jump_prob` 1, `jump_sigma` ≈ 4 c → SD(V^pub/V − 1) ≈ 0.5 %); both variants reported |
13+| A5 | No look-ahead: private signals s = x_t + N(0, σ²/precision) are about the *current* state; news reports x_t with noise; nobody sees future draws | Rules out mechanical information advantages | Standard in noisy rational-expectations settings | Unit test on the signal function; prompt audit (`prompting.py` builds only from `Observation`) |
14+| A6 | Shock: latent jump in x at t = 300 revealed through dividends/news; placebo at t = 450. Baseline size 40 c (+8.4 % on V); confirmatory size 10 c (+2.1 %) | Event-study outcomes (`time_to_absorb`, `response_ratio`, local projections) | A sub-threshold (< 5 %) jump so that a lagged response is not counted as a bubble; placebo for falsification | Sizes 10/20/40 c on the control; `news_burst` variant |
15+
16+## 2. Market mechanism
17+
18+| ID | Assumption | Role | Justification | Robustness check |
19+|---|---|---|---|---|
20+| A7 | Continuous double auction, price–time priority, limit/market/cancel, partial fills, IOC remainder of market orders, integer ticks (1 c) and lots | Price formation; no Walrasian auctioneer and no imposed equilibrium | Matches modern electronic markets; prices emerge from order matching | `call_auction_interval` = 5 (batch clearing with a 2 % collar), mock only |
21+| A8 | Per-agent latency U[0.05, 1] tick, fixed for the run; orders processed in arrival order; LLM agents draw latency like others | Removes a speed advantage from either population | Speed is not the object of study | `latency.llm_latency` matched-latency variant |
22+| A9 | Fees: taker 2 bp, maker 0, no rebates; fees leave the economy; exact cash/share conservation asserted after every fill | Transaction costs; accounting integrity | Low explicit costs so that spreads are endogenous | Taker 0 and 5 bp on the control |
23+| A10 | Order TTL 50 ticks; price band ±50 % of the reference; max order 10,000 lots (policies cap at 40–50) | Keeps books finite and prices bounded | Prevents stale quotes and absurd limit prices | TTL 20 / 100 on the control |
24+| A11 | No short selling by default; buys limited by free cash (reserved for resting buys) | Budget constraint; asymmetry between buying and selling | Retail-like constraint; makes the no-short assumption explicit for H3 | `allow_short` with `max_short_lots` 100 on the control and at φ = 0.25 (mock) |
25+| A12 | Leverage only for "leveraged" slots: cap 3× gross/equity, maintenance margin 25 %, forced sale of 50 % by market order on the next tick, bankrupt agents frozen | The leverage channel of H3 (spiral when λX/m ≥ 1) | Mirrors margin trading with mechanical liquidation | Cap 2×/5×; maintenance 15 %/35 % (free at φ = 0, live only in the T4 leverage cell) |
26+| A13 | Safeguards off by default; treatments: halt when |10-tick move| > 5 % for 20 ticks with resting orders cancelled; position limit 300 lots | H6 | Simple, transparent rules | Halt 3 %/8 %; limit 150/600 (mock) |
27+| A14 | Market making by 5 bounded inventory-skewed two-sided quoters (half-spread 8 ticks + volatility term, skew 2 % at 200 lots), endowed ×5, never replaced by LLM agents | Liquidity supply; spread floor ≈ 8 bp | Keeps a stable liquidity benchmark across cells so liquidity changes come from the treated population | `quote_qty` 10/20 and `liquidity` shock (makers withdraw) on the control |
28+
29+## 3. Agents
30+
31+| ID | Assumption | Role | Justification | Robustness check |
32+|---|---|---|---|---|
33+| A15 | **No rationality or equilibrium assumption**: classical agents are documented heuristics (fundamentalist with signal-weighted value, EMA trend, z-score mean reverter, zero-intelligence-plus noise, leveraged trend); LLM agents do whatever the model outputs | Defines the "human-like" baseline | The brief's theory (β-response traders) is a stylization; the simulator tests directional claims, not point predictions | Calibration sweep (360 runs) shows the stylized facts are robust to aggressiveness, trend share, market-order share |
34+| A16 | Mix 25/15/10/35/5/10 % (fundamentalist/trend/meanrev/noise/MM/leveraged), stratified by wealth; endowment 20,000 + 100 shares × lognormal(0.3) | Population composition | Common in ABM calibrations; 50/50 cash–stock endowment at V | Trend share 10–25 % in the sweep; `wealth_dispersion` 0/0.6 |
35+| A17 | Decision frequency: classical activation Bernoulli(0.2–0.5) per tick; LLM agents decide every 20 ticks with staggered offsets, from t = 50 | Event frequency vs decision frequency | API cost; one decision per dividend period is a defensible "slow trader" | Realized order/volume shares always reported (mock: 3.5 % / 8 % at φ = 0.25); `decision_interval` 10 (mock) |
36+| A18 | Information: 30 % of fundamentalists informed (precision 2 → signal SD 1.4 c); after the gate-4 fix an LLM slot inherits the status of the slot it replaces | Holds information quality fixed across arms (H1's premise) | Otherwise the treatment bundles policy and information (mock: 44 % vs 6 % informed) | Report `stratum` composition of LLM slots per cell; variant with `llm.informed_share` 0 |
37+| A19 | Stratified replacement: proportional quotas by classical type, market makers excluded → 95 eligible slots, so φ = 1 means 95 % | Dose definition | Keeps composition of the *replaced* population constant along the dose | `llm_replace: noise` (replace one type only) at φ = 0.25 (mock) |
38+| A20 | LLM observation = canonical snapshot (5 levels of depth, 60-tick mid history, 30 recent trades, last dividend, public PV, ≤ 3 news items, own signal, account, open orders); personas single ("generalist") or 8 diverse; memory 0/5; channel = last 5 rationales of a cohort | What the model can condition on | Identical information set to the classical agents' `Observation` | Prompt audit; prompt version frozen (v1) |
39+| A21 | Invalid or infeasible decisions become `hold` (quantity, ±20 % price window, cash/holdings, owned cancel ids); sells clipped to holdings | Reliability rule; ITT estimand | A deployed agent that fails holds | Validity reported per cell; cells < 80 % flagged |
40+| A22 | Provider sampling is not seeded; cached responses replay exactly; the frozen library is a nearest-neighbour map, not an agent | Reproducibility | Only option with current APIs | Cache-hit share and online/replay flag per run; library distance diagnostics |
41+| A23 | Equal decision opportunities across models by default (27 per agent); equal-USD via per-run `usd_cap` (single-provider cells) | Fairness of cross-model comparisons | Decision opportunities, not tokens, are the economically relevant unit | T5 fairness cell |
42+
43+## 4. Measurement
44+
45+| ID | Assumption | Role | Justification | Robustness check |
46+|---|---|---|---|---|
47+| A24 | Mid-price is the price; metrics use the mid (fallback in `engine.mid_ticks` when one side is empty); effective spread uses the start-of-tick mid | All price-based outcomes | Standard; avoids bid–ask bounce | Also compute `msd_log` on last trade prices |
48+| A25 | Bubble = |P/V − 1| > 5 % for ≥ 10 ticks; crash = drop ≥ 10 % from the trailing 20-tick max; `time_to_absorb` tolerance 1 % for 5 ticks, censored at 100 | Instability and absorption outcomes | Pre-specified; the 10 % crash rule has a floor effect in the control (0 crashes) | Grid bubble 3/5/8 %, crash 7/10/15 %, computed on saved ticks |
49+| A26 | Coordination measured among LLM agents only (sign correlation in 20-tick windows; synchrony per decision round) | H2/H5 | Only LLM decisions are logged with intent | Classical analogue from aggressor-signed trades (analysis stage) |
50+| A27 | Multi-asset: common factor 0.7 in innovations; LLM prompt covers asset 0 only | Contagion arm | Keeps the prompt single-asset (cost, validity) | Report that spillover runs from the LLM-traded asset to the classical-only asset |
added docs/identification.md +191 −0
@@ -0,0 +1,191 @@
1+# Identification and pre-analysis plan — WP 27
2+
3+Version 1.0, 2026-10-27, written before any live API call. Everything in §3–§6 is frozen after the pilot (§6.2); changes afterwards are logged as deviations in the paper.
4+
5+## 1. Causal structure
6+
7+### 1.1 Variables
8+
9+- **Z — treatment (cell labels)**: `llm_share` φ ∈ {0, …, 1}; provider/model mix (`provider_mix`, `models`); `prompt_set` ∈ {single, diverse}; `memory` ∈ {0, 5}; `channel` ∈ {off, on}; leverage (share of leveraged slots, `leverage_cap`); safeguards (`halt_threshold`, `position_limit`); fairness regime (`decision_cap`, `usd_cap`). A cell is a vector of these.
10+- **U — exogenous randomness, by named seed stream** (`utils/rng.py`): `fundamentals` (dividend path, jumps), `news`, `slots` (wealth multipliers, latencies, informed draws), `assign` (classical policy of each slot), `llm_assign` (which eligible slots become LLM, provider allocation, decision offsets), `activation`, `tiebreak`, and per-agent generators `agent_rng(seed, id)` (classical policy randomness, private-signal noise).
11+- **ε — provider noise**: the LLM's sampling randomness, not seeded and not controllable (gpt-5 family rejects `temperature`; no seed parameter). It is part of the treatment.
12+- **M — within-run mediators** (`outcomes.py`): order-flow correlation ρ̄ = `llm_pairwise_corr`, synchrony = `llm_synchrony`, aggressiveness β̂ = `llm_market_share` (share of market orders) and mean order size, validity = `llm_valid_rate`, realized dose = `llm_share_orders`, `llm_share_volume`.
13+- **Y — run-level outcomes** (§3).
14+
15+### 1.2 DAG
16+
17+```
18+ U_fund, U_news ───────────────────────────────────────────┐
19+ U_slots, U_assign, U_agents ───────────────┐ │
20+ │ │
21+ cell label ─────► Z ───┐ ▼ ▼
22+ ├──► LLM slot set & policies ──► M (ρ̄, synchrony, β̂, validity, realized dose) ──► Y
23+ U_llm_assign ──────────┘ ▲ ▲ ▲
24+ │ │ │
25+ ε_provider ─────────────────────────┴─────────────────────┘ │
26+ U_activation, U_tiebreak ───────────────────────────────────────────────────────────────────────────────┘
27+ Z ──────────────────────────────────────────────────────────────────────────────────────────────────────┘ (direct: fewer heuristic agents, halts, limits)
28+```
29+
30+Z → Y is identified because Z is set by the design file and the only random input that depends on Z (`llm_assign`) is independent of every other stream by construction (`SeedSequence.spawn`). Fundamentals, news, endowments, latencies, information draws and policy assignment are *identical* across cells sharing a seed; the treatment replaces the policy in a stratified subset of slots and nothing else. Slot replacement is stratified by classical policy type (proportional quotas, market makers never replaced).
31+
32+Two leaks of common random numbers exist in the current code and must be closed before the pilot (gate 4 in `research_plan.md`): (i) the per-tick shuffle of active classical agents consumes the `activation` stream, whose length depends on the number of classical agents, so activation draws differ across arms after tick 0; (ii) an LLM slot draws its informed status from `llm.informed_share` (30 %) instead of inheriting it from the replaced slot, so the treatment arm holds more private information than the control (in a mock run, 44 % vs 6 % informed). Neither leak biases the ATE (Z is still randomized), but (ii) changes the *estimand* to "LLM policy + extra information" and (i) reduces the precision gain from pairing.
33+
34+### 1.3 Confounders ruled out by design
35+
36+| Potential confounder | Why it cannot confound Z → Y |
37+|---|---|
38+| Fundamental path, shocks, news | Same `fundamentals`/`news` streams within a seed; shocks at fixed ticks in every cell |
39+| Endowments, wealth dispersion, latencies | Same `slots` stream; LLM slots keep the replaced slot's cash, shares and latency |
40+| Composition of classical types | `assign` stream fixed; replacement stratified by type |
41+| Private information | After the gate-4 fix, inherited from the replaced slot |
42+| Market-maker behaviour | Market makers never replaced (`llm_keep_market_makers`) |
43+| Code/version drift | `config_hash`, `git_revision`, `prompt_version`, price table recorded in every manifest |
44+
45+### 1.4 What is *not* identified
46+
47+- **Mediation.** M is generated inside the run jointly with Y by the same path of U and ε. Sequential ignorability (M ⫫ Y(z, m) | Z, covariates) does not hold: e.g. a volatile fundamental path raises both ρ̄ and `msd_log`. We therefore report mediation only as a *descriptive decomposition* (§4.6) and treat each M as an **outcome** of Z (that is H2 and is identified).
48+- **Effects of the model's reasoning per se.** Z bundles the model, the prompt, the decision frequency and the invalid-decision rule. The estimand is intention-to-treat: "deploy this agent as configured".
49+
50+## 2. Estimands
51+
52+Unit = run (seed s × cell z). Y_s(z) is the potential outcome of seed s under cell z.
53+
54+| Label | Estimand | Contrast |
55+|---|---|---|
56+| E1 | ATE of cell z vs control: τ_z = E_s[Y_s(z) − Y_s(0)] | Each treated cell vs `share_0` of the same seed |
57+| E2 | Dose–response: τ(φ) for φ ∈ {0.01, 0.05, 0.10, 0.25, 0.50, 0.75, 1.00} with gpt-5.4-nano, single prompt; linear slope ∂τ/∂φ and ordered-trend test | Levels vs 0 and across levels |
58+| E3 | Diversity at equal share φ: (a) τ_div = E[Y(diverse, φ) − Y(single, φ)]; (b) τ_mix = E[Y(mix, φ) − ½(Y(nano, φ) + Y(mini, φ))] | (a) prompt diversity holding the model fixed; (b) model diversity net of composition (requires the mini-only cell) |
59+| E4 | Mechanism arms at φ = 0.25: memory 5 vs 0; channel on vs off; leverage high vs base; breaker vs none; position limit vs none | Each vs `share_25` |
60+| E5 | φ × leverage interaction: [Y(φ, lev_hi) − Y(0, lev_hi)] − [Y(φ, lev_base) − Y(0, lev_base)] | Difference of paired differences |
61+| E6 | Local projection of the mid–value gap around the t = 300 fundamental jump: β_h = E[g_s(z, h) − g_s(0, h)], g = log P − log V, h ∈ [−20, 100]; placebo at t = 450 | Treated vs control path |
62+| E7 | Realized-dose-scaled effect: τ_z / E[`llm_share_orders`] (descriptive, not causal per unit of order flow) | Reported alongside E1 |
63+
64+Primary confirmatory contrast: **E1 at φ = 0.25** (gpt-5.4-nano, single prompt, confirmatory fundamentals); secondary confirmatory: E1 at φ = 0.50 and E3(a). Everything else is exploratory unless the tiered budget allows the pre-specified seed count (`protocol.md` §5).
65+
66+## 3. Outcomes
67+
68+All variables are produced by `metrics/outcomes.py` on ticks t ≥ `warmup` = 100 (baseline.yaml), one row per run in `outcomes.parquet`. Multi-asset variants carry the suffix `_a1` for asset 1.
69+
70+### 3.1 Primary families and directional hypotheses
71+
72+| Family | Variable | Definition (short) | Direction under H | Hypothesis |
73+|---|---|---|---|---|
74+| Efficiency | `msd_log` **(lead H1, H4)** | mean (log P − log V)² | ↑ in φ; ↓ with diversity | H1, H4 |
75+| | `mad_pct` | mean 100·|log P − log V| | ↑ in φ | H1 |
76+| | `time_to_absorb` | first h after t = 300 with |P/V − 1| < 1 % for 5 ticks (censored at 100) | ↑ in φ; ↑ with safeguards | H1, H6 |
77+| | `response_ratio` | (P_{t+20} − P_{t−1}) / (V_{t+20} − V_{t−1}) | |RR − 1| ↑ in φ (two-sided on RR) | H1 |
78+| | `vr5` | VR(5) of log mid | |VR − 1| ↑ in φ (two-sided on VR) | H1 |
79+| Liquidity | `spread_bp` **(lead H1b)** | mean quoted spread / mid, bp | ↑ in φ | H1b |
80+| | `eff_spread_bp` | 2·|trade − pre-trade mid| / mid, bp | ↑ in φ | H1b |
81+| | `depth5` | mean lots within 5 levels, both sides | ↓ in φ | H1b |
82+| | `lambda_bp_100` | OLS of Δlog mid (bp) on signed volume / 100 | two-sided (theory: λ = Cov/Var falls as flow gets noisier) | H1b |
83+| | `resiliency` | half-life (ticks) of log-spread deviations | ↑ in φ | H1b |
84+| Instability | `n_crashes` **(lead H3)** | drops ≥ 10 % from the trailing 20-tick max | ↑ in φ × leverage | H3 |
85+| | `max_dd` **(lead H6)** | max drawdown of mid | ↑ in φ; ↓ with safeguards | H3, H6 |
86+| | `n_bubbles`, `bubble_amp` | episodes with |P/V − 1| > 5 % for ≥ 10 ticks; max amplitude | ↑ in φ × leverage | H3 |
87+| | `acf_absr_1_10` | Σ ACF(|r|) lags 1–10 | ↑ in φ | H3 |
88+| | `kurtosis` | excess kurtosis of tick returns | ↑ in φ | H3 |
89+| Coordination | `llm_pairwise_corr` **(lead H2)** | mean pairwise corr. of agents' net order sign per 20-tick window | ↑ in φ; ↓ with diversity | H2, H4 |
90+| | `llm_synchrony` **(lead H5)** | mean |mean sign| per decision round | ↑ with channel | H2, H5 |
91+| Contagion (K = 2) | `ret_corr`, `excess_comovement` **(lead)**, `spillover_dy` | return correlation; minus fundamental correlation; Diebold–Yilmaz total spillover (VAR(2), h = 10) | ↑ in φ | H2/H3 extension |
92+
93+Thresholds are fixed: bubble 5 % for ≥ 10 ticks; crash 10 % within 20 ticks. **Sensitivity grid** (reported for every instability result, no re-selection): bubble ∈ {3, 5, 8} %, crash ∈ {7, 10, 15} %. In the classical control (10 seeds) `n_crashes` = 0 at 10 %: a floor effect is expected and the 7 % variant is the pre-specified fallback for H3 (§`research_plan.md` §4).
94+
95+Transformations fixed in advance: `msd_log` is analysed on log10 scale for t-based inference (strongly right-skewed: control mean 0.0020, SD 0.0017); `time_to_absorb` is censored at 100 and analysed with rank-based inference; counts (`n_bubbles`, `n_crashes`, `n_halts`) by mean difference with randomization inference.
96+
97+### 3.2 Secondary outcomes
98+
99+`vol_bp`, `bias_pct`, `vr10`, `acf_r_1`, `bubble_dur`, `volume`, `turnover`, `cancel_ratio`, `fill_ratio`, `reject_ratio`, `n_halts`, `share_ticks_halted`, `pnl_<policy>` (incl. `pnl_llm`), `mm_pnl`, `mm_inventory_abs`, `gini_final`, `n_bankrupt`, `leadlag_01`, `fund_corr`, and the LLM diagnostics `llm_valid_rate`, `llm_hold_rate`, `llm_market_share`, `llm_buy_share`, `llm_usd`, `llm_tokens`, `llm_latency_s`, `llm_cached_hits`, plus the manifest fields `llm_share_orders`, `llm_share_volume`, `n_llm_decisions`.
100+
101+### 3.3 Known measurement caveats
102+
103+- `llm_synchrony` groups decisions by tick; with staggered offsets only agents sharing an offset are in the same round (≈ n_llm/20 per tick), so at φ ≤ 0.05 it rests on very few rounds. `llm_pairwise_corr` (20-tick windows) is the preferred coordination measure at low φ.
104+- Both coordination measures exist only for LLM agents, so they are undefined in the control; H2 is tested as a dose–response among φ > 0 plus a comparison with a classical analogue (§3.4).
105+- In multi-asset runs the prompt covers asset 0 only (`user_message(obs, 0)`): LLM agents never trade asset 1, so contagion is measured from the LLM-traded asset to a classical-only asset.
106+
107+### 3.4 Analysis-stage additions (to be coded in `analysis/`, not in `outcomes.py`)
108+
109+Classical analogue of ρ̄: the same `pairwise_sign_corr` applied to classical agents' aggressor-signed trades from `trades.parquet`, by policy type. Local-projection paths (E6) from `ticks.parquet`.
110+
111+## 4. Estimators
112+
113+### 4.1 Paired differences (primary)
114+
115+For each cell z and seed s: Δ_s = Y_s(z) − Y_s(0). Report mean Δ̄, SD, paired-t 95 % CI (df = n − 1) and the effect size d_z = Δ̄ / SD(Δ). Also Glass's Δ = Δ̄ / SD(Y(0)) using 30 free control seeds, for comparability across cells.
116+
117+### 4.2 Randomization inference (primary p-value)
118+
119+Under the sharp null Y_s(z) = Y_s(0), the sign of each Δ_s is exchangeable within its pair. P-value = share of the 2ⁿ sign-flip assignments with |mean Δ| ≥ |observed| (exact enumeration for n ≤ 14; 10⁵ Monte Carlo draws otherwise). This is distribution-free and valid for counts, censored and skewed outcomes at small n. The paired t (§4.1) and Wilcoxon signed-rank are reported as secondary.
120+
121+### 4.3 OLS with seed fixed effects (dose–response and multi-cell arms)
122+
123+Y_{s,z} = α_s + Σ_k τ_k 1[z = k] + ε_{s,z}. With ≤ 12 clusters, cluster-robust SE by seed are unreliable; inference uses the wild cluster bootstrap (Rademacher weights, 9,999 draws, cluster = seed) and, for ordered φ, **Page's L trend test** for randomized blocks (block = seed). The linear slope ∂τ/∂φ is reported with a bootstrap CI; the dose–response figure shows cell means with paired CIs.
124+
125+### 4.4 Diversity contrasts
126+
127+E3(a): paired difference diverse − single within seed. E3(b): τ_mix,s = Y_s(mix) − ½[Y_s(nano) + Y_s(mini)], then §4.1–4.2.
128+
129+### 4.5 Multiplicity, CIs, effect sizes
130+
131+Holm–Bonferroni within each hypothesis family of §3.1 at family-wise α = 0.05 (the lead outcome is reported adjusted and unadjusted). Two-sided tests; the sign of the estimate is compared with the predicted direction. 95 % CIs everywhere; no result is reported as a bare p-value. Secondary outcomes are unadjusted and labelled exploratory.
132+
133+### 4.6 Mediation (descriptive only)
134+
135+Within treated cells, regress Y on M with seed FE and cell dummies; report the coefficient and the share of τ_z "associated" with M (product-of-coefficients with the Z → M regression). Stated assumption: this is a decomposition under *no unmeasured mediator–outcome confounding*, which §1.4 argues is false; the numbers describe co-movement, not causal paths.
136+
137+### 4.7 Local projections (E6)
138+
139+For h ∈ [−20, 100]: g_s(z, h) = log P_{300+h} − log V_{300+h}. β_h = mean over seeds of g_s(z, h) − g_s(0, h), with pointwise paired-t bands and a sup-t band from the bootstrap. The same at the placebo tick 450 must show β_h ≈ 0 (falsification). Summary scalars: `time_to_absorb`, `response_ratio`.
140+
141+## 5. Power and seed counts
142+
143+Paired design, standardized paired effect d = Δ̄ / SD(Δ), two-sided α = 0.05, power 0.80:
144+
145+n ≈ (z_{0.975} + z_{0.80})² / d² = (1.960 + 0.842)² / d² = 7.85 / d²
146+
147+| d | n (pairs) |
148+|---|---|
149+| 0.5 | 32 |
150+| 0.8 | 13 |
151+| 1.0 | 8 |
152+| MDE at n = 10 | 0.89 |
153+| MDE at n = 8 | 0.99 |
154+
155+σ_d (the SD of paired differences) is **TBD from the pilot** (3 pairs per share; a poor estimate — the 30-seed classical control SD is used as a floor: e.g. SD(`msd_log`) = 0.0017, SD(`spread_bp`) = 6.4, SD(`max_dd`) = 0.042 in the default calibration cell, n = 10). Rule for the confirmatory seed count of the primary contrast: n_conf = max(8, ⌈7.85 σ̂_d² / Δ_min²⌉) with Δ_min = 0.5 σ̂_d (i.e. 32), **capped by the tier budget** (`protocol.md` §5: 10 seeds at 25 % and 50 % ≈ 10 USD). The achieved MDE is reported in the paper; detecting d = 0.5 on the primary contrast would require ≈ 32 USD for that contrast alone and is only done if extra budget is approved before unblinding. Classical-only cells cost nothing and use 30 seeds.
156+
157+## 6. Stopping rules, freeze, negative results
158+
159+### 6.1 Stopping rules
160+
161+- Pilot stops at 5 USD (hard `usd_cap`), or if provider failure rate > 10 %, or validity < 80 %; the prompt is then revised once (v2), re-dry-run with the mock, re-piloted on one seed.
162+- Confirmatory: tiers run in the fixed order of `protocol.md` §5; no interim efficacy looks; spend reconciled after each tier against the plan; a tier is complete only when every cell has the same seeds (unbalanced seeds are dropped from all cells of the tier). The 40 USD cap is enforced by per-run `usd_cap` and by the running total.
163+
164+### 6.2 Frozen after the pilot
165+
166+Prompt v1 text (`prompting.py` SHA) and schema; `configs/baseline.yaml` plus the confirmatory overrides (fundamentals with latent uncertainty, shock size) and their `config_hash`; cell list and seed lists (pilot seeds 1–3, confirmatory seeds from 101; pilot runs are *not* pooled into confirmatory estimates); outcome definitions (`outcomes.py` SHA), thresholds and sensitivity grid; estimators of §4; tier budgets; model snapshots and price table; the git revision. A freeze record is written to `results/manifests/freeze.json`.
167+
168+### 6.3 What counts as a negative result
169+
170+For a lead outcome with predicted sign: (i) *refuting*: CI of d excludes d ≥ 0.5 in the predicted direction; (ii) *no large effect*: CI contains 0 and excludes |d| ≥ MDE; (iii) *inconclusive*: CI contains both 0 and the MDE — reported as such, never as "no effect". Secondary outcomes cannot rescue a refuted lead.
171+
172+## 7. Threats to validity
173+
174+### 7.1 Internal (inside the simulator)
175+
176+| Threat | Consequence | Handling |
177+|---|---|---|
178+| Provider non-determinism (no seed; `temperature` unsupported on gpt-5) | Same seed ≠ same LLM decisions across repeated online runs | Every response cached with request id; replay from cache is exact; ε treated as part of the treatment variance; online-vs-replay flag `llm_cached_hits` reported |
179+| Cache replay across cells | Identical prompts (e.g. first decision at t = 50) hit the cache across cells — desirable CRN, but mixes online and replayed decisions | Report cache hit share per cell; cache key includes provider, model, prompt version and full prompt text |
180+| Invalid-decision handling (→ hold) | Validity differs by model; "hold" is a one-sided failure | ITT estimand; `llm_valid_rate` reported as outcome; cells with validity < 80 % flagged; no per-protocol rerun |
181+| Decision interval (20 ticks) vs classical activation (0.2–0.5 per tick) | Realized order share ≪ slot share (mock: 3.5 % of orders, 8 % of volume at φ = 0.25) | Report assigned and realized dose; E7; `decision_interval` = 10 sensitivity with the mock |
182+| Exact-revelation fundamentals in the baseline | V^pub ≡ V; private signals redundant; H1 unidentified | Confirmatory fundamentals: noisy dividends (`jump_prob` = 1, `jump_sigma` TBD ≈ 4 c → SD(V^pub/V − 1) ≈ 0.5 %) |
183+| Shock size (+8.4 % at 40 c) exceeds bubble threshold | Lagged adjustment counted as a bubble | Shock ≈ 10 c (+2.1 %) |
184+| Information-parity leak and activation-stream leak (§1.2) | Estimand drift; precision loss | Gate-4 fixes before the pilot |
185+| Budget halt mid-run (`halted_for_budget`) | Remaining decisions become hold | Per-run `usd_cap` set ≥ 2× expected spend; halted runs excluded and rerun |
186+| Model drift between pilot and confirmatory | Different behaviour over weeks | Confirmatory calls within a short window; model id and date in manifest |
187+| Frozen library (nearest-neighbour replay, k = 5) | Not an adaptive agent; distribution shift at N = 1,000 | Labelled provider `library`; used only for scale and cached-vs-online arms; hit distance diagnostics reported |
188+
189+### 7.2 External
190+
191+Simulated heuristic traders and prompted LLM agents are not institutions: no risk management, no regulation, no learning across runs (memory ≤ 5 own decisions), one asset at a time in the prompt, model time without calendar mapping, fees and latencies stylized. Effects are statements about *this* market mechanism and *these* model snapshots; magnitudes do not transfer, signs and dose–response shapes may.
added docs/literature_ledger.md +212 −0
@@ -0,0 +1,212 @@
1+# Literature ledger — WP 27 "The Invisible Hand of Machines"
2+
3+Claim-to-citation ledger. Every row was verified on 2026-10-27 against Crossref (`https://api.crossref.org/works/<DOI>`), the arXiv API / abstract page, or the publisher page named in the column. Bib keys match `paper/references.bib`. Items that could not be verified are listed at the end and are **not** in the bib file.
4+
5+
6+## (a) Agent-based computational economics and heterogeneous-agent models
7+
8+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
9+|---|---|---|---|---|---|---|---|
10+| 1 | A001 | Agent-based computational finance reproduces fat tails, volatility clustering and bubbles from interacting heterogeneous rules; survey we build on for the baseline rule-based population. | `lebaron2006` | 10.1016/S1574-0021(05)02024-1 | 2006 | Crossref (title/authors/venue matched) | 2026-10-27 |
11+| 2 | A002 | The Santa Fe artificial stock market shows that the speed of belief updating governs whether prices track fundamentals or display excess volatility and technical-trading regimes. | `lebaron1999` | 10.1016/S0165-1889(98)00081-5 | 1999 | Crossref (title/authors/venue matched) | 2026-10-27 |
12+| 3 | A003 | Interacting noise traders switching between optimistic/pessimistic and fundamentalist states generate scaling laws and clustered volatility endogenously. | `lux1999` | 10.1038/17290 | 1999 | Crossref (title/authors/venue matched) | 2026-10-27 |
13+| 4 | A004 | Volatility clustering arises from endogenous switching between chartist and fundamentalist strategies in a microsimulation. | `lux2000` | 10.1142/S0219024900000826 | 2000 | Crossref (title/authors/venue matched) | 2026-10-27 |
14+| 5 | A005 | Adaptive belief systems with discrete-choice switching between predictors produce complex (bifurcating) price dynamics as intensity of choice rises. | `brock1997` | 10.2307/2171879 | 1997 | Crossref (title/authors/venue matched) | 2026-10-27 |
15+| 6 | A006 | Fundamentalist/chartist heterogeneous-beliefs asset-pricing model: the share of trend-followers determines stability of the fundamental price (used to motivate our policy mix). | `brock1998` | 10.1016/S0165-1889(98)00011-6 | 1998 | Crossref (title/authors/venue matched) | 2026-10-27 |
16+| 7 | A007 | Simulated double-auction microstructure with fundamentalist, chartist and noise traders reproduces order-book stylized facts; template for our exchange design. | `chiarella2002` | 10.1088/1469-7688/2/5/303 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
17+| 8 | A008 | Heterogeneous trading rules in a limit-order book generate fat tails, volatility clustering and order-flow autocorrelation; chartist share drives excess volatility. | `chiarella2009` | 10.1016/j.jedc.2008.08.001 | 2009 | Crossref (title/authors/venue matched) | 2026-10-27 |
18+| 9 | A009 | Agent-based models are the appropriate tool for studying out-of-equilibrium market dynamics and policy counterfactuals that cannot be solved analytically. | `farmer2009` | 10.1038/460685a | 2009 | Crossref (title/authors/venue matched) | 2026-10-27 |
19+| 10 | A010 | Survey of heterogeneous-agent models: strategy switching and bounded rationality explain bubbles, crashes and excess volatility. | `hommes2006` | 10.1016/S1574-0021(05)02023-X | 2006 | Crossref (title/authors/venue matched) | 2026-10-27 |
20+| 11 | A011 | Complex-systems view of behavioral macro/finance: laboratory and ABM evidence that expectations heterogeneity drives aggregate instability; justifies treating LLM policies as another expectation type. | `hommes2021` | 10.1257/jel.20191434 | 2021 | Crossref (title/authors/venue matched) | 2026-10-27 |
21+| 12 | A012 | Recruitment/epidemic models of opinion switching generate persistent herding states without any informational reason. | `kirman1993` | 10.2307/2118498 | 1993 | Crossref (title/authors/venue matched) | 2026-10-27 |
22+| 13 | A013 | Herd behaviour among speculators generates bubbles and crashes in a mean-field model of contagious optimism. | `lux1995` | 10.2307/2235156 | 1995 | Crossref (title/authors/venue matched) | 2026-10-27 |
23+| 14 | A014 | Current state of agent-based modeling in economics and finance (JEL survey): validation, calibration and scale are the open frontiers our design addresses with matched seeds and power analysis. | `axtell2025` | 10.1257/jel.20221319 | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
24+| 15 | A015 | Structural stochastic volatility models with herding (fundamentalist/chartist switching) can be estimated by matching moments of stylized facts; we use the same moment set for validation. | `franke2012` | 10.1016/j.jedc.2011.10.004 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
25+
26+## (b) Zero-intelligence, double-auction microstructure and information aggregation
27+
28+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
29+|---|---|---|---|---|---|---|---|
30+| 16 | B016 | Zero-intelligence traders constrained by budgets reach near-full allocative efficiency in double auctions: market structure, not trader rationality, drives efficiency (our ZI baseline). | `gode1993` | 10.1086/261868 | 1993 | Crossref (title/authors/venue matched) | 2026-10-27 |
31+| 17 | B017 | A zero-intelligence model of the continuous double auction predicts spread and price-impact relations from order-flow rates alone. | `farmer2005` | 10.1073/pnas.0409157102 | 2005 | Crossref (title/authors/venue matched) | 2026-10-27 |
32+| 18 | B018 | Statistical theory of the continuous double auction: order-flow parameters determine spread, depth and price diffusion in the ZI limit. | `smith2003` | 10.1088/1469-7688/3/6/307 | 2003 | Crossref (title/authors/venue matched) | 2026-10-27 |
33+| 19 | B019 | Empirical statistics of stock order books (limit-order placement distribution, book shape) used as reference facts for our simulated book. | `bouchaud2002` | 10.1088/1469-7688/2/4/301 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
34+| 20 | B020 | Stochastic order-book model with Markovian order flow: conditional probabilities of price moves computed from book state; benchmark for our book-state features. | `cont2010` | 10.1287/opre.1090.0780 | 2010 | Crossref (title/authors/venue matched) | 2026-10-27 |
35+| 21 | B021 | Order-flow imbalance (OFI) linearly predicts short-horizon price changes; we use OFI as a mechanism metric for synchronized LLM order flow. | `cont2014` | 10.1093/jjfinec/nbt003 | 2014 | Crossref (title/authors/venue matched) | 2026-10-27 |
36+| 22 | B022 | Reference treatment of order-book dynamics, price impact and the slow digestion of order flow; defines the impact and liquidity measures we report. | `bouchaud2018` | 10.1017/9781316659335 | 2018 | Crossref (title/authors/venue matched) | 2026-10-27 |
37+| 23 | B023 | Survey of limit-order-book models and empirical regularities used to parametrize the exchange. | `gould2013` | 10.1080/14697688.2013.803148 | 2013 | Crossref (title/authors/venue matched) | 2026-10-27 |
38+| 24 | B024 | Review of zero-intelligence models in economics and finance: ZI benchmarks isolate the contribution of market structure from agent intelligence. | `ladley2012` | 10.1017/s0269888912000173 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
39+| 25 | B025 | Continuous double auctions with induced values converge to competitive equilibrium with few traders; origin of the experimental double-auction paradigm. | `smith1962` | 10.1086/258609 | 1962 | Crossref (title/authors/venue matched) | 2026-10-27 |
40+| 26 | B026 | Experimental asset markets with known dividend streams produce bubbles and crashes; our dividend-paying asset and bubble metrics follow this design. | `smith1988` | 10.2307/1911361 | 1988 | Crossref (title/authors/venue matched) | 2026-10-27 |
41+| 27 | B027 | Insider trading with a risk-neutral market maker: price impact lambda = Cov(v,Y)/Var(Y) and the informativeness of prices is pinned down by informed-order variance relative to noise; our stylized model is a static Kyle variant. | `kyle1985` | 10.2307/1913210 | 1985 | Crossref (title/authors/venue matched) | 2026-10-27 |
42+| 28 | B028 | Bid-ask spreads arise from adverse selection when some traders are informed; informed share determines the spread. | `glosten1985` | 10.1016/0304-405X(85)90044-3 | 1985 | Crossref (title/authors/venue matched) | 2026-10-27 |
43+| 29 | B029 | Competitive noisy rational-expectations equilibrium: prices aggregate dispersed private signals imperfectly because of noise supply; benchmark for informativeness. | `hellwig1980` | 10.1016/0022-0531(80)90056-3 | 1980 | Crossref (title/authors/venue matched) | 2026-10-27 |
44+| 30 | B030 | Prices cannot be fully informationally efficient when information is costly; the equilibrium degree of informativeness is bounded. | `grossman1980` | https://www.jstor.org/stable/1805228 (AER 70(3):393-408) | 1980 | publisher/IDEAS record (ideas.repec.org/a/aea/aecrev/v70y1980i3p393-408.html); no Crossref DOI | 2026-10-27 |
45+| 31 | B031 | With correlated private signals among strategic informed traders, the correlation structure of signals (not only their precision) governs trading intensity and price informativeness. | `foster1996` | 10.1111/j.1540-6261.1996.tb04075.x | 1996 | Crossref (title/authors/venue matched) | 2026-10-27 |
46+| 32 | B032 | Imperfect competition among informed traders with correlated signals: more correlated information leads to faster revelation (rat race), with implications for how shared signals affect price discovery. | `back2000` | 10.1111/0022-1082.00282 | 2000 | Crossref (title/authors/venue matched) | 2026-10-27 |
47+| 33 | B033 | Public information can increase disagreement and trading volume through higher-order beliefs; shared public signals do not trivially homogenize behaviour. | `kondor2012` | 10.1093/restud/rdr051 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
48+| 34 | B034 | Information diversity (different traders informed about different components) is complementary; loss of diversity reduces price informativeness about some components. | `goldstein2015` | 10.1111/jofi.12226 | 2015 | Crossref (title/authors/venue matched) | 2026-10-27 |
49+| 35 | B035 | Abundant cheap data can lower price informativeness about fundamentals by crowding out costly deep information; parallel to shared-model crowding. | `dugast2018` | 10.1016/j.jfineco.2018.07.004 | 2018 | Crossref (title/authors/venue matched) | 2026-10-27 |
50+| 36 | B036 | Realism metrics (stylized facts) for evaluating limit-order-book simulations; adopted as validation checklist. | `vyetrenko2020` | 10.1145/3383455.3422561 | 2020 | Crossref (title/authors/venue matched) | 2026-10-27 |
51+| 37 | B037 | ABIDES: discrete-event multi-agent market simulator with latency and a NASDAQ-like matching engine; our exchange follows the same event-driven design. | `byrd2020` | 10.1145/3384441.3395986 | 2020 | Crossref (title/authors/venue matched) | 2026-10-27 |
52+
53+## (c) Price discovery and information-efficiency measurement
54+
55+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
56+|---|---|---|---|---|---|---|---|
57+| 38 | C038 | Information content of trades measured by a VAR of quote revisions and trades (permanent price impact); we use the Hasbrouck impulse-response measure. | `hasbrouck1991` | 10.1111/j.1540-6261.1991.tb03749.x | 1991 | Crossref (title/authors/venue matched) | 2026-10-27 |
58+| 39 | C039 | Decomposition of transaction price into an efficient (random-walk) component and a pricing error; the standard deviation of the pricing error is our market-quality metric. | `hasbrouck1993` | 10.1093/rfs/6.1.191 | 1993 | Crossref (title/authors/venue matched) | 2026-10-27 |
59+| 40 | C040 | Information shares attribute price discovery to venues/agents via the common efficient price; adapted to attribute discovery to LLM vs rule-based order flow. | `hasbrouck1995` | 10.1111/j.1540-6261.1995.tb04054.x | 1995 | Crossref (title/authors/venue matched) | 2026-10-27 |
60+| 41 | C041 | Variance-ratio test rejects random walk under positive autocorrelation; we use variance ratios as an efficiency statistic. | `lo1988` | 10.1093/rfs/1.1.41 | 1988 | Crossref (title/authors/venue matched) | 2026-10-27 |
61+| 42 | C042 | Effective bid-ask spread can be inferred from the serial covariance of price changes. | `roll1984` | 10.1111/j.1540-6261.1984.tb03897.x | 1984 | Crossref (title/authors/venue matched) | 2026-10-27 |
62+| 43 | C043 | Illiquidity measured by absolute return per unit of volume; used as our price-impact proxy. | `amihud2002` | 10.1016/S1386-4181(01)00024-6 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
63+| 44 | C044 | Price informativeness is measured by how well prices predict future fundamentals (forecasting-regression R2); we use this to define informativeness about the latent dividend process. | `bai2016` | 10.1016/j.jfineco.2016.08.005 | 2016 | Crossref (title/authors/venue matched) | 2026-10-27 |
64+| 45 | C045 | Price informativeness matters for real decisions (feedback effects), motivating informativeness as a welfare-relevant outcome. | `bond2012` | 10.1146/annurev-financial-110311-101826 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
65+| 46 | C046 | Transitory price pressures from inventory imbalances are distinguished from permanent information effects; justifies separating pricing error from efficient-price variance. | `hendershott2014` | 10.1016/j.jfineco.2014.08.001 | 2014 | Crossref (title/authors/venue matched) | 2026-10-27 |
66+
67+## (d) Liquidity spirals, fire sales and margin
68+
69+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
70+|---|---|---|---|---|---|---|---|
71+| 47 | D047 | Funding liquidity and market liquidity reinforce each other through margins, producing liquidity spirals; our margin-call mechanism follows this logic. | `brunnermeier2009` | 10.1093/rfs/hhn098 | 2009 | Crossref (title/authors/venue matched) | 2026-10-27 |
72+| 48 | D048 | Liquidation values fall when potential buyers are themselves constrained; fire-sale discounts emerge from industry-wide distress. | `shleifer1992` | 10.1111/j.1540-6261.1992.tb04661.x | 1992 | Crossref (title/authors/venue matched) | 2026-10-27 |
73+| 49 | D049 | Limits of arbitrage: constrained arbitrageurs can amplify rather than correct mispricing when losses trigger withdrawals. | `shleifer1997` | 10.1111/j.1540-6261.1997.tb03807.x | 1997 | Crossref (title/authors/venue matched) | 2026-10-27 |
74+| 50 | D050 | Fire sales in finance and macroeconomics: forced sales by constrained agents push prices below fundamentals and propagate losses. | `shleifer2011` | 10.1257/jep.25.1.29 | 2011 | Crossref (title/authors/venue matched) | 2026-10-27 |
75+| 51 | D051 | The leverage cycle: endogenous margins amplify booms and crashes; leverage caps are a policy lever. | `geanakoplos2010` | 10.1086/648285 | 2010 | Crossref (title/authors/venue matched) | 2026-10-27 |
76+| 52 | D052 | Procyclical leverage of intermediaries: balance-sheet adjustment amplifies price moves. | `adrian2010` | 10.1016/j.jfi.2008.12.002 | 2010 | Crossref (title/authors/venue matched) | 2026-10-27 |
77+| 53 | D053 | Financially constrained arbitrageurs may under-provide liquidity; welfare effects of constraints. | `gromb2002` | 10.1016/S0304-405X(02)00228-3 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
78+| 54 | D054 | Leverage in an agent-based model generates fat tails and clustered volatility via synchronized margin-driven selling; closest ABM antecedent of our leverage treatment. | `thurner2012` | 10.1080/14697688.2012.674301 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
79+| 55 | D055 | Contagion as a wealth effect: convergence traders' losses in one asset propagate to others through reduced risk-bearing capacity. | `kyle2001` | 10.1111/0022-1082.00373 | 2001 | Crossref (title/authors/venue matched) | 2026-10-27 |
80+| 56 | D056 | Distressed selling by funds induces endogenous correlation between assets; multi-asset spillover mechanism in our K>1 runs. | `cont2013` | 10.1111/j.1467-9965.2011.00510.x | 2013 | Crossref (title/authors/venue matched) | 2026-10-27 |
81+| 57 | D057 | Fire-sale spillovers across institutions scale with common exposures and leverage; aggregate vulnerability index. | `greenwood2015` | 10.1016/j.jfineco.2014.11.006 | 2015 | Crossref (title/authors/venue matched) | 2026-10-27 |
82+
83+## (e) Herding, correlated trading, algorithmic trading and flash crashes
84+
85+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
86+|---|---|---|---|---|---|---|---|
87+| 58 | E058 | Herding of institutional investors is measurable by the buy-side imbalance statistic (LSV measure) which we compute for LLM cohorts. | `lakonishok1992` | 10.1016/0304-405X(92)90023-Q | 1992 | Crossref (title/authors/venue matched) | 2026-10-27 |
88+| 59 | E059 | During the Flash Crash, HFTs did not trigger the crash but their synchronized inventory management amplified it; crash-amplification channel. | `kirilenko2017` | 10.1111/jofi.12498 | 2017 | Crossref (title/authors/venue matched) | 2026-10-27 |
89+| 60 | E060 | High-frequency market makers behave as new market makers with tight inventory control; informs our market-maker policy. | `menkveld2013` | 10.1016/j.finmar.2013.06.006 | 2013 | Crossref (title/authors/venue matched) | 2026-10-27 |
90+| 61 | E061 | Algorithmic trading improves liquidity on average (causal evidence from NYSE autoquote). | `hendershott2011` | 10.1111/j.1540-6261.2010.01624.x | 2011 | Crossref (title/authors/venue matched) | 2026-10-27 |
91+| 62 | E062 | Continuous-time trading creates a latency arms race with correlated sniping; frequent batch auctions as alternative design (motivates our latency and batching treatments). | `budish2015` | 10.1093/qje/qjv027 | 2015 | Crossref (title/authors/venue matched) | 2026-10-27 |
92+| 63 | E063 | Informational cascades: rational agents ignore private signals after observing predecessors; cascade probability rises with signal correlation. | `bikhchandani1992` | 10.1086/261849 | 1992 | Crossref (title/authors/venue matched) | 2026-10-27 |
93+| 64 | E064 | Simple model of herd behavior: sequential decision-makers follow others, destroying information aggregation. | `banerjee1992` | 10.2307/2118364 | 1992 | Crossref (title/authors/venue matched) | 2026-10-27 |
94+| 65 | E065 | Reputational herding: managers mimic others' decisions; shared evaluation produces correlated choices. | `scharfstein1990` | https://www.jstor.org/stable/2006678 (AER 80(3):465-479) | 1990 | IDEAS record (ideas.repec.org/a/aea/aecrev/v80y1990i3p465-79.html); no Crossref DOI | 2026-10-27 |
95+| 66 | E066 | Short-horizon speculators herd on the same information source, which can be unrelated to fundamentals. | `froot1992` | 10.1111/j.1540-6261.1992.tb04665.x | 1992 | Crossref (title/authors/venue matched) | 2026-10-27 |
96+| 67 | E067 | Algorithmic trading in FX: algorithmic strategies are more correlated with each other than human trades, yet improve price efficiency. | `chaboud2014` | 10.1111/jofi.12186 | 2014 | Crossref (title/authors/venue matched) | 2026-10-27 |
97+| 68 | E068 | HFTs trade in the direction of permanent price changes and against transitory pricing errors, improving price discovery. | `brogaard2014` | 10.1093/rfs/hhu032 | 2014 | Crossref (title/authors/venue matched) | 2026-10-27 |
98+| 69 | E069 | Review of the economics of HFT: speed, adverse selection, and liquidity consequences. | `menkveld2016` | 10.1146/annurev-financial-121415-033010 | 2016 | Crossref (title/authors/venue matched) | 2026-10-27 |
99+| 70 | E070 | The August 2007 quant unwind: common strategies produced simultaneous deleveraging, evidence of crowding among algorithmic funds. | `khandani2011` | 10.1016/j.finmar.2010.07.005 | 2011 | Crossref (title/authors/venue matched) | 2026-10-27 |
100+| 71 | E071 | Order-flow toxicity (VPIN) rose before the Flash Crash; liquidity provision withdrew when flow became toxic. | `easley2011` | 10.3905/jpm.2011.37.2.118 | 2011 | Crossref (title/authors/venue matched) | 2026-10-27 |
101+| 72 | E072 | News trading and speed: fast traders react to common signals, affecting price informativeness and liquidity. | `foucault2016` | 10.1111/jofi.12302 | 2016 | Crossref (title/authors/venue matched) | 2026-10-27 |
102+| 73 | E073 | Ultrafast extreme events (mini flash crashes) proliferate in a machine ecology beyond human response time. | `johnson2013` | 10.1038/srep02627 | 2013 | Crossref (title/authors/venue matched) | 2026-10-27 |
103+
104+## (f) Stylized facts
105+
106+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
107+|---|---|---|---|---|---|---|---|
108+| 74 | F074 | Catalogue of stylized facts of asset returns (fat tails, absence of linear autocorrelation, volatility clustering, leverage effect) used as validation targets. | `cont2001` | 10.1080/713665670 | 2001 | Crossref (title/authors/venue matched) | 2026-10-27 |
109+| 75 | F075 | Speculative price changes have heavy (stable-Paretian) tails. | `mandelbrot1963` | 10.1086/294632 | 1963 | Crossref (title/authors/venue matched) | 2026-10-27 |
110+| 76 | F076 | ARCH: conditional heteroskedasticity captures volatility clustering. | `engle1982` | 10.2307/1912773 | 1982 | Crossref (title/authors/venue matched) | 2026-10-27 |
111+| 77 | F077 | GARCH generalization used to estimate volatility persistence in simulated returns. | `bollerslev1986` | 10.1016/0304-4076(86)90063-1 | 1986 | Crossref (title/authors/venue matched) | 2026-10-27 |
112+| 78 | F078 | Efficient markets hypothesis: definition of weak/semi-strong/strong form efficiency that our efficiency metrics operationalize. | `fama1970` | 10.2307/2325486 | 1970 | Crossref (title/authors/venue matched) | 2026-10-27 |
113+| 79 | F079 | Absolute returns display long memory; power-law decay of the autocorrelation of absolute returns. | `ding1993` | 10.1016/0927-5398(93)90006-D | 1993 | Crossref (title/authors/venue matched) | 2026-10-27 |
114+| 80 | F080 | Order-flow signs display long memory while prices remain nearly efficient: liquidity adapts to predictable flow. | `lillo2004` | 10.2202/1558-3708.1226 | 2004 | Crossref (title/authors/venue matched) | 2026-10-27 |
115+
116+## (g) Contagion and spillovers
117+
118+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
119+|---|---|---|---|---|---|---|---|
120+| 81 | G081 | Spillover index from forecast-error variance decompositions measures return and volatility spillovers. | `diebold2009` | 10.1111/j.1468-0297.2008.02208.x | 2009 | Crossref (title/authors/venue matched) | 2026-10-27 |
121+| 82 | G082 | Generalized (order-invariant) directional spillover measures. | `diebold2012` | 10.1016/j.ijforecast.2011.02.006 | 2012 | Crossref (title/authors/venue matched) | 2026-10-27 |
122+| 83 | G083 | Variance decompositions define connectedness networks among financial entities; we apply them across assets and agent cohorts. | `diebold2014` | 10.1016/j.jeconom.2014.04.012 | 2014 | Crossref (title/authors/venue matched) | 2026-10-27 |
123+| 84 | G084 | Correlation-based contagion tests must adjust for heteroskedasticity; otherwise interdependence is mistaken for contagion. | `forbes2002` | 10.1111/0022-1082.00494 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
124+| 85 | G085 | Rational-expectations contagion: cross-market rebalancing by informed investors transmits shocks between assets with unrelated fundamentals. | `kodres2002` | 10.1111/1540-6261.00441 | 2002 | Crossref (title/authors/venue matched) | 2026-10-27 |
125+| 86 | G086 | Dense financial networks are robust to small shocks but fragile to large ones (phase transition). | `acemoglu2015` | 10.1257/aer.20130456 | 2015 | Crossref (title/authors/venue matched) | 2026-10-27 |
126+| 87 | G087 | Information heterogeneity among strategic speculators generates financial contagion; homogeneity reduces it. | `pasquariello2007` | 10.1093/rfs/hhl010 | 2007 | Crossref (title/authors/venue matched) | 2026-10-27 |
127+
128+## (h) LLM agents in markets and economics; algorithmic collusion and monoculture
129+
130+| # | claim id | exact claim we will make in the paper | citation key | DOI or URL | year | how verified | verification date |
131+|---|---|---|---|---|---|---|---|
132+| 88 | H088 | LLMs can be used as simulated economic agents (homo silicus) to replicate classic behavioural experiments at low cost. | `horton2023` | 10.3386/w31122 | 2023 | Crossref (title/authors/venue matched) | 2026-10-27 |
133+| 89 | H089 | EconAgent: LLM-empowered agents with perception, memory and reflection produce realistic macroeconomic dynamics in a simulation. | `li2024econagent` | 10.18653/v1/2024.acl-long.829 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
134+| 90 | H090 | ChatGPT-derived sentiment scores on headlines predict next-day stock returns out of sample. | `lopezlira2023chatgpt` | arXiv:2304.07619 (also SSRN 10.2139/ssrn.4412788) | 2023 | arXiv API + Crossref (SSRN) | 2026-10-27 |
135+| 91 | H091 | LLM economic forecasts are contaminated by memorization of historical data; backtests of LLM agents on real histories are unreliable. | `lopezlira2025memorization` | arXiv:2504.14765 | 2025 | arXiv API | 2026-10-27 |
136+| 92 | H092 | GPT choices in budgetary decision tasks score higher on rationality (GARP consistency) than humans and are largely stable across demographic prompts. | `chen2023pnas` | 10.1073/pnas.2316205120 | 2023 | Crossref (title/authors/venue matched) | 2026-10-27 |
137+| 93 | H093 | FinMem: single LLM trading agent with layered memory and character design evaluated by backtesting on real stock histories. | `yu2023finmem` | arXiv:2311.13743 | 2023 | arXiv API | 2026-10-27 |
138+| 94 | H094 | TradingGPT: multi-agent LLM trading system with layered memory and distinct characters, evaluated on historical returns. | `li2023tradinggpt` | arXiv:2309.03736 | 2023 | arXiv API | 2026-10-27 |
139+| 95 | H095 | FinAgent: multimodal foundation agent for financial trading, evaluated against trading benchmarks on historical data. | `zhang2024finagent` | 10.1145/3637528.3671801 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
140+| 96 | H096 | StockAgent: LLM-driven multi-agent stock-trading simulation with bulletin-board communication; GPT- vs Gemini-driven agents differ systematically in trading behaviour. | `zhang2024stockagent` | arXiv:2407.18957 | 2024 | arXiv API | 2026-10-27 |
141+| 97 | H097 | ASFM: agent-based simulated financial market with LLM traders and a real order-matching system; reactions to rate and inflation shocks match economic priors. | `gao2024asfm` | arXiv:2406.19966 | 2024 | arXiv API | 2026-10-27 |
142+| 98 | H098 | TwinMarket: scalable LLM-agent stock-market simulation with social-media interaction reproduces bubbles and crashes; reports that agents of one model family are more homogeneous. | `yang2025twinmarket` | arXiv:2502.01506 (NeurIPS 2025 proceedings page) | 2025 | arXiv API + proceedings.neurips.cc listing | 2026-10-27 |
143+| 99 | H099 | LLM agents in a persistent order-book simulation adhere to assigned strategies, generate price discovery and bubbles, and can be analysed with partial-dependence-style perturbations. | `lopezlira2025trade` | arXiv:2504.10789 | 2025 | arXiv API | 2026-10-27 |
144+| 100 | H100 | In Smith-Suchanek-Williams-type experimental markets, LLM agents price near fundamentals and form only muted bubbles unlike humans; LLM strategy text has lower variance. | `henning2025` | arXiv:2502.15800 | 2025 | arXiv API | 2026-10-27 |
145+| 101 | H101 | LLM agents in a simulated call auction exhibit disposition effects and extrapolative beliefs; prompt interventions causally change bubble size. | `ouyang2026` | arXiv:2604.18373 | 2026 | arXiv abstract page | 2026-10-27 |
146+| 102 | H102 | Across 15 LLMs, behaviour ranges from fundamental pricing to human-like bubbles; mixed populations are unstable and advanced models adapt to exploit weaker ones, raising volatility. | `saxena2026` | arXiv:2604.18602 | 2026 | arXiv abstract page | 2026-10-27 |
147+| 103 | H103 | Replications of Smith (1962) double auctions with LLM agents converge more slowly or not at all to competitive equilibrium, with model-family differences. | `struski2026` | arXiv:2609.02580 | 2026 | arXiv abstract page | 2026-10-27 |
148+| 104 | H104 | Market institution (call market, CDA, posted offer, bargaining) changes efficiency of identical LLM agents from 56% to 89%. | `chupilkin2026` | arXiv:2608.04020 | 2026 | arXiv abstract page | 2026-10-27 |
149+| 105 | H105 | FCLAgent: LLM-decided buy/sell with rule-based order sizing reproduces path-dependent price patterns absent from conventional ABMs. | `hashimoto2025` | arXiv:2510.12189 | 2025 | arXiv abstract page | 2026-10-27 |
150+| 106 | H106 | StockSim: open order-level simulator with latency, slippage and price-time matching for evaluating multi-agent LLMs. | `papadakis2025` | arXiv:2507.09255 | 2025 | arXiv abstract page | 2026-10-27 |
151+| 107 | H107 | LLM agents' trading-style switching in a year-long stock simulation is only partially consistent with behavioural-finance theory. | `li2026switch` | arXiv:2602.07023 | 2026 | arXiv API | 2026-10-27 |
152+| 108 | H108 | Overlap in retrieved information among RAG-based LLM trading agents raises mean pairwise action correlation from 0.04 to 0.41 and increases position volatility without raising profits. | `song2026` | https://openreview.net/forum?id=8v4FskZp8I | 2026 | ICLR 2026 workshop page (iclr.cc/virtual/2026/10016534); no arXiv version found | 2026-10-27 |
153+| 109 | H109 | LLM agents in multi-agent systems conform to peers; the confidence gap and format of peer information control the strength of herding. | `cho2025` | arXiv:2505.21588 | 2025 | arXiv abstract page | 2026-10-27 |
154+| 110 | H110 | LLM sellers in continuous double auctions collude more when they can communicate; collusion propensity differs across models. | `agrawal2025` | arXiv:2507.01413 | 2025 | arXiv abstract page | 2026-10-27 |
155+| 111 | H111 | LLM-based pricing agents autonomously reach supracompetitive prices; small prompt wording changes alter the degree of collusion. | `fish2024` | arXiv:2404.00806 | 2024 | arXiv API | 2026-10-27 |
156+| 112 | H112 | Q-learning pricing algorithms learn to collude tacitly in repeated oligopoly without communication. | `calvano2020` | 10.1257/aer.20190623 | 2020 | Crossref (title/authors/venue matched) | 2026-10-27 |
157+| 113 | H113 | Q-learning under sequential pricing converges to supracompetitive (Edgeworth-cycle) outcomes. | `klein2021` | 10.1111/1756-2171.12383 | 2021 | Crossref (title/authors/venue matched) | 2026-10-27 |
158+| 114 | H114 | Empirical evidence of higher margins after adoption of algorithmic pricing in German retail gasoline. | `assad2024` | 10.1086/726906 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
159+| 115 | H115 | Asymmetric pricing-algorithm adoption softens competition through commitment and frequency effects. | `brown2023` | 10.1257/mic.20210158 | 2023 | Crossref (title/authors/venue matched) | 2026-10-27 |
160+| 116 | H116 | Reinforcement-learning informed speculators in a Kyle-type market sustain supracompetitive profits via price-trigger strategies or homogenized learning biases, lowering price informativeness and liquidity. | `dou2025` | 10.3386/w34054 | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
161+| 117 | H117 | Q-learning market makers learn adverse-selection pricing but quote markups over competitive spreads, shrinking with the number of algorithms. | `colliard2026` | 10.1093/rfs/hhag010 | 2026 | Crossref (title/authors/venue matched) | 2026-10-27 |
162+| 118 | H118 | Algorithmic monoculture: when many decision-makers rely on the same algorithm, outcomes can be worse even if the algorithm is individually more accurate. | `kleinberg2021` | 10.1073/pnas.2018340118 | 2021 | Crossref (title/authors/venue matched) | 2026-10-27 |
163+| 119 | H119 | Shared foundation models produce outcome homogenization: the same individuals are systematically mis-served across deployers. | `bommasani2022` | arXiv:2211.13972 | 2022 | arXiv API | 2026-10-27 |
164+| 120 | H120 | Foundation models create homogenization risk: downstream systems inherit the same strengths and failure modes. | `bommasani2021` | arXiv:2108.07258 | 2021 | arXiv API | 2026-10-27 |
165+| 121 | H121 | Generative AI raises individual creativity but reduces collective diversity of outputs. | `doshi2024` | 10.1126/sciadv.adn5290 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
166+| 122 | H122 | Standard LLM outputs show diminished diversity of thought relative to human samples. | `park2024brm` | 10.3758/s13428-023-02307-x | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
167+| 123 | H123 | LLM assistance homogenizes human creative ideation across users. | `anderson2024` | 10.1145/3635636.3656204 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
168+| 124 | H124 | S3: social-network simulation with LLM-empowered agents reproduces emotion, attitude and information propagation. | `gao2023s3` | arXiv:2307.14984 | 2023 | arXiv API | 2026-10-27 |
169+| 125 | H125 | Generative agents with memory, reflection and planning produce believable emergent social behaviour. | `park2023` | 10.1145/3586183.3606763 | 2023 | Crossref (title/authors/venue matched) | 2026-10-27 |
170+| 126 | H126 | LLMs can simulate multiple humans and replicate classic human-subject studies (Turing experiments), with fidelity varying by model and task. | `aher2023` | https://proceedings.mlr.press/v202/aher23a.html | 2023 | publisher page (PMLR v202:337-371) + arXiv API 2208.10264 | 2026-10-27 |
171+| 127 | H127 | Conditioning LLMs on demographic backstories produces silicon samples that match human sub-populations' response distributions. | `argyle2023` | 10.1017/pan.2023.2 | 2023 | Crossref (title/authors/venue matched) | 2026-10-27 |
172+| 128 | H128 | Expectations elicited from an LLM reading WSJ articles track professional forecaster surveys and are extrapolative. | `bybee2023` | arXiv:2305.02823 | 2023 | arXiv API | 2026-10-27 |
173+| 129 | H129 | Automated social science: LLMs generate hypotheses and act as subjects in simulated experiments. | `manning2024` | arXiv:2404.11794 | 2024 | arXiv API | 2026-10-27 |
174+| 130 | H130 | ChatGPT choices in behavioural games fall within the human distribution and are more cooperative/altruistic than the median human. | `mei2024` | 10.1073/pnas.2313925121 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
175+| 131 | H131 | LLMs in repeated games cooperate well in self-interested games but coordinate poorly, revealing systematic behavioural signatures. | `akata2025` | 10.1038/s41562-025-02172-y | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
176+| 132 | H132 | LLM service behaviour drifts over months (GPT-3.5/4 March vs June 2023), motivating frozen decision libraries for replicability. | `chen2024hdsr` | 10.1162/99608f92.5317da47 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
177+| 133 | H133 | Ensembles of twelve LLMs match human crowd forecasting accuracy (wisdom of the silicon crowd), illustrating diversity benefits across models. | `schoenegger2024` | 10.1126/sciadv.adp1528 | 2024 | Crossref (title/authors/venue matched) | 2026-10-27 |
178+| 134 | H134 | Multi-agent reinforcement-learning stock market reproduces stylized facts; RL-agent precursor of LLM-populated markets. | `lussange2021` | 10.1007/s10614-020-10038-w | 2021 | Crossref (title/authors/venue matched) | 2026-10-27 |
179+| 135 | H135 | Generative AI agents can be modelled as economic agents with new primitives (prompts, context); framework for LLM-agent economics. | `immorlica2024` | arXiv:2406.00477 | 2024 | arXiv API | 2026-10-27 |
180+| 136 | H136 | LLM social simulations are a promising method provided validity concerns (homogeneity, sycophancy, drift) are addressed. | `anthis2025` | arXiv:2504.02234 | 2025 | arXiv API | 2026-10-27 |
181+| 137 | H137 | Deep learning adoption increases uniformity and interconnectedness in finance; models built on the same data generate correlated predictions. | `gensler2020` | 10.2139/ssrn.3723132 | 2020 | Crossref (title/authors/venue matched) | 2026-10-27 |
182+| 138 | H138 | Widespread use of common AI models and data sources could increase correlations in trading, lending and pricing (FSB 2024). | `fsb2024` | https://www.fsb.org/uploads/P14112024.pdf | 2024 | publisher page (fsb.org, 14 Nov 2024) | 2026-10-27 |
183+| 139 | H139 | AI in risk management can create endogenous systemic risk through common models and procyclical responses. | `danielsson2022` | 10.1016/j.jbankfin.2021.106290 | 2022 | Crossref (title/authors/venue matched) | 2026-10-27 |
184+| 140 | H140 | AI amplifies existing vulnerabilities and makes crises faster and more severe in a game-theoretic model of AI-driven markets. | `danielsson2025` | 10.1016/j.jfs.2025.101453 | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
185+| 141 | H141 | Intelligent financial system: AI transforms intermediation, asset management and payments, with monoculture and correlation among the financial-stability concerns. | `aldasoro2025` | 10.1016/j.jfs.2025.101472 | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
186+| 142 | H142 | In LLM re-creations of herding experiments, AI agents rely more on private signals than humans, but can be prompted to herd when maximizing profit. | `hansen2025` | 10.17016/FEDS.2025.090 | 2025 | Crossref (title/authors/venue matched) | 2026-10-27 |
187+| 143 | H143 | Unified model in which AI adoption share and signal correlation raise systemic-risk coupling convexly; 13F evidence of tail-loss amplification. | `meng2026` | arXiv:2604.03272 | 2026 | arXiv abstract page | 2026-10-27 |
188+
189+## Summary counts
190+
191+- Verified entries in this ledger: **143**, one per bib key; `paper/references.bib` has 143 entries (every ledger row has a bib entry and vice versa; cross-checked with `comm` on 2026-10-27).
192+- Could not verify / replaced: see next section (none of these are in the bib).
193+
194+## Could not verify (NOT in references.bib)
195+
196+| item | what we looked for | why excluded |
197+|---|---|---|
198+| "ElliottAgents" / other 2025 LLM-trading benchmark names seen in secondary blogs | a primary arXiv or proceedings record | no primary record found; blog mentions only |
199+| Danielsson & Uthemann, "Artificial intelligence and financial crises" arXiv:2407.17048 | journal reference on the arXiv page | arXiv page shows no journal-ref; we cite the Journal of Financial Stability version `danielsson2025` (Crossref 10.1016/j.jfs.2025.101453) instead |
200+| Lopez-Lira & Tang (2023) journal version | a peer-reviewed journal DOI | still an arXiv/SSRN preprint as of v6 (Oct 2025); cited as `lopezlira2023chatgpt` (arXiv) |
201+| Dou, Goldstein & Ji — journal version | a journal DOI | only NBER w34054 / SSRN 4452704 exist; cited as `dou2025` (NBER, Crossref 10.3386/w34054) |
202+| Colliard, Foucault & Lovo — volume/pages | RFS volume, issue, pages | Crossref lists the RFS article (10.1093/rfs/hhag010) with no volume/pages yet; bib entry carries `note = {Forthcoming}` |
203+| Song (2026) — arXiv version | an arXiv ID for the ICLR 2026 workshop paper | none found; cited via the OpenReview/ICLR page |
204+| Byrd, Hybinette & Balch 2019 arXiv 1904.12066 | arXiv API record (rate-limited, HTTP 429) | abstract page fetched instead; we cite the SIGSIM-PADS 2020 version `byrd2020` (Crossref 10.1145/3384441.3395986) |
205+| Arthur, Holland, LeBaron, Palmer & Tayler (1997) Santa Fe chapter | a DOI for the book chapter in *The Economy as an Evolving Complex System II* | no Crossref record; we cite `lebaron1999` (JEDC) for the Santa Fe market instead |
206+| Hasbrouck (2007) *Empirical Market Microstructure* (book) | a DOI | book has no DOI; not needed since `hasbrouck1991`/`hasbrouck1993`/`hasbrouck1995` cover the measures |
207+| Vives (2008) *Information and Learning in Markets* | a DOI | book without Crossref DOI; `hellwig1980`, `grossman1980`, `kyle1985` suffice |
208+| Aher et al. 2023 ICML via ACM DL (10.5555/3618408.3618425) | Crossref record | 10.5555 is not registered at Crossref; cited via the PMLR page instead |
209+| Aldasoro et al. — guessed DOI 10.1016/j.jfs.2025.101456 | Crossref | resolved to a different paper; corrected to 10.1016/j.jfs.2025.101472 (now `aldasoro2025`) |
210+| Thurner, Farmer & Geanakoplos — guessed DOI 10.1080/14697688.2011.586336 | Crossref | not found; corrected to 10.1080/14697688.2012.674301 (now `thurner2012`) |
211+| Pasquariello — guessed DOI 10.1093/rfs/hhl046 | Crossref | not found; corrected to 10.1093/rfs/hhl010 (now `pasquariello2007`) |
212+| Chiarella–Iori–Perelló, Back–Cao–Willard, Foster–Viswanathan, Ladley, Hasbrouck 1991, Kondor 2012 — first-guess DOIs | Crossref | each first guess resolved to a *different* paper; all corrected by Crossref bibliographic query and re-verified (DOIs in table above) |
added docs/model_cards.md +84 −0
@@ -0,0 +1,84 @@
1+# Model cards — WP 27
2+
3+One card per model or provider used or planned. Prices are USD per 1M tokens (input / cached input / output) as entered in `LLMCfg.price_assumptions` (`experiments/config.py`); source: provider pricing pages fetched 2026-10-27 (OpenAI) and Anthropic's published price table. The budget tracker (`llm/budget.py`) prices every call from this table; unknown model ids are priced at the most expensive known output price. Every run manifest stores the table it used.
4+
5+## 1. gpt-5.4-nano (OpenAI) — primary model
6+
7+| Field | Value |
8+|---|---|
9+| Model id / snapshot | `gpt-5.4-nano` (alias; the dated snapshot returned in `response.model` is recorded per decision via `request_id` and the manifest) |
10+| Price | 0.20 / 0.02 / 1.25 |
11+| Measured usage (2026-10-27, prompt v1) | ≈ 760 input, ≈ 230 output tokens per decision, of which ≈ 150 reasoning tokens at `reasoning.effort = low` → ≈ 0.00044 USD per decision (planning figure 0.0005) |
12+| API / format | Responses API; `text.format = {type: json_schema, name: trading_decision, strict: true}`; `instructions` = frozen system prompt; `store = False`; `prompt_cache_key = ma-v1-<prompt_id>` |
13+| Reasoning / sampling | `reasoning.effort = low`; `temperature` not sent (rejected by the gpt-5 family); no seed parameter |
14+| Known non-determinism | Sampling at the provider; identical prompts may yield different decisions across calls; replay is exact only from the SQLite cache |
15+| Data retention | `store=False`: responses are not kept in the account's response store; OpenAI's standard abuse-monitoring retention applies (no zero-data-retention agreement) |
16+| Role in design | All dose–response, mechanism and safeguard cells; single-prompt baseline of the diversity arm; source of the frozen library |
17+| Status | **Live** (key valid 2026-10-27) |
18+
19+## 2. gpt-5.4-mini (OpenAI) — second model for the mix arm
20+
21+| Field | Value |
22+|---|---|
23+| Model id | `gpt-5.4-mini` |
24+| Price | 0.75 / 0.075 / 4.50 |
25+| Usage assumption | Same token profile as nano (760 / 230) → ≈ 0.0016 USD per decision; **TBD** from a one-seed check before T2 (reasoning tokens may differ) |
26+| API / format / reasoning | As gpt-5.4-nano |
27+| Role | `mini_25` (model-quality control), `mix_25` (two-model mix), `mini_25_equalusd` (fairness) |
28+| Status | Live-capable; not yet called; note the engineering item on mixing two OpenAI models in one run (`protocol.md` §5.2 note ii) |
29+
30+## 3. gpt-5-nano (OpenAI) — cheap alternative / robustness
31+
32+| Field | Value |
33+|---|---|
34+| Model id | `gpt-5-nano` |
35+| Price | 0.05 / 0.005 / 0.40 |
36+| Usage assumption | 760 / 230 → ≈ 0.00013 USD per decision (TBD) |
37+| API / format / reasoning | As gpt-5.4-nano |
38+| Role | Optional "previous-generation" replication of `share_25` if budget remains after T6; not in the 40 USD plan |
39+| Status | Live-capable; not planned in the confirmatory tiers |
40+
41+## 4. claude-haiku-5-5 (Anthropic) — planned cross-provider model
42+
43+| Field | Value |
44+|---|---|
45+| Model id | `claude-haiku-5-5` |
46+| Price (Anthropic published table) | 0.10 / 0.01 / 0.50 |
47+| Usage assumption | 760 / 230 → ≈ 0.00019 USD per decision (TBD; no reasoning-token accounting in the adapter) |
48+| API / format | Messages API; `output_config.format = {type: json_schema, schema}`; `output_config.effort = low`; system prompt with `cache_control: ephemeral`; no `thinking` parameter sent; `stop_reason = refusal` mapped to an invalid decision |
49+| Known non-determinism | Provider sampling; no seed |
50+| Data retention | Anthropic standard API retention (no zero-data-retention agreement) |
51+| Role | Cross-provider replication of `share_25` and a nano + haiku mix cell |
52+| Status | **Blocked** — the Anthropic key available on 2026-10-27 is rejected (HTTP 401 invalid x-api-key). The adapter is implemented and the cells are dry-run with the mock provider mapped to this model id; they enter the design only with a valid key and approved budget |
53+
54+## 5. claude-sonnet-5-5 (Anthropic) — planned frontier-model cell
55+
56+| Field | Value |
57+|---|---|
58+| Model id | `claude-sonnet-5-5` |
59+| Price (Anthropic published table) | 2.00 / 0.20 / 10.00 |
60+| Usage assumption | 760 / 230 → ≈ 0.0038 USD per decision (TBD); one `share_25` run ≈ 2.6 USD |
61+| API / format / retention | As claude-haiku-5-5 |
62+| Role | At most a 2-seed "frontier model" comparison of `share_25`; outside the 40 USD plan |
63+| Status | **Blocked** (same key issue); mock dry-run only |
64+
65+## 6. mock-v1 (local) — deterministic stand-in
66+
67+| Field | Value |
68+|---|---|
69+| Implementation | `llm/providers/mock.py`: parses the canonical user message (mid, public PV, private signal, holdings, free cash) and applies a seeded value-plus-noise rule; 60 % limit / 40 % market orders; `invalid_rate` = 5 % (half non-JSON, half schema-invalid); `herd_bias` knob adds a common tilt to every mock agent |
70+| Price | 0 / 0 / 0 (tokens approximated by word counts) |
71+| Determinism | Fully seeded (`PCG64(seed)`); reproducible |
72+| Role | Dry-run of every cell; CRN and validation tests; σ floors; `herd_bias` sweeps as a sanity check of the coordination metrics |
73+| Status | Live (local). **Not evidence about LLM behaviour** |
74+
75+## 7. library (local) — frozen nearest-neighbour replay
76+
77+| Field | Value |
78+|---|---|
79+| Implementation | `llm/library.py`: 7 standardized features of the observation (mispricing vs public PV, momentum, signal, inventory and cash ratios, spread, open-order flag); returns the recorded decision of one of the 5 nearest neighbours (seeded draw), limit price rescaled to the current mid |
80+| Source | Valid decisions recorded in the T1 gpt-5.4-nano runs (`results/library/nano_v1.npz`) |
81+| Price | 0 |
82+| Role | Scale arm at N = 1,000 and the "cached" side of the cached-vs-online comparison; runs are labelled provider `library` |
83+| Caveat | Not an adaptive agent; out-of-support at large N must be reported (distance diagnostics, `protocol.md` §5.4) |
84+| Status | Implemented; unused until T1 exists |
added docs/novelty_positioning.md +39 −0
@@ -0,0 +1,39 @@
1+# Novelty positioning — WP 27 "The Invisible Hand of Machines"
2+
3+Prepared 2026-10-27 by the literature-review member. All citation keys refer to `paper/references.bib`; every item was verified (see `docs/literature_ledger.md`).
4+
5+## 1. What the existing LLM-and-markets literature does
6+
7+**(i) Single-agent trading benchmarks and backtests.** FinMem (`yu2023finmem`), TradingGPT (`li2023tradinggpt`), FinAgent (`zhang2024finagent`) and the InvestorBench family evaluate one LLM agent (sometimes a small team) against a historical price path. The market does not react to the agent; the object is the agent's P&L or Sharpe ratio. Lopez-Lira and Tang (`lopezlira2023chatgpt`) is the return-predictability analogue (ChatGPT headline scores predict next-day returns). These papers say nothing about equilibrium prices because the price series is exogenous, and Lopez-Lira, Tang and Zhu (`lopezlira2025memorization`) show that such backtests are contaminated by memorization of the historical period.
8+
9+**(ii) LLM-populated market simulators without causal identification.** ASFM (`gao2024asfm`), StockAgent (`zhang2024stockagent`), TwinMarket (`yang2025twinmarket`, NeurIPS 2025), FCLAgent (`hashimoto2025`), StockSim (`papadakis2025`) and Lopez-Lira's open-source simulator (`lopezlira2025trade`) all place many LLM agents on a matching engine and report emergent bubbles, crashes, or reactions to macro shocks. They are descriptive: they show that LLM markets *can* produce certain patterns, usually for one population composition and a handful of seeds. Two of them already contain observations close to our mechanism — TwinMarket notes that agents driven by one model family are more homogeneous and links this to herd behaviour, and StockAgent reports systematic differences between GPT- and Gemini-driven agents — but neither randomizes the LLM share, controls the information set, or separates the fundamental value from the efficient price and the transaction price. Lopez-Lira (`lopezlira2025trade`) is the closest in spirit (persistent order book, heterogeneous roles, perturbation analysis "like partial-dependence plots"), yet the perturbations are over market conditions, not over the penetration of LLM agents, and there is no matched-seed design.
10+
11+**(iii) Experimental-finance replications with LLM subjects.** Henning et al. with Camerer (`henning2025`) run Smith–Suchanek–Williams markets with LLM traders and find near-fundamental pricing and muted bubbles; Ouyang and Sui (`ouyang2026`) find disposition effects and extrapolation in an open call auction and show prompt interventions move bubble size; Saxena, Pangallo, Hommes, Caccioli and del Rio-Chanona (`saxena2026`) test 15 models and find everything from fundamental pricing to human-like bubbles, with mixed populations unstable; Struski et al. (`struski2026`) and Chupilkin (`chupilkin2026`) replicate Smith (1962) double auctions and show slower convergence and strong dependence on the trading institution. These are the right benchmark for *behavioural fidelity* (do LLMs behave like humans?) but they hold the population 100 % LLM (or 100 % human) and ask a different question from ours.
12+
13+**(iv) Homogeneity, herding and monoculture.** The algorithmic-monoculture literature (`kleinberg2021`, `bommasani2022`, `bommasani2021`) and the output-diversity evidence (`doshi2024`, `park2024brm`, `anderson2024`) establish that shared models homogenize decisions. In LLM multi-agent systems, Cho et al. (`cho2025`) document peer conformity. The single paper that measures correlated trading from shared inputs is Song (`song2026`, ICLR 2026 workshop): overlap in retrieved documents raises pairwise action correlation among RAG trading agents from 0.04 to 0.41. That is a backtest on crypto data with no market feedback — the price does not respond to the agents — so it cannot speak to price informativeness or liquidity spirals. Hansen and Lee (`hansen2025`, Fed FEDS) re-create herding experiments with LLMs and find less herding than humans unless agents are told to maximize profit.
14+
15+**(v) AI collusion and RL agents in markets.** `calvano2020`, `klein2021`, `fish2024` (LLM pricing agents reach supracompetitive prices; prompt wording matters), `agrawal2025` (LLM sellers in CDAs collude more with communication), `colliard2026` (Q-learning market makers quote markups) and `dou2025` (RL informed speculators in a Kyle market lower price informativeness through "homogenized learning biases"). Dou, Goldstein and Ji is the nearest *theoretical* neighbour: it also ties a common learning process to reduced price efficiency. Its mechanism is strategic (price-trigger punishment, over-pruning bias in Q-learning), not a shared-error structure in signals, and it has no LLMs.
16+
17+**(vi) Policy literature.** Gensler and Bailey (`gensler2020`), the FSB (`fsb2024`), Danielsson and Uthemann (`danielsson2025`), Aldasoro et al. (`aldasoro2025`) and Meng and Chen (`meng2026`) all argue that common models and data sources will raise trading correlations and amplify stress. None provides a controlled experiment; `meng2026` offers a reduced-form 13F estimate.
18+
19+## 2. The gap this paper fills
20+
21+1. **Exogenous, randomized LLM penetration with matched seeds.** We treat `llm_share` as a treatment assigned to trader slots by an independent random stream, holding every other stream (fundamentals, news, policy assignment, activation, tie-breaks) fixed across the pair. Differences in outcomes between φ = 0 and φ > 0 are therefore causal effects of LLM penetration on the *same* market history, estimated with ≥ 30 seeds and a power calculation for the confirmatory design. No existing LLM-market paper does this; the simulators in (ii) report single compositions and the experiments in (iii) compare 100 %-LLM to 100 %-human markets.
22+
23+2. **Three prices, not one.** We separate the latent fundamental V_t (known to the simulator only), the public value V^pub_t (Kalman/HMM posterior on announced dividends and news) and the transaction price, and we compute Hasbrouck's efficient-price / pricing-error decomposition (`hasbrouck1993`), variance ratios (`lo1988`), Kyle lambda (`kyle1985`), forecasting-regression informativeness (`bai2016`) and information shares (`hasbrouck1995`) on simulated data where the truth is observed. Existing LLM simulators report returns, volatility and "bubbles" relative to a dividend-discount value but do not distinguish information-efficiency loss from transitory pressure.
24+
25+3. **A shared-model correlated-error mechanism, derived and then tested by intervention.** The theory section nests a static Kyle/Hellwig market in which each trader's signal error has a model-specific common component η_g; the share φ_g using model g and the effective number of models M_eff = 1/Σφ_g² pin down price informativeness, order-flow correlation and pricing error in closed form, with feedback (trend demand) and leverage (margin) extensions giving amplification 1/(1−λγ) and 1/(1−λX/m). The correlated-signal microstructure literature (`foster1996`, `back2000`, `goldstein2015`, `pasquariello2007`) has the ingredients but never applies them to shared foundation models, and the monoculture literature (`kleinberg2021`, `bommasani2022`) has the homogenization idea without a market-clearing price. The simulator then *intervenes* on the mechanism directly: same vs. diverse prompts (H4), provider mix, communication cohorts (H5), memory, and frozen decision-library replay vs. online calls — so M_eff is manipulated, not merely observed. Song (`song2026`) manipulates information overlap but without price feedback; TwinMarket and StockAgent observe model-family homogeneity without manipulating it.
26+
27+4. **Fairness designs by token, USD and decision-opportunity budgets, with matched latency.** Because LLM agents decide every 20 ticks and incur latency, naive comparisons confound "being an LLM" with "being slow and infrequent". We report realized LLM shares of agents, orders and volume, and run budget-matched treatments (equal tokens, equal dollars, equal decision opportunities) and matched-latency treatments. No prior LLM-market study controls for these; most do not even report the realized share of volume.
28+
29+5. **Leverage × homogeneity interaction and policy counterfactuals.** H3 (bubble/crash frequency and liquidity spirals rise in φ × leverage) connects the LLM literature to `brunnermeier2009`, `thurner2012` and `kirilenko2017`; H6 evaluates circuit breakers and position limits by crash depth and time-to-absorb, in the spirit of `budish2015`. The policy papers in (vi) call for exactly this evidence.
30+
31+## 3. Where we must be honest
32+
33+- **The idea that shared models correlate trading is not ours.** It is in `gensler2020`, `fsb2024`, `danielsson2025`, `dou2025` (as "homogenized learning biases") and empirically in `song2026`. Our contribution is identification and mechanism, not the hypothesis. The introduction should say so.
34+- **Model-family homogeneity inside LLM markets has already been observed** (`yang2025twinmarket`, `zhang2024stockagent`, `saxena2026`). We turn an observation into a treatment.
35+- **LLM-populated order-book simulators exist and are open source** (`lopezlira2025trade`, `papadakis2025`, `gao2024asfm`). Our simulator is not the novelty; the design is. We should cite and, where feasible, reuse their validation metrics (`vyetrenko2020`).
36+- **Behavioural fidelity is contested.** `henning2025` finds LLMs more fundamental-driven than humans; `ouyang2026` and `saxena2026` find bubbles; `hansen2025` finds less herding. Our results on informativeness do not require LLMs to be human-like — they require only that errors be correlated within a model — but we must not claim external validity for human-plus-LLM markets without caveats.
37+- **Prompt sensitivity and drift** (`fish2024`, `chen2024hdsr`) threaten replicability. The frozen decision-library treatment and the mock provider are our answer; the limitation remains for online runs.
38+- **Scale.** TwinMarket runs thousands of agents; our N = 10,000-slot runs replace only a fraction with online LLM calls and use the decision library for the rest. We should report this clearly rather than imply fully online populations.
39+- **The stylized model is a one-period Kyle variant with a fixed response intensity β.** The CARA extension relaxes it, but the strategic effects in `dou2025` and `colliard2026` (learning to collude, markups) are outside our theory and we should not claim to nest them.
added docs/protocol.md +96 −0
@@ -0,0 +1,96 @@
1+# Run protocol — WP 27
2+
3+Version 1.0, 2026-10-27. Operational companion to `identification.md`. Every number marked TBD is filled by the pilot and recorded in the freeze file.
4+
5+## 1. Environment
6+
7+- Project root: `~/Desktop/Recherche-UQO/finance/invisible-hand-of-machines`; Python ≥ 3.12 in `.venv` (uv lock `uv.lock`); package `market_agents` with entry point `ma` (`.venv/bin/ma`, equivalently `.venv/bin/python -m market_agents.cli`).
8+- Keys in `.env` only (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`), loaded by `ma` via `python-dotenv`; never in configs or manifests. Status 2026-10-27: OpenAI key live; **Anthropic key rejected (HTTP 401 invalid x-api-key)** — Claude cells run with the mock provider only until a valid key is installed.
9+- OpenAI calls use the Responses API with `store=False`, `text.format = json_schema (strict)`, `reasoning.effort = low`, `prompt_cache_key` per prompt id. Anthropic calls (when enabled) use the Messages API with `output_config.format = json_schema`, `effort = low`, system prompt marked for prompt caching.
10+- Hard limits: project-wide live spend ≤ 40 USD; pilot ≤ 5 USD; per-run `population.llm.usd_cap` set to ≥ 2× the expected run cost so that no confirmatory run halts for budget.
11+- Results: `results/runs/<design>/<cell>/seed<NNNN>/` (config.yaml, manifest.json, ticks/trades/agents/llm_decisions parquet, outcomes.json) and `results/runs/<design>/outcomes.parquet`. Caches: `results/cache/<design>.sqlite` (one per design; the cache is also the recorded decision library).
12+
13+## 2. Commands
14+
15+```bash
16+.venv/bin/python -m pytest tests # 23 tests (unit, property, integration) must pass
17+.venv/bin/ma run configs/baseline.yaml --seed 1 --out results/runs/baseline/seed0001 # one classical run (~0.5 s)
18+.venv/bin/ma budget configs/<design>.yaml --tokens-in 760 --tokens-out 230 # calls and USD before any live design
19+.venv/bin/ma design configs/<design>.yaml --workers 8 --cache results/cache/<design>.sqlite
20+.venv/bin/ma design configs/<design>.yaml --cells share_25 --max-seeds 1 --cache ... # single cell / single seed
21+```
22+
23+`ma design` runs mock cells in parallel processes (`--workers`) and any cell with a live provider sequentially with a shared cache (the worker count is ignored for API cells). Existing `outcomes.json` files are reused, so an interrupted design resumes without re-calling the API.
24+
25+## 3. Phase 5a — mock dry-run (no cost)
26+
27+1. Apply the gate-4 fixes listed in `research_plan.md` §3 (information parity, activation stream, confirmatory fundamentals, shock size, first commit). Re-run the test suite.
28+2. `ma design configs/exploratory.yaml --workers 8` — all 12 cells × seeds 1–3 with the mock provider (`usd_cap: 0`). Check: every cell completes; `llm_share_traders` equals the slot share (minus market makers at 100 %); `llm_valid_rate` ≈ 0.95 (the mock injects 5 % invalid answers); `n_llm_decisions` = 27–28 per LLM agent; `n_halts` > 0 only in `breaker_25`; `reject_ratio` rises in `poslimit_25`; `ret_corr` and `spillover_dy` defined in `k2_25`.
29+3. Dry-run the Anthropic cells with the mock provider mapped to the Claude model ids (`provider_mix: {mock: 1.0}`, `models: {mock: claude-haiku-5-5}`) to exercise the price table and manifests; label `treatment.provider: anthropic-mock`.
30+4. Free σ estimates: run `share_0` for seeds 1–30 (classical, ≈ 15 s) to obtain the control SD of every outcome.
31+
32+## 4. Phase 5b — live pilot (OpenAI, ≤ 5 USD)
33+
34+| Cell | `llm_share` | Model / prompt | Seeds | Decisions per run | Planned USD (0.0005/decision) |
35+|---|---|---|---|---|---|
36+| share_0 | 0 | — (control, free) | 1–3 | 0 | 0 |
37+| share_5 | 0.05 | gpt-5.4-nano, single | 1–3 | 135 | 0.20 |
38+| share_25 | 0.25 | gpt-5.4-nano, single | 1–3 | 675 | 1.01 |
39+| share_50 | 0.50 | gpt-5.4-nano, single | 1–3 | 1,350 | 2.03 |
40+| **Total** | | | | 6,480 | **3.24** (measured rate 0.00044 → 2.85) |
41+
42+Design file: `configs/pilot_openai.yaml` (per-run `usd_cap` 1.5; add the free `share_0` cell so the parquet is self-contained). Steps: `ma budget` → confirm ≤ 5 USD → `ma design configs/pilot_openai.yaml --cache results/cache/pilot_openai.sqlite` → record in `results/manifests/pilot.json`: total USD, tokens in/out/reasoning per decision, latency, validity rate, failure rate, cache-hit share, realized order and volume shares, and the SD of paired differences (vs `share_0`) for every primary outcome.
43+
44+Pilot pass criteria: validity ≥ 80 %, failures ≤ 10 %, cost per decision within ±30 % of 0.0005 USD, no budget halts. Failure → one prompt revision (v2), mock re-run, one-seed re-pilot (≤ 0.7 USD). Pilot seeds 1–3 are excluded from confirmatory estimates.
45+
46+## 5. Phase 6–7 — freeze and confirmatory design
47+
48+### 5.1 Freeze (before the first confirmatory call)
49+
50+`results/manifests/freeze.json` records: git revision; SHA of `prompting.py`, `schema.py`, `outcomes.py`; `config_hash` of the confirmatory base; cell list; seed lists (confirmatory seeds 101–132, used in order); thresholds (bubble 5 %/10 ticks, crash 10 %/20 ticks; sensitivity grid 3/5/8 % and 7/10/15 %); the σ̂_d table from the pilot; the tier budget below; model ids and prices. Confirmatory base = `configs/baseline.yaml` with design-level overrides `fundamentals.jump_prob: 1.0`, `fundamentals.jump_sigma: 4.0` (provisional — chosen so that SD(V^pub/V − 1) ≈ 0.5 %; confirm at freeze), `shocks: [{time: 300, kind: fundamental_jump, size: 10.0}, {time: 450, kind: placebo}]` (+2.1 % on V).
51+
52+### 5.2 Cells and budget by tier (gpt-5.4-nano unless stated; 27 decisions per LLM agent per run; planning cost 0.0005 USD per nano decision, 0.0016 per gpt-5.4-mini decision — the mini token profile is TBD and assumed equal to nano's)
53+
54+| Tier | Cell | Overrides (on the confirmatory base) | Seeds | Live decisions | USD |
55+|---|---|---|---|---|---|
56+| T1 primary | share_0 | `population.llm_share: 0.0` | 101–130 | 0 | 0 |
57+| | share_25 | `llm_share: 0.25` | 101–110 | 6,750 | 3.38 |
58+| | share_50 | `llm_share: 0.50` | 101–110 | 13,500 | 6.75 |
59+| T2 diversity | diverse_25 | `llm_share: 0.25, llm.prompt_set: diverse` | 101–106 | 4,050 | 2.03 |
60+| | mix_25 | `llm_share: 0.25, llm.provider_mix: {openai: 1.0}` with a second OpenAI model id for half the slots (see note) | 101–106 | 2,028 nano + 2,022 mini | 4.25 |
61+| | mini_25 | `llm_share: 0.25, llm.models.openai: gpt-5.4-mini` | 101–104 | 2,700 mini | 4.32 |
62+| T3 dose shape | share_1, share_5, share_10 | `llm_share: 0.01 / 0.05 / 0.10` | 101–104 | 1,728 | 0.86 |
63+| | share_75, share_100 | `llm_share: 0.75 / 1.00` (95 eligible slots at 100 %) | 101–102 | 9,180 | 4.59 |
64+| T4 mechanisms (φ = 0.25) | memory_25 | `llm.memory: 5` | 101–103 | 2,025 | 1.01 |
65+| | channel_25 | `llm.channel: true` (cohorts of 5) | 101–103 | 2,025 | 1.01 |
66+| | leverage_25 | `population.mix.leveraged: 0.19, trend: 0.06` (+ free `leverage_0` control at φ = 0 for the E5 interaction) | 101–103 | 2,025 | 1.01 |
67+| | breaker_25 | `exchange.halt_threshold: 0.05` (10-tick window, 20-tick halt) | 101–103 | 2,025 | 1.01 |
68+| | poslimit_25 | `exchange.position_limit: 300` | 101–102 | 1,350 | 0.68 |
69+| T5 fairness | mini_25_equalusd | mini_25 with `llm.usd_cap` = mean nano spend of share_25 (TBD ≈ 0.34) → decisions stop at equal USD | 101–103 | ≤ 630 mini | ≤ 1.01 |
70+| T6 extensions | k2_25 | two assets, `factor_loading: [0.7, 0.7]`, `statarb: 0.05` | 101–102 | 1,350 | 0.68 |
71+| | library_1000 | `population.n_traders: 1000`, `llm.frozen_library: results/library/nano_v1.npz`, provider `library` | 101–110 | 0 | 0 |
72+| | auction_25, interval_10 | call auction every 5 ticks; `decision_interval: 10` — **mock only** | 1–10 | 0 | 0 |
73+| **Confirmatory total** | | | | ≈ 66,000 | **≈ 33.3** |
74+| Pilot (§4) | | | | 6,480 | 3.24 |
75+| Contingency (retries, longer outputs) | | | | | ≈ 3.5 (≈ 9 %) |
76+| **Project cap** | | | | | **40.00** |
77+
78+Notes. (i) Equal-decisions fairness is the default (`decision_cap` unset: every LLM agent gets the same 27 opportunities); equal-USD uses the per-run `usd_cap` and therefore applies to single-provider cells only — the code has no per-provider cap. (ii) The two-model mix: `provider_mix` keys are providers, not models, and `models` maps one model per provider; mixing two OpenAI models in one run requires either a second provider alias (e.g. `openai_mini`) or a per-slot model list — a gate-4 engineering item; until then `mix_25` is dry-run with `{mock: 0.5, openai: 0.5}`. (iii) Claude cells (haiku_25 at ≈ 0.19 USD per 1,000 decisions; sonnet at ≈ 3.8 USD per 1,000) are planned only if a valid key *and* additional budget are approved before the freeze; they are not in the 40 USD plan. (iv) `ma budget` reproduces this table with `--tokens-in 760 --tokens-out 230`.
79+
80+### 5.3 Execution order and order of sacrifice
81+
82+Tiers run T1 → T6; spend is reconciled after each tier (`sum(llm_usd)` over `outcomes.parquet` plus the provider dashboard). If the cumulative spend exceeds the plan by > 10 %, seeds are cut in this fixed order: T6 → T5 → T3 (share_75/100 first) → T4 poslimit → T2 mini_25 (E3(b) then unavailable) → T4 others. T1 is never cut below 8 seeds. Nothing is added after seeing confirmatory results.
83+
84+### 5.4 Frozen-library replay (T6)
85+
86+Build the library from the T1 nano runs: `DecisionLibrary.from_runs([...T1 run dirs...]).save("results/library/nano_v1.npz")`. Replay at N = 1,000 with `activity` scaled by 100/N (as in `scripts/11_scale_benchmark.py`) so order flow per tick is constant. Report the nearest-neighbour distance distribution; if the median standardized distance at N = 1,000 exceeds the 90th percentile observed at N = 100, the arm is reported as out-of-support, not as evidence.
87+
88+## 6. Replication checklist
89+
90+1. `git log -1` matches `freeze.json`; `pytest` passes (23 tests).
91+2. `ma design` of each tier reproduces `outcomes.parquet` from the cache (`--cache` path, `llm_cached_hits` = 1.0, zero USD).
92+3. Every run directory has `manifest.json` with `config_hash`, `git_revision`, `prompt_version`, `price_assumptions`, `llm_usage`, `shocks`, `final_conservation_ok`.
93+4. Analysis scripts read only `outcomes.parquet`, `ticks.parquet`, `trades.parquet`, `llm_decisions.parquet`; tables and figures are regenerated by one command (`paper/Makefile`).
94+5. The sensitivity grid (bubble 3/5/8 %, crash 7/10/15 %) is produced by re-running `run_outcomes` with the alternative thresholds on saved ticks, not by re-simulating.
95+6. Decision logs are published without raw prompts if they contain nothing private (they do not: the prompt is a canonical market snapshot); model ids, dates and prices are listed in `model_cards.md`.
96+7. Deviations from this protocol are listed in the paper's appendix with the date and reason.
added docs/research_plan.md +63 −0
@@ -0,0 +1,63 @@
1+# Research plan — UQO Working Paper 27
2+## *The Invisible Hand of Machines: Price Discovery in Markets Populated by LLM Agents*
3+
4+Methodology document (causal inference and experimental design). Version 1.0, 2026-10-27. Companion documents: `identification.md` (pre-analysis plan), `protocol.md` (run protocol and budget), `assumptions.md` (assumption register), `model_cards.md`. The simulator is `src/market_agents`; what it implements is summarised in `DESIGN-BRIEF.md`.
5+
6+## 1. Primary contribution
7+
8+A randomized, pre-registered simulation experiment that identifies the *causal* effect of replacing a share of human-like heuristic traders by LLM-driven traders on price discovery, liquidity and stability in a continuous double auction. The identification strategy is experimental: treatment (which trader slots become LLM-controlled, which model/prompt they use, which market safeguards apply) is assigned by dedicated seed streams, while fundamentals, news, endowments and latencies are held fixed within matched seeds (common random numbers). The stylized model in the brief (shared model error η_g, effective number of models M_eff = 1/Σφ_g²) supplies the directional hypotheses; the simulator tests them.
9+
10+What is new relative to the LLM-agent-market literature: (i) explicit control arms and matched pairs instead of single demonstrations; (ii) dose–response in the LLM share; (iii) diversity as a treatment (same model vs diverse prompts vs model mix) at a *fixed* share; (iv) safeguards as treatments; (v) a budget-explicit, power-explicit protocol with pre-specified stopping and negative-result rules.
11+
12+## 2. Research questions and hypotheses
13+
14+| RQ | Question | Hypothesis (brief) | Lead outcome (`outcomes.py`) |
15+|---|---|---|---|
16+| RQ1 | Does price informativeness fall as the share φ of traders sharing one model rises, holding information quality fixed? | H1: `msd_log` increases in φ; falls in M_eff | `msd_log` |
17+| RQ2 | Do LLM traders produce correlated, synchronised order flow? | H2: ρ̄ and synchrony rise in φ | `llm_pairwise_corr` |
18+| RQ3 | Does the φ × leverage interaction raise bubble/crash frequency and liquidity spirals? | H3: `n_crashes`, `max_dd`, `n_bubbles` rise with φ × leverage | `n_crashes` |
19+| RQ4 | Does prompt or model diversity restore part of the loss? | H4: diverse < single on `msd_log` at equal φ | `msd_log` (diverse − single) |
20+| RQ5 | Does a communication channel raise synchrony? | H5: channel on > off on synchrony | `llm_synchrony` |
21+| RQ6 | Do circuit breakers and position limits cut crash depth at a cost in absorption time? | H6: `max_dd` falls, `time_to_absorb` rises | `max_dd` |
22+
23+Liquidity (spread, depth, Kyle λ, resiliency) is treated as a sub-family H1b of RQ1 with its own lead outcome `spread_bp`. Full outcome families, directions, thresholds and estimators: `identification.md` §3–4.
24+
25+## 3. Phases, gates and status
26+
27+| Phase | Content | Gate (must hold to proceed) | Status 2026-10-27 |
28+|---|---|---|---|
29+| 0 | Scoping: brief, economy, treatments, outcome list | Brief agreed by author, theory and methods | Done (`DESIGN-BRIEF.md`) |
30+| 1 | Engine: event-sourced LOB, accounts, fees, latency, margin, halts, dividends, Kalman public value, news | Unit + property tests pass; cash/share conservation checked after every fill | Done — 23 tests pass (`tests/unit`, `tests/property`, `tests/integration`) |
31+| 2 | Classical population (fundamentalist, trend, mean-reverter, noise, market maker, leveraged, stat-arb), stratified slot assignment, seed streams | Determinism across identical runs; matched-pair invariance of fundamentals and endowments (`test_common_random_numbers_across_llm_share`) | Done |
32+| 3 | Calibration and scale | Stylized facts reproduced (fat tails, volatility clustering, spread/depth in plausible range); run time ≤ 1 min at N = 10,000 | Done — 360-run sweep (`results/calibration/sweep.parquet`): default cell kurtosis ≈ 27, Σ ACF(abs r) ≈ 3.1, spread ≈ 12 bp, mad ≈ 3.3 %; wall time 0.5 s / 2.4 s / 22 s at N = 100 / 1,000 / 10,000 |
33+| 4 | LLM layer (OpenAI, Anthropic, mock, library), cache, budget tracker, prompts v1, decision schema; pre-analysis plan (this folder) | **Gate 4 (open):** (a) information parity fix — an LLM slot must inherit the informed/uninformed status of the slot it replaces (`population.py`, l. 105; today 30 % of *all* LLM slots are informed vs 7.5 % of classical slots: in a mock run 44 % vs 6 %); (b) activation-stream fix — `runner.py` l. 204 shuffles the active list with the activation stream, so activation draws diverge across arms after tick 0 (96 % of non-replaced agents had a different order count across arms in a mock test); (c) confirmatory fundamentals with latent uncertainty — in the baseline the dividend reveals x_t exactly, so V^pub ≡ V and private signals are redundant (H1 not identified); (d) shock size — `size: 40.0` moves V by +8.4 %, not the +2 % stated in the YAML comment (a lagged response then counts as a 5 % "bubble"); use ≈ 10 c (+2.1 %); (e) first git commit so manifests carry a `git_revision`; (f) documents of this folder reviewed | In progress: code exists, Anthropic key rejected (HTTP 401) → Claude cells mock-only |
34+| 5 | Mock dry-run of every cell (`configs/exploratory.yaml`), then live OpenAI pilot (`configs/pilot_openai.yaml`, ≤ 5 USD) | Validity rate ≥ 80 %, failure rate ≤ 10 %, cost per decision within ±30 % of 0.0005 USD, σ of paired differences estimated | Configs written, not run |
35+| 6 | Freeze: prompt v1 SHA, schema, config hashes, thresholds, estimators, seed lists, budget tiers (§`identification.md` §6) | Freeze record committed before any confirmatory call | Pending pilot |
36+| 7 | Confirmatory runs by tier (`protocol.md` §5), reconciliation of spend after each tier | Cumulative live spend ≤ 40 USD; balanced seeds within tier | Not started |
37+| 8 | Analysis: paired estimates, randomization inference, dose–response, diversity contrasts, local projections, sensitivity grid, mediation (descriptive), robustness (mock, library at N = 1,000, call auction) | All pre-registered tables produced from `results/runs/*/outcomes.parquet` by scripted code; no hand edits | Not started |
38+| 9 | Paper, replication package, model cards, data (decision logs without raw prompts) | Clean-room re-run of one tier from the frozen library reproduces tables | Literature review and theory in progress |
39+
40+## 4. What would make us abandon or revise each hypothesis
41+
42+Criteria are evaluated on the confirmatory tier for the primary contrast (25 % vs 0 %, gpt-5.4-nano, single prompt) unless stated. MDE = minimal detectable effect at the achieved seed count (≈ d = 0.9 at n = 10 pairs; see `identification.md` §5).
43+
44+| H | Revise if | Abandon (report as negative) if |
45+|---|---|---|
46+| H1 (informativeness ↓ in φ) | `msd_log` effect is positive but driven entirely by the `llm_valid_rate` or by the realized order share being < 2 % (dose too small to matter) → re-interpret as "activity" effect; or effect disappears under latent-uncertainty fundamentals but not under exact-revelation fundamentals → it is a microstructure, not an information, effect | Paired 95 % CI of Δ`msd_log` excludes d ≥ 0.5 in the predicted direction at both 25 % and 50 %, and the dose–response (Page's L) is flat |
47+| H2 (ρ̄, synchrony ↑ in φ) | ρ̄ among LLM agents is high but *not* higher than among classical agents of the replaced types (classical analogue computed from `trades.parquet`; see `identification.md` §3.4) → the correlation is a property of rule-like trading, not of model sharing | ρ̄ does not rise with φ (Page's L, p > 0.05) *and* is below the classical analogue |
48+| H3 (φ × leverage → crashes) | Crash counts are zero at the 10 % threshold in all cells (floor effect) → use the pre-registered 7 % sensitivity threshold and `max_dd` as lead | Interaction term CI excludes the predicted sign at 7, 10 and 15 % thresholds |
49+| H4 (diversity restores) | Diverse prompts help but model mix does not (or vice versa) → theory must distinguish persona-level from model-level error η_g | Neither contrast (diverse − single; mix − average of singles) has the predicted sign with CI excluding d ≥ 0.5 |
50+| H5 (channel ↑ synchrony) | Synchrony rises but `msd_log` does not → channel moves coordination without moving prices | Channel effect on `llm_synchrony` CI excludes d ≥ 0.5 |
51+| H6 (safeguards) | `max_dd` falls but `time_to_absorb` does not rise → no trade-off (report as such) | Breaker and position limit both leave `max_dd` and `n_crashes` unchanged (CI excludes d ≥ 0.5) |
52+
53+Cross-cutting abandonment: if the pilot validity rate of gpt-5.4-nano is < 80 % after one prompt revision (v2), the treatment is "an agent that mostly holds" and the study is reframed around activity rather than reasoning; if the live spend cannot deliver ≥ 8 matched seeds on the primary contrast, the confirmatory claim is downgraded to "exploratory, powered for d ≥ 1 only".
54+
55+## 5. Risks
56+
57+| Risk | Mitigation |
58+|---|---|
59+| Anthropic key invalid (confirmed 2026-10-27) | Claude cells are implemented and mock-tested; they enter the design only when a key is validated; budget tiers do not depend on them |
60+| Budget: 40 USD ≈ 70,000–80,000 nano decisions; a full factorial is impossible | Tiered design with a pre-specified order of sacrifice (`protocol.md` §5.3) |
61+| Provider non-determinism and drift | Every response cached (SQLite) with request id; replay reproduces runs exactly; model snapshot and date recorded in manifests |
62+| Realized LLM dose far below slot share (mock: 3.5 % of orders at 25 % of slots) | Report both assigned and realized dose; `decision_interval` sensitivity with the mock; interpret effects per unit of realized order share |
63+| Pilot σ from 3 pairs is imprecise | Classical control σ from 30 free seeds as floor; conservative seed rule |
added paper/.latexmkrc +5 −0
@@ -0,0 +1,5 @@
1+$pdf_mode = 1;
2+$pdflatex = 'pdflatex -interaction=nonstopmode -halt-on-error -synctex=1 %O %S';
3+$bibtex_use = 2;
4+$clean_ext = 'synctex.gz run.xml bbl bcf fdb_latexmk fls log aux out toc lof lot blg';
5+@default_files = ('main.tex');
added paper/Makefile +11 −0
@@ -0,0 +1,11 @@
1+.PHONY: all clean distclean
2+
3+all:
4+ latexmk
5+
6+clean:
7+ latexmk -c
8+
9+distclean:
10+ latexmk -C
11+ rm -f *.synctex.gz *.run.xml *.bbl *.bcf
added paper/appendices/proofs.tex +282 −0
@@ -0,0 +1,282 @@
1+% paper/appendices/proofs.tex — UQO WP 27. Proofs of the propositions of Section "A stylized model".
2+\section{Proofs}
3+\label{app:proofs}
4+
5+Throughout, A1--A4 hold and the notation is that of Section~\ref{sec:theory}:
6+$n_g=\phi_gN$, $\Phi=\sum_g\phi_g$, $H=\sum_g\phi_g^2$, $\sigma_s^2=\sigma_v^2+\sigma_\eta^2+\sigma_u^2$,
7+$\bar\varepsilon=N^{-1}\sum_i\varepsilon_i$ and $\bar Y=Y/(\beta N)$.
8+
9+\subsection*{Two lemmas}
10+
11+\begin{lemma}[Flow decomposition]
12+\label{lem:flow}
13+$Y=\beta N\,(v+\bar\varepsilon)+z$ and
14+$\operatorname{Var}(\bar\varepsilon)=\sigma_\eta^2\big[H+(1-\Phi)/N\big]+\sigma_u^2/N$. Consequently
15+$\operatorname{Var}(\bar Y-v)=\Omega$ as defined in \eqref{eq:lambda}.
16+\end{lemma}
17+
18+\begin{proof}
19+By A2, $\sum_ix_i=\beta\sum_i(v+\varepsilon_i)=\beta N(v+\bar\varepsilon)$. Let $I$ be the set of
20+traders on private models, $|I|=N(1-\Phi)$. Then
21+$\sum_i\varepsilon_i=\sum_{g=1}^Gn_g\eta_g+\sum_{i\in I}\eta_i+\sum_{i=1}^Nu_i$, a sum of
22+$G+|I|+N$ independent centered Gaussians (A1), whence
23+$\operatorname{Var}(\sum_i\varepsilon_i)=\sigma_\eta^2\sum_gn_g^2+\sigma_\eta^2N(1-\Phi)+N\sigma_u^2$.
24+Dividing by $N^2$ and using $n_g^2/N^2=\phi_g^2$ gives the variance of $\bar\varepsilon$. Finally
25+$\bar Y-v=\bar\varepsilon+z/(\beta N)$ with $z$ independent of $\bar\varepsilon$, so
26+$\operatorname{Var}(\bar Y-v)=\operatorname{Var}(\bar\varepsilon)+\sigma_z^2/(\beta^2N^2)=\Omega$.
27+\end{proof}
28+
29+\begin{lemma}[Projection]
30+\label{lem:proj}
31+$\lambda=\tau/(\beta N)$, $\tau=\sigma_v^2/(\sigma_v^2+\Omega)$, $P=\tau\bar Y$, and
32+$\operatorname{Var}(P-v)=\operatorname{Var}(v\mid Y)=\sigma_v^2(1-\tau)$.
33+\end{lemma}
34+
35+\begin{proof}
36+$(v,Y)$ is jointly Gaussian, so $\mathbb E[v\mid Y]=\lambda Y$ with
37+$\lambda=\operatorname{Cov}(v,Y)/\operatorname{Var}(Y)$ and
38+$\operatorname{Var}(v\mid Y)=\sigma_v^2-\operatorname{Cov}(v,Y)^2/\operatorname{Var}(Y)$. By Lemma~\ref{lem:flow},
39+$\operatorname{Cov}(v,Y)=\beta N\sigma_v^2$ and $\operatorname{Var}(Y)=\beta^2N^2(\sigma_v^2+\Omega)$. Hence
40+$\tau=1-\operatorname{Var}(v\mid Y)/\sigma_v^2=\operatorname{Cov}(v,Y)^2/(\sigma_v^2\operatorname{Var}(Y))
41+=\sigma_v^2/(\sigma_v^2+\Omega)$ and $\lambda=\sigma_v^2/[\beta N(\sigma_v^2+\Omega)]=\tau/(\beta N)$, so
42+$P=\lambda Y=\tau\bar Y$. For the pricing error,
43+\begin{align*}
44+\operatorname{Var}(P-v)&=\lambda^2\operatorname{Var}(Y)-2\lambda\operatorname{Cov}(v,Y)+\sigma_v^2
45+=\frac{\operatorname{Cov}(v,Y)^2}{\operatorname{Var}(Y)}-2\frac{\operatorname{Cov}(v,Y)^2}{\operatorname{Var}(Y)}+\sigma_v^2\\
46+&=\sigma_v^2-\frac{\operatorname{Cov}(v,Y)^2}{\operatorname{Var}(Y)}=\operatorname{Var}(v\mid Y),
47+\end{align*}
48+which equals $\sigma_v^2(1-\tau)$ by definition of $\tau$.
49+\end{proof}
50+
51+\subsection*{Proof of Proposition~\ref{prop:info}}
52+
53+With a single model of $n=\phi N$ users, $H=\phi^2$ and $\Phi=\phi$, so Lemma~\ref{lem:flow} gives
54+\eqref{eq:tau_phi}. Since $\tau=\sigma_v^2/(\sigma_v^2+\Omega)$ is strictly decreasing in $\Omega$, every
55+monotonicity claim about $\tau$ is the reverse claim about $\Omega$.
56+
57+\emph{(i) Discrete monotonicity.} Writing $\Omega$ as a function of the integer $n$,
58+$\Omega(n)=\sigma_\eta^2\,(n^2-n+N)/N^2+C$ with $C=\sigma_u^2/N+\sigma_z^2/(\beta^2N^2)$. Then
59+\[
60+\Omega(n+1)-\Omega(n)=\frac{\sigma_\eta^2}{N^2}\Big[(n+1)^2-(n+1)-n^2+n\Big]=\frac{2n\,\sigma_\eta^2}{N^2},
61+\]
62+which is zero for $n=0$ and strictly positive for every $n\ge1$ when $\sigma_\eta^2>0$. Hence
63+$\Omega(0)=\Omega(1)<\Omega(2)<\dots<\Omega(N)$ and $\tau$ is strictly decreasing on $\{1/N,\dots,1\}$,
64+with $\tau(0)=\tau(1/N)$. For $N=1$ the grid is $\{0,1\}$ and $\Omega(0)=\Omega(1)$. In the continuous
65+relaxation, $\Omega'(\phi)=\sigma_\eta^2(2\phi-1/N)$, which is strictly positive if and only if
66+$\phi>1/(2N)$; so $\partial\tau/\partial\phi=-\sigma_v^2\Omega'(\phi)/(\sigma_v^2+\Omega)^2<0$ exactly
67+there. (For $0<\phi<1/(2N)$ the relaxation is slightly increasing in $\phi$; no integer population lies
68+in this region, since it corresponds to fewer than one-half of a trader using the model.)
69+
70+\emph{(ii) Uniform bound and limit.} For every $N$ and $\phi\in[0,1]$,
71+$\Omega(\phi)-\sigma_\eta^2\phi^2=\sigma_\eta^2(1-\phi)/N+\sigma_u^2/N+\sigma_z^2/(\beta^2N^2)\ge0$, so
72+$\Omega(\phi)\ge\sigma_\eta^2\phi^2$ and $\tau(\phi)\le\sigma_v^2/(\sigma_v^2+\phi^2\sigma_\eta^2)=\tau_\infty(\phi)$,
73+which is strictly below one when $\phi\sigma_\eta>0$. The difference $\Omega(\phi)-\sigma_\eta^2\phi^2$ is
74+$O(1/N)$ for fixed $\phi$ and fixed $\sigma_z^2$, so $\tau(\phi)\to\tau_\infty(\phi)$.
75+
76+\emph{(iii) Private-model benchmark.} At $\phi=0$, $\Omega=(\sigma_\eta^2+\sigma_u^2)/N+\sigma_z^2/(\beta^2N^2)$,
77+which tends to zero whenever $\sigma_z^2/N^2\to0$; then $\tau\to1$. If instead noise trading scales
78+with the market, $\sigma_z^2=cN^2$, the limit is $\sigma_v^2/(\sigma_v^2+c/\beta^2)<1$ even at $\phi=0$;
79+this is the usual noisy-rational-expectations bound and is unrelated to model sharing. \qed
80+
81+\subsection*{Proof of Proposition~\ref{prop:corr}}
82+
83+\emph{(i)} By Lemma~\ref{lem:proj}, $\operatorname{Var}(P-v)=\sigma_v^2(1-\tau)=\sigma_v^2\Omega/(\sigma_v^2+\Omega)$,
84+an increasing function of $\Omega$; the monotonicity in $\phi$ and the uniform lower bound follow from
85+parts (i)--(ii) of Proposition~\ref{prop:info} since $y\mapsto\sigma_v^2y/(\sigma_v^2+y)$ is increasing.
86+
87+\emph{(ii)} By A2, $\operatorname{Corr}(x_i,x_j)=\operatorname{Corr}(s_i,s_j)$ since $\beta>0$. By A1,
88+$\operatorname{Var}(s_i)=\sigma_s^2$ for every $i$, and for $i\neq j$,
89+$\operatorname{Cov}(s_i,s_j)=\sigma_v^2+\operatorname{Cov}(\eta_{g(i)},\eta_{g(j)})$, which equals
90+$\sigma_v^2+\sigma_\eta^2$ if $g(i)=g(j)\neq\varnothing$ and $\sigma_v^2$ otherwise (two private models, or
91+two different shared models, have independent $\eta$'s). This gives $\rho_1$ and $\rho_0$, and
92+$\rho_1-\rho_0=\sigma_\eta^2/\sigma_s^2>0$ if and only if $\sigma_\eta^2>0$.
93+
94+\emph{(iii)} Among the $N(N-1)$ ordered pairs $i\neq j$, exactly $n(n-1)$ have both members on the
95+shared model; all others have correlation $\rho_0$. Hence
96+$\bar\rho=\rho_0+w(\rho_1-\rho_0)$ with $w=n(n-1)/[N(N-1)]=\phi(N\phi-1)/(N-1)$. As a function of
97+real $\phi$, $w'(\phi)=(2N\phi-1)/(N-1)$ and $w''(\phi)=2N/(N-1)>0$: $w$ is convex and increasing
98+for $\phi>1/(2N)$. On the integer grid, $w(n+1)-w(n)=2n/[N(N-1)]>0$ for $n\ge1$. As $N\to\infty$,
99+$w\to\phi^2$.
100+
101+\emph{(iv)} Let $(x_i,x_j)$ be centered jointly Gaussian with correlation $\rho\in(-1,1)$. Write
102+$x_j/\sigma_j=\rho\,x_i/\sigma_i+\sqrt{1-\rho^2}\,\xi$ with $\xi$ standard normal independent of $x_i$.
103+The classical orthant formula gives $\Pr(x_i>0,x_j>0)=\tfrac14+\arcsin(\rho)/(2\pi)$; by symmetry
104+$\Pr(x_i<0,x_j<0)$ is the same, so $S(\rho)=\Pr(x_ix_j>0)=\tfrac12+\arcsin(\rho)/\pi$.\footnote{For
105+completeness: $\Pr(x_i>0,x_j>0)=\Pr(\vartheta\in(0,\pi/2)\text{ and }\vartheta\in(\alpha-\pi/2,\alpha+\pi/2))$
106+where $\vartheta$ is the uniformly distributed angle of a standard bivariate normal vector and
107+$\cos\alpha=\rho$; the two arcs overlap on a set of measure $\pi-\alpha$, so the probability is
108+$(\pi-\arccos\rho)/(2\pi)=\tfrac14+\arcsin(\rho)/(2\pi)$.} Since $\arcsin$ is strictly increasing on
109+$[-1,1]$, so is $S$. Averaging over ordered pairs with the same count as in (iii) gives \eqref{eq:sync}.
110+Because $\bar\rho$ is affine in $w$ with slope $\rho_1-\rho_0>0$ (when $\sigma_\eta^2>0$), we may
111+regard $\bar S$ as a function of $\bar\rho$ with
112+\[
113+\frac{d\bar S}{d\bar\rho}=\frac{1}{\pi}\cdot\frac{\arcsin\rho_1-\arcsin\rho_0}{\rho_1-\rho_0}>0 .
114+\]
115+For the Jensen bound, $(\arcsin)''(\rho)=\rho(1-\rho^2)^{-3/2}\ge0$ on $[0,1)$, and $\rho_0,\rho_1\ge0$,
116+so $(1-w)\arcsin\rho_0+w\arcsin\rho_1\ge\arcsin\big((1-w)\rho_0+w\rho_1\big)=\arcsin\bar\rho$, with
117+equality if and only if $\rho_0=\rho_1$ or $w\in\{0,1\}$; for $0<w<1$ equality thus requires
118+$\sigma_\eta^2=0$.
119+
120+\emph{The placebo.} If $\sigma_\eta^2=0$ then $\Omega$ does not depend on $\phi$ (the bracket in
121+\eqref{eq:tau_phi} is multiplied by zero), $\rho_1=\rho_0$, and $w$ drops out of \eqref{eq:rhobar} and
122+\eqref{eq:sync}. Hence none of the four objects varies with $\phi$. This shows that the restriction
123+$\sigma_\eta^2>0$ is necessary for every strict claim in the proposition. \qed
124+
125+\subsection*{Proof of Proposition~\ref{prop:diversity}}
126+
127+\emph{(i)} By Lemma~\ref{lem:flow}, $\Omega=\sigma_\eta^2[H+(1-\Phi)/N]+\sigma_u^2/N+\sigma_z^2/(\beta^2N^2)$;
128+for fixed $\Phi$ the shares enter only through $H$, and $\partial\Omega/\partial H=\sigma_\eta^2>0$, so
129+$\partial\tau/\partial H=-\sigma_v^2\sigma_\eta^2/(\sigma_v^2+\Omega)^2<0$. Setting $\Phi=1$ and $H=1/M_{\mathrm{eff}}$
130+gives the stated form.
131+
132+\emph{(ii)} By the Cauchy--Schwarz inequality,
133+$\Phi^2=\big(\sum_g\phi_g\cdot1\big)^2\le\big(\sum_g\phi_g^2\big)\big(\sum_g1^2\big)=GH$, with equality if
134+and only if $(\phi_g)$ is proportional to $(1,\dots,1)$, i.e.\ $\phi_g=\Phi/G$. For the upper bound,
135+$\Phi^2=\sum_g\phi_g^2+\sum_{g\neq g'}\phi_g\phi_{g'}\ge H$, with equality if and only if all cross
136+products vanish, i.e.\ at most one share is positive. In the integer version one minimizes $\sum_gn_g^2$
137+subject to $\sum_gn_g=\Phi N$: if some $n_a\ge n_b+2$, moving one trader from $a$ to $b$ changes the
138+sum by $(n_a-1)^2+(n_b+1)^2-n_a^2-n_b^2=-2(n_a-n_b-1)<0$, so at a minimum all $n_g$ differ by at most one.
139+
140+\emph{(iii)} Combine (i) and (ii): $H_{\text{single}}=\Phi^2\ge H_{\text{mixed}}\ge\Phi^2/G=H_{\text{uniform}}$
141+and $\tau$ is decreasing in $H$. Strictness: $H_{\text{mixed}}<\Phi^2$ as soon as two shares are
142+positive, and $\partial\tau/\partial H<0$ requires $\sigma_\eta^2>0$.
143+
144+\emph{(iv)} Ordered pairs with both members on the same shared model number
145+$\sum_gn_g(n_g-1)=N^2H-N\Phi$; dividing by $N(N-1)$ gives $w=(NH-\Phi)/(N-1)$. For fixed $\Phi$, $w$
146+is increasing in $H$, and $\bar\rho$ and $\bar S$ are increasing in $w$ by the proof of
147+Proposition~\ref{prop:corr}. \qed
148+
149+\subsection*{Proof of Proposition~\ref{prop:feedback} and Corollary~\ref{cor:llmtrend}}
150+
151+Under A5 the round's price change solves $\Delta P=\lambda(Y_1+\gamma\Delta P)$.
152+
153+\emph{(i)} If $\lambda\gamma\neq1$ the unique solution is $\Delta P^\ast=\lambda Y_1/(1-\lambda\gamma)=\kappa\lambda Y_1$.
154+The iterated response satisfies $\Delta P^{(k+1)}-\Delta P^\ast=\lambda\gamma(\Delta P^{(k)}-\Delta P^\ast)$,
155+so $\Delta P^{(k)}-\Delta P^\ast=(\lambda\gamma)^k(\Delta P^{(0)}-\Delta P^\ast)$, which converges to zero
156+for every starting point if and only if $|\lambda\gamma|<1$; with $\gamma\ge0$ this is $\lambda\gamma<1$.
157+Then $\operatorname{Var}(\Delta P)=\kappa^2\lambda^2\operatorname{Var}(Y_1)$, i.e.\ amplification by
158+$\kappa^2=1/(1-\lambda\gamma)^2$ relative to the no-feedback price change $\lambda Y_1$.
159+
160+\emph{(ii)} If $\lambda\gamma=1$ the equation reads $\Delta P=\lambda Y_1+\Delta P$, impossible for
161+$Y_1\neq0$, and the iteration gives $\Delta P^{(k)}=\Delta P^{(0)}+k\lambda Y_1$, unbounded. If
162+$\lambda\gamma>1$ the algebraic solution $\Delta P^\ast=\lambda Y_1/(1-\lambda\gamma)$ exists but has the
163+sign of $-Y_1$ (a price that falls when the flow is a net purchase), and since $(\lambda\gamma)^k\to\infty$
164+the iteration diverges from every $\Delta P^{(0)}\neq\Delta P^\ast$; in particular from the natural start
165+$\Delta P^{(0)}=\lambda Y_1$. This is the counterexample announced in the text: the closed form
166+$1/(1-\lambda\gamma)^2$ is meaningless outside $\lambda\gamma<1$.
167+
168+\emph{(iii)} $\Delta P^\ast=\kappa\lambda Y_1$ is a strictly monotone function of $Y_1$ (for $\kappa>0$), so
169+$\sigma(\Delta P^\ast)=\sigma(Y_1)$ and $\operatorname{Var}(v\mid P_1)=\operatorname{Var}(v\mid Y_1)$: $\tau$ is unchanged.
170+Using $\lambda^2\operatorname{Var}(Y_1)=\lambda\operatorname{Cov}(v,Y_1)=\sigma_v^2\tau$ (Lemma~\ref{lem:proj}),
171+\[
172+\operatorname{Var}(\kappa\lambda Y_1-v)=\kappa^2\lambda^2\operatorname{Var}(Y_1)-2\kappa\lambda\operatorname{Cov}(v,Y_1)+\sigma_v^2
173+=\sigma_v^2\big[\kappa^2\tau-2\kappa\tau+1\big]=\sigma_v^2\big[(1-\tau)+\tau(\kappa-1)^2\big].
174+\]
175+On $\gamma\in[0,1/\lambda)$, $\kappa$ increases from $1$ to $+\infty$, so $(\kappa-1)^2$ is increasing in $\gamma$.
176+
177+\emph{Corollary.} Under A6 the total flow is $Y_1+\gamma_T\Delta P+\sum_i\kappa_{g(i)}\Delta P
178+=Y_1+\big(\gamma_T+\sum_gn_g\kappa_g\big)\Delta P=Y_1+\big(\gamma_T+N\sum_g\phi_g\kappa_g\big)\Delta P$,
179+with $\kappa_\varnothing\equiv0$ for private-model traders (any such loading can be folded into $\gamma_T$).
180+Applying (i)--(ii) with $\gamma=\gamma_T+N\sum_g\phi_g\kappa_g$ gives the statements; with a single
181+model, $\gamma(\phi)=\gamma_T+N\phi\kappa$ is increasing in $\phi$ when $\kappa>0$, $\kappa^2(\phi)$ is
182+increasing in $\gamma$ hence in $\phi$, and $\lambda\gamma(\phi)<1$ if and only if
183+$\phi<\phi^\ast=(1/\lambda-\gamma_T)/(N\kappa)$. If $\kappa=0$, $\gamma$ does not depend on $\phi$. With
184+several models, $\sum_g\phi_g\kappa_g$ is a share-weighted average that lies between $\Phi\min_g\kappa_g$
185+and $\Phi\max_g\kappa_g$; if the $\kappa_g$ differ in sign it can be smaller in absolute value than
186+$\Phi\kappa_g$ for every $g$. \qed
187+
188+\subsection*{Proof of Proposition~\ref{prop:spiral}}
189+
190+Let $R\equiv\{\Delta P:\Delta P<-b/X\}$ be the region in which $F>0$. On $R$,
191+$F(\Delta P)=(-X\Delta P-b)/m$ and the fixed-point equation $\Delta P=\Delta P_0-\lambda F(\Delta P)$ reads
192+\begin{equation}
193+ \Delta P=\Delta P_0+a\,\Delta P+\frac{\lambda b}{m},\qquad a=\frac{\lambda X}{m}.
194+ \label{eq:fp_affine}
195+\end{equation}
196+Off $R$, $F=0$ and the equation reads $\Delta P=\Delta P_0$.
197+
198+\emph{(i)} If $\Delta P_0\ge-b/X$, then $\Delta P=\Delta P_0\notin R$ solves the equation, and the
199+cascade defined below stops at its first step since $F(\Delta P_0)=0$. For $a<1$ it is the only fixed
200+point: a solution in $R$ would satisfy \eqref{eq:fp_affine}, whose candidate
201+$(\Delta P_0+\lambda b/m)/(1-a)$ lies in $R$ if and only if $\Delta P_0+\lambda b/m<-(b/X)(1-a)=-b/X+\lambda b/m$,
202+i.e.\ $\Delta P_0<-b/X$, which fails. For $a>1$ and $b>0$ the same algebra shows that the candidate
203+\emph{does} lie in $R$ whenever $\Delta P_0>-b/X$ (dividing by $1-a<0$ reverses the inequality): a
204+second, self-fulfilling fixed point exists in which the cohort is forced to sell because the price has
205+fallen enough to exhaust the buffer, and the price has fallen because the cohort sells. This is the
206+multiplicity familiar from \citet{brunnermeierpedersen2009}. We select the cascade limit, which is
207+$\Delta P_0$; the simulator's forced-liquidation rule is likewise sequential and cannot jump to the
208+self-fulfilling point.
209+
210+\emph{(ii)} Suppose $\Delta P_0<-b/X$ and $a<1$. The candidate $\Delta P=\Delta P_0$ is in $R$, where
211+$F>0$, so it is not a solution; the affine equation \eqref{eq:fp_affine} has the unique solution
212+$\Delta P^\ast=(\Delta P_0+\lambda b/m)/(1-a)$, which lies in $R$ by the equivalence just shown. With $b=0$
213+this is $\Delta P_0/(1-\lambda X/m)$ and the multiplier $1/(1-a)$ exceeds one. For the cascade, let
214+$\Delta P^{(0)}=\Delta P_0$ and $\Delta P^{(k)}=\Delta P_0-\lambda F(\Delta P^{(k-1)})$. Since
215+$\Delta P^{(0)}\in R$, $\Delta P^{(1)}-\Delta P^{(0)}=-\lambda F(\Delta P_0)<0$, so $\Delta P^{(1)}\in R$; by
216+induction all iterates are in $R$ and satisfy $\Delta P^{(k)}-\Delta P^\ast=a(\Delta P^{(k-1)}-\Delta P^\ast)$,
217+hence
218+\begin{equation}
219+ \Delta P^{(k)}-\Delta P^\ast=a^k(\Delta P_0-\Delta P^\ast)=-a^{k+1}\,\frac{|\Delta P_0|-b/X}{1-a},
220+ \label{eq:cascade_path}
221+\end{equation}
222+where we used $\Delta P_0-\Delta P^\ast=-\frac{\lambda}{m}\frac{X\Delta P_0+b}{1-a}=a\frac{|\Delta P_0|-b/X}{1-a}$.
223+The sequence is decreasing and converges to $\Delta P^\ast$ since $a<1$.
224+
225+\emph{(iii)} Suppose $\Delta P_0<-b/X$ and $a\ge1$. No solution exists off $R$ (it would have to be
226+$\Delta P_0\in R$). On $R$, if $a=1$ then $\lambda b/m=(b/X)(\lambda X/m)=b/X$ and \eqref{eq:fp_affine} reduces to
227+$0=\Delta P_0+b/X$, which is false because $\Delta P_0<-b/X$; if $a>1$ the unique affine solution $(\Delta P_0+\lambda b/m)/(1-a)$ is the ratio of a
228+negative numerator and a negative denominator, hence positive, so it is not in $R$. Thus there is no
229+fixed point. Along the cascade, the increments obey
230+$\Delta P^{(k+1)}-\Delta P^{(k)}=-\lambda[F(\Delta P^{(k)})-F(\Delta P^{(k-1)})]=a(\Delta P^{(k)}-\Delta P^{(k-1)})$
231+as long as the iterates remain in $R$, which they do because the first increment is negative and the
232+ratio $a$ is positive; with $a\ge1$ the increments do not shrink, so $\Delta P^{(k)}\to-\infty$. In the
233+simulator the sequence stops at the price band.
234+
235+\emph{(iv)} $\sum_{i\in L}x_i=\beta\sum_{i\in L}s_i$ is a centered Gaussian (A1--A2) with
236+\[
237+\operatorname{Var}\Big(\sum_{i\in L}s_i\Big)=\sum_{i\in L}\operatorname{Var}(s_i)+\sum_{i\neq j\in L}\operatorname{Cov}(s_i,s_j)
238+=\sigma_s^2\big[N_L+N_L(N_L-1)\bar\rho_L\big],
239+\]
240+by definition of the cohort-average correlation $\bar\rho_L$. Hence $X=|Z|$ with
241+$Z\sim\mathcal N(0,\sigma_X^2)$, $\sigma_X=\beta\sigma_s\sqrt{N_L[1+(N_L-1)\bar\rho_L]}$. Standard facts give
242+$\mathbb E|Z|=\sigma_X\sqrt{2/\pi}$ and $\Pr(|Z|\ge c)=2\bar\Phi(c/\sigma_X)$ for $c>0$, both strictly
243+increasing in $\sigma_X$, which is strictly increasing in $\bar\rho_L$ when $N_L>1$. Finally, applying
244+Proposition~\ref{prop:corr}(iii) to the cohort (with $N_L$ in place of $N$ and the cohort's own
245+shared-model share), $\bar\rho_L$ is increasing in that share on its admissible grid. The spiral
246+probability is $\Pr(a\ge1)=\Pr(X\ge m/\lambda)$, which gives the stated expression with $c=m/\lambda$.
247+
248+\emph{Remark on the net position.} If the cohort contains both longs and shorts, a negative shock forces
249+sales only from the longs, whose gross exposure $\sum_{i\in L}\max\{x_i,0\}$ is at least
250+$\max\{\sum_{i\in L}x_i,0\}$; using the net position in the spiral coefficient therefore understates
251+$a$ for a shock against the cohort's net side, and the spiral condition stated is sufficient, not
252+necessary. \qed
253+
254+\subsection*{Proof of Proposition~\ref{prop:safeguards}}
255+
256+\emph{(i)} If $X\le L<m/\lambda$ then $a=\lambda X/m\le\lambda L/m<1$ for every realization, so case (iii)
257+of Proposition~\ref{prop:spiral} cannot occur and, by case (ii), the multiplier is at most
258+$1/(1-\lambda L/m)$. For the informational cost, let $g(s)=\min\{\max\{\beta s,-\ell\},\ell\}$, which is
259+Lipschitz with $g'(s)=\beta\,\mathbf 1\{|\beta s|<\ell\}$ almost everywhere. Since $(v,s_i)$ is jointly
260+Gaussian, write $v=\theta s_i+e$ with $\theta=\operatorname{Cov}(v,s_i)/\operatorname{Var}(s_i)$ and $e$ independent of
261+$s_i$. Then $\operatorname{Cov}(v,g(s_i))=\theta\operatorname{Cov}(s_i,g(s_i))=\theta\operatorname{Var}(s_i)\mathbb E[g'(s_i)]$ by
262+Stein's lemma, i.e.\ $\operatorname{Cov}(v,\tilde x_i)=\operatorname{Cov}(v,s_i)\,\beta\Pr(|\beta s_i|<\ell)=\Pr(|\beta s_i|<\ell)\operatorname{Cov}(v,x_i)$,
263+and $\Pr(|\beta s_i|<\ell)<1$ for any finite $\ell$. We do not claim a closed form for $\tau$ under
264+clipping, since the clipped flow is non-Gaussian and the market maker's pricing rule is then nonlinear.
265+
266+\emph{(ii)} Under A7, after the halt the cascade is that of Proposition~\ref{prop:spiral} with $a$
267+replaced by $a_h\equiv\psi(h)a$ and the same starting point $\Delta P_0$ (nothing trades during the
268+halt). If $a_h<1$, part (ii) of that proposition gives convergence to
269+$\Delta P^\ast_h=(\Delta P_0+\lambda b/m)/(1-a_h)$, finite regardless of whether $a<1$. If also $a<1$,
270+then $1-a_h\ge1-a>0$ and the common numerator is negative, so $|\Delta P^\ast_h|\le|\Delta P^\ast|$, with
271+strict inequality if $\psi(h)<1$.
272+
273+\emph{(iii)} From \eqref{eq:cascade_path}, $|\Delta P^{(k)}-\Delta P^\ast|=a^{k+1}(|\Delta P_0|-b/X)/(1-a)$,
274+which is at most $\epsilon$ if and only if $k+1\ge\log\big(\epsilon(1-a)/(|\Delta P_0|-b/X)\big)/\log a$
275+(the division by $\log a<0$ reverses the inequality). Hence
276+$T_\epsilon(a)=\max\{0,\lceil\log(\epsilon(1-a)/(|\Delta P_0|-b/X))/\log a\rceil-1\}$, which is the stated
277+formula when $b=0$. Under the halt, rounds $1,\dots,h$ leave the price at $\Delta P_0$ and the cascade
278+with coefficient $a_h$ then starts from $\Delta P_0$, so the first round within $\epsilon$ of
279+$\Delta P^\ast_h$ is $h+T_\epsilon(a_h)$. Since $T_\epsilon\ge0$, $T^h_\epsilon\ge h$; if $\psi(h)=1$ then
280+$a_h=a$, $\Delta P^\ast_h=\Delta P^\ast$ and $T^h_\epsilon=T_\epsilon(a)+h$. When $a\ge1$ and $a_h<1$ the
281+comparison is $T^h_\epsilon<\infty=T_\epsilon(a)$, where the latter is infinite because the no-halt cascade
282+has no finite limit (Proposition~\ref{prop:spiral}(iii)). \qed
added paper/references.bib +1526 −0
Large diff (1,526 lines) is not loaded by default to keep the page fast.Load diff
added paper/sections/theory.tex +470 −0
Large diff (470 lines) is not loaded by default to keep the page fast.Load diff
added paper/sections/titlepage.tex +77 −0
Large diff (77 lines) is not loaded by default to keep the page fast.Load diff
added paper/sections/titlepage_anon.tex +53 −0
Large diff (53 lines) is not loaded by default to keep the page fast.Load diff
added paper/tex2docx/README.md +26 −0
Large diff (26 lines) is not loaded by default to keep the page fast.Load diff
added paper/tex2docx/post_docx.py +41 −0
Large diff (41 lines) is not loaded by default to keep the page fast.Load diff
added paper/tex2docx/prep_tex.py +134 −0
Large diff (134 lines) is not loaded by default to keep the page fast.Load diff
added paper/uq_logo.jpg +0 −0

Binary file not shown.

added pyproject.toml +45 −0
Large diff (45 lines) is not loaded by default to keep the page fast.Load diff
added results/calibration/scale_benchmark.json +373 −0
Large diff (374 lines) is not loaded by default to keep the page fast.Load diff
added results/calibration/sweep_summary.csv +37 −0
Large diff (37 lines) is not loaded by default to keep the page fast.Load diff
added results/figures/fig_baseline_paths.pdf +0 −0

Binary file not shown.

added results/figures/fig_baseline_paths.png +0 −0

Binary file not shown.

added results/figures/fig_classical_lambda_bp_100.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_lambda_bp_100.png +0 −0

Binary file not shown.

added results/figures/fig_classical_mad_pct.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_mad_pct.png +0 −0

Binary file not shown.

added results/figures/fig_classical_max_dd.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_max_dd.png +0 −0

Binary file not shown.

added results/figures/fig_classical_n_bubbles.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_n_bubbles.png +0 −0

Binary file not shown.

added results/figures/fig_classical_spread_bp.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_spread_bp.png +0 −0

Binary file not shown.

added results/figures/fig_classical_time_to_absorb.pdf +0 −0

Binary file not shown.

added results/figures/fig_classical_time_to_absorb.png +0 −0

Binary file not shown.

added results/figures/fig_contagion_excess.pdf +0 −0

Binary file not shown.

added results/figures/fig_contagion_excess.png +0 −0

Binary file not shown.

added results/figures/fig_contagion_spillover.pdf +0 −0

Binary file not shown.

added results/figures/fig_contagion_spillover.png +0 −0

Binary file not shown.

added results/figures/fig_wealth_depth.pdf +0 −0

Binary file not shown.

added results/figures/fig_wealth_depth.png +0 −0

Binary file not shown.

added results/runs/.gitkeep +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added results/tables/theory_checks.csv +89 −0
Large diff (89 lines) is not loaded by default to keep the page fast.Load diff
added scripts/10_calibration_sweep.py +62 −0
Large diff (62 lines) is not loaded by default to keep the page fast.Load diff
added scripts/11_scale_benchmark.py +32 −0
Large diff (32 lines) is not loaded by default to keep the page fast.Load diff
added scripts/40_figures.py +152 −0
Large diff (152 lines) is not loaded by default to keep the page fast.Load diff
added scripts/50_tables.py +221 −0
Large diff (221 lines) is not loaded by default to keep the page fast.Load diff
added scripts/90_theory_checks.py +264 −0
Large diff (264 lines) is not loaded by default to keep the page fast.Load diff
added scripts/analyze.py +6 −0
Large diff (6 lines) is not loaded by default to keep the page fast.Load diff
added scripts/run_experiment.py +6 −0
Large diff (6 lines) is not loaded by default to keep the page fast.Load diff
added scripts/smoke_test.py +22 −0
Large diff (22 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/__init__.py +2 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/agents/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/agents/base.py +98 −0
Large diff (98 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/agents/classical.py +338 −0
Large diff (338 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/analysis/__init__.py +1 −0
Large diff (1 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/analysis/estimators.py +126 −0
Large diff (126 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/analysis/plots.py +137 −0
Large diff (137 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/assets/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/assets/fundamentals.py +165 −0
Large diff (165 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/cli.py +68 −0
Large diff (68 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/accounts.py +120 −0
Large diff (120 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/book.py +190 −0
Large diff (190 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/call_auction.py +37 −0
Large diff (37 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/engine.py +487 −0
Large diff (487 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/exchange/orders.py +133 −0
Large diff (133 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/experiments/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/experiments/config.py +202 −0
Large diff (202 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/experiments/design.py +111 −0
Large diff (111 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/experiments/population.py +119 −0
Large diff (119 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/experiments/runner.py +357 −0
Large diff (357 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/budget.py +75 −0
Large diff (75 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/cache.py +51 −0
Large diff (51 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/library.py +96 −0
Large diff (96 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/policy.py +219 −0
Large diff (219 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/prompting.py +97 −0
Large diff (97 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/providers/__init__.py +31 −0
Large diff (31 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/providers/anthropic_provider.py +55 −0
Large diff (55 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/providers/mock.py +78 −0
Large diff (78 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/providers/openai_provider.py +70 −0
Large diff (70 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/llm/schema.py +65 −0
Large diff (65 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/metrics/__init__.py +1 −0
Large diff (1 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/metrics/outcomes.py +269 −0
Large diff (269 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/signals/__init__.py +2 −0
Large diff (2 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/signals/news.py +75 −0
Large diff (75 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/utils/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/utils/hashing.py +21 −0
Large diff (21 lines) is not loaded by default to keep the page fast.Load diff
added src/market_agents/utils/rng.py +20 −0
Large diff (20 lines) is not loaded by default to keep the page fast.Load diff
added tests/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/conftest.py +14 −0
Large diff (14 lines) is not loaded by default to keep the page fast.Load diff
added tests/integration/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/integration/test_simulation.py +61 −0
Large diff (61 lines) is not loaded by default to keep the page fast.Load diff
added tests/property/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/property/test_lob_properties.py +64 −0
Large diff (64 lines) is not loaded by default to keep the page fast.Load diff
added tests/statistical/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/unit/__init__.py +0 −0
Large diff (0 lines) is not loaded by default to keep the page fast.Load diff
added tests/unit/test_book.py +53 −0
Large diff (53 lines) is not loaded by default to keep the page fast.Load diff
added tests/unit/test_engine.py +104 −0
Large diff (104 lines) is not loaded by default to keep the page fast.Load diff
added tests/unit/test_llm_validation.py +51 −0
Large diff (51 lines) is not loaded by default to keep the page fast.Load diff
added uv.lock +1614 −0
Large diff (1,615 lines) is not loaded by default to keep the page fast.Load diff
Menu

Theme