pretium
A market simulator you can run a strategy against. Rust core, Python API.
Give it a seed and a set of companies and it runs a market forward: prices, a limit order book, fills, and an economy that advances itself daily. Your orders match against real depth, so trading moves the price the way it would anywhere else.
It exists because historical data can't answer two questions. What would have happened if I'd traded differently, and what actually caused this price move.
Install
pip install pretium
Wheels are prebuilt for Linux, macOS and Windows on CPython 3.11+, and the core package has no dependencies.
The engine is also published as a Rust crate, so you can use it without Python at all:
cargo add pretium
Both are built from the same source at the same version, and run the same market: https://crates.io/crates/pretium.
The API may still move before 1.0. What will not move is a published result: anything that changes the simulated trajectory arrives as a new model preset rather than an edit to an existing one, so a run you cited last month reproduces this month.
In thirty seconds
import pretium as pt
universe = pt.Universe.random(40, seed=111)
spec = pt.StrategySpec.momentum(lookback_days=1.0, top_k=5)
scores = pt.evaluate({"mine": spec}, seed=7, universe=universe, days=10)
scores["mine"].return_pct # what it made
scores["mine"].impact_bps # what its own footprint cost
scores["mine"].strategy_fingerprint # sha256, cite this
That's one market draw, which tells you as much about the seed as about the
strategy. pt.rank runs many seeds and compares them with a paired sign
test.
What makes it different
Determinism that's checked. The crate ships its own exp, log, sin
and cos instead of calling the platform libm. Every release builds five
targets -- linux-x86_64, linux-aarch64, macos-arm64, macos-x86_64 and
windows-x86_64 -- runs one fixed simulation inside each, and compares
digests. A disagreement fails the release.
The WebAssembly build is checked by hand rather than by that gate, because it
needs a toolchain CI does not carry: on 2026-08-24 the native and
wasm32-unknown-unknown builds hashed the same fixed simulation -- twelve
instruments, five days, pt-v3 -- to 2b2f3141..., and
tests/test_wasm_parity.py pins the Python half of that pair so the two
cannot drift apart unnoticed.
Ground truth you can read. The simulator computed every price, so it can tell you why. One row per instrument per tick, with nine factor contributions that sum to the move and a residual around 1e-16. No historical dataset carries those labels. You can see that a stock fell, never that 60% of the fall was order-flow pressure.
Counterfactuals you can run. The same seed runs with and without your orders, so every fill is priced against the market where you never traded. That's the number TCA vendors approximate.
Results someone else can check. A StrategySpec is a declarative,
hashable document rather than an arbitrary callable. A RunManifest carries
the seed, universe, macro conditions, scenario, model and strategy together
with the expected digest. reproduce() refuses on a mismatch and names the
culprit, because a manifest that quietly reproduced a different market would
be worse than no manifest.
Driving it from an agent
pip install "pretium[mcp]"
claude mcp add pretium -- pretium-mcp
Eleven read-only tools over the simulator, so a coding agent can ask whether a momentum strategy beats buy-and-hold here, and whether the difference is real. Strategies, universes and scenarios are composed as data. There's no path from a tool argument to code execution.
Every result carries computed caveats and full provenance. A model
summarising a result has the tool output and nothing else, and will otherwise
report return_pct: 88.7 as "the strategy made 88.7%".
The MCP server has the
tool list and the client configuration.
What it's bad at
Good results here don't predict real returns. The price process comes from a known model, so a strategy that fits that model's structure will look excellent and teach you nothing. A strategy that fails here is more informative, because it broke against a live order book under honest impact costs.
Realism is a stated envelope, not a score. pt.facts.measure() reports
fourteen statistics against real-market bands. At 252 days the shipped pt-v12
preset holds all fourteen in band on thirty calibration seeds, all
fourteen again at 504 days against bands re-derived at that window, and all
fourteen again on a 60-name universe it never saw. On thirty seeds it never
used it holds thirteen, the single miss being corr_persistence_acf1. Read
that as fourteen in-band verdicts rather than fourteen independent
validations: five of the fourteen were live calibration targets, the bands
were used both to tune against and to grade against, and "held out" means
unseen simulation seeds and another roster from the same generator rather
than withheld market data.
That is a market with the right volatility, the right tails, the right
co-movement, industries that co-move more than strangers, correlation that
stays elevated after a panic, volume that behaves, and volatility episodes it
produces itself.
pt-v12 became the default on 2026-08-26, an era boundary: every trajectory
that came from the default changed. Runs recorded before it are not
comparable to runs after it unless they name their preset, and every earlier
preset from pt-v1 onward stays selectable and reproduces bit for bit.
Checked rather than asserted: pt-v1, pt-v2 and pt-v3 give identical
market digests under 0.1.4 and 0.2.0. A fully specified run is still
(package version, model, universe fingerprint, seed), since the preset pins
the coefficients and the package version pins the implementation.
At 504 days pt-v12 holds all fourteen, which is the first two-year clean sheet this project has measured -- pt-v3 held seven there and pt-v10 held thirteen, missing volume-change autocorrelation. Read the headroom rather than the count: annualised volatility reads 33.89 against a band ending at 34.0, so that row is genuine but thin, and the certified horizon stays 252 days because that is where the certification is measured.
Beyond two years the model has now been measured rather than assumed. At 2520 days it holds ten of the fourteen against the (horizon-mismatched) two-year bands, and nothing runs away or drifts: measured year by year over ten years, annualised volatility reads 31.5, 35.6, 30.2, 33.5, 33.0, 33.1, 31.3, 32.4, 32.4, 31.6 percent -- flat, with the year-to-year variation a real market has.
Five gaps are measured and named rather than assumed. The certified
horizon is 252 days; two and five-year panels are measured but not
certified. Volatility memory decays exponentially where real markets decay
hyperbolically. Scenario response has the right size, measured as a
regression gain, but too much noise around it for one run to size a scenario
from -- the driven-window noise ratio is 1.57x real. The endogenous MACRO
economy cannot reach its own crisis regimes, so an inflation regime or a
policy crisis has to be driven through a scenario; a volatility crisis does
not: measured on pt-v10, the preset's own VIX crossed its crisis threshold
on 10.2% of days against a real 12.5%, and that figure has not been
re-measured on pt-v12. And certification was measured on a sector-balanced
roster, which no real index is: re-measured on pt-v12, an S&P-like or
technology-heavy roster holds all fourteen at one year, so the envelope
transfers at the certified horizon, and the cost of concentration shows up
in the second year instead.
The realism envelope
states each gap and what it forbids. pt.envelope.check() refuses to certify
a question that falls outside one.
Single venue, no latency, no strategic counterparties. Orders arrive instantly, there's one book per name, and you trade against a market maker and aggregate flow rather than agents that adapt to you.
Worked examples
Eight notebooks and two scripts in examples/, numbered in
reading order and executed as part of the test suite:
| what it covers | |
|---|---|
00-a-year-in-one-market |
Start here: one company, one year, two crises, one chart |
01-first-simulation |
Universe, engine, order book, determinism |
02-evaluating-a-strategy |
Specs, baselines, ranking across seeds |
03-why-did-the-price-move |
The nine factors that sum to every move |
04-how-realistic-is-this |
The realism panel and the gaps |
05-training-an-agent |
The Gymnasium environment, and what size costs |
06-execution-and-impact |
TCA and the counterfactual run |
07-research-workflow.py |
A whole study in one file: sweep, evaluation, TCA and replay |
08-claude-agent.py |
An LLM agent trading the market through the harness |
09-a-pandemic-shaped-market |
A real 2020-21 macro path, and which fields actually transmit |
The two scripts run from the command line rather than a notebook. The whole study takes about five seconds:
python examples/07-research-workflow.py
Documentation
Full docs: simoncoombes.github.io/pretium
Getting started and core concepts. Agents, evaluation and the RL environment. Scenarios and macro paths, strategy specs, model presets, checkpointing and forking, sharing a run, Arrow output and streaming sweeps, SEC EDGAR loading, transaction cost analysis, the MCP server, running in the browser, the realism envelope and metrics, and the conventions worth reading before you hit them.
Contributing
See CONTRIBUTING.md, and RELEASING.md for how a version reaches PyPI and crates.io. One rule shapes the rest: a change to the simulated trajectory is a breaking change, whatever its size. A market that runs differently from the same seed invalidates every published result that cited it.
Citing this
See CITATION.cff, or cite a specific result by its manifest.
A citation identifies the software; it does not identify a run. A
RunManifest does: it carries the package version and preset it was written
by, the seed, the universe fingerprint, the macro conditions, the scenario
and the strategy fingerprint.
Licence
MIT OR Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE.
Metadata
Release files for pretium 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pretium-0.3.0.tar.gz | 512.3 kB | Details |
Built distributions (wheels)
| File | Reset | |||
|---|---|---|---|---|
| pretium-0.3.0-cp311-abi3-win_amd64.whl | CPython 3.11 | abi3 | Windows x86-64 | Details |
| pretium-0.3.0-cp311-abi3-manylinux_2_34_x86_64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ x86-64 | Details |
| pretium-0.3.0-cp311-abi3-manylinux_2_34_aarch64.whl | CPython 3.11 | abi3 | Linux glibc 2.34+ ARM64 | Details |
| pretium-0.3.0-cp311-abi3-macosx_11_0_arm64.whl | CPython 3.11 | abi3 | macOS 11.0+ ARM64 | Details |
| pretium-0.3.0-cp311-abi3-macosx_10_12_x86_64.whl | CPython 3.11 | abi3 | macOS 10.12+ x86-64 | Details |
Total release size: 4.4 MB
Release files / pretium-0.3.0.tar.gz
| Download URL | pretium-0.3.0.tar.gz |
|---|---|
| Size | 512.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
649233e98f10aa546f8a4bf88d23ad5398f4f237231769b99f19763cba2e8efd
|
|
BLAKE2b-256 checksum How to use checksums |
b809481eab37b50d750f1d08fc9b00e3690b18d36a1760a6bb95e0fe28115813
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / pretium-0.3.0-cp311-abi3-win_amd64.whl
| Download URL | pretium-0.3.0-cp311-abi3-win_amd64.whl |
|---|---|
| Size | 719.7 kB |
| Tags | CPython 3.11 Windows x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
037adc5e03f0ddfb353dad6f9dce2387e9f3e9dafe043923cc1ff8aa69255bd8
|
|
BLAKE2b-256 checksum How to use checksums |
4b8ab1c19a1467af906541a5d1cf3a3c42f72ba6a38fafd61e1e2c2cbbded130
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / pretium-0.3.0-cp311-abi3-manylinux_2_34_x86_64.whl
| Download URL | pretium-0.3.0-cp311-abi3-manylinux_2_34_x86_64.whl |
|---|---|
| Size | 821.4 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ x86-64 abi3 |
|
SHA-256 checksum How to use checksums |
8084d62f4e99b36adf4c95aaa3334737d5652d3272e0f527e04bab29928da15f
|
|
BLAKE2b-256 checksum How to use checksums |
6084b5047202c73674e704f78cc82d5aa9108ed37ac0a7d58f8b424f0d6a60ae
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / pretium-0.3.0-cp311-abi3-manylinux_2_34_aarch64.whl
| Download URL | pretium-0.3.0-cp311-abi3-manylinux_2_34_aarch64.whl |
|---|---|
| Size | 804.9 kB |
| Tags | CPython 3.11 Linux glibc 2.34+ ARM64 abi3 |
|
SHA-256 checksum How to use checksums |
f5092cb97ac2077eed2482aa6b4a1a3eaedbc776775778c721f5c381dcda1cee
|
|
BLAKE2b-256 checksum How to use checksums |
2bcf5353c15ddac4eef216973da303d98ee5f1f0b910bef0f627005cd5376d6b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / pretium-0.3.0-cp311-abi3-macosx_11_0_arm64.whl
| Download URL | pretium-0.3.0-cp311-abi3-macosx_11_0_arm64.whl |
|---|---|
| Size | 771.1 kB |
| Tags | CPython 3.11 abi3 macOS 11.0+ ARM64 |
|
SHA-256 checksum How to use checksums |
abb2ca3717c5092e8fa639791da06a800494cb41308ac22b9e4aca49d9f6b67e
|
|
BLAKE2b-256 checksum How to use checksums |
b7d48f37b511af3b24e800d9d03738708978cb25e18da7762d4fa57a73c6c1c5
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency logRelease files / pretium-0.3.0-cp311-abi3-macosx_10_12_x86_64.whl
| Download URL | pretium-0.3.0-cp311-abi3-macosx_10_12_x86_64.whl |
|---|---|
| Size | 796.1 kB |
| Tags | CPython 3.11 abi3 macOS 10.12+ x86-64 |
|
SHA-256 checksum How to use checksums |
eea0b20c0416537664045be986d0ba6f072ee3af32dc85de487c0abfad351c6c
|
|
BLAKE2b-256 checksum How to use checksums |
54e16c9d812e6a12071d360733e7e5ad782e8960dc66b465a8ba7d329bd653e9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2026.
Transparency log