σμ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 Academyロードマップ
Ctrl K
AO
+1.2k 人の学習者
ログイン参加する ↗
ロードマップ
AO
+1.2k 人の学習者
ログイン
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python ロードマップ›モジュール 6 · バックテストと取引コスト›トピック 6.4·~45 分上級

取引コスト

ロードマップ上の位置モジュール 6/11 · トピック 4/6
6.4 取引コスト
—ラボスコア— / 100合計XP—連続日数—

取引は無料ではない

無料で売買するバックテストはどんな戦略も過大評価し、売買が多いほど嘘が大きくなります。実際のコストは、ブローカーの手数料、取引所や規制の手数料、そして何より毎回またぐビッド・アスク・スプレッドです。通常は売買代金のベーシスポイントで表し、1bp は0.01%です。片道5bpの往復は10bpかかり、1日3bpしか稼げない戦略は、毎日ポジションを反転させるとこれに耐えられません。

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

回転率:どれだけ売買するか

コストはポジションの大きさではなく、その変化量で決まります。ポジションを口座に対する割合で表すと、1日の回転率は前日のポジションからの変化の絶対値 abs(position[t] - position[t - 1]) で、0日目は無ポジションから始めます。ロングを持ち続けるのは最初の購入以外コストがかからず、ロングからショートへ反転すると口座を2回分売買します。1年で合計した回転率は、どの戦略でも最初に見る数です。

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

ネットリターンと損益分岐コスト

その日のコストは口座に対する割合で turnover * bps / 10000 となり、ネットリターンはグロスのリターンからそれを引いたものです。便利な1つの数が損益分岐コストで、総利益がちょうどゼロになる売買単位あたりのコスト sum(gross) / sum(turnover) * 10000 です。実際に払うコストと比べてください。損益分岐が2bpの戦略は実質的に死んでいて、40bpの戦略には余裕があります。

# 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
コストは手数料だけではない一律のbp課金は最も単純なモデルです。実際のコストは銘柄、時間帯、注文サイズにも左右されます。小型株や寄り付きではスプレッドが広がり、大きな注文は価格を不利に動かします。これは次のトピックの主題です。モデルが何であれ、コストを無視したバックテストは楽観的で、低く見積もったバックテストは危険です。
  • コストは売買代金のベーシスポイントで表し、abs(notional) * bps / 10000。買いも売りも同じ
  • 回転率は abs(ポジション変化)(反転は2)。ネット=グロス − 回転率 × bps / 10000
  • 損益分岐コスト sum(gross) / sum(turnover) * 10000 は戦略が耐えられるコストの大きさを示す。実際のコストと比べる

次はスリッページです。期待した価格と実際に得た価格の差です。

ラボ:採点される内容

  • trade_cost で1回の取引のコストを求める25点
  • turnover で売買した量を数える25点
  • net_returns で請求額を差し引く25点
  • breakeven_bps で利益を消すコストを求める25点
エクスプローラー · lab-90-1
▾ lab-90-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-90-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

このトピックをリセットしますか?

lab-90-1 の内容はすべてスターターファイルに戻り、ターミナルも消去されます。現在の解答は失われ、元に戻せません。

リセットされるもの
  • main.py → スターターコード
  • ターミナル履歴とテスト出力
  • 未提出の変更
保持されるもの
  • ラボの最高スコア
  • XPと連続日数
  • 講義の進捗とメモ

コードを実行するにはログインしてください。

レクチャーはすべて無料で読めます。コードの実行、テスト、ラボの提出にはアカウントの作成かログインが必要です。

  • ブラウザ内IDEとbashターミナル。インストール不要
  • 即時採点、XP、ロードマップでの現在地
アカウントを作成ログイン
または
GitHubで続ける