Commit Graph

540 Commits

Author SHA1 Message Date
jgrusewski
c4fb3f73eb fix(vrp): exec-twin ladder cap + per-rung sizing + combo BUY-credit sign + backfill master branch + P&L helper tests
The VRP exec twin previously opened a NEW full-envelope spread every run, overwriting the
single-slot book-state and never closing the prior one -- armed weekly it would stack N x
notional. plan_and_record_vrp now maintains a 5-rung ladder (mirrors VrpStrategy.advance):
closes rungs at 50% profit-take or DTE<=1 first, then opens at most one new rung sized at
envelope/ladder (never the full envelope) only when a slot is free. Ladder decisions are
factored into a pure, unit-tested plan_vrp_ladder helper.

Also: IbkrBroker.place_combo used the wrong parent-order action for a net-credit combo (SELL
with a negative limit); switched to BUY with a negative limit per IBKR's combo convention.
fxhnt-opra-backfill.yaml's git-sync cloned the feature branch instead of master (this Job is
applied manually post-merge). Added tests/unit/test_vrp_exec_helpers.py for the previously
untested pure P&L helpers (compute_spread_exec_return/compute_ladder_exec_return/build_pos_state).
Removed the dead --live flag from execute-vrp (plan_and_record_vrp never consulted allow_live;
the paper-envelope refusal guard is the real safety mechanism).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 00:36:11 +02:00
jgrusewski
8d0c6c67f9 feat(vrp): IBKR XSP mleg combo + execute-vrp + backfill-xsp-opra + vrp_exec twin (SUSPENDED)
place_combo (BAG combo, net credit); vrp_exec_record.plan_and_record_vrp (paper-envelope
refuse on non-paper, reuses Task-6 freeze machinery for selection); execute-vrp CLI;
backfill-xsp-opra CLI (2013-> monthly-chunked, cost-guard active for the wide band);
vrp_exec observed registry twin; fxhnt-vrp-rebalancer (suspend:true weekly) +
fxhnt-opra-backfill (manual one-time Job). Both exec paths SUSPENDED/untestable (no options
account, no live OPRA in CI) -> pure/testable contracts unit-tested (combo legs, refusal,
registry, yaml suspend). (Controller committed after self-verify + E402/ruff cleanup.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-13 00:15:36 +02:00
jgrusewski
4c49d94b45 refactor(vrp): batch forward-estimate mark fetch + fix stale band comment (review Minors) 2026-07-12 23:54:05 +02:00
jgrusewski
fe8d8c1ff2 fix(vrp): widen freeze band for held legs + close-on-missing-mark + guard forward-estimate KeyError
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-12 23:49:17 +02:00
jgrusewski
e0db586bbf feat(vrp): vrp_nav asset (freeze OPRA PIT slice -> recompute + real backtest ref) + wiring
Freezes puts (spread band) + near-ATM calls (for the strategy's parity forward) into
xsp_option_bars, then recomputes the vrp track off the frozen table. _xsp_forward_estimate
uses min(sorted(...)) for cross-process determinism. Wires vrp_nav into the nightly job,
Definitions.assets, and cockpit_forward deps. (Controller committed after self-verifying:
subagent completed the work + augmentations but returned the malformed monitor-wait status.)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 23:41:10 +02:00
jgrusewski
03e12004aa feat(vrp): registry vrp entry + migration anchor builder 2026-07-12 23:29:54 +02:00
jgrusewski
3c13ec8f5b fix(vrp): deterministic ATM pair selection (min|C-P| over sorted common strikes) + chain_asof ORDER BY
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 23:24:55 +02:00
jgrusewski
4cc401f83b test(vrp): fix fat-left-tail CVaR test — fill the 10% tail with genuine losses
The brief's test supplied only 2 loss values but cvar_daily averages the worst
ceil(0.10*n) returns (5 slots at n=42), diluting CVaR with positives -> ratio 1.69
< 1.755, unsatisfiable. Rebuilt as a genuinely fat-left VRP-shaped series (45x +0.06,
5x -0.5 at n=50 -> cvar/std ~2.98). VrpStrategy code unchanged (was already correct).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-12 23:06:45 +02:00
jgrusewski
5d7aa3a3f8 feat(vrp): VrpStrategy defined-risk XSP put-spread ladder (recompute off frozen bars)
Adds VrpStrategy.advance() recomputing the daily book entirely off frozen
xsp_option_bars rows (parity forward -> IV inversion -> ~20-delta short
strike, real-mark daily P&L / (n_open * margin)), plus the trading_days()
helper on XspOptionBarsRepo it depends on.

Known issue: test_fat_left_tail_triggers_cvar_floor is a pure-arithmetic
assertion independent of VrpStrategy; with the merged cvar_daily's
ceil(alpha*n) discrete tail count (n=42, alpha=0.10 -> n_tail=5), the given
2-loss-day series structurally cannot exceed the 1.755 threshold (max
achievable ratio ~1.694 by brute force). Left as-authored per no-silent-
change directive; needs a follow-up fix to the test's series shape or
threshold.
2026-07-12 23:03:23 +02:00
jgrusewski
2cea5be70c feat(vrp): xsp_option_bars PIT table + repo (upsert/bars_for/chain_asof) 2026-07-12 22:56:42 +02:00
jgrusewski
e5e9f7e8de style(vrp): drop unused imports in OPRA adapter test (ruff F401) 2026-07-12 22:55:14 +02:00
jgrusewski
1c30e69a50 feat(vrp): OPRA options path on the Databento adapter (chain + bars, cost-guarded) 2026-07-12 22:52:01 +02:00
jgrusewski
1ac3627c80 feat(vrp): pure BS/IV/delta + put-call-parity forward helpers 2026-07-12 22:48:11 +02:00
jgrusewski
4a1d91885d test(cockpit): render assertion -> resolved paper ceiling $1M (not hardcoded $35k)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:59:22 +02:00
jgrusewski
31bc726053 fix(cockpit): overview ceiling reads resolved policy (paper/live), not hardcoded $35k; ruff import-sort
Whole-branch Important: dashboard showed the stale hardcoded ceiling while the engine sizes against
the resolved (paper $1M / live $35k) ceiling. Task-5 Minor: ruff I001 import-sort.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:51:15 +02:00
jgrusewski
689fd3672e feat(alloc): record_allocation uses resolve_allocation_policy (paper/live ceiling, v2 hash)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:38:25 +02:00
jgrusewski
4630491454 test+guard(alloc): assert real CVaR no-op + validate cvar_alpha in _GAUSSIAN_ES (Task 4 Minors)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:33:12 +02:00
jgrusewski
51369199dc feat(alloc): CVaR-aware leverage floor K=min(max_lev,K_vol,K_cvar) (no-op for Gaussian) 2026-07-11 20:26:51 +02:00
jgrusewski
441b4b381a test(alloc): split E702 semicolon line (Task 3 Minor)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:22:54 +02:00
jgrusewski
8ec63cecb5 feat(alloc): cvar_daily full-history expected-shortfall helper 2026-07-11 20:19:56 +02:00
jgrusewski
c0401f10e3 test(alloc): drop unused monkeypatch param (Task 2 Minor)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 20:18:56 +02:00
jgrusewski
3bdb9c5d32 feat(alloc): cvar_alpha + resolve_allocation_policy (paper/live ceiling in hash); version 2 2026-07-11 20:15:15 +02:00
jgrusewski
08477ac5f1 feat(config): AllocationSettings paper/live capital ceilings 2026-07-11 20:10:12 +02:00
jgrusewski
e8f0dd6c4e chore(cleanup): decommission legacy combined-book forward-track (CLI + modules + cron)
The 'combined' crypto-momentum book was retired; its legacy forward-tracking path is
now dead (the fxhnt-forward-cronjob was long since replaced by the Dagster deterministic
engine, and is already gone from the cluster). Removed: the 'forward-track' CLI command +
_FUTURES_UNIVERSE, the combined_book / combined_book_factory / combined_book_source
modules, CombinedBookStrategy + CombinedBookForwardTracker (KEEPING the load-bearing
ForwardTracker base used by the recompute engine + bybit tracks), the combined_book_*
config fields, and 5 combined-book-dedicated test files. MomentumVrpStrategy kept (a
tested strategy primitive, not a combined_book module).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 11:11:40 +02:00
jgrusewski
391400f233 chore(strategy): retire vestigial 'combined' crypto-momentum book from nightly + registry
The broad-Binance-universe momentum book (venue binance+glbx) was a survivorship/
microcap mirage superseded by the isolated crypto_tstrend edge + bybit_4edge. Removed
the combined_forward_nav Dagster asset (+ its cockpit_forward/paper_book_snapshot deps),
the registry entry (DB registry row auto-prunes via _seed_registry), the dashboard
headline preference, and the dead migration builder. CombinedBook modules retained
(still used by the forward-track CLI). Test fixtures repointed combined -> crypto_tstrend.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 10:54:07 +02:00
jgrusewski
da91c412ab fix(cli): distinct paper-envelope refuse message + reject negative --paper-envelope (Task 9 review)
Two execute-CLI gaps from the C3 port:

- `execute_multistrat`'s generic `except Exception` caught the ValueError `plan_and_record` raises
  when a paper-envelope is refused (account not paper) and printed it as a connectivity failure
  ("broker error: ... reachable? ... creds/gateway set?") — misleading for a deliberate safety
  refusal. `execute_bybit` had no try/except at all, so the same refusal from `run_bybit_testnet`
  surfaced as a raw traceback. Both commands now catch `ValueError` distinctly, print
  "paper-envelope refused: <msg>", and exit 1 — same exit code and zero orders placed, just an
  honest message.

- `_resolve_paper_envelope` silently fell back to the config default whenever the flag was <= 0.0,
  so `--paper-envelope -5` looked identical to "unset" and hid an operator typo. A negative flag
  now raises `typer.BadParameter` instead of falling through.

Extends test_cli_execute_helpers.py: the negative-envelope rejection, and two new tests (no live
broker — YahooDataProvider/AlpacaBroker faked, run_bybit_testnet faked) proving each command's
refuse path prints the distinct message and never reaches order placement.
2026-07-11 02:15:12 +02:00
jgrusewski
7c05189aa2 test(exec): restore behavioral coverage lost porting the bybit testnet leg off Dagster (Task 9 review)
Task 7 deleted tests/integration/test_bybit_testnet_job_wiring.py wholesale, taking with it the
regression tests for 4 named past bugs the ported `run_bybit_testnet` code still contains but was
left untested: unlock-tier misclassification on the bare-vs-USDT-suffixed symbol (FIX 1),
mean_timing_drift dividing by the wrong denominator when a fill has no book_mark (FIX 2), the
recorded fill ts using the record-step wall clock instead of the exchange fill time (FIX 3), and
the open-orders resting-guard not aborting placement (FIX 4) — plus the per-day NAV-marker
idempotency no-op and the normal-path fills+NAV happy path. Ports all of them onto
`run_bybit_testnet` directly (not the deleted Dagster assets), patching the module's own
`fxhnt.application.bybit_testnet_run` seams instead of `adapters.orchestration.assets`. Also adds
a new run-level test for the paper-envelope refuse (non-paper account + paper_envelope>0 raises
ValueError before any order is placed) — the case the CLI-level Minor fixes in the next commit
need to stay distinct from a connectivity error.

Deliberately does NOT port `test_job_exists_with_two_assets_and_not_in_combined` or
`test_schedule_registered_on_its_own_job_stopped` — those tested the deleted Dagster job/schedule
and their absence is already asserted in test_orchestration_definitions.py.
2026-07-11 02:15:02 +02:00
jgrusewski
58e39955ba feat(cockpit): surface recorded exec venue in Executed-reality badge (fallback to configured) 2026-07-11 01:36:54 +02:00
jgrusewski
26e80df075 test(config): drop schedule_cron assertions (field removed, Task 7 Minor)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 01:27:15 +02:00
jgrusewski
185e504028 refactor(dagster): remove bybit exec assets/job/schedule (leg now CLI-driven)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 01:23:34 +02:00
jgrusewski
59439bfcd9 feat(cli): execute-bybit command (bybit testnet exec off Dagster, --paper-envelope) 2026-07-11 01:13:44 +02:00
jgrusewski
1c9cec8e29 feat(exec): port bybit testnet leg to run_bybit_testnet (faithful, +paper-envelope +venue)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 01:06:45 +02:00
jgrusewski
4837a1fe8e feat(exec): bybit paper-envelope helper (testnet-only) + venue in book-state 2026-07-11 00:58:52 +02:00
jgrusewski
8e54d6dc1d feat(cli): execute-multistrat --paper-envelope flag + record real exec venue 2026-07-11 00:54:06 +02:00
jgrusewski
5953272f88 test(config): drop redundant local Settings imports (Task 1 Minor)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-11 00:48:59 +02:00
jgrusewski
e6713367b1 feat(exec): multistrat paper-envelope gate (bypasses B2a, paper-only) + venue in book-state 2026-07-11 00:47:15 +02:00
jgrusewski
730d3dbf7d feat(config): PaperValidationSettings.envelope (paper-only exec envelope, default off) 2026-07-11 00:33:29 +02:00
jgrusewski
146e1733f3 test(cockpit): cover latest_testnet_nav + executed-reality detail block (review)
Adds two test cases:
1. Test that latest_testnet_nav() returns the most-recent row by run_date
2. Test that the Executed reality detail block renders with exec/modeled return figures

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:24:57 +02:00
jgrusewski
7dd4a813e4 feat(cockpit): detail page funding / allocation / executed-reality blocks
Adds the per-edge lifecycle blocks (funding health, allocation, executed
reality) to the strategy detail page, plus a minimal latest_testnet_nav()
reader on BybitTestnetRepo to surface mean exec slippage for the bybit
executed twin.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:20:18 +02:00
jgrusewski
e15b648f24 feat(cockpit): overview capital meter + allocation/funding columns + nested exec twin
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:13:55 +02:00
jgrusewski
6899c2787f feat(cockpit): mobile bottom-tab nav + funding/meter/exec CSS tokens
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:09:11 +02:00
jgrusewski
94674ddfe6 feat(cockpit): read-model surfaces allocation, funding, exec-vs-modeled pairing
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 12:02:00 +02:00
jgrusewski
05f0b1439e feat(cockpit): repo reads for allocation + funding rows
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 11:58:04 +02:00
jgrusewski
110d1bd3b7 fix(bybit): missing-prior-mark 0-pnl (not full notional) + funding-cursor precision + flatten test (C2 final review)
Critical: a held symbol absent from PRIOR marks (rotated out of the crypto
universe then back in) was booking its FULL notional as P&L in
compute_crypto_exec_return, since a missing prior mark fell back to price 0.
Fix falls back to today's mark instead, so a missing prior mark yields 0 P&L
for that symbol this period. Also: document the accepted re-entry-day fee
gap, advance the funding cursor to the reconcile's funding-query timestamp
(no gap to the next period's funding_since), and strengthen the flatten
test to use a nonzero sleeve weight with equity=0, pinning that equity=0
alone flattens.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 11:06:37 +02:00
jgrusewski
f6b42aa740 fix(bybit): observed-mode pin + skip kill-switch funding call + flatten test (C2 review)
Task 5 review fixes: update the stale observed-track invariant pin (Task 3
added bybit_4edge_exec), move funding_since off the kill-switch dry-run
path so it doesn't make a wasted network call, and add unit coverage
proving plan_orders flattens a held position when equity=0 (de-funded/
killswitched edge).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:53:17 +02:00
jgrusewski
370c0be80b test(bybit): seed bybit_4edge B2a allocation in testnet job-wiring fixtures
bybit_testnet_reconcile now sizes plan_orders to the B2a/B3 envelope
(min(current_allocation, equity)) instead of raw equity (prior commit).
These pre-existing fixtures never seeded a bybit_4edge allocation row, so
the envelope collapsed to 0 and 6 of these tests started asserting on a
flattened (zero-order) book. Seed an allocation well above the fake
equity by default so envelope == equity, preserving the sizing these
tests were written against.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:33:35 +02:00
jgrusewski
371f795161 feat(bybit): B2a/B3-envelope-driven testnet leg + record bybit_4edge_exec observed track (C2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:33:31 +02:00
jgrusewski
9f0322c177 feat(bybit): record_bybit_exec_track — book the executed crypto track via A run_track (C2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:22:59 +02:00
jgrusewski
b3b3b71341 feat(bybit): register bybit_4edge_exec observed track + reconciliation ref alias (C2)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:17:52 +02:00
jgrusewski
397f734f7a fix(bybit): apply_fills case-normalizes side + fails loud on unknown (C2 review)
Replace exact-match side check with case-insensitive comparison and explicit
ValueError on unrecognized fill side. Prevents silent misclassification of
differently-cased sides on a capital-accounting path.

- apply_fills now normalizes f["side"] to uppercase before checking
- Raises ValueError with fill side repr on unknown side (not BUY/SELL)
- Added test_apply_fills_case_insensitive_side: lowercase/mixed-case sides
- Added test_apply_fills_rejects_unknown_side: ValueError on garbage side

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-10 10:16:19 +02:00