σμ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 11 · Systèmes de production et modèles de pointe›Sujet 11.1·~1 hExpert

Packager une bibliothèque Python

Position dans le parcoursModule 11 sur 11 · Sujet 1 sur 13
11.1 Packager une bibliothèque Python
—Score du lab— / 100XP total—Série—

D'un dossier de scripts à une bibliothèque installable

Du code qui vit dans un dossier de scripts fonctionne sur une machine, pour une personne, jusqu'au jour où quelqu'un d'autre en a besoin ou où vous en avez besoin dans un autre environnement. L'empaquetage transforme votre code en bibliothèque avec un nom, une version et des dépendances déclarées que chacun peut installer avec pip install. C'est ainsi qu'une équipe partage une bibliothèque de valorisation sans copier des fichiers, qu'un notebook de recherche et une tâche de production exécutent exactement le même code, et qu'un correctif atteint tout le monde par un nouveau numéro de version.

# Versions are numbers, not text: compare them as tuples
def parse_version(text):
    parts = [int(part) for part in text.split(".")]
    return tuple(parts + [0] * (3 - len(parts)))

print("1.10" > "1.9")                                # False  as text, "1" < "9" decides it: wrong
print(parse_version("1.10") > parse_version("1.9"))  # True   as numbers (1, 10, 0) is newer than (1, 9, 0)
print(parse_version("2"))                            # (2, 0, 0)

Arborescence, pyproject.toml et construction

Une disposition courante met le code dans src/yourlib/ (avec un __init__.py), les tests dans tests/ et un pyproject.toml à la racine. Ce fichier unique nomme l'outil de construction (la table [build-system]) et décrit le projet : son name, sa version, une description, les versions de Python prises en charge et ses dependencies. pip install -e . installe le dossier en mode éditable pendant le développement, donc les modifications prennent effet aussitôt ; python -m build produit une wheel (.whl, prête à installer) et une sdist (archive source) dans dist/. Mettez la version à un seul endroit et exposez-la comme yourlib.__version__ si les utilisateurs en ont besoin.

# A minimal pyproject.toml, generated and then read back with tomllib to prove it is valid
import tomllib

def pyproject_toml(name, version, dependencies):
    lines = ["[build-system]", 'requires = ["setuptools>=68"]', 'build-backend = "setuptools.build_meta"', "",
             "[project]", f'name = "{name}"', f'version = "{version}"']
    if dependencies:
        lines += ["dependencies = ["] + [f'    "{d}",' for d in dependencies] + ["]"]
    else:
        lines.append("dependencies = []")
    return "\n".join(lines) + "\n"

text = pyproject_toml("qcpricing", "0.3.0", ["numpy>=1.26", "pandas>=2"])
data = tomllib.loads(text)
print(data["project"]["name"], data["project"]["version"])      # qcpricing 0.3.0
print(data["project"]["dependencies"])                          # ['numpy>=1.26', 'pandas>=2']

Versions et spécificateurs de version

La plupart des bibliothèques suivent le versionnage sémantique : MAJEUR.MINEUR.CORRECTIF. Une correction de bug incrémente le correctif (1.4.2 en 1.4.3), une fonctionnalité rétrocompatible incrémente le mineur et remet le correctif à zéro (1.5.0), et un changement cassant incrémente le majeur (2.0.0). Les dépendances se déclarent avec des spécificateurs : numpy>=1.26,<3 accepte tout NumPy de la 1.26 jusqu'à la 3 exclue. Soyez aussi souple que vous pouvez l'être honnêtement : une borne basse pour la plus ancienne version testée, une borne haute seulement pour une version majeure dont vous savez qu'elle vous casse. Figer des versions exactes (==) relève du fichier de verrouillage d'une application, pas d'une bibliothèque que d'autres installent.

# Bumping a version and checking a requirement, with versions compared as tuples
import operator

def parse_version(text):
    parts = [int(part) for part in text.split(".")]
    return tuple(parts + [0] * (3 - len(parts)))

def bump_version(version, part):
    major, minor, patch = parse_version(version)
    return {"major": f"{major + 1}.0.0", "minor": f"{major}.{minor + 1}.0", "patch": f"{major}.{minor}.{patch + 1}"}[part]

OPS = {">=": operator.ge, "<": operator.lt, "==": operator.eq}

def satisfies(version, specifier):
    for clause in specifier.split(","):
        symbol = next(op for op in (">=", "==", "<") if clause.startswith(op))
        if not OPS[symbol](parse_version(version), parse_version(clause[len(symbol):])):
            return False
    return True

print(bump_version("1.4.2", "minor"))                # 1.5.0
print(satisfies("1.26.4", ">=1.26,<3"), satisfies("3.0.0", ">=1.26,<3"))      # True False
# One place for the version: read it from the source instead of repeating it in several files
import re

init_py = """__version__ = "0.3.0"
from .pricing import price
"""
match = re.search(r'^__version__ = "([^"]+)"', init_py, re.MULTILINE)
version = match.group(1)
print(version)                                       # 0.3.0
print(tuple(int(part) for part in version.split(".")))      # (0, 3, 0)
Publier avec soinUne version publiée est une promesse : quelqu'un dépendra demain de cette version exacte, donc une version publiée ne doit jamais changer. Corrigez les erreurs en publiant une nouvelle version, et tenez un journal des modifications. Lancez les tests avec les plus anciennes et les plus récentes versions de Python et des dépendances que vous prétendez prendre en charge. Utilisez un index privé pour le code de stratégie propriétaire, et ne mettez jamais clés, mots de passe ni fichiers de données dans le paquet.
  • L'empaquetage donne au code un nom, une version et des dépendances déclarées, installable avec pip install ; développez avec pip install -e ., construisez avec python -m build.
  • pyproject.toml contient le système de construction et les métadonnées [project] ; comparez les versions comme des tuples de nombres, jamais comme du texte.
  • Utilisez le versionnage sémantique (MAJEUR.MINEUR.CORRECTIF) et des spécificateurs souples (numpy>=1.26,<3) ; ne changez jamais une version publiée et gardez les secrets hors du paquet.

À suivre : CI/CD pour le code quantitatif, exécuter automatiquement les contrôles à chaque modification.

Lab : ce qui est noté

  • Comparer les versions comme des nombres avec parse_version25 pts
  • Publier la version suivante avec bump_version25 pts
  • Vérifier une exigence avec satisfies25 pts
  • Décrire le paquet avec pyproject_toml25 pts
Explorateur · lab-130-1
▾ lab-130-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-130-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

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