This repo is a self-contained Rust backtester for IMC Prosperity 4.
It only supports local backtesting. There is no API surface and no hosted workflow in this repo.
Everything needed for the default backtest flow now lives inside this directory. The bundled default trader is:
traders/latest_trader.py
There is also a diagnostic trader that aggressively tests every visible product in a dataset:
traders/all_products_trader.py
Clone the repo:
git clone https://github.com/GeyzsoN/prosperity_rust_backtester.git
cd prosperity_rust_backtesterInstall the toolchain once:
xcode-select --install
curl https://sh.rustup.rs -sSf | sh
source "$HOME/.cargo/env"
python3 --versionFor normal end-user usage, install the published CLI from crates.io:
cargo install rust_backtester --lockedThen run it directly:
rust_backtester --help
rust_backtesterIf rust_backtester is not found after install, make sure ~/.cargo/bin is on your PATH.
If rust_backtester cannot be executed after install, make sure that ~/scripts/cargo_local.sh` is executable:
ls -la scripts/
sed -i 's/\r$//' scripts/cargo_local.sh
chmod +x scripts/cargo_local.sh
For local development from this repo, either install the local CLI:
make installor run the backtester directly from source:
make backtestFor the fastest local-source runs, prefer:
cargo run --release -- --helpThe macOS make targets intentionally build through a wrapper instead of your full shell environment. By default they write Rust build artifacts to:
~/Library/Caches/rust_backtester/targetIf you want a different target dir, override it explicitly:
CARGO_TARGET_DIR=/path/to/target make build-releaseUse WSL2. Open an Ubuntu shell inside WSL2 and run the same commands there. Native Windows shells are not the target environment for this repo.
There is no separate manual build step required for normal use:
make backtestand the othermakerun targets usecargo run, which builds automatically on first usecargo install rust_backtester --lockedinstalls the published release binary so you can runrust_backtesterdirectly afterwardmake installinstalls the CLI once so you can runrust_backtesterdirectly afterwardmake doctorprints local diagnostics for macOS build hangs and execution-policy issues
The repo is organized by round:
datasets/tutorial/prices_round_0_day_-2.csvdatasets/tutorial/trades_round_0_day_-2.csvdatasets/tutorial/prices_round_0_day_-1.csvdatasets/tutorial/trades_round_0_day_-1.csvdatasets/tutorial/submission.logdatasets/round1/prices_round_1_day_-2.csvdatasets/round1/trades_round_1_day_-2.csvdatasets/round1/prices_round_1_day_-1.csvdatasets/round1/trades_round_1_day_-1.csvdatasets/round1/prices_round_1_day_0.csvdatasets/round1/trades_round_1_day_0.csvdatasets/round2/prices_round_2_day_-1.csvdatasets/round2/trades_round_2_day_-1.csvdatasets/round2/prices_round_2_day_0.csvdatasets/round2/trades_round_2_day_0.csvdatasets/round2/prices_round_2_day_1.csvdatasets/round2/trades_round_2_day_1.csvdatasets/round3/prices_round_3_day_0.csvdatasets/round3/trades_round_3_day_0.csvdatasets/round3/prices_round_3_day_1.csvdatasets/round3/trades_round_3_day_1.csvdatasets/round3/prices_round_3_day_2.csvdatasets/round3/trades_round_3_day_2.csvdatasets/round4/prices_round_4_day_1.csvdatasets/round4/trades_round_4_day_1.csvdatasets/round4/prices_round_4_day_2.csvdatasets/round4/trades_round_4_day_2.csvdatasets/round4/prices_round_4_day_3.csvdatasets/round4/trades_round_4_day_3.csvdatasets/round5/prices_round_5_day_2.csvdatasets/round5/trades_round_5_day_2.csvdatasets/round5/prices_round_5_day_3.csvdatasets/round5/trades_round_5_day_3.csvdatasets/round5/prices_round_5_day_4.csvdatasets/round5/trades_round_5_day_4.csvdatasets/round6/datasets/round7/datasets/round8/
Right now the bundled public data is the raw IMC tutorial day data in datasets/tutorial/, the raw round 1 day data in datasets/round1/, the raw round 2 day data in datasets/round2/, the raw round 3 day data in datasets/round3/, the raw round 4 day data in datasets/round4/, the raw round 5 day data in datasets/round5/, plus a sample tutorial submission.log produced with the bundled basic trader. The remaining round folders are there so future round files can be placed in the correct folder instead of being mixed together.
If you place a portal submission.log file into a round folder, the backtester will use it. submission.log is also generated for persisted runs.
The CLI is intentionally simple:
rust_backtesterWith no arguments it will:
- auto-pick the newest Python file that looks like a trader from this repo's local
scripts/,traders/submissions/, ortraders/ - default the dataset to the latest populated round folder under
datasets/ - run in fast mode
- print one compact row per day
That means the simplest local commands are:
make backtestor:
rust_backtesterFor the published crates.io binary, the normal flow is:
cargo install rust_backtester --locked
rust_backtesterTo update later:
cargo install rust_backtester --lockedRound-specific shortcuts:
make tutorialSubmission and future-round shortcuts are also available once you place a submission.log, submission.json, or round data into datasets/round1/, datasets/round2/, and so on.
Useful optional variables for any make backtest target:
make tutorial DAY=-1
make submission ROUND=round1
make round3 TRADER=traders/latest_trader.py
make round3 TRADER=traders/all_products_trader.py
make round2 PERSIST=1
make tutorial FLAT=1
make tutorial CARRY=1Supported input formats:
- normalized dataset JSON files
- IMC day data as matching
prices_*.csvandtrades_*.csv, with optional pairedobservations_*.csv - portal submission logs such as
submission.log
Day selection behavior:
DAY=-1orDAY=-2runs only that day file inside the roundDAY=allor omittingDAYruns the whole round bundle, including any submission file when presentmake submission ROUND=round1runs the submission dataset fordatasets/round1/when a submission file is present
Explicit examples:
rust_backtester \
--trader /path/to/trader.py \
--dataset tutorialrust_backtester \
--trader /path/to/trader.py \
--dataset datasets/tutorialrust_backtester \
--trader /path/to/trader.py \
--dataset /path/to/submission.logrust_backtester \
--trader /path/to/trader.py \
--dataset datasets/round1Behavior:
- fast mode is the default
- the CLI prints one result row per day
--datasetaccepts either a path or a short alias- when
--datasetpoints to a directory, every supported dataset in that directory is run prices_*.csvfiles are paired automatically with matchingtrades_*.csvfiles from the same folder- matching
observations_*.csvfiles are loaded automatically when present and exposed throughstate.observations.conversionObservations latestandtutorialrun the full bundled tutorial round bundle: day-2, day-1, and the sample tutorial submission log- use
--day <n>to run only the matching day dataset within the round bundle; this excludes submission files metrics.jsonis always written underruns/<backtest-id>/- default fast runs also write
submission.logunderruns/<backtest-id>/ - use
--artifact-modeto choose which extra artifacts are written - use
--carryorCARRY=1to carry positions, own trades, market trades, and trader state across non-submission day datasets in the same round - use
--flatorFLAT=1to place multi-run outputs in a single directory with dataset/day-prefixed filenames - use
--persistorPERSIST=1to write the full replay artifact set underruns/ - persisted multi-day or multi-file runs also write one combined bundle at
runs/<backtest-id>/, includingcombined.logandmanifest.json - for multi-run visualizer uploads, use each child
RUN_DIR/submission.log; the top-level bundle does not emit a stitched replay file - product output defaults to every product so no product PnL is hidden in larger rounds
Published binary vs local development:
rust_backtesterruns the installed binary found on yourPATH, typically~/.cargo/bin/rust_backtestercargo run -- ...runs the local source tree in debug modecargo run --release -- ...runs the local source tree in release mode- if end users report slow runs, make sure they are running the installed
rust_backtesterbinary and not repeatedly usingcargo run
Bundled dataset aliases:
latesttutorial,tut,tutorial-round,tut-roundround1,r1round2,r2round3,r3round4,r4round5,r5round6,r6round7,r7round8,r8tutorial-1,tut-1,tut-d-1tutorial-2,tut-2,tut-d-2
Product display modes:
--products fulldefault: print a separate product table with every product--products summary: print a compact product table with the top product PnL contributors and anOTHER(+N)rollup when needed--products off: show only the per-day total
Artifact modes:
--artifact-mode none: write onlymetrics.json--artifact-mode submissiondefault when--persistis not set: writemetrics.jsonandsubmission.log--artifact-mode diagnostic: writemetrics.jsonandbundle.jsonwith the PnL series included for diagnostics--artifact-mode full: write the full persisted artifact set:metrics.json,bundle.json,submission.log,activity.csv,pnl_by_product.csv,combined.log, andtrades.csv--persistimplies--artifact-mode fullunless you explicitly override--artifact-mode
Flat layout behavior:
--flatonly changes multi-run layouts; single-run outputs stay unchanged- multi-run outputs are written into
runs/<backtest-id>/with prefixed filenames such astutorial-day-2-submission.logandtutorial-day-2-metrics.json - when
--flatis combined with--persist, the same directory also includescombined.logandmanifest.json
Carry mode behavior:
--carryonly applies to non-submission day datasets; submission datasets remain separate runs- with
--carry, consecutive day datasets in the same round are merged into one connected replay ordered by(day, timestamp) - positions, prior own trades, prior market trades, and trader data are carried across those merged day boundaries
- carry mode also normalizes timestamps into one continuous timeline, so the first tick of the next day starts immediately after the previous day ends
- a carried run reports
DAY=allin the summary because it spans multiple days
Artifact mode examples:
rust_backtester \
--trader /path/to/trader.py \
--dataset tutorial \
--artifact-mode nonerust_backtester \
--trader /path/to/trader.py \
--dataset tutorial \
--artifact-mode diagnosticrust_backtester \
--trader /path/to/trader.py \
--dataset tutorial \
--artifact-mode fullExample output shape:
trader: latest_trader.py [auto]
dataset: tutorial [default]
mode: fast
artifacts: log-only
SET DAY TICKS OWN_TRADES FINAL_PNL RUN_DIR
D-2 -2 10000 39 118.10 runs/backtest-123-day-2-day-2
D-1 -1 10000 42 123.45 runs/backtest-123-day-1-day-1
SUB -1 2000 18 51.20 runs/backtest-123-submission-day-1
PRODUCT D-2 D-1 SUB
TOM 70.00 77.20 29.10
EMR 48.10 46.25 22.10
make doctor
make build
make build-release
make test
make install
make install-pip
make install-uv
make install-uv-editable
make backtest
make tutorialIf a local Rust build hangs on macOS, the most likely symptom is that cargo build, make build-release, or make backtest stalls during build-script-build while syspolicyd uses a lot of CPU.
First retry path:
make doctor
make build-release
make backtestThose make targets already use the repo wrapper and a stable target dir outside the repo.
If it still hangs and you do not want to reboot, the non-restart remediation is:
sudo killall syspolicyd
make build-releaseIf local macOS execution policy is still unhealthy, use the isolated fallback:
make docker-build
make docker-smokeThis is a local macOS executable-launch issue, not a backtester logic issue.
Additional round1 to round8 and round1-submission to round8-submission targets are included in the Makefile. They become usable once those dataset folders contain JSON files.
There is a Docker-based smoke path for isolated verification:
make docker-smokeThe Docker image builds the project in a clean container and runs the zero-argument backtest flow during image build.
src/Rust backtester implementationtraders/latest_trader.pybundled default tradertraders/all_products_trader.pydiagnostic trader for verifying every product surfacedatasets/tutorial/bundled raw IMC tutorial day CSVs and sample submission logdatasets/round1/bundled raw IMC round 1 CSVsdatasets/round2/bundled raw IMC round 2 CSVsdatasets/round3/bundled raw IMC round 3 CSVsdatasets/round4/bundled raw IMC round 4 CSVsdatasets/round5/bundled raw IMC round 5 CSVsdatasets/round6/...datasets/round8/placeholders for future round dataruns/persisted outputs when--persistis usedruns/<backtest-id>/combined bundle for persisted multi-day runs, includingcombined.logandmanifest.json
Dual-licensed under:
- Apache-2.0:
LICENSE-APACHE - MIT:
LICENSE-MIT