σμ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.2·~50 minAvancé

Déséquilibre du flux d'ordres

Position dans le parcoursModule 9 sur 11 · Sujet 2 sur 5
9.2 Déséquilibre du flux d'ordres
—Score du lab— / 100XP total—Série—

La pression avant que le prix bouge

Un prix bouge rarement tout seul ; il bouge parce que des ordres arrivent et retirent de la liquidité. Ne regarder que les transactions fait manquer l'essentiel, car l'essentiel de l'action est constitué d'ordres placés et annulés en haut du carnet. Le déséquilibre du flux d'ordres (OFI) résume chaque mise à jour du meilleur bid et du meilleur ask en un seul nombre signé : positif quand les acheteurs ajoutent ou que les vendeurs se retirent, négatif dans le cas inverse. Sur de courts horizons, il prédit remarquablement bien les prochains changements de prix.

def book_imbalance(bid_size, ask_size):
    total = bid_size + ask_size
    if total == 0:
        return 0.0
    return (bid_size - ask_size) / total

print(book_imbalance(450, 200))        # 0.3846  more size on the bid: upward pressure
print(book_imbalance(100, 400))        # -0.6    sellers dominate
print(book_imbalance(0, 0))            # 0.0     an empty top does not divide by zero

Une mise à jour, un nombre

Comparez deux cotations successives. Côté bid : si le prix du bid monte ou reste, sa nouvelle taille s'ajoute ; s'il baisse ou reste, son ancienne taille est retirée (à prix inchangé, les deux s'appliquent, donc c'est la variation de taille qui compte). Côté ask, les signes sont inversés : un ask plus bas ou égal ajoute de la pression vendeuse (- nouvelle taille ask), un ask plus haut ou égal retire l'ancienne (+ ancienne taille ask). Les quatre termes sont (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas, chaque comparaison valant 1 ou 0.

# The order-flow imbalance of one quote update, tried on four changes of the top of the book
def ofi_event(prev, cur):
    pb, pbs, pa, pas_ = prev
    b, bs, a, as_ = cur
    return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_

q0 = (99.5, 300, 100.0, 200)
print(ofi_event(q0, (99.5, 450, 100.0, 200)))     # 150   more size on the same bid
print(ofi_event(q0, (99.6, 100, 100.0, 200)))     # 100   a higher bid: the whole new size counts
print(ofi_event(q0, (99.4, 300, 100.0, 200)))     # -300  the bid price fell: the old size is gone
print(ofi_event(q0, (99.5, 300, 100.1, 200)))     # 200   the ask retreated: less selling pressure

Une série, et ce qu'elle explique

Appliquer la règle à chaque paire de cotations successives donne une série d'OFI. Sur une courte fenêtre, par exemple une seconde, additionnez les événements et comparez à la variation du prix milieu : la relation est presque linéaire, d_mid = slope * OFI. La pente dit de combien chaque unité de flux déplace le prix, et elle diminue quand le carnet est profond. On l'ajuste comme une droite des moindres carrés passant par l'origine : sum(ofi * dmid) / sum(ofi ** 2).

# A series of events from consecutive quotes, set beside the change of the mid price
import numpy as np

def ofi_event(prev, cur):
    pb, pbs, pa, pas_ = prev
    b, bs, a, as_ = cur
    return (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as_ + (a >= pa) * pas_

quotes = [(99.5, 300, 100.0, 200), (99.5, 450, 100.0, 200), (99.6, 100, 100.0, 150), (99.6, 100, 100.1, 400)]
events = np.array([ofi_event(prev, cur) for prev, cur in zip(quotes, quotes[1:])], dtype=float)
print(events)                                                       # [150. 150. 150.]

mid = np.array([(q[0] + q[2]) / 2 for q in quotes])
dmid = np.diff(mid)
print(np.round(dmid, 3))                                            # the mid moved in the direction of the flow
# Recover the price impact of the flow with a slope through the origin
import numpy as np

def impact_slope(ofi, dmid):
    return float(np.sum(ofi * dmid) / np.sum(ofi ** 2))

rng = np.random.default_rng(1)
flow = rng.normal(0, 200, size=500)                                  # order-flow imbalance per second
price_change = 0.00005 * flow + rng.normal(0, 0.004, size=500)       # the mid moves with the flow, plus noise
print(round(impact_slope(flow, price_change), 6))                    # 5e-05, the true impact per unit of flow
Prédictif, mais pas de l'argent gratuitL'OFI prédit des mouvements plus petits que l'écart, sur lesquels les acteurs rapides négocient déjà avant coûts. Sa valeur pour la plupart des gens est dans l'exécution : il dit s'il faut être patient avec un ordre d'achat parce que le carnet penche de votre côté, ou se dépêcher parce que le prix va filer. Il dépend aussi du marché : la pente diffère selon les actions et les heures de la journée.
  • Le déséquilibre du carnet (bid - ask) / (bid + ask) est entre -1 et +1 ; protégez le cas vide.
  • OFI d'une mise à jour : (b >= pb) * bs - (b <= pb) * pbs - (a <= pa) * as + (a >= pa) * pas ; une série l'applique à chaque paire consécutive.
  • Les variations du prix milieu sont presque linéaires en l'OFI : slope = sum(ofi * dmid) / sum(ofi**2) ; c'est un signal de court horizon, surtout utile pour l'exécution.

À suivre : le code asynchrone avec asyncio, gérer de nombreux flux de données sans attendre chacun.

Lab : ce qui est noté

  • Comparer les deux côtés avec book_imbalance25 pts
  • Noter une mise à jour avec ofi_event25 pts
  • Suivre la pression en continu avec ofi_series25 pts
  • Chiffrer le flux avec impact_slope25 pts
Explorateur · lab-113-1
▾ lab-113-1
…
bash · dans le navigateur
learner@quantcraft:~/lab-113-1$
Python pas encore chargéPythonLn 1, Col 1Spaces: 4UTF-8

Réinitialiser ce sujet ?

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