σμ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 9 · Données de marché et microstructure›Sujet 9.5·~1 hAvancé

Le protocole FIX

Position dans le parcoursModule 9 sur 11 · Sujet 5 sur 5
9.5 Le protocole FIX
—Score du lab— / 100XP total—Série—

La langue que parlent courtiers et bourses

Quand un système de trading envoie un ordre à un courtier ou à une bourse, il le fait très souvent en FIX, le protocole Financial Information eXchange, utilisé depuis le début des années 1990. Un message FIX est du texte brut : une liste de champs tag=valeur, chacun terminé par un caractère séparateur invisible, chr(1) (SOH). Chaque tag est un nombre au sens convenu : 35 est le type de message, 55 le symbole, 54 le sens, 38 la quantité, 44 le prix. Le format est ancien et peu glamour, et toute l'industrie le comprend.

# A FIX message is tag=value fields each ended by a separator (shown here as |)
message = "8=FIX.4.2|9=60|35=D|11=ord-1|55=AAPL|54=1|38=100|40=2|44=184.50|10=123|"

fields = {}
for part in message.split("|"):
    if part:                                       # the last separator leaves an empty piece
        tag, value = part.split("=", 1)            # split at the FIRST = only
        fields[int(tag)] = value

print(fields[35], fields[55], fields[38], fields[44])    # D AAPL 100 184.50
print(sorted(fields))                                    # [8, 9, 10, 11, 35, 38, 40, 44, 54, 55]

La forme d'un message

Un message a trois parties. L'en-tête commence par 8=FIX.4.2 (la version), puis 9= la longueur du corps, puis le type de message 35=. Le corps porte le contenu : pour un New Order Single (35=D), l'identifiant d'ordre client, le symbole, le sens (1 achat, 2 vente), la quantité, le type d'ordre (40=2 limite) et le prix. Le pied est 10=, une somme de contrôle : additionnez les codes des caractères de tout ce qui précède et gardez le reste de la division par 256, écrit sur trois chiffres. Le destinataire la recalcule pour détecter la corruption, et vérifie aussi la longueur du corps. Les sessions ajoutent le reste : connexion (35=A), heartbeats (35=0) et numéros de séquence comme ceux suivis dans le dernier sujet.

# The checksum: add up the character codes, keep the remainder modulo 256, three digits
def checksum(text):
    return f"{sum(ord(c) for c in text) % 256:03d}"

print(checksum("A"))                      # 065  the code of "A" is 65
print(checksum("aaa"))                    # 035  3 * 97 = 291 and 291 - 256 = 35
print(checksum("8=FIX.4.2|35=0|"))        # a heartbeat header
# Writing fields: tag=value and a separator after each one
def build_fix(fields, sep="|"):
    return "".join(f"{tag}={value}{sep}" for tag, value in fields)

body = build_fix([(35, "D"), (11, "ord-1"), (55, "AAPL"), (54, 1), (38, 100)])
print(body)                               # 35=D|11=ord-1|55=AAPL|54=1|38=100|
print(len(body))                          # 34  tag 9 holds this length
# A complete order: header with the body length, the body, then the checksum trailer
def checksum(text):
    return f"{sum(ord(c) for c in text) % 256:03d}"

def build_fix(fields, sep="|"):
    return "".join(f"{tag}={value}{sep}" for tag, value in fields)

def new_order_message(cl_ord_id, symbol, side, quantity, price, sep="|"):
    code = "1" if side == "buy" else "2"
    body = build_fix([(35, "D"), (11, cl_ord_id), (55, symbol), (54, code), (38, quantity), (40, 2), (44, f"{price:.2f}")], sep)
    head = build_fix([(8, "FIX.4.2"), (9, len(body))], sep) + body
    return head + build_fix([(10, checksum(head))], sep)

message = new_order_message("ord-1", "AAPL", "buy", 100, 184.5)
print(message)                            # 8=FIX.4.2|9=...|35=D|11=ord-1|...|44=184.50|10=...|
print(message.split("|")[-2])             # the checksum field
Ne codez pas à la main un moteur de productionAnalyser et construire des messages est un bon moyen de comprendre FIX, mais une vraie connexion exige une logique de session : connexion, heartbeats, réinitialisations de séquence, demandes de renvoi et dialectes propres à chaque place. En production, utilisez un moteur éprouvé comme QuickFIX et limitez votre code à la logique d'ordres. Un ordre mal formé ou dupliqué peut coûter de l'argent réel : journalisez chaque message envoyé et reçu.
  • Un message FIX est un ensemble de champs tag=valeur chacun terminé par un séparateur (chr(1) sur le fil) ; coupez chaque champ au premier =.
  • En-tête 8 (version) et 9 (longueur du corps), corps à partir de 35 (type), pied 10 (somme de contrôle).
  • La somme de contrôle est la somme des codes des caractères modulo 256, sur trois chiffres ; utilisez un moteur éprouvé en production et journalisez chaque message.

À suivre : le code propre, les noms, les petites fonctions et les habitudes qui gardent lisible une base de code de trading.

Lab : ce qui est noté

  • Lire un message avec parse_fix25 pts
  • Sceller un message avec checksum25 pts
  • Écrire des champs avec build_fix25 pts
  • Envoyer un ordre avec new_order_message25 pts
Explorateur · lab-116-1
▾ lab-116-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-116-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

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