Zum Hauptinhalt springen

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 scheduleTrigger + 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

  1. Verlässliche, nachvollziehbare Laufpläne für wiederkehrende Jobs (Ingestion, Refreshes, Scoring, optional Retraining).
  2. Saubere Zeitzonen‑Behandlung für EU/US‑EOD‑Daten ohne komplizierte Schedule‑Konfiguration.
  3. 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):

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_date aus 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/Zurich geplant.
  • USA‑EOD wird in America/New_York geplant (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-eu
  • ingest-eod-us
  • ingest-updates-daily
  • refresh-fundamentals-weekly
  • batch-scoring-daily
  • monitoring-daily
  • retrain-candidate-monthly (optional)
  • retrain-on-demand

Run‑Parameter (Minimum)

Minimaler Parameter‑Satz, der sich in allen Deployments wiederfindet:

  • region: EU | US | GLOBAL
  • dataset_group: z. B. eod, updates, fundamentals
  • as_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.

DeploymentZweckQuellen/APIs (typisch)RhythmusSchedule (local)ZeitzoneCron
ingest-eod-euEOD‑Preise Europa + Corporate Actions (EU‑Bezug)FMPMo–Fr20:15Europe/Zurich15 20 * * 1-5
ingest-eod-usEOD‑Preise USA + Corporate Actions (US‑Bezug)FMPMo–Fr18:30America/New_York30 18 * * 1-5
ingest-updates-dailyMakro + Events/Filings als täglicher Delta‑RunFRED + FMP + SEC EDGARMo–Fr07:10Europe/Zurich10 7 * * 1-5
refresh-fundamentals-weeklyFundamentals‑Refresh (Statements, Ratios, Estimates)FMPwöchentlichMo 06:10Europe/Zurich10 6 * * 1
batch-scoring-dailyScore‑Berechnung / Signal‑Generierung (latest available)Internal Data Zone + Model RegistryMo–Fr08:00Europe/Zurich0 8 * * 1-5
monitoring-dailyDrift/Performance‑Checks & StatusInternal Zone + EvidenceMo–Fr08:30Europe/Zurich30 8 * * 1-5
retrain-candidate-monthlyperiodischer Retrain‑Kandidat (Baseline)Internal Zone + MLflowmonatlicherster Mo 09:00Europe/Zurich0 9 1-7 * 1
retrain-on-demandmanuell gestartet (Monitoring‑Anlass)wie obenad hoc

Bemerkungen:

  • ingest-eod-us in America/New_York ist bewusst gewählt, damit DST‑Wechsel ohne Cron‑Pflege funktionieren.
  • batch-scoring-daily nutzt „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-prod für Ingestion/Scoring/Monitoring
  • docker-train fü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 ingestion auf 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:

  1. monitoring-daily schreibt einen Status (z. B. „review required“) inkl. Referenzen (Run IDs, Metrics).
  2. Bei Bedarf wird retrain-on-demand manuell 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: backfill gestartet.

Siehe: Backfills

BPMN‑Detailansicht

Hier wird die BPMN‑Darstellung „Scheduling“ eingebettet (Datei z. B. site/static/bpmn/scheduling.bpmn).

Diagramm wird geladen …

Glossar‑Begriffe

  • Prefect – Orchestrierung, Deployments, Schedules
  • Backfill – historisches Nachziehen von Runs
  • Monitoring – 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“