σμ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.2k Learners
LoginJoin ↗
Skills
AO
+1.2k Learners
Login
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Python skill›Module 1 · Python foundations for quants›Topic 1.26·~45 minBeginner

Classes and objects

Skill positionModule 1 of 11 · Topic 26 of 33
1.26 Classes and objects
—Lab score— / 100Total XP—Streak—

Data and behaviour together

So far a position could be a tuple or a dictionary, with separate functions working on it. A class bundles the data and the functions that belong to it into one new type. class Position: defines the blueprint; calling it, Position("AAPL", 100, 180.0), builds an object (also called an instance) from that blueprint. Each object holds its own data, and the functions defined in the class, called methods, work on that object.

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__ and self

__init__ is the constructor: Python runs it automatically when you create an object, and it stores the starting values. Every method receives the object itself as its first parameter, conventionally called self; you do not pass it, Python does (apple.describe() calls Position.describe(apple)). Anything saved as self.name = value is an attribute of that object and stays there between method calls. __init__ sets things up and returns nothing.

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

Methods that change state or answer questions

Some methods answer a question about the object without changing it (market_value(price)); they should just return a result and leave the attributes alone. Others change the object (apply_fill), updating attributes and often returning something useful such as the realised profit. A method can call another with self.other_method(...), which keeps rules in one place: if unrealized_pnl needs the market value, it asks self.market_value(price) rather than repeating the formula.

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

Pitfalls and when to use a class

Forgetting self. is the classic slip: quantity = 5 inside a method creates a throw-away local variable, not an attribute. Use CapWords for class names (Position) and lower-case with underscores for attributes and methods; a leading underscore (_cache) marks something as internal. Never use a mutable default such as def __init__(self, fills=[]): all objects would share that one list; use fills=None and create [] inside. Make a class when data and the rules about it travel together; a plain function or dictionary is often simpler.

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
Check that each object keeps its own stateA good habit when you write a class: make two objects, change one, and print the other. If the second changed too, something is shared that should not be. The lab tests do exactly this, and they also check that a method which should only answer a question leaves the attributes unchanged.
  • class Name: defines a type; Name(args) builds an object and runs __init__.
  • self.attr = value stores data on the object; every method takes self first.
  • Query methods return answers; update methods change attributes; avoid mutable defaults.

Next up: special methods such as __repr__ and __eq__, which make your objects print nicely and compare as you expect.

Lab · what's graded

  • Build a position with __init__25 pts
  • Value the position with market_value25 pts
  • Measure the paper profit with unrealized_pnl25 pts
  • Update the position after a trade with apply_fill25 pts
Explorer · lab-26-1
▾ lab-26-1
…
bash · in-browser
learner@quantcraft:~/lab-26-1$
Python not loaded yetPythonLn 1, Col 1Spaces: 4UTF-8

Reset this topic?

Everything in lab-26-1 goes back to the starter files and the terminal is cleared. Your current solution will be lost — this can't be undone.

Will be reset
  • main.py → starter code
  • Terminal history and test output
  • Unsubmitted changes
Will be kept
  • Best lab score
  • Your XP and streak
  • Lecture progress and notes

Log in to run your code.

Every lecture is free to read. Create an account or log in to run code, run tests and submit this lab.

  • In-browser IDE with a bash terminal — nothing to install
  • Instant grading, XP and your place on the skill
Create an accountLog in
OR
Continue with GitHub