σμ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 6 · Backtesting und Handelskosten›Thema 6.4·~45 Min.Fortgeschritten

Transaktionskosten

Position in der SkillModul 6 von 11 · Thema 4 von 6
6.4 Transaktionskosten
—Lab-Punkte— / 100XP gesamt—Serie—

Handeln ist nicht gratis

Ein Backtest, der gratis handelt, überschätzt jede Strategie, und je mehr sie handelt, desto mehr lügt er. Reale Kosten sind die Broker-Provision, Börsen- und Aufsichtsgebühren und vor allem der Spread, den man jedes Mal überquert. Sie werden meist in Basispunkten des Handelswerts angegeben: 1 bp sind 0,01 %. Ein Round-Trip mit je 5 bp kostet 10 bp, was eine Strategie mit 3 bp Tagesgewinn nicht überlebt, wenn sie täglich dreht.

def trade_cost(notional, bps):
    return abs(notional) * bps / 10000

print(trade_cost(25000, 5))         # 12.5   buying 25,000 at 5 bps
print(trade_cost(-25000, 5))        # 12.5   selling costs the same
print(trade_cost(1_000_000, 1))     # 100.0  one basis point on a million

Umschlag: wie viel Sie handeln

Die Kosten hängen davon ab, wie stark sich die Position ändert, nicht von ihrer Größe. Ist die Position ein Anteil des Kontos, ist der Umschlag eines Tages die absolute Änderung gegenüber der vorherigen Position: abs(position[t] - position[t - 1]), an Tag 0 ab flach. Long zu bleiben kostet nach dem ersten Kauf nichts; von Long auf Short zu wechseln handelt das Konto zweimal. Über ein Jahr summiert ist der Umschlag die erste Zahl, die man bei jeder Strategie ansieht.

import numpy as np

positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0])        # long, long, flip to short, short, flat
turnover = np.abs(np.diff(positions, prepend=0.0))       # day 0 starts from a flat position
print(turnover)                                          # [1. 0. 2. 0. 1.]
print(turnover.sum())                                    # 4.0  accounts traded over the five days

Nettorenditen und Break-even-Kosten

Die Kosten eines Tages als Anteil des Kontos sind turnover * bps / 10000, und die Nettorendite ist die Bruttorendite minus diese Kosten. Eine nützliche Einzelzahl ist der Break-even-Kostensatz: der Kostensatz je gehandelter Einheit, bei dem der Gesamtgewinn genau null ist, sum(gross) / sum(turnover) * 10000. Vergleichen Sie ihn mit dem, was Sie wirklich zahlen. Eine Strategie mit 2 bp Break-even ist praktisch tot, eine mit 40 bp hat Spielraum.

# Gross and net returns of a rule that flips often, at 5 bps per unit traded
import numpy as np

rng = np.random.default_rng(11)
positions = np.where(rng.random(250) > 0.5, 1.0, -1.0)      # a coin-flip position, flipping often
gross = rng.normal(0.0015, 0.005, size=250)                   # a strategy with a real daily edge before costs

turnover = np.abs(np.diff(positions, prepend=0.0))
net = gross - turnover * 5 / 10000
print(round(float(gross.sum()), 4), round(float(net.sum()), 4))
print(round(float(turnover.sum()), 1), "accounts traded;", round(float(gross.sum() / turnover.sum() * 10000), 2), "bps break-even")
# The break-even cost of a small example
import numpy as np

gross = np.array([0.004, 0.002, 0.003, 0.001, 0.002])
positions = np.array([1.0, 1.0, -1.0, -1.0, 0.0])
turnover = np.abs(np.diff(positions, prepend=0.0))
breakeven = gross.sum() / turnover.sum() * 10000
print(round(float(breakeven), 2))                                           # 30.0 bps per unit traded
print(abs(round(float((gross - turnover * breakeven / 10000).sum()), 10)))       # 0.0: the whole profit is gone
Kosten sind nicht nur ProvisionEin fester bp-Satz ist das einfachste Modell. Reale Kosten hängen auch vom Instrument, der Tageszeit und der Ordergröße ab: Der Spread ist bei Small Caps und zur Eröffnung weiter, und große Orders bewegen den Preis gegen Sie, das Thema der nächsten Themen. Egal welches Modell: Ein Backtest ohne Kosten ist optimistisch, und einer mit zu niedrigen Kosten gefährlich.
  • Kosten werden in Basispunkten des Handelswerts angegeben: abs(notional) * bps / 10000, für Kauf und Verkauf gleich.
  • Der Umschlag ist abs(Positionsänderung) (ein Wechsel handelt 2); Nettorendite = brutto - Umschlag * bp / 10000.
  • Der Break-even-Kostensatz sum(gross) / sum(turnover) * 10000 zeigt, wie viel Kosten eine Strategie verträgt; vergleichen Sie ihn mit dem echten.

Als Nächstes: Slippage, die Lücke zwischen erwartetem und erhaltenem Preis.

Lab: Was bewertet wird

  • Mit trade_cost einen Handel beziffern25 Pkt.
  • Mit turnover das Gehandelte zählen25 Pkt.
  • Mit net_returns die Rechnung abziehen25 Pkt.
  • Mit breakeven_bps die Kosten finden, die sie töten25 Pkt.
Explorer · lab-90-1
▾ lab-90-1
…
bash · im Browser
learner@quantcraft:~/lab-90-1$
Python noch nicht geladenPythonLn 1, Col 1Spaces: 4UTF-8

Dieses Thema zurücksetzen?

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