Commit Graph

115 Commits

Author SHA1 Message Date
jgrusewski
10c0c4a59f feat(b1): TiingoDailyClient (native adjClose, 33yr); swap equity sleeves Massive->Tiingo
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:50:25 +02:00
jgrusewski
17eca26bb3 test(b1): lock multi-dividend back-adjustment compounding in MassiveDailyClient
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:38:29 +02:00
jgrusewski
6e547dad80 feat(b1): MassiveDailyClient total-return adapter; swap equity sleeves Yahoo->Massive
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:32:51 +02:00
jgrusewski
2e391489bf feat(b1): wire 6 paper-track assets into the Dagster graph
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:18:12 +02:00
jgrusewski
6468b756ba feat(b1): surfer poc paper-forward strategy — faithful port with torch + real signal_sweep/pit_sweep
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 08:03:10 +02:00
jgrusewski
559795b3fd refactor(b1): crossvenue single venue snapshot per run (funding+volume one fetch)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 07:22:25 +02:00
jgrusewski
3a0e6cf06e feat(b1): cross-venue funding paper-forward strategy (faithful port)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 07:16:13 +02:00
jgrusewski
e2168ee0ef fix(b1): funding port faithful — qualify on tf30 (30d mean), crypto-native+hedgeable universe
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 07:08:39 +02:00
jgrusewski
84bfb2110e feat(b1): crypto funding-harvest paper-forward strategy (Binance, faithful port)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 07:02:48 +02:00
jgrusewski
6e004f1749 feat(b1): growth-discipline paper-forward blend (composes multistrat, faithful)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 06:54:27 +02:00
jgrusewski
f2aade706a feat(b1): multistrat adaptive paper-forward book (Yahoo, faithful port)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 06:48:53 +02:00
jgrusewski
2e7ba4764c feat(b1): sixtyforty paper-forward strategy (Yahoo) — template
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 06:40:41 +02:00
jgrusewski
4f9b6fcc0f feat(b1): generic ForwardTracker over a ForwardStrategy port
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-16 06:31:10 +02:00
jgrusewski
07cd72533e fix(orchestration): schedule default_status=RUNNING (auto-arm on fresh deploy) + Argo archiveLogs=false per-template (build no longer fails on unreachable MinIO log-sink)
Both latent bugs: a recreated Dagster instance would silently not arm the nightly schedule; and the
Argo build marked Error on the MinIO log-sink (masking real failures + skipping the auto-deploy step).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 21:23:22 +02:00
jgrusewski
5000333aeb perf(warehouse): bulk ingest in one transaction (~50x faster crypto ingest on PVC)
write_features_bulk writes many symbols in a single transaction (one fsync/checkpoint vs one per
symbol); ingest_crypto_pit collects all 155 symbols then one bulk call. Equivalence test proves
identical result. Targets the ~52min nightly crypto ingest in the Dagster combined-book run.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 19:20:30 +02:00
jgrusewski
f4cfec0f73 feat(orchestration): Definitions + daily combined-book schedule
Wire the 4 B0 assets into combined_book_forward_job and a
ScheduleDefinition (cron 30 23 * * *, UTC) via a Dagster Definitions
object; dagster definitions validate passes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:51:55 +02:00
jgrusewski
c0a4932de9 feat(orchestration): B0 Dagster assets (crypto/futures bars -> nav -> cockpit) + forward_ingest extract
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:40:39 +02:00
jgrusewski
5a75effd8d feat(combined-book): FXHNT_COMBINED_BOOK_DATA_SOURCE flag + source factory; wire CLI
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:27:24 +02:00
jgrusewski
c3c90881e0 refactor(combined-book): read via injected CombinedBookSource (default RawFileSource)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:24:19 +02:00
jgrusewski
c66bffabef feat(combined-book): WarehouseSource reads SSOT; equivalence test proves A->B faithful
- Extend FeatureStore protocol with catalog() and read_panel() so WarehouseSource
  can be typed against the port (mypy strict clean)
- Add silver_ingest_helpers.ingest_crypto_pit — shared bronze→silver→warehouse
  write path for assets and tests
- Implement WarehouseSource in combined_book_source.py; delegates crypto panel
  to read_panel+_panel and futures to WarehousePriceProvider
- Add equivalence test: warehouse-fed panel == raw-file-fed panel (A→B gate)
- 291 tests pass, 0 regressions

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:16:25 +02:00
jgrusewski
9ecb24f82c feat(combined-book): CombinedBookSource port + RawFileSource (existing path) 2026-06-15 11:13:21 +02:00
jgrusewski
7a33082020 feat(warehouse): read_panel — per-symbol epoch-day matrix for one feature
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 11:11:57 +02:00
jgrusewski
461b89eba6 refactor(crypto): extract _panel builder (shared by raw + warehouse sources)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 11:10:13 +02:00
jgrusewski
c76bae9d05 feat(cli): warehouse-ingest + warehouse-catalog commands; warehouse data source
Adds the `warehouse` branch to `_data_provider` (the cutover seam for
hunt/run --data-source warehouse), plus two new commands: `warehouse-ingest`
(bronze→silver→gold for futures and crypto) and `warehouse-catalog`
(per-symbol inventory/freshness view of the SSOT).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:38:17 +02:00
jgrusewski
6f9fb9a9f6 feat(warehouse): catalog/freshness inventory (store.catalog + format_catalog)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:34:55 +02:00
jgrusewski
c203df8d09 fix(warehouse): ingest_bars rejects symbol mismatch (prevent mislabeled bars)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:32:42 +02:00
jgrusewski
ecb9fba115 feat(warehouse): WarehousePriceProvider reads bars as PriceSeries (DataProvider)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:28:40 +02:00
jgrusewski
11fda08fc8 feat(warehouse): WarehouseIngest gold-write service (idempotent) 2026-06-15 00:26:44 +02:00
jgrusewski
fec4a78a83 feat(warehouse): silver_crypto normalizer (close-only daily bars) 2026-06-15 00:25:36 +02:00
jgrusewski
47603755a1 feat(warehouse): silver_futures normalizer (reuses continuous_front_adjust)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:24:41 +02:00
jgrusewski
bd0f6d78fb refactor(dbn_local): extract continuous_front_adjust + read_front_arrays for reuse
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:23:05 +02:00
jgrusewski
ec8b05bfaa feat(warehouse): BarRecord canonical daily-bar value object 2026-06-15 00:20:48 +02:00
jgrusewski
fd1310fc46 feat(config): add warehouse_path setting 2026-06-15 00:19:29 +02:00
jgrusewski
d0e9772dd7 feat(duckdb): migrate + round-trip high/low (COALESCE fallback to close)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:40:56 +02:00
jgrusewski
fd81f1b6c6 feat(dbn_local): ratio-adjusted synthetic high/low via pure _front_to_series helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:35:59 +02:00
jgrusewski
5651a503aa feat(yahoo): adjustment-scaled high/low via pure _build_series helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:28:33 +02:00
jgrusewski
cd9dc4a504 refactor(databento): TYPE_CHECKING pandas annotation + column-absent fallback test
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:26:47 +02:00
jgrusewski
63b78da87f feat(databento): fill NaN-guarded high/low via pure _df_to_series helper
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:23:53 +02:00
jgrusewski
c174c74ad7 feat(strategies): register breakout/seasonality/vol_managed_momentum (3->6 kinds)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:21:08 +02:00
jgrusewski
1b83390e26 feat(strategies): vol_managed_momentum kind (Moreira-Muir, de-risk only)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:18:09 +02:00
jgrusewski
45fab8c1a9 feat(strategies): seasonality kind; move seasonal_signal to domain (DRY, no shift)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:14:32 +02:00
jgrusewski
10f63192b2 feat(strategies): breakout kind (true Donchian channel)
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:09:15 +02:00
jgrusewski
543e4c9f43 feat(strategies): causal rolling_max/rolling_min helpers 2026-06-14 23:06:33 +02:00
jgrusewski
90c25d70b1 fix(models): PriceSeries high/low — copy-on-default (immutability) + strict-mypy field type + test gaps
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 23:05:03 +02:00
jgrusewski
7262238193 feat(models): PriceSeries gains high/low fields defaulting to close 2026-06-14 22:59:51 +02:00
jgrusewski
0689884f8b fix(factory): constrain LlmAnalyst to backtestable kinds (no hallucinated kinds)
Real Ollama test showed qwen2.5:3b inventing invalid strategy kinds (FUTURES_CONTRACTS, MARKET_RETURN, ...)
because the prompt never listed the engine's available() kinds. Now the analyst is given the allowed kinds,
the prompt forbids inventing others, and proposals with an unknown/empty kind are dropped — so the fleet only
emits backtestable hypotheses. The gauntlet still filters the rest.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:44:16 +02:00
jgrusewski
8a63f69130 fix(factory): closure hardening — zero-sum HRP guard, read-only dry-run, single trial-count authority, funnel + E501
I1 (crash): zero-sum HRP ZeroDivisionError — `hrp_sum = sum(...) or 0.0` was a no-op since
`0.0 or 0.0 == 0.0`. Guard BOTH divide sites in `_size_active`: all-allocated branch and
mixed branch now fall back to equal-weight when `hrp_sum <= 0`.

I2 (honest dry-run): `factory-cycle --dry-run` previously ran the full discovery chain
(gather+hunt+forward) and wrote to the store (mark_seen, upsert DISCOVERED, set_status
RETIRED). Gate the entire GENERATE→JUDGE→PROMOTE→PERSIST block behind `if execute:`.
In dry-run, only the FactoryLoop runs in kill-gated mode (promotes nothing) and reports
the current pool state without any store writes.

M1 (double-count + dedup namespace split): analyst fleet AND hunt each called `add_trials`,
and used different key formats (`market:kind:k=v` vs `kind|market|params`). Fix:
- `candidate_key(market, kind, params)` added to `fxhnt.domain.factory` as the single
  canonical key helper (format: `market:kind:k1=v1,k2=v2` — params sorted, 10g floats).
- `Proposal.key()` delegates to `candidate_key` (unified namespace).
- `FleetOrchestrator.hunt` uses `candidate_key` for its `cand_key` (was `kind|sym|params`).
- `AnalystFleet.gather` is now read-only: no `add_trials`, no `mark_seen`. The hunt is the
  single counting authority. gather only filters proposals already in `store.is_seen`.

M2 (funnel double-count): `forward` was sampled BEFORE `loop.allocate_and_promote()` so
sleeves promoted this cycle appeared in both `forward` and `deployed`. Now `forward` is
computed as `fwd_report.forward_tracking - len(res.promoted)` after promotion.

M3 (E501): wrap `assemble` signature in `regime_execution.py` (was 123 chars).

Pre-existing lint (UP042, E501) in `domain/factory/models.py` also fixed:
`StrategyStatus(str, Enum)` → `StrategyStatus(StrEnum)`;
`forward_returns` comment moved above the field to fit in 120 chars.

Tests: 246 pass (was 241). New tests in test_regime_execution.py:
  test_hrp_zero_weights_all_allocated_no_crash
  test_hrp_zero_weight_single_leg_no_crash
  test_hrp_zero_weights_mixed_branch_no_crash

Updated test_analyst_fleet.py: dedup-only contract assertions (trials==0, seen==0 after gather;
fresh proposals not pre-emptively marked seen; canonical key format check).

Updated test_factory_cycle_wiring.py: aligned with M1 — gather is read-only, hunt is the
single counting authority.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:27:23 +02:00
jgrusewski
1ea5149ea1 feat(factory): close autonomous loop — generate→judge→promote→allocate + HRP sizing
Part A: factory-cycle now runs the full chain. Analyst fleet (LlmAnalyst
per specialty, graceful LLM-absent fallback) gathers proposals; a
proposal→Territory bridge groups them by kind and merges with the standing
fixed-grid hunters; FleetOrchestrator.hunt() + ForwardValidationService.run()
execute the judge step; FactoryLoop.allocate_and_promote() does the
diversification-gated promote+HRP step. Funnel counts (proposed/tested/
survived/forward/deployed/retired/global_trials) are persisted via
FactoryStore.record_cycle() in --execute mode with real values from each
layer's report object. Dry-run safe; kill-switch respected.

Part B: RegimeConditionalExecutor.assemble() sizes deployed legs by HRP
weights from the latest factory cycle allocation (injected via hrp_weights
kwarg). Legs not in the allocation (newly promoted) get an equal share of the
unallocated gross budget. No allocation recorded (hrp_weights=None) → previous
equal-weight behaviour preserved. Gross budget is always renormalised.
FactoryStore.latest_weights() added to retrieve the most-recent cycle's HRP
dict (None = no cycle, {} = cycle with no sleeves).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 21:11:52 +02:00
jgrusewski
420d74c142 fix(factory): scale DSR bar by global N + remove gate-bypass promote + silence HRP warning
Fix 1 (CRITICAL): FleetOrchestrator.hunt now passes n_trials =
store.total_trials() + local_eff to evaluate_by_regime so the deflated-
Sharpe bar scales with the full cumulative search across all prior hunts,
not just the current territory's candidate count. The immune system is
no longer decorative. add_trials() was already called once after the loop,
so no double-counting is introduced.

Fix 2 (IMPORTANT): ForwardValidationService._review no longer auto-
promotes a FORWARD sleeve to DEPLOYED when forward_mean() > 0. That path
bypassed the factory_loop's diversification gate entirely and could route
capital around governance. _review now only retires (CUSUM decay or
negative forward mean after min_days); promotion to DEPLOYED is the
factory_loop's sole responsibility. test_forward.py updated accordingly.

Fix 3 (MINOR): hrp._ivp wraps both 1.0/diag(cov) and iv/iv.sum() inside
np.errstate(divide="ignore", invalid="ignore") so a zero-variance asset
no longer emits a RuntimeWarning before the uniform fallback catches it.

New test: tests/integration/test_global_n_flows.py asserts the n_trials
expression (store.total + local_eff) and that hunt() records
n_trials_at_discovery >= 5000 after seeding 5000 prior trials.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:54:16 +02:00
jgrusewski
cbc1cd81b8 feat(factory): cockpit funnel view (funnel counts + global trials + HRP weights)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:37:54 +02:00