σμ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.26·~45 分初級

クラスとオブジェクト

ロードマップ上の位置モジュール 1/11 · トピック 26/33
1.26 クラスとオブジェクト
—ラボスコア— / 100合計XP—連続日数—

データと振る舞いをひとまとめに

これまで、ポジションはタプルや辞書で表し、別々の関数がそれを処理していました。クラスは、データとそれに属する関数をひとつの新しい型にまとめます。class Position: が設計図を定義し、それを呼び出す Position("AAPL", 100, 180.0) が、その設計図からオブジェクト(インスタンスとも呼ばれます)を作ります。各オブジェクトは自分のデータを持ち、クラスの中で定義された関数、つまりメソッドがそのオブジェクトに対して働きます。

class Position:
    def __init__(self, symbol, quantity=0):
        self.symbol = symbol          # attributes belong to this object
        self.quantity = quantity

    def describe(self):
        return f"{self.quantity} x {self.symbol}"

apple = Position("AAPL", 100)
tesla = Position("TSLA")

print(apple.describe())   # 100 x AAPL
print(tesla.describe())   # 0 x TSLA
print(apple.quantity, tesla.quantity)  # 100 0

__init__ と self

__init__ はコンストラクターです。オブジェクトを作るときに Python が自動で実行し、初期値を保存します。すべてのメソッドは第1引数としてオブジェクト自身を受け取り、慣習で self と呼びます。自分で渡す必要はなく、Python が渡します(apple.describe() は Position.describe(apple) を呼びます)。self.name = value で保存したものはそのオブジェクトの属性となり、メソッド呼び出しをまたいで残ります。__init__ は準備をするだけで、何も返しません。

class Account:
    def __init__(self, cash):
        self.cash = cash

    def deposit(self, amount):
        self.cash += amount          # changes this object's attribute
        return self.cash

first = Account(1000)
second = Account(50)

first.deposit(500)
print(first.cash, second.cash)       # 1500 50  (separate objects, separate data)

same = first                          # a second name for the same object
same.deposit(1)
print(first.cash)                     # 1501

状態を変えるメソッドと、問いに答えるメソッド

オブジェクトを変えずに問いに答えるメソッド(market_value(price))は、結果を返すだけで属性には触れないようにします。オブジェクトを変更するメソッド(apply_fill)は、属性を更新し、実現損益のような有用な値を返すことがよくあります。メソッドは self.other_method(...) で別のメソッドを呼べるため、ルールを1か所にまとめられます。unrealized_pnl が時価を必要とするなら、式を繰り返さず self.market_value(price) に尋ねます。

class Position:
    def __init__(self, symbol, quantity=0, avg_price=0.0):
        self.symbol = symbol
        self.quantity = quantity
        self.avg_price = avg_price

    def market_value(self, price):
        return self.quantity * price

    def unrealized_pnl(self, price):
        return self.market_value(price) - self.quantity * self.avg_price

pos = Position("AAPL", 100, 180.0)
print(pos.market_value(185.0))       # 18500.0
print(pos.unrealized_pnl(185.0))     # 500.0

落とし穴と、クラスを使うべきとき

self. を忘れるのは典型的なミスで、メソッド内の quantity = 5 は属性ではなく使い捨てのローカル変数を作ります。クラス名は CapWords(Position)、属性とメソッドは小文字とアンダースコアで書き、先頭のアンダースコア(_cache)は内部用の印です。def __init__(self, fills=[]) のような変更可能なデフォルト値は使わないでください。すべてのオブジェクトがその1つのリストを共有してしまいます。fills=None として、内部で [] を作りましょう。クラスは、データとそれに関するルールが一緒に動くときに作ります。単純な関数や辞書のほうが簡単なことも多いです。

class Wrong:
    def __init__(self, quantity):
        quantity = quantity          # forgot self.: nothing is stored

class Shared:
    def __init__(self, fills=[]):    # one list shared by every object
        self.fills = fills

class Right:
    def __init__(self, fills=None):
        self.fills = [] if fills is None else list(fills)

a, b = Shared(), Shared()
a.fills.append(100)
print(b.fills)                        # [100]  (surprise!)

c, d = Right(), Right()
c.fills.append(100)
print(d.fills)                        # []

print(hasattr(Wrong(5), "quantity"))  # False
各オブジェクトが自分の状態を持つことを確認するクラスを書くときの良い習慣は、2つのオブジェクトを作り、片方を変更して、もう片方を表示してみることです。後者も変わったなら、共有されるべきでないものが共有されています。ラボのテストはまさにこれを行い、問いに答えるだけのメソッドが属性を変えないことも確認します。
  • class Name: で型を定義し、Name(args) でオブジェクトを作って __init__ を実行する
  • self.attr = value でオブジェクトにデータを保存する。メソッドは最初に self を受け取る
  • 問い合わせメソッドは答えを返し、更新メソッドは属性を変える。変更可能なデフォルト値は避ける

次は __repr__ や __eq__ などの特殊メソッドです。オブジェクトをきれいに表示し、期待どおりに比較できるようにします。

ラボ:採点される内容

  • __init__ でポジションを作る25点
  • market_value でポジションの時価を求める25点
  • unrealized_pnl で含み損益を計算する25点
  • apply_fill で約定後にポジションを更新する25点
エクスプローラー · lab-26-1
▾ lab-26-1
…
bash · ブラウザ内
learner@quantcraft:~/lab-26-1$
Pythonは未読み込みPythonLn 1, Col 1Spaces: 4UTF-8

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

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

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

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

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

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