bit-backtest-lab / HANDOFF.md
Bit-Trading-Company's picture
Add HANDOFF.md
d8478d9 verified
|
Raw
History Blame Contribute Delete
8.67 kB

A newer version of the Gradio SDK is available: 6.25.0

Upgrade

Backtest Lab v1.0.0 β€” Handoff

Built end-to-end and deployed. Everything below was verified against the live Space, not just locally.

Live URLs

Both tagged v1.0.0. Space stage: RUNNING on zero-a10g (ZeroGPU).

Deployment status

Check Result
Build βœ… 142s build + ~30s app start
Cold start (app boot) βœ… ~30s, under the 60s budget
HTTP response βœ… 200 in 0.74s
Hardware βœ… ZeroGPU (zero-a10g) granted β€” no billing escalation needed
Example config end-to-end βœ… /load_example returns the design's worked example
Backtest on live Space βœ… +33.2%, 12 trades, $486 costs β€” bit-identical to local
Warm run time βœ… 0.1s engine time for a 3-year daily run (budget: <2s)
Coverage map from live manifest βœ… 18 rows, all labelled real
Login button βœ… present; /login/huggingface returns 302
ZeroGPU detected in-app βœ… "ZEROGPU AVAILABLE Β· EXTENSION RUNS ON YOUR OWN QUOTA"

Tests: all green

bash tests/run_all.sh --slow β†’ 191 passed, run with -W error::FutureWarning.

Verified on both Python 3.11 (dev) and Python 3.10 (what the ZeroGPU image actually provides) β€” 190 offline + 1 real-model test.

The six known-answer tests

# Test Status
1 Buy & Hold, zero costs, reproduces the asset return (tol 1e-9) βœ…
2 Deliberately lookahead-biased strategy is caught structurally βœ…
3 Zero-cost vs costed run differ by exactly the modelled costs βœ…
4 Zero-signal strategy β†’ flat equity, zero trades βœ…
5 Walk-forward train/test never overlap; holdout untouched by selection βœ…
6 Same config + same data β†’ bit-identical results βœ…

31 tests cover these six directly. Test 2 catches three distinct cheats: reading bar t+1, a centred rolling window, and full-sample normalisation.

Spec compliance

  • βœ… No lookahead paths. Enforced two ways: the engine applies the one-bar shift itself (a strategy cannot bypass it), and assert_causal proves it by perturbing future prices up and down and requiring earlier outputs to be bit-identical. All seven shipped presets pass.
  • βœ… Fills at next bar open. fill accepts only next_open; anything else raises. A test asserts the entry price equals bar 1's open, not bar 0's.
  • βœ… Costs default ON. Costs().enabled is True. gross βˆ’ costs = net holds to 1e-9 on every trade row. Costs-off runs are labelled "these numbers are not achievable" in the UI.
  • βœ… Every displayed metric traceable to engine output. The stat band, trade table and report are asserted against metrics.py values in test_ui.py.
  • βœ… No placeholder slices remain. All 18 signal slices are real Chronos-Bolt output. The PLACEHOLDER labelling machinery is still present and tested for contributors on weaker hardware.
  • βœ… No arbitrary code execution. Adapter families are allow-listed, model ids are validated, trust_remote_code is never set, and the design's Custom (code) preset is rendered disabled with an explanation.
  • βœ… Token hygiene. Scanned every file in both repos: the token appears in none of them. It exists only in the local gitignored key.txt and as the HF_WRITE_TOKEN Space secret.

What shipped

Signal store β€” 18 signal slices / 60,375 real rows across chronos-bolt-small + chronos-bolt-base, 6 assets (BTC, ETH, SOL, SPY, QQQ, NVDA) Γ— 3 timeframes (1d, 1h, 15m); 15 price slices; 4 precomputed comparison tables (model performance, calibration, directional accuracy, strategyΓ—timeframe heatmap).

Derived data worth reading: Chronos-Bolt is consistently over-dispersed β€” its nominal 80% q10–q90 band actually covers 83–89% of outcomes across every slice. Worth knowing before trusting a q10 stop level.

Engine β€” vectorbt, next-bar-open fills, commission + fixed/volume-scaled slippage, SL/TP/trailing stops, fixed-% and vol-target sizing, three validation modes with a locked holdout, full IS/OOS/holdout metric split, trade list with R-multiple, MAE/MFE and per-trade trigger reasons.

UI β€” the design implemented in Gradio Blocks with the Bit design system vendored verbatim (tokens + Styrene/Mac Minecraft fonts): Strategy Builder (5 numbered sections), Results Canvas (Overview / Trades / Comparison / Robustness / Report / Coverage), Run Manager, pinned disclaimer footer.

⚠️ Human-verify checklist

These need a real human with a real account β€” I cannot complete them:

  1. OAuth login end-to-end. The button renders and /login/huggingface redirects correctly, but I cannot complete a real sign-in. Click Sign in with Hugging Face and confirm you land back signed in. If it fails, check Space settings β†’ the hf_oauth: true header is set in README.md and may need the owner to approve the OAuth app once.
  2. ZeroGPU extension with a real account. Sign in, open the Coverage tab, pick an uncovered range, press Estimate then Extend coverage. Confirm: progress stages appear, the commit lands in the dataset repo, and the toast reads "Coverage extended by @you". This is the only path that spends real GPU quota, so it is untested against real hardware.
  3. Add-model flow with a real Hub model id, same reason.
  4. Torch version difference. The Space runs torch 2.11.0 (ZeroGPU only accepts 2.11/2.10/2.9.1/2.8); my adapter smoke test ran locally on 2.13.0. The first real ZeroGPU extension doubles as the check that Chronos inference behaves identically on 2.11.
  5. Visual pass on a real screen. I verified the UI functionally and via screenshots, but the in-app browser stalled before I could click through every tab at full size. Worth a human eye on the Comparison and Robustness tabs with several runs loaded.

Open items from DECISIONS.md

  • D-001 β€” Space is under the personal namespace. Gradio Spaces under an org need a paid Team/Enterprise plan (402). You chose the personal namespace; the dataset stays under the org. To move it later, subscribe and re-point BIT_SPACE_REPO.
  • D-006 β€” Binance is geo-blocked (451) from the seeding machine; crypto came from Coinbase via the fallback chain. Stooq now serves an HTML block page, so the equity chain effectively runs on yfinance alone. Tiingo is wired but needs a TIINGO_KEY secret to join the chain.
  • Sentiment is a stub. Sentiment-Gated Momentum runs on a labelled, deterministic price-derived proxy behind a SentimentSource interface β€” not news sentiment. Wiring a real feed is the obvious next task.
  • Pairs Trading is in the design's preset list but not runnable in v1 (needs a second leg). It is shown disabled with that reason.
  • Equity intraday depth is provider-capped (~730d hourly, ~60d 15m) and recorded in the manifest as provider_max_days, not hidden.

Things I'd flag as genuinely uncertain

  • The example strategy loses money on the locked holdout (βˆ’5.2%, Sharpe βˆ’0.38). That is the system working: the holdout is doing its job and the app reports it rather than burying it. Don't read the headline +33.2% as a result.
  • Walk-forward on short ranges produces no OOS windows at all. The app now says so explicitly instead of printing 0.00, but it is easy to configure a run that looks complete and has no out-of-sample content. Watch for the red note.
  • vectorbt is pinned to 1.0.0, not the 1.1.0 I developed against, because 1.1.0 requires Python β‰₯3.11 and the ZeroGPU image is 3.10. The full suite passes on both, but that is a real version skew between dev and prod.

Repo layout

hugging-face/
  key.txt            local only, gitignored, never committed
  DECISIONS.md       15 logged decisions across all phases
  HANDOFF.md         this file
  ops/               provisioning scripts (local only, not deployed)
  store_stage/       dataset card staging
  space/             β†’ pushed to the Space
    app.py  src/{store,data,engine,strategies,adapters,charts,metrics,
                 comparisons,runtime,extension,config,ui/theme}.py
    scripts/seed_store.py   tests/ (191)   assets/ (vendored design system)
    DESIGN_NOTES.md  the extracted design contract Phase 3 was built against