Skip to content

Repository files navigation

SharpeArena

The point-in-time environment for trading agents, and the contract they speak

Whoever defines the agent interface owns the ecosystem. SharpeArena is the leak-free trading floor every agent runs on, and the language-agnostic contract that makes any agent scorable.

Crates.io npm PyPI docs.rs CI License Unsafe

Why · Quickstart · Train an agent · Surfaces · The contract · Architecture · Tech stack


Why

An eval is useless without an environment. A benchmark scores trajectories; something has to produce them. SharpeArena is that producer: a leak-free, point-in-time market environment wrapped in a dead-simple, language-agnostic agent contract. The harness sends an Observation, the agent returns a Decision, repeat.

Two properties make it trustworthy rather than a toy:

  1. Look-ahead is structurally impossible. The environment owns the time cursor and the data layer has no API to read a future bar, so an agent cannot peek by construction, not by policing.
  2. Trajectories are recompute-from-raw-decisions. A run records only the agent's decisions; a separate verifier replays them against the frozen data to recompute a byte-identical result. A tampered trajectory recomputes differently, so an agent cannot lie about its returns.

The strategic bet is interface ownership: if every trading agent in the open ecosystem conforms to SharpeArena's Observation/Decision contract, then SharpeBench is the natural scorer and the whole funnel (env, trajectory, score, leaderboard) runs on one standard. This is the OpenAI-Gym moment for trading agents. The interface is the product; the simulator is the credibility behind it.

An agent is just a program that reads an observation and writes a decision, in any language. Conform to the contract, and you are scorable everywhere.

Status: published, active (pre-1.0)

Published to crates.io, npm, and PyPI (the badges above show the live versions), depending on the published sharpebench engine (not a vendored copy). CI is green across four surfaces: Rust (fmt, clippy -D warnings, tests, a WASM target build), cargo-deny, the npm package, and the Python wheel (maturin + pytest).

What the evidence shows. The paper, SharpeArena: The Point-in-Time (PIT) RL Environment for Trading Agents (paper/), commits ten experiments (every number from a script, JSON evidence, and fixed seeds) and frames them as calibrations of the suite's instruments, not market findings. Among them:

  • The corrected deflation prior rewrites the baseline board. The pre-0.5.0 kernel scored every baseline 0.0000 deflated Sharpe on every tier: a unit bug, an annualized prior applied per period, a bar near annualized Sharpe 18. Corrected, drift saturates the deflated Sharpe at 1.0000 on Calm, and still nothing is rank-eligible: no baseline passes pass^k on every seed (best rate 0.75), and Hard/Extreme collapse the score to 0.11/0.02. The eligibility conjunction, not a mis-united floor, is what gates.
  • The realism gate fails the canonical tape, and says so. The three calibrated stylized-facts checks fail the canonical configuration on 23 of 24 runs (0/8 Calm, 0/8 Hard, 1/8 Extreme). The ACF gate uses a fixed 95th-percentile IID null for its exact short-panel estimator, while the finite-panel Fano ratio is conditional-IID-calibrated but exploratory. At vol_clustering=0.5, three-check pass counts are 0/8, 8/8 and 4/8; the 99-cell Calm follow-up has no setting that meets its diagnostic, confirmation and 25% volatility rule. At 0.0, the leaderboard configuration, the tape is byte-identical, so certification is reported beside the results rather than required by them.
  • Market-making agents are scored on regret against a closed-form reference. The env ships the closed-form Avellaneda-Stoikov reference policy; its regret is 0.0 by construction, and fixed-spread quoting pays a U-shaped regret: 84.6 at a 0.05 half-spread, a minimum of 0.037 at 0.5 whose CI [-8.7, 8.8] makes it indistinguishable from the reference, back up to 58.8 at 4.0.
  • Cross-regime transfer exposes what the within-tier gap cannot. The calm-trained reference loses 0.88 of deflated Sharpe zero-shot on Hard and 0.97 on Extreme, while its within-tier generalization gap sits near zero (+0.0012 on Calm), the expected control for an unfitted policy.
  • Linear-impact manipulation is a finite-grid consistency check, not a theorem. The red-team pump-and-unwind probe has negative means in all 45 sampled linear-impact cells (Kyle lambda 0 to 0.8, eta 0 to 0.8, follower gain 0 to 120). The size-response sweep is bounded and decreasing on its sampled range. This finite-grid result does not cover other parameter interactions, transient impact, or nonlinear permanent impact.
  • The concave ablation is an honest null, and the positive control demonstrates falsifiability. At normalized permanent-impact exponents 0.5 and 0.7, every sampled symmetric-pump mean is negative; 7 of 23 stored intervals cross zero at 0.5 (five distinct configurations), and 0 of 23 cross at 0.7. An exploratory 135-cell asymmetric search finds a profitable sampled schedule at exponent 0.5: nine bars of slow accumulation followed by a one-bar block liquidation earns an impact-attributable +21.8e-4, with pointwise 95% interval [17.4, 26.2]e-4 and Bonferroni familywise interval [10.0, 33.6]e-4. A 60-cell one-axis extension uses independently normalized unequal legs and, because its anchor comes from the first grid on the same seeds, global 195-cell familywise intervals: 23 cells are positive, 31 negative and 6 unresolved; the largest sampled 45:5 cell is +135.0e-4, [122.1, 148.0]e-4. All 45 sampled linear-impact means are negative, and the mirror values are numerically near-symmetric rather than bit-identical. These are finite-grid results, not a universal theorem or optimum; interactions, other exponents, flow scales, transient impact and overshooting trips remain outside the search.
  • Bounded public seed bands are invertible; salt secrecy defeats that scanner. A causal AR adversary finds no undisclosed stressed-tier edge, but a scan of a public 2^16 seed band recovers 16/16 tested seeds from one observed bar in about one second. The opt-in sealed_seed / sealed_eval_seeds derivation recovers 0/16 under that same bounded scanner while a high-entropy salt is withheld, and revealing the salt replays 16/16. This is a simulated commit-reveal result against one enumeration budget, not a cryptographic proof or evidence that any live evaluation uses sealed seeds. A forward protocol can commit a salt hash before entry; custody and deployment remain operator responsibilities.
  • Rank-eligibility is attainable, and pass^k is what binds. An out-of-band oracle (the seed replayed one bar ahead, not an entrant, never scored) mixed with noise at controlled strength opens the gates on every tier: the eligibility region is non-empty, and at all ten attained boundaries the binding leg is the per-run PSR gate on every seed, which the pooled deflated-Sharpe and bootstrap legs clear long before. On Calm an every-bar sign follower never passes even with a perfect oracle, because flipping every bar costs about 14 bp/bar against 2.7 bp of omniscient sign value; a turnover-rationing variant passes from strength 0.90. flat fails 16/16 because a zero-dispersion series carries no evidence of edge (PSR 0.5), not because inactivity is penalized.
  • Ecology is a distribution, not one trajectory. Across eight replicator seeds per schedule, shock-driven replacement of the volatility targeter occurs on 1 of 8 seeds, while a kelly_vol_target lineage ends dominant on 7 of 8 shocked seeds. The probe reports this outcome distribution rather than treating one trajectory as a general conclusion.

The rest (the generalization-gap bootstrap CIs, adverse-selection markouts, failure-mode distributions) is in the paper's Experiments section, with the exact command per number in its appendix. The scoring kernel's own paper, SharpeBench: A Luck-Robust Benchmark for Trading Agents, is the companion to this one.

Beyond the core reset/step lifecycle, the environment now ships a full reinforcement-learning training surface:

Capability What it is
Procedural scenarios A seeded generator (ScenarioSpec / generate_scenario) using Procgen's integer-seed-interval model, with Calm / Hard / Extreme volatility-and-jump tiers and provably disjoint train_test_split, cross-runtime golden-hashed for byte-identical generation, plus an opt-in vol_clustering persistence driver on ScenarioSpec (default 0.0, byte-identical off; threaded through the Gymnasium and vector envs) pinned by its own golden hash.
Generalization gap generalization_gap measures train-vs-held-out deflated Sharpe over disjoint seed bands, turning "did it overfit" into one number scored by the SharpeBench kernel.
verifiers training env A PrimeIntellect verifiers MultiTurnEnv that steps the market bar-by-bar, over a multi-row scenario Dataset, with an XMLParser decision protocol and a GRPO-safe bounded reward scored by the real SharpeBench score_run (deflated Sharpe, pass^k, process checks).
Pluggable reward schemes load_environment(reward_scheme=...) selects from a registry: an online differential Sharpe (Moody-Saffell, aligns the training signal with the deflated-Sharpe score), Sortino, drawdown-penalized, turnover-penalized, loss-averse, plus two risk-aware schemes that price risk per bar instead of at episode end (risk_aware charges a causally-estimated EMA conditional volatility at a fixed aversion; time_inhomogeneous_vol_aversion varies that aversion across the horizon). Schemes shape training only; the rank key stays the SharpeBench kernel.
Reward-misspecification probes A registry of deliberately flawed rewards (raw PnL, win-rate, indicator-shaped, recency-biased) run as negative controls: greedy proxy maximizers of each flawed reward score below a clean baseline on the SharpeBench kernel, making "the scorer punishes over-leverage / overfit / churn" falsifiable. Never registered as valid schemes; never feed the rank key.
More env tasks Beyond the position env: a PortfolioEnv (simplex allocation, log-return), an ExecutionEnv (VWAP/TWAP implementation-shortfall MDP), and a MarketMakingEnv (Avellaneda-Stoikov) that ships its closed-form analytical-optimal policy as a baseline, so agents are scored on regret-vs-provably-optimal.
Scenario families Calm/Hard/Extreme vol-jump tiers plus CointegratedPairs (genuine mean-reverting spread), RegimeShift (trend-to-whipsaw), curriculum chaining (CurriculumEnv/regime_curriculum), and a frozen named held-out eval-seed regression set.
Rich observations Opt-in, causal, leak-free obs augmentations computed from the point-in-time history: technical indicators (RSI/MACD/Bollinger/...), multi-timescale momentum, rolling covariance, a spread z-score, a recursive Kalman hedge-ratio spread (a KalmanSpreadObservation for the cointegrated-pairs scenario emitting the innovation-normalized z, leak-free by construction, superseding the rolling-OLS approximation), a Kalman constant-velocity trend obs (filtered velocity + sign), a synthetic seed-derived news/sentiment channel, and time-to-horizon. Declarative via PreprocessingConfig.
Risk + eval axes Drawdown stop-out, turbulence-halt, liquidation-cascade, and a cross-sectional deleveraging circuit-breaker (flattens the oversold subset when universe-wide breadth flips oversold, distinct from the single-asset breakers) wrappers; a forecast-quality calibrated eval axis (FinPILOT), per-regime breakdown, efficient-frontier/Kelly baselines, a deterministic episode-failure taxonomy + suite rollup (clean / bankrupt / stopped-out / cascade-wiped / mandate-breach), and a full risk/profit metrics panel (Calmar/Sortino/VaR/CVaR/tail/turnover).
Deferred-claims resolution Predictions scored after the episode: an agent commits a claim (point, probability, direction, interval) with a resolution horizon via a DeferredDesk that holds no dataset, no env, and no path to future data, so leak-freedom is structural. resolve_claims scores later against outcomes stamped with when the datum first existed, refusing any outcome available at or before commit; scoring covers Brier, sign accuracy, and interval coverage, and claims round-trip through JSON so commit and resolution can be separate processes or days.
Vectorized rollouts VecTradingEnv runs B scenario lanes in lockstep (rayon, structure-of-arrays JSON, current-Gymnasium AutoresetMode, async send/recv), exposed as a gymnasium.vector env.
Point-in-time-safe wrappers Causal normalize (no future-bar leak), TimeLimit, FrameStack, RecordEpisodeStatistics, vector-env variants, and flatten/unflatten Dict-obs helpers, plus a check_env conformance harness that proves seed-determinism (and adopts Gymnasium's own check_env).
Real-data blocks + discrete actions Gap-aware contiguous-block episode sampling for frozen real-data CSVs (every sampled window lies inside one continuous block, so a reset never straddles a listing gap or exchange downtime and fabricates a jump), and a DiscreteAction wrapper that maps Discrete/MultiDiscrete heads (long/flat/short or binned) onto the canonical target-weight Box for value-based learners.
Gymnasium registration Versioned, namespaced IDs: gymnasium.make("SharpeArena/Hard-v1") and make_vec(...) route to the scalar and vector envs, with -Eval-v1 variants on a disjoint held-out seed band.
Multi-agent markets A PettingZoo MultiAgentSharpeArenaEnv (batched competition: N agents on one frozen scenario, SharpeBench-ranked), an EndogenousMarketEnv (a shared-book market where aggregate flow moves the cleared price via Kyle + Almgren-Chriss impact), and an LOBMarketEnv over a real deterministic limit-order-book matching engine (integer ticks, price-time priority, market/limit/cancel/modify, depth-ladder + microprice + queue-imbalance obs), now with a single-price call-auction uncross (uncross, the max-matched-volume open/close equilibrium the CDA book lacked) and a read-only walk-the-book sweep_cost query (average fill price + slippage without mutating the book or the tape).
Ecological population dynamics run_ecology plays generations of a strategy population on the endogenous market (FinEvo): discrete-replicator selection moves share toward above-field-average payoff, new variants are bred from the leader on a fixed cadence, and a Shock schedule rotates the regime tier and scales the impact coefficients (a liquidity shock). Output is the full generation-by-generation share/fitness trajectory plus classify_outcomes (dominant / collapsed / extinct / persistent / marginal, labeling the shape of each share trajectory) and detect_coalitions, RNG-free so a run reproduces exactly.
Adverse-selection scenario An informed trader whose meta-order flow precedes the price move, sliced into child orders, against a paired uninformed control (identical schedule, sizes, and path; side drawn independently), so the two modes differ only in whether the counterparty's direction is correlated with what happens next. Measured by per-fill markout decomposition: spread_capture + adverse_drift = markout, an exact partition, with toxic_fill_rate and a stated picked_off verdict.
Manipulation red-team probe A diagnostic aimed at the simulator, not a strategy: a crude pump-and-dump schedule, an AsymmetricSchedule family (leg durations plus a block fraction, containing the symmetric schedule as a member), impact-boundary and size-response sweeps, paired zero-impact references, and an opt-in permanent-impact exponent (impact_exponent=1.0 linear, below 1 concave). The unit exponent preserves the canonical byte-identical path; non-unit exponents are explicit ablations outside the cross-runtime golden guarantee.
Sealed evaluation seeds Opt-in, commit-reveal: sealed_seed(salt, slot) (Rust, pyo3, and sealed_eval_seeds(salt) / evaluate_eval_set(salt=...) in Python) derives each named held-out slot from a secret salt into the [EVAL_SEED_BASE, 2^64-1) band, so disjointness from the train band stays publicly checkable without the salt while the concrete seeds are unenumerable. The evaluator publishes SHA-256(salt) before the run and reveals the salt after; anyone then recomputes the seeds and replays byte for byte. A keyed PRF-style derivation (FNV-1a plus SplitMix64 finalizer rounds), not a certified MAC; the public set and its regression snapshot are untouched.
Robust market clearing An opt-in elliptic uncertainty set over the Kyle/Almgren-Chriss impact coefficients (EllipticUncertaintySet): the robust entry points clear each bar at the closed-form worst case inside the set (the support function of the ellipse in the cost direction). With no set supplied the robust path executes the identical float operations as the point-estimate path, byte for byte, so published results and golden hashes never move.
Market realism diagnostic A stylized_facts / certify_realism finite-panel diagnostic (Python, off the byte-identical hot path). Its calibrated conjunction gates positive excess kurtosis, absolute-return autocorrelation above an estimator-specific IID null, and aggregation toward zero absolute excess kurtosis. Gain/loss skew, Zumbach asymmetry and conditional-IID-calibrated Fano are exploratory; the canonical tape fails the conjunction on 23 of 24 panels, and the diagnostic is reported rather than used to rank.
Per-scenario mandates Each scenario samples a trading mandate (long-only, market-neutral, drawdown-capped, beat-a-benchmark); the verifiers rubric is mandate-conditioned, so wrong-objective behavior is penalized, not just unrewarded.
Offline-RL + checkpointing to_minari exports rollouts as a Farama Minari dataset (leak-safe, recover_environment-ready); CheckpointableEnv clones/restores/branches market state for tree search (O(1) native engine snapshot or replay-from-decisions); SharpeArenaFuncEnv is a stateless gymnasium.functional.FuncEnv view.
Benchmark protocol A committed EVALUATION.md: the canonical eval contract, the disjoint train/held-out split, and a baseline leaderboard (no baseline is rank-eligible: drift saturates the deflated Sharpe on Calm but no baseline passes pass^k on every seed, and pass^k degrades Calm to Hard to Extreme).
Behavioral counterparties Deliberately biased policies (DispositionEffectPolicy trims winners early and holds/tops up losers; OverconfidentPolicy over-sizes a 3-bar signal and churns the book every step) as counterparties and a realism floor, not strategies. Kept out of the ranked reference set on purpose, so the deflation trial count the leaderboard is scored against stays honest.
Harness integration An MCP server (reset / step / spec tools) so any MCP agent harness drives an episode with zero glue, a LookaheadGuard that refuses agent operations reading future data, versioned JSONL rollout traces that re-score offline through the SharpeBench kernel, and a cost-adjusted RunMetrics block for leaderboard ranking.

The determinism-critical core (the engine, scoring, scenario generation, mandates, the market-clearing model, the execution-noise integrity knob) lives in Rust so a published number is byte-identical across every surface; the per-ecosystem adapters (gymnasium, PettingZoo, Minari, verifiers, MCP) are thin and live in the language each ecosystem speaks.

Not yet shipped: the PrimeIntellect Environments-Hub listing and the Gordon conforming-agent adapter.

Quickstart

cargo add sharpearena        # the Rust crate (re-exports the engine + the wire contract)
use sharpearena::{TradingEnv, Dataset, CostModel, Window, BuyAndHold, Agent};

let data = Dataset::synthetic(4, 120, 1);
let mut env = TradingEnv::new(data, Window { start: 20, end: 120 }, CostModel::default(), 7);
let mut agent = BuyAndHold;
let mut obs = env.reset();
loop {
    let decision = agent.decide(&obs);
    let step = env.step(decision);     // -> { observation, reward, done, info }
    obs = step.observation;
    if step.done { break; }
}

Both stepping surfaces (the open-loop TradingEnv and the closed-loop run_backtest) call one shared per-step body, so a trajectory the env produces is byte-identical to the equivalent backtest, enforced by a test.

import gymnasium, sharpearena          # a first-class Gymnasium env
env = sharpearena.SharpeArenaEnv(n_symbols=4, n_days=120, seed=1)
obs, info = env.reset(seed=1)         # the seed selects the scenario
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())

Train an agent

The Python package is a PrimeIntellect verifiers environment, so an agent trains over a distribution of leak-free scenarios scored by the SharpeBench kernel:

import sharpearena

# A multi-turn env that steps the market bar-by-bar over many seeded scenarios.
env = sharpearena.load_environment(n_windows=256, n_symbols=4, n_days=120)

# Measure overfitting directly: train vs a provably disjoint held-out seed band.
gap = sharpearena.generalization_gap(
    lambda seed: sharpearena.SharpeArenaEnv(n_symbols=4, n_days=120, seed=seed),
    n_train=64, n_test=64,
)
print(gap["gap_deflated_sharpe"])

Scale with vectorized rollouts. SharpeArenaVectorEnv steps B independent scenario lanes in lockstep (rayon under the hood), exposing the standard gymnasium.vector API:

import numpy as np, sharpearena

vec = sharpearena.SharpeArenaVectorEnv(num_envs=64, n_symbols=4, n_days=120)
obs, infos = vec.reset()
actions = np.full((vec.num_envs, len(vec.symbols)), 0.25, dtype=np.float32)
obs, rewards, terminated, truncated, infos = vec.step(actions)   # arrays of length 64

Compose point-in-time-safe wrappers. Standard gym wrappers, but the normalizers are causal, so no future bar ever leaks into the running statistics:

import sharpearena
from sharpearena import TimeLimit, CausalNormalizeObservation, RecordEpisodeStatistics

env = RecordEpisodeStatistics(            # info["episode"] carries Sharpe + max drawdown
    CausalNormalizeObservation(
        TimeLimit(sharpearena.SharpeArenaEnv(n_symbols=4, n_days=120), max_episode_steps=64)
    )
)

Register it like any Gymnasium env. Importing sharpearena registers versioned IDs, so the whole RL ecosystem reaches it through muscle memory:

import gymnasium, sharpearena
env = gymnasium.make("SharpeArena/Hard-v1")            # difficulty + version pinned in the ID
vec = gymnasium.make_vec("SharpeArena/Hard-v1", num_envs=8)

Trade a real multi-agent market. In EndogenousMarketEnv the agents' aggregate flow moves the price they all see (Kyle permanent + Almgren-Chriss temporary impact), not a frozen path:

from sharpearena import EndogenousMarketEnv     # a PettingZoo ParallelEnv

market = EndogenousMarketEnv(n_agents=3, n_symbols=4, n_days=120, seed=1)
obs, infos = market.reset(seed=1)
# every agent submits a target-weight order; the book clears once and the cleared
# price reflects everyone's flow, so one agent's size moves the others' fills.
obs, rewards, terminations, truncations, infos = market.step(
    {a: market.action_space(a).sample() for a in market.agents}
)

A one-command prime-rl GRPO training config lives in examples/prime-rl/; see docs/training.md for the full loop (install, vf-eval baseline, uv run rl).

Use it from anywhere

One Rust engine, scored identically across every surface, because they run the same code.

Surface Get it What it is
  Rust crate cargo add sharpearena The env, the procedural scenario generator, the batched VecTradingEnv, the mandate / execution-noise / market-clearing cores, and the governed wire contract, re-exporting the leak-free engine.
  Python pip install sharpearena Gymnasium (Env + vector + registered IDs), PettingZoo (competition + endogenous market), the verifiers training env, Minari export, checkpointing, FuncEnv, point-in-time-safe wrappers, traces, and an MCP server, over the pyo3 binding.
  npm npm i @general-liquidity/sharpearena A typed JS/TS API over the engine compiled to WASM.
  WASM sharpearena-wasm The wasm-bindgen bridge the npm package and Gordon (Bun) embed.
import { runBaseline } from "@general-liquidity/sharpearena";

// The identical Rust engine, in the browser or Bun: run a baseline over a seeded panel.
const run = runBaseline({
  agent: "momentum",
  dataset: { synthetic: { n_symbols: 4, n_days: 120, seed: 1 } },
  seed: 7,
});
console.log(run.returns.length, run.cost);   // per-period returns + realized execution cost

The agent itself can be written in any language: a conforming agent is a program that reads MarketObservation JSON (stdin or POST /decide) and writes Decision JSON. Reference agents in Rust, TypeScript, and Python double as the conformance smoke tests (crates/sharpearena/examples/).

The agent contract

The load-bearing standard. An Observation is point-in-time; a Decision is a set of target-weight orders:

// Observation (harness -> agent)
{ "date": "2025-01-02", "cash": 1.0,
  "symbols": [{ "symbol": "AAPL", "close_history": [187.2, 188.0, 190.4] }],
  "portfolio": [] }

// Decision (agent -> harness)
{ "orders": [{ "symbol": "AAPL", "action": "buy", "target_weight": 0.5 }] }

CONTRACT_VERSION tracks the wire shape and evolves additively only (new fields are optional with defaults), pinned by published JSON Schemas plus a conformance kit. The validate_decision_json boundary check rejects malformed decisions before they reach the engine. See crates/sharpearena/GOVERNANCE.md and crates/sharpearena/contract/.

Architecture

A Rust Cargo workspace, #![forbid(unsafe_code)], that depends on the published SharpeBench engine rather than vendoring it, so the env and the benchmark cannot drift.

sharpebench-sim (published) ...... the leak-free point-in-time engine
        |
   crates/sharpearena ......... the env, scenario generator, batched VecTradingEnv,
        |                       mandate / exec-noise / market-clearing cores, the
        |                       Gym reset/step, and the governed wire contract
        |-- crates/sharpearena-wasm   the engine as WASM (-> the npm package)
        |-- crates/sharpearena-py     pyo3 + the ecosystem adapters (maturin)
        +-- npm/sharpearena           the typed TS wrapper over the wasm
Crate / package Role
sharpearena The Rust moat: TradingEnv (reset/step), VecTradingEnv (batched), the procedural scenario generator, the mandate and execution-noise cores, the MarketClearing impact engine, the Scenario/crisis-suite bundle, the re-exported wire contract plus scored Run, CONTRACT_VERSION, the conformance kit, and reference agents.
sharpearena-wasm Pure JSON kernels (run_baseline, replay_run, generate_scenario, ...) plus wasm-bindgen exports, the identical engine for JS/TS.
sharpearena-py A pyo3 extension over the Rust cores plus the thin ecosystem adapters: Gymnasium (Env/vector/registration), PettingZoo (competition + endogenous market), verifiers, Minari export, checkpointing, FuncEnv, wrappers, traces, and MCP (built by maturin). Optional extras: verifiers, minari, pettingzoo.
@general-liquidity/sharpearena The typed npm wrapper over the WASM kernel.

Tech stack

Technology Role
  Rust The engine and env, pure f64, deterministic, no unsafe, batched with rayon
  WebAssembly The engine for non-Rust hosts (wasm-bindgen)
  TypeScript The typed npm package
  Python The pyo3 binding and Gymnasium adapter (built by maturin)
  Gymnasium The RL env standard the Python adapter conforms to (reset/step/spaces/vector/registration)
  PettingZoo The multi-agent API the competition and endogenous-market envs conform to (passes parallel_api_test)
  Minari The offline-RL dataset standard to_minari exports trajectories into
  Prime Intellect verifiers The RLVR Environment/Rubric standard the training env conforms to
  serde Deterministic JSON for the wire contract (float_roundtrip for byte-exact replay)
  GitHub Actions CI: fmt, clippy, tests, wasm, cargo-deny, npm, maturin

Governance

The contract is governed in the open: additive-only evolution, a published deprecation window, and a conformance badge (see GOVERNANCE.md). Hosted by General Liquidity to start; the credibility is the leak-free-by-construction substrate plus recompute-to-verify trajectories, not trust in the host. Gordon (GL's agent) conforms to the contract like any other entrant.

License

Dual-licensed under either MIT or Apache-2.0, at your option.


The trading floor every agent runs on.

About

SharpeArena is a leak-free, point-in-time reinforcement-learning environment for trading agents, and the language-agnostic contract they speak. The environment half of the SharpeBench suite.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages