Skip to content

Recording Runs

There is no RunRecorder class. Recording is done inline after your session using conn.fills_to_polars() and standard file I/O.


Basic pattern

import pathlib, json, datetime

run_dir = pathlib.Path(f"runs/{arena.arena_id}")
run_dir.mkdir(parents=True, exist_ok=True)

# 1. Export fills
fills_df = conn.fills_to_polars(arena.asset_id)
if fills_df is not None and fills_df.shape[0] > 0:
    fills_df.write_parquet(run_dir / "fills.parquet")

# 2. Export market snapshots (optional)
arena_market = p.arena_market()
market_df    = arena_market.to_polars(arena.asset_id)
if market_df is not None and market_df.shape[0] > 0:
    market_df.write_parquet(run_dir / "market.parquet")

# 3. Write metadata (committed to git)
metadata = {
    "arena_id":   arena.arena_id,
    "asset_id":   arena.asset_id,
    "strategy":   "mean-reversion",
    "fill_count": fills_df.shape[0] if fills_df is not None else 0,
    "timestamp":  datetime.datetime.utcnow().isoformat(),
}
(run_dir / "metadata.json").write_text(json.dumps(metadata, indent=2))

What fills_to_polars() returns

A Polars DataFrame with columns:

Column Type Description
ts u64 Nanosecond timestamp
price u64 Fill price (raw ticks)
volume u64 Filled quantity
side u8 0=BUY fill, 1=SELL fill
is_maker bool True if passive
client_tag u64 Tag from the order
asset_id u64 Asset
import polars as pl
from fastboxex.price import to_display

fills_df = conn.fills_to_polars(asset_id)
fills_df = fills_df.with_columns(
    (pl.col("price") / 10_000).alias("price_display")
)

Directory layout

runs/
├── .arena_code           ← invite code (deleted on 07.py exit)
├── .arena_state.json     ← arena state (deleted on 07.py exit)
└── <arena_id>/
    ├── fills.parquet     ← fill tape   (gitignored, large)
    ├── market.parquet    ← snapshots   (gitignored, large)
    └── metadata.json     ← committed to git

.gitignore already excludes *.parquet. Only metadata.json is committed.


Committing a run

git add runs/*/metadata.json
git commit -m "run: arena 74 — mean-reversion 170 fills"

Zero-copy buffer (ML / PyTorch path)

import numpy as np, torch

mv   = conn.fills_as_tensor()               # PyMemoryView — zero copy
arr  = np.frombuffer(mv, dtype=np.uint8)    # no allocation
feat = torch.from_numpy(arr).float()

Anti-patterns

  • ❌ from fastboxex.recorder import RunRecorder — does not exist
  • ❌ from fastboxex import RunRecorder — does not exist
  • ❌ Not calling fills_to_polars() — data is lost when the process exits
  • ❌ Committing fills.parquet — large binary, gitignored for a reason