From 988743302dbecd1a8592fc83df9a087e02ee6137 Mon Sep 17 00:00:00 2001 From: jgrusewski Date: Thu, 18 Jun 2026 19:04:39 +0200 Subject: [PATCH] deploy(b3b): one-off Job to run the backtest + publish verdict to cockpit (pg egress netpol) Co-Authored-By: Claude Opus 4.8 (1M context) --- .../k8s/jobs/fxhnt-backtest-verdict-job.yaml | 67 +++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 infra/k8s/jobs/fxhnt-backtest-verdict-job.yaml diff --git a/infra/k8s/jobs/fxhnt-backtest-verdict-job.yaml b/infra/k8s/jobs/fxhnt-backtest-verdict-job.yaml new file mode 100644 index 0000000..9891a7d --- /dev/null +++ b/infra/k8s/jobs/fxhnt-backtest-verdict-job.yaml @@ -0,0 +1,67 @@ +# B3b-verdict — run the survivorship-free walk-forward equity-factor backtest against the dedicated +# backtest warehouse and PUBLISH the per-construction gauntlet verdict into the cockpit DB +# (backtest_summary table, surfaced in the dashboard). Run DELIBERATELY/occasionally (not nightly) — +# delete + re-apply to refresh after a new ingest or a methodology change. +# +# PIT (point-in-time) universe selection by default (no peak-liquidity lookahead); reads ONLY the +# dedicated warehouse (never live Tiingo). Memory: the run peaks ~4.3Gi (103M-row monthly aggregate + +# union adjclose panel), so request 3Gi / limit 5Gi. +apiVersion: batch/v1 +kind: Job +metadata: + name: fxhnt-backtest-verdict + namespace: foxhunt + labels: { app.kubernetes.io/name: fxhnt-backtest-verdict, app.kubernetes.io/part-of: foxhunt } +spec: + backoffLimit: 1 + ttlSecondsAfterFinished: 604800 # 7d — keep for log inspection + template: + metadata: + labels: { app.kubernetes.io/part-of: foxhunt, app.kubernetes.io/name: fxhnt-backtest-verdict } + spec: + restartPolicy: Never + nodeSelector: + k8s.scaleway.com/pool-name: platform + imagePullSecrets: + - name: gitlab-registry + containers: + - name: backtest + image: gitlab-registry.foxhunt.svc.cluster.local:5000/root/foxhunt/fxhnt-cockpit:latest + command: ["fxhnt"] + args: ["backtest-equity", "--pit", "--n", "150", "--trailing-window-months", "12", + "--cost-bps", "15", "--delisting-return", "-0.30", "--persist-cockpit", + "--out", "/backtest-data/equity_backtest_report.json"] + env: + - name: PYTHONUNBUFFERED + value: "1" + - name: FXHNT_BACKTEST_WAREHOUSE_PATH + value: /backtest-data/warehouse.duckdb + - name: FXHNT_OPERATIONAL_DSN + value: postgresql+psycopg://foxhunt@postgres.foxhunt.svc.cluster.local:5432/fxhnt + - name: PGPASSWORD + valueFrom: { secretKeyRef: { name: db-credentials, key: password } } + resources: + requests: { memory: "3Gi", cpu: "500m" } + limits: { memory: "5Gi" } + volumeMounts: + - { name: backtest-data, mountPath: /backtest-data } + volumes: + - name: backtest-data + persistentVolumeClaim: { claimName: fxhnt-backtest-data } +--- +# Egress for the verdict Job: DNS + internal Postgres (5432). foxhunt has default-deny-all egress and +# the shared argo-base-egress only opens 443 — this Job talks to the cockpit Postgres on 5432 (internal), +# so it needs its own rule. No external egress needed (reads the local warehouse, writes internal pg). +apiVersion: networking.k8s.io/v1 +kind: NetworkPolicy +metadata: + name: fxhnt-backtest-verdict + namespace: foxhunt + labels: { app.kubernetes.io/part-of: foxhunt } +spec: + podSelector: { matchLabels: { app.kubernetes.io/name: fxhnt-backtest-verdict } } + policyTypes: [Egress] + egress: + - ports: [{ port: 53, protocol: UDP }, { port: 53, protocol: TCP }] + - ports: [{ port: 5432, protocol: TCP }] + to: [{ ipBlock: { cidr: 10.32.0.0/16 } }, { ipBlock: { cidr: 172.16.0.0/16 } }]