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¶
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