σμ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.13·~4 Std.Experte

Abschlussprojekt: eine durchgängige Pricing- oder Strategie-Bibliothek

Position in der SkillModul 11 von 11 · Thema 13 von 13
11.13 Abschlussprojekt: eine durchgängige Pricing- oder Strategie-Bibliothek
—Lab-Punkte— / 100XP gesamt—Serie—

Von Übungen zur Bibliothek

Sie haben hundert kleine Funktionen geschrieben. Eine Bibliothek sind diese Funktionen so angeordnet, dass jemand anderes (auch Sie in sechs Monaten) sie mit Vertrauen nutzen kann: eine klare öffentliche Schnittstelle, jedes Stück einzeln getestet, die Stücke zu einer Pipeline zusammengesetzt und das Ganze installierbar, dokumentiert und automatisch geprüft. Dieses Abschlussprojekt ist das Muster im Kleinen. Eine Strategiebibliothek ist der einfachste Ort, es zu üben: Das Signal macht aus Preisen Positionen, der Backtest macht aus Positionen Renditen nach Kosten, die Kennzahlen fassen die Renditen zusammen, und ein Runner verdrahtet sie. Jede Stufe nimmt einfache Arrays und liefert einfache Arrays, sodass sich jede einzeln mit Zahlen testen lässt, die man von Hand nachrechnen kann.

# The shape of a small library: a package, its tests, its metadata and its automated checks
tree = """\
quantlib/
├── pyproject.toml            name, version, dependencies (numpy)
├── src/quantlib/
│   ├── __init__.py           the public API: sma_positions, strategy_returns, performance_summary, run_strategy
│   ├── signals.py            prices -> positions
│   ├── backtest.py           positions -> returns after costs
│   └── metrics.py            returns -> total return, volatility, Sharpe, drawdown
├── tests/                    one test file per module, fixed seeds, hand-checked cases
└── .github/workflows/ci.yml  lint, types, tests on every push
"""
print(tree.splitlines()[0])                          # quantlib/
print(sum(1 for line in tree.splitlines() if ".py" in line))     # 4   the four module files

Signal und Backtest: ohne Look-ahead, mit Kosten

Das Signal ist hier eine Kreuzung gleitender Durchschnitte: long sein, wenn der schnelle Durchschnitt der Preise über dem langsamen liegt, short, wenn darunter, flat, wenn sie gleich sind oder der langsame noch nicht existiert. Die zwei Regeln, die entscheiden, ob ein Backtest ehrlich ist, sind im Code zu sehen. Erstens kein Look-ahead: Die am Schluss von Tag t entschiedene Position darf nur Preise bis Tag t nutzen und verdient die Rendite von Tag t + 1, weshalb die Rendite des Schritts t positions[t - 1] nutzt. Ein Test beweist es: Das Entfernen der letzten Preise darf frühere Positionen nicht ändern. Zweitens Kosten: Jede Positionsänderung zahlt cost * |Änderung|, sodass eine ständig wechselnde Strategie vor Kosten gewinnen und danach verlieren kann.

# The signal and the honest backtest: positions decided at the close are earned on the NEXT step, and trading costs money
import numpy as np

def sma_positions(prices, fast, slow):
    prices = np.asarray(prices, dtype=float)
    positions = np.zeros(len(prices), dtype=int)
    for t in range(slow - 1, len(prices)):
        f = prices[t - fast + 1 : t + 1].mean()
        s = prices[t - slow + 1 : t + 1].mean()
        positions[t] = 1 if f > s else -1 if f < s else 0
    return positions

def strategy_returns(prices, positions, cost):
    returns = []
    for t in range(1, len(prices)):
        before = positions[t - 2] if t >= 2 else 0
        returns.append(positions[t - 1] * (prices[t] / prices[t - 1] - 1) - cost * abs(positions[t - 1] - before))
    return np.array(returns)

prices = np.array([100, 101, 103, 102, 105, 108, 107, 110, 112, 111, 115, 118], dtype=float)
positions = sma_positions(prices, 2, 4)
print(positions)                                     # [0 0 0 1 1 1 1 1 1 1 1 1]   flat until the 4-day average exists, then long
print(np.allclose(sma_positions(prices[:8], 2, 4), positions[:8]))      # True   later prices never change earlier positions
print(np.round(strategy_returns(prices, positions, 0.0).sum() - strategy_returns(prices, positions, 0.001).sum(), 3))    # 0.001   one purchase at 0.1%

Die Leistungskennzahlen und der Runner

Eine Renditereihe wird durch wenige Zahlen zusammengefasst. Die Gesamtrendite verzinst die Perioden, prod(1 + r) - 1; die Jahresrendite rechnet sie auf ein Jahr um, (1 + total)^(Perioden_pro_Jahr / n) - 1; die Jahresvolatilität ist die Stichproben-Standardabweichung mal sqrt(Perioden_pro_Jahr); die Sharpe-Ratio teilt die mittlere Rendite durch diese Abweichung, annualisiert, und ist die Hauptkennzahl für Rendite pro Risikoeinheit (0 für eine flache Reihe statt eines Divisionsfehlers); der maximale Drawdown ist der schlimmste Rückgang von einem Hoch der Kapitalkurve, die Zahl, die sagt, wie viel Schmerz die Strategie verlangt. Eine Runner-Funktion verbindet alles: Positionen, dann Renditen, dann die Zusammenfassung. Sie sollte nur die anderen Funktionen zusammensetzen, damit sich ein Fehler immer auf eine Stufe zurückführen lässt.

# Performance statistics of a return series, and the runner that wires the three stages together
import math
import numpy as np

def performance_summary(returns, periods_per_year):
    returns = np.asarray(returns, dtype=float)
    n = len(returns)
    equity = np.concatenate(([1.0], np.cumprod(1 + returns)))
    total = float(equity[-1] - 1)
    deviation = float(np.std(returns, ddof=1))
    peak = np.maximum.accumulate(equity)
    return {
        "total_return": total,
        "annual_return": float((1 + total) ** (periods_per_year / n) - 1),
        "annual_vol": deviation * math.sqrt(periods_per_year),
        "sharpe": float(returns.mean() / deviation * math.sqrt(periods_per_year)) if deviation > 0 else 0.0,
        "max_drawdown": float(np.max((peak - equity) / peak)),
    }

summary = performance_summary([0.10, -0.20, 0.05], 252)
print(round(summary["total_return"], 4), round(summary["max_drawdown"], 4))     # -0.076 0.2   equity 1 -> 1.1 -> 0.88 -> 0.924: a 20% fall from the peak
print(performance_summary([0.0, 0.0, 0.0], 252)["sharpe"])                       # 0.0   no variation: a Sharpe of 0, not an error
# The runner only composes: if a number looks wrong you can test each stage on its own
def run_strategy(prices, fast, slow, cost, periods_per_year=252):
    positions = sma_positions(prices, fast, slow)
    returns = strategy_returns(prices, positions, cost)
    return performance_summary(returns, periods_per_year)

# (sma_positions, strategy_returns and performance_summary are the functions you wrote in this lab)
steps = ["sma_positions", "strategy_returns", "performance_summary"]
print(" -> ".join(steps))                           # sma_positions -> strategy_returns -> performance_summary
print(len(steps), "stages, one result: a dict of five numbers")        # 3 stages, one result: a dict of five numbers

Ihr Abschlussprojekt

Bauen Sie nun Ihr eigenes, in Ihrem eigenen Repository. Wählen Sie eine von zwei Richtungen. Eine Bewertungsbibliothek: Black-Scholes und Greeks, ein Monte-Carlo-Bewerter mit antithetischen Variablen, ein Löser für die implizite Volatilität und die Kalibrierung eines Modells an einen Quote-Satz. Oder eine Strategiebibliothek: mehrere Signale, ein Backtest mit Kosten und Positionslimits, Walk-forward-Auswertung und ein Bericht. In beiden Fällen liefern Sie dasselbe: ein Paket mit klarer öffentlicher API und Typannotationen; Tests mit festen Seeds und von Hand geprüften Fällen; eine pyproject.toml und ein README, das Installation und ein Beispiel zeigt; einen CI-Workflow mit Lint, Typen und Tests; eine Performance-Notiz mit einem profilierten Engpass; und einen kurzen Text zu den Annahmen und dem, was das Modell brechen würde. Teilen Sie Ihre Zeit ein: erst die Schnittstelle entwerfen, die kleinste funktionierende Pipeline bauen, dann erweitern.

Ein gutes Ergebnis ist langweilig zu reproduzierenJemand anderes sollte Ihr Repository klonen, einen Befehl ausführen und genau Ihre Zahlen erhalten können. Fixieren Sie Seeds, pinnen Sie Versionen, behalten Sie den Datensnapshot oder ein Skript, das ihn holt, und zeigen Sie die Kapitalkurve neben einem einfachen Benchmark. Berichten Sie, was die Strategie an Drawdown und Umschlag kostet, nicht nur, was sie verdient, und sagen Sie offen, welche Teile Sie nicht getestet haben. Diese Ehrlichkeit macht die Arbeit eines Quants vertrauenswürdig.
  • Eine Bibliothek sind kleine getestete Funktionen, zu einer Pipeline hinter einer klaren Schnittstelle zusammengesetzt: Signal -> Positionen -> Renditen nach Kosten -> Kennzahlen, verdrahtet von einem Runner.
  • Ein ehrlicher Backtest hat kein Look-ahead (die Position bei t nutzt Preise bis t und verdient die nächste Rendite) und berechnet Kosten bei jeder Positionsänderung.
  • Fassen Sie mit Gesamt- und Jahresrendite, Volatilität, Sharpe und maximalem Drawdown zusammen; liefern Sie dann ein Paket mit Tests, CI, einem README und einem ehrlichen Bericht.

Damit ist der Lernpfad abgeschlossen. Sie haben nun die Sprache, die numerischen Werkzeuge, die Bausteine für Marktdaten und Ausführung, die Modelle und die Engineering-Gewohnheiten eines arbeitenden Quant-Entwicklers. Behalten Sie Ihr Abschluss-Repository: Es ist der beste Beleg für die hier aufgebauten Fähigkeiten.

Lab: Was bewertet wird

  • Mit sma_positions einen Trend in Positionen verwandeln25 Pkt.
  • Mit Kosten in strategy_returns backtesten25 Pkt.
  • Das Ergebnis mit performance_summary beurteilen25 Pkt.
  • Alles in run_strategy verdrahten25 Pkt.
Explorer · lab-142-1
▾ lab-142-1
…
bash · im Browser
learner@quantcraft:~/lab-142-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

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