| name | midas-core |
|---|---|
| tagline_fr | Un moteur Brain/Hands open source pour agents IA en paper trading — la sécurité vit dans le broker, pas dans le prompt. |
| tagline_en | An open Brain/Hands engine for paper-trading AI agents — safety enforced by the broker, not the prompt. |
| facts_fr | Licence MIT, Python 3.12+, 15 codes de garde-fou du broker, desk de démo exécutable, pip install midas-core. |
| facts_en | MIT license, Python 3.12+, 15 broker safety-rail reason codes, a runnable demo desk, pip install midas-core. |
An open, multi-agent paper-trading fund-manager framework built on a Brain/Hands split: agents author decisions; a broker enforces the safety rails and executes them. This repo is the reusable core — the engine, the config-driven roster/allocator model, a runnable demo desk, and the deterministic Hands pipeline. Bring your own agents.
The whole thesis in one command. Two orders, same agent, same instant: the broker fills the
3-share clip and refuses the 10-share one against a $5,000 notional cap it enforces itself.
Reproduce it with the quickstart below — nothing above is mocked.
Paper-trading by default. This is a framework, not a service: it never executes against your broker keys, never pools funds, never gives per-user advice. See DISCLAIMER.md.
- Safety lives in the broker, not the prompt. The persona is aspirational; the broker is
enforcing. Every order is checked at fill time against a fixed set of 15 rejection/cancel
reason codes —
MAX_ORDER_NOTIONAL,MAX_ORDERS_PER_DAY,TICKER_NOT_IN_UNIVERSE,INSUFFICIENT_CASH,DAILY_DRAWDOWN_HALT, … — so a coaxed or confused agent still can't slip an oversized or out-of-universe trade through. - Reproducible by construction. Dependencies are a fully-pinned lockfile; prices and index
universes are committed to git; a trading session makes no outbound HTTP calls. Every fill is
stamped with
executed_sha, the git HEAD it executed against —git checkout <sha>re-derives the exact order and price store the broker saw. - Proven on a live desk. A 10-agent desk has run this engine every weekday since 2026-04-17, narrated publicly at midas.revah.paris. This repo is a one-way code mirror of that desk's engine — the same code, without the private data ledger.
- Conditional orders, not just market orders. Agents can defer a trade until a price level is crossed. Expiry is mandatory; a separate watcher process fires the order when the condition is met and applies the same order-level rails as a market fill.
The Brain (agents) only ever writes to disk; it holds no credentials. The Hands (the paper broker, a separate watcher process) reads that outbox, enforces the rails, and executes. The boundary is a directory of append-only JSONL files, so a real-money broker is a drop-in swap for the paper one behind the same contract.
flowchart LR
A["Agents (Brain)"] -->|"author orders"| O["outbox/*.jsonl"]
O --> B{"paper broker: safety rails"}
B -->|"filled"| I["inbox/*.jsonl"]
B -->|"rejected + reason code"| I
I -->|"apply_trade"| P["portfolios/*.json"]
A -.->|"conditional order"| PE["pending/order_id.json"]
PE --> W["check_triggers watcher"]
W -.->|"price level crossed"| B
This drives the full loop end-to-end: bootstrap prices, hand-author two orders (one clears, one is deliberately oversized to trip a rail), run the broker, and inspect the fills.
python -m venv .venv && source .venv/bin/activate
pip install midas-core
# Materialise the packaged demo desk (roster.yaml, .claude/agents/demo-*.md,
# data/universes/*.json) into a directory you name — no git clone required.
midas init-demo ./my-desk
export MIDAS_DATA_DIR=$PWD/my-desk
# One-time: open a USD 10,000 portfolio for demo-momentum.
python -c "
from engine.config import get_config
from engine.portfolio import PortfolioManager
pm = PortfolioManager(base_dir=get_config().portfolios_dir)
pm.initialize('demo-momentum', initial_capital=10000, currency='USD')
"
# Bootstrap the price store from yfinance (the one networked step; the live desk
# populates this store from a cron so trading sessions stay HTTP-free).
midas fetch-ohlcv --symbols SPY,QQQ,IWM,VTV,SCHD,BRK-B,URTH --history-days 90Author two orders — append-only JSONL, one per line — to
$MIDAS_DATA_DIR/data/orders/outbox/<TODAY>.jsonl (<TODAY> = today's YYYY-MM-DD). Every
field is required, including a non-empty reasoning (no silent trades); shares must be
strictly positive (Midas is long-only):
{"order_id": "ord_demo_001", "ts": "2026-04-17T20:00:00Z", "agent_id": "demo-momentum", "action": "BUY", "ticker": "SPY", "shares": 3, "reasoning": "Trend intact above the 50-day; adding core exposure.", "currency": "USD"}
{"order_id": "ord_demo_002", "ts": "2026-04-17T20:00:00Z", "agent_id": "demo-momentum", "action": "BUY", "ticker": "SPY", "shares": 10, "reasoning": "Deliberately oversized clip to demonstrate the notional rail.", "currency": "USD"}demo-momentum's max_order_notional is 5000. With SPY near $740 the first order ($2,200)
clears; the second ($7,400) breaches the cap. Run the broker:
midas fill-day
# fill-day: 1 filled, 1 rejected out of 2The inbox is the durable Hands-side record of both outcomes:
cat $MIDAS_DATA_DIR/data/orders/inbox/<TODAY>.jsonl{"order_id": "ord_demo_001", "status": "filled", "fill_price": 738.18, "notional_base": 2214.54, "fees": 1.25, "reason": null}
{"order_id": "ord_demo_002", "status": "rejected", "fill_price": null, "notional_base": null, "fees": null, "reason": "MAX_ORDER_NOTIONAL"}The filled order mutated data/portfolios/demo-momentum/portfolio.json (cash debited, a SPY
position opened); the rejected one changed nothing but its reason. Exact prices depend on the day
you fetch — the shape (one fill, one rejection, a debited portfolio) is the point.
The full walkthrough — the portfolio JSON, the executed_sha provenance stamp, and the roster
schema — is in ./examples/demo-desk/README.md.
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt # pinned lockfile (incl. pytest + hypothesis)
pip install -e . # the midas-core package + the `midas` CLI
# Point the engine at a working copy of the demo desk.
cp -R examples/demo-desk /tmp/my-desk
export MIDAS_DATA_DIR=/tmp/my-desk
pytest -qThe whole cast is config. Copy the demo desk and edit two things:
roster.yaml— declare your traders, anarrator, and an optionalallocator, each with its universe, starting capital, and broker-enforcedsafetyrails (max_order_notional,max_orders_per_day,daily_drawdown_halt_pct,allowed_universe)..claude/agents/*.md— the persona behind each id: its voice and its strategy.
Nothing else is hardcoded. The full roster schema (every field and its default) is documented in
./examples/demo-desk/README.md.
| To run… | Requirements |
|---|---|
| Deterministic pipeline — fills, baselines, backtests | Python 3.12+ only. No API keys, no accounts. |
| LLM trading sessions — personas, journals, narration | Runs under Claude Code (scripts/daily_session.py). |
The deterministic pipeline is headless and fully tested; you can drive a desk end-to-end with no model at all by hand-authoring orders, exactly as the quickstart does.
- Paper-trading by default. Fills are simulated against a committed price store. No output is a track record, evidence of an edge, or investment advice.
- Framework, not a service. midas-core never executes against your broker keys, never holds credentials, never pools or manages anyone's funds, and gives no per-user advice. A real-money broker would be your code, swapped in behind the same outbox/inbox contract.
- Full terms: DISCLAIMER.md.
This repository is a one-way code mirror, synced from the operator's private live repo (the
source of truth) by a manifest tool. The live desk's data ledger — its real portfolios, journals,
and daily narrative — stays private and is not in this repo; the bundled examples/demo-desk
is a synthetic fixture. Because of the mirror direction, code PRs against synced trees can't be
merged — please open an issue instead. See CONTRIBUTING.md.
engine/— types, market data, bt adapter, paper broker, config (roster.yamlloader), universes.scripts/— session orchestration (daily_session.py), the conditional-order watcher (check_triggers.py), backtest runners, universe refresh.examples/demo-desk/— the forkable reference desk.data/{strategies,universes}/— generic strategy specs + index constituents.
MIT.
