Индикатор Trade Size Distribution: формула, настройки и чтение
Trade Size Distribution измеряет, насколько объём бара сосредоточен на его самых тяжёлых уровнях цены. Индикатор выводит долю объёма бара в процентах, проторгованную на уровнях выше процентильного порога, рассчитанного по тому же бару, по умолчанию по 80-му процентилю.
Senzoukria · Индикаторы · Updated September 2026
Trade Size Distribution — Лента и поток, в отдельной панели под графиком.
Что измеряет Trade Size Distribution
Для каждого бара объёмы его уровней цены сортируются, и порог берётся по ближайшему рангу, без интерполяции, так что порог — всегда реально наблюдавшийся объём уровня, а не число, вычисленное между двумя уровнями. Затем индикатор суммирует объём всех уровней строго выше порога, делит на общий объём уровней бара и выводит результат в процентах. Уровни с одинаковой ценой предварительно объединяются, а уровни без количества исключаются, поэтому источник, публикующий необъединённый список уровней, не может завысить их число. Бар футпринта агрегирован, и порядок исполнений утрачен, поэтому измеряется концентрация потока по ценам, а не гистограмма размеров отдельных сделок.
Формула — так, как она реализована
Это не привычное определение из других источников, а то, что вычисляет поставляемый код, задокументированное рядом с реализацией:
Points d'histogramme : `f` rend `null` quand la barre n'a pas d'information — la barre n'émet alors PAS de point (contrat `HistogramPoint` : pas de trou, pas de valeur inventée). */ function histPoints( bars: readonly FootprintBar[], f: (bar: FootprintBar, i: number) => number | null, ): HistogramPoint[] { const out: HistogramPoint[] = []; for (let i = 0; i < bars.length; i++) { const v = f(bars[i], i); if (v !== null) out.push({ time: bars[i].bucketTsNs, value: v }); } return out; } function histOut( points: HistogramPoint[], positiveColor: string, negativeColor: string, ): SeriesOutput { return { shape: "histogram", points, positiveColor, negativeColor }; } /** Un niveau de la barre indexé par sa CLÉ ENTIÈRE (indice de tick quand le tick est connu, quantification 1e-6 sinon — canon : jamais de clé f64). */ type KeyedLevel = { key: number; price: number; buy: number; sell: number }; /** Niveaux EXPLOITABLES de la barre (canon : qty = 0 et prix non fini exclus), agrégés par clé de prix, rendus en ordre ASCENDANT. L'agrégation est indispensable : deux entrées `levels` au même prix (source qui n'a pas fusionné, ou deux prix qui tombent sur le même tick) ne doivent compter QUE POUR UN niveau — sinon le compte de niveaux, les percentiles et la largeur traversée mentent tous les trois. / function barLevelsByKey( bar: FootprintBar, tickSize: number | null, ): KeyedLevel[] { const byKey = new Map<number, KeyedLevel>(); for (const lvl of usableLevels(bar)) { const key = priceKey(lvl.price, tickSize); const cur = byKey.get(key); if (cur !== undefined) { cur.buy += lvl.buyVolume; cur.sell += lvl.sellVolume; } else { byKey.set(key, { key, price: lvl.price, buy: lvl.buyVolume, sell: lvl.sellVolume, }); } } return [...byKey.values()].sort((a, b) => a.key - b.key); } /** CVD de séance par barre + indice de la PREMIÈRE barre de sa séance. CVD = Σ `totalDelta` depuis l'ouverture CME 17:00 CT, RESET à chaque ouverture (`splitSessions`) — canon, jamais le début du chart. Le second tableau permet aux fenêtres glissantes de refuser de comparer deux barres séparées par un reset : la différence de CVD n'aurait alors aucun sens. / function sessionCvd(bars: readonly FootprintBar[], ctx: SeriesContext): { cvd: number[]; sessionStart: number[]; } { const cvd = new Array<number>(bars.length).fill(0); const sessionStart = new Array<number>(bars.length).fill(0); for (const s of splitSessions(bars, ctx)) { let running = 0; for (let i = s.start; i <= s.end; i++) { running += bars[i].totalDelta; cvd[i] = running; sessionStart[i] = s.start; } } return { cvd, sessionStart }; } /** VWAP de séance par barre : Σ(tp·vol)/Σvol cumulé depuis l'ouverture CME 17:00 CT, reset à CHAQUE ouverture. Prix d'échantillon = prix TYPIQUE (H+L+C)/3, poids = volume de la barre — exactement le mode `typical` de `vwap.ts` (parité ATAS/Sierra/TradingView) : un second VWAP maison qui divergerait du VWAP dessiné serait pire qu'inutile. Barres à volume nul : n'alimentent rien ; avant le premier volume de la séance → `null` (pas de VWAP, pas de distance). / function sessionVwap(bars: readonly FootprintBar[], ctx: SeriesContext): Array<number | null> { const out = new Array<number | null>(bars.length).fill(null); for (const s of splitSessions(bars, ctx)) { let pv = 0; let v = 0; for (let i = s.start; i <= s.end; i++) { const w = bars[i].totalVolume; if (w > 0) { pv += typicalPrice(bars[i]) * w; v += w; } out[i] = v > 0 ? pv / v : null; } } return out; } /** Extrêmes COURANTS (running high/low) de la séance en cours, reset à chaque ouverture 17:00 CT. Définis dès la 1ʳᵉ barre : un extrême courant existe immédiatement, contrairement à une moyenne — pas de warm-up. */ function runningSessionExtremes( bars: readonly FootprintBar[], ctx: SeriesContext, ): Array<{ hi: number; lo: number }> { const out = new Array<{ hi: number; lo: number }>(bars.length); for (const s of splitSessions(bars, ctx)) { let hi = Number.NEGATIVE_INFINITY; let lo = Number.POSITIVE_INFINITY; for (let i = s.start; i <= s.end; i++) { if (bars[i].high > hi) hi = bars[i].high; if (bars[i].low < lo) lo = bars[i].low; out[i] = { hi, lo }; } } return out; } /** Offset de la barre depuis l'ouverture de SA séance, en NANOSECONDES. Les buckets sont des ns entiers sur la grille du timeframe : la clé est exacte (la règle `priceKey` ne concerne que les PRIX). */ function offsetNs(bar: FootprintBar, openSec: number): number { return bar.bucketTsNs - openSec * 1e9; } /** Offset de la barre depuis l'ouverture de SA séance, en MINUTES ENTIÈRES (plancher). Clé plus grossière qu'`offsetNs` — voir `time-of-day-volume` pour la raison d'être de ce choix. */ function offsetMinutes(bar: FootprintBar, openSec: number): number { return Math.floor((bar.bucketTsNs / 1e9 - openSec) / 60); } /** Seuil de percentile par RANG LE PLUS PROCHE (nearest-rank, méthode NIST « inverse empirique ») sur une liste TRIÉE ASCENDANTE et NON VIDE : rang = ⌈pct/100 × m⌉, borné à [1, m] → seuil = trié[rang − 1] Choix documenté : pas d'interpolation linéaire. Sur 4 ou 5 niveaux — le cas courant d'une barre footprint — une interpolation fabriquerait un seuil qui n'existe dans aucun niveau ; le rang le plus proche rend toujours un volume RÉELLEMENT observé. */ function nearestRankThreshold(sortedAsc: readonly number[], pct: number): number { const m = sortedAsc.length; const rank = Math.min(m, Math.max(1, Math.ceil((pct / 100) * m))); return sortedAsc[rank - 1]; } // ── Microstructure (Tape & flow) ──────────────────────────────────────────── /** Distribution des tailles — part du volume venant des niveaux LOURDS : seuil = percentile P des volumes de niveau de la barre (nearest-rank) value = 100 × Σ { vol(niveau) : vol(niveau) > seuil } / Σ vol(niveau) POURQUOI : une barre de 1 000 lots répartie sur 20 niveaux et une barre de 1 000 lots dont 800 sont tombés sur 2 prix ne racontent pas la même histoire. Cet indicateur mesure la CONCENTRATION du flux, c'est-à-dire la trace que laissent les gros participants — le seul angle honnête sur la « taille des trades » que permette une barre footprint AGRÉGÉE : la distribution des tailles trade par trade exigerait le tape brut (l'ordre des exécutions est perdu à l'agrégation). Le doc-comment le dit plutôt que le nom seul. Convention : comparaison STRICTE au seuil (`>`), donc une barre dont TOUS les niveaux pèsent pareil rend 0 — c'est une valeur MESURÉE (aucune concentration), pas un 0/0 déguisé : le dénominateur, lui, est > 0 par construction (`usableLevels` exclut les niveaux à volume nul). Défaut P=80 : le décile supérieur est trop fin pour 3-5 niveaux, la médiane ne mesure plus la concentration mais la simple asymétrie. Barre sans niveau exploitable → PAS de point. Aucun tick size requis (les clés ne servent qu'à dédupliquer).
Как его читать
- Низкие значения означают, что объём бара распределён по его уровням цены довольно равномерно; высокие — что большая его часть пришлась на очень немногие цены.
- Концентрацию, возникшую на краю диапазона, стоит открыть на самом футпринте, где видно, какая сторона ленты её создала.
- Число пригодных уровней в баре определяет, что может оказаться выше порога по умолчанию: при менее чем пяти уровнях 80-й процентиль попадает на самый тяжёлый уровень, и значение по построению равно 0.
- Значение ровно 0 — измеренный результат, а не отсутствие данных: ни один уровень не нёс объёма больше порога.
- Бары без пригодного уровня не дают никакой точки, так что пропуск на панели означает, что у бара не было данных по уровням, а не нулевое значение.
Параметры и значения по умолчанию
Percentile по умолчанию равен 80 и принимает значения от 1 до 99. Поскольку порог берётся по ближайшему рангу, процентиль и число уровней напрямую взаимодействуют: бар возвращает ненулевое значение, только если содержит не менее 100/(100 − P) пригодных уровней, то есть пять при значении по умолчанию. На баре ровно из пяти уровней порог приходится на четвёртый по тяжести, так что значение — это доля единственного самого тяжёлого уровня; на более широких барах оно охватывает примерно верхнюю пятую часть уровней. Снижение процентиля к 50 ставит порог на медианный уровень бара, что повышает значения и измеряет скорее асимметрию, чем концентрацию. Повышение к 99 требует сотни уровней, прежде чем что-либо превысит порог, поэтому на обычных барах футпринта все значения сводятся к 0.
| Параметр | Тип | По умолчанию | Диапазон |
|---|---|---|---|
| Percentile | number | 80 | 1 – 99 |
Чего он не показывает
Это не распределение размеров по сделкам. Восстановление размера каждого исполнения требует исходной ленты, а эта информация теряется, как только бар агрегирует свои уровни. У строгого сравнения есть следствие, которое стоит знать: бар, торговавшийся по одной цене, возвращает 0, потому что ни один уровень не может превысить порог, равный ему самому, хотя такой бар максимально сконцентрирован; та же арифметика объясняет все нули на узких барах при процентиле по умолчанию. Поэтому значение зависит от числа уровней в баре, которое определяется таймфреймом, диапазоном бара и группировкой цен источника, и значения сопоставимы только в пределах одного инструмента и одного таймфрейма. Наконец, нужны данные по уровням с объёмом по каждой цене; источник, дающий только открытие, максимум, минимум, закрытие и объём, не даёт ничего.
Похожие индикаторы
- Unfinished Auctions — Лента и поток
- Effort vs Result — Лента и поток
- POC Drift (ticks) — Лента и поток
- Cumulative buy volume — Лента и поток
- Cumulative sell volume — Лента и поток
- Buy/sell ratio — Лента и поток
Эта страница на других языках
Frequently asked questions
- Можно ли измерить размеры отдельных сделок на футпринте?
- По агрегированному бару футпринта — нет. Агрегация сохраняет объём, проторгованный на каждой цене, но отбрасывает последовательность и размер отдельных исполнений, из которых он сложился. Измеримой остаётся концентрация этого объёма по ценам, её и выводит индикатор.
- Что означает значение 0 в распределении размера сделок?
- Что ни один уровень цены в этом баре не нёс объёма больше процентильного порога, поскольку сравнение строгое. Так бывает, когда все уровни весят примерно одинаково, на баре, торговавшемся по одной цене, и на любом баре с менее чем пятью пригодными уровнями при 80-м процентиле по умолчанию, где порог попадает на самый тяжёлый уровень. Это измеренное значение, а не ошибка.
- Какой процентиль использовать для распределения размера сделок?
- Начните со значения по умолчанию 80, которое работает на барах из пяти и более уровней. Прежде чем менять его, проверьте, сколько уровней на самом деле в ваших барах: процентилю P нужно не менее 100/(100 − P) уровней, прежде чем какой-либо уровень превысит порог, поэтому 99 на типичном баре футпринта непригоден. Процентиль около 50 измеряет, насколько асимметрично распределение, а не насколько оно сконцентрировано.