σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
σμimplied vol · KKmax(S−K,0)udβρᵢⱼfat tailsPnL · drawdownyield · TdSₜ = μSₜ dt + σSₜ dWₜC = S·N(d₁) − K·e⁻ʳᵀ·N(d₂)σₚ² = wᵀΣwd₁ = [ln(S/K) + (r + σ²⁄2)T] ⁄ σ√T∂V/∂t + ½σ²S²·∂²V/∂S² + rS·∂V/∂S − rV = 0Sharpe = (Rₚ − R_f) ⁄ σₚVaR₉₉ = μ − 2.33σρ = Cov(X,Y) ⁄ σₓσᵧE[Rₚ] = Σ wᵢ·E[Rᵢ]φ(x) = e^(−x²/2) ⁄ √2πE[Rᵢ] = R_f + βᵢ(E[Rₘ] − R_f)dXₜ = θ(μ − Xₜ)dt + σ dWₜσ²ₜ = ω + α·ε²ₜ₋₁ + β·σ²ₜ₋₁C − P = S − K·e⁻ʳᵀΔ = ∂V/∂S Γ = ∂²V/∂S²p = (e^(rΔt) − d) ⁄ (u − d)rₜ = ln(Pₜ ⁄ Pₜ₋₁)E[Xₜ₊₁ | ℱₜ] = Xₜf* = (bp − q) ⁄ bz = (x − μ) ⁄ σP(N=k) = λᵏe^(−λ) ⁄ k!Θ = −∂V/∂Tν = S·φ(d₁)·√Tmin wᵀΣw s.t. wᵀμ = μ*∫Σ∂∞λ
uantCraft AcademySkills
Ctrl K
AO
+1,2 Tsd. Lernende
AnmeldenBeitreten ↗
Skills
AO
+1,2 Tsd. Lernende
Anmelden
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python-Skill›Modul 11 · Produktivsysteme und Spitzenmodelle›Thema 11.2·~1 Std.Experte

CI/CD für Quant-Code

Position in der SkillModul 11 von 11 · Thema 2 von 13
11.2 CI/CD für Quant-Code
—Lab-Punkte— / 100XP gesamt—Serie—

Prüfungen, die von selbst laufen

Tests schützen nur, wenn sie jedes Mal von etwas ausgeführt werden, das nicht Ihr Gedächtnis ist. Continuous Integration (CI) ist ein Server, der bei jedem Push und Pull Request den Code in einer sauberen Umgebung auscheckt und die definierten Prüfungen ausführt: Lint, Typprüfung, Tests, einen kleinen Backtest. Scheitert etwas, wird die Änderung blockiert. Continuous Delivery/Deployment (CD) geht weiter: Bestehen die Prüfungen auf dem Hauptzweig, wird die neue Version automatisch gebaut und veröffentlicht. In der Quant-Arbeit ist der Einsatz konkret: Ein Refactoring, das einen Preis still um einen Basispunkt verschiebt, sollte eine Maschine fangen, bevor es ein Portfolio erreicht.

# A test matrix: every operating system with every Python version, minus the combinations you skip
from itertools import product

os_list = ["linux", "macos", "windows"]
py_versions = ["3.11", "3.12"]
exclude = {("windows", "3.11")}

jobs = [(os_name, version) for os_name, version in product(os_list, py_versions) if (os_name, version) not in exclude]
print(len(jobs))                                     # 5
print(jobs[0], jobs[-1])                             # ('linux', '3.11') ('windows', '3.12')

Was eine Quant-Pipeline prüft

Eine typische Pipeline hat Stufen, die schnell scheitern: Lint (Stil und offensichtliche Fehler) und Typprüfung dauern Sekunden, dann die Unit-Tests, dann langsamere Prüfungen wie ein kleiner Regressions-Backtest, der mit einem gespeicherten Ergebnis verglichen wird. Machen Sie die Prüfungen deterministisch: feste Zufalls-Seeds, kein Netz, keine Abhängigkeit vom heutigen Datum und Daten aus einem kleinen eingecheckten Snapshot statt eines Live-Feeds. Führen Sie sie auf einer Matrix aus Python-Versionen und Betriebssystemen aus, die Sie zu unterstützen behaupten. Für schnelles Feedback führen Sie nur die Tests aus, die eine Änderung betreffen kann (Testauswahl), mit sicherem Rückfall auf die gesamte Suite, wenn man es nicht sagen kann.

# Test selection: run only the tests a change can affect; an unknown file means "run everything"
def select_tests(changed_files, mapping):
    chosen = set()
    for path in changed_files:
        matches = [tests for prefix, tests in mapping.items() if path.startswith(prefix)]
        if not matches:
            return sorted({test for tests in mapping.values() for test in tests})
        for tests in matches:
            chosen.update(tests)
    return sorted(chosen)

mapping = {"src/pricing/": ["tests/test_bs.py", "tests/test_greeks.py"], "src/risk/": ["tests/test_var.py"]}
print(select_tests(["src/risk/var.py"], mapping))                    # ['tests/test_var.py']
print(select_tests(["src/risk/var.py", "setup.cfg"], mapping))       # all three tests: setup.cfg could affect anything

Gates, Secrets und die Workflow-Datei

Die Pipeline wird in einer Datei im Repository beschrieben, etwa .github/workflows/ci.yml für GitHub Actions: wann sie läuft (on:), die Jobs, die Matrix und die Schritte, wobei jeder Schritt entweder eine fertige Action mit uses: nutzt oder einen Befehl mit run: ausführt. Behandeln Sie die Datei wie Code, der wie jeder andere geprüft wird. Fügen Sie ein Deploy-Gate hinzu: Nur der Zweig main deployt, und nur wenn jeder erforderliche Job erfolgreich war (ein übersprungener oder fehlender Job ist kein Erfolg). Schützen Sie den Zweig, damit er nicht ohne bestandene Prüfungen gemergt wird. Halten Sie API-Schlüssel und Passwörter in den Secrets des CI-Systems, nie im Repository, und geben Sie jedem Job nur die nötigen Rechte. Veröffentlichen Sie zuerst in einer Paper-Trading- oder Staging-Umgebung.

# The deploy gate: main branch only, and every required job must have succeeded
def can_deploy(results, required, branch):
    return branch == "main" and all(results.get(job) == "success" for job in required)

print(can_deploy({"lint": "success", "tests": "success"}, ["lint", "tests"], "main"))     # True
print(can_deploy({"lint": "success", "tests": "skipped"}, ["lint", "tests"], "main"))     # False  skipped is not success
print(can_deploy({"lint": "success"}, ["lint", "tests"], "main"))                         # False  a missing job is not success
print(can_deploy({"lint": "success", "tests": "success"}, ["lint", "tests"], "dev"))      # False  only main deploys
# The workflow file is plain text, so it can be generated and checked like any other output
def workflow_yaml(name, python_versions, command):
    versions = ", ".join(f'"{version}"' for version in python_versions)
    lines = [f"name: {name}", "on: [push, pull_request]", "jobs:", "  test:", "    runs-on: ubuntu-latest",
             "    strategy:", "      matrix:", f"        python-version: [{versions}]", "    steps:",
             "      - uses: actions/checkout@v4", "      - uses: actions/setup-python@v5", "        with:",
             "          python-version: ${{ matrix.python-version }}", "      - run: pip install -e .[test]",
             f"      - run: {command}"]
    return "\n".join(lines) + "\n"

text = workflow_yaml("ci", ["3.11", "3.12"], "pytest -q")
print(text.splitlines()[7])                          #         python-version: ["3.11", "3.12"]
print(text.splitlines()[-1])                         #       - run: pytest -q
Eine grüne Pipeline ist nur so gut wie ihre TestsCI beweist, dass die Prüfungen bestehen, nicht dass die Strategie gut ist. Halten Sie die Suite schnell, damit man sie ausführt, reparieren Sie einen instabilen Test oder löschen Sie ihn (ein zufällig scheiternder Test lehrt alle, Rot zu ignorieren) und behandeln Sie einen fehlgeschlagenen Build als erste Priorität des Teams. Fixieren Sie die in der CI genutzten Werkzeugversionen und behalten Sie eine Möglichkeit, genau dieselben Prüfungen auf Ihrer Maschine auszuführen, damit „läuft bei mir“ und „scheitert in der CI“ nie ein Rätsel sind.
  • CI führt Lint, Typprüfung und Tests bei jedem Push in einer sauberen Umgebung aus; CD veröffentlicht nur automatisch, wenn sie auf main bestehen.
  • Machen Sie Prüfungen deterministisch (Seeds, Snapshots, kein Netz), führen Sie sie auf einer Matrix aus Versionen und Systemen aus und wählen Sie Tests nach dem Geänderten.
  • Beschreiben Sie die Pipeline in einer geprüften Workflow-Datei, knüpfen Sie Deploys an main und erforderliche Jobs, halten Sie Secrets im CI-System und reparieren Sie instabile Tests.

Als Nächstes: geplante Pipelines, Daten- und Trading-Jobs zur richtigen Zeit in der richtigen Reihenfolge ausführen.

Lab: Was bewertet wird

  • Die Testmatrix mit matrix_jobs aufspannen25 Pkt.
  • Mit select_tests nur Relevantes ausführen25 Pkt.
  • Das Release mit can_deploy absichern25 Pkt.
  • Den Workflow mit workflow_yaml erzeugen25 Pkt.
Explorer · lab-131-1
▾ lab-131-1
…
bash · im Browser
learner@quantcraft:~/lab-131-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-131-1 wird auf die Startdateien zurückgesetzt und das Terminal geleert. Ihre aktuelle Lösung geht verloren – das lässt sich nicht rückgängig machen.

Wird zurückgesetzt
  • main.py → Startcode
  • Terminal-Verlauf und Testausgabe
  • Nicht eingereichte Änderungen
Bleibt erhalten
  • Beste Lab-Punktzahl
  • Ihre XP und Ihre Serie
  • Vorlesungsfortschritt und Notizen

Melde dich an, um deinen Code auszuführen.

Alle Lektionen kannst du kostenlos lesen. Erstelle ein Konto oder melde dich an, um Code auszuführen, Tests zu starten und dieses Lab abzugeben.

  • IDE im Browser mit Bash-Terminal — nichts zu installieren
  • Sofortige Bewertung, XP und dein Platz auf der Skill
Konto erstellenAnmelden
ODER
Weiter mit GitHub