Skip to content

Rust ​

The native crate — the same engine every other binding of Wickra Gym wraps.

bash
cargo add wickra-gym

examples/rust/src/main.rs is the runnable example the CI examples job builds; in full:

rust
//! A runnable Rust example: read a candle CSV, load a spec, then drive a fixed
//! long policy through the environment and print each step's reward.
//!
//! ```bash
//! cargo run -p wickra-gym-example
//! ```
//!
//! This mirrors the CLI's ingestion path — the CSV is read with the same
//! `wickra-data` reader — so the trajectory matches `wickra-gym run` on the same
//! spec, data and seed.

use std::path::Path;

use wickra_data::csv::CandleReader;
use wickra_gym_core::{Candle, Env};

/// Read a candle CSV via `wickra-data` and map into gym candles (OHLCV only;
/// microstructure columns are absent and default to `0.0`).
fn load_candles(path: &Path) -> Vec<Candle> {
    let mut reader = CandleReader::open(path).expect("open the candle CSV");
    reader
        .read_all()
        .expect("read the candle CSV")
        .into_iter()
        .map(|c| Candle {
            ts: c.timestamp,
            open: c.open,
            high: c.high,
            low: c.low,
            close: c.close,
            volume: c.volume,
            bid_px: Vec::new(),
            bid_sz: Vec::new(),
            ask_px: Vec::new(),
            ask_sz: Vec::new(),
            funding: None,
            oi: None,
        })
        .collect()
}

fn main() {
    let data = Path::new(env!("CARGO_MANIFEST_DIR")).join("../data");

    let spec =
        std::fs::read_to_string(data.join("specs/momentum_discrete.json")).expect("read the spec");
    let candles = load_candles(&data.join("series/BTCUSDT.csv"));

    let mut env = Env::new(&spec).expect("valid spec");
    env.load(&candles).expect("load candles");

    let reset = env.reset(Some(42)).expect("reset");
    println!("wickra-gym {}", wickra_gym_core::version());
    println!("reset observation: {:?}", reset.observation);

    // A fixed "always long" policy (discrete action 2 -> target +1).
    let mut equity = 0.0;
    for step in 0.. {
        match env.step(2.0) {
            Ok(result) => {
                equity += result.reward;
                println!(
                    "step {step}: reward {:+.6}  equity {:+.6}  terminated={} truncated={}",
                    result.reward, equity, result.terminated, result.truncated
                );
                if result.terminated || result.truncated {
                    break;
                }
            }
            Err(err) => {
                eprintln!("step {step}: {err}");
                break;
            }
        }
    }
}

More ​

Updated: