σμ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 10 · Ingénierie Python haute performance›Sujet 10.1·~45 minAvancé

Code propre

Position dans le parcoursModule 10 sur 11 · Sujet 1 sur 13
10.1 Code propre
—Score du lab— / 100XP total—Série—

Le code est lu bien plus souvent qu'il n'est écrit

Une base de code de trading vit des années et est modifiée par des gens qui ne l'ont pas écrite, souvent sous pression et souvent par vous-même, six mois plus tard. Le code propre est un code qu'on comprend vite et qu'on peut modifier sans danger. Il ne s'agit pas de règles de style, mais de rendre visible une mauvaise modification. Une fonction mal nommée, qui fait trois choses et cache une limite dans une formule, est l'endroit où se logent les bugs coûteux, comme une limite de risque que personne ne se rappelait codée en dur.

# The same calculation, written two ways
def f(d, e, m, w):
    r = []
    if sum([abs(x) for x in d.values()]) / e > m:
        r.append("LEVERAGE")
    for k in sorted(d):
        if abs(d[k]) / sum([abs(x) for x in d.values()]) > w:
            r.append("CONCENTRATION:" + k)
    return r

book = {"AAPL": 80_000.0, "MSFT": -10_000.0, "NVDA": 10_000.0}
print(f(book, 50_000.0, 1.5, 0.5))                  # works, but what is d? e? m? w?

Des noms, de petites fonctions, pas de nombres cachés

Trois habitudes font l'essentiel. Nommez les choses pour ce qu'elles sont : gross_exposure plutôt que f, max_leverage plutôt que m. Gardez des fonctions petites et à but unique : chacune fait une tâche qu'on peut nommer en quelques mots, donc se teste seule et se réutilise, et une fonction plus grande se construit en les appelant. N'enterrez pas les nombres : une limite comme 1.5 tapée dans une formule est un nombre magique que personne ne peut trouver ou changer sans risque ; passez-la en argument (ou nommez-la comme constante). Calculer l'exposition brute une fois dans sa propre fonction supprime aussi l'expression répétée.

# Small functions with names that say what they return; the limits come in as arguments
def gross_exposure(positions):
    return sum(abs(value) for value in positions.values())

def leverage(positions, equity):
    return gross_exposure(positions) / equity

def risk_flags(positions, equity, max_leverage, max_weight):
    flags = []
    if leverage(positions, equity) > max_leverage:
        flags.append("LEVERAGE")
    gross = gross_exposure(positions)
    for symbol in sorted(positions):
        if abs(positions[symbol]) / gross > max_weight:
            flags.append(f"CONCENTRATION:{symbol}")
    return flags

book = {"AAPL": 80_000.0, "MSFT": -10_000.0, "NVDA": 10_000.0}
print(risk_flags(book, 50_000.0, 1.5, 0.5))         # ['LEVERAGE', 'CONCENTRATION:AAPL']
print(risk_flags(book, 50_000.0, 3.0, 0.9))         # []  the same code, looser limits

Protéger les bords et dire pourquoi

Traitez d'abord l'entrée invalide et retournez ou levez tout de suite (une clause de garde), pour que le chemin principal se lise droit, sans imbrication. Un levier gross / equity avec un capital nul doit être une ValueError claire, pas une ZeroDivisionError venue du fond, et un portefeuille vide doit donner 0.0 plutôt qu'un plantage. Les commentaires doivent expliquer le pourquoi, que le code ne peut pas dire (# la bourse arrondit au centime), pas répéter le quoi que le code montre déjà. Les docstrings disent ce qu'une fonction prend et rend. Enfin, préférez les fonctions pures, qui ne dépendent que de leurs arguments et n'ont pas d'effet de bord : ce sont celles qu'on teste avec quelques entrées.

# A guard clause stops bad input at the door and says exactly what is wrong
def leverage(positions, equity):
    if equity <= 0:
        raise ValueError("equity must be positive")
    return sum(abs(value) for value in positions.values()) / equity

print(leverage({"AAPL": 60_000.0, "MSFT": -30_000.0}, 45_000.0))     # 2.0
print(leverage({}, 45_000.0))                                         # 0.0  an empty book is fine

try:
    leverage({"AAPL": 60_000.0}, 0.0)
except ValueError as error:
    print("rejected:", error)                                         # rejected: equity must be positive
# A pure function answers the same way every time; hidden state does not
history = []

def running_notional(price, quantity):          # remembers earlier calls: the answer depends on the past
    history.append(price * quantity)
    return sum(history)

def notional(price, quantity):                  # depends only on its arguments
    return price * quantity

print(running_notional(10.0, 5), running_notional(10.0, 5))     # 50.0 100.0  same call, different answers
print(notional(10.0, 5), notional(10.0, 5))                     # 50.0 50.0   always the same
Propre ne veut pas dire astucieuxNe compressez pas le code pour faire malin : une boucle de trois lignes que tout le monde comprend vaut mieux qu'une astuce d'une ligne qui exige un commentaire. Ne découpez pas non plus en dizaines de minuscules fonctions ; arrêtez-vous quand une fonction se lit comme une étape claire. Et le nettoyage est un changement distinct d'un changement de comportement : refactorez avec des tests qui passent avant et après, pour que toute différence vienne de la nouvelle logique et non du rangement.
  • Nommez les choses pour ce qu'elles sont, gardez des fonctions petites et à but unique, et construisez les plus grandes en les appelant.
  • Pas de nombres magiques : les limites arrivent en arguments ou en constantes nommées ; calculez une valeur répétée une seule fois.
  • Protégez d'abord contre l'entrée invalide avec une erreur claire, commentez le pourquoi et non le quoi, et préférez les fonctions pures testables.

À suivre : les annotations de type et la vérification statique, laisser des outils attraper les erreurs avant l'exécution.

Lab : ce qui est noté

  • Netter le portefeuille avec net_exposure25 pts
  • Additionner chaque position avec gross_exposure25 pts
  • Protéger le dénominateur dans leverage25 pts
  • Composer les contrôles dans risk_flags25 pts
Explorateur · lab-117-1
▾ lab-117-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-117-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

Tout le contenu de lab-117-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