Skip to content

wickra-lib/wickra-gym

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

29 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Wickra Gym — a Gymnasium-compatible, microstructure-aware backtest environment with O(1) steps for fast, deterministic RL rollouts

Built on Wickra Status CI CodeQL codecov License: MIT OR Apache-2.0 OpenSSF Scorecard OpenSSF Best Practices Build provenance Deterministic across 10 languages Docs


Wickra Gym

A Gymnasium-compatible, microstructure-aware backtest environment with O(1) steps for fast RL rollouts over 514 streaming indicators. The whole dataset is precomputed once into a fixed feature tensor, so step() is a pure array index — and the same seed produces a byte-identical trajectory in every language.

Part of the Wickra ecosystem. Built on the same deterministic engine and ten-language binding surface as wickra-backtest, wickra-benchmark and the rest.

wickra-gym turns a candle dataset plus an observation/action/reward specification into a reinforcement-learning environment. It precomputes every bar's features (indicators, and optionally orderbook / funding / open-interest microstructure) in one O(1)-per-bar pass into a fixed FeatureTensor; from then on each step() is a constant-time index into that tensor, so rollouts are fast. The reward draws on the wickra-backtest fill/PnL model, and the only source of randomness is an explicitly-seeded episode RNG — so a (seed, policy) pair fully determines a trajectory.

The core (gym-core) is a JSON-over-C-ABI data API usable in ten languages, and Python additionally ships a real gymnasium.Env subclass as its primary consumer.

Determinism is the product

  • O(1) steps — the dataset is precomputed once to a fixed feature tensor; step() is a pure array index, never a recompute.
  • Seed-determined trajectories — the only RNG is the seeded episode RNG (never thread_rng); the same (seed, policy) yields a byte-identical trajectory in every language and between the parallel (rayon) and sequential (WASM) tensor precompute.
  • Fixed observation layout — an observation is an f64 vector of fixed length and canonical order (the ObsSpec order), so it is comparable across languages bit for bit.

Status

Pre-release — functionally complete, CI-verified, not yet published. The core, the CLI, all ten language bindings, the golden trajectory corpus, the property + fuzz suites, the benchmarks and one runnable example per language are built and green across Linux, macOS and Windows. Packages are not yet on the registries. Track progress in ROADMAP.md and CHANGELOG.md.

Documentation

Quickstart

Drive a fixed deterministic policy through an environment from the command line:

# A discrete "always long" rollout on the bundled example data, seed 42.
cargo run -p wickra-gym -- \
  --spec examples/data/specs/momentum_discrete.json \
  --data examples/data/series/BTCUSDT.csv \
  --policy always-2 --seed 42

# Golden-format JSON ({reset, trajectory}) instead of the human-readable table.
cargo run -p wickra-gym -- \
  --spec examples/data/specs/momentum_discrete.json \
  --data examples/data/series/BTCUSDT.csv \
  --policy always-2 --seed 42 --format json

A spec names the observation features, the action space, the reward kind and the episode bounds; the CLI loads the candle CSV, resets with the seed and prints each step's reward and equity. The same spec, data and seed produce the same trajectory here as in every language binding.

Gymnasium usage

The Python binding ships a real gymnasium.Env subclass — the environment plugs straight into the RL ecosystem (Stable-Baselines3, CleanRL, RLlib, …):

import json
import gymnasium as gym
from wickra_gym import register

register()  # registers "WickraGym-v0"

spec = json.dumps({
    "dataset_ref": "demo",
    "symbol": "BTCUSDT",
    "observation": {"features": [
        {"kind": "indicator", "name": "Rsi", "params": [14]},
        {"kind": "price", "field": "close"},
    ]},
    "action_space": {"type": "discrete", "n": 3},
    "reward": "pnl",
    "episode": {"max_steps": 256, "warmup": 15},
    "seed": 42,
})
candles = [{"ts": 0, "open": 100, "high": 101, "low": 99, "close": 100, "volume": 1000}, ...]

env = gym.make("WickraGym-v0", spec_json=spec, candles=candles)
obs, info = env.reset(seed=42)
obs, reward, terminated, truncated, info = env.step(env.action_space.sample())

observation_space is a Box derived from the spec (finite bounds where the core knows them, ±inf otherwise); action_space is Discrete(n) or a 1-D Box. Without Gymnasium installed, the lower-level RawEnv (the JSON command surface) still works — see docs/GYMNASIUM.md and examples/python/.

Observations, actions and rewards

  • Observation — an ObsSpec lists Features in declaration order, and the observation vector concatenates them in exactly that order: the features, then 4 × include_book_levels orderbook columns, then 2 funding/OI columns if requested. A feature is an indicator ({"kind":"indicator","name":"Rsi", "params":[14]}, optionally a sub-output "field"), a price field, or a microstructure field. Before warmup the indicators are not ready, so the first warmup bars are skipped rather than emitted as NaN.
  • ActionDiscrete{n} maps n buckets onto a target position; Continuous{low,high} sets the target position directly (clamped). The position feeds the wickra-backtest fill/PnL model.
  • RewardPnl, Sharpe or LogReturn, computed from the realised position path.

Full semantics (with the exact ordering and formulas) are in docs/OBSERVATIONS.md and docs/ACTIONS_REWARDS.md.

Microstructure observations

Beyond price and indicators, the observation can include exchange microstructure: set include_book_levels: N to append bid_px, bid_sz, ask_px, ask_sz for each of N orderbook levels, and include_funding_oi: true to append funding rate and open interest. When a dataset lacks a requested column the value is a defined 0.0 (never NaN), so the observation length stays fixed. See docs/MICROSTRUCTURE.md.

Use in any language

The core drives a single command_json envelope (load, reset, step, spec, version); every binding passes the same string through verbatim, so a trajectory is byte-identical everywhere. The golden/ fixtures pin one blessed response per case and the cross-language golden tests assert byte-for-byte equality — the same observations, rewards and termination flags in all ten bindings and between the parallel (rayon) and sequential (WASM) tensor precompute. One runnable example per language lives under examples/; per-binding quickstarts are in each bindings/<lang>/README.md.

Language Binding Package
Rust gym-core (native) crates.io
Python PyO3 (native) + gymnasium.Env PyPI
Node.js napi (native) npm
WASM wasm-bindgen (native) npm
C / C++ C ABI header + library
C# C ABI (P/Invoke) NuGet
Go C ABI (cgo) Go module
Java C ABI (FFM/Panama) Maven
R C ABI (.Call) R-universe

Project layout

crates/gym-core            the library: feature tensor + env + reward + command
crates/gym-cli             reference CLI, binary `wickra-gym`
crates/gym-bench           Criterion benchmarks
bindings/{c,python,node,wasm,go,csharp,java,r}   ten-language surface
golden/                    spec + policy + seed -> byte-exact trajectories
examples/                  runnable per-language rollouts + shared data
fuzz/                      cargo-fuzz targets (spec/command/tensor/step)
docs/                      observations, actions/rewards, gymnasium, microstructure

Building from source

cargo build --workspace
cargo test --workspace --all-features

Each binding builds with its own toolchain; see bindings/<lang>/README.md. The C-ABI consumers (C/C++, C#, Go, Java, R) need the C ABI library first: cargo build --release -p wickra-gym-c.

Requirements

Rust 1.86 (workspace) / 1.88 (Node binding). Per-binding toolchains: Python 3.9+ (Gymnasium needs 3.10+), Node.js 22+, .NET 8, JDK 22+, Go 1.23+, R release, and a C11/C++14 compiler with CMake for the C example.

Benchmarks

Criterion benchmarks for reset + N × step throughput (at observation dimensions 5/20/50) and build_tensor (at 1k/10k/100k bars, parallel vs sequential) live in crates/gym-bench; numbers and methodology are in BENCHMARKS.md.

Contributing

See CONTRIBUTING.md and the Code of Conduct. Every change runs the full CI matrix (all ten languages × three OSes) plus CodeQL, Scorecard, zizmor and the metadata audit.

Security

Report vulnerabilities per SECURITY.md. The threat model is in THREAT_MODEL.md.

License

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

Disclaimer

wickra-gym is research and engineering tooling, not financial advice. A trained agent's backtested performance says nothing about future returns; markets carry risk and you are responsible for your own decisions. wickra-gym is free software you run yourself: no hosted service, no data collection, no warranty.

About

A Gymnasium-compatible, microstructure-aware backtest environment with O(1) steps: precompute the dataset to a fixed feature tensor once, then step() is a pure array index. Deterministic RL rollouts, recomputable byte-for-byte in ten languages.

Resources

License

Apache-2.0, MIT licenses found

Licenses found

Apache-2.0
LICENSE-APACHE
MIT
LICENSE-MIT

Code of conduct

Contributing

Security policy

Stars

1 star

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors