Skip to main content

Midas — open multi-agent fund-manager engine (Brain/Hands, honest controls)

Project description


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."

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.

tests PyPI License: MIT Python 3.12+

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.

Why this exists

  • 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.

Architecture — Brain / Hands

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

Quickstart — reach a real fill

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 90

Author 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 2

The 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.

From source (contributors)

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 -q

Run your own desk

The whole cast is config. Copy the demo desk and edit two things:

  1. roster.yaml — declare your traders, a narrator, and an optional allocator, each with its universe, starting capital, and broker-enforced safety rails (max_order_notional, max_orders_per_day, daily_drawdown_halt_pct, allowed_universe).
  2. .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.

What you need

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.

Honest framing

  • 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.

Relationship to the live desk

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.

Layout

  • engine/ — types, market data, bt adapter, paper broker, config (roster.yaml loader), 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.

License

MIT.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

midas_core-0.1.0.tar.gz (291.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

midas_core-0.1.0-py3-none-any.whl (181.0 kB view details)

Uploaded Python 3

File details

Details for the file midas_core-0.1.0.tar.gz.

File metadata

  • Download URL: midas_core-0.1.0.tar.gz
  • Upload date:
  • Size: 291.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for midas_core-0.1.0.tar.gz
Algorithm Hash digest
SHA256 1d2901367bd034d7b9307da4d6957b297d95ef50ab38bd835be66868eea36ee7
MD5 4c386f6da7ee3f68e97c2db4c017139a
BLAKE2b-256 6b98fee43642ac979448677ba9de01be4a5fd2e7432ce0e13c2afa6832e4b8bd

See more details on using hashes here.

Provenance

The following attestation bundles were made for midas_core-0.1.0.tar.gz:

Publisher: publish.yml on w2ur/midas-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file midas_core-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: midas_core-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 181.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for midas_core-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1aac4ea0e8044c5e30f52be0a70d38892d9f9774a7481666b8d46c7beff2c129
MD5 b9cb86e9b65e5cd8ed6b0b49812fed03
BLAKE2b-256 16a13de64c1e9d423847cdc12b1825689b2253661071567b8ac9c39dd81d4f77

See more details on using hashes here.

Provenance

The following attestation bundles were made for midas_core-0.1.0-py3-none-any.whl:

Publisher: publish.yml on w2ur/midas-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page