SPB Git

spb/wp27_uqo

Public

fix: leaf dict overrides replace instead of merge (provider_mix was half mock in live cells)

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

53 changed files +972 −2

53 changed files
Unified Split
modified configs/baseline.yaml +1 −1
@@ -34,7 +34,7 @@ population:
34 34 decision_interval: 20
35 35 stagger: true
36 36 stagger_slots: 4
37 − informed_share: 0.3
37 + informed_share: null # inherit the replaced slot's information (matched pairs hold information fixed)
38 38 precision: 2.0
39 39 max_order_qty: 50
40 40 reasoning_effort: low
added docs/research_log.md +24 −0
@@ -0,0 +1,24 @@
1 +# Research log — WP 27 (chronological, 2026-10-27)
2 +
3 +All times local. Code revision in each run manifest (`git_revision`). Entries record every change made
4 +between the pre-analysis plan and the confirmatory runs, so that nothing is revised silently.
5 +
6 +| # | When | Phase | Change | Why | Consequence for pre-registration |
7 +|---|---|---|---|---|---|
8 +| 1 | 18:30 | 2 | Engine written: integer-cent accounting, price–time LOB, latency heap, fees, halts, margin, event log, replay | — | — |
9 +| 2 | 18:50 | 2 | Market-maker rule replaced (A–S formula in ticks² produced negative reservation prices → MM dumped inventory) by a bounded inventory-skew rule targeting the endowment | engine smoke run: price fell 30 % below value | baseline only |
10 +| 3 | 19:05 | 2 | Reservation accounting: limit bids reserve notional + worst-case fee + 1 c/lot; market buys priced lot-by-lot on the total fee; releases equal cash charged | property test found reserved cash 6 c above cash | — |
11 +| 4 | 19:20 | 3 | Calibration sweep (36 cells × 10 seeds): baseline = fundamentalist aggressiveness 20, trend + leveraged 10 %, noise market-order rate 0.6, MM size 20 | stylized facts: ACF₁ ≈ 0, kurtosis > 10, Σ ACF|r| ≈ 2.7, spread ≈ 24 bp, tracking error ≈ 1 % | baseline frozen |
12 +| 5 | 19:40 | 2 | Periodic call auction added (robustness) with market orders as IOC and a ±2 % collar | first version let band-edge market orders set the clearing price | robustness arm only |
13 +| 6 | 20:10 | 4 | OpenAI adapter verified live (gpt-5.4-nano); `max_output_tokens` raised 400 → 1200 because reasoning tokens count against it | smoke test truncated JSON | — |
14 +| 7 | 20:30 | 5 | LLM decisions batched into 4 stagger slots; parallel run workers | one decision per tick made API runs 10× slower | none (same decision count) |
15 +| 8 | 20:45 | 1→2 | **Fundamental timing restructured**: the upcoming dividend's deviation is latent during the period; PV = μ/r + x/(1+r−ρ); public filter updated by news; private signals are about the latent deviation | methodologist audit + classical runs: dividends revealed x exactly, so V^pub ≡ V, news and private signals were redundant (H1 unidentified) | this *is* the pre-registered economy; no confirmatory run had been analysed |
16 +| 9 | 21:05 | 1→2 | Shocks applied after the dividend step (a t = 300 jump was paid out at once); shock size 40 c → 10 c (+2.2 % of V) | public value jumped at the shock; 40 c was +9 % with the corrected PV | thresholds unchanged |
17 +| 10 | 21:10 | 1→2 | LLM slots inherit the replaced slot's information set (`llm.informed_share: null`); within-tick shuffle moved to its own RNG stream | methodologist audit: treatment bundled information; activations diverged across arms | matched-pair CRN now exact for every non-replaced agent |
18 +| 11 | 21:12 | — | First git commit; pilot and confirmatory designs launched on the frozen revision | manifests now carry `git_revision` | **freeze** |
19 +| 12 | — | 5 | Pilot (3 seeds × {5, 25, 50 %}, gpt-5.4-nano) runs concurrently with the confirmatory design on the same revision; pilot seeds (1–3) are never pooled with confirmatory seeds (201–207) | time budget | the pilot's role is reduced to cost/validity/variance reporting; the seed count (7) was fixed by the USD cap, not by the pilot variance |
20 +
21 +Known deviations from `docs/identification.md` / `docs/protocol.md` (written before items 8–12):
22 +- Noisy dividends (`jump_prob = 1`) were proposed to make V^pub ≠ V; item 8 achieves this through the timing of information instead (no jumps in the baseline).
23 +- The `mini-only at 25 %` cell needed for the model-mix decomposition was not run (≈ 8.5 USD): the two-model arm is compared with the single-model diverse-prompt arm only, and this limitation is stated in the paper.
24 +- Anthropic cells: the key provided on 2026-10-27 is rejected (HTTP 401). The adapter is implemented and dry-run tested with the mock provider; Claude cells are not part of the reported results.
added paper/appendices/hyperparameters.tex +1 −0
@@ -0,0 +1 @@
1 +% hyperparameters — to be written
added paper/appendices/prompts.tex +1 −0
@@ -0,0 +1 @@
1 +% prompts — to be written
added paper/appendices/pseudocode.tex +1 −0
@@ -0,0 +1 @@
1 +% pseudocode — to be written
added paper/appendices/reproducibility.tex +1 −0
@@ -0,0 +1 @@
1 +% reproducibility — to be written
added paper/main.tex +95 −0
@@ -0,0 +1,95 @@
1 +% ============================================================================
2 +% UQO Working Paper No. 27 — The Invisible Hand of Machines
3 +% ============================================================================
4 +\documentclass[12pt,letterpaper]{article}
5 +\usepackage[utf8]{inputenc}
6 +\usepackage[T1]{fontenc}
7 +\usepackage[english]{babel}
8 +\usepackage[letterpaper,top=1in,bottom=1in,left=1in,right=1in]{geometry}
9 +\usepackage{mathptmx}
10 +\usepackage{microtype}
11 +\usepackage{setspace}
12 +\onehalfspacing
13 +\usepackage{amsmath,amssymb,amsthm}
14 +\usepackage{booktabs,tabularx,multirow,threeparttable,array,longtable}
15 +\usepackage{siunitx}
16 +\sisetup{input-symbols = {()}, table-format = -1.3, parse-numbers = false}
17 +\usepackage{graphicx,subcaption,float,rotating}
18 +\usepackage[dvipsnames]{xcolor}
19 +\usepackage[authoryear,round,semicolon]{natbib}
20 +\bibliographystyle{aer}
21 +\usepackage[font=small,labelfont=bf,labelsep=period,justification=justified,singlelinecheck=false]{caption}
22 +\usepackage{fancyhdr}
23 +\pagestyle{fancy}\fancyhf{}\renewcommand{\headrulewidth}{0pt}\fancyfoot[C]{\thepage}
24 +\usepackage{titlesec}
25 +\titleformat{\section}{\large\bfseries}{\thesection.}{0.5em}{}
26 +\titleformat{\subsection}{\normalsize\bfseries}{\thesubsection.}{0.5em}{}
27 +\titleformat{\subsubsection}{\normalsize\itshape}{\thesubsubsection.}{0.5em}{}
28 +\usepackage[toc,page]{appendix}
29 +\usepackage{enumitem}
30 +\setlist{nosep,leftmargin=*}
31 +\usepackage{listings}
32 +\lstset{basicstyle=\ttfamily\footnotesize,breaklines=true,columns=fullflexible,frame=single,framerule=0.3pt,xleftmargin=0.5em}
33 +\usepackage{algorithm,algpseudocode}
34 +\usepackage{hyperref}
35 +\hypersetup{colorlinks=true,linkcolor=NavyBlue,citecolor=NavyBlue,urlcolor=NavyBlue,breaklinks=true,
36 + pdftitle={The Invisible Hand of Machines: Price Discovery in Markets Populated by LLM Agents},
37 + pdfauthor={Simon-Pierre Boucher}}
38 +
39 +\theoremstyle{plain}
40 +\newtheorem{proposition}{Proposition}
41 +\newtheorem{lemma}{Lemma}
42 +\newtheorem{corollary}{Corollary}
43 +\theoremstyle{definition}
44 +\newtheorem{assumption}{Assumption}
45 +\newtheorem{definition}{Definition}
46 +\theoremstyle{remark}
47 +\newtheorem{remark}{Remark}
48 +\newtheorem{hypothesis}{Hypothesis}
49 +
50 +\newcommand{\E}{\mathbb{E}}
51 +\newcommand{\Var}{\operatorname{Var}}
52 +\newcommand{\Cov}{\operatorname{Cov}}
53 +\newcommand{\Corr}{\operatorname{Corr}}
54 +\newcommand{\code}[1]{\texttt{#1}}
55 +
56 +% ============================================================================
57 +% METADATA
58 +% ============================================================================
59 +\newcommand{\WPnumber}{27}
60 +\newcommand{\WPtitle}{The Invisible Hand of Machines}
61 +\newcommand{\WPsubtitle}{Price Discovery in Markets Populated by LLM Agents}
62 +\newcommand{\WPdate}{October 2026}
63 +\newcommand{\WPversion}{1.0}
64 +\newcommand{\WPabstract}{\input{sections/abstract}}
65 +\newcommand{\WPkeywords}{price discovery, large language models, agent-based markets, limit order book, herding, liquidity spirals, randomized simulation experiments}
66 +\newcommand{\WPjel}{G14, G12, D53, C63, C15, D83}
67 +\newcommand{\WPauthor}{Simon-Pierre Boucher}
68 +\newcommand{\WPaffiliation}{Département des sciences administratives\\Université du Québec en Outaouais}
69 +\newcommand{\WPemail}{simon-pierre.boucher@uqo.ca}
70 +\newcommand{\WPaddress}{Gatineau -- Pavillon Alexandre-Taché\\283, boulevard Alexandre-Taché\\Gatineau, Québec, Canada J9A 1L8}
71 +
72 +\begin{document}
73 +\input{sections/titlepage}
74 +\input{sections/introduction}
75 +\input{sections/literature}
76 +\input{sections/model}
77 +\input{sections/theory}
78 +\input{sections/identification}
79 +\input{sections/implementation}
80 +\input{sections/results}
81 +\input{sections/mechanisms}
82 +\input{sections/robustness}
83 +\input{sections/limitations}
84 +\input{sections/conclusion}
85 +\newpage
86 +\bibliography{references}
87 +\newpage
88 +\begin{appendices}
89 +\input{appendices/proofs}
90 +\input{appendices/prompts}
91 +\input{appendices/pseudocode}
92 +\input{appendices/hyperparameters}
93 +\input{appendices/reproducibility}
94 +\end{appendices}
95 +\end{document}
added paper/sections/abstract.tex +1 −0
@@ -0,0 +1 @@
1 +% abstract — to be written
added paper/sections/conclusion.tex +1 −0
@@ -0,0 +1 @@
1 +% conclusion — to be written
added paper/sections/identification.tex +1 −0
@@ -0,0 +1 @@
1 +% identification — to be written
added paper/sections/implementation.tex +1 −0
@@ -0,0 +1 @@
1 +% implementation — to be written
added paper/sections/introduction.tex +1 −0
@@ -0,0 +1 @@
1 +% introduction — to be written
added paper/sections/limitations.tex +1 −0
@@ -0,0 +1 @@
1 +% limitations — to be written
added paper/sections/literature.tex +298 −0
@@ -0,0 +1,298 @@
1 +% paper/sections/literature.tex — UQO WP 27, "The Invisible Hand of Machines"
2 +% Section: Related literature. Every citation key is in paper/references.bib and every claim is
3 +% backed by the corresponding row of docs/literature_ledger.md.
4 +\section{Related literature}
5 +\label{sec:literature}
6 +
7 +The paper sits at the intersection of six literatures: agent-based and heterogeneous-agent models of
8 +financial markets; the microstructure of double auctions and the measurement of price discovery;
9 +information aggregation with correlated signals, herding and feedback trading; liquidity spirals,
10 +fire sales and the measurement of contagion; algorithmic trading, flash crashes, algorithmic
11 +monoculture and algorithmic collusion; and, closest to our question, the rapidly growing work that
12 +places large language model (LLM) agents in economic experiments and market simulations. We review
13 +each in turn and close with a statement of what the present paper adds and where it overlaps with
14 +existing work.
15 +
16 +\subsection{Agent-based and heterogeneous-agent models of financial markets}
17 +\label{sec:literature:abm}
18 +
19 +Our baseline population of rule-based traders descends from agent-based computational finance, which
20 +showed that interacting heterogeneous rules reproduce the fat tails, volatility clustering and bubbles
21 +of real markets \citep{lebaron2006}. In the Santa Fe artificial stock market the speed of belief
22 +updating governs whether prices track fundamentals or display excess volatility and technical-trading
23 +regimes \citep{lebaron1999}; in adaptive belief systems, discrete-choice switching between predictors
24 +produces increasingly complex price dynamics as the intensity of choice rises \citep{brock1997}, and
25 +the share of trend followers determines whether the fundamental price is stable \citep{brock1998}.
26 +Interacting noise traders who switch between optimistic, pessimistic and fundamentalist states generate
27 +scaling laws and clustered volatility endogenously \citep{lux1999,lux2000}; herd behaviour among
28 +speculators yields bubbles and crashes in a mean-field model of contagious optimism \citep{lux1995}; and
29 +recruitment-type opinion dynamics generate persistent herding states without any informational reason
30 +\citep{kirman1993}. These mechanisms matter for us because they describe what a \emph{classical}
31 +population does on its own, before any LLM is introduced, and because trend following and herding are
32 +precisely the channels through which a correlated LLM order flow can be amplified.
33 +
34 +Closer to our exchange design, \citet{chiarella2002} simulate a double auction populated by
35 +fundamentalist, chartist and noise traders and reproduce order-book regularities, and
36 +\citet{chiarella2009} show that heterogeneous rules in a limit-order book generate fat tails,
37 +volatility clustering and order-flow autocorrelation, with the chartist share driving excess
38 +volatility. Leverage in an agent-based model produces fat tails and clustered volatility through
39 +synchronized margin-driven selling \citep{thurner2012}, which is the closest antecedent of our leverage
40 +treatment. Multi-agent reinforcement-learning markets reproduce the same stylized facts
41 +\citep{lussange2021} and are a precursor of LLM-populated markets. The surveys of \citet{hommes2006}
42 +and \citet{hommes2021} summarize the laboratory and agent-based evidence that expectation heterogeneity
43 +drives aggregate instability; we follow their lead in treating an LLM policy as one more expectation
44 +type. \citet{farmer2009} argue that agent-based models are the appropriate tool for out-of-equilibrium
45 +dynamics and for policy counterfactuals that cannot be solved analytically; \citet{axtell2025}
46 +identify validation, calibration and scale as the open frontiers, which our matched-seed design and
47 +power analysis address directly. For calibration and validation we use the moment set of structural
48 +stochastic volatility models \citep{franke2012} and the catalogue of stylized facts: heavy tails
49 +\citep{mandelbrot1963,cont2001}, conditional heteroskedasticity \citep{engle1982,bollerslev1986}, the
50 +long memory of absolute returns \citep{ding1993}, and the long memory of order-flow signs coexisting
51 +with nearly efficient prices \citep{lillo2004}.
52 +
53 +\subsection{Double auctions, zero intelligence and the measurement of price discovery}
54 +\label{sec:literature:lob}
55 +
56 +The continuous double auction is the institution we study, and its experimental pedigree is long:
57 +\citet{smith1962} showed that double auctions with induced values converge to competitive equilibrium
58 +with few traders, and \citet{smith1988} showed that experimental asset markets with known dividend
59 +streams nevertheless produce bubbles and crashes; our dividend-paying asset and bubble metrics follow
60 +that design. The zero-intelligence tradition established that market structure, not trader
61 +rationality, drives allocative efficiency \citep{gode1993}, a point reviewed by \citet{ladley2012}. A
62 +zero-intelligence model of the continuous double auction predicts spread and price impact from
63 +order-flow rates alone \citep{farmer2005}, and the statistical theory of \citet{smith2003} ties
64 +spread, depth and price diffusion to the same parameters. These results fix the benchmark against
65 +which any effect of ``intelligence'' must be measured: a change in the composition of a population can
66 +move liquidity merely by changing order-flow rates, which is why we report realized order and volume
67 +shares alongside the assigned treatment. On the empirical side we rely on the order-book facts of
68 +\citet{bouchaud2002}, the Markovian book model of \citet{cont2010}, the linear relation between
69 +order-flow imbalance and short-horizon price changes \citep{cont2014}, the survey of
70 +\citet{gould2013}, and the treatment of impact and the slow digestion of order flow in
71 +\citet{bouchaud2018}. Our event-driven exchange, with per-agent latency and a price--time matching
72 +engine, follows the design of ABIDES \citep{byrd2020}, and our realism checklist is that of
73 +\citet{vyetrenko2020}.
74 +
75 +The outcome variables are standard measures of price discovery and market quality. The price-impact
76 +coefficient $\lambda=\Cov(v,Y)/\Var(Y)$ of \citet{kyle1985} and the adverse-selection spread of
77 +\citet{glosten1985} tie liquidity to the information content of order flow. \citet{hasbrouck1991}
78 +measures that content by the permanent price impact in a VAR of quote revisions and trades;
79 +\citet{hasbrouck1993} decomposes the transaction price into an efficient random-walk component and a
80 +pricing error whose standard deviation is a market-quality metric; \citet{hasbrouck1995} attributes
81 +price discovery across venues through information shares, which we adapt to LLM versus rule-based
82 +order flow. Variance ratios reject the random walk under autocorrelation \citep{lo1988}, the effective
83 +spread can be inferred from serial covariance \citep{roll1984}, and illiquidity can be measured as
84 +absolute return per unit of volume \citep{amihud2002}. \citet{bai2016} define informativeness by how
85 +well prices forecast future fundamentals, and \citet{bond2012} argue that informativeness is the
86 +welfare-relevant object because real decisions feed on prices. \citet{hendershott2014} separate
87 +transitory price pressure from permanent information effects, which justifies our separation of the
88 +pricing error from the efficient-price variance. Because the simulator observes the latent value, we
89 +can compute these statistics against the truth rather than against a proxy, which is the main
90 +advantage of a simulated economy for this question \citep{fama1970}.
91 +
92 +\subsection{Information aggregation with correlated signals, herding and feedback}
93 +\label{sec:literature:info}
94 +
95 +The theoretical core of the paper is the aggregation of \emph{correlated} private signals.
96 +\citet{hellwig1980} shows that competitive prices aggregate dispersed private signals imperfectly
97 +because of noise supply, and \citet{grossman1980} that prices cannot be fully informationally
98 +efficient when information is costly. With strategic informed traders, \citet{foster1996} show that
99 +the correlation structure of signals, not only their precision, governs trading intensity and price
100 +informativeness, and \citet{back2000} that more correlated information leads to faster revelation.
101 +\citet{goldstein2015} show that information diversity across traders is complementary, so that a loss
102 +of diversity reduces informativeness about some components of value; \citet{dugast2018} show that
103 +abundant cheap data can lower informativeness by crowding out costly deep information, a close parallel
104 +to shared-model crowding; and \citet{kondor2012} warn that public information can raise disagreement
105 +through higher-order beliefs, so that shared inputs do not trivially homogenize behaviour.
106 +\citet{pasquariello2007} ties information heterogeneity among strategic speculators to contagion and
107 +shows that homogeneity reduces it. Our stylized model (Section~\ref{sec:theory}) borrows the
108 +correlated-error structure of these papers and reinterprets the common component as the signature of a
109 +shared foundation model or prompt family.
110 +
111 +Herding supplies the behavioural counterpart. Sequential decision-makers who follow their predecessors
112 +destroy information aggregation \citep{banerjee1992}, informational cascades become more likely as
113 +signals become more correlated \citep{bikhchandani1992}, reputational concerns make managers mimic one
114 +another \citep{scharfstein1990}, and short-horizon speculators herd on the same information source
115 +even when it is unrelated to fundamentals \citep{froot1992}. The buy-side imbalance statistic of
116 +\citet{lakonishok1992} is the standard empirical measure of institutional herding, and we compute it
117 +for LLM cohorts. Feedback trading closes the loop: the share of trend followers determines the
118 +stability of the fundamental price in heterogeneous-belief models \citep{brock1998}, and
119 +contagious optimism among speculators produces bubbles and crashes \citep{lux1995}. Our feedback
120 +extension (Proposition~\ref{prop:feedback}) is a mechanical version of this amplification.
121 +
122 +\subsection{Liquidity spirals, fire sales, leverage and contagion measurement}
123 +\label{sec:literature:spirals}
124 +
125 +The leverage treatment and the H3 and H6 hypotheses draw on the literature on funding constraints.
126 +\citet{brunnermeier2009} show that market liquidity and funding liquidity reinforce each other through
127 +margins, producing liquidity spirals; our margin-call mechanism follows this logic. Liquidation values
128 +fall when potential buyers are themselves constrained \citep{shleifer1992}, constrained arbitrageurs can
129 +amplify rather than correct mispricing \citep{shleifer1997}, forced sales push prices below
130 +fundamentals and propagate losses \citep{shleifer2011}, and financially constrained arbitrageurs may
131 +under-provide liquidity \citep{gromb2002}. Endogenous margins amplify booms and crashes in the leverage
132 +cycle, with leverage caps as a policy lever \citep{geanakoplos2010}, and procyclical intermediary
133 +leverage amplifies price moves \citep{adrian2010}. In the agent-based setting, \citet{thurner2012}
134 +obtain fat tails and clustered volatility from synchronized margin-driven selling. Across assets,
135 +losses of convergence traders propagate through reduced risk-bearing capacity \citep{kyle2001},
136 +distressed selling induces endogenous correlation \citep{cont2013}, fire-sale spillovers scale with
137 +common exposures and leverage \citep{greenwood2015}, cross-market rebalancing transmits shocks between
138 +assets with unrelated fundamentals \citep{kodres2002}, and dense networks are robust to small shocks
139 +but fragile to large ones \citep{acemoglu2015}. For measurement we use the spillover index of
140 +\citet{diebold2009}, its generalized directional form \citep{diebold2012} and its network
141 +interpretation \citep{diebold2014}, and we heed the warning of \citet{forbes2002} that correlation-based
142 +contagion tests must adjust for heteroskedasticity.
143 +
144 +\subsection{Algorithmic trading, flash crashes, monoculture and algorithmic collusion}
145 +\label{sec:literature:algo}
146 +
147 +The evidence on algorithmic and high-frequency trading is, on average, favourable to liquidity and
148 +price discovery: algorithmic trading improves liquidity \citep{hendershott2011}, high-frequency traders
149 +trade in the direction of permanent price changes and against transitory pricing errors
150 +\citep{brogaard2014}, and algorithmic strategies in foreign exchange improve price efficiency even
151 +though they are more correlated with each other than human trades \citep{chaboud2014}. That last
152 +finding is the one we take most seriously: correlation among algorithms is a documented fact, and its
153 +consequences depend on what the algorithms are correlated \emph{on}. High-frequency market makers
154 +behave as new market makers with tight inventory control \citep{menkveld2013}, a feature we build into
155 +the market-maker policy; \citet{menkveld2016} reviews the speed, adverse-selection and liquidity
156 +consequences, and \citet{foucault2016} show how fast traders reacting to common news signals affect
157 +informativeness and liquidity. The darker evidence concerns stress. During the Flash Crash,
158 +high-frequency traders did not trigger the crash but their synchronized inventory management amplified
159 +it \citep{kirilenko2017}; order-flow toxicity rose before the crash and liquidity provision withdrew
160 +when flow became toxic \citep{easley2011}; the August 2007 quant unwind revealed that common strategies
161 +produce simultaneous deleveraging \citep{khandani2011}; and ultrafast extreme events proliferate in a
162 +machine ecology operating beyond human response time \citep{johnson2013}. \citet{budish2015} show that
163 +continuous-time trading creates a latency arms race with correlated sniping and propose frequent batch
164 +auctions, which motivates our latency-matching treatment and call-auction robustness arm.
165 +
166 +The algorithmic-monoculture literature gives the homogenization mechanism a name. \citet{kleinberg2021}
167 +show that when many decision-makers rely on the same algorithm, outcomes can be worse even if that
168 +algorithm is individually more accurate; \citet{bommasani2021} identify homogenization as a
169 +structural risk of foundation models, and \citet{bommasani2022} document outcome homogenization
170 +across deployers of shared models. On the output side, generative AI raises individual creativity but
171 +reduces collective diversity \citep{doshi2024}, standard LLM outputs show diminished diversity of
172 +thought relative to human samples \citep{park2024brm}, and LLM assistance homogenizes human ideation
173 +\citep{anderson2024}; conversely, ensembles of twelve LLMs match human crowd forecasting accuracy
174 +\citep{schoenegger2024}, which illustrates the diversity benefit our H4 tests in a market. The
175 +algorithmic-collusion literature shows that learning algorithms can coordinate without being told to:
176 +Q-learning pricing algorithms learn tacit collusion \citep{calvano2020,klein2021}, algorithmic pricing
177 +raised margins in German retail gasoline \citep{assad2024}, asymmetric adoption softens competition
178 +\citep{brown2023}, LLM pricing agents reach supracompetitive prices with a sensitivity to prompt
179 +wording \citep{fish2024}, and LLM sellers in continuous double auctions collude more when they can
180 +communicate \citep{agrawal2025}. In securities markets, \citet{colliard2026} show that Q-learning market
181 +makers learn adverse-selection pricing but quote markups that shrink with the number of algorithms,
182 +and \citet{dou2025} show that reinforcement-learning informed speculators in a Kyle-type market sustain
183 +supracompetitive profits through price-trigger strategies or homogenized learning biases, lowering
184 +price informativeness and liquidity. \citet{dou2025} is the nearest theoretical neighbour of our
185 +mechanism; the difference is that their channel is strategic, whereas ours is a shared-error structure
186 +in signals, and that they have no language models.
187 +
188 +The policy literature has already drawn the systemic conclusion. \citet{gensler2020} argue that deep
189 +learning increases uniformity and interconnectedness because models built on the same data generate
190 +correlated predictions; \citet{danielsson2022} show that AI in risk management can create endogenous
191 +systemic risk through common models and procyclical responses; the \citet{fsb2024} warns that common AI
192 +models and data sources could raise correlations in trading, lending and pricing;
193 +\citet{danielsson2025} model AI as amplifying existing vulnerabilities and making crises faster;
194 +\citet{aldasoro2025} list monoculture and correlation among the financial-stability concerns of an
195 +intelligent financial system; and \citet{meng2026} propose a unified model in which the AI adoption
196 +share and signal correlation raise systemic coupling convexly, with 13F evidence of tail-loss
197 +amplification. None of these provides a controlled experiment; the present paper is an attempt to
198 +supply one.
199 +
200 +\subsection{LLM agents in economics and markets}
201 +\label{sec:literature:llm}
202 +
203 +\paragraph{LLMs as simulated subjects.}
204 +\citet{horton2023} proposed using LLMs as simulated economic agents to replicate classic behavioural
205 +experiments at low cost; \citet{aher2023} showed that LLMs can simulate multiple humans and replicate
206 +human-subject studies with fidelity that varies by model and task; and \citet{argyle2023} showed that
207 +conditioning on demographic backstories produces ``silicon samples'' matching sub-population response
208 +distributions. GPT choices in budgetary tasks score higher on rationality than humans and are largely
209 +stable across demographic prompts \citep{chen2023pnas}; chatbot choices in behavioural games fall within
210 +the human distribution and are more cooperative than the median human \citep{mei2024}; in repeated
211 +games LLMs cooperate well but coordinate poorly \citep{akata2025}; and expectations elicited from an
212 +LLM reading newspaper articles track professional forecasters and are extrapolative
213 +\citep{bybee2023}. \citet{manning2024} automate hypothesis generation and testing with LLM subjects, and
214 +\citet{immorlica2024} propose a framework in which generative agents are economic agents with new
215 +primitives such as prompts and context. Generative agents with memory, reflection and planning produce
216 +believable emergent social behaviour \citep{park2023}, social-network simulations reproduce
217 +information propagation \citep{gao2023s3}, and EconAgent produces realistic macroeconomic dynamics
218 +\citep{li2024econagent}. \citet{anthis2025} conclude that LLM social simulations are a promising
219 +method provided that validity concerns---homogeneity, sycophancy, drift---are addressed; homogeneity is
220 +the concern this paper turns into a treatment.
221 +
222 +\paragraph{Single-agent trading and backtests.}
223 +ChatGPT-derived sentiment on headlines predicts next-day returns \citep{lopezlira2023chatgpt}.
224 +FinMem \citep{yu2023finmem}, TradingGPT \citep{li2023tradinggpt} and FinAgent \citep{zhang2024finagent}
225 +evaluate one LLM agent, or a small team with layered memory and distinct characters, by backtesting on
226 +historical prices. In these designs the market does not react to the agent, so nothing can be learned
227 +about equilibrium prices, and \citet{lopezlira2025memorization} show that such backtests are
228 +contaminated by memorization of the historical period. Both points motivate a synthetic economy with
229 +an endogenous price and no history to memorize.
230 +
231 +\paragraph{LLM-populated market simulators.}
232 +A second generation places many LLM agents on a matching engine. ASFM couples LLM traders to a real
233 +order-matching system and finds reactions to rate and inflation shocks consistent with economic priors
234 +\citep{gao2024asfm}; StockAgent adds bulletin-board communication and reports that GPT- and
235 +Gemini-driven agents differ systematically in trading behaviour \citep{zhang2024stockagent};
236 +TwinMarket scales to a social-media-connected population, reproduces bubbles and crashes, and reports
237 +that agents of one model family are more homogeneous \citep{yang2025twinmarket}; FCLAgent combines
238 +LLM-decided direction with rule-based sizing and reproduces path-dependent patterns absent from
239 +conventional agent-based models \citep{hashimoto2025}; StockSim provides an open order-level simulator
240 +with latency, slippage and price--time matching \citep{papadakis2025}; and \citet{li2026switch} find
241 +that LLM agents' trading-style switching in a year-long simulation is only partially consistent with
242 +behavioural-finance theory. \citet{lopezlira2025trade} is the closest in spirit: LLM agents in a
243 +persistent order-book simulation adhere to assigned strategies, generate price discovery and bubbles,
244 +and are analysed with partial-dependence-style perturbations. These papers establish that LLM markets
245 +\emph{can} produce the patterns we study. They are descriptive in the sense that the population
246 +composition is fixed, the information set of LLM agents is not held equal to that of the agents they
247 +replace, and the fundamental value, the efficient price and the transaction price are not separated.
248 +
249 +\paragraph{Experimental-finance replications.}
250 +A third strand replicates laboratory markets with LLM subjects. In Smith--Suchanek--Williams-type
251 +markets, LLM agents price near fundamentals and form only muted bubbles, with lower variance in their
252 +strategy text than humans \citep{henning2025}. In a simulated call auction, LLM agents exhibit
253 +disposition effects and extrapolative beliefs, and prompt interventions causally change bubble size
254 +\citep{ouyang2026}. Across fifteen models, \citet{saxena2026} find behaviour ranging from fundamental
255 +pricing to human-like bubbles, with mixed populations unstable and advanced models adapting to exploit
256 +weaker ones. Replications of \citet{smith1962} find slower or absent convergence with model-family
257 +differences \citep{struski2026}, and the trading institution alone moves the efficiency of identical
258 +LLM agents from 56\,\% to 89\,\% \citep{chupilkin2026}. These studies answer the question of
259 +behavioural fidelity---whether LLMs behave like humans---and their answers conflict. Our results do not
260 +require fidelity: they require only that errors be correlated within a model.
261 +
262 +\paragraph{Correlated behaviour from shared inputs.}
263 +The single paper that measures correlated trading from shared inputs is \citet{song2026}: overlap in
264 +retrieved documents among retrieval-augmented trading agents raises mean pairwise action correlation
265 +from 0.04 to 0.41 and increases position volatility without raising profits. That design is a backtest
266 +without market feedback, so it cannot speak to informativeness or liquidity. \citet{cho2025} document
267 +peer conformity in LLM multi-agent systems, with the confidence gap and format of peer information
268 +controlling its strength. In LLM re-creations of herding experiments, \citet{hansen2025} find that AI
269 +agents rely more on private signals than humans but can be prompted to herd when maximizing profit.
270 +Finally, LLM service behaviour drifts over months \citep{chen2024hdsr}, which is why we cache every
271 +response and replay from a frozen decision library.
272 +
273 +\subsection{What this paper adds}
274 +\label{sec:literature:adds}
275 +
276 +We should be candid about overlap. The hypothesis that shared models correlate trading is not ours: it
277 +is stated by \citet{gensler2020}, the \citet{fsb2024} and \citet{danielsson2025}, modelled as
278 +homogenized learning biases by \citet{dou2025}, and measured in a backtest by \citet{song2026}.
279 +Model-family homogeneity inside LLM markets has been observed by \citet{yang2025twinmarket},
280 +\citet{zhang2024stockagent} and \citet{saxena2026}. LLM-populated order-book simulators exist and are
281 +open source \citep{lopezlira2025trade,papadakis2025,gao2024asfm}. Our simulator is therefore not the
282 +contribution; the design is. First, we treat the LLM penetration share as a randomized treatment
283 +assigned to trader slots by an independent seed stream, so that matched pairs across the share share
284 +every other stream---fundamentals, news, endowments, latencies, policy assignment, activation,
285 +tie-breaks---and differences in outcomes are causal effects on the same market history
286 +(Section~\ref{sec:identification}). Second, we separate three prices: the latent value known to the
287 +simulator only, the public value implied by announced dividends and news, and the transaction price, so
288 +that an information-efficiency loss can be distinguished from transitory pressure
289 +\citep{hasbrouck1993,hendershott2014}. Third, we derive the shared-error mechanism in a Kyle--Hellwig
290 +setting with a model-specific common error and an effective number of models, and then test it by
291 +intervention---prompt diversity at equal share, a two-model mix, inherited information sets, memory,
292 +communication cohorts---so that the effective number of models is manipulated rather than observed.
293 +Fourth, we report the realized dose (the share of orders and volume actually originated by LLM agents)
294 +alongside the assigned share, and we run fairness designs with equal decision opportunities, equal
295 +dollar budgets and matched latency, because naive comparisons confound ``being an LLM'' with being slow
296 +and infrequent. Fifth, the leverage interaction and the safeguard counterfactuals connect the LLM
297 +literature to \citet{brunnermeier2009}, \citet{thurner2012} and \citet{kirilenko2017}, with thresholds,
298 +estimators and seed counts fixed before the first confirmatory call.
added paper/sections/mechanisms.tex +1 −0
@@ -0,0 +1 @@
1 +% mechanisms — to be written
added paper/sections/model.tex +1 −0
@@ -0,0 +1 @@
1 +% model — to be written
added paper/sections/results.tex +1 −0
@@ -0,0 +1 @@
1 +% results — to be written
added paper/sections/robustness.tex +1 −0
@@ -0,0 +1 @@
1 +% robustness — to be written
modified results/figures/fig_baseline_paths.pdf +0 −0

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

added results/tables/tab_classical_cells.tex +22 −0
@@ -0,0 +1,22 @@
1 +\begin{tabular}{lrrrrrrrr}
2 +\toprule
3 +Cell & Mean $|P/V-1|$ (\%) & Time to absorb (ticks) & Quoted spread (bp) & Price impact (bp/100 lots) & Bubble episodes & Max drawdown & Crashes & Vol. clustering $\sum_{1}^{10}\mathrm{ACF}|r|$ \\
4 +\midrule
5 +Control & 0.63 & 25.27 & 20.69 & 10.76 & 0.00 & 0.03 & 0.00 & 2.02 \\
6 +Placebo shock & 0.52$^{***}$ & -- & 19.03$^{*}$ & 9.35$^{*}$ & 0.00 & 0.03 & 0.00 & 1.73$^{*}$ \\
7 +Trend followers 16\% & 1.49$^{***}$ & 34.47 & 34.63$^{***}$ & 14.04$^{**}$ & 0.13$^{**}$ & 0.06$^{***}$ & 0.00 & 2.27 \\
8 +Leveraged 19\% & 2.74$^{***}$ & 52.80$^{***}$ & 36.26$^{***}$ & 15.13$^{***}$ & 0.90$^{***}$ & 0.08$^{***}$ & 0.13$^{**}$ & 2.42$^{*}$ \\
9 +Leveraged 19\% + funding shock & 2.96$^{***}$ & 60.43$^{***}$ & 38.00$^{***}$ & 16.49$^{***}$ & 1.37$^{***}$ & 0.09$^{***}$ & 0.30$^{***}$ & 2.39$^{*}$ \\
10 +Market makers withdraw & 0.64 & 33.17$^{**}$ & 19.38 & 8.72$^{***}$ & 0.00 & 0.03 & 0.00 & 1.63$^{***}$ \\
11 +Signal precision 0.5 & 0.60 & 24.97 & 20.27 & 9.52 & 0.00 & 0.03$^{*}$ & 0.00 & 2.03 \\
12 +Signal precision 8 & 0.58 & 26.20 & 17.67$^{***}$ & 8.58$^{**}$ & 0.00 & 0.03$^{**}$ & 0.00 & 1.83 \\
13 +Misleading news 50\% & 0.71$^{***}$ & 23.17 & 23.52$^{**}$ & 12.00 & 0.00 & 0.04$^{***}$ & 0.00 & 2.04 \\
14 +Circuit breaker 5\% & 0.64$^{*}$ & 25.13 & 20.60 & 10.56 & 0.00 & 0.03 & 0.00 & 1.96 \\
15 +Position limit 300 & 1.89$^{***}$ & 53.30$^{***}$ & 38.48$^{***}$ & 12.30 & 0.63$^{***}$ & 0.03 & 0.00 & 0.77$^{***}$ \\
16 +Call auction (5 ticks) & 1.36$^{***}$ & 25.10 & -- & -2.83$^{***}$ & 0.13 & 0.06$^{***}$ & 0.00 & 0.24$^{***}$ \\
17 +Mock LLM 25\% & 0.66 & 28.23 & 16.26$^{***}$ & 11.04 & 0.00 & 0.03 & 0.00 & 1.97 \\
18 +Mock LLM 50\% & 0.68 & 28.30$^{*}$ & 13.57$^{***}$ & 12.36$^{*}$ & 0.00 & 0.03 & 0.00 & 2.40$^{**}$ \\
19 +\midrule
20 +Seeds per cell & 30 & & & & & & & \\
21 +\bottomrule
22 +\end{tabular}
\ No newline at end of file
added results/tables/tab_classical_effects.csv +66 −0
@@ -0,0 +1,66 @@
1 +outcome,level,n,control_mean,treat_mean,diff,se,ci_lo,ci_hi,t,p,p_wilcoxon,cohen_d,pct_change,cell,p_holm
2 +mad_pct,placebo_shock,30,0.6282540919469869,0.5228496884134598,-0.105404403533527,0.0260831529140309,-0.158750441033583,-0.052058366033470985,-4.041091346622702,0.0003577844519032219,0.00012333691120147705,-0.7377989624947274,-16.777352489161533,placebo_shock,0.0010733533557096657
3 +time_to_absorb,placebo_shock,0,,,,,,,,,,,,placebo_shock,
4 +spread_bp,placebo_shock,30,20.68987407852468,19.02562407892965,-1.664249999595028,0.9104903111467902,-3.526411772827072,0.19791177363701595,-1.8278612954143953,0.07787609209897943,0.09194962680339813,-0.3337202878296929,-8.043789891029146,placebo_shock,0.15575218419795886
5 +n_bubbles,placebo_shock,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,placebo_shock,
6 +max_dd,placebo_shock,30,0.03313559734901605,0.03124532261713216,-0.0018902747318838898,0.0019984533683765375,-0.005977570799307531,0.002197021335539752,-0.9458688212572467,0.35203053516393307,0.5676916025573617,-0.17269122994780536,-5.704664720462692,placebo_shock,0.35203053516393307
7 +mad_pct,trend_heavy,30,0.6282540919469868,1.4894389768807208,0.8611848849337337,0.1246024914283476,0.606344175980891,1.1160255938865764,6.911457989818415,1.3536543920906025e-07,5.587935447692871e-09,1.2618538154242858,137.07588951229656,trend_heavy,5.41461756836241e-07
8 +time_to_absorb,trend_heavy,30,25.266666666666666,34.46666666666667,9.2,5.806140229775379,-2.6748901043157947,21.07489010431579,1.584529418152878,0.12391908710163213,0.5270892568655381,0.28929416845095574,36.41160949868073,trend_heavy,0.12391908710163213
9 +spread_bp,trend_heavy,30,20.68987407852468,34.62717383838306,13.937299759858377,2.3683605689552474,9.09345852097283,18.781140998743922,5.884787959464519,2.185900359452944e-06,6.917864084243774e-06,1.0744103705111714,67.36290277534737,trend_heavy,6.557701078358832e-06
10 +n_bubbles,trend_heavy,30,0.0,0.13333333333333333,0.13333333333333333,0.06312427686319992,0.004229691154525234,0.2624369755121414,2.112235418114766,0.04339741781077554,0.045500263896358396,0.38563966175427117,,trend_heavy,0.08679483562155108
11 +max_dd,trend_heavy,30,0.03313559734901605,0.06073696070483838,0.027601363355822337,0.0035535803541489716,0.02033347547981643,0.03486925123182825,7.767198319744326,1.4490308139866929e-08,6.910413503646851e-07,1.4180899094467303,83.29822174351703,trend_heavy,7.245154069933464e-08
12 +mad_pct,leverage_heavy,30,0.6282540919469867,2.7377706861587074,2.109516594211721,0.33054271789106565,1.4334808295898054,2.7855523588336366,6.381978727805274,5.61666122443336e-07,3.725290298461914e-09,1.1651845702456904,335.77442968564475,leverage_heavy,2.246664489773344e-06
13 +time_to_absorb,leverage_heavy,30,25.266666666666666,52.8,27.533333333333335,7.952550857058357,11.268540589909744,43.79812607675693,3.4622014782710733,0.001683414812682758,0.006827030024128609,0.6321086160922663,108.97097625329816,leverage_heavy,0.001683414812682758
14 +spread_bp,leverage_heavy,30,20.68987407852468,36.25765496390989,15.567780885385222,3.372307612659998,8.67063739358322,22.464924377187224,4.616358492013639,7.358646567477612e-05,0.00013739429414272308,0.842827893202134,75.24347816859843,leverage_heavy,0.00022075939702432835
15 +n_bubbles,leverage_heavy,30,0.0,0.9,0.9,0.22154110176243813,0.4468975717247238,1.3531024282752764,4.062451585011451,0.00033757404082763944,0.0004730724812796508,0.741698790627796,,leverage_heavy,0.0006751480816552789
16 +max_dd,leverage_heavy,30,0.03313559734901605,0.07811242732953337,0.04497682998051735,0.005317411213479523,0.0341015029473002,0.0558521570137345,8.458407329209757,2.5464721711326925e-09,2.60770320892334e-08,1.5442868315917366,135.73568481889137,leverage_heavy,1.2732360855663462e-08
17 +mad_pct,leverage_heavy_funding_shock,30,0.6282540919469867,2.958604840512614,2.3303507485656274,0.3309132677965215,1.6535571242931841,3.007144372838071,7.042179856017618,9.569332641420283e-08,1.862645149230957e-09,1.285720253716444,370.9248818967131,leverage_heavy_funding_shock,3.827733056568113e-07
18 +time_to_absorb,leverage_heavy_funding_shock,30,25.266666666666666,60.43333333333333,35.166666666666664,7.943924640712425,18.91951651661322,51.41381681672011,4.426863075517904,0.00012425575522840936,0.000614000783560083,0.8082309218159505,139.1820580474934,leverage_heavy_funding_shock,0.00012425575522840936
19 +spread_bp,leverage_heavy_funding_shock,30,20.68987407852468,38.00473078793235,17.31485670940766,3.345013937297895,10.47353505149898,24.156178367316343,5.176318255760278,1.553831088819794e-05,7.910653948783875e-05,0.9450620911685667,83.68758864211667,leverage_heavy_funding_shock,3.107662177639588e-05
20 +n_bubbles,leverage_heavy_funding_shock,30,0.0,1.3666666666666667,1.3666666666666667,0.24203796288790566,0.8716434504469067,1.8616898828864268,5.6464971459853475,4.2177639491799116e-06,4.338803172973628e-05,1.0309046192482385,,leverage_heavy_funding_shock,1.2653291847539736e-05
21 +max_dd,leverage_heavy_funding_shock,30,0.03313559734901605,0.094022027434633,0.06088643008561697,0.006712607068457487,0.047157607133218205,0.07461525303801574,9.070459430244629,5.752487239564372e-10,9.313225746154785e-09,1.6560317456268137,183.749305752066,leverage_heavy_funding_shock,2.876243619782186e-09
22 +mad_pct,liquidity_shock,30,0.6282540919469867,0.6375685616065419,0.009314469659554982,0.027251007041271744,-0.04642009771922102,0.06504903703833098,0.3418027688095411,0.7349639130942708,0.8871948085725307,0.06240436223156962,1.4825959399148578,liquidity_shock,0.7349639130942708
23 +time_to_absorb,liquidity_shock,30,25.266666666666666,33.166666666666664,7.9,3.8561340893364338,0.013320256450725765,15.786679743549275,2.0486839453654575,0.04963907844851497,0.015751121568152216,0.3740368033584474,31.266490765171504,liquidity_shock,0.19855631379405989
24 +spread_bp,liquidity_shock,30,20.68987407852468,19.38476399998455,-1.3051100785401253,0.9903887839086477,-3.3306825766258523,0.720462419545602,-1.3177755036657475,0.19789462166450567,0.23665234446525574,-0.24059178969515385,-6.3079653050898985,liquidity_shock,0.39578924332901133
25 +n_bubbles,liquidity_shock,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,liquidity_shock,
26 +max_dd,liquidity_shock,30,0.03313559734901605,0.03023922492546186,-0.0028963724235541942,0.0018099280248392202,-0.006598090870082065,0.0008053460229736757,-1.6002693940337684,0.12037802875949395,0.09749059620220792,-0.29216788173247266,-8.740969396286442,liquidity_shock,0.36113408627848187
27 +mad_pct,info_low,30,0.6282540919469867,0.6026463991451105,-0.025607692801876355,0.02365127473041428,-0.07397998095474381,0.022764595350991106,-1.0827193499615573,0.28785378862941297,0.370740607380867,-0.1976766038070917,-4.076008915838018,info_low,0.8635613658882388
28 +time_to_absorb,info_low,30,25.266666666666666,24.966666666666665,-0.3,2.7780543923574554,-5.981759190706424,5.381759190706425,-0.1079892462960094,0.914747917936226,0.34541581215055495,-0.019716048721435186,-1.187335092348285,info_low,1.0
29 +spread_bp,info_low,30,20.68987407852468,20.27325361817352,-0.4166204603511574,0.9304469506093098,-2.3195981441693014,1.4863572234669868,-0.4477637979019981,0.6576507775114152,0.761065473780036,-0.08175011084836957,-2.0136442530773735,info_low,1.0
30 +n_bubbles,info_low,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,info_low,
31 +max_dd,info_low,30,0.03313559734901605,0.030426155138508,-0.0027094422105080505,0.0015618758372030646,-0.005903836970086592,0.00048495254907049033,-1.7347359796281854,0.09340609319392706,0.19807579927146435,-0.3167180091193932,-8.176832250735044,info_low,0.37362437277570826
32 +mad_pct,info_high,30,0.6282540919469867,0.583635110753795,-0.04461898119319179,0.030384585406036172,-0.10676243592952972,0.017524473543146145,-1.4684742476139836,0.1527397481733936,0.06056523136794567,-0.2681054901778685,-7.102059782040676,info_high,0.3054794963467872
33 +time_to_absorb,info_high,30,25.266666666666666,26.2,0.9333333333333333,3.646737900920172,-6.525083118717398,8.391749785384064,0.25593649960361226,0.7998066240890291,0.8192500254019224,0.046727398040603475,3.6939313984168867,info_high,0.7998066240890291
34 +spread_bp,info_high,30,20.68987407852468,17.674358574644632,-3.01551550388005,0.8436325288226298,-4.740937758895465,-1.2900932488646346,-3.574441952930017,0.0012527919846749588,0.0008718203753232956,-0.6526008293708632,-14.574837393573327,info_high,0.005011167938699835
35 +n_bubbles,info_high,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,info_high,
36 +max_dd,info_high,30,0.03313559734901605,0.02785980850434493,-0.005275788844671122,0.002186873838565948,-0.009748448042910727,-0.0008031296464315165,-2.412479746948157,0.02239567174887383,0.005382779985666275,-0.44045652564262017,-15.92181601285599,info_high,0.06718701524662149
37 +mad_pct,misleading_news,30,0.6282540919469868,0.707292854995019,0.07903876304803209,0.01962027022094286,0.038910804805506176,0.119166721290558,4.028423775920547,0.0003703271034647764,0.0009753641365557986,0.7354861910872733,12.5807000799768,misleading_news,0.0014813084138591056
38 +time_to_absorb,misleading_news,30,25.266666666666666,23.166666666666668,-2.1,1.8403835182518,-5.864006924421055,1.6640069244210554,-1.1410665109600702,0.263177805181749,0.281084103394311,-0.2083292892221821,-8.311345646437996,misleading_news,0.263177805181749
39 +spread_bp,misleading_news,30,20.68987407852468,23.51591601826055,2.8260419397358745,1.0597430147248355,0.6586241129775665,4.993459766494182,2.6667238193305405,0.012395591106970309,0.03692078702122783,0.48687493016122274,13.659058189576903,misleading_news,0.024791182213940617
40 +n_bubbles,misleading_news,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,misleading_news,
41 +max_dd,misleading_news,30,0.03313559734901605,0.038069095171641455,0.004933497822625399,0.0016643866992440016,0.001529444809360157,0.00833755083589064,2.964153597758438,0.006012508226009909,0.014990431977029232,0.541177929800797,14.888815103168488,misleading_news,0.01803752467802973
42 +mad_pct,breaker_5,30,0.6282540919469869,0.6436703744684232,0.015416282521436609,0.008871426884037416,-0.0027278227098096845,0.0335603877526829,1.7377455422842427,0.09286600685468777,0.10880943004054569,0.31726747757104234,2.453829225952333,breaker_5,0.37146402741875106
43 +time_to_absorb,breaker_5,30,25.266666666666666,25.133333333333333,-0.13333333333333333,0.1333333333333333,-0.4060306189510271,0.13936395228436047,-1.0000000000000002,0.3255819880161932,0.31731050786291415,-0.1825741858350554,-0.5277044854881267,breaker_5,0.6511639760323864
44 +spread_bp,breaker_5,30,20.68987407852468,20.599037031113088,-0.09083704741159479,0.059877925033521344,-0.2133011545995525,0.03162705977636293,-1.5170373282097143,0.14008374994513234,0.10880943004054569,-0.27697185507927624,-0.43904108389852536,breaker_5,0.420251249835397
45 +n_bubbles,breaker_5,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,breaker_5,
46 +max_dd,breaker_5,30,0.03313559734901605,0.0331720767406367,3.64793916206511e-05,0.0003926976674050563,-0.0007666775181525398,0.000839636301393842,0.09289434251470523,0.9266262966626592,1.0,0.01696010895330508,0.1100912448820976,breaker_5,0.9266262966626592
47 +mad_pct,poslimit_300,30,0.6282540919469869,1.8911586792602286,1.2629045873132414,0.19593886537029576,0.8621646118120634,1.6636445628144194,6.445401145538619,4.729705740517956e-07,9.313225746154785e-09,1.1767638665270463,201.01812363839045,poslimit_300,1.8918822962071823e-06
48 +time_to_absorb,poslimit_300,30,25.266666666666666,53.3,28.033333333333335,8.112780230299235,11.440834726217158,44.625831940449515,3.455453314097644,0.0017134343335242206,0.00545559119110836,0.630876575512421,110.94986807387863,poslimit_300,0.005140303000572662
49 +spread_bp,poslimit_300,30,20.68987407852468,38.48234651034019,17.792472431815515,1.9105986967985755,13.884859342902955,21.700085520728077,9.312511550242768,3.2378780191024443e-10,4.6566128730773926e-08,1.7002242143651225,85.99604020927048,poslimit_300,1.6189390095512222e-09
50 +n_bubbles,poslimit_300,30,0.0,0.6333333333333333,0.6333333333333333,0.1946605258045745,0.23520785580467946,1.031458810861987,3.2535272917589646,0.0028932275163866,0.004508698364904228,0.5940100963850257,,poslimit_300,0.0057864550327732
51 +max_dd,poslimit_300,30,0.03313559734901605,0.034456638636437525,0.0013210412874214686,0.002740865520307808,-0.004284658119811537,0.006926740694654474,0.4819796074026687,0.6334381365601258,0.4771064817905426,0.08799703441064186,3.9867737210438325,poslimit_300,0.6334381365601258
52 +mad_pct,auction_5,30,0.6282540919469867,1.35564882733449,0.7273947353875033,0.11832214381516283,0.4853987795360435,0.9693906912389632,6.147579074664201,1.0633232074358769e-06,1.862645149230957e-09,1.1223892444134396,115.78034185710999,auction_5,3.1899696223076306e-06
53 +time_to_absorb,auction_5,30,25.266666666666666,25.1,-0.16666666666666666,3.980724630312361,-8.308162677749255,7.974829344415922,-0.04186842400439756,0.9668905278378153,0.2664233269499078,-0.007644093424799773,-0.6596306068601583,auction_5,0.9668905278378153
54 +spread_bp,auction_5,0,,,,,,,,,,,,auction_5,
55 +n_bubbles,auction_5,30,0.0,0.13333333333333333,0.13333333333333333,0.07926868804398468,-0.028789337147194394,0.29545600381386106,1.6820428926406503,0.10329970911247394,0.10247043485974941,0.3070976116635082,,auction_5,0.20659941822494787
56 +max_dd,auction_5,30,0.03313559734901605,0.05628606196832761,0.02315046461931156,0.0032313309119088966,0.016541650854735784,0.029759278383887335,7.164374448309136,6.931526079709137e-08,5.587935447692871e-09,1.3080298319175145,69.86584359855824,auction_5,2.7726104318836547e-07
57 +mad_pct,mock_llm_25_indep,30,0.6282540919469867,0.6573609826050393,0.02910689065805242,0.04227381377767932,-0.05735276636605522,0.11556654768216007,0.6885324047441619,0.4965892162378058,0.5978077705949545,0.12570824321721819,4.632980673130024,mock_llm_25_indep,0.9931784324756116
58 +time_to_absorb,mock_llm_25_indep,30,25.266666666666666,28.233333333333334,2.966666666666667,2.9774954117853922,-3.1229952088309387,9.056328542164273,0.9963631362534218,0.3273152497245478,0.8483154780154493,0.1819101883975308,11.741424802110819,mock_llm_25_indep,0.9819457491736434
59 +spread_bp,mock_llm_25_indep,30,20.68987407852468,16.25631641329572,-4.43355766522896,0.9814521456395995,-6.440852685825813,-2.426262644632108,-4.5173447171381635,9.678202704795945e-05,0.00013739429414272308,-0.8247505338677887,-21.428635323744324,mock_llm_25_indep,0.0003871281081918378
60 +n_bubbles,mock_llm_25_indep,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,mock_llm_25_indep,
61 +max_dd,mock_llm_25_indep,30,0.03313559734901605,0.032746308923070254,-0.0003892884259457959,0.0021208214839804843,-0.0047268553906545515,0.00394827853876296,-0.18355548964694385,0.8556395780450193,0.7000329215079546,-0.03351249407784571,-1.174834489462903,mock_llm_25_indep,0.9931784324756116
62 +mad_pct,mock_llm_50_indep,30,0.6282540919469867,0.6798607327887491,0.05160664084176236,0.031913313378619,-0.01366341365885941,0.11687669534238414,1.6170881484320372,0.11668682433457427,0.06989291124045849,0.29523855212349637,8.214294423746791,mock_llm_50_indep,0.28389459081403096
63 +time_to_absorb,mock_llm_50_indep,30,25.266666666666666,28.3,3.033333333333333,1.7554403667530416,-0.5569453397462927,6.623612006412959,1.7279614795140847,0.09463153027134365,0.11816765662651728,0.3154811602766217,12.00527704485488,mock_llm_50_indep,0.28389459081403096
64 +spread_bp,mock_llm_50_indep,30,20.68987407852468,13.5671243158387,-7.1227497626859755,0.8152976245444828,-8.790220631564733,-5.455278893807219,-8.736379879268686,1.2878226187043162e-09,1.862645149230957e-09,-1.5950374436032397,-34.42625960724973,mock_llm_50_indep,5.151290474817265e-09
65 +n_bubbles,mock_llm_50_indep,30,0.0,0.0,0.0,0.0,0.0,0.0,,,1.0,,,mock_llm_50_indep,
66 +max_dd,mock_llm_50_indep,30,0.03313559734901605,0.03175647106215273,-0.0013791262868633192,0.002565621448445398,-0.00662641132371529,0.003868158749988652,-0.5375408315591457,0.5949953367044932,1.0,-0.09814107967500967,-4.162068582428232,mock_llm_50_indep,0.5949953367044932
added results/tables/tab_classical_effects.tex +84 −0
@@ -0,0 +1,84 @@
1 +\begin{tabular}{llrrrrr}
2 +\toprule
3 +Cell & Outcome & Control & Effect & 95\% CI & $d$ & $p$ (Holm) \\
4 +\midrule
5 +Placebo shock & Mean $|P/V-1|$ (\%) & 0.63 & -0.11$^{***}$ & [-0.16, -0.05] & -0.74 & 0.001 \\
6 + & Time to absorb (ticks) & -- & -- & [--, --] & -- & -- \\
7 + & Quoted spread (bp) & 20.69 & -1.66 & [-3.53, 0.20] & -0.33 & 0.156 \\
8 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
9 + & Max drawdown & 0.03 & -0.00 & [-0.01, 0.00] & -0.17 & 0.352 \\
10 +\addlinespace
11 +Trend followers 16\% & Mean $|P/V-1|$ (\%) & 0.63 & 0.86$^{***}$ & [0.61, 1.12] & 1.26 & 0.000 \\
12 + & Time to absorb (ticks) & 25.27 & 9.20 & [-2.67, 21.07] & 0.29 & 0.124 \\
13 + & Quoted spread (bp) & 20.69 & 13.94$^{***}$ & [9.09, 18.78] & 1.07 & 0.000 \\
14 + & Bubble episodes & 0.00 & 0.13$^{*}$ & [0.00, 0.26] & 0.39 & 0.087 \\
15 + & Max drawdown & 0.03 & 0.03$^{***}$ & [0.02, 0.03] & 1.42 & 0.000 \\
16 +\addlinespace
17 +Leveraged 19\% & Mean $|P/V-1|$ (\%) & 0.63 & 2.11$^{***}$ & [1.43, 2.79] & 1.17 & 0.000 \\
18 + & Time to absorb (ticks) & 25.27 & 27.53$^{***}$ & [11.27, 43.80] & 0.63 & 0.002 \\
19 + & Quoted spread (bp) & 20.69 & 15.57$^{***}$ & [8.67, 22.46] & 0.84 & 0.000 \\
20 + & Bubble episodes & 0.00 & 0.90$^{***}$ & [0.45, 1.35] & 0.74 & 0.001 \\
21 + & Max drawdown & 0.03 & 0.04$^{***}$ & [0.03, 0.06] & 1.54 & 0.000 \\
22 +\addlinespace
23 +Leveraged 19\% + funding shock & Mean $|P/V-1|$ (\%) & 0.63 & 2.33$^{***}$ & [1.65, 3.01] & 1.29 & 0.000 \\
24 + & Time to absorb (ticks) & 25.27 & 35.17$^{***}$ & [18.92, 51.41] & 0.81 & 0.000 \\
25 + & Quoted spread (bp) & 20.69 & 17.31$^{***}$ & [10.47, 24.16] & 0.95 & 0.000 \\
26 + & Bubble episodes & 0.00 & 1.37$^{***}$ & [0.87, 1.86] & 1.03 & 0.000 \\
27 + & Max drawdown & 0.03 & 0.06$^{***}$ & [0.05, 0.07] & 1.66 & 0.000 \\
28 +\addlinespace
29 +Market makers withdraw & Mean $|P/V-1|$ (\%) & 0.63 & 0.01 & [-0.05, 0.07] & 0.06 & 0.735 \\
30 + & Time to absorb (ticks) & 25.27 & 7.90 & [0.01, 15.79] & 0.37 & 0.199 \\
31 + & Quoted spread (bp) & 20.69 & -1.31 & [-3.33, 0.72] & -0.24 & 0.396 \\
32 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
33 + & Max drawdown & 0.03 & -0.00 & [-0.01, 0.00] & -0.29 & 0.361 \\
34 +\addlinespace
35 +Signal precision 0.5 & Mean $|P/V-1|$ (\%) & 0.63 & -0.03 & [-0.07, 0.02] & -0.20 & 0.864 \\
36 + & Time to absorb (ticks) & 25.27 & -0.30 & [-5.98, 5.38] & -0.02 & 1.000 \\
37 + & Quoted spread (bp) & 20.69 & -0.42 & [-2.32, 1.49] & -0.08 & 1.000 \\
38 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
39 + & Max drawdown & 0.03 & -0.00 & [-0.01, 0.00] & -0.32 & 0.374 \\
40 +\addlinespace
41 +Signal precision 8 & Mean $|P/V-1|$ (\%) & 0.63 & -0.04 & [-0.11, 0.02] & -0.27 & 0.305 \\
42 + & Time to absorb (ticks) & 25.27 & 0.93 & [-6.53, 8.39] & 0.05 & 0.800 \\
43 + & Quoted spread (bp) & 20.69 & -3.02$^{***}$ & [-4.74, -1.29] & -0.65 & 0.005 \\
44 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
45 + & Max drawdown & 0.03 & -0.01$^{*}$ & [-0.01, -0.00] & -0.44 & 0.067 \\
46 +\addlinespace
47 +Misleading news 50\% & Mean $|P/V-1|$ (\%) & 0.63 & 0.08$^{***}$ & [0.04, 0.12] & 0.74 & 0.001 \\
48 + & Time to absorb (ticks) & 25.27 & -2.10 & [-5.86, 1.66] & -0.21 & 0.263 \\
49 + & Quoted spread (bp) & 20.69 & 2.83$^{**}$ & [0.66, 4.99] & 0.49 & 0.025 \\
50 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
51 + & Max drawdown & 0.03 & 0.00$^{**}$ & [0.00, 0.01] & 0.54 & 0.018 \\
52 +\addlinespace
53 +Circuit breaker 5\% & Mean $|P/V-1|$ (\%) & 0.63 & 0.02 & [-0.00, 0.03] & 0.32 & 0.371 \\
54 + & Time to absorb (ticks) & 25.27 & -0.13 & [-0.41, 0.14] & -0.18 & 0.651 \\
55 + & Quoted spread (bp) & 20.69 & -0.09 & [-0.21, 0.03] & -0.28 & 0.420 \\
56 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
57 + & Max drawdown & 0.03 & 0.00 & [-0.00, 0.00] & 0.02 & 0.927 \\
58 +\addlinespace
59 +Position limit 300 & Mean $|P/V-1|$ (\%) & 0.63 & 1.26$^{***}$ & [0.86, 1.66] & 1.18 & 0.000 \\
60 + & Time to absorb (ticks) & 25.27 & 28.03$^{***}$ & [11.44, 44.63] & 0.63 & 0.005 \\
61 + & Quoted spread (bp) & 20.69 & 17.79$^{***}$ & [13.88, 21.70] & 1.70 & 0.000 \\
62 + & Bubble episodes & 0.00 & 0.63$^{***}$ & [0.24, 1.03] & 0.59 & 0.006 \\
63 + & Max drawdown & 0.03 & 0.00 & [-0.00, 0.01] & 0.09 & 0.633 \\
64 +\addlinespace
65 +Call auction (5 ticks) & Mean $|P/V-1|$ (\%) & 0.63 & 0.73$^{***}$ & [0.49, 0.97] & 1.12 & 0.000 \\
66 + & Time to absorb (ticks) & 25.27 & -0.17 & [-8.31, 7.97] & -0.01 & 0.967 \\
67 + & Quoted spread (bp) & -- & -- & [--, --] & -- & -- \\
68 + & Bubble episodes & 0.00 & 0.13 & [-0.03, 0.30] & 0.31 & 0.207 \\
69 + & Max drawdown & 0.03 & 0.02$^{***}$ & [0.02, 0.03] & 1.31 & 0.000 \\
70 +\addlinespace
71 +Mock LLM 25\% & Mean $|P/V-1|$ (\%) & 0.63 & 0.03 & [-0.06, 0.12] & 0.13 & 0.993 \\
72 + & Time to absorb (ticks) & 25.27 & 2.97 & [-3.12, 9.06] & 0.18 & 0.982 \\
73 + & Quoted spread (bp) & 20.69 & -4.43$^{***}$ & [-6.44, -2.43] & -0.82 & 0.000 \\
74 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
75 + & Max drawdown & 0.03 & -0.00 & [-0.00, 0.00] & -0.03 & 0.993 \\
76 +\addlinespace
77 +Mock LLM 50\% & Mean $|P/V-1|$ (\%) & 0.63 & 0.05 & [-0.01, 0.12] & 0.30 & 0.284 \\
78 + & Time to absorb (ticks) & 25.27 & 3.03 & [-0.56, 6.62] & 0.32 & 0.284 \\
79 + & Quoted spread (bp) & 20.69 & -7.12$^{***}$ & [-8.79, -5.46] & -1.60 & 0.000 \\
80 + & Bubble episodes & 0.00 & 0.00 & [0.00, 0.00] & -- & -- \\
81 + & Max drawdown & 0.03 & -0.00 & [-0.01, 0.00] & -0.10 & 0.595 \\
82 +\addlinespace
83 +\bottomrule
84 +\end{tabular}
\ No newline at end of file
added results/tables/tab_contagion.tex +10 −0
@@ -0,0 +1,10 @@
1 +\begin{tabular}{lrrrrrr}
2 +\toprule
3 +Cell & Return correlation & Fundamental correlation & Excess comovement & DY spillover (\%) & Mean $|P/V-1|$ (\%) & Max drawdown \\
4 +\midrule
5 +Two assets & -0.01 & 0.38 & -0.39 & 1.21 & 0.76 & 0.04 \\
6 +Two assets + leveraged 19\% + funding shock & 0.02$^{*}$ & 0.34 & -0.32 & 1.25 & 11.82$^{***}$ & 0.12$^{***}$ \\
7 +\midrule
8 +Seeds per cell & 30 & & & & & \\
9 +\bottomrule
10 +\end{tabular}
\ No newline at end of file
added results/tables/tab_scale.tex +9 −0
@@ -0,0 +1,9 @@
1 +\begin{tabular}{rrrrrrrr}
2 +\toprule
3 +Traders & Seeds & Wall-clock (s) & Orders & Trades & Mean $|P/V-1|$ (\%) & ACF$_1$ & Spread (bp) \\
4 +\midrule
5 +100 & 3 & 0.6 & 13,689 & 10,521 & 0.82 & 0.11 & 25.5 \\
6 +1,000 & 3 & 2.7 & 14,939 & 11,840 & 0.99 & 0.15 & 14.2 \\
7 +10,000 & 1 & 23.7 & 15,378 & 11,885 & 1.23 & 0.10 & 10.9 \\
8 +\bottomrule
9 +\end{tabular}
\ No newline at end of file
added results/tables/tab_stylized_facts.tex +22 −0
@@ -0,0 +1,22 @@
1 +\begin{tabular}{lrrrr}
2 +\toprule
3 +Statistic & Mean & SD & Min & Max \\
4 +\midrule
5 +ACF$_1$ of returns & -0.007 & 0.146 & -0.292 & 0.312 \\
6 +Variance ratio (5) & 1.18 & 0.29 & 0.69 & 1.79 \\
7 +Excess kurtosis & 20.4 & 15.3 & 1.8 & 66.0 \\
8 +Vol. clustering $\sum_{1}^{10}\mathrm{ACF}|r|$ & 2.02 & 0.59 & 0.68 & 3.71 \\
9 +Tick volatility (bp) & 17.0 & 7.7 & 6.0 & 38.6 \\
10 +Quoted spread (bp) & 20.7 & 5.0 & 13.0 & 38.6 \\
11 +Effective spread (bp) & 30.4 & 10.3 & 17.4 & 69.2 \\
12 +Depth, 5 levels (lots) & 139 & 5 & 133 & 150 \\
13 +Price impact (bp/100 lots) & 10.8 & 3.9 & 5.4 & 22.3 \\
14 +Mean $|P/V-1|$ (\%) & 0.63 & 0.15 & 0.41 & 0.98 \\
15 +Bubble episodes & 0.00 & 0.00 & 0.00 & 0.00 \\
16 +Max drawdown & 0.033 & 0.012 & 0.010 & 0.060 \\
17 +MM P\&L (\%) & 4.9 & 1.2 & 1.9 & 7.1 \\
18 +Wealth Gini (final) & 0.285 & 0.023 & 0.243 & 0.338 \\
19 +\midrule
20 +Runs (seeds) & 30 & & & \\
21 +\bottomrule
22 +\end{tabular}
\ No newline at end of file
added results/tables/tab_threshold_sensitivity.tex +14 −0
@@ -0,0 +1,14 @@
1 +\begin{tabular}{lllrrrrrrrrr}
2 +\toprule
3 +Design & Cell & Outcome & b3/c7 & b3/c10 & b3/c15 & b5/c7 & b5/c10 & b5/c15 & b8/c7 & b8/c10 & b8/c15 \\
4 +\midrule
5 +classical confirmatory & leverage heavy & n bubbles & +2.33 & +2.33 & +2.33 & +0.90 & +0.90 & +0.90 & +0.30 & +0.30 & +0.30 \\
6 +classical confirmatory & leverage heavy & n crashes & +0.93 & +0.13 & +0.00 & +0.93 & +0.13 & +0.00 & +0.93 & +0.13 & +0.00 \\
7 +classical confirmatory & leverage heavy funding shock & n bubbles & +2.27 & +2.27 & +2.27 & +1.37 & +1.37 & +1.37 & +0.47 & +0.47 & +0.47 \\
8 +classical confirmatory & leverage heavy funding shock & n crashes & +1.23 & +0.30 & +0.00 & +1.23 & +0.30 & +0.00 & +1.23 & +0.30 & +0.00 \\
9 +classical confirmatory & mock llm 50 indep & n bubbles & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 \\
10 +classical confirmatory & mock llm 50 indep & n crashes & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 & +0.00 \\
11 +classical confirmatory & trend heavy & n bubbles & +1.10 & +1.10 & +1.10 & +0.13 & +0.13 & +0.13 & +0.00 & +0.00 & +0.00 \\
12 +classical confirmatory & trend heavy & n crashes & +0.07 & +0.00 & +0.00 & +0.07 & +0.00 & +0.00 & +0.07 & +0.00 & +0.00 \\
13 +\bottomrule
14 +\end{tabular}
\ No newline at end of file
added results/tables/threshold_sensitivity.csv +109 −0
@@ -0,0 +1,109 @@
1 +design,bubble_thr,crash_thr,cell,outcome,control,effect,p,n
2 +classical_confirmatory,0.03,0.07,leverage_heavy,n_bubbles,0.06666666666666667,2.3333333333333335,7.712408930919837e-07,30
3 +classical_confirmatory,0.03,0.07,leverage_heavy,bubble_amp,0.00285286025986331,0.05610639628186829,1.92806912918991e-09,30
4 +classical_confirmatory,0.03,0.07,leverage_heavy,n_crashes,0.0,0.9333333333333333,0.004069703036845098,30
5 +classical_confirmatory,0.03,0.07,leverage_heavy_funding_shock,n_bubbles,0.06666666666666667,2.2666666666666666,9.309666772654047e-08,30
6 +classical_confirmatory,0.03,0.07,leverage_heavy_funding_shock,bubble_amp,0.00285286025986331,0.07032997069381303,1.225662004179797e-09,30
7 +classical_confirmatory,0.03,0.07,leverage_heavy_funding_shock,n_crashes,0.0,1.2333333333333334,0.00027633309040706456,30
8 +classical_confirmatory,0.03,0.07,trend_heavy,n_bubbles,0.06666666666666667,1.1,9.439794156231982e-06,30
9 +classical_confirmatory,0.03,0.07,trend_heavy,bubble_amp,0.00285286025986331,0.027465752199760496,2.7211457127751164e-07,30
10 +classical_confirmatory,0.03,0.07,trend_heavy,n_crashes,0.0,0.06666666666666667,0.1607882084258767,30
11 +classical_confirmatory,0.03,0.07,mock_llm_50_indep,n_bubbles,0.06666666666666667,0.0,,30
12 +classical_confirmatory,0.03,0.07,mock_llm_50_indep,bubble_amp,0.00285286025986331,1.2987245178545475e-06,0.9961006414963004,30
13 +classical_confirmatory,0.03,0.07,mock_llm_50_indep,n_crashes,0.0,0.0,,30
14 +classical_confirmatory,0.03,0.1,leverage_heavy,n_bubbles,0.06666666666666667,2.3333333333333335,7.712408930919837e-07,30
15 +classical_confirmatory,0.03,0.1,leverage_heavy,bubble_amp,0.00285286025986331,0.05610639628186829,1.92806912918991e-09,30
16 +classical_confirmatory,0.03,0.1,leverage_heavy,n_crashes,0.0,0.13333333333333333,0.04339741781077554,30
17 +classical_confirmatory,0.03,0.1,leverage_heavy_funding_shock,n_bubbles,0.06666666666666667,2.2666666666666666,9.309666772654047e-08,30
18 +classical_confirmatory,0.03,0.1,leverage_heavy_funding_shock,bubble_amp,0.00285286025986331,0.07032997069381303,1.225662004179797e-09,30
19 +classical_confirmatory,0.03,0.1,leverage_heavy_funding_shock,n_crashes,0.0,0.3,0.009981299812861963,30
20 +classical_confirmatory,0.03,0.1,trend_heavy,n_bubbles,0.06666666666666667,1.1,9.439794156231982e-06,30
21 +classical_confirmatory,0.03,0.1,trend_heavy,bubble_amp,0.00285286025986331,0.027465752199760496,2.7211457127751164e-07,30
22 +classical_confirmatory,0.03,0.1,trend_heavy,n_crashes,0.0,0.0,,30
23 +classical_confirmatory,0.03,0.1,mock_llm_50_indep,n_bubbles,0.06666666666666667,0.0,,30
24 +classical_confirmatory,0.03,0.1,mock_llm_50_indep,bubble_amp,0.00285286025986331,1.2987245178545475e-06,0.9961006414963004,30
25 +classical_confirmatory,0.03,0.1,mock_llm_50_indep,n_crashes,0.0,0.0,,30
26 +classical_confirmatory,0.03,0.15,leverage_heavy,n_bubbles,0.06666666666666667,2.3333333333333335,7.712408930919837e-07,30
27 +classical_confirmatory,0.03,0.15,leverage_heavy,bubble_amp,0.00285286025986331,0.05610639628186829,1.92806912918991e-09,30
28 +classical_confirmatory,0.03,0.15,leverage_heavy,n_crashes,0.0,0.0,,30
29 +classical_confirmatory,0.03,0.15,leverage_heavy_funding_shock,n_bubbles,0.06666666666666667,2.2666666666666666,9.309666772654047e-08,30
30 +classical_confirmatory,0.03,0.15,leverage_heavy_funding_shock,bubble_amp,0.00285286025986331,0.07032997069381303,1.225662004179797e-09,30
31 +classical_confirmatory,0.03,0.15,leverage_heavy_funding_shock,n_crashes,0.0,0.0,,30
32 +classical_confirmatory,0.03,0.15,trend_heavy,n_bubbles,0.06666666666666667,1.1,9.439794156231982e-06,30
33 +classical_confirmatory,0.03,0.15,trend_heavy,bubble_amp,0.00285286025986331,0.027465752199760496,2.7211457127751164e-07,30
34 +classical_confirmatory,0.03,0.15,trend_heavy,n_crashes,0.0,0.0,,30
35 +classical_confirmatory,0.03,0.15,mock_llm_50_indep,n_bubbles,0.06666666666666667,0.0,,30
36 +classical_confirmatory,0.03,0.15,mock_llm_50_indep,bubble_amp,0.00285286025986331,1.2987245178545475e-06,0.9961006414963004,30
37 +classical_confirmatory,0.03,0.15,mock_llm_50_indep,n_crashes,0.0,0.0,,30
38 +classical_confirmatory,0.05,0.07,leverage_heavy,n_bubbles,0.0,0.9,0.00033757404082763944,30
39 +classical_confirmatory,0.05,0.07,leverage_heavy,bubble_amp,0.0,0.04273920530809517,4.378937522799665e-05,30
40 +classical_confirmatory,0.05,0.07,leverage_heavy,n_crashes,0.0,0.9333333333333333,0.004069703036845098,30
41 +classical_confirmatory,0.05,0.07,leverage_heavy_funding_shock,n_bubbles,0.0,1.3666666666666667,4.2177639491799116e-06,30
42 +classical_confirmatory,0.05,0.07,leverage_heavy_funding_shock,bubble_amp,0.0,0.06542884594559688,2.562375048895747e-07,30
43 +classical_confirmatory,0.05,0.07,leverage_heavy_funding_shock,n_crashes,0.0,1.2333333333333334,0.00027633309040706456,30
44 +classical_confirmatory,0.05,0.07,trend_heavy,n_bubbles,0.0,0.13333333333333333,0.04339741781077554,30
45 +classical_confirmatory,0.05,0.07,trend_heavy,bubble_amp,0.0,0.007614737144890871,0.04373909157771441,30
46 +classical_confirmatory,0.05,0.07,trend_heavy,n_crashes,0.0,0.06666666666666667,0.1607882084258767,30
47 +classical_confirmatory,0.05,0.07,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
48 +classical_confirmatory,0.05,0.07,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
49 +classical_confirmatory,0.05,0.07,mock_llm_50_indep,n_crashes,0.0,0.0,,30
50 +classical_confirmatory,0.05,0.1,leverage_heavy,n_bubbles,0.0,0.9,0.00033757404082763944,30
51 +classical_confirmatory,0.05,0.1,leverage_heavy,bubble_amp,0.0,0.04273920530809517,4.378937522799665e-05,30
52 +classical_confirmatory,0.05,0.1,leverage_heavy,n_crashes,0.0,0.13333333333333333,0.04339741781077554,30
53 +classical_confirmatory,0.05,0.1,leverage_heavy_funding_shock,n_bubbles,0.0,1.3666666666666667,4.2177639491799116e-06,30
54 +classical_confirmatory,0.05,0.1,leverage_heavy_funding_shock,bubble_amp,0.0,0.06542884594559688,2.562375048895747e-07,30
55 +classical_confirmatory,0.05,0.1,leverage_heavy_funding_shock,n_crashes,0.0,0.3,0.009981299812861963,30
56 +classical_confirmatory,0.05,0.1,trend_heavy,n_bubbles,0.0,0.13333333333333333,0.04339741781077554,30
57 +classical_confirmatory,0.05,0.1,trend_heavy,bubble_amp,0.0,0.007614737144890871,0.04373909157771441,30
58 +classical_confirmatory,0.05,0.1,trend_heavy,n_crashes,0.0,0.0,,30
59 +classical_confirmatory,0.05,0.1,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
60 +classical_confirmatory,0.05,0.1,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
61 +classical_confirmatory,0.05,0.1,mock_llm_50_indep,n_crashes,0.0,0.0,,30
62 +classical_confirmatory,0.05,0.15,leverage_heavy,n_bubbles,0.0,0.9,0.00033757404082763944,30
63 +classical_confirmatory,0.05,0.15,leverage_heavy,bubble_amp,0.0,0.04273920530809517,4.378937522799665e-05,30
64 +classical_confirmatory,0.05,0.15,leverage_heavy,n_crashes,0.0,0.0,,30
65 +classical_confirmatory,0.05,0.15,leverage_heavy_funding_shock,n_bubbles,0.0,1.3666666666666667,4.2177639491799116e-06,30
66 +classical_confirmatory,0.05,0.15,leverage_heavy_funding_shock,bubble_amp,0.0,0.06542884594559688,2.562375048895747e-07,30
67 +classical_confirmatory,0.05,0.15,leverage_heavy_funding_shock,n_crashes,0.0,0.0,,30
68 +classical_confirmatory,0.05,0.15,trend_heavy,n_bubbles,0.0,0.13333333333333333,0.04339741781077554,30
69 +classical_confirmatory,0.05,0.15,trend_heavy,bubble_amp,0.0,0.007614737144890871,0.04373909157771441,30
70 +classical_confirmatory,0.05,0.15,trend_heavy,n_crashes,0.0,0.0,,30
71 +classical_confirmatory,0.05,0.15,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
72 +classical_confirmatory,0.05,0.15,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
73 +classical_confirmatory,0.05,0.15,mock_llm_50_indep,n_crashes,0.0,0.0,,30
74 +classical_confirmatory,0.08,0.07,leverage_heavy,n_bubbles,0.0,0.3,0.05918466045448987,30
75 +classical_confirmatory,0.08,0.07,leverage_heavy,bubble_amp,0.0,0.019283614900718903,0.029827175281888312,30
76 +classical_confirmatory,0.08,0.07,leverage_heavy,n_crashes,0.0,0.9333333333333333,0.004069703036845098,30
77 +classical_confirmatory,0.08,0.07,leverage_heavy_funding_shock,n_bubbles,0.0,0.4666666666666667,0.004069703036845098,30
78 +classical_confirmatory,0.08,0.07,leverage_heavy_funding_shock,bubble_amp,0.0,0.03740679784531051,0.0023922175643250406,30
79 +classical_confirmatory,0.08,0.07,leverage_heavy_funding_shock,n_crashes,0.0,1.2333333333333334,0.00027633309040706456,30
80 +classical_confirmatory,0.08,0.07,trend_heavy,n_bubbles,0.0,0.0,,30
81 +classical_confirmatory,0.08,0.07,trend_heavy,bubble_amp,0.0,0.0,,30
82 +classical_confirmatory,0.08,0.07,trend_heavy,n_crashes,0.0,0.06666666666666667,0.1607882084258767,30
83 +classical_confirmatory,0.08,0.07,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
84 +classical_confirmatory,0.08,0.07,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
85 +classical_confirmatory,0.08,0.07,mock_llm_50_indep,n_crashes,0.0,0.0,,30
86 +classical_confirmatory,0.08,0.1,leverage_heavy,n_bubbles,0.0,0.3,0.05918466045448987,30
87 +classical_confirmatory,0.08,0.1,leverage_heavy,bubble_amp,0.0,0.019283614900718903,0.029827175281888312,30
88 +classical_confirmatory,0.08,0.1,leverage_heavy,n_crashes,0.0,0.13333333333333333,0.04339741781077554,30
89 +classical_confirmatory,0.08,0.1,leverage_heavy_funding_shock,n_bubbles,0.0,0.4666666666666667,0.004069703036845098,30
90 +classical_confirmatory,0.08,0.1,leverage_heavy_funding_shock,bubble_amp,0.0,0.03740679784531051,0.0023922175643250406,30
91 +classical_confirmatory,0.08,0.1,leverage_heavy_funding_shock,n_crashes,0.0,0.3,0.009981299812861963,30
92 +classical_confirmatory,0.08,0.1,trend_heavy,n_bubbles,0.0,0.0,,30
93 +classical_confirmatory,0.08,0.1,trend_heavy,bubble_amp,0.0,0.0,,30
94 +classical_confirmatory,0.08,0.1,trend_heavy,n_crashes,0.0,0.0,,30
95 +classical_confirmatory,0.08,0.1,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
96 +classical_confirmatory,0.08,0.1,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
97 +classical_confirmatory,0.08,0.1,mock_llm_50_indep,n_crashes,0.0,0.0,,30
98 +classical_confirmatory,0.08,0.15,leverage_heavy,n_bubbles,0.0,0.3,0.05918466045448987,30
99 +classical_confirmatory,0.08,0.15,leverage_heavy,bubble_amp,0.0,0.019283614900718903,0.029827175281888312,30
100 +classical_confirmatory,0.08,0.15,leverage_heavy,n_crashes,0.0,0.0,,30
101 +classical_confirmatory,0.08,0.15,leverage_heavy_funding_shock,n_bubbles,0.0,0.4666666666666667,0.004069703036845098,30
102 +classical_confirmatory,0.08,0.15,leverage_heavy_funding_shock,bubble_amp,0.0,0.03740679784531051,0.0023922175643250406,30
103 +classical_confirmatory,0.08,0.15,leverage_heavy_funding_shock,n_crashes,0.0,0.0,,30
104 +classical_confirmatory,0.08,0.15,trend_heavy,n_bubbles,0.0,0.0,,30
105 +classical_confirmatory,0.08,0.15,trend_heavy,bubble_amp,0.0,0.0,,30
106 +classical_confirmatory,0.08,0.15,trend_heavy,n_crashes,0.0,0.0,,30
107 +classical_confirmatory,0.08,0.15,mock_llm_50_indep,n_bubbles,0.0,0.0,,30
108 +classical_confirmatory,0.08,0.15,mock_llm_50_indep,bubble_amp,0.0,0.0,,30
109 +classical_confirmatory,0.08,0.15,mock_llm_50_indep,n_crashes,0.0,0.0,,30
added scripts/45_recompute_outcomes.py +11 −0
@@ -0,0 +1,11 @@
1 +"""Recompute outcomes.parquet for one or more designs from saved run artefacts (no simulation, no API)."""
2 +import sys
3 +from pathlib import Path
4 +ROOT = Path(__file__).resolve().parents[1]
5 +sys.path.insert(0, str(ROOT / "src"))
6 +from market_agents.analysis.reload import recompute_design # noqa: E402
7 +for d in sys.argv[1:] or ["classical_confirmatory", "exploratory_mock", "pilot_openai", "confirmatory_openai"]:
8 + p = ROOT / "results/runs" / d
9 + if p.exists():
10 + df = recompute_design(p)
11 + print(f"{d}: {len(df)} runs recomputed")
added scripts/46_threshold_sensitivity.py +39 −0
@@ -0,0 +1,39 @@
1 +"""Pre-registered sensitivity grid for the bubble/crash definitions: bubble 3/5/8 % (>= 10 ticks), crash 7/10/15 % (20-tick window).
2 +Writes results/tables/threshold_sensitivity.csv and a LaTeX fragment with the control-vs-treatment paired effects per threshold."""
3 +import sys
4 +from pathlib import Path
5 +import pandas as pd
6 +ROOT = Path(__file__).resolve().parents[1]
7 +sys.path.insert(0, str(ROOT / "src"))
8 +from market_agents.analysis.reload import recompute_design # noqa: E402
9 +from market_agents.analysis.estimators import paired_effects # noqa: E402
10 +
11 +rows = []
12 +for design, control, cells in (("classical_confirmatory", "control", ["leverage_heavy", "leverage_heavy_funding_shock", "trend_heavy", "mock_llm_50_indep"]),
13 + ("confirmatory_openai", "dose_000", ["dose_025", "dose_050", "dose_100", "leverage_025"])):
14 + p = ROOT / "results/runs" / design
15 + if not p.exists():
16 + continue
17 + for b in (0.03, 0.05, 0.08):
18 + for c in (0.07, 0.10, 0.15):
19 + df = recompute_design(p, write=False, bubble_thr=b, crash_thr=c)
20 + df["cell"] = df.name.str.split("/").str[-1]
21 + for cell in cells:
22 + if cell not in set(df.cell):
23 + continue
24 + for oc in ("n_bubbles", "bubble_amp", "n_crashes"):
25 + e = paired_effects(df, oc, "cell", cell, control)
26 + rows.append({"design": design, "bubble_thr": b, "crash_thr": c, "cell": cell, "outcome": oc, "control": e.get("control_mean"),
27 + "effect": e.get("diff"), "p": e.get("p"), "n": e.get("n")})
28 +t = pd.DataFrame(rows)
29 +out = ROOT / "results/tables"
30 +out.mkdir(parents=True, exist_ok=True)
31 +t.to_csv(out / "threshold_sensitivity.csv", index=False)
32 +if len(t):
33 + piv = t[t.outcome.isin(["n_bubbles", "n_crashes"])].pivot_table(index=["design", "cell", "outcome"], columns=["bubble_thr", "crash_thr"], values="effect")
34 + lines = ["\\begin{tabular}{lll" + "r" * piv.shape[1] + "}", "\\toprule", "Design & Cell & Outcome & " + " & ".join(f"b{int(b*100)}/c{int(c*100)}" for b, c in piv.columns) + " \\\\", "\\midrule"]
35 + for (d, cell, oc), r in piv.iterrows():
36 + lines.append(f"{d.replace('_', ' ')} & {cell.replace('_', ' ')} & {oc.replace('_', ' ')} & " + " & ".join(f"{v:+.2f}" for v in r.values) + " \\\\")
37 + lines += ["\\bottomrule", "\\end{tabular}"]
38 + (out / "tab_threshold_sensitivity.tex").write_text("\n".join(lines))
39 +print(t.groupby(["design", "cell", "outcome"])["effect"].agg(["min", "max"]).round(2).to_string() if len(t) else "nothing")
added scripts/60_frozen_library.py +59 −0
@@ -0,0 +1,59 @@
1 +"""Phase 6 (scaling arm) — build the frozen decision library from recorded live LLM decisions and replay it
2 +at N = 1,000 traders with zero API calls. The library policy is a k-NN replay of recorded decisions (non-adaptive);
3 +runs are labelled provider = 'library' and reported separately from online runs."""
4 +from __future__ import annotations
5 +
6 +import sys
7 +from pathlib import Path
8 +
9 +import numpy as np
10 +import pandas as pd
11 +
12 +ROOT = Path(__file__).resolve().parents[1]
13 +sys.path.insert(0, str(ROOT / "src"))
14 +from market_agents.experiments.config import RunConfig # noqa: E402
15 +from market_agents.experiments.runner import run_config # noqa: E402
16 +from market_agents.llm.library import DecisionLibrary, FEATURES # noqa: E402
17 +from market_agents.metrics.outcomes import run_outcomes # noqa: E402
18 +
19 +SRC = ROOT / "results/runs/confirmatory_openai"
20 +LIB = ROOT / "results/library/gpt-5.4-nano_single.npz"
21 +OUT = ROOT / "results/runs/library_scale"
22 +
23 +
24 +def build() -> DecisionLibrary:
25 + run_dirs = [p.parent for p in SRC.glob("dose_*/seed*/llm_decisions.parquet")]
26 + if not run_dirs:
27 + raise SystemExit("no confirmatory runs with LLM decisions yet")
28 + lib = DecisionLibrary.from_runs(run_dirs)
29 + LIB.parent.mkdir(parents=True, exist_ok=True)
30 + lib.save(LIB)
31 + print(f"library: {len(lib)} recorded decisions from {len(run_dirs)} runs; features {FEATURES}")
32 + return lib
33 +
34 +
35 +def replay(seeds=(301, 302, 303, 304, 305), n_traders=1000, shares=(0.0, 0.25)):
36 + rows = []
37 + for n in (100, n_traders):
38 + act = {k: v * 100.0 / n for k, v in RunConfig().population.activity.items()}
39 + for share in shares:
40 + for s in seeds:
41 + cfg = RunConfig.from_yaml(ROOT / "configs/baseline.yaml", **{
42 + "name": f"library_scale/n{n}_share{int(share * 100)}", "seed": s, "population.n_traders": n, "population.activity": act,
43 + "population.llm_share": share, "population.llm.provider_mix": {"library": 1.0}, "population.llm.models": {"library": "knn-replay"},
44 + "population.llm.frozen_library": str(LIB), "population.llm.usd_cap": 0.0, "population.llm.cache": False,
45 + "treatment": {"arm": "library", "share": share, "n": n}})
46 + res = run_config(cfg, out_dir=OUT / f"n{n}_share{int(share * 100)}" / f"seed{s:04d}")
47 + oc = run_outcomes(res)
48 + oc["run_dir"] = str(OUT / f"n{n}_share{int(share * 100)}" / f"seed{s:04d}")
49 + rows.append(oc)
50 + print(f" n={n} share={share} seed={s}: mad={oc['mad_pct']:.2f} spread={oc['spread_bp']:.1f} bubbles={oc['n_bubbles']} llm_vol={oc['llm_share_volume']:.3f} wall={oc['wall_s']:.1f}s", flush=True)
51 + df = pd.DataFrame(rows)
52 + OUT.mkdir(parents=True, exist_ok=True)
53 + df.to_parquet(OUT / "outcomes.parquet", index=False)
54 + print(df.groupby("name")[["mad_pct", "spread_bp", "n_bubbles", "max_dd", "llm_share_volume"]].mean().round(3))
55 +
56 +
57 +if __name__ == "__main__":
58 + build()
59 + replay()
added src/market_agents/analysis/reload.py +50 −0
@@ -0,0 +1,50 @@
1 +"""Rebuild run-level outcomes from saved run artefacts (no re-simulation): used after metric changes and for
2 +threshold-sensitivity grids. Every recomputed number is still traceable to the saved parquet files."""
3 +from __future__ import annotations
4 +
5 +import json
6 +from dataclasses import dataclass
7 +from pathlib import Path
8 +
9 +import pandas as pd
10 +
11 +from ..experiments.config import RunConfig
12 +from ..metrics.outcomes import run_outcomes
13 +
14 +
15 +@dataclass
16 +class SavedRun:
17 + config: RunConfig
18 + ticks: pd.DataFrame
19 + trades: pd.DataFrame
20 + agents: pd.DataFrame
21 + llm: pd.DataFrame
22 + manifest: dict
23 + run_dir: Path
24 +
25 +
26 +def load_run(run_dir: str | Path) -> SavedRun:
27 + rd = Path(run_dir)
28 + cfg = RunConfig.from_yaml(rd / "config.yaml")
29 + with open(rd / "manifest.json") as f:
30 + man = json.load(f)
31 + llm_p = rd / "llm_decisions.parquet"
32 + return SavedRun(cfg, pd.read_parquet(rd / "ticks.parquet"), pd.read_parquet(rd / "trades.parquet"), pd.read_parquet(rd / "agents.parquet"),
33 + pd.read_parquet(llm_p) if llm_p.exists() else pd.DataFrame(columns=["t", "agent_id", "provider", "model", "valid"]), man, rd)
34 +
35 +
36 +def recompute_design(design_dir: str | Path, write: bool = True, **thresholds) -> pd.DataFrame:
37 + design_dir = Path(design_dir)
38 + rows = []
39 + for man in sorted(design_dir.glob("*/seed*/manifest.json")):
40 + r = load_run(man.parent)
41 + oc = run_outcomes(r, **thresholds)
42 + oc["run_dir"] = str(man.parent)
43 + rows.append(oc)
44 + df = pd.DataFrame(rows)
45 + if write and not thresholds:
46 + df.to_parquet(design_dir / "outcomes.parquet", index=False)
47 + for r in rows:
48 + with open(Path(r["run_dir"]) / "outcomes.json", "w") as f:
49 + json.dump(r, f, indent=1, default=float)
50 + return df
modified src/market_agents/experiments/config.py +7 −1
@@ -189,13 +189,19 @@ class RunConfig(BaseModel):
189 189 yaml.safe_dump(self.model_dump(mode="json"), f, sort_keys=False)
190 190
191 191
192 +SECTIONS = {"assets", "fundamentals", "news", "exchange", "population", "llm", "endowment", "latency", "output", "treatment"}
193 +
194 +
192 195 def deep_update(base: dict, upd: dict) -> dict:
196 + """Recursive override. Config *sections* (nested models) are merged key by key; *leaf* dictionaries
197 + (provider_mix, mix, activity, models, policy_kwargs, price_assumptions, ...) are REPLACED wholesale, so
198 + `population.llm.provider_mix: {openai: 1.0}` yields exactly {openai: 1.0} and not a mock/openai mixture."""
193 199 out = dict(base)
194 200 for k, v in upd.items():
195 201 if "." in k: # dotted override: population.llm_share=0.25
196 202 head, rest = k.split(".", 1)
197 203 out[head] = deep_update(out.get(head, {}) or {}, {rest: v})
198 − elif isinstance(v, dict) and isinstance(out.get(k), dict):
204 + elif isinstance(v, dict) and isinstance(out.get(k), dict) and k in SECTIONS:
199 205 out[k] = deep_update(out[k], v)
200 206 else:
201 207 out[k] = v
modified src/market_agents/metrics/outcomes.py +27 −0
@@ -259,6 +259,32 @@ def pairwise_sign_corr(d: pd.DataFrame, window: int = 20) -> float:
259 259 return float(np.nanmean(vals)) if np.isfinite(vals).any() else np.nan
260 260
261 261
262 +def flow_corr_by_policy(trades: pd.DataFrame, agents: pd.DataFrame, window: int = 20) -> dict:
263 + """Average pairwise correlation of agents' net signed traded volume per `window` ticks, by policy group
264 + (a classical analogue of llm_pairwise_corr that needs no decision log)."""
265 + if len(trades) < 50:
266 + return {}
267 + t = trades.copy()
268 + t["w"] = (t["time"] // window).astype(int)
269 + buy = t.groupby(["w", "buyer"])["qty"].sum().rename("q").reset_index().rename(columns={"buyer": "agent_id"})
270 + sell = t.groupby(["w", "seller"])["qty"].sum().rename("q").reset_index().rename(columns={"seller": "agent_id"})
271 + sell["q"] = -sell["q"]
272 + flow = pd.concat([buy, sell]).groupby(["w", "agent_id"])["q"].sum().reset_index()
273 + piv = flow.pivot(index="w", columns="agent_id", values="q").fillna(0.0)
274 + pol = agents.set_index("agent_id")["policy"]
275 + out = {}
276 + for name, grp in pol.groupby(pol):
277 + ids = [i for i in grp.index if i in piv.columns]
278 + if len(ids) < 3 or piv.shape[0] < 4:
279 + continue
280 + c = piv[ids].corr().to_numpy()
281 + iu = np.triu_indices(len(ids), 1)
282 + vals = c[iu]
283 + if np.isfinite(vals).any():
284 + out[f"flow_corr_{name}"] = float(np.nanmean(vals))
285 + return out
286 +
287 +
262 288 def run_outcomes(res, bubble_thr: float = 0.05, bubble_min_len: int = 10, crash_thr: float = 0.10, crash_window: int = 20) -> dict:
263 289 cfg = res.config
264 290 out = {"name": cfg.name, "seed": cfg.seed, "config_hash": cfg.config_hash(), "n_traders": cfg.population.n_traders,
@@ -266,4 +292,5 @@ def run_outcomes(res, bubble_thr: float = 0.05, bubble_min_len: int = 10, crash_
266 292 out.update({k: res.manifest[k] for k in ("llm_share_traders", "llm_share_orders", "llm_share_volume", "n_llm_decisions", "n_trades", "wall_s")})
267 293 out.update(series_outcomes(res.ticks, cfg.warmup, bubble_thr, bubble_min_len, crash_thr, crash_window, res.manifest.get("shocks")))
268 294 out.update(agent_outcomes(res.agents, res.trades, res.llm, cfg.n_ticks))
295 + out.update(flow_corr_by_policy(res.trades, res.agents))
269 296 return out
added tests/unit/test_config_overrides.py +11 −0
@@ -0,0 +1,11 @@
1 +from market_agents.experiments.config import RunConfig
2 +
3 +
4 +def test_leaf_dict_overrides_replace_and_sections_merge():
5 + cfg = RunConfig()
6 + t = cfg.with_overrides(**{"population.llm.provider_mix": {"openai": 1.0}, "population.llm_share": 0.25, "exchange.halt_threshold": 0.05})
7 + assert t.population.llm.provider_mix == {"openai": 1.0}
8 + assert t.population.llm_share == 0.25 and t.exchange.halt_threshold == 0.05
9 + assert t.exchange.taker_fee_bps == cfg.exchange.taker_fee_bps # section merge keeps the rest
10 + t2 = cfg.with_overrides(population={"mix": {"market_maker": 1.0}, "activity": {"market_maker": 0.0}})
11 + assert t2.population.mix == {"market_maker": 1.0}
12
Menu

Theme