agentic-trader

An agentic AI trading desk for equities and FX. Specialist agents (technical, fundamentals or macro-rates, news, sentiment, alpha) write structured reports; bull and bear researchers debate them; a trader sizes the position around a strategic weight; a three-view risk team argues the size; a portfolio manager decides inside hard limits. Around the desk sits an enterprise-style harness: every data access is a catalogued, policy-gated tool call that leaves SHA-256 evidence, plans are validated before they run, a critic challenges the result, and the report is audited so every number and evidence id traces back. Below it, a C++17 quant core, an alpha library, execution algorithms and portfolio construction. Python · C++17 · pybind11 · MCP · FastAPI · Claude (Anthropic SDK) · FRED · SEC EDGAR · walk-forward backtesting.

What changed in v0.12.0

Four research rounds, no edge

Since v0.8.0 the project looked for an edge over the volatility-targeted control four times, on design data only: a multi-asset base, trend and carry streams (v0.9), the desk's tilt as a sized overlay (v0.10), and a longer design period from 2008 with a long/short multi-horizon trend stream (v0.12). None beat its control and nothing was adopted. The pages are generated from result files: v0.9, v0.10, v0.12.

Every table re-measured again

A second adversarial review (89 confirmed findings) changed when a filing becomes visible (acceptance time, not filing date), the price impact is measured on, and two sizing and confidence rules. The 15-sleeve holdout portfolio is at Sharpe 0.91 against 0.86 buy & hold and 0.99 vol-target (desk − vol-target −0.08 [−0.46, +0.30]). The tables further down this page are the v0.8.0 measurement; each is re-measured in the v0.11 page.

The forward record

Every historical period has now been looked at. A daily paper-trading job, frozen on 2026-09-29 and pre-registered, appends to an append-only ledger and logs any revision of history beside it. It is the only unseen data, and a Sharpe near 1 needs years before its interval excludes zero.

Two new guides

How the AI works: what each agent does, when the model is called, what it may decide and what stops it. How the quant works: the two-backend core, the backtester's conventions, risk, alphas, portfolios and the statistics. The guide now has 50 concepts, the cookbook 100 recipes, and there are 38 diagrams.

Engineering

879 tests collected on both backends (C++ 879 passed; numpy 839 passed, 40 C++-only skipped) and 26 C++ test functions. Every function the quant facade exports is fuzzed on both backends; that fuzzing found and fixed a threshold in an old baseline that rounding noise decided differently on one platform. The trend signal strat_tsmom is in the C++ core with a numpy twin.

What changed in v0.8.0

Every number re-measured

A tier-1 review of v0.7 (91 findings) changed the engine: constant units between decisions with post-cost sizing, a cash leg (idle capital earns the 3-month bill; Sharpe on excess returns), equity-scaled impact with each sleeve paying at its own capital, the desk told its true position after a stop, gap-through-take fills at the open, a two-stage cluster bootstrap. No number from v0.7 is carried forward: scripts/measure_v08.py re-measures every published table into results/v08/ (each file carries its provenance) and scripts/render_v08_tables.py prints what the documents paste.

The cash leg decided the headline

Holdout 15-sleeve portfolio, cash leg on: desk Sharpe 0.80 vs 0.86 plain buy & hold vs 0.99 vol-targeted (desk − B&H −0.06 [−0.41, +0.30] p 0.748; desk − vol-target −0.19 [−0.53, +0.16] p 0.297, paired block bootstrap over days). Cash leg off, the v0.7 convention: 1.04 / 1.05 / 1.24. The order is the same either way, so the v0.7 "beats plain buy & hold" (1.09 vs 1.06) is retracted.

Drawdown against the fair control

Core holdout mean max drawdown 17.40% (desk) vs 31.64% (buy & hold) vs 18.98% (vol-target): −14.24 points [−20.41, −8.70] p 0.00 against buy & hold, BH-significant; −1.58 [−4.33, +1.14] p 0.27 against the control, not. On the 10 core equities the desk's drawdown is not lower than the control's (+0.83 [−1.63, +3.21] p 0.50, not BH-significant); on the 45 extended names it is (−4.33 [−6.10, −2.55] p 0.00, BH-significant). On FX the control sits at the shared position cap, so there is no control.

Retracted

The v0.7 stratified bootstrap (it could only narrow intervals; replaced by the cluster bootstrap); the v0.7 execution-algorithm magnitudes (every sleeve was charged √15× too much — re-measured at the sleeve's capital on the $1B holdout portfolio: VWAP 0.66%, TWAP 0.70%, Almgren–Chriss (κ=5) 0.87% of the sleeve paid in impact, Sharpe 0.78 / 0.78 / 0.77); "the desk's own risk model is calibrated" (what was tested was the portfolio's own returns — the desk's per-instrument forecast is now tested: Kupiec rejects on 2 of 15 core instruments at 5%, Christoffersen independence on 6 of 15); and the portfolio's "beats plain buy & hold".

Engineering

832 tests collected on both backends (C++ 832 passed; numpy 796 passed, 36 C++-only skipped), 95% line coverage, 25 C++ test functions; every result carries provenance (version, commit, backend, dependency versions) and a *.provenance.json sidecar; the lock file is Python-3.12-only. The measurement driver hands each run its own provider settings — a first run had shared one provider, leaving EDGAR and the cash leg on in the "off" runs, and those five files were re-measured. Nothing remains unseen: the reserve period and the extended universe were consulted for earlier decisions, and v0.8 re-measured every period.

Measured, not claimed

Test suite               879 pytest tests collected on both backends at v0.12.0 (C++ backend 879 passed; numpy fallback 839 passed, 40 C++-only skipped; the breakdown that follows is the v0.8.0 one, 832 tests) · 95% line coverage on the numpy backend (weakest file data/yahoo.py 75%) — 105 v0.8 fixes + 17 CLI · 68 v0.8 agents · 59 hypothesis fuzz properties on the C++ boundary + 7 on the agentic layer · 57 v0.8 engine · 57 v0.8 data · 41 v0.8 execution · 41 v0.8 agentic · 38 quant edge cases · 37 v0.7 · 35 agent · 30 v0.8 portfolio · 30 agentic · 21 v0.8 CLI · 20 v0.6 · 20 quant research · 19 v0.5 · 19 pipeline · 17 workflow · 15 adversarial · 13 data · 12 v0.8 stats · 11 LLM-eval · 11 EDGAR · 10 v0.8 protocol · 8 v0.8 alpha · 7 services (FastAPI client + a real MCP stdio round trip) · 7 quant · 25 C++ test functions (one ctest test)
One task                 ≈31 ms offline: plan → 12 steps → 2 parallel tool calls → 4 analysts → debate → trader → risk → critic (6 checks) → validation → audited report · 21 evidence records · 7 findings · 18 spans · every transition written to SQLite when a task store is configured
Capability surface        16 tools on 5 servers (market_data · quant incl. cross-sectional alphas · knowledge · portfolio · execution) · schemas derived from Python signatures · in-process or MCP over stdio from one definition
Governance              11-state machine · 5 roles · 6 policy rules (deny list → capabilities → read-only → argument guards → risk level → allow) · auto / queued / deny approvals · plans pinned to the task's symbol and date · call and dollar LLM budgets · TLS and dev-key guards on the API · a bounded task pool per process (503 + Retry-After when full) and multi-process serving over the task store
Knowledge (RAG)          11 runbooks and policies · 76 chunks · dependency-free hashed TF-IDF · served as DOCUMENT evidence and shown to the trader and PM
Quant research           9 alphas, time-series and cross-sectional (per-date IC, quantile spreads, breadth) · 4 execution algorithms + intraday simulator · square-root impact inside the backtester · 5 weighting schemes with Ledoit-Wolf covariance, cross-asset risk budgets and attribution · bootstrap, probabilistic and deflated Sharpe · a paired bootstrap across instruments · ALFRED vintages · SEC EDGAR point-in-time fundamentals and filing news
Evaluation              real prices · 60 instruments: 15 core (every rule choice) + 45 extended (no rule tuned on them) · design 2016–21 · holdout 2022–26 · reserve 2026-07 → 2026-09, spent: it and the extended universe were consulted for the v0.5.1 and v0.6 decisions, and v0.8 re-measured every period, so the next unseen data is the future · 26-trial registry (24 re-measured under the v0.8 engine) · alpha and cross-sectional analysts measured on the design period and kept off · impact sweep at $100k / $10M / $1B, equity-scaled · first LLM run: 5 stocks × Q1 2024, 271 Claude calls, $4 (pre-v0.8 engine, not re-derived) · EDGAR on/off, the carry rule, the track-record cut and the cross-sectional analyst re-checked on all 60 names × 4 periods (cluster-bootstrap intervals on the all-60 rows, instrument bootstrap on the core and extended rows); the v0.2 rules and the alpha analyst re-checked on the 15 core names × 4 periods (instrument-bootstrap intervals) · VaR coverage of the desk's own forecast · prompt hashes and provenance in every result · a calibration harness · the multi-year LLM run staged (not yet executed) with a dollar cap per stage
Out of sample           v0.8 (cash leg on, Sharpe on excess returns): 15-sleeve portfolio holdout Sharpe 0.80 vs 0.86 plain buy & hold vs 0.99 vol-targeted B&H (desk − B&H −0.06 [−0.41, +0.30] p 0.748; desk − vol-target −0.19 [−0.53, +0.16] p 0.297, block bootstrap over days), max drawdown 7.80% vs 20.43% vs 9.17% · extended 45 names: median Sharpe 0.25 vs 0.39 B&H (mean difference −0.07 [−0.12, −0.02] p 0.01, BH-significant, bootstrap over instruments) vs 0.27 vol-target (−0.03 [−0.09, +0.02] p 0.19, not BH-significant); mean max drawdown 15.46% vs 26.39% vs 19.79% · v0.5.1 FX carry rule: chosen on the core design period; on minus off positive on every slice, small, with intervals touching zero on most
Code                     ≈13.7k non-empty lines of Python in agentic_trader (57 files; 3.9k in the agentic layer, 2.0k research, 1.1k EDGAR / prompts / calibration) · ≈1.7k lines of C++17 incl. its tests · ≈10.9k lines of tests · MSVC /W4 and GCC -Wall -Wextra clean · CI on Linux, Windows, macOS, Python 3.10–3.14
The model writes the reasoning; the numbers, the limits and the audit come from deterministic code. That boundary is enforced, not described. Every tool call is policy-checked and leaves a digest before an agent sees the result; findings whose evidence ids do not resolve are dropped; the critic may only lower confidence; the narrative is audited afterwards and every untraceable figure or id is attached as a warning — the adversarial suite feeds a fabricated "350 bps / 88% / CALC-badbadba" narrative, an injected headline that tries to close the untrusted block, a rogue plan with an order and a shell command, and a model that returns a 5.0 weight, and checks that each is contained. The performance figures above are from the rule-based desk, re-measured in v0.8 with idle cash credited at the 3-month bill and Sharpe on excess returns (every number is copied from results/v08/tables.md). Out of sample it is below buy & hold on Sharpe: per instrument on the 15 names its rules were chosen on (core holdout median 0.30 vs 0.51; mean difference −0.10 [−0.21, −0.00] p 0.04, not BH-significant, bootstrap over instruments) and on the 45 names it was never tuned on, where the deficit clears the BH bar (0.25 vs 0.39; −0.07 [−0.12, −0.02] p 0.01), and as a 15-sleeve portfolio inside the noise (0.80 vs 0.86; −0.06 [−0.41, +0.30] p 0.748, block bootstrap over days). It takes about half of buy & hold's drawdown (core holdout 17.40% vs 31.64%; −14.24 points [−20.41, −8.70] p 0.00, BH-significant), which buy & hold scaled to the same volatility also achieves (18.98%; desk − vol-target −1.58 [−4.33, +1.14] p 0.27); on the core equities the desk's drawdown is not lower than that control's (+0.83 [−1.63, +3.21] p 0.50, not BH-significant). The v0.7 claim that the portfolio beat plain buy & hold (1.09 vs 1.06) is retracted; with the cash leg off the holdout order is the same (1.04 / 1.05 / 1.24). Giving its untuned fundamentals and news rules point-in-time filings adds exposure and drawdown on the core names for about no Sharpe (+0.01 [−0.03, +0.04] p 0.72 on the design period) and a small gain on the extended names (holdout +0.03 [+0.01, +0.06] p 0.00; all 60 with the cluster bootstrap +0.02 [−0.02, +0.05] p 0.39; the on/off tables carry no BH flag), and the data stays on. The alpha analyst (design −0.00 [−0.05, +0.05] p 0.90) and the cross-sectional analyst (−0.01 [−0.02, +0.00] p 0.36) measure as nothing on the design period and stay off. With market impact on, the desk keeps its Sharpe at $100k and $10M and loses 0.05 (design) / 0.03 (holdout) at $1B. The LLM desk has been measured once (v0.5.1: five stocks, one quarter, Claude Opus, anonymised prompts, $4): the same Sharpe as the rules, less than half the exposure, return and drawdown — produced under the pre-v0.8 engine and not re-derived; a single quarter shows what it does, not whether it has an edge; the multi-year run is staged, dollar-capped per stage, and has not been executed.

The architectural boundary

LLM (Claude)reasoning, debate, narrative, optional plans — never a metric, never an evidence id
C++ quant coreindicators, VaR/CVaR, backtests with stops and carry, Spearman, Almgren-Chriss — numpy twin
Toolsthe only way to reach data — catalogued, policy-gated, evidenced; in-process or MCP
Harnessthe control plane — an explicit state machine; agents never control the loop
Policy engineauthority: allow / deny / require approval, explained by the rule that fired
Evidence & auditsevery finding cites resolvable records; every reported number traces to a fact

Real prices, out of sample (v0.8: every number re-measured; cash leg on, Sharpe on excess returns)

Holdout 2022-01-03 → 2026-06-30, Yahoo Finance total-return prices, SEC EDGAR point-in-time fundamentals and filings, FRED point-in-time FX carry and 3-month bill, costs included, rules frozen before the run. Portfolio = 15 equal-capital sleeves. Every cell is copied from results/v08/tables.md (sections "portfolio: holdout", "cash leg on vs off: holdout", "portfolio Sharpe difference: holdout").

Portfolio (holdout)Sharpet(SR)ReturnMax DDExposureSharpe, cash leg offDesk − this, Sharpe [95% CI], p
AgenticTrader v0.80.801.7050.62%7.80%59.10%1.04—
Buy & hold0.861.8296.91%20.43%94.96%1.05−0.06 [−0.41, +0.30], 0.748
B&H vol-target (fair control)0.992.1061.48%9.17%72.12%1.24−0.19 [−0.53, +0.16], 0.297
SMA(20/50)0.641.3649.35%11.98%71.51%0.85—
MACD0.380.8035.29%16.02%65.35%0.54—

Portfolio intervals: paired block bootstrap over days (block 10, n 1167). With the cash leg off (the v0.7 convention) the order desk < buy & hold < vol-target is unchanged. Shifting the 5-bar rebalance phase (offsets 0–4) moves the desk's holdout Sharpe across 0.80 / 0.85 / 0.86 / 0.80 / 0.84 (spread 0.06) against a fixed 0.99 and 0.86: the cadence noise floor is as large as the differences quoted.

The 15 core instruments every rule choice was made on, median Sharpe and means over instruments, with the paired bootstrap of the desk minus each control (scheme=instruments, 2 groups; "BH" is the Benjamini–Hochberg flag on the unrounded p across the table). Sections "summary: core (15), design / holdout", "head to head: core (15)", "paired Sharpe ... core (15)", "paired MDD% ... core (15)".

Core universe, 15 namesDesign median SharpeHoldout median SharpeHoldout mean max DDHoldout mean exposureDesk beats it on Sharpe (holdout)Desk − this, holdout Sharpe [95% CI], p, BHDesk − this, holdout max DD (pts) [95% CI], p, BH
AgenticTrader v0.80.670.3017.40%60.51%———
Buy & hold0.730.5131.64%97.39%3 / 15−0.10 [−0.21, −0.00], 0.04, not significant−14.24 [−20.41, −8.70], 0.00, significant
B&H vol-target (fair control)0.690.5218.98%73.67%4 / 15−0.11 [−0.21, −0.00], 0.04, not significant−1.58 [−4.33, +1.14], 0.27, not significant

The 45 extended instruments no rule was tuned on (they were consulted for the v0.5.1 and v0.6 decisions; nothing remains unseen), same layout (scheme=instruments, 3 groups). Sections "summary: extended (45), design / holdout", "head to head: extended (45)", "paired Sharpe ... extended (45)", "paired MDD% ... extended (45)".

Extended universe, 45 namesDesign median SharpeHoldout median SharpeHoldout mean max DDHoldout mean exposureDesk beats it on Sharpe (holdout)Desk − this, holdout Sharpe [95% CI], p, BHDesk − this, holdout max DD (pts) [95% CI], p, BH
AgenticTrader v0.80.510.2515.46%64.73%———
Buy & hold0.550.3926.39%97.87%12 / 45−0.07 [−0.12, −0.02], 0.01, significant−10.93 [−13.41, −8.64], 0.00, significant
B&H vol-target (fair control)0.580.2719.79%81.32%16 / 45−0.03 [−0.09, +0.02], 0.19, not significant−4.33 [−6.10, −2.55], 0.00, significant

The cross-sectional analyst under the protocol, re-measured: per-instrument Sharpe with the analyst minus without (both with EDGAR), scheme=instruments; the on/off tables print p without a BH flag. Section "with the cross-sectional analyst (a) vs default (b)". Off by default stands.

Cross-sectional analystCore designCore holdoutExtended 45, holdoutExtended 45, reserve
Mean Sharpe difference [95% CI]−0.01 [−0.02, +0.00]0.00 [−0.01, +0.02]−0.00 [−0.01, +0.00]−0.02 [−0.06, +0.01]
p0.360.600.230.20
Better on5 / 159 / 1518 / 4514 / 45
Earlier tables (v0.6, v0.5.1 and v0.5, EDGAR on or off as labelled): holdout portfolio, extended universe, cross-sectional analyst, impact sweep, first LLM run, alpha analyst

Measured under the v0.7-and-earlier engine (constant weight between decisions, no cash leg, per-instrument impact at whole-book capital, static-table FX fallback); superseded by the v0.8 re-measurement — see v0.8. The tables stay as the historical record; where a v0.8 number contradicts a table's conclusion, the line under it says so.

Real prices, out of sample (v0.6 defaults: EDGAR on, cross-sectional analyst off)

Holdout 2022-01-03 → 2026-06-30, Yahoo Finance total-return prices, SEC EDGAR point-in-time fundamentals and filings, FRED point-in-time FX carry, costs included, rules frozen before the run. Portfolio = 15 equal-capital sleeves.

Portfolio (holdout)Sharpet(SR)ReturnMax DDExposure
AgenticTrader v0.6 defaults1.092.3136.2%7.8%59%
AgenticTrader v0.5.1 (EDGAR off)1.162.4632.8%7.0%55%
Buy & hold1.062.2486.6%20.8%98%
B&H vol-target (fair control)1.242.6346.3%9.8%74%

v0.8 contradicts this table's conclusion: re-measured with the cash leg the holdout portfolio is 0.80 (desk) vs 0.86 (buy & hold) vs 0.99 (vol-target), and 1.04 / 1.05 / 1.24 with it off; "beats plain buy & hold" is retracted (the v0.8 table above).

The 45 extended instruments, mean over instruments, with the v0.6 cross-instrument bootstrap of the desk's Sharpe minus buy & hold's (scheme=instruments, no BH flag was printed then).

Extended universe, 45 namesDesign mean SharpeHoldout mean SharpeHoldout mean max DDBeats B&H (holdout)Lower DD than B&HHoldout Sharpe − B&H, 95% CI
AgenticTrader v0.6 defaults0.520.4517.6%14 / 4542 / 45-0.04 [-0.10, +0.01]
Buy & hold0.560.5027.2%———
B&H vol-target (fair control)0.610.4721.1%———

v0.8: holdout median Sharpe 0.25 vs 0.39, desk − buy & hold −0.07 [−0.12, −0.02] p 0.01 and BH-significant — the "noise" reading of this table does not survive; the drawdown gap against the fair control does (−4.33 [−6.10, −2.55] p 0.00, BH-significant).

The cross-sectional analyst under the v0.6 measurement (per-instrument Sharpe with the analyst minus without, both with EDGAR).

Cross-sectional analystCore designCore holdoutExtended 45, holdoutExtended 45, reserve
Mean Sharpe difference [95% CI]-0.01 [-0.02, 0.00]0.00 [-0.02, +0.01]-0.01 [-0.01, 0.00]-0.03 [-0.07, 0.00]
Better on5 / 158 / 1515 / 4510 / 45

Real prices, out of sample (v0.5.1 rules, EDGAR off)

Holdout 2022-01-03 → 2026-06-30, Yahoo Finance total-return prices, FRED point-in-time FX carry, costs included, rules frozen before the run. Portfolio = 15 equal-capital sleeves.

Portfolio (holdout)Sharpet(SR)ReturnMax DDExposure
AgenticTrader v0.5.1 rules (current: + FX carry weight)1.162.4632.8%7.0%55%
AgenticTrader v0.3 rules1.142.4131.5%6.8%51%
AgenticTrader v0.2 rules1.212.5520.5%3.6%36%
Buy & hold1.062.2486.6%20.8%98%
B&H vol-target (fair control)1.242.6346.3%9.8%74%
SMA(20/50)0.841.7934.6%13.3%72%
MACD0.541.1420.2%16.3%66%

v0.8 contradicts this table's conclusion: with the cash leg the holdout portfolio is 0.80 (desk) vs 0.86 (buy & hold) vs 0.99 (vol-target); the desk does not beat plain buy & hold on Sharpe under either convention.

v0.5: the 45 extended instruments (sector equities, rates / credit / commodity ETFs, FX crosses), same frozen rules, mean over instruments (they were later consulted for the v0.5.1 and v0.6 decisions).

Extended universe, 45 namesDesign mean SharpeHoldout mean SharpeHoldout mean max DDBeats B&H (holdout)Lower DD than B&H
AgenticTrader v0.5.1 rules0.510.4217.7%15 / 4540 / 45
AgenticTrader v0.3 rules0.490.3717.7%14 / 4540 / 45
Buy & hold0.560.5027.2%——
B&H vol-target (fair control)0.610.4721.1%——
Market impact, core universe, design periodSharpe, impact off$100k$10M$1BImpact paid at $1B
AgenticTrader (≈107 trades, v0.5.1 rules)0.700.700.690.607.7%
B&H vol-target (≈1,100 trades)0.670.670.670.625.7%
Buy & hold0.620.620.620.621.0%
MACD0.420.410.35−0.2475.4%

v0.8 re-measured the sweep with equity-scaled impact: the desk 0.66 → 0.66 → 0.66 → 0.61 at $1B on the design period (4.24% of equity paid), holdout 0.34 → 0.31 (2.53%); the vol-targeted control 0.64 → 0.57; MACD 0.40 → −0.18 (64.71% paid). The magnitudes here are the v0.5 record.

v0.5.1: the first LLM measurement — the same desk with Claude Opus (medium effort, one debate round) in every reasoning role, anonymised prompts, Q1 2024, five stocks, a decision every 10 bars, against the rule-based desk on identical bars. 271 calls, 0 refusals, 0 fallbacks, $4.12. Produced under the pre-v0.8 engine and not re-derived under v0.8; still the only LLM measurement.

Q1 2024, mean over AAPL · NVDA · MSFT · META · GOOGLSharpeReturnMax DDExposureTrades
LLM desk (Claude Opus)2.196.9%2.2%23%2.4
Rule-based desk, same cadence2.1915.5%5.6%57%2.8
Buy & hold2.2728.6%9.2%100%1.0
B&H vol-target2.3313.3%6.6%62%54.8
Design period 2016–21, agent mean over 15 instrumentsMean SharpeMedian SharpeBeats B&HBeats vol-target B&H
Current default analysts0.650.5510 / 156 / 15
+ alpha analyst (v0.4.0)0.600.609 / 155 / 15
+ alpha analyst (significance-gated, window fixed)0.650.628 / 156 / 15
alpha analyst replaces technical0.570.595 / 155 / 15

v0.8, alpha analyst with the corrected gate minus default, design core: −0.00 [−0.05, +0.05] p 0.90 — the conclusion (off by default) stands. The rows here are the v0.4 and v0.5.0 record: "+ alpha analyst (v0.4.0)" is one of the two historical trials the current engine cannot re-run (registry: 0.60 recorded); the significance-gated, window-fixed row is the v0.5 trial the registry re-measured under v0.8 at 0.66 (0.65 recorded); "alpha analyst replaces technical" is not a registered trial.

What's inside

Domain model

Frozen dataclasses for the whole vocabulary — Task, Plan, PlanStep, ToolDescriptor, ToolRequest/Result, Evidence (6 types), Finding, PolicyDecision, roles, capabilities and the 11-state task machine with its legal transitions. Nothing here imports an LLM SDK, MCP or a web framework.

Tool servers & executor

16 tools on 5 servers with schemas derived from Python signatures and annotations for read-only, risk level, capabilities and evidence type. The executor checks policy, coerces arguments, retries transient errors, times out, traces, and writes an evidence record for every call — including failures.

MCP server & client

The same catalogue as a real MCP server over stdio (official SDK 2.x), callable from any MCP client. The client side turns a remote server's tools into a local registry, so policy, evidence and tracing apply to remote tools unchanged — tested with a real subprocess round trip.

Policy engine & approvals

Ordered rules — deny list, required capabilities, read-only, argument guards (symbol universe, future dates, weight caps, lookback bounds), risk level — returning ALLOW / DENY / REQUIRE_APPROVAL with the rule named. Roles viewer, analyst, trader, risk, admin. Gateways: auto (dev), queued (a person decides via the API), deny.

Planner

A canonical plan per asset class, or a model-proposed one. The validator strips unknown tools, stages and arguments, pins every tool call to the task's symbol and date, refuses state-changing tools in plans, repairs stage order, and appends critic, validation and finalisation whenever a plan omits them. Unusable output falls back to the canonical plan.

Agent harness

CREATED → PLANNING → VALIDATING_PLAN → EXECUTING ⇄ AWAITING_APPROVAL → CRITIQUING → VALIDATING_EVIDENCE → FINALISING → COMPLETED. Parallel tool batches, pause and resume on approvals, cooperative cancellation, per-run tracer, and governance steps that a hand-built plan cannot skip.

The desk

Analysts (technical, fundamentals or FX macro, news, sentiment, optional alpha and cross-sectional alpha) that abstain without data — fundamentals and news read SEC EDGAR filings point in time; a bull/bear debate with a facilitator; a trader with strategic weight plus tilt and ATR stops; aggressive / neutral / conservative risk views; a portfolio manager with limits that run after any model output and a no-trade band.

Critic

Deterministic checks first: cited evidence must resolve; a model view must not diverge from its own rules by more than 0.6; strong contradictions need a balanced verdict; limits, stop sides and direction-vs-verdict must hold; single-evidence findings are capped. A model critique may then run and can only lower confidence.

Reporter with audits

Structured facts go to the model; the narrative comes back. A number audit checks every figure against the facts (rounding and percentage forms allowed, counts included) and an evidence-id audit checks every id; discrepancies are attached as warnings, not accepted.

RAG knowledge base

Eleven desk documents — risk limits, position sizing, stops, FX carry, execution, point-in-time data, evaluation protocol, incident runbook, alpha research, portfolio construction, agentic governance — chunked by heading, embedded with hashed TF-IDF, retrieved as DOCUMENT evidence and shown to the trader and PM.

Alpha library, time-series and cross-sectional

12-1 momentum, vol-adjusted momentum, short-term reversal, 52-week high, Donchian breakout, MACD, RSI, low-vol and FX carry — all in [-1, 1], point in time by construction. Per name: IC with t-stat, decay, hit rate, tercile spread, turnover. Across a universe (v0.5): daily z-scores or ranks within asset class, per-date IC with an overlap-aware t-statistic, top-minus-bottom quantile spreads, breadth.

Execution, in the simulator and in the backtest

TWAP, VWAP, participation-of-volume and Almgren-Chriss schedules; a simulator that builds intraday bars from the daily bar, charges half the spread and square-root impact, and reports implementation shortfall. v0.5 puts the same square-root model inside the backtester: a trade of |dw| costs |dw|^1.5 · Kt of equity, scaled by account size, charged to the desk and every baseline alike.

Portfolio construction with risk budgets

EWMA and Ledoit-Wolf shrunk covariance; equal, inverse-vol, risk parity, minimum variance and mean-variance weights with per-sleeve caps and a portfolio vol target; marginal and component risk, diversification ratio. v0.5 adds cross-asset risk budgets: allocate within each class, then risk parity with the budgets across classes from the full covariance, with budget vs realised share reported.

Operations

A SQLite task store that writes every run at each state transition and serves old records after a restart (in-flight runs are failed once their heartbeat lease expires, never silently resumed); a dollar LLM budget next to the call budget; TLS on the API and a refusal to bind a public interface with the shipped development keys; ALFRED vintages so revised macro series enter the backtest as first published.

Backtest statistics

Block-bootstrap Sharpe confidence intervals, the probabilistic Sharpe ratio, the deflated Sharpe ratio for the number of variants tried, and the minimum track record length — applied to the desk's own 26-trial registry of variants judged on the design period.

HTTP API & observability

FastAPI gateway with API-key roles: 202-accepted tasks run in the background; reports as JSON or markdown; traces; evidence; cancel; an approvals queue for the risk role; the tool catalogue; health; Prometheus text metrics. Spans with parent ids and JSON-lines logs.

Adversarial suite and fuzzing

Injected headlines that try to close the untrusted block, rogue plans with orders and shell commands, unparsable planner output, a critic that tries to raise confidence, fabricated numbers and ids, unresolvable evidence, hostile arguments, role escalation, a plan without governance — each mapped to a control in the threat model. Plus hypothesis fuzzing of the Python ↔ C++ boundary on NaN, ±inf, empty and huge inputs, which found and fixed five backend divergences on its first run.

Offline by default

No API key, no network: deterministic rule-based agents on synthetic data run the whole harness, the API, the MCP server, the tests and the backtests out of the box. --data yahoo --llm anthropic switches to real data and Claude, with a hard call budget and anonymised prompts available.

What a task looks like

$ agentic-trader task EURUSD --date 2024-03-01 --position 0.2

AgenticTrader | task EURUSD as of 2024-03-01 role=trader approval=auto | llm=offline data=synthetic quant=cpp
state: COMPLETED  plan: canonical  steps: 12  evidence: 21  findings: 7

# EURUSD decision — 2024-03-01

## Executive summary
EUR/USD: HOLD with a target weight of 0.00 (confidence 0.02). The debate verdict was balanced
with a score of +0.02; 3 analysts leaned bullish and 1 bearish. The trader proposed 0.00; the
risk team's views were aggressive 0.00, neutral 0.00, conservative 0.00. The critic's checks all passed.

## Findings
- **technical** (0.53): Technical picture is bullish (score +0.37). [CALC-896da157, DEC-98dabaa0]
- **macro** (0.52): Macro backdrop score -0.42 (carry-led). [DATA-7c6d1339, CALC-31fb60a5, DEC-713fd845]
...
## Critic
- PASS evidence_resolves: 7 findings, all evidence resolves
- PASS firm_limits: size, shorting and VaR within limits
...
## Policy passages applied
- FX carry and macro methodology / Introduction (fx_carry_methodology#0)
## Evidence
- DATA-... DATA market_data.history: market_data.history(symbol=EURUSD, as_of=2024-03-01, lookback_days=400) -> 6 fields
- DOC-...  DOCUMENT knowledge.search: knowledge.search(query=..., k=3) -> 3 items
- CALC-... CALCULATION quant.alpha: quant.alpha(symbol=EURUSD, as_of=2024-03-01, horizon=10) -> 4 fields

trace: {'spans': 18, 'errors': 0, 'ms_by_kind': {'plan': 0.1, 'prepare': 8.7, 'tool': 12.4, 'agent': 4.9, ...}}

The same tools over MCP, and the API

$ agentic-trader mcp --approval deny      # stdio server: 16 tools with read-only / risk / capability annotations; locked down (tools needing approval refused); --role picks the role every call is evaluated for
$ agentic-trader serve --task-db results/tasks.sqlite      # http://127.0.0.1:8000/docs, records survive restarts
$ curl -s -X POST http://127.0.0.1:8000/tasks -H "X-API-Key: dev-trader-key" \
       -H "Content-Type: application/json" -d '{"symbol": "AAPL", "as_of": "2024-03-01", "current_weight": 0.1}'
{"task_id": "TASK-67732293", "state": "EXECUTING"}
$ curl -s http://127.0.0.1:8000/tasks/TASK-67732293/report?format=markdown -H "X-API-Key: dev-viewer-key"
$ curl -s http://127.0.0.1:8000/approvals -H "X-API-Key: dev-risk-key"      # queued orders awaiting a person

Part of a wider portfolio

AgenticAICashEquities

The sibling agentic platform for cash-equity execution investigation: MCP servers, a policy-gated agent harness, deterministic TCA analytics, a critic and audited, evidence-linked reports. GitHub →

intraday-alpha-platform

The polyglot research-to-production trading platform: market data → order books → feature factory → alphas → validation → ML → portfolio → fail-closed risk → execution/SOR → TCA, golden-tested across Python, C++, Rust and Java. GitHub →

quant-portfolio

The end-to-end quantitative finance portfolio: project areas built in Python with C++ and Rust performance twins, golden-vector cross-language validation, a learning guide and a cookbook. GitHub →

quantfinlib

A zero-dependency quantitative finance platform for the JVM — research, validation, execution and connectivity, with CI on every push. GitHub →

Quick start

git clone https://github.com/AshJha0/agentic-trader && cd agentic-trader
python -m venv .venv && source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e ".[all]"

# one task through the harness — offline, rule-based agents, ~30 ms
agentic-trader task EURUSD --date 2024-03-01 --position 0.2

# the catalogue, the API and the MCP server
agentic-trader tools
agentic-trader serve                      # docs at http://127.0.0.1:8000/docs
agentic-trader mcp --approval deny        # the MCP stdio server, locked down; --role viewer|analyst|trader|risk|admin

# research: alphas (per name and cross-sectional), execution, portfolio construction, statistics
agentic-trader alpha USDJPY --start 2021-01-04 --end 2024-03-28
agentic-trader xalpha AAPL,MSFT,NVDA,JPM,XOM --start 2021-01-04 --end 2024-03-28
agentic-trader execute AAPL --date 2024-03-01 --target 0.6 --current 0.1 --capital 5000000
agentic-trader portfolio AAPL,JPM,XOM,EURUSD,USDJPY --start 2023-01-02 --end 2023-12-29 --weighting risk_parity --class-budgets equity=0.6,fx=0.4
agentic-trader backtest NVDA --start 2024-01-02 --end 2024-03-28 --impact 1.0 --capital 1e9
agentic-trader stats returns.csv --trials 26

# the evaluation on real prices: 60 instruments, design / holdout / Q1 2024 / reserve
agentic-trader evaluate --data yahoo --universe all --periods design,holdout,q1_2024,reserve

# the suites (C++ core optional: scripts/build_cpp.sh or scripts\build_cpp.ps1)
pytest && ctest --test-dir build -C Release

# live: Claude + real prices (export ANTHROPIC_API_KEY=... or `ant auth login`)
agentic-trader task MSFT --llm anthropic --data yahoo --max-llm-calls 50 --llm-planner