Spaces:
Running on Zero
Running on Zero
| # 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 | |
| | What | URL | | |
| |---|---| | |
| | **Backtest Lab** (Space) | https://huggingface.co/spaces/Bit-Trading-Company/bit-backtest-lab | | |
| | Direct app | https://bit-trading-company-bit-backtest-lab.hf.space | | |
| | **Signal store** (Dataset) | https://huggingface.co/datasets/The-Bit-Trading-Company/bit-signal-store | | |
| 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 | |
| ``` | |