\section{Full hyperparameters} \label{app:hyperparameters} Table~\ref{tab:hp_baseline} lists every parameter of \code{configs/baseline.yaml} together with the defaults of the configuration schema (\code{experiments/config.py}) that the file does not set explicitly. Tables~\ref{tab:hp_classical}--\ref{tab:hp_pilot} list the overrides of every cell of the four design files; a cell inherits everything else from the baseline. Table~\ref{tab:hp_models} summarises the model cards (\code{docs/model\_cards.md}). \begin{small} \begin{longtable}{@{}p{5.0cm} p{3.4cm} p{6.6cm}@{}} \caption{Baseline configuration (\code{configs/baseline.yaml}; schema defaults in italics)} \label{tab:hp_baseline}\\ \toprule Parameter & Value & Meaning \\ \midrule \endfirsthead \toprule Parameter & Value & Meaning \\ \midrule \endhead \bottomrule \endfoot \multicolumn{3}{@{}l}{\emph{Run}}\\ \code{name} & baseline & run label (design/cell in designs) \\ \code{seed} & 1 & master seed of all streams \\ \code{n\_ticks} & 600 & ticks per run \\ \code{warmup} & 100 & ticks excluded from outcomes; LLM decisions start at \code{warmup}/2 \\ \multicolumn{3}{@{}l}{\emph{assets}}\\ \code{n\_assets} & 1 & number of risky assets \\ \code{tick\_cents} & 1 & tick size in cents \\ \code{initial\_price\_cents} & 20000 & reference price $=\mu/r$ (200.00) \\ \code{price\_band\_pct} & 0.5 & limit prices farther than $\pm50\%$ from the midpoint are rejected \\ \code{max\_order\_qty} & 10000 & maximum lots per order at the exchange \\ \multicolumn{3}{@{}l}{\emph{fundamentals}}\\ \code{div\_interval} & 20 & ticks between dividends ($\Delta$) \\ \code{r\_period} & 0.0025 & discount rate per dividend period ($r$) \\ \code{mu} & [50.0] & mean dividend in cents, regime 0, per asset ($\mu$) \\ \code{mu\_shift} & 0.0 & regime-1 mean $=\mu(1+\text{mu\_shift})$; 0 disables regimes \\ \code{p\_switch} & 0.0 & per-period regime switch probability \\ \code{rho} & 0.98 & persistence of the deviation ($\rho$) \\ \code{sigma} & 2.0 & innovation standard deviation in cents ($\sigma$) \\ \code{jump\_prob} & 0.0 & per-period jump probability (dividend noise) \\ \code{jump\_sigma} & 0.0 & jump standard deviation in cents \\ \code{factor\_loading} & [0.0] & loading $b_k$ on the common factor \\ \code{x0} & 0.0 & initial revealed deviation \\ \multicolumn{3}{@{}l}{\emph{news}}\\ \code{rate} & 0.02 & per-tick probability of a public item per asset \\ \code{noise\_sd} & 1.0 & stated noise of credible items (cents) \\ \code{misleading\_share} & 0.0 & share of biased items \\ \code{misleading\_bias} & 10.0 & bias of a misleading item (cents, random sign) \\ \code{window} & 20 & ticks of news visible in the observation \\ \multicolumn{3}{@{}l}{\emph{exchange}}\\ \code{maker\_fee\_bps} & 0.0 & maker fee (negative = rebate) \\ \code{taker\_fee\_bps} & 2.0 & taker fee in basis points of notional \\ \code{min\_latency} & 0.05 & floor on per-agent latency (ticks) \\ \code{halt\_threshold} & null & circuit breaker off (treatment: 0.05) \\ \code{halt\_window} & 10 & ticks over which the move is measured \\ \code{halt\_duration} & 20 & halt length in ticks \\ \code{halt\_cancel\_resting} & true & cancel resting orders at a halt \\ \code{allow\_short} & false & short selling switch (inert: every account has \code{short\_allowed=false}) \\ \code{max\_short\_lots} & 0 & short limit when shorting is allowed \\ \code{margin\_check} & true & end-of-tick margin and bankruptcy check \\ \code{liquidation\_fraction} & 0.5 & share of each position sold on a margin call \\ \code{order\_ttl} & 50 & resting orders expire after this many ticks \\ \code{position\_limit} & \emph{null} & max $|$position$|$ in lots (treatment: 300) \\ \code{call\_auction\_interval} & \emph{null} & batch clearing every $k$ ticks (treatment: 5); collar 0.02 fixed in \code{ExchangeConfig} \\ \multicolumn{3}{@{}l}{\emph{population}}\\ \code{n\_traders} & 100 & trader slots ($N$) \\ \code{mix} & fund.\ 0.25, trend 0.06, meanrev 0.10, noise 0.50, MM 0.05, statarb 0.0, leveraged 0.04 & shares of slots by policy (calibrated 2026-10-27) \\ \code{activity} & fund.\ 0.20, trend 0.20, meanrev 0.20, noise 0.30, MM 0.5, statarb 0.2, leveraged 0.2 & per-tick activation probability \\ \code{policy\_kwargs} & fundamentalist \{aggressiveness: 20.0\}; noise \{p\_market: 0.6\}; market\_maker \{quote\_qty: 20\} & calibrated policy parameters (others at code defaults, Table~\ref{tab:policies}) \\ \code{llm\_share} & 0.0 & fraction of slots controlled by the LLM policy ($\varphi$) \\ \code{llm\_replace} & proportional & stratified replacement across types (or one policy name) \\ \code{llm\_keep\_market\_makers} & true & market makers are never replaced \\ \code{informed\_share} & 0.3 & share of fundamentalists receiving private signals \\ \code{precision} & 2.0 & signal precision $\pi$ of informed fundamentalists \\ \code{leverage\_cap} & 3.0 & gross exposure / equity cap of leveraged slots ($L$) \\ \code{maintenance\_margin} & 0.25 & margin-call threshold on equity / gross ($m$) \\ \code{endowment.cash\_cents} & 2000000 & base cash (20,000.00) \\ \code{endowment.shares} & 100 & base lots per asset \\ \code{endowment.wealth\_dispersion} & 0.3 & lognormal sd of the wealth multiplier \\ \code{latency.min}, \code{latency.max} & 0.05, 1.0 & uniform latency range (ticks) \\ \code{latency.llm\_latency} & null & matched-latency override for LLM slots \\ \multicolumn{3}{@{}l}{\emph{population.llm}}\\ \code{provider\_mix} & \{mock: 1.0\} & provider $\to$ share of LLM slots \\ \code{models} & mock: mock-v1; openai: gpt-5.4-nano; anthropic: claude-haiku-5-5 & model id per provider alias \\ \code{prompt\_set} & single & single (generalist) or diverse (8 personas) \\ \code{prompt\_version} & v1 & frozen prompt version \\ \code{memory} & 0 & past own decisions shown (treatment: 5) \\ \code{channel} & false & cohort communication channel \\ \code{cohort\_size} & 5 & cohort size and channel length \\ \code{decision\_interval} & 20 & ticks between LLM decisions \\ \code{stagger}, \code{stagger\_slots} & true, 4 & offsets $\{0,5,10,15\}$ \\ \code{informed\_share} & null & inherit the replaced slot's information (a number overrides) \\ \code{precision} & 2.0 & precision used when \code{informed\_share} is a number \\ \code{max\_order\_qty} & 50 & cap on LLM order size (lots) \\ \code{reasoning\_effort} & low & OpenAI \code{reasoning.effort} / Anthropic \code{effort} \\ \code{max\_output\_tokens} & 1200 & output cap per call (includes reasoning tokens) \\ \code{concurrency} & 8 & parallel requests per decision batch \\ \code{usd\_cap} & 5.0 & hard USD cap per run \\ \code{cache} & true & reuse identical (provider, model, prompt) decisions \\ \code{temperature} & \emph{null} & never sent to gpt-5 / o-series models \\ \code{timeout\_s}, \code{max\_retries} & \emph{60.0, 3} & client timeout and retries \\ \code{token\_cap}, \code{decision\_cap} & \emph{null, null} & optional total-token and per-agent decision caps \\ \code{frozen\_library} & \emph{null} & path of the recorded decision library (provider \code{library}) \\ \code{adaptive\_prompt} & \emph{false} & P\&L feedback line in the prompt \\ \code{price\_assumptions} & \emph{Table~\ref{tab:hp_models}} & USD per 1M tokens by model id \\ \multicolumn{3}{@{}l}{\emph{shocks}}\\ shock 1 & \{time: 300, kind: fundamental\_jump, size: 10.0\} & $+10$ cents on the latent deviation ($+2.2\%$ of $V$) \\ shock 2 & \{time: 450, kind: placebo\} & logged, no effect \\ \multicolumn{3}{@{}l}{\emph{output}}\\ \code{events} & false & write the full event log \\ \code{trades}, \code{llm\_log} & true, true & write trade and LLM-decision frames \\ \code{lookback} & 60 & ticks of midpoint history in the observation \\ \end{longtable} \end{small} \begin{small} \begin{longtable}{@{}p{4.3cm} p{10.7cm}@{}} \caption{Cells of \code{configs/classical\_confirmatory.yaml} (seeds 101--130; design overrides: \code{provider\_mix} \{mock: 1.0\}, \code{usd\_cap} 0.0)} \label{tab:hp_classical}\\ \toprule Cell & Overrides (dotted paths relative to the baseline) \\ \midrule \endfirsthead \toprule Cell & Overrides \\ \midrule \endhead \bottomrule \endfoot control & none \\ placebo\_shock & shocks: placebo at 300 and at 450 (no jump) \\ trend\_heavy & population.mix: trend 0.16, noise 0.40 (others as baseline) \\ leverage\_heavy & population.mix: leveraged 0.19, noise 0.35 \\ leverage\_heavy\_funding\_shock & population.mix as leverage\_heavy; shocks: fundamental\_jump $-10.0$ at 300, funding 0.5 at 320 \\ liquidity\_shock & shocks: fundamental\_jump 10.0 at 300, liquidity at 300, liquidity\_end at 360 \\ info\_low & population.precision 0.5 \\ info\_high & population.precision 8.0 \\ misleading\_news & news.misleading\_share 0.5 \\ breaker\_5 & exchange.halt\_threshold 0.05 \\ poslimit\_300 & exchange.position\_limit 300 \\ auction\_5 & exchange.call\_auction\_interval 5 \\ mock\_llm\_25\_indep & population.llm\_share 0.25 (mock provider) \\ mock\_llm\_50\_indep & population.llm\_share 0.50 (mock provider) \\ k2\_control & assets.n\_assets 2; fundamentals.mu [50, 50]; factor\_loading [0.7, 0.7]; population.mix: noise 0.45, statarb 0.05 \\ k2\_leverage & as k2\_control with leveraged 0.19, noise 0.30; shocks: fundamental\_jump $-10.0$ on asset 0 at 300, funding 0.5 at 320 \\ \end{longtable} \end{small} \begin{small} \begin{longtable}{@{}p{4.3cm} p{10.7cm}@{}} \caption{Cells of \code{configs/confirmatory\_openai.yaml} (seeds 201--207; design overrides: \code{provider\_mix} \{openai: 1.0\}, \code{models} \{openai: gpt-5.4-nano, openai\_mini: gpt-5.4-mini, mock: mock-v1, anthropic: claude-haiku-5-5\}, \code{usd\_cap} 2.0, \code{concurrency} 8)} \label{tab:hp_confirmatory}\\ \toprule Cell & Overrides \\ \midrule \endfirsthead \toprule Cell & Overrides \\ \midrule \endhead \bottomrule \endfoot dose\_000 / 005 / 010 / 025 / 050 / 100 & population.llm\_share 0.00 / 0.05 / 0.10 / 0.25 / 0.50 / 1.00 (single generalist prompt, gpt-5.4-nano) \\ div\_prompts\_025 & llm\_share 0.25; llm.prompt\_set diverse \\ div\_models\_025 & llm\_share 0.25; llm.prompt\_set diverse; llm.provider\_mix \{openai: 0.5, openai\_mini: 0.5\} \\ memory\_025 & llm\_share 0.25; llm.memory 5 \\ channel\_025 & llm\_share 0.25; llm.channel true \\ adaptive\_025 & llm\_share 0.25; llm.adaptive\_prompt true \\ leverage\_025 & llm\_share 0.25; population.mix: leveraged 0.19, noise 0.35 \\ breaker\_025 & llm\_share 0.25; exchange.halt\_threshold 0.05 \\ poslimit\_025 & llm\_share 0.25; exchange.position\_limit 300 \\ fair\_mini\_005 & llm\_share 0.05; llm.provider\_mix \{openai\_mini: 1.0\} (gpt-5.4-mini; equal-USD comparison with dose\_025) \\ fair\_latency\_025 & llm\_share 0.25; population.latency.llm\_latency 0.05 \\ \end{longtable} \end{small} \begin{small} \begin{longtable}{@{}p{4.3cm} p{10.7cm}@{}} \caption{Cells of \code{configs/exploratory.yaml} (mock dry run, seeds 1--3; design overrides: \code{provider\_mix} \{mock: 1.0\}, \code{usd\_cap} 0.0)} \label{tab:hp_exploratory}\\ \toprule Cell & Overrides \\ \midrule \endfirsthead \toprule Cell & Overrides \\ \midrule \endhead \bottomrule \endfoot share\_0 / 5 / 25 / 50 & population.llm\_share 0.0 / 0.05 / 0.25 / 0.50 \\ diverse\_25 & llm\_share 0.25; llm.prompt\_set diverse \\ memory\_25 & llm\_share 0.25; llm.memory 5 \\ channel\_25 & llm\_share 0.25; llm.channel true \\ leverage\_25 & llm\_share 0.25; population.mix: leveraged 0.19, noise 0.35 \\ breaker\_25 & llm\_share 0.25; exchange.halt\_threshold 0.05 \\ poslimit\_25 & llm\_share 0.25; exchange.position\_limit 300 \\ auction\_25 & llm\_share 0.25; exchange.call\_auction\_interval 5 \\ k2\_25 & llm\_share 0.25; assets.n\_assets 2; fundamentals.mu [50, 50]; factor\_loading [0.7, 0.7]; population.mix: noise 0.45, statarb 0.05 \\ \end{longtable} \end{small} \begin{small} \begin{longtable}{@{}p{4.3cm} p{10.7cm}@{}} \caption{Cells of \code{configs/pilot\_openai.yaml} (seeds 1--3; design overrides: \code{provider\_mix} \{openai: 1.0\}, \code{models} \{openai: gpt-5.4-nano, mock: mock-v1, anthropic: claude-haiku-5-5\}, \code{usd\_cap} 1.5, \code{concurrency} 8)} \label{tab:hp_pilot}\\ \toprule Cell & Overrides \\ \midrule \endfirsthead \toprule Cell & Overrides \\ \midrule \endhead \bottomrule \endfoot share\_5 / 25 / 50 & population.llm\_share 0.05 / 0.25 / 0.50 (gpt-5.4-nano, single prompt) \\ \end{longtable} \end{small} \begin{table}[H] \centering \caption{Model cards summary (prices in USD per 1M tokens: input / cached input / output; source: provider pricing pages fetched 2026-10-27 for OpenAI, Anthropic's published table; identical to \code{LLMCfg.price\_assumptions})} \label{tab:hp_models} \footnotesize \begin{tabular}{@{}p{2.7cm} p{2.6cm} p{2.3cm} p{1.6cm} p{5.6cm}@{}} \toprule Model id & Price & Reasoning effort & Output cap & Status / role \\ \midrule gpt-5.4-nano & 0.20 / 0.02 / 1.25 & low & 1,200 & live; primary model (all dose, mechanism, safeguard and fairness cells; library source) \\ gpt-5.4-mini & 0.75 / 0.075 / 4.50 & low & 1,200 & live-capable; two-model mix and equal-USD cells \\ gpt-5-nano & 0.05 / 0.005 / 0.40 & low & 1,200 & priced; optional replication, not planned \\ gpt-5-mini & 0.25 / 0.025 / 2.00 & low & 1,200 & priced only \\ gpt-4.1-nano & 0.10 / 0.025 / 0.40 & n/a & 1,200 & priced only \\ gpt-4.1-mini & 0.40 / 0.10 / 1.60 & n/a & 1,200 & priced only \\ claude-haiku-5-5 & 0.10 / 0.01 / 0.50 & low (\code{effort}) & 1,200 & blocked (Anthropic key rejected, HTTP 401); mock dry run only \\ claude-sonnet-5-5 & 2.00 / 0.20 / 10.00 & low & 1,200 & blocked; mock dry run only \\ mock-v1 & 0 / 0 / 0 & n/a & n/a & mock (seeded value rule, 5\% invalid); not evidence about LLMs \\ library (knn-replay) & 0 & n/a & n/a & frozen nearest-neighbour replay of recorded decisions; non-adaptive; reported separately \\ \bottomrule \end{tabular} \end{table} \noindent The Anthropic adapter sends \code{max\_tokens} $=\max(\texttt{max\_output\_tokens},256)$ and \code{output\_config.effort}. Reasoning-token accounting exists only in the OpenAI adapter; the Anthropic adapter reports input, cached-input and output tokens. An unknown model id is priced at the most expensive known output price. Every manifest stores the price table in force when the run was made.