Commit Graph

466 Commits

Author SHA1 Message Date
jgrusewski
84c9fcd146 fix(alloc): per-strategy cap now binds (concentration limit, holds cash) instead of a renormalise no-op (B2a)
The equal-weight cap+renormalise was algebraically a no-op — n=1 got 100% weight despite a 50% cap.
Cap without renormalising: when 1/n > max_strategy_weight the book holds cash rather than over-
concentrating; common case (1/n <= cap) is plain equal weight. + tests that exercise the binding cap.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:17:52 +02:00
jgrusewski
497d4022db feat(alloc): compute_allocation — ex-ante vol-target on full-history vol, marginal gate, killswitch (B2a)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:10:54 +02:00
jgrusewski
5893604158 fix(alloc): deterministic tie-break in equal_weight_marginal_prune + accurate module docstring (B2a)
sorted(kept) makes the leave-one-out bench choice stable across process runs (a set's iteration order
is PYTHONHASHSEED-dependent) — a reproducibility fix for a capital-allocation function. Docstring no
longer claims compute_allocation/target_capital, which land in later tasks.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:07:23 +02:00
jgrusewski
7b886f0a05 feat(alloc): pure allocation helpers — full-history vol, equal-weight marginal prune, killswitch latch (B2a)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 21:02:12 +02:00
jgrusewski
9ec8eaab9c feat(alloc): versioned AllocationPolicy + content-derived hash + capital_ceiling (B2a)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 20:58:21 +02:00
jgrusewski
178f0388d9 fix(policy): promotion backstop gates emptiness on deploy MEMBERSHIP not aggregated data (B1)
book_empty was `not book` (the aggregated returns dict), so deploy members present but with no
overlapping forward_nav data (e.g. a just-re-inceptioned deploy track) read as "first edge" and
AUTO-PROMOTED with no correlation check — a one-way false-promote on a capital-adjacent gate.
Now `not book_sids` (membership): no deploy members → promote (true first edge); members present
but no data → indeterminate → WITHHOLD, per spec. + regression test.

Also neutralizes the real registry's deploy-tier tracks in two pre-existing promotion tests that
were unknowingly relying on the old inversion (they didn't seed nav data for the real deploy book).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 15:24:32 +02:00
jgrusewski
0817067dcf feat(policy): promotion correlation backstop — human flag + data-confirmed diversification (B1)
evaluate_promotions now promotes a promote_on_pass candidate at gate==PASS only when its daily-return
correlation to the equal-weight deploy book (registry deploy-tier ∪ promoted, from A's records, minus
the candidate) is < POLICY.promotion_max_corr. Empty book (first edge) passes; short overlap or corr
above threshold withholds (logged). Catches a human mis-flag of a correlated edge with data. One-way
promotion unchanged; no capital.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:55:56 +02:00
jgrusewski
5eef3068b4 feat(policy): ingest stamps POLICY_VERSION + policy_hash on every gate verdict (B1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:41:42 +02:00
jgrusewski
1adcd40ee0 feat(policy): stamp forward_summary with policy_version + policy_hash (B1 audit)
ForwardSummaryRow gains nullable policy_version + policy_hash; upsert_summary stamps them
(keyword args, default None). migrate() additively ensures the two columns on an EXISTING
forward_summary table on BOTH dialects (Postgres ADD COLUMN IF NOT EXISTS; sqlite PRAGMA-guarded
ADD COLUMN) — create_all does not add columns to an existing table, so a persistent DB (prod
Postgres rows, or a lagging test sqlite) would otherwise be missing them (fixed a regression
where the ORM SELECT referenced the absent column).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:38:59 +02:00
jgrusewski
f821929ddf refactor(policy): gate functions take ResolvedPolicy; remove scattered gate constants (B1)
evaluate_reconciliation_gate + evaluate_gate now take a ResolvedPolicy (resolve_policy(POLICY,
gate_spec)); the module constants (MIN_FORWARD_DAYS / RECON_* ) + gate.py inline defaults are
removed — thresholds now come from the single GatePolicy. Verdict logic + reason strings
unchanged → byte-identical verdicts (full suite 1873 green proves it). _gate_verdict resolves once.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 14:16:18 +02:00
jgrusewski
cba9f6531b feat(policy): resolve_policy — per-track overrides on GatePolicy defaults, one resolution point (B1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:37:00 +02:00
jgrusewski
5a99bb6329 feat(policy): versioned GatePolicy + content-derived policy_hash (B1)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 13:33:34 +02:00
jgrusewski
7137d62bfa fix(forward): resolve whole-branch review findings (combined migration crash + hash/PIT accuracy)
- CRITICAL: add combined to migration_builders so its anchor is seeded — the pre-branch forward_summary
  row would otherwise trip the lost-anchor guard and crash combined_forward_nav every nightly
- hash accuracy: bybit cost_bps mirrors Settings default (10.0); multistrat instruments derive from
  FUND_INSTRUMENTS (no duplicate) so a return-affecting change actually re-inceptions
- sixtyforty documented as a benchmark exempt from strict PIT (spec §4)
- observed mode: xsfunding consumes the engine's UTC _today; re-inception resets carried book-state

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:51:00 +02:00
jgrusewski
5c7a5c5c49 fix(forward): restore per-tracker fault isolation in the gate ETL + test the DB sleeve series
ForwardIngestService.ingest now wraps each tracker's DB read/gate-compute/write in try/except+continue
so a failure in an earlier (research) track can't abort the batch and silently freeze the deploy-tier
real-capital gate. Adds a fault-isolation test + a direct test for the DB-backed _sleeve_return_series
(and dropped its now-unused data_dir param).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:23:38 +02:00
jgrusewski
1745249cf4 refactor(forward): gate ETL + allocator read the DB record; retire state_reader JSON path
forward_ingest now evaluates the gate from the DB record the engine writes (all_summaries +
nav_history) instead of reading *_state.json via ForwardStateReader; _sleeve_return_series reads
nav_history too. ingest_forward_state drops state_dir. state_reader.py + its test deleted — the
DB anchor + record are the single source of truth (spec sub-project A). Gate verdict logic unchanged.
Docstrings updated to reflect the engine path.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 10:02:28 +02:00
jgrusewski
a7533980da feat(forward): wire combined through the engine (recompute); drop track-level killswitch
combined_forward_nav now runs CombinedBookStrategy through forward_engine.run_track (DB anchor +
recompute) — the last track off the JSON ForwardTracker. The former ForwardTracker-level drawdown
killswitch overlay is intentionally dropped (a track throttle, not part of the edge; vestigial
research track, not capital). record_mode observed->recompute (version 2) -> clean re-inception.
Removes now-unused build_combined_forward_nav / CombinedBookForwardTracker registration in
migration_builders.py + the test_orchestration_assets.py test (its only exerciser). Also drops the
"combined" entry from the one-time migrate-forward-anchors builder map (record_mode is now
recompute, so the observed lambda:None placeholder would crash it; combined re-inceptions cleanly
through run_track with no JSON left to migrate).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:38:24 +02:00
jgrusewski
b1c736b35f test(forward): deterministic seed in _seeded_paper_repo (fix pre-existing flaky sleeve test)
_seeded_paper_repo seeded its synthetic sleeve returns from random.Random(hash(sleeve)), but
hash() is PYTHONHASHSEED-salted, so the vol-targeted-vs-raw assertion tripped for a small
fraction of process salts under the full suite (passed in isolation). Seed from zlib.crc32
instead — stable across processes → the test is now deterministic. Pre-existing flake, unrelated
to sub-project A; fixed to keep the suite green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:17:09 +02:00
jgrusewski
9a2859ea88 fix(forward): engine fails loud on lost anchor instead of silently re-inceptioning
Restores the safety invariant the legacy ForwardTracker enforced (raise on state loss rather
than reset the OOS clock to day 0 + discard the record — 3 prod resets "burned real capital").
run_track now raises when there is no active anchor BUT prior forward history exists (lost
anchor row), while a genuine first run still inceptions. Protects the deploy-tier tracks Task 8b
routed onto the engine.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 09:17:09 +02:00
jgrusewski
a957821e55 feat(forward): wire the 3 Bybit/positioning tracks through the deterministic engine
build_{bybit_4edge,bybit_4edge_levered,positioning}_forward_nav now run their (recompute)
strategy through forward_engine.run_track (DB anchor + recompute) instead of the JSON
ForwardTracker, so the deploy-tier Bybit book + positioning sleeve record to the DB SSOT
like the other tracks. Asset callers thread repo/today/at; tests re-pointed to the DB.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 08:54:14 +02:00
jgrusewski
965f286ca2 fix(forward): migration reconcile surfaces missing-coverage divergence + bounds window by today
- an accumulated date absent from the recompute now counts as divergence (status=diverged,
  missing_dates) instead of silently staying "match" — fixes the false-match when PIT history
  is incomplete (the multistrat/YahooPitClient shape the reconcile exists to catch)
- recompute window bounded to [T0, today] (today param was unused -> window was [T0, inf))

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:47:51 +02:00
jgrusewski
4bae18b4b7 feat(forward): one-time migration — seed anchors, reconcile recompute, import observed
migrate_track seeds each track's anchor from its *_state.json inception (preserve-T0),
reconciles recompute tracks vs the accumulated nav (divergence surfaced, never silently
overwritten), and imports observed tracks' booked log verbatim. migration_builders maps
each registry id to its (state_file, build_strategy); `fxhnt migrate-forward-anchors` CLI.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:32:35 +02:00
jgrusewski
33c356a8df feat(forward): PIT Yahoo close snapshots + PIT-reading client (stable recompute)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 01:01:10 +02:00
jgrusewski
5af0668b78 feat(forward): wire _run_paper_tracker to the DB-backed deterministic engine
_run_paper_tracker now runs each track through forward_engine.run_track (anchor +
recompute/observed dispatch, DB-backed) instead of the JSON ForwardTracker, keeping
the transient-error tolerance. Returns forward_days/last_date/reinception.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 00:50:31 +02:00
jgrusewski
a224127ab2 fix(forward): engine writes forward_nav as a true derived cache + validates record_mode early
- replace_nav purges stale pre-t0 rows on re-inception (nav cache == current record; fixes
  polluted nav_history / wrong dashboard headline_t0 after a definition change)
- record_mode validated before any anchor mutation (a bad mode no longer persists a broken anchor)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 00:37:22 +02:00
jgrusewski
d07e70b5a5 feat(forward): forward engine — anchor lifecycle + recompute/observed dispatch
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 00:21:19 +02:00
jgrusewski
423aad7911 feat(forward): pure recompute_series + derive_nav (matches ForwardTracker formula)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-09 00:02:20 +02:00
jgrusewski
c3451560f5 fix(forward): resolve Task 1-3 review minors (enforce single-active anchor, validate dates, tighten tests)
- set_anchor self-guards the single-active-anchor invariant (archive prior active on re-inception)
- append_record/record_series validate + normalize ISO-8601 dates (fail loud on malformed)
- ordering test now inserts out-of-order; removed dead test imports/vars; clean Session import

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:57:05 +02:00
jgrusewski
b16e8b87fa feat(forward): append-only forward_record log + carried book-state (observed mode)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:40:35 +02:00
jgrusewski
15572f0e60 feat(forward): declared definition + content hash + per-track definition entries
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:27:36 +02:00
jgrusewski
c88138aa1a feat(forward): forward_anchor table + repo (immutable per-track anchor, lineage)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 23:13:15 +02:00
jgrusewski
42c9234c81 feat(multistrat): drop BTC from the fund book — purer diversifier, higher combined Sharpe
The multistrat book had BTC-USD as 1 of 6 streams — redundant (crypto exposure
already comes from the Bybit book) AND the main source of correlation between the
equity and crypto legs. Measured (437d overlap): dropping BTC cuts multistrat<->crypto
daily-return correlation +0.284 -> +0.175, lifts multistrat's own Sharpe 1.23 -> 1.46,
and the combined portfolio Sharpe ~1.95 -> 2.14. Nothing lost (crypto exposure stays
via the Bybit book); the Alpaca leg is now pure equities (no crypto order).

- multistrat: FUND_INSTRUMENTS = the 5 pure-equity ETFs (SPY/IEF/GLD/PDBC/DBMF);
  book_series/target_weights/_build parameterized by instrument list (default = the
  original 6, faithful port intact). MultiStratStrategy takes an instruments arg.
- multistrat_nav + execute-multistrat use FUND_INSTRUMENTS (BTC symbol map dropped).

Full suite green (1838). Re-inceptions the multistrat track (return series changed).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:52:51 +02:00
jgrusewski
a1f9b27822 feat(gate): auto-promote research→deploy on gate PASS (multistrat)
When a track flagged `promote_on_pass` clears its reconciliation gate, the nightly
promotes it research→deploy — one-way + persistent, so it becomes fund-tier
deliberately once and never flickers with the daily gate.

- registry: multistrat gets promote_on_pass=True. Its diversification vs the crypto
  book was validated out-of-band (measured +0.284 daily-return corr over 437d → a
  real diversifier; combined Sharpe ~2.06 > 1.8). Correlation = the tested/deliberate
  judgment; gate PASS = the automated trigger.
- persistence: strategy_promotion table + ForwardNavRepo.promote / promoted_strategy_ids.
- DashboardService.fleet(): effective tier = deploy if promoted (overrides registry).
- forward_ingest.evaluate_promotions(dsn): light (reads gate_status + the flag),
  called by cockpit_forward after ingest. One-way; never reverts on a later dip.

Tested: promotes flagged+PASS, not unflagged, not while WAIT, one-way persistent,
fleet tier flips. Full suite green (1837).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 21:31:53 +02:00
jgrusewski
f1916404b4 fix(gate): tolerate weekday-only gaps (equity tracks) via max_gap_days
The reconciliation gate's _has_gaps assumed calendar-continuous booking (crypto is
24/7). A weekday-only US-equity NAV (multistrat) has Fri->Mon 3-day steps + holiday
long weekends (<=4d) — NORMAL, but the gate would flag them as an execution gap at
day 20 -> perpetual false-WAIT (never reconciles). Now _has_gaps takes max_gap_days
from gate_spec (default 1 = crypto, unchanged); multistrat sets 4. A step of
0/negative (duplicate/out-of-order) is still always a hole.

Surfaced verifying the just-added multistrat gate track (14/20 building, real ref
CAGR 9.9% / Sharpe 1.48). Full suite green (1833).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:49:33 +02:00
jgrusewski
f30b9c1871 feat(gate): track the multi-strat book on the cockpit reconciliation gate
Re-adds multistrat_nav (retired in the 2026-06-20 cockpit cleanup) as a forward-
tracked strategy so the TradFi book runs the SAME honest gate as the crypto edges
— the diversification-Sharpe path (uncorrelated equity leg beside crypto).

- multistrat_nav asset: _run_paper_tracker(MultiStratStrategy(YahooDailyClient()),
  persist_backtest_ref=True). Yahoo covers all 6 instruments incl BTC-USD natively.
  persist_backtest_ref publishes the basis-matched ref (full book_series via
  advance(None,{})) so the gate reconciles for real (Fix A/B), not a hollow PASS.
- registry: multistrat entry, reconciliation gate, min_forward_days=20.
- wired into the nightly combined_book_forward_job + cockpit_forward deps.

Full suite green (1832); asset count 20 -> 21.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 09:29:54 +02:00
jgrusewski
fd9534e978 feat(exec): multistrat book on Alpaca — target-weight bridge + crypto BTC leg
Puts the adaptive multi-strat ETF book on the clean execution port:
- multistrat.target_weights(closes): exposes the final-day per-instrument weights
  (L*tw*volnorm_scale) that book_series applies but only collapses into a return.
  Refactored _volnorm via a shared _volnorm_scale so book_series stays byte-identical.
  Tested: sum(w*R[last]) reconstructs book_series's last booked return exactly.
- ExecutionService.rebalance_weights(weights, prices): a direct pre-computed-weights
  entry beside rebalance(book), sharing one _plan engine (gates + fractional sizing).
  Caller owns data<->broker symbol mapping.
- AlpacaBroker crypto-aware: a slash symbol (BTC/USD) -> time_in_force gtc; equities
  stay day. So the book's BTC-USD leg trades on Alpaca crypto alongside the 5 ETFs.
- CLI fxhnt execute-multistrat (maps BTC-USD -> BTC/USD); the alpaca-rebalancer
  CronJob now runs it (suspended until paper keys).

Full suite green (1832); +5 tests. Alpaca-crypto position-symbol form validated on
first paper run.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:33:22 +02:00
jgrusewski
4ada050f7e feat(exec): Alpaca broker adapter + fractional execution (commission-free US-equity leg)
Foundation for a 2nd, uncorrelated execution venue alongside the Bybit crypto book:
- AlpacaBroker (httpx REST, Broker port): account_state + place_order, FRACTIONAL
  market+day orders, is_paper from base_url, supports_fractional=True. httpx test
  seam (MockTransport) — no network.
- ExecutionService fractional-aware: sizes float shares when broker.supports_fractional
  (Alpaca) — precise weights at small capital — else whole shares (IBKR, unchanged).
- AlpacaSettings (paper base_url default; live gated by allow_live). CLI
  .
- Suspended CronJob + credentials scaffold (arm after paper keys, like the Bybit
  testnet leg). Runs the survivor book end-to-end.

The multi-strat ETF book on Alpaca is a documented follow-up (its position logic
isn't on the clean port yet). Full suite green (1827); 6 new tests.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-08 00:00:06 +02:00
jgrusewski
d386c972d9 feat(positioning): capacity + tail-concentration haircuts (capturable, tail-robust)
Two gains-only, adaptive haircuts in _book_breakdown (SSOT for the positioning
forward track + gate ref + 4-edge book), both OFF by default (byte-identical):
- CAPACITY: cap each coin's GAIN by min(1, participation*med_turnover/(capital*|w|))
  — you cannot bank more of an extreme move than you can exit. Barely binds at
  $100k (positioning IS capturable there), caps thin names as capital scales.
- TAIL-CONCENTRATION: clip each coin's positive contribution at K*sigma_book (robust
  MAD scale of the book's own daily returns, K=4), so no single microcap-squeeze day
  dominates the book. Cuts the fat right tail (28% of return was 10 days).

Threaded capacity_capital/tail_cap_k through positioning_returns_from_store ->
_positioning_series -> sleeve_returns_from_store -> BybitFourEdgeStrategy ->
bybit_4edge_backtest_summary + the nav builders; wired s.paper_capital +
POSITIONING_TAIL_CAP_K=4.0 at the asset/persist layer. Validated in-cluster on real
data: off=byte-identical, tail-cap trims CAGR 154->120% (K=4), capacity curve
degrades monotonically (00k Sh2.8 -> 00M Sh-2.3). Full suite green (1821).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 22:45:53 +02:00
jgrusewski
5b79c9416f fix(gate): persist basis-matched backtest refs for individual tracks (Fix B)
Complements Fix A: the individual forward tracks now get a reconciliation-gate
backtest ref built from their OWN forward strategy (correct basis), so the gate
reconciles instead of withholding PASS.

- backtest_summary_from_rows(): shared helper; ref built from a strategy's
  advance(None,{}) inception series (extracted from bybit_4edge_backtest_summary).
- _run_paper_tracker(persist_backtest_ref=True): crypto_tstrend / unlock /
  stablecoin persist a ref from their own strategy — NOT the raw sleeve series
  (crypto_tstrend's forward is 15%-book-vol-targeted, a DIFFERENT basis; a
  sleeve-series ref would understate expected return -> false-PASS). xsfunding
  excluded (live-snapshot, no full-history series).
- positioning ref via bybit_4edge_backtest_summary(sleeves=[positioning]) in the
  persist Job (its forward IS BybitFourEdgeStrategy(sleeves=[positioning]) — same
  basis), reusing the precomputed sleeve series.

Full suite green (1818).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 21:28:50 +02:00
jgrusewski
765402062a fix(gate): withhold PASS when no backtest reference (was a false-PASS)
The reconciliation gate degraded to a bare min-window + clean-exec timer when no
backtest_summary row existed, yet still returned PASS labelled 'reconciles with
backtest' — a hollow/false-PASS. For a real-capital gate the safe error is a
false-WAIT, never a false-PASS. Now backtest=None -> WAIT ('no backtest reference
to reconcile against — PASS withheld'). Reverses the prior degrade-to-PASS test.

Surfaced by positioning showing PASS +1.82% (one +15.3% anomaly day) with no
backtest_summary row; crypto_tstrend + stablecoin_rotation had the same hollow PASS.
Fix B (persist per-strategy backtest refs) makes their gates reconcile for real.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:51:07 +02:00
jgrusewski
12615cf90a refactor(cockpit): retire xvenue_carry forward track (H3) — light retire
xvenue_carry (cross-venue Bybit<->Deribit static carry) is VALIDATED-BUT-NOT-LIVE
with ~0 forward contribution (measured: +0.004%/day, dilutes book CAGR -18pp at
equal weight). Retire the forward-tracked strategy: registry entry, xvenue_carry_nav
asset + build_xvenue_carry_forward_nav, definitions wiring, cockpit backtest-ref
mapping, include_xvenue_carry persist path. KEEP the cross_venue_carry_eval research
lib + deribit_funding_bars ingestion (data stays warm for a possible cross-venue
execution revival). Asset count 21 -> 20; tests updated to assert the retire.
Full suite green (1816).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 20:22:30 +02:00
jgrusewski
eaea1a03cb feat(levered): tail-budgeted shape — carry 40% of gross (bounds -20% dislocation to -8%)
Re-tune _LEVERED_SLEEVE_SHAPE from the Sharpe-max fixed shape (carry ~53%) to a
tail-budgeted one (carry ~40%, non-carry inverse-vol): {tstrend 1.0, unlock 2.2,
xsfunding 3.0, positioning 1.3}. Caps a -20% carry dislocation to ~-8% of the book
(vs -10.5%) while keeping Sharpe ~2.7 (>> naive 2.26). One constant re-tunes the
whole levered chain. A new invariant test pins carry at 40% of gross. 1824 pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-07 00:34:30 +02:00
jgrusewski
b51da1ec2d test(cockpit): verify Replay levered curve renders once the track has >=2 days 2026-07-06 22:20:00 +02:00
jgrusewski
406baa9eb4 feat(cockpit): naive<->levered track toggle in Replay (position-less shadow) 2026-07-05 22:44:42 +02:00
jgrusewski
89b2232aa1 feat(cockpit): levered book pill in the Backtest 2026-07-05 22:40:44 +02:00
jgrusewski
2b95bc262d feat(measured): precompute the bybit_4edge_levered measured curve 2026-07-05 22:39:11 +02:00
jgrusewski
cde42b022f feat(measured): per_coin_book_returns gross-capped leverage_shape 2026-07-05 22:35:57 +02:00
jgrusewski
1fd0942c74 perf(bybit-persist): compute the 4 sleeves once, reuse for both backtest refs (3x -> 1x)
The persist Job recomputed the heavy multi-symbol sleeve walk-forward three
times: once to write bybit_sleeve_ret, once for the naive backtest reference,
once for the levered one. Thread an optional precomputed `sleeve_returns`
through persist_bybit_sleeve_returns, BybitFourEdgeStrategy, and
bybit_4edge_backtest_summary (all default to the prior recompute path, so
existing callers/tests are unchanged); the CLI computes the 4 deploy sleeves
ONCE and reuses them for the row persist + both references. Behavior-neutral
(equivalence tests assert byte-identical summaries + identical persisted rows).
~3x faster; the in-cluster Job now avoids the tunnel entirely. 1818 tests pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 22:00:01 +02:00
jgrusewski
b019204360 fix(bybit-levered): thread max_gross through backtest ref; correct definitions test comment
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 21:20:45 +02:00
jgrusewski
e712f234d0 test(bybit-levered): update definitions asset-count for bybit_4edge_levered_nav (20->21) 2026-07-05 21:10:00 +02:00
jgrusewski
9142c1e96f feat(bybit-levered): persist bybit_4edge_levered backtest reference in the persist Job 2026-07-05 21:00:29 +02:00