σμ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 AcademyRutas
Ctrl K
AO
+1,2 k estudiantes
Iniciar sesiónUnirse ↗
Rutas
AO
+1,2 k estudiantes
Iniciar sesión
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Ruta de Python›Módulo 1 · Fundamentos de Python para quants›Tema 1.28·~35 minPrincipiante

Dataclasses

Posición en la rutaMódulo 1 de 11 · Tema 28 de 33
1.28 Dataclasses
—Puntuación del lab— / 100XP total—Racha—

Menos código repetitivo para clases que guardan datos

Muchas clases existen sobre todo para guardar unos pocos campos: una operación, una cotización, una configuración. Escribir __init__, __repr__ y __eq__ para cada una es repetitivo. El decorador @dataclass del módulo dataclasses los escribe por ti a partir de una lista de campos anotados. Declaras symbol: str, price: float, quantity: int una vez y obtienes un constructor Trade("AAPL", 184.25, 200), un repr legible como Trade(symbol='AAPL', price=184.25, quantity=200) y una igualdad campo a campo. Las anotaciones documentan la intención; Python no las impone.

from dataclasses import dataclass

@dataclass
class Trade:
    symbol: str
    price: float
    quantity: int

a = Trade("AAPL", 184.25, 200)
b = Trade("AAPL", 184.25, 200)

print(a)                       # Trade(symbol='AAPL', price=184.25, quantity=200)
print(a == b)                  # True: compared field by field
print(a.price * a.quantity)    # 36850.0

Valores por defecto, field() y valores mutables

Un campo puede tener un valor por defecto (currency: str = "USD"), y los campos con valor por defecto deben ir después de los que no lo tienen. Para un valor por defecto mutable como una lista, un simple = [] lo compartirían todos los objetos (y Python lo rechaza); escribe trades: list = field(default_factory=list) para que cada objeto reciba su propia lista nueva. field(...) permite también ocultar un campo del repr (repr=False) o de las comparaciones (compare=False).

from dataclasses import dataclass, field

@dataclass
class Book:
    name: str
    currency: str = "USD"                       # a default
    trades: list = field(default_factory=list)  # a fresh list per object

one = Book("desk-a")
two = Book("desk-b")
one.trades.append(("AAPL", 100))

print(one)                  # Book(name='desk-a', currency='USD', trades=[('AAPL', 100)])
print(two.trades)           # []   (not shared)
print(Book("x", "EUR"))     # Book(name='x', currency='EUR', trades=[])

Tus propios métodos, __post_init__ y constructores alternativos

Una dataclass sigue siendo una clase normal, así que puedes añadir métodos. __post_init__(self) se ejecuta justo después del __init__ generado, el lugar para validar o limpiar valores (self.symbol = self.symbol.upper(), raise ValueError(...) para un mal precio). Un @classmethod recibe la clase como cls y es la forma habitual de construir un objeto desde otra forma, como texto: Trade.from_line("AAPL,184.25,200") devuelve cls(symbol, float(price), int(quantity)), así la validación sigue aplicándose y las subclases también funcionan.

from dataclasses import dataclass

@dataclass
class Trade:
    symbol: str
    price: float
    quantity: int

    def __post_init__(self):
        self.symbol = self.symbol.strip().upper()
        if self.price <= 0:
            raise ValueError("price must be positive")

    def notional(self):
        return self.price * abs(self.quantity)

    @classmethod
    def from_line(cls, line):
        symbol, price, quantity = line.split(",")
        return cls(symbol, float(price), int(quantity))

t = Trade.from_line(" aapl,184.25,-200")
print(t)              # Trade(symbol='AAPL', price=184.25, quantity=-200)
print(t.notional())   # 36850.0

Congeladas, ordenadas y cuándo ganan las clases normales

@dataclass(frozen=True) hace que las instancias sean de solo lectura (asignar a un campo lanza FrozenInstanceError) y les da un hash, así que pueden ser claves de diccionario o miembros de conjunto: ideal para valores que no deben cambiar, como la especificación de un contrato. @dataclass(order=True) añade <, <=, >, >= comparando los campos en orden. Usa una dataclass para registros de datos; para objetos con mucho comportamiento y estado oculto, una clase escrita a mano con métodos cuidados es más clara.

from dataclasses import dataclass

@dataclass(frozen=True, order=True)
class Contract:
    symbol: str
    expiry: str          # ISO dates sort correctly as text

a = Contract("ESZ5", "2025-12-19")
b = Contract("ESZ5", "2026-03-20")
print(a < b)                          # True
print({a: "front", b: "next"}[a])     # front  (frozen => hashable)

try:
    a.symbol = "NQZ5"
except Exception as error:
    print(type(error).__name__)       # FrozenInstanceError
Valida donde entran los datosAnotaciones como price: float no impiden crear Trade("AAPL", "abc", 1). Si valores erróneos corrompieran en silencio cálculos posteriores, compruébalos en __post_init__ y lanza ValueError, de modo que un registro roto no pueda existir. Crea siempre los objetos mediante el constructor normal, también desde from_line, para que la comprobación no se pueda saltar.
  • @dataclass convierte campos anotados en __init__, __repr__ y __eq__.
  • Los valores por defecto van al final; usa field(default_factory=list) para listas y diccionarios.
  • __post_init__ valida; @classmethod construye desde otras formas; frozen=True hace los valores de solo lectura.

A continuación: derivadas en código, estimar con qué rapidez cambia una magnitud, la idea detrás de sensibilidades de opciones como delta y gamma.

Lab: qué se califica

  • Limpiar y validar una operación con __post_init__25 pts
  • Calcular el valor negociado con notional25 pts
  • Construir una operación desde texto con from_line25 pts
  • Netear las operaciones de un símbolo con net_quantity25 pts
Explorador · lab-28-1
▾ lab-28-1
…
bash · en el navegador
learner@quantcraft:~/lab-28-1$
Python aún no cargadoPythonLn 1, Col 1Spaces: 4UTF-8

¿Restablecer este tema?

Todo lo que hay en lab-28-1 vuelve a los archivos iniciales y se limpia el terminal. Tu solución actual se perderá: no se puede deshacer.

Se restablecerá
  • main.py → código inicial
  • Historial del terminal y salida de pruebas
  • Cambios sin enviar
Se conservará
  • Mejor puntuación del lab
  • Tu XP y tu racha
  • Progreso de la lección y notas

Inicia sesión para ejecutar tu código.

Todas las clases se pueden leer gratis. Crea una cuenta o inicia sesión para ejecutar código, lanzar las pruebas y enviar este lab.

  • IDE en el navegador con terminal bash — sin instalar nada
  • Corrección instantánea, XP y tu lugar en la ruta
Crear una cuentaIniciar sesión
O
Continuar con GitHub