← Retour aux articles
August 13, 2026
5 min de lecture

Updating the Volume Curve Intraday: Does Adaptive Forecasting Actually Help?

Updating the Volume Curve Intraday: Does Adaptive Forecasting Actually Help?
#microstructure
#liquidity
#execution
#prediction
#order-book

Dans TWAP, VWAP et POV, nous avons exécuté les trois planificateurs face à face pendant 90 jours de rediffusion BTCUSDT L2 et sommes parvenus à une conclusion qui a été délibérément laissée comme une plaie ouverte : en crypto, la courbe de volume est le maillon le plus faible du pipeline, pas le découpage. Cet article a volontairement livré la version simple – une courbe de volume basée sur la médiane, courbe jour de la semaine × heure, réajustée chaque semaine, maintenue statique tout au long de la journée de négociation. Et il a constaté que tout l'avantage de VWAP sur TWAP réside dans la qualité des prévisions : sous réserve de l'erreur réalisée sur la courbe de volume, VWAP bat TWAP d'environ 4 points de base sur le tercile de jours le mieux prévu, et l'écart s'effondre en bruit sur le pire tercile.

Ce résultat implique un suivi spécifique et falsifiable. Si le VWAP ne gagne que les jours où la courbe s'avère correcte, alors un prévisionniste qui se corrige au fur et à mesure que la journée se déroule devrait convertir certains des mauvais-terciles jours en bons. Ou cela ne devrait pas – et la version intéressante de cet article est celle où ce n’est pas le cas, car le mauvais tercile en crypto est les jours en cascade et les jours d’actualité, et ce sont exactement les jours où les deux premières heures de volume observé sont les moins informatives sur les deux suivantes.

Cet article implémente le programme de mise à jour intrajournalier, l'exécute sur le même harnais et rapporte le delta IS par rapport à la courbe statique – avec la distribution et le nombre du quartile final, pas seulement la moyenne.

Qu'est-ce qui est testé

Courbe de volume adaptative avant mise à jour à partir de l'activité de trading observée

La courbe statique est un a priori : un vecteur fixe u={u1,,uB}u = \{u_1, \ldots, u_B\} des fractions volumiques attendues par seau, estimées hors ligne. La version adaptative le traite comme un avant d'être mis à jour. Après cc les buckets se sont écoulés et vous avez observé les volumes réels V1,,VcV_1, \ldots, V_c, vous disposez de deux nouvelles informations que la courbe statique jette :

  1. Une estimation de niveau. Si le précédent indique des seaux 1..c1..c aurait dû porter une fraction icui\sum_{i \le c} u_i du jour et ils ont porté icVi\sum_{i\le c} V_i unités, le total implicite d’une journée entière est V^=icVi/icui\hat{V} = \sum_{i \le c} V_i \big/ \sum_{i \le c} u_i. Il s'agit d'un signal « Aujourd'hui est un jour lourd / Aujourd'hui est un jour mort », et il est disponible à partir du premier compartiment.
  2. Une correction de forme. Si la forme réalisée des tranches écoulées s'écarte systématiquement de la forme antérieure, les tranches restantes peuvent également s'écarter - mais seulement si les erreurs intrajournalières de courbe de volume sont autocorrélées au cours de la journée, ce qui est en soi une question empirique et non une hypothèse que nous pouvons faire gratuitement.

L'implémentation ci-dessous utilise (1) entièrement et (2) pas du tout : elle renormalise la queue antérieure intacte sur le total mis à jour. C'est la version conservatrice, et c'est la bonne première expérience, car si la mise à jour du niveau pur capture déjà la majeure partie du delta disponible, alors la machinerie de forme est d'une complexité injustifiée.

import numpy as np
from typing import Optional


class AdaptiveVolumePredictor:
    """
    Bayesian-style adaptive volume profile predictor.

    Combines a prior (the offline day-of-week x time-of-day curve)
    with volume observed so far today to produce an updated forecast
    for the remaining buckets.
    """

    def __init__(self, historical_profiles: np.ndarray):
        """
        Args:
            historical_profiles: shape (n_days, n_buckets), each row sums to 1.0.
                Use the median-based, day-of-week-conditioned curve from the
                TWAP/VWAP/POV article -- a pooled mean curve is misspecified
                and will make the adaptive version look better than it is by
                giving it a weaker baseline to beat.
        """
        self.prior_profile = np.median(historical_profiles, axis=0)
        self.prior_profile /= self.prior_profile.sum()
        self.prior_iqr = np.subtract(*np.percentile(historical_profiles, [75, 25], axis=0))
        self.n_buckets = len(self.prior_profile)

    def predict(
        self,
        observed_volumes: np.ndarray,
        current_bucket: int,
        total_volume_estimate: Optional[float] = None,
    ) -> np.ndarray:
        """
        Predict absolute volume for every bucket: realized values for elapsed
        buckets, forecasts for the remainder.

        Args:
            observed_volumes: actual volumes in buckets 0..current_bucket-1
            current_bucket: index of the current bucket (0-based)
            total_volume_estimate: external ADV estimate (optional prior on level)
        """
        profile = np.zeros(self.n_buckets)

        if current_bucket == 0:
            base = total_volume_estimate if total_volume_estimate else 1.0
            return self.prior_profile * base

        profile[:current_bucket] = observed_volumes[:current_bucket]
        observed_total = observed_volumes[:current_bucket].sum()

        expected_fraction_so_far = self.prior_profile[:current_bucket].sum()
        if expected_fraction_so_far > 0.01:
            implied_total = observed_total / expected_fraction_so_far
        else:
            implied_total = observed_total * self.n_buckets

        if total_volume_estimate:
            w_obs = expected_fraction_so_far
            implied_total = w_obs * implied_total + (1 - w_obs) * total_volume_estimate

        remaining_prior = self.prior_profile[current_bucket:]
        remaining_sum = remaining_prior.sum()
        if remaining_sum > 0:
            remaining_volume = max(0.0, implied_total - observed_total)
            profile[current_bucket:] = remaining_prior / remaining_sum * remaining_volume

        return profile

Deux détails dans ce code portent l'expérience. L'a priori est la courbe médiane conditionnée par le jour de la semaine, et non une moyenne groupée. Pour savoir pourquoi cela est important sur un marché où une cascade de liquidation peut représenter 15 % du volume d'une journée en dix minutes, voir la section courbe de volume de l'article VWAP. Et la mise à jour du niveau est rétrécie vers une estimation ADV externe avec un poids égal à la fraction précédente écoulée, car dans le premier compartiment implied_total est une observation divisée par un nombre proche de zéro. Un programme de mise à jour non réduit fait son pire travail exactement quand il lui reste le plus de jours à gâcher.

Harnais

Chemins d'exécution parallèles dans un harnais de recherche de prévision adaptative

Identique à l'exécution de TWAP/VWAP/POV, donc les nombres sont comparables ligne par ligne :

  • Instrument/données : BTCUSDT perpétuel, 90 jours de relecture L2 (20 premiers niveaux, 100 ms) plus la bande des échanges. UTC partout ; les horodatages de financement ont été signalés.
  • Commandes parents : 500, horizon T=4T = 4h, taille 0,75 % de l'ADV des 30 derniers jours, côté acheteur, prix de décision = milieu au début. Mêmes heures de début aléatoires que l’exécution publiée.
  • Arms : (A) VWAP sur la courbe statique de radoub hebdomadaire — la référence publiée ; (B) VWAP sur le même avant avec mise à jour intrajournalière ; (C) TWAP comme sol.
  • Mesures : IS en points de base du prix de décision, frais inclus, par rapport à l'arrivée – indiqués sous forme de moyenne, médiane, écart type, 95e centile et IS du quartile final de chaque parent. Le glissement VWAP est enregistré uniquement à titre de diagnostic, jamais comme tableau de bord ; la section de référence de l'article VWAP montre un cas concret où le glissement et l'arrivée VWAP IS classent deux algorithmes dans des ordres opposés. La décomposition complète du SI, y compris le terme opportunité-coût, suit manque de mise en œuvre et TCA.

Résultats

Est-ce que cela aide là où c'est nécessaire ?

La moyenne globale est le chiffre le moins intéressant ici. Le résultat publié a établi que l'écart VWAP-TWAP est monotone en termes d'erreur de courbe de volume réalisée, de sorte que le bras adaptatif doit être noté de la même manière : regrouper les 90 jours en terciles par L1L_1 distance entre les prévisions statiques et les volumes de compartiment réalisés, puis signalez le delta IS adaptatif moins statique dans chaque tercile.

Les deux résultats sont tous deux publiables et signifient des choses opposées :

  • Delta concentré dans le bon tercile. L'updater affine des jours qui étaient déjà faciles. L’effet net sur la répartition des coûts est cosmétique ; la queue – qui est ce que paie réellement un parent axé sur l’alpha à horizon dur – est inchangée. Cela voudrait dire que le programme de mise à jour intrajournalier n’est pas la solution au maillon le plus faible, et que les routes de correction de forme et d’actifs croisés sont les prochaines étapes à suivre.
  • Delta concentré dans le mauvais tercile. Le programme de mise à jour fait le travail pour lequel il a été conçu : détecter la cascade et les jours d'actualité où la courbe statique est la plus fausse. C’est le résultat qui justifierait l’ajout d’un état dans la boucle d’exécution.

Un résultat négatif est attendu et mérite d’être signalé clairement. Le mécanisme qui rend les courbes de volume cryptographiques difficiles – une cascade est une rupture de régime, pas un changement de niveau – est précisément le mécanisme qui défait un prévisionniste de mise à jour de niveau : au moment où les seaux écoulés vous disent qu'aujourd'hui est lourd, la partie la plus lourde peut être passée. Voir le négatif honnête pour savoir pourquoi ce blog les publie.

Pente du livre : est-ce que ça ajoute quelque chose ?

Paysage abstrait de la profondeur du carnet d'ordres limite et pente de liquidité

Une fonctionnalité du projet d'ensemble de fonctionnalités n'est couverte nulle part ailleurs sur ce blog : la pente du livre, la vitesse à laquelle la profondeur cumulée s'accumule à mesure que vous vous éloignez du toucher. Ajuster CumVol(d)=α+βd\text{CumVol}(d) = \alpha + \beta d par-dessus KK niveaux ; grand β\beta signifie que la profondeur est concentrée au toucher, petite β\beta signifie qu'il est réparti sur tout le livre.

def book_slope(prices: np.ndarray, volumes: np.ndarray, mid: float) -> float:
    """Slope of cumulative depth vs. distance from mid. One side only."""
    distances = np.abs(prices - mid)
    return float(np.polyfit(distances, np.cumsum(volumes), 1)[0])

La seule version qui vaille la peine d’être formulée est une version mesurée : l’ajout de book_slope à l'ensemble de fonctionnalités existant, déplacer la prévision de volume, ou le SI résultant, au-delà d'une référence AR/EWMA ? L'article sur la modélisation de propagation établit la norme — rapporter la compétence au-dessus d'une ligne de base triviale avec l'horizon indiqué, car ces séries sont dominées par la persistance et un titre R² mesure principalement l'autocorrélation.

Ce que cet article ne redirige délibérément pas

Module de recherche ciblé au sein d'un pipeline quantitatif limité

Tout ce qui suit est déjà plus approfondi sur le blog, et le réexpliquer ici ne ferait que créer une deuxième version plus faible :

  • Mesure de la liquidité. L'estimateur de Roll (avec le correctif de racine signée et le piège prix-unités-vs-rendements) et le lambda de Kyle : modélisation de propagation avec apprentissage automatique. Le lambda de Kyle est également calibré sur de vrais aggTrades de Binance en tant que coefficient d'impact permanent dans Almgren-Chriss. Coût de balayage Walk-the-book : modèles de glissement et de coûts.
  • Caractéristiques du carnet de commandes. Le milieu pondéré (qui n'est pas le microprix de Stoikov - celui-ci est ajusté en fonction de la martingale), le déséquilibre du livre à plusieurs niveaux, OFI et la taxonomie complète des fonctionnalités LOB : DeepLOB et spread modeling.
  • Modèles intrajournaliers. La forme en U des actions n'est pas le bon modèle pour un marché sans clôture ; la structure de session crypto/financement/hebdomadaire qui la remplace, ainsi que la grille jour de la semaine × heure de la journée, se trouve dans l'article VWAP. Le codage de l'heure cyclique se trouve dans la table des fonctionnalités de spread article.
  • Événements programmés. Expirations du Deribit à 08h00 UTC, macro américaine à 12h30/14h00 UTC, règlements CME — traitez-les comme des mannequins plutôt que de les laisser polluer la courbe de référence ; le calendrier crypto concret se trouve dans l'article VWAP. Le programme de mise à jour adaptatif ci-dessus n'est pas un gestionnaire d'événements et il ne faut pas lui demander d'en être un.
  • Modèles. Augmentation du dégradé avec CV purgé et sous embargo (un simple TimeSeriesSplit fuites à travers la cible de fenêtre avant qui se chevauche) est dans modélisation de propagation ; la famille CNN-LSTM, le tenseur d'entrée à 40 fonctionnalités/10 niveaux, LOBFrame et la discussion sur la crise de réplication se trouvent dans DeepLOB. Notez en particulier que l'axe des niveaux ne doit pas être réduit avant le calque récurrent.
  • La décision relative à l'ordre des enfants. Passif versus agressif est un seuil de rentabilité calculé p=δ/(Π+δ)p^* = \delta/(\Pi + \delta), pas un seuil de propagation codé en dur : tactiques d'exécution des ordres enfants. Le ciblage du taux de participation est endogène – vos propres remplissages sont imprimés sur la bande – et la correction se trouve dans l'article VWAP.
  • Fragmentation des sites. Routage intelligent des commandes en crypto, avec la carte de pointage TCA par site dans manque de mise en œuvre.
  • Latence de production. Section de production de DeepLOB ; notez que l'article diffusé qualifie déjà les affirmations sur le temps d'inférence - un LightGBM de 2000 tours prédit en dizaines de microsecondes à partir de Python, à un chiffre uniquement avec un prédicteur compilé.

Les dynamiques contradictoires méritent un paragraphe plutôt qu'une section. La profondeur affichée est en partie performative, et les mécanismes de détection – taux d'annulation, vitesse de construction du mur, comportement à l'approche du prix, superposition – sont couverts par une méthode concrète basée sur le PIQ dans [position de la file d'attente et analyse du mur] (/en/blog/post/queue-position-order-book-wall-analysis). Le seul delta que cet article pourrait ajouter est de les traiter comme des entrées de prévisionnistes : le rapport d'annulation/échange, le temps de repos moyen au toucher et la fraction de profondeur qui s'annule dans les 100 ms suivant l'apparition, transmise au modèle de volume aux côtés du signal de compartiment écoulé. Qu'ils ajoutent des compétences à l'ensemble des fonctionnalités existantes est une mesure ouverte et non une affirmation.

Conclusion

Chemin de preuve passant de l'incertitude à un résultat d'exécution mesuré

L'affirmation testée est étroite et le blog a déjà mis en place les conditions pour la falsifier : l'article VWAP a établi que l'avantage de VWAP réside entièrement dans la qualité des prévisions et que les prévisions échouent les jours qui coûtent le plus cher. Un programme de mise à jour intrajournalier corrige ce problème ou non, et la réponse est un nombre dans le mauvais tercile d'une rediffusion de 500 parents.

Ce que cet article ne fera pas, c'est attacher un chiffre en bps à un système de production sans rediffusion derrière celui-ci. Les affirmations du type « une prévision de liquidité bien réglée permet d'économiser 2 à 5 points de base, la différence entre un Sharpe de 1,5 et 2,0 » sont exactement le genre que Sharpe dégonflé et tests multiples existe pour démanteler : sans source, sans condition et jamais accompagné de dispersion. Le nombre qui compte ici est le quartile final IS du pire tercile des jours, et il est soit mesuré, soit il n'est pas rapporté.

blog.disclaimer

Authors

Eugen Soloviov
Eugen Soloviov

Trading-systems engineer

Trading-systems engineer building bots since 2017: cross-exchange arbitrage (connected up to 30 venues), cointegration-based pairs arbitrage across spot and futures, scalping, news and sentiment-driven strategies, trend algorithms, and portfolio management and balancing algorithms. Also builds sub-millisecond order execution, big-data warehouses, backtesting engines, AI agents, and trading interfaces (incl. open-source profitmaker.cc). Stack: JS/TS, Python, Rust/Zig/Go, DevOps, backend, frontend, architecture.

Newsletter

Gardez une longueur d'avance sur le marché

Abonnez-vous à notre newsletter pour des insights exclusifs sur le trading IA, des analyses de marché et des mises à jour de la plateforme.

Nous respectons votre vie privée. Désabonnement possible à tout moment.