σμ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 1 · Python-Grundlagen für Quants›Thema 1.25·~40 Min.Einsteiger

Reproduzierbare Forschungs-Workflows

Position in der SkillModul 1 von 11 · Thema 25 von 33
1.25 Reproduzierbare Forschungs-Workflows
—Lab-Punkte— / 100XP gesamt—Serie—

Gleiche Eingaben, gleiche Antwort

Ein Ergebnis ist reproduzierbar, wenn Sie, ein Kollege oder ein Prüfer dasselbe Projekt später ausführen und dieselben Zahlen erhalten. Ein Backtest, der sich nicht neu erzeugen lässt, kann weder geprüft noch debuggt noch geglaubt werden. Ergebnisse driften aus wenigen Gründen: Zufallszahlen, unterschiedliche Bibliotheksversionen, geänderte oder von Hand bearbeitete Daten, im Code verstreute Einstellungen und versteckter Zustand, etwa ein in falscher Reihenfolge ausgeführtes Notebook. Ein reproduzierbarer Ablauf beseitigt jede Driftquelle und hält fest, was verwendet wurde.

import random

# Same seed, same "random" numbers
a = random.Random(42)
b = random.Random(42)
print([round(a.random(), 3) for _ in range(3)])   # [0.639, 0.025, 0.275]
print([round(b.random(), 3) for _ in range(3)])   # [0.639, 0.025, 0.275]

# A different seed gives a different but equally repeatable sequence
print(round(random.Random(7).random(), 3))        # 0.324

Seeds und welcher Generator sie besitzt

Simulationen und Bootstraps nutzen Zufallszahlen, die in Wahrheit eine deterministische Folge sind, die von einem Seed startet. Legen Sie den Seed fest, und der Lauf wiederholt sich exakt. random.seed(42) initialisiert den einen globalen Generator, den das ganze Programm teilt; anderer Code, der Zahlen zieht, verschiebt daher Ihre Folge. Sicherer ist ein eigener Generator, rng = random.Random(42) (oder numpy.random.default_rng(42)), den Sie weiterreichen und aus dem Sie ziehen. Dann hängen Ihre Ergebnisse nur von Ihrem Seed ab, und Ihr Seeding stört niemandes Zufall.

import random

# The global generator is shared: seeding it changes everyone's numbers
random.seed(1)
first = random.random()
random.seed(1)
print(random.random() == first)        # True: global seeding repeats...

# ...but a private generator leaves the global one untouched
random.seed(1)
before = random.getstate()
mine = random.Random(99)
mine.random()
print(random.getstate() == before)     # True: your draws did not disturb it

Fingerabdrücke für Daten und Einstellungen

Woher wissen Sie, dass die Datendatei dieselbe ist wie letzten Monat? Berechnen Sie eine Prüfsumme: Ein Hash wie SHA-256 macht jede Datei zu einem kurzen String fester Länge, der sich ändert, sobald sich nur ein Byte ändert. hashlib.sha256(data).hexdigest() liefert ihn; große Dateien lesen Sie blockweise. Einstellungen verdienen dieselbe Behandlung: Serialisieren Sie die Konfiguration mit sortierten Schlüsseln (json.dumps(config, sort_keys=True)) und hashen Sie den Text; der Fingerabdruck ist für zwei gleichbedeutende Konfigurationen unabhängig von der Schlüsselreihenfolge identisch und unterscheidet sich, sobald sich ein Wert ändert.

import hashlib
import json

# A checksum of bytes
print(hashlib.sha256(b"AAPL,184.25").hexdigest()[:12])   # 06ea4aa73ec1 (12 characters of 64)

# A fingerprint of settings, independent of key order
def fingerprint(config):
    text = json.dumps(config, sort_keys=True, separators=(",", ":"))
    return hashlib.sha256(text.encode("utf-8")).hexdigest()[:12]

one = {"fee": 0.001, "window": 20}
two = {"window": 20, "fee": 0.001}
print(fingerprint(one) == fingerprint(two))              # True
print(fingerprint(one) == fingerprint({"fee": 0.002, "window": 20}))  # False

Halten Sie fest, was Sie ausgeführt haben

Jeder Lauf sollte neben seinen Ergebnissen ein kleines Manifest hinterlassen: den Seed, den Konfigurations-Fingerabdruck, die Python- und Bibliotheksversionen, die Prüfsumme jeder Eingabedatei und den Git-Commit des Codes. Mit dieser Aufzeichnung können Sie genau sagen, was eine Zahl erzeugt hat, und sie später neu aufbauen. Kombinieren Sie sie mit den früheren Gewohnheiten: eine in requirements.txt festgelegte Umgebung, Code in Git, Einstellungen in einer Datei, ein Befehl, der alles von den Rohdaten bis zu den Endtabellen ausführt, und keine manuellen Datenänderungen dazwischen.

import json
import platform

# A manifest records what a run used
manifest = {
    "seed": 42,
    "config_fingerprint": "a1b2c3d4e5f6",
    "python": platform.python_version().split(".")[0] + ".x",
    "inputs": {"prices.csv": "9f86d081884c"},
}
print(json.dumps(manifest, indent=2, sort_keys=True))
# {
#   "config_fingerprint": "a1b2c3d4e5f6",
#   "inputs": {
#     "prices.csv": "9f86d081884c"
#   },
#   "python": "3.x",
#   "seed": 42
# }
Reproduzierbar heißt nicht korrektAuch ein Fehler wiederholt sich perfekt. Reproduzierbarkeit lässt andere Ihre Arbeit prüfen, den Fehler finden und der Korrektur trauen; sie ersetzt weder Tests noch Plausibilitätsprüfungen der Daten noch einen kritischen Blick auf das Ergebnis. Seeds verbergen auch Glück: Hängt ein Ergebnis vom Seed ab, führen Sie es mit mehreren aus und berichten Sie die Streuung.
  • Nutzen Sie ein eigenes random.Random(seed), damit die Ergebnisse nur von Ihrem Seed abhängen.
  • Fingerabdruck für Daten (Datei-Prüfsumme) und Einstellungen (sortiertes JSON, dann SHA-256).
  • Speichern Sie bei jedem Lauf ein Manifest; fixierte Umgebung + Git-Commit + ein Befehl zum Neuaufbau.

Als Nächstes: Klassen und Objekte, um Daten und die Funktionen dazu in einer sauberen Einheit zu bündeln.

Lab: Was bewertet wird

  • Mit seeded_returns wiederholbare Zufallsrenditen erzeugen25 Pkt.
  • Mit file_checksum einer Datendatei einen Fingerabdruck geben25 Pkt.
  • Mit config_fingerprint einer Konfiguration einen Fingerabdruck geben25 Pkt.
  • Mit run_manifest festhalten, was ein Lauf verwendet hat25 Pkt.
Explorer · lab-25-1
▾ lab-25-1
…
bash · im Browser
learner@quantcraft:~/lab-25-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

Alles in lab-25-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