σμ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)把数据和属于它们的函数打包成一种新类型。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 会自动运行它,由它保存初始值。每个方法都会把对象本身作为第一个参数接收,按惯例叫 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(...) 调用另一个,让规则集中在一处:如果 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=[]) 这样的可变默认值:所有对象会共享那一个列表;应使用 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
确认每个对象都有自己的状态写类时的一个好习惯:创建两个对象,修改其中一个,再打印另一个。如果第二个也变了,说明有不该共享的东西被共享了。实验的测试正是这样做的,并且还会检查本该只回答问题的方法有没有改动属性。
  • 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 继续