σμ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 ロードマップ›モジュール 1 · クオンツのためのPython基礎›トピック 1.31·~40 分初級

ベクトルと内積

ロードマップ上の位置モジュール 1/11 · トピック 31/33
1.31 ベクトルと内積
—ラボスコア— / 100合計XP—連続日数—

ベクトルとは、規則を持つ数のリスト

ベクトルは、[0.5, 0.3, 0.2] のようなポートフォリオのウェイトや、3銘柄のある日のリターン [0.02, -0.01, 0.03] のような、長さの決まった順序付きの数の列です。Python では float のリストで表せます。ベクトルは位置ごとに足し算、スケーリング、組み合わせができ、クオンツファイナンスの多くがこの言葉で書かれているのはそのためです。2つのベクトルは長さが同じでなければ組み合わせられません。長さの不一致は、はっきり知らされるべきバグです。

weights = [0.5, 0.3, 0.2]
returns = [0.02, -0.01, 0.03]

# Position by position: zip pairs the elements
products = [w * r for w, r in zip(weights, returns)]
print([round(p, 4) for p in products])   # [0.01, -0.003, 0.006]

# Scaling and adding vectors
print([2 * w for w in weights])          # [1.0, 0.6, 0.4]
print([a + b for a, b in zip(weights, returns)])  # [0.52, 0.29, 0.23]

内積

内積は、2つのベクトルを位置ごとに掛けて合計します:a1*b1 + a2*b2 + ... + an*bn。結果は1つの数です。a がウェイト、b がリターンなら、それがポートフォリオのリターンです:0.5*0.02 + 0.3*(-0.01) + 0.2*0.03 = 0.013。ポジション一覧の価値(数量と価格の内積)や、回帰の構成要素でもあります。Python では、len(a) == len(b) を確認したうえで sum(x * y for x, y in zip(a, b)) と書きます。zip は短いほうで黙って止まるからです。

def dot(a, b):
    if len(a) != len(b):
        raise ValueError("vectors must have the same length")
    return sum(x * y for x, y in zip(a, b))

print(dot([1, 2, 3], [4, 5, 6]))                       # 32
print(round(dot([0.5, 0.3, 0.2], [0.02, -0.01, 0.03]), 6))  # 0.013  (portfolio return)

try:
    dot([1, 2], [1, 2, 3])
except ValueError as error:
    print(error)                                       # vectors must have the same length

長さ・向き・類似度

ベクトル自身との内積は長さの2乗になるので、ノルム(長さ)は math.sqrt(dot(a, a)) です。[3, 4] なら 5.0 です。ベクトルをノルムで割ると、向きだけを保つ長さ1の単位ベクトルになります(ただしゼロベクトルには向きがないので ValueError で拒否します)。コサイン類似度 dot(a, b) / (norm(a) * norm(b)) は2つのベクトルの向きの揃い具合を -1(正反対)、0(無関係、直角)、1(スケールによらず同じ向き)で測ります。平均を引いたリターン系列に適用すると相関になり、ポートフォリオのリスクで中心的な量です。

import math

def dot(a, b):
    return sum(x * y for x, y in zip(a, b))

def norm(a):
    return math.sqrt(dot(a, a))

print(norm([3, 4]))                                    # 5.0

def normalize(a):
    length = norm(a)
    if length == 0:
        raise ValueError("a zero vector has no direction")
    return [x / length for x in a]

print(normalize([3, 4]))                               # [0.6, 0.8]

def cosine_similarity(a, b):
    return dot(a, b) / (norm(a) * norm(b))

print(round(cosine_similarity([1, 2], [2, 4]), 6))     # 1.0   (same direction)
print(cosine_similarity([1, 0], [0, 1]))               # 0.0   (perpendicular)
print(round(cosine_similarity([1, 2], [-1, -2]), 6))   # -1.0  (opposite)
import math

def dot(a, b):
    return sum(x * y for x, y in zip(a, b))

def mean(values):
    return sum(values) / len(values)

# Correlation is the cosine of the demeaned series
a = [0.01, 0.02, -0.01, 0.03]
b = [0.02, 0.04, -0.02, 0.06]       # always twice a
da = [x - mean(a) for x in a]
db = [x - mean(b) for x in b]
corr = dot(da, db) / math.sqrt(dot(da, da) * dot(db, db))
print(round(corr, 6))               # 1.0

# Value of a book: quantities dot prices
quantities = [100, -50, 20]
prices = [184.0, 410.0, 171.0]
print(dot(quantities, prices))      # 1320.0
zip は長さの不一致を隠し、浮動小数点は厳密な等しさを隠すzip を使う前に必ず長さを確認しましょう。そうしないとデータが黙って捨てられます。また、float の結果を == で比べてはいけません。同じ向きの2つのベクトルのコサインが 0.9999999999999999 になることがあります。ラボのテストのように math.isclose(...) で比べます。実務ではまもなく NumPy を使い、np.dot や np.linalg.norm がこれらを高速に行いますが、何を計算しているか知っていれば検算できます。
  • 内積:位置ごとに掛けて合計する。先に長さを確認する
  • ノルム sqrt(dot(a, a))、単位ベクトル a / norm(a)(ゼロベクトルは拒否)
  • コサイン類似度 dot(a, b) / (norm(a) * norm(b)) は -1 から 1。float は isclose で比べる

次は行列と連立一次方程式です。ベクトルに作用し、多数の方程式を一度に解く数の表を学びます。

ラボ:採点される内容

  • dot でウェイトとリターンを組み合わせる25点
  • norm でベクトルの長さを測る25点
  • cosine_similarity で向きを比較する25点
  • normalize でベクトルの長さを1にそろえる25点
エクスプローラー · lab-31-1
▾ lab-31-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-31-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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