chore(scheduling): delete compare-measured + vrp crons; arm factory + ucits-volume

compare-measured-precompute is now the Dagster bybit_book_precompute asset
(K8sRunLauncher, own memory) — cron + NP deleted. vrp-rebalancer deleted
(shelved/falsified; vrp_nav de-wired from the nightly). Armed factory +
ucits-volume-ibkr in the manifests (source of truth) to match the live state;
bybit-rebalancer (no testnet creds) + ibkr-rebalancer (PRIIPs) stay suspended.
Final: Dagster owns all nightly ETL+precompute; K8s CronJobs own execution only.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-19 10:12:45 +00:00
parent 06156bdb1a
commit 1ecf3983d9
2 changed files with 0 additions and 233 deletions

View File

@@ -1,128 +0,0 @@
# CONSOLIDATED DAILY bybit precompute (WRITER) — one own-memory CronJob that runs BOTH heavy per-coin/per-sleeve
# writers back-to-back, so every cockpit + reconciliation input is refreshed on the SAME daily cadence as the
# live forward book (fixing the recon-ref lag: `bybit_sleeve_ret` used to refresh only WEEKLY via the separate
# `fxhnt-backtest-refs` CronJob — now RETIRED/merged here — so the daily forward ran up to a week ahead of its
# reconciliation reference). The two writers stay SEPARATE compute paths (not compute-once — that is a distinct
# refactor of load-bearing sim/recon math); this only CO-SCHEDULES them, so the numbers are unchanged.
#
# Writers, in order:
# 1. `bybit-spread-refresh` — samples Bybit L1 top-of-book → `bybit_real_spread` (non-fatal; keeps prior/CS).
# 2. `compare-measured-precompute` — per-COIN MEASURED-cost curves → `compare_measured_cache` (the Backtest's
# DEFAULT cost mode; `/paper/sim` READS these, falling back to the LIGHT flat-cost view until present).
# 3. `backtest-refs --all` — the 4 per-SLEEVE return series → `bybit_sleeve_ret` (the sim's precompute) + the
# `_BYBIT_BOOK_SIDS` `backtest_summary` reconciliation-gate refs (bybit_4edge / levered / positioning /
# xsfunding / unlock). Without a FRESH ref the recon gate silently skips its divergence band — a false-PASS
# risk on the real-capital book — which is exactly why this must be DAILY, not weekly.
# The two writers run INDEPENDENTLY (a compare failure must not starve the sleeve-ret/recon ref); the Job still
# fails if EITHER writer fails, so a failure surfaces in failedJobsHistory.
#
# WHY A CRONJOB (own memory, NOT a Dagster asset): this heavy compute needs up to 6Gi and OOM-killed the 4Gi
# `fxhnt-dashboard` when it ran live; the Dagster daemon is ALSO 4Gi, so it can't run inside the nightly asset
# graph either. So it runs as its OWN-memory Job (6Gi req / 8Gi limit) pinned to the 16GB autoscale pool, on a
# daily schedule timed AFTER the Dagster combined-book ingests (23:30 UTC) so it reads FRESH
# `features`/`bybit_features` + the refreshed bybit backfill. `backtest-refs` (4Gi) runs sequentially in the
# SAME pod, so peak memory stays ~6Gi (processes release between commands). Both writers' egress needs (DNS,
# postgres 5432, gitea, api.bybit.com + DefiLlama unlock-calendar 443) are already covered by the NetworkPolicy
# below. On-demand: `kubectl create job <name> --from=cronjob/fxhnt-compare-measured-precompute -n foxhunt`.
#
# FULLY-DECOUPLED BATCH: NO PVC — reads TimescaleDB over the network (5432: `features` + `bybit_features` +
# the cockpit paper tables incl. the unlock calendar), writes `compare_measured_cache` to the same DB;
# schedules on ANY node with room. git-sync brings the current code (compare-measured-precompute CLI).
apiVersion: batch/v1
kind: CronJob
metadata:
name: fxhnt-compare-measured-precompute
namespace: foxhunt
labels: { app.kubernetes.io/name: fxhnt-compare-measured-precompute, app.kubernetes.io/part-of: foxhunt }
spec:
schedule: "0 1 * * *" # 01:00 UTC daily — AFTER the Dagster 23:30 combined-book ingests finish
timeZone: "UTC"
concurrencyPolicy: Forbid # never overlap runs (one heavy writer at a time)
startingDeadlineSeconds: 3600
successfulJobsHistoryLimit: 2
failedJobsHistoryLimit: 2
jobTemplate:
spec:
backoffLimit: 2
ttlSecondsAfterFinished: 604800
template:
metadata:
labels: { app.kubernetes.io/name: fxhnt-compare-measured-precompute, app.kubernetes.io/part-of: foxhunt }
spec:
restartPolicy: Never
# Pin to the 16GB POP2-4C-16G pool (the platform DEV1-L nodes are 8GB — too small for the 8Gi
# limit). The pool autoscales min=0→up on demand for this Pending pod, runs it, scales back to 0
# (cost = only the minutes it runs). Soft PreferNoSchedule autoscaler tag doesn't block scheduling.
nodeSelector:
k8s.scaleway.com/pool-name: large
imagePullSecrets:
- name: scw-registry
initContainers:
- name: git-sync
image: alpine/git:latest
command: [/bin/sh, -c]
args:
- |
mkdir -p /root/.ssh && cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519 && chmod 600 /root/.ssh/id_ed25519
printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config
rm -rf /code/src
git clone --depth 1 --branch master --filter=blob:none --sparse \
"ssh://git@gitea-ssh.gitea.svc.cluster.local:22/gitadmin/fxhnt.git" /tmp/repo
cd /tmp/repo && git sparse-checkout set src && [ -d /tmp/repo/src ]
cp -a /tmp/repo/src /code/src && echo "git-sync OK: $(git rev-parse --short HEAD)"
resources: { requests: { cpu: 50m, memory: 64Mi }, limits: { cpu: 500m, memory: 256Mi } }
volumeMounts:
- { name: code, mountPath: /code }
- { name: git-ssh-key, mountPath: /etc/git-ssh, readOnly: true }
containers:
- name: bybit-daily-precompute
image: rg.fr-par.scw.cloud/bizworx/fxhnt-cockpit:latest
# 1) Refresh the REAL per-coin L1 quoted spread (samples Bybit top-of-book → median per coin,
# needs api.bybit.com:443) — non-fatal (keeps prior/CS on a fetch failure), so it never blocks.
# 2) compare-measured-precompute reads bybit_real_spread to cost the liquid book at the REAL spread
# (not the 104×-too-harsh daily-high/low CS proxy) → compare_measured_cache.
# 3) backtest-refs --all → bybit_sleeve_ret + the reconciliation-gate refs (merged from the retired
# weekly fxhnt-backtest-refs CronJob, now DAILY so the recon ref keeps pace with the forward).
# Steps 2 and 3 run INDEPENDENTLY (a compare failure must not starve the recon ref); the Job still
# exits non-zero if EITHER writer fails, so failures show up in failedJobsHistory.
command: ["/bin/sh", "-c"]
args:
- |
fxhnt bybit-spread-refresh --samples 5 || echo "spread-refresh non-fatal; continuing"
fxhnt compare-measured-precompute; rc_compare=$?
fxhnt backtest-refs --all; rc_refs=$?
echo "exit codes -> compare-measured=$rc_compare backtest-refs=$rc_refs"
[ "$rc_compare" = 0 ] && [ "$rc_refs" = 0 ]
env:
- { name: PYTHONPATH, value: /code/src }
- { name: FXHNT_OPERATIONAL_DSN, value: "postgresql+psycopg://foxhunt@postgres.foxhunt.svc.cluster.local:5432/fxhnt" }
- name: PGPASSWORD
valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
- { name: PYTHONUNBUFFERED, value: "1" }
resources:
requests: { memory: "6Gi", cpu: "1" }
limits: { memory: "8Gi", cpu: "2" } # own memory, generous headroom; no PVC
volumeMounts:
- { name: code, mountPath: /code, readOnly: true }
volumes:
- { name: code, emptyDir: {} }
- { name: git-ssh-key, secret: { secretName: argo-git-ssh-key, defaultMode: 256 } }
---
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fxhnt-compare-measured-precompute
namespace: foxhunt
labels: { app.kubernetes.io/part-of: foxhunt }
spec:
podSelector: { matchLabels: { app.kubernetes.io/name: fxhnt-compare-measured-precompute } }
policyTypes: [Egress]
egress:
- ports: [{ port: 53, protocol: UDP }, { port: 53, protocol: TCP }]
- to: [{ podSelector: { matchLabels: { app.kubernetes.io/name: postgres } } }]
ports: [{ port: 5432, protocol: TCP }]
- to: [{ namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: gitea } }, podSelector: { matchLabels: { app.kubernetes.io/name: gitea } } }]
ports: [{ port: 2222, protocol: TCP }, { port: 22, protocol: TCP }]
# api.bybit.com (443) — the `bybit-spread-refresh` step samples the live L1 top-of-book over the public
# internet. No selector (external host); HTTPS only.
- ports: [{ port: 443, protocol: TCP }]

View File

@@ -1,105 +0,0 @@
# VRP rebalancer — the EXECUTED XSP put-credit-spread VRP twin (Task 7). Runs `execute-vrp` weekly (mirrors
# `vrp`'s ~weekly entry cadence) via `fxhnt execute-vrp --execute --paper-envelope 1000000` at IBKR paper
# (DU9600528). Records the OBSERVED vrp_exec track (real executed-vs-modeled reconciliation), same shape as
# fxhnt-ibkr-rebalancer's multistrat_exec twin.
#
# SUSPENDED (suspend: true) — the IBKR paper account currently has NO options trading permission, so
# `place_combo` cannot fill. Copied from fxhnt-ibkr-rebalancer.yaml; do NOT flip `suspend: false` until
# options permission is granted on the account AND this has been dry-run (--execute omitted) against a live
# gateway to confirm OPRA/IBKR reachability.
#
# ib_async + databento are NOT baked into the cockpit image -> pip-install both at runtime (databento is
# needed here for the live OPRA freeze `execute-vrp` performs each run, unlike the equity-only multistrat
# twin). Requires ib-gateway UP (kubectl scale deploy/ib-gateway --replicas=1).
apiVersion: batch/v1
kind: CronJob
metadata:
name: fxhnt-vrp-rebalancer
namespace: foxhunt
labels: { app.kubernetes.io/name: fxhnt-vrp-rebalancer, app.kubernetes.io/part-of: foxhunt }
spec:
schedule: "40 14 * * 1" # weekly Monday 14:40 UTC (~1h after US equity open)
suspend: true # SUSPENDED — no IBKR options permission yet; arm manually once granted
concurrencyPolicy: Forbid
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 3
jobTemplate:
spec:
backoffLimit: 1
ttlSecondsAfterFinished: 604800
template:
metadata:
labels:
app.kubernetes.io/name: fxhnt-vrp-rebalancer # egress NetworkPolicy selects this
app.kubernetes.io/part-of: foxhunt # gitea ingress (git-sync) + base egress
app: multistrat-rebalancer # ib-gateway INGRESS allows this label on 4004
spec:
restartPolicy: Never
imagePullSecrets:
- name: scw-registry
initContainers:
- name: git-sync
image: alpine/git:latest
command: [/bin/sh, -c]
args:
- |
mkdir -p /root/.ssh && cp /etc/git-ssh/ssh-privatekey /root/.ssh/id_ed25519 && chmod 600 /root/.ssh/id_ed25519
printf 'Host *\n StrictHostKeyChecking no\n UserKnownHostsFile /dev/null\n' > /root/.ssh/config
rm -rf /code/src
git clone --depth 1 --branch master --filter=blob:none --sparse \
"ssh://git@gitea-ssh.gitea.svc.cluster.local:22/gitadmin/fxhnt.git" /tmp/repo
cd /tmp/repo && git sparse-checkout set src && [ -d /tmp/repo/src ]
cp -a /tmp/repo/src /code/src && echo "git-sync OK: $(git rev-parse --short HEAD)"
resources: { requests: { cpu: 50m, memory: 64Mi }, limits: { cpu: 500m, memory: 256Mi } }
volumeMounts:
- { name: code, mountPath: /code }
- { name: git-ssh-key, mountPath: /etc/git-ssh, readOnly: true }
containers:
- name: rebalancer
image: rg.fr-par.scw.cloud/bizworx/fxhnt-cockpit:latest
command: ["/bin/sh", "-c"]
args:
- |
pip install --quiet --no-cache-dir ib_async==2.1.0 databento==0.79.0
fxhnt execute-vrp --execute --paper-envelope 1000000
env:
- { name: PYTHONPATH, value: /code/src }
- { name: FXHNT_OPERATIONAL_DSN, value: "postgresql+psycopg://foxhunt@postgres.foxhunt.svc.cluster.local:5432/fxhnt" }
- name: PGPASSWORD
valueFrom: { secretKeyRef: { name: db-credentials, key: password } }
- { name: FXHNT_IBKR_HOST, value: "ib-gateway" }
- { name: FXHNT_IBKR_PORT, value: "4004" } # socat-bridged pod-to-pod port (TrustedIPs-safe)
- { name: FXHNT_IBKR_CLIENT_ID, value: "26" } # unique client id (25 = multistrat rebalancer)
- name: DATABENTO_API_KEY
valueFrom: { secretKeyRef: { name: databento-credentials, key: api-key } }
- { name: PYTHONUNBUFFERED, value: "1" }
resources:
requests: { memory: "512Mi", cpu: "250m" }
limits: { memory: "1Gi", cpu: "1" }
volumeMounts:
- { name: code, mountPath: /code, readOnly: true }
volumes:
- { name: code, emptyDir: {} }
- { name: git-ssh-key, secret: { secretName: argo-git-ssh-key, defaultMode: 256 } }
---
# Egress: DNS + Postgres (5432, record vrp_exec) + gitea-sshd (22, git-sync) + ib-gateway (4004/4002) +
# external 443 (OPRA via Databento historical API + IBKR). Same shape as fxhnt-ibkr-rebalancer's egress.
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: fxhnt-vrp-rebalancer
namespace: foxhunt
labels: { app.kubernetes.io/part-of: foxhunt }
spec:
podSelector: { matchLabels: { app.kubernetes.io/name: fxhnt-vrp-rebalancer } }
policyTypes: [Egress]
egress:
- ports: [{ port: 53, protocol: UDP }, { port: 53, protocol: TCP }]
- to: [{ podSelector: { matchLabels: { app.kubernetes.io/name: postgres } } }]
ports: [{ port: 5432, protocol: TCP }]
- to: [{ namespaceSelector: { matchLabels: { kubernetes.io/metadata.name: gitea } }, podSelector: { matchLabels: { app.kubernetes.io/name: gitea } } }]
ports: [{ port: 2222, protocol: TCP }, { port: 22, protocol: TCP }]
- to: [{ podSelector: { matchLabels: { app: ib-gateway } } }]
ports: [{ port: 4004, protocol: TCP }, { port: 4002, protocol: TCP }]
- to: [{ ipBlock: { cidr: 0.0.0.0/0, except: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16] } }] # OPRA/IBKR 443
ports: [{ port: 443, protocol: TCP }]