5925 Commits

Author SHA1 Message Date
jgrusewski
8213f29a5b Merge: relocate platform IaC to fxhnt (Phase 2D) 2026-06-21 18:21:37 +02:00
jgrusewski
bf9a6d20ee chore(infra): relocate platform IaC to fxhnt (Phase 2D)
Platform terraform (live+modules) + k8s manifests moved to fxhnt (now the IaC home).
Rust-only remnants kept: docker build images, gpu-taint.yaml, Rust scripts. foxhunt
being archived; history retained. Live platform IaC now in the fxhnt repo.
2026-06-21 18:21:34 +02:00
jgrusewski
ffc83da643 docs: plan — relocate platform IaC to fxhnt, archive foxhunt (Phase 2D), inline+gated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:14:58 +02:00
jgrusewski
b017daf04b docs: spec — relocate platform IaC foxhunt->fxhnt, archive foxhunt (Phase 2D)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:12:38 +02:00
jgrusewski
b566b2c194 Merge: decommission GitLab compute + fix minio.fxhnt.ai (Phase 2C)
GitLab fully removed (helm + dead events/cronjobs + :5050 proxy block + dead manifests);
~5.5GiB RAM / 12 pods reclaimed. Data retained as cold backup (gitaly PVC + buckets +
secrets). minio.fxhnt.ai admitted to the tailnet proxy. Gitea-only git host; auto-deploy verified.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:07:35 +02:00
jgrusewski
c6d0d2ab38 chore(infra): decommission GitLab compute — keep data as cold backup (Phase 2C)
helm uninstall gitlab + foxhunt-agent (~5.5GiB RAM / 12 pods freed). Removed :5050
registry block from the (now Gitea) tailscale proxy; deleted dead Argo events
(gitlab-push ES, ci-pipeline-trigger sensor) + dead gitlab-pat cronjobs; removed dead
GitLab manifests (values.yaml, pat-rotation.yaml, postgres-init.yaml).

RETAINED (cold backup): gitaly PVC (50Gi), gitlab MinIO+Scaleway buckets, 25 gitlab-* secrets.
KEPT: tailscale-proxy.yaml (serves Gitea + all *.fxhnt.ai), grafana-values.yaml (Phase 2E).
Also fixed minio.fxhnt.ai (proxy admitted to minio ingress netpol).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 18:06:55 +02:00
jgrusewski
e86384ff99 fix(infra): admit tailscale proxy to minio ingress netpol (minio.fxhnt.ai S3 API)
minio.fxhnt.ai returned 000 — proxy not in minio's ingress allow-list. Same pattern as
gitea/postgres. Now reachable over the tailnet (health 200).
2026-06-21 18:01:41 +02:00
jgrusewski
35e4078989 docs: plan — decommission GitLab compute, cold-backup data (Phase 2C), inline+gated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 17:51:32 +02:00
jgrusewski
9a7707c749 docs: spec — decommission GitLab compute, retain data as cold backup (Phase 2C)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 17:49:55 +02:00
jgrusewski
f0c4de66ad Merge: Gitea replaces GitLab + cockpit registry to Scaleway (Phase 2B)
Gitea (chart + existing postgres) is the git host behind git.fxhnt.ai (tailnet proxy,
SSH :22); both repos migrated (foxhunt archived); cockpit image -> Scaleway Container
Registry; build clones Gitea; Gitea webhook -> Argo auto-deploy. GitLab now idle (removed in 2C).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 17:40:05 +02:00
jgrusewski
ad3637303f feat(infra): Gitea push webhook -> Argo Events cockpit auto-deploy (Phase 2B Task 6)
- gitea-push eventsource (:12000/push) + gitea-deploy sensor (filter ref main/master ->
  submit fxhnt-cockpit, commit-sha from body.after). Pods NOT part-of:foxhunt (stay
  default-allow, matching working workflow-trigger pattern).
- gitea netpol: egress 12000 namespace-wide (eventsource not part-of -> can't target by label)
- gitea values: webhook.ALLOWED_HOST_LIST=private (Gitea blocked delivery to in-cluster 10.32.x)

Verified: push to fxhnt master auto-fires a cockpit build+deploy.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 17:39:44 +02:00
jgrusewski
c284158dfb fix(infra): gitea SSH ports — rootless listens on 2222 (Phase 2B)
- gitea-sshd svc targetPort 22->2222 (rootless gitea binds non-privileged 2222)
- netpol ingress ssh port 22->2222 (NetworkPolicy ports are POD ports, not svc ports)
SSH over ssh://git@git.fxhnt.ai now works (port 22 via proxy socat -> 2222).
2026-06-21 17:04:42 +02:00
jgrusewski
bf9558539a fix(infra): gitea mem limit 512Mi->2Gi + Recreate strategy (Phase 2B)
- 2Gi: indexing the 876MB foxhunt pack OOMKilled at 512Mi (exit 137)
- Recreate: RWO PVC (sbs-default-retain) can't RollingUpdate (Multi-Attach deadlock)
2026-06-21 17:03:04 +02:00
jgrusewski
79f2ad94a4 feat(infra): cut git.fxhnt.ai over to Gitea via tailnet proxy (Phase 2B)
- gitea-web/gitea-sshd ClusterIP services: the chart's gitea-http/ssh are HEADLESS
  (pod IP 100.64.x) which COLLIDES with the Tailscale CGNAT range 100.64.0.0/10, so the
  tailscale-sidecar proxy swallowed the traffic. ClusterIP (10.32.x) fixes it.
- tailscale-proxy: nginx git.fxhnt.ai -> gitea-web:3000; socat :22 -> gitea-sshd:22
  (drop :2222, GitLab); GitLab webservice/registry blocks left for Task 4/2C.
- dns git_ip -> 100.95.225.27 (live proxy node); stale 100.90.76.85 duplicate A records
  removed across api/chat/dashboard/git/grafana/mail/minio (were causing platform-wide flakiness).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 16:37:29 +02:00
jgrusewski
c3aec12f9a feat(infra): Gitea (chart 12.6, external postgres, no valkey, Actions off) + netpol
- infra/k8s/gitea/values.yaml: gitea-charts/gitea 12.6.0, reuse in-cluster postgres,
  subcharts + valkey disabled, memory cache / db session / level queue, SSH_PORT=22
- infra/k8s/gitea/networkpolicy.yaml: egress postgres/dns/webhook/https, ingress web+ssh
- infra/k8s/network-policies/infrastructure.yaml: admit gitea to postgres ingress

Phase 2B Task 2. Internal-only (no public hostname yet).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 16:07:08 +02:00
jgrusewski
b21d9b671d docs(plan): SSH on :22 only, retire :2222, update remotes (Phase 2B refinement) 2026-06-21 15:49:54 +02:00
jgrusewski
08cee0de0d docs: plan — Gitea replaces GitLab (Phase 2B); SSH on both :22 and :2222
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:46:34 +02:00
jgrusewski
80f3fbecef docs: spec — Gitea replaces GitLab + cockpit image to Scaleway registry (Phase 2B)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:38:26 +02:00
jgrusewski
042fcd76e5 Merge: migrate Terraform state to Scaleway Object Storage (Phase 2A)
4 modules migrated off GitLab http backend to s3 (foxhunt-tfstate). State now
external to the cluster + GitLab — prerequisite for GitLab decommission (2C).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:26:11 +02:00
jgrusewski
af3815ab6a chore(infra): migrate Terraform state GitLab -> Scaleway Object Storage (Phase 2A)
All 4 modules (kapsule/public-gateway/dns/block-storage) migrated to s3 backend
(bucket foxhunt-tfstate, fr-par, use_lockfile=true). plan=No changes verified per
module + final re-plan; all 4 state objects present in bucket; lock smoke test passed
(refresh-only apply, no orphan lockfile). GitLab http state left intact as fallback
(removed in Phase 2C). Also fixed root.hcl path in spec/plan docs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:25:20 +02:00
jgrusewski
3a18a348ac docs: plan — migrate Terraform state to Scaleway Object Storage (Phase 2A), inline+gated
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:18:02 +02:00
jgrusewski
2eb8cd8333 docs: spec — migrate Terraform state GitLab -> Scaleway Object Storage (Phase 2A)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 15:16:28 +02:00
jgrusewski
2c08b49b4f Merge: decommission dead Rust infra (Phase 1)
GPU pools (L40S/H100/cpu-hm) destroyed, 4 gitlab-runners uninstalled, 5 build-cache
PVCs + Scaleway volumes deleted (~195GB), 3 Rust buckets deleted (~6.7GB, 0 .dbn),
dead Argo templates/manifests removed. All .dbn market data + fxhnt/platform preserved.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:46:26 +02:00
jgrusewski
b1a60ca134 chore(infra): remove dead Rust Argo templates, runner values, GPU overlays, cache PVC manifests
Removed (Rust compute/CI/GPU, now decommissioned):
- argo: alpha-{cv,perception,rl}, build-ci-image, ci-pipeline, compile-and-deploy,
  gpu-test-*, lob-backtest-sweep, nsys-test, sanitizer-test, smoke-test, train,
  train-multi-seed, refresh-deps-cache templates + README; cargo/sccache PVC manifests;
  Rust CI events (ci-pipeline-sensor, gitlab-push-eventsource, auto-compile-configmap)
- gitlab: runner-{h100,h100x2,rl,}-values.yaml (runners uninstalled)
- gpu-overlays/: ml-training + trading GPU service overlays
- training/: training-output-pvc, image-prepuller, job-template, populate-test-data, s3-creds example
- kustomization.yaml trimmed to platform RBAC + netpol

Preserved (.dbn data tooling + kept-PVC declarations + active deploy):
- training/: training-data-pvc, test-data-pvc, download-mbp10/trades, data-sync/upload jobs
- argo: databento-download-template, feature-cache-pvc, fxhnt-cockpit (cluster)

Cluster: deleted 14 dead wftmpls + gpu-test-nightly/refresh-deps-cache-nightly crons.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:45:06 +02:00
jgrusewski
f4f54c352b chore(infra): destroy GPU+precompute pools (L40S/H100/cpu-hm) — Rust training retired
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:33:20 +02:00
jgrusewski
a0181431b3 docs: plan — decommission dead Rust infra (Phase 1), inline+gated execution
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:24:41 +02:00
jgrusewski
feb0ae2541 docs: spec — decommission dead Rust infra (Phase 1), data-preserving (keep all .dbn)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:21:49 +02:00
jgrusewski
4afaa5e248 fix(infra): resolve double-declared NAT gateway (kapsule vs public-gateway)
The real gateway foxhunt-gw (42653780) was an unmanaged orphan: kapsule state never had a gateway,
public-gateway state referenced a deleted gateway (7a7ffaa5) -> BOTH modules' terragrunt apply would
have created a duplicate gateway (risking cluster egress). Fix:
- kapsule module: removed the legacy gateway/dhcp/gateway_network resources (pre-refactor duplicate,
  never in kapsule state; cluster only needs the private_network which stays). kapsule plan now clean.
- public-gateway module (canonical, IPAM mode): state rm the stale 7a7ffaa5 refs + imported the real
  gateway/gateway_network/IP (42653780 / 661c8543 / dc419a10); set bastion_enabled=true to match the
  live gw. public-gateway plan now 'No changes'. Live gateway untouched throughout.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 14:05:50 +02:00
jgrusewski
e21a9a5da4 fix(gitlab): enable terraformState object storage (was 403 on all TF-state API calls)
Root cause: global.appConfig.terraformState was missing entirely from the GitLab Helm values, so the
chart rendered terraform_state.enabled=false + object_store disabled -> every /terraform/state API call
403'd ('Object Storage is not enabled for Terraform::StateUploader'), blocking terragrunt. State files
were intact in MinIO (foxhunt-gitlab-artifacts) the whole time. Added terraformState{enabled,bucket,
connection} mirroring artifacts/lfs/packages; helm upgrade -> revision 25 -> TF-state API now 200.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 13:54:13 +02:00
jgrusewski
b2efc58940 fix(ci): downsize ci-compile-cpu pool POP2-HC-32C-64G -> POP2-4C-16G (root-cause: zone stock-out)
Root cause of the stuck cockpit deploy: ci-compile-cpu (32C/64G POP2-HC) hit a fr-par-2 zone stock-out
('Resource POP2-HC-32C-64G is out of stock') -> autoscaler ScaleUpTimedOut -> kaniko build Pending forever.
The big node was sized for the now-dormant Rust cargo compile + precompute_features; the Python fxhnt
cockpit build only needs ~2-6 vCPU. Downsized to POP2-4C-16G (in stock in fr-par-2, far cheaper, scale-to-zero).
Apply blocked in-session: cluster GitLab tokens lack 'api' scope for the TF state backend (403).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 12:26:01 +02:00
jgrusewski
fbb7b429e3 infra(cert): ACME wildcard *.fxhnt.ai via cert-manager + Scaleway DNS-01 (replaces expired manual LE cert)
cert-manager ClusterIssuers (LE staging+prod) + Certificate writing gitlab-tls-cert, auto-renewing.
Scaleway webhook helm-installed (scaleway/scaleway-certmanager-webhook, cert-manager ns); DNS creds
in cert-manager/scaleway-dns-credentials. Proxy tls-certs volume repointed live to gitlab-tls-cert.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 11:21:30 +02:00
jgrusewski
f4bd1e2432 research(surfer): crypto edge-falsification probes — intraday/cascade dead, stablecoin peg-reversion validated
- crypto_mft_xsec / mft_*: intraday/MFT XS price edge FALSIFIED (fee-trap)
- crypto_cascade_reversion: liquidation-cascade reversion FALSIFIED (continuation)
- crypto_trend_sizing: TS-trend return-engine reconfirmed (Sharpe ~1.25)
- crypto_stablecoin_dislocation/harden/intraday: short-rich peg-reversion VALIDATED (bounded, uncorrelated); long-cheap = death-spiral trap

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 10:40:34 +02:00
jgrusewski
6878aac950 fix(ci): grant ci-deploy SA serviceaccounts/pvc/cronjobs + deployments-watch
The fxhnt-cockpit deploy step applies manifests containing ServiceAccounts (dashboard/dagster), a PVC
(forward track), and a CronJob — none of which the ci-deploy Role permitted, so kubectl apply failed
partway. Also added 'watch' on deployments for 'kubectl rollout status'. Surfaced once the cockpit deploy
finally ran (it previously died at the MinIO log sink first). Rule: this Role must gain a grant for every
new resource KIND a deployed manifest introduces.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-15 22:36:25 +02:00
jgrusewski
bccd814716 deploy(proxy): route dashboard.fxhnt.ai to the fxhnt cockpit (via its tailnet node)
Replaces the web-dashboard upstream. Proxies peer-to-peer over the tailnet (the kernel-mode proxy can't
reach platform-pool ClusterIPs due to the 100.64/15 pod-CIDR ↔ Tailscale CGNAT overlap, but reaches tailnet
nodes fine). Live CM already patched; this keeps the repo in sync.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 14:42:55 +02:00
jgrusewski
cfa28368d5 fix(surfer): futures fetch weekly (Sunday only) in forward-track cron — cost control
Daily 16y all-expiry Databento refetch was ~$6/day (~$190/mo) for the 17% hedge sleeve. Now: crypto_pit
fetched daily (free, the 83% alpha), futures fetched only on Sundays (~$25/mo, within free credits), and
forward-track runs daily (books the combined book's new days). The alpha is validated daily-accurate; the
slow trend hedge weekly.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 00:11:00 +02:00
jgrusewski
f9b62d108c feat(surfer): fxhnt combined-book forward-track cron + dynamic fetch END
fetch_daily.py: END now clamps to the GLBX dataset range-end (was hardcoded 2026-06-05; clamp handles the
~1-3d exchange lag — END=today failed get_cost). scripts/surfer/fxhnt_forward_cron.sh: daily wrapper —
fetch crypto_pit (free) + futures (Databento, cost-capped) + 'fxhnt forward-track' to book the new paper-
NAV day of the validated combined book (crypto X-sec momentum alpha + futures trend hedge). Crontab: daily
23:30 UTC -> data/surfer/fxhnt_forward.log. Sources DATABENTO key from ~/.secrets (never printed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 00:09:40 +02:00
jgrusewski
54e3d50db8 backtest: fusion (regime-adaptive QQQ<->crisis-alpha) FAILS OOS, keep static GD
Fused all ideas: QQQ core + foxhunt controllers as a ROTATOR (edge-decay-trust + resurrection +
drawdown-CB) rotating QQQ<->crisis-alpha by regime. Pre-registered criterion: beat static GD on OOS
Calmar. RESULT: full-sample fusion Calmar 0.41 > GD 0.34 (IS-flattered by 2008), but OOS (2018-2026)
static GD 0.64 > fusion 0.58, even pure QQQ 0.59 > fusion -- GD strictly dominates OOS (higher CAGR +
lower DD). Regime-rotation whipsaw + late-re-entry cost exceeds the protection benefit in bulls.
Verdict: fusion fails OOS -> keep the simpler static GD. Simple beats fancy; only OOS separates them.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 23:01:04 +02:00
jgrusewski
d82439219d add: drawdown-profile analysis tool (multistrat_dd.py)
Full drawdown profile of the deployable book (depth/frequency/duration/recovery/ulcer) vs 60/40.
Analysis tool, not part of the deployed pipeline.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:11:06 +02:00
jgrusewski
3f321bb4bf fix: broker-data sanity-check + drop incomplete intraday bar (two live-only bugs)
(1) IBKR paper reports summary fields (cash/GrossPositionValue) inconsistent with actual positions
(found: $141k/13% gap, fills+positions are ground truth). Bot now cross-checks NLV vs cash+position-
market-value, WARNs on >2% gap, sizes on the CONSERVATIVE NLV (never inflates), and a gate refuses to
trade if the gap exceeds MULTISTRAT_DATA_TOL (default 25%).
(2) build() included today's INCOMPLETE intraday bar when run mid-session -> spiked vol estimate ->
halved the leverage (1.0->0.5) -> would have sold half the book as churn at the 14:35 cron. Now drops
today's partial bar; uses completed closes only (matches the daily-close backtest). Verified live:
leverage back to 1.0, book recognized on-target (in_band), no spurious orders.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 16:01:04 +02:00
jgrusewski
02b851ca8b feat: growth-discipline forward-tracker (NAV sim, alongside the live book)
Works exactly like multistrat_paper.py (daily cron, status/run/weights, idempotent, forward-start,
catch-up) but tracks the GD strategy: 70% QQQ + 30% multi-strat book, continuously rebalanced. NAV
simulation (no orders) running alongside the live IBKR-paper book to compare forward: GD = higher
CAGR, deeper drawdown by design. Cron 12/15/18 UTC. GD_EQUITY_WEIGHT configurable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:45:35 +02:00
jgrusewski
a3f309dd7e backtest: growth-discipline multi-premia (QQQ core + trend sleeve + book)
User's '10x boring' idea tested. GD-70 (70%QQQ/15%trend/15%book) has highest Sharpe-excess (0.67-0.84
vs QQQ 0.65, book 0.39); trend sleeve = genuine crisis-alpha. GD@1.3x cheap-lev ~= QQQ return with
shallower drawdown (-48 vs -53%). VRP(PUTW) does NOT add (dilutes); carry no clean retail ETF. Clean
stackable premia = equity-core + trend-sleeve + execution-alpha (behavior gap/tax/cheap-lev, on top,
not in backtest). GD genuinely beats both the over-conservative book and panic-prone raw QQQ.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 09:42:30 +02:00
jgrusewski
db8f5434a0 doc+tool: CAGR-maximizer reference plan + side-by-side strategy comparison
Honest reference plan (docs/.../2026-06-08-cagr-reference-plan.md): CAGR builds wealth not Sharpe;
more CAGR always = more drawdown; only free CAGR is drag reduction; book's 0.96 Sharpe was an rf=0
artifact (excess-over-financing, equities win); leverage moat = cheap financing. Recommendation:
max equity + low drag + contribute + never sell, optional 1.2-1.3x futures if you survive -65%.
strategy_compare.py: re-runnable side-by-side (book / SPY 1x / SPY 1.3x / 60-40 / 70-30 / overlay)
with backtest stats + the P0+PMT trajectory. Configurable --p0 --pmt --fin --years.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 08:34:49 +02:00
jgrusewski
1cdbc81390 tune: daily weekday rebalancer eval (35 14 * * 1-5, REBALANCE_DAYS=1)
Switch from weekly to daily (weekday) evaluation for faster risk response — the leverage (vol-target
+ drawdown CB + corr de-risk) re-evaluates each day so a vol spike de-levers within a day vs a week.
Hysteresis (3% NLV) still gates actual trades, so turnover stays low (in-band days = no-ops). No
return impact; tighter risk only. Weekends excluded (US market closed).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:51:20 +02:00
jgrusewski
7662d82232 fix(bot): whole-share orders (IBKR API rejects fractional, err 10243) + state only on accepted
Eyes-on EXECUTE=true validation caught two bugs: (1) fractional qty -> all 6 orders cancelled (10243);
round to whole shares (skip if 0). (2) last_rebalance was set even when all orders were rejected,
which would block retry; now only marked when >=1 order is accepted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:34:01 +02:00
jgrusewski
2a468e4b5e arm: multistrat-rebalancer EXECUTE=true (autonomous paper trading)
After full validation (in-cluster connect via 4004, paper account DU9600528, gates pass, clean logs
post NaN-fix), arm the CronJob to place paper orders. Triple-guarded against real money: paper
account + Gateway paper-mode + bot refuses non-DU without MULTISTRAT_ALLOW_LIVE_CONFIRMED.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:31:18 +02:00
jgrusewski
8ebb65f27e fix: NaN-safe correlation de-risk in book_series (zero-variance windows)
np.corrcoef on a window where a vol-normalized stream is constant (warmup / non-moving stream)
divided by zero std -> RuntimeWarning + NaN in the corr matrix -> ac=NaN -> propagated via chist
into the z-score and could poison leverage L and book with NaN (silent corruption). Fix: correlate
only streams with std>0 in the window, nansum over the actual valid count, fall back to ac=0 when
<2 vary. Verified: no RuntimeWarning (tested with warnings-as-errors), no NaN, identical L/weights.
Affects all scripts importing book_series + the cluster ConfigMap.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:29:36 +02:00
jgrusewski
f320c5f09f fix(infra): rebalancer connects to ib-gateway:4004 (socat bridge), not 4002
Pod-to-pod on 4002 reaches IB Gateway with the pod IP as source -> not in the trusted-IP allowlist
(default 127.0.0.1) -> TCP connects but API handshake times out. The gnzsnz image's socat on 4004
relays via localhost so IB Gateway trusts it. (Local port-forward worked on 4002 because it enters
the pod netns = localhost.) Egress netpol now allows 4002+4004; IB_PORT=4004.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:20:28 +02:00
jgrusewski
dc2b7214f7 feat(infra): K8s CronJob for multi-strat rebalancer (production deployment)
Weekly in-cluster CronJob running multistrat_bot.py on IBKR paper via the existing ib-gateway
(connects to ib-gateway:4002 directly, no port-forward). Lean: code via ConfigMap (no image build),
python:3.12-slim + runtime pip. Includes PVC (state/HWM persistence across runs), egress
NetworkPolicy (ib-gateway:4002 + 443 for pip/Yahoo + DNS), and ib-gateway ingress patched to allow
the rebalancer. Schedule Mon 14:35 UTC (~1h after US open). MULTISTRAT_EXECUTE=false by default
(cluster dry-run); flip to true after validating logs. Drawdown CB + leverage cap + idempotency +
paper-guard enforced by the bot.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:16:36 +02:00
jgrusewski
4bbf07bddf feat: production multi-strat rebalance bot (lean enterprise core)
Single-file cron-ready IBKR rebalancer for the adaptive book. Money-touching core only: env config
(no secrets), paper/live guard (refuses live without MULTISTRAT_ALLOW_LIVE_CONFIRMED), leverage cap,
HWM drawdown circuit-breaker, fat-finger per-order cap, once-per-period idempotency, stale-price
guard, post-trade reconciliation, structured JSON audit log. Default dry-run; run needs
MULTISTRAT_EXECUTE=true. Verified vs cluster ib-gateway paper (DU9600528): gates pass, 6-order plan,
JSON audit trail + HWM state persisted.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-08 00:10:24 +02:00
jgrusewski
66e37955ce feat(ibkr-bot): mini test mode — validate paper env + order routing with 1 share
'mini' mode: confirms account is paper (DU prefix; aborts on live U-prefix), places BUY 1 SPY,
reports fill/routing. Validated against cluster ib-gateway: account DU9600528 [PAPER], order routed
(PreSubmitted, queued for next open — market closed on weekend). Confirms the full chain works:
cluster Gateway -> port-forward 4002 -> bot -> paper account.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-07 22:59:27 +02:00