Scheduling
Kurzzusammenfassung
- Diese Seite beschreibt, wie die Prefect‑Deployments im Projekt geplant werden: EOD‑Ingestion (Europa/USA), tägliche Makro‑/Event‑Updates, wöchentliche Fundamentals‑Refreshes sowie optional periodisches Retraining.
- Der Fokus liegt auf stabilen Laufzeiten, klaren Run‑Parametern (
as_of_date,region,dataset_group) und einer einfachen, robusten Zeitzonen‑Strategie (Europa vs. USA). - Das Modell ist langfristig ausgelegt (Stock‑Picking via Score). Intraday/minütliche Schedules sind nicht erforderlich.
- BPMN‑Leitpfad (Scheduling‑Detail):
Plan schedule→Trigger + capacity valid?→Run queued/deferred.
Einordnung: Scheduling verbindet den Timer‑Start im Hauptprozess (Schedule / New Data) mit den konkreten Prefect‑Deployments. Siehe Gesamtarchitektur und Ingestion (Data Pipeline: ELT + Validierung).
Ziel
- Verlässliche, nachvollziehbare Laufpläne für wiederkehrende Jobs (Ingestion, Refreshes, Scoring, optional Retraining).
- Saubere Zeitzonen‑Behandlung für EU/US‑EOD‑Daten ohne komplizierte Schedule‑Konfiguration.
- Pragmatik im Betrieb: überschaubare Anzahl Deployments, klare Regeln gegen Overlaps, Backfills bewusst getrennt.
Scope & Abgrenzung
In Scope (diese Seite):
- Welche Jobs laufen wann (Tages‑/Wochen‑/Monatsrhythmus)
- Zeitzonen‑Strategie (Europa/USA), Umgang mit Weekends/Holidays
- Deployment‑Schnitt, Parameterisierung, einfache Overlap‑/Kapazitätsregeln
- Retraining‑Trigger als Scheduling‑Thema (zeitbasiert + monitoring‑basiert)
Out of Scope (separate Seiten):
- Ingestion‑Inhalte (Extract/Load/Transform/Validate):
Data Pipeline - Fehler‑Handling und Runbooks:
Failure Handling - Incidents / Tickets:
Incident Management - Backfills (historische Nachläufe):
Backfills
Scheduling‑Strategie im Projekt
Grundprinzip
- Deployments sind nach Frequenz und Datenfamilie geschnitten (EOD EU, EOD US, Daily Updates, Weekly Fundamentals).
- Jeder Run ist deterministisch über Parameter und kann sicher erneut gestartet werden.
- Der Flow bestimmt die effektive
as_of_dateaus dem Run‑Kontext (z. B. „letzter Handelstag“). Dadurch bleiben Schedules bewusst simpel (Mo–Fr), auch wenn einzelne Börsentage ausfallen.
Zeitzonen
- Europa‑EOD wird in
Europe/Zurichgeplant. - USA‑EOD wird in
America/New_Yorkgeplant (DST‑Wechsel werden dadurch ohne manuelle Pflege korrekt abgebildet).
Die Datumslogik (as_of_date) liegt im Flow (zentral, testbar), nicht im Cron.
Handelstage und Feiertage
Prefect‑Cron bildet Börsenfeiertage nicht nativ ab. Deshalb:
- Schedule: Mo–Fr
- Im Flow: ermittle je Region den letzten gültigen Handelstag
- Wenn kein neues Delta verfügbar ist, beendet sich der Run sauber (No‑Update) und schreibt einen Status in die Metadaten (statt Fehler zu erzeugen)
Deployment‑Layout
Deployment-Granularität
Ein einziges Deployment für alles wird schnell unübersichtlich (Run‑History, Debugging, Backfills). Zu viele Micro‑Deployments erzeugen dagegen Overhead. Der Mittelweg:
- pro Frequenz/Zeitzone/Datenfamilie ein Deployment
- innerhalb eines Deployments mehrere zusammengehörige Abfragen (z. B. EOD Prices + Corporate Actions der Region)
Namenskonvention
Kurz, aber eindeutig:
ingest-eod-euingest-eod-usingest-updates-dailyrefresh-fundamentals-weeklybatch-scoring-dailymonitoring-dailyretrain-candidate-monthly(optional)retrain-on-demand
Run‑Parameter (Minimum)
Minimaler Parameter‑Satz, der sich in allen Deployments wiederfindet:
region:EU|US|GLOBALdataset_group: z. B.eod,updates,fundamentalsas_of_date: optional (Default im Flow: „letzter Handelstag“)mode:incremental|backfill
Provider‑Details (z. B. FMP/FRED/SEC) werden im Flow pro dataset_group sauber gekapselt und müssen nicht in jedem Deployment als Pflichtparameter auftauchen.
Scheduling‑Matrix
Die Zeiten sind auf EOD‑Daten (Europa/USA), tägliche Updates und wöchentliche Fundamentals ausgelegt. Alle Zeiten sind lokale Zeiten der jeweiligen Zeitzone.
| Deployment | Zweck | Quellen/APIs (typisch) | Rhythmus | Schedule (local) | Zeitzone | Cron |
|---|---|---|---|---|---|---|
ingest-eod-eu | EOD‑Preise Europa + Corporate Actions (EU‑Bezug) | FMP | Mo–Fr | 20:15 | Europe/Zurich | 15 20 * * 1-5 |
ingest-eod-us | EOD‑Preise USA + Corporate Actions (US‑Bezug) | FMP | Mo–Fr | 18:30 | America/New_York | 30 18 * * 1-5 |
ingest-updates-daily | Makro + Events/Filings als täglicher Delta‑Run | FRED + FMP + SEC EDGAR | Mo–Fr | 07:10 | Europe/Zurich | 10 7 * * 1-5 |
refresh-fundamentals-weekly | Fundamentals‑Refresh (Statements, Ratios, Estimates) | FMP | wöchentlich | Mo 06:10 | Europe/Zurich | 10 6 * * 1 |
batch-scoring-daily | Score‑Berechnung / Signal‑Generierung (latest available) | Internal Data Zone + Model Registry | Mo–Fr | 08:00 | Europe/Zurich | 0 8 * * 1-5 |
monitoring-daily | Drift/Performance‑Checks & Status | Internal Zone + Evidence | Mo–Fr | 08:30 | Europe/Zurich | 30 8 * * 1-5 |
retrain-candidate-monthly | periodischer Retrain‑Kandidat (Baseline) | Internal Zone + MLflow | monatlich | erster Mo 09:00 | Europe/Zurich | 0 9 1-7 * 1 |
retrain-on-demand | manuell gestartet (Monitoring‑Anlass) | wie oben | ad hoc | — | — | — |
Bemerkungen:
ingest-eod-usinAmerica/New_Yorkist bewusst gewählt, damit DST‑Wechsel ohne Cron‑Pflege funktionieren.batch-scoring-dailynutzt „latest available“ aus der Internal Zone. Das Scoring hängt nicht davon ab, dass der US‑EOD‑Run am selben Morgen frisch fertig wurde.- Weekly Fundamentals am Montag ist ein sinnvoller Kompromiss zwischen Aktualität und Aufwand.
Umsetzung in Prefect
Deployments mit Schedule definieren
Für Versionierung/Review ist schedule‑as‑code (z. B. prefect.yaml oder ein Deployment‑Script) der sauberste Weg.
Beispiel prefect.yaml (auszugsweise, als Muster):
deployments:
- name: ingest-eod-eu
entrypoint: flows/ingestion.py:market_data_ingestion
work_pool:
name: docker-prod
tags: ["ingestion", "eod", "eu"]
parameters:
region: "EU"
dataset_group: "eod"
mode: "incremental"
schedule:
cron: "15 20 * * 1-5"
timezone: "Europe/Zurich"
- name: ingest-eod-us
entrypoint: flows/ingestion.py:market_data_ingestion
work_pool:
name: docker-prod
tags: ["ingestion", "eod", "us"]
parameters:
region: "US"
dataset_group: "eod"
mode: "incremental"
schedule:
cron: "30 18 * * 1-5"
timezone: "America/New_York"
- name: ingest-updates-daily
entrypoint: flows/ingestion.py:market_data_ingestion
work_pool:
name: docker-prod
tags: ["ingestion", "updates"]
parameters:
region: "GLOBAL"
dataset_group: "updates"
mode: "incremental"
schedule:
cron: "10 7 * * 1-5"
timezone: "Europe/Zurich"
- name: refresh-fundamentals-weekly
entrypoint: flows/ingestion.py:market_data_ingestion
work_pool:
name: docker-prod
tags: ["ingestion", "fundamentals"]
parameters:
region: "GLOBAL"
dataset_group: "fundamentals"
mode: "incremental"
schedule:
cron: "10 6 * * 1"
timezone: "Europe/Zurich"
- name: batch-scoring-daily
entrypoint: flows/scoring.py:batch_scoring
work_pool:
name: docker-prod
tags: ["prod", "scoring"]
parameters:
mode: "incremental"
schedule:
cron: "0 8 * * 1-5"
timezone: "Europe/Zurich"
- name: monitoring-daily
entrypoint: flows/monitoring.py:monitoring_run
work_pool:
name: docker-prod
tags: ["prod", "monitoring"]
schedule:
cron: "30 8 * * 1-5"
timezone: "Europe/Zurich"
- name: retrain-candidate-monthly
entrypoint: flows/retrain.py:retrain_pipeline
work_pool:
name: docker-train
tags: ["train", "retrain"]
parameters:
trigger: "monthly"
schedule:
# erster Montag im Monat um 09:00
cron: "0 9 1-7 * 1"
timezone: "Europe/Zurich"
- name: retrain-on-demand
entrypoint: flows/retrain.py:retrain_pipeline
work_pool:
name: docker-train
tags: ["train", "retrain"]
parameters:
trigger: "on_demand"
Work Pools und Kapazität (VM‑Setup)
Bei einem self‑hosted Setup auf einer VM ist es meist ausreichend, zwei Pools zu trennen:
docker-prodfür Ingestion/Scoring/Monitoringdocker-trainfür rechenintensivere Jobs (Training/Validierung/Backtests)
Das schafft klare Prioritäten, ohne unnötige Komplexität.
Overlaps: „queued“ vs. „deferred“
Das ist der praktische Kern aus Trigger + capacity valid?:
- Für Ingestion ist es sinnvoll, Overlaps zu vermeiden (ein aktiver Run pro Datenfamilie).
- Für Train ist meist ein Run gleichzeitig ausreichend.
Pragmatische Leitplanken:
- Worker‑Concurrency
docker-prod: 1–2 gleichzeitige Runs (je nach VM‑Ressourcen) - Worker‑Concurrency
docker-train: 1 Run - Optional zusätzlich: Concurrency‑Limit für Tag
ingestionauf 1, damit Ingestion‑Runs nicht parallel schreiben
Das Ergebnis ist: Wenn ein Trigger kommt, aber die Kapazität nicht frei ist, wird der Run queued (oder bewusst deferred), statt parallel zu laufen.
Retraining: Trigger‑Logik
Zeitbasiert (Baseline)
retrain-candidate-monthly (erster Montag im Monat) erzeugt regelmässig einen konsistenten Retrain‑Kandidaten (Run‑Artefakte, Metrics, Vergleiche). Das erleichtert langfristige Vergleichbarkeit.
Monitoring‑basiert (on demand)
Zusätzlich kann Monitoring einen Anlass liefern. Das Vorgehen bleibt absichtlich einfach:
monitoring-dailyschreibt einen Status (z. B. „review required“) inkl. Referenzen (Run IDs, Metrics).- Bei Bedarf wird
retrain-on-demandmanuell gestartet (Prefect UI/CLI) und bekommt ggf. Parameter wie Lookback‑Window.
Siehe: Monitoring
Missed Runs, Backfills und Catch‑up
Zwei Fälle werden getrennt behandelt:
- Missed Run (Scheduler/Worker down): Der nächste reguläre Run läuft wie geplant; fehlende Tage werden nur bei Bedarf nachgezogen.
- Backfill: Historischer Nachlauf für definierte Zeiträume wird bewusst als eigener Run mit
mode: backfillgestartet.
Siehe: Backfills
BPMN‑Detailansicht
Hier wird die BPMN‑Darstellung „Scheduling“ eingebettet (Datei z. B. site/static/bpmn/scheduling.bpmn).
Glossar‑Begriffe
Prefect– Orchestrierung, Deployments, SchedulesBackfill– historisches Nachziehen von RunsMonitoring– Drift/Performance‑Signale als Entscheidungsgrundlage
BPMN‑Kontext
- Main BPMN:
Gesamtarchitektur - Scheduling‑Einstieg:
StartEvent_Timer– „Schedule / New Data“ - Ingestion‑Call Activity:
CallActivity_DataPipeline– „Datapipeline (ELT + Validierung)“ - Retrain‑Entscheid:
Gateway_Retrain– „Retrain Trigger?“ - Retrain‑Ausführung:
CallActivity_RetrainJob– „Retraining Job“