σμ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 AcademyParcours
Ctrl K
AO
+1,2 k apprenants
ConnexionRejoindre ↗
Parcours
AO
+1,2 k apprenants
Connexion
  • English
  • Français
  • Español
  • العربية
  • Português
  • Deutsch
  • 日本語
  • 中文
Parcours Python›Module 1 · Les bases de Python pour les quants›Sujet 1.28·~35 minDébutant

Dataclasses

Position dans le parcoursModule 1 sur 11 · Sujet 28 sur 33
1.28 Dataclasses
—Score du lab— / 100XP total—Série—

Moins de code répétitif pour les classes qui portent des données

Beaucoup de classes existent surtout pour contenir quelques champs : une transaction, une cotation, une configuration. Écrire __init__, __repr__ et __eq__ pour chacune est répétitif. Le décorateur @dataclass du module dataclasses les écrit pour vous à partir d'une liste de champs annotés. Vous déclarez une fois symbol: str, price: float, quantity: int et vous obtenez un constructeur Trade("AAPL", 184.25, 200), un repr lisible comme Trade(symbol='AAPL', price=184.25, quantity=200) et une égalité champ par champ. Les annotations documentent l'intention ; Python ne les impose pas.

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

Valeurs par défaut, field() et valeurs modifiables

Un champ peut avoir une valeur par défaut (currency: str = "USD"), et les champs avec défaut doivent venir après ceux qui n'en ont pas. Pour un défaut modifiable comme une liste, un simple = [] serait partagé par tous les objets (et Python le refuse) ; écrivez trades: list = field(default_factory=list) pour que chaque objet reçoive sa propre liste neuve. field(...) permet aussi de masquer un champ du repr (repr=False) ou des comparaisons (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=[])

Vos méthodes, __post_init__ et constructeurs alternatifs

Une dataclass reste une classe ordinaire : on peut y ajouter des méthodes. __post_init__(self) s'exécute juste après le __init__ généré, c'est l'endroit pour valider ou nettoyer les valeurs (self.symbol = self.symbol.upper(), raise ValueError(...) pour un mauvais prix). Une @classmethod reçoit la classe sous le nom cls et c'est la façon habituelle de construire un objet depuis une autre forme, comme du texte : Trade.from_line("AAPL,184.25,200") renvoie cls(symbol, float(price), int(quantity)), si bien que la validation s'applique toujours et que les sous-classes fonctionnent aussi.

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

Figé, ordonné, et quand les classes ordinaires gagnent

@dataclass(frozen=True) rend les instances en lecture seule (assigner à un champ lève FrozenInstanceError) et leur donne un hachage, ce qui permet de les utiliser comme clés de dictionnaire ou membres d'ensemble : idéal pour des valeurs qui ne doivent pas changer, comme la spécification d'un contrat. @dataclass(order=True) ajoute <, <=, >, >= en comparant les champs dans l'ordre. Utilisez une dataclass pour des enregistrements de données ; pour des objets riches en comportement et en état caché, une classe écrite à la main avec des méthodes soignées est plus claire.

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
Validez là où les données entrentDes annotations comme price: float n'empêchent pas la création de Trade("AAPL", "abc", 1). Si de mauvaises valeurs corrompaient silencieusement des calculs ultérieurs, vérifiez-les dans __post_init__ et levez ValueError, afin qu'un enregistrement cassé ne puisse pas exister. Créez toujours les objets via le constructeur normal, y compris depuis from_line, pour que la vérification ne puisse pas être contournée.
  • @dataclass transforme des champs annotés en __init__, __repr__ et __eq__.
  • Les défauts viennent en dernier ; utilisez field(default_factory=list) pour les listes et dictionnaires.
  • __post_init__ valide ; @classmethod construit depuis d'autres formes ; frozen=True rend les valeurs en lecture seule.

À suivre : les dérivées en code, estimer la vitesse de variation d'une grandeur, l'idée derrière les sensibilités d'options comme delta et gamma.

Lab : ce qui est noté

  • Nettoyer et valider une transaction avec __post_init__25 pts
  • Calculer la valeur échangée avec notional25 pts
  • Construire une transaction depuis du texte avec from_line25 pts
  • Compenser les transactions d'un symbole avec net_quantity25 pts
Explorateur · lab-28-1
▾ lab-28-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-28-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-28-1 revient aux fichiers de départ et le terminal est vidé. Votre solution actuelle sera perdue : cette action est irréversible.

Sera réinitialisé
  • main.py → code de départ
  • Historique du terminal et sortie des tests
  • Modifications non soumises
Sera conservé
  • Meilleur score du lab
  • Votre XP et votre série
  • Progression du cours et notes

Connectez-vous pour exécuter votre code.

Tous les cours sont gratuits à lire. Créez un compte ou connectez-vous pour exécuter du code, lancer les tests et soumettre ce lab.

  • IDE dans le navigateur avec terminal bash — rien à installer
  • Correction instantanée, XP et votre place dans le parcours
Créer un compteSe connecter
OU
Continuer avec GitHub