Commit Graph

107 Commits

Author SHA1 Message Date
jgrusewski
86eadae42f fix(factory): capital-correct loop — record_cycle, sequential HRP-weighted admission, kill-switch, tests
Fix 1: wire record_cycle in factory-cycle --execute so the funnel table is populated.
  LoopResult gains deployed_before/deployed_after/forward_count; cli.py calls
  fs.record_cycle(proposed=forward_count, ...) and record_allocation after the loop.

Fix 2+4: replace equal-weight book proxy with HRP-weighted blend of deployed sleeves;
  rewrite admission as sequential — each candidate is re-gated against the running mean
  of already-admitted-this-cycle candidates, so two candidates uncorrelated to the book
  but correlated to each other cannot both be admitted in one cycle.

Fix 3: HRP inclusion now requires >= min_forward_days (was >= 2). Folded into the
  final rets comprehension in allocate_and_promote.

Fix 5: StrategyStoreLoopAdapter.set_status now asserts status == "DEPLOYED" so a future
  demotion path cannot silently promote via the loop adapter.

Fix 6: persisted kill-switch — FactoryFlagRow ORM model added to cockpit_models.py;
  FactoryStore.set_kill(on)/is_killed() read/write a key="kill" row; factory-cycle
  folds db kill with env kill; factory-flatten renamed to factory-halt; factory-resume
  and factory-status commands added.

Fix 7: sleeve returns fetched once per sleeve in the final HRP comprehension via a
  shared dict, avoiding double store I/O.

Fix 8: three new integration tests covering min_forward_days filter, empty-book
  founding-admit-then-gate, and mutual-correlation blocking within a cycle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:24:50 +02:00
jgrusewski
2f8c384d26 feat(factory): wire loop to SqlStrategyStore + CLI factory-cycle/flatten
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:11:24 +02:00
jgrusewski
21b9e63839 feat(factory): diversification-gated promotion + HRP allocation loop
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:10:18 +02:00
jgrusewski
f18c824198 feat(factory): funnel + allocation persistence (cockpit DB)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:09:30 +02:00
jgrusewski
7a6ab8e723 feat(factory): promotion governance (caps + kill-switch budget)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:08:35 +02:00
jgrusewski
5f5c2a693f fix(factory): fail-safe diversification core — HRP uniform fallback, corr epsilon + empty guard, gate reason
Fix 1 (HRP, IMPORTANT): both the main bisection path and the except-branch fallback in
hrp_weights now guard the weight vector after computation — if any weight is non-finite,
negative, or the sum is ≤ 0 (triggered by a zero-variance asset causing 1/0→inf in _ivp),
the result is replaced with a uniform distribution (1/n each), which is always a valid
allocation. Prevents NaN weights from silently propagating to capital allocation.

Fix 2 (correlation, MINOR): replace exact `std() == 0` zero-vol guards in full_correlation
and left_tail_correlation with `std() < 1e-12`, so arrays with near-constant float-noise
(std ~1e-17) return NaN instead of a garbage corrcoef value.

Fix 3 (gate, MINOR): split the formerly combined `not isfinite(mg) or mg < min_marginal`
branch into two: a non-finite marginal now reports "marginal Sharpe unestimable — fail-safe
reject" (distinct from the "< threshold" message), making log/alert triage unambiguous.
Admit/reject outcome is unchanged.

Fix 4 (correlation, MINOR): _aligned now returns two empty arrays immediately when either
input has length 0, guarding against the a[-0:] == a[:] footgun that would otherwise return
the full array. Downstream len < 2 guards then produce NaN as designed.

New tests: test_hrp_zero_vol_asset_falls_back_to_valid, test_near_constant_returns_nan,
test_empty_input_is_nan_not_raise, test_unestimable_marginal_reason_is_distinct.
All 203 tests pass; ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 20:06:52 +02:00
jgrusewski
7e45f3f2b6 test(factory): lock DSR bar rises with trial count (FST immune system)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:54:57 +02:00
jgrusewski
38293d5537 feat(factory): diversification gate (left-tail corr + marginal, fail-safe)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:54:38 +02:00
jgrusewski
e48c0c2094 feat(factory): marginal Sharpe contribution (selection objective)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:54:08 +02:00
jgrusewski
90511dbb83 feat(factory): Hierarchical Risk Parity weights (scipy to_tree, ivp fallback)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:53:41 +02:00
jgrusewski
d7a79ced21 feat(factory): full-sample + left-tail correlation (crisis-relevant)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:53:02 +02:00
jgrusewski
4a73c99db7 feat(factory): scipy dep + FactorySettings (safe diversification/governance defaults)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:52:26 +02:00
jgrusewski
652340325d plan(factory): ongoing diversification-aware edge-factory — 13 TDD tasks, 5 milestones
M1 diversification core (left-tail corr, HRP via scipy to_tree, marginal Sharpe, gate; FST DSR verification)
M2 governance + funnel persistence + diversification-gated promotion/HRP-allocation loop + CLI
M3 domain-analyst fleet (dedup + honest global trial count) M4 cockpit funnel view M5 in-cluster CronJob.
Reuses the existing factory skeleton + gauntlet.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:40:18 +02:00
jgrusewski
2d07b18525 docs(factory): design spec — ongoing diversification-aware edge-factory
Research-grounded (Bailey/LdP False Strategy Theorem -> SR* scales with honest global N; Harvey-Liu-Zhu
factor-zoo t>3 discipline; T.RowePrice left-tail correlation; LdP HRP + Raffinot HERC; CFA rolling re-allocation).
Closed loop: analyst-fleet -> gauntlet -> diversification-gate (left-tail ρ + marginal contribution) ->
paper-forward -> autonomous promotion (governance: kill-switch/caps) -> HRP allocation -> edge-decay retirement,
in-cluster daily, cockpit funnel view. 5 milestones; reuses the existing factory skeleton.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 19:34:39 +02:00
jgrusewski
1a069ace68 merge: live crypto execution layer (Binance USDM perps, testnet-first)
Hexagonal execution layer: crypto_exchange port + ccxt adapter (rate-limit governor, idempotent client ids,
testnet sandbox), pure smart router (maker->IOC, participation/depth caps, slippage abort, reduce-only), full
risk layer (capacity + gates + edge-decay×Kelly + kill-switch + drawdown CB, fail-safe on NaN), orchestrator
+ reconciliation + TCA + fills store + CLI. 19 commits, 184 tests, money-grade reviewed (caught fail-open NaN
gates, IOC over-fill, false-drift halt — all fixed). Final review: SHIP-READY (testnet). M5 testnet validation
pending (needs Binance testnet keys).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 18:33:28 +02:00
jgrusewski
124edda582 fix(exec): stable data-derived rebalance_id + rate-limit signal + cover/drift invariant tests
Fix 1: derive rebalance_id from last panel day (reb<day_int>) instead of
wall-clock strftime so crash+re-run in a different minute reuses the same
deterministic clientOrderIds — Binance dedupes on clientOrderId → idempotent.

Fix 2: add rate_limited: bool field to RebalancePlan; set True whenever any
placed Fill has status == "REJECTED" (budget-exhausted leg); surface in CLI echo
so operators see exhaustion explicitly rather than learning via a drift halt.

Fix 3: test_reduce_only_at_exact_cover_boundary locks the boundary invariant
that an order sized to exactly cover an open position (qty == |current_qty|) is
always flagged reduce_only for both SELL-covers-long and BUY-covers-short cases.

Fix 4: test_reconcile_flags_unexpected_drift_on_untraded_symbol proves
reconciliation catches drift on holdings the orchestrator never touched this
cycle (the actual-union path in diff_positions covers untraded symbols too).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:39:29 +02:00
jgrusewski
abdc9b8dc8 fix(exec): capital-risk fixes — authoritative IOC sizing, accumulate all legs, θ=0 hold, true arrival mid, dry-run gate report, rate-budget window
C2 (over-fill): after cancel, fetch `order_status` for the authoritative post-cancel
fill qty instead of the stale place-response; maker may keep filling during the sleep
so the stale qty would size the IOC too large.

C1 (false-halt): accumulate BOTH the maker AND the IOC fills into `intended` so
reconciliation sees the full executed quantity and does not false-halt on the IOC leg.

I3 (dry-run observability): `block_reason` is now populated and returned even when
`execute=False`, so monitoring can see gate trips on dry-runs.

I4 (arrival mid): capture the true decision-time `book.mid` per symbol while building
route inputs; pass that to `_persist` / TCA instead of the stale maker/abort blend.

I5 (θ=0 hold): `gross_scaler == 0` (EMA/Kelly warm-up or NaN-recovery) now returns
early with `block_reason="zero_gross_scale_hold"` rather than flattening the book.
Deliberate exits belong to the kill-switch / crypto-flatten path.

M7 (rate-budget window): `RateBudget.try_order` now resets the order counter after a
60-second window so a long-running process never permanently exhausts the per-minute budget.

Tests: add FakeExchangePartialMaker + FakeExchangeMakerFillsDuringSleep variants and
three new integration tests exercising the full maker→cancel→order_status→IOC path
(previously zero coverage); add SELL-above-mid savings case to test_tca; add short
position drift + expected-position-fully-closed cases to test_reconciliation.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:29:37 +02:00
jgrusewski
64b0204703 feat(exec): CLI crypto-rebalance/positions/flatten
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:18:12 +02:00
jgrusewski
db9f570693 feat(exec): orchestrator (gates->router->maker/IOC->reconcile->persist) + fills store
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:15:30 +02:00
jgrusewski
87f34d8c23 feat(exec): pure position reconciliation (drift detection -> halt)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:13:50 +02:00
jgrusewski
13f1b46678 feat(exec): pure TCA (implementation shortfall bps)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:13:28 +02:00
jgrusewski
df14b8a92f fix(exec): fail-safe risk gates — NaN/misconfig guards (no fail-open to max exposure)
Any non-finite input to gross_scaler now returns 0.0 (flat) instead of silently
propagating through min()/max() to the non-NaN argument and potentially inverting
to maximum exposure. A negative/misconfigured gross_cap is clamped to 0.0 (not
negative). pretrade_block blocks on NaN session_pnl_pct ("session_pnl_unknown")
and on a misconfigured session_dd that is non-finite or non-negative
("bad_session_dd_config"). cap_weights zeros all outputs on non-finite NLV, zeros
individual symbols on non-finite weights, and skips the ADV cap when ADV is
non-finite (rather than weakening the per_symbol_cap). GateConfig gains kelly_cap
field for cohesion. Locked by 13 new NaN/edge-case unit tests (166 total, all pass).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:11:58 +02:00
jgrusewski
890824d040 feat(exec): pure risk gates + edge-decay×Kelly gross scaler
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:05:26 +02:00
jgrusewski
c1019f08c7 feat(exec): pure capacity caps (per-symbol + ADV)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:04:35 +02:00
jgrusewski
3d5291ffdb fix(exec): clear remaining minors — zip strict, rate-budget margin test, mid-sizing rationale
- crypto_momentum_research.py: add strict=True to zip(day, close) in load_crypto_panel
  so mismatched-length arrays raise immediately instead of silently truncating the panel
- crypto_momentum_research.py: extract turnover variable to fix E501 (line 64, 126→≤120 chars)
- test_binance_ccxt_helpers.py: add test_rate_budget_production_weight_margin that exercises
  RateBudget(max_orders=int(1200*0.9), max_weight=int(2400*0.9)) — the exact args used in
  BinanceUsdmExchange.__init__ — and asserts the 2160 effective ceiling (boundary 2159/2161)
- smart_router.py: add clarifying comment on qty=usd/mid explaining that MID is correct
  (both target_usd and current notional are mark-to-mid; changing to limit price breaks
  mark-to-mid consistency)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:03:11 +02:00
jgrusewski
161c9aead9 test(exec): rigorous smart-router assertions + no_book zero-depth guard
Extend `_plan_one` to treat zero depth on the relevant side as `no_book`
(computed before the depth-usd calc so it never reaches the dust branch);
add a comment that `round_qty` floors make qty-overshooting impossible.

Tests: replace non-falsifiable qty assertion with exact `abs(p.qty-4.995)<1e-9`;
rename old dust test to `test_min_notional_skip` (matches its skip_reason);
add `test_dust_skip`, `test_no_book_when_zero_depth`,
`test_reduce_only_false_when_increasing`, `test_reduce_only_false_when_flipping`.
9 tests total, all pass; full suite 123 passed; ruff clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 17:00:35 +02:00
jgrusewski
69f41ce791 feat(exec): pure smart router (sizing, caps, maker+abort pricing, reduce-only)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:56:11 +02:00
jgrusewski
522cbbd517 fix(exec): honor Retry-After on 429 + defensive position side guard
_backoff now reads last_response_headers for a Retry-After value and
prefers it (capped at 60 s) over the blind 2^attempt fallback when a
rate-limit error is caught.

positions() now explicitly checks side ∈ {"long","short"} and skips
any position with an unrecognized side, preventing silent sign errors
from None/unknown values being coerced to -1.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:54:27 +02:00
jgrusewski
fcd12cb9ed feat(exec): binance_ccxt adapter — rate-limit governor, idempotent ids, testnet sandbox
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:48:28 +02:00
jgrusewski
ba053b19ee feat(exec): latest_target_weights — current per-symbol targets for execution
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:46:45 +02:00
jgrusewski
0b1f7ad487 feat(exec): pure exchange-filter rounding (step/tick/min-notional)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:46:05 +02:00
jgrusewski
e6a2e9848e feat(exec): crypto_exchange port (DTOs + Protocol)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:45:36 +02:00
jgrusewski
7723aeee1d feat(exec): crypto dep + BinanceSettings (safe defaults: testnet on, live off)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:45:01 +02:00
jgrusewski
d70696e6ad plan(exec): crypto execution layer — 13 TDD tasks, 5 milestones
M1 port+ccxt-adapter (rate-limit governor, idempotency, testnet) · M2 pure smart router (maker->IOC, caps,
slippage abort) · M3 risk gates + capacity + edge-decay×Kelly · M4 TCA + reconciliation + orchestrator +
cockpit fill persistence + CLI · M5 testnet end-to-end. Research-grounded; intraday slicing deferred (measure
TCA first).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:42:00 +02:00
jgrusewski
cd3647f5d9 docs(exec): design spec — live crypto execution layer (Binance USDM perps, ccxt)
Research-grounded (rate limits 2400wt/1200ord per min + 418 ban risk, clientOrderId idempotency, LOT/PRICE/
MIN_NOTIONAL filters, maker-first+POV slicing saves 50-90bps, ccxt testnet). Hexagonal: crypto_exchange port +
binance_ccxt adapter w/ rate-limit governor, pure smart_router (maker->IOC, slicing, slippage abort), full
risk layer (gross/per-symbol/leverage caps + edge-decay×Kelly scaler + kill-switch + drawdown CB), reconcile +
TCA, testnet-first w/ allow_live gate. 5 milestones.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 16:33:27 +02:00
jgrusewski
857d4819d6 perf(fetch): rolling-window futures fetch (~2y) instead of full 16y history
Forward-tracking only needs recent bars (>250d signal lookback); re-pulling all-expiry history weekly cost
~$18.70/run. Rolling FXHNT_DATABENTO_FETCH_YEARS window (default 2) cuts it ~90% with identical forward signals.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:56:00 +02:00
jgrusewski
00e0f1f934 feat(tailnet): add TCP:80 forward to cockpit serve (for dashboard.fxhnt.ai vanity via gitlab proxy)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:42:10 +02:00
jgrusewski
eda742a624 fix(tailnet): expose cockpit via in-pod tailscale userspace sidecar (CGNAT-safe)
Pod CIDR 100.64.0.0/15 overlaps Tailscale CGNAT (100.64.0.0/10), so a kernel-mode tailscale proxy hijacks
cross-node pod routes and can't reach the Service (the old separate proxy failed identically to the cluster's
web-dashboard). Fix: tailscale userspace sidecar INSIDE the cockpit pod, serving tailnet -> 127.0.0.1:8080
(no kernel routes, localhost target). Reachable at https://fxhnt-dashboard*.tailff20e.ts.net with MagicDNS TLS.
Netpol adds public 443/UDP egress for the sidecar's coordination/DERP.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:23:54 +02:00
jgrusewski
af2777ae79 fix(netpol): dashboard egress via postgres podSelector (Cilium ipBlock doesn't match in-cluster identity)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:08:51 +02:00
jgrusewski
990287a85b fix(cockpit): package web assets in wheel + cockpit NetworkPolicies + pod labels
- pyproject package-data ships templates/*.html + static/* (logo, htmx) — pip install omitted them, crashing serve
- fxhnt-dashboard/fxhnt-forward egress NetworkPolicies (postgres 5432; cronjob also DNS + public 443 for fetch)
- part-of:foxhunt on dashboard+cronjob pods (postgres ingress allow); TS proxy intentionally unlabeled (open egress)

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 13:48:35 +02:00
jgrusewski
8ba71ed7bc fix(argo): disable log archival (MinIO sink unreachable from ci pool)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 13:31:16 +02:00
jgrusewski
be37128e0a deploy(cockpit): Argo CI/CD (in-cluster Kaniko build + deploy) + real-secret manifests
Argo WorkflowTemplate fxhnt-cockpit mirrors foxhunt's build-ci-image (Kaniko) + compile-and-deploy (kubectl):
clones root/fxhnt over in-cluster gitlab-shell, builds infra/docker/fxhnt.Dockerfile to the internal registry
(native registry+token access, no laptop push, no private-CA trust), applies manifests + rolls the dashboard.
Manifests corrected to the cluster's real secrets: DSN via PGPASSWORD (db-credentials), DATABENTO via
databento-credentials, TS via tailscale-auth; image -> internal gitlab registry.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 13:23:29 +02:00
jgrusewski
4832161c9a merge: fxhnt cockpit dashboard + edge-pipeline containerization
Postgres-backed in-cluster cockpit (FastAPI+HTMX) over the in-cluster TimescaleDB: forward-track fleet view,
period-aware raw rolling means (daily/weekly/monthly, no normalization), factory population. Combined-book
edge pipeline ported into fxhnt (crypto + futures fetchers) so the daily loop runs fully in-cluster via a
CronJob (fetch -> forward-track -> ingest); dashboard Deployment behind a Tailscale proxy. 28 commits,
103 tests, reviewed per milestone. Live deploy (image push + kubectl apply + dashboard.fxhnt.ai re-route)
deferred to an explicit deploy step.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:55:26 +02:00
jgrusewski
754c423a86 deploy(cockpit): CronJob full loop — fetch -> forward-track -> ingest (futures weekly)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:31:05 +02:00
jgrusewski
eaa4e699b2 fix(fetch): clean missing-key error + day-aligned funding array
Fix A: `fxhnt fetch --futures` with no DATABENTO_API_KEY now exits 1
with a clear message instead of surfacing a RuntimeError traceback;
guard runs before any network call so crypto still proceeds normally.

Fix B: `fetch_crypto_pit` writes `funding` as a per-day array aligned
to `kd` (same length as `day`/`close`), dropping the separate
`funding_day` key that was unaligned with the price axis.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:30:07 +02:00
jgrusewski
fa10f92d7e feat(fetch): fxhnt fetch CLI (crypto/futures into data-dir)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:24:51 +02:00
jgrusewski
2f4fef18f6 feat(fetch): port futures fetcher into fxhnt (Databento, cost-gated, offline-testable)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:23:09 +02:00
jgrusewski
e8f62c87ff feat(fetch): port crypto_pit fetcher into fxhnt (Binance public, refresh, offline-testable)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:22:09 +02:00
jgrusewski
bce04d0031 plan(fetch): edge-pipeline containerization spec + plan (combined book only)
Port the two fetchers (Binance crypto / Databento futures) into fxhnt as 'fxhnt fetch' so the combined-book
daily loop runs fully in-cluster: fetch -> forward-track -> ingest -> dashboard. Edge-only scope; funding +
other trackers deferred. 4 TDD tasks (offline-testable fetchers) + CronJob full-loop update.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:20:32 +02:00
jgrusewski
5ea49466cb chore(cockpit): trim over-length comment (E501)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 12:06:51 +02:00