Indicatore On Balance Volume: formula, impostazioni e lettura

L’On Balance Volume, pubblicato da Joseph Granville nel 1963, aggiunge l’intero volume di una barra a un totale cumulato quando la chiusura sale e lo sottrae quando la chiusura scende. Una chiusura invariata lascia il totale esattamente dov’è.

Senzoukria · Indicatori · Updated September 2026


On Balance Volume Volume, in un pannello separato sotto il grafico.

Che cosa misura On Balance Volume

La direzione è decisa dal confronto stretto tra chiusure consecutive: maggiore aggiunge, minore sottrae, uguale non fa nulla, quindi le barre doji non sono mai contate come rialziste. Il volume di ogni barra riceve il segno per intero: l’indicatore non distingue una chiusura più alta di un tick da una più alta di trenta tick. Senzoukria inizializza la serie a 0 sulla prima barra caricata, il che rende la linea riproducibile ma lascia il suo livello assoluto privo di significato. Il cumulo è continuo e non si azzera all’apertura delle 17:00 CT, un’ancora riservata alle misure di sessione come il delta cumulato.

La formula, così come è implementata

Non è la definizione consueta altrove: è ciò che calcola il codice distribuito, documentato accanto alla sua implementazione:

Période entière ≥ `min` depuis les params (garde-fou UI). */ function intParam( params: Record<string, unknown>, key: string, fallback: number, min = 1, ): number { return Math.max(min, Math.floor(numParam(params, key, fallback))); } function toPoints( bars: readonly FootprintBar[], values: ReadonlyArray<number | null>, ): SeriesPoint[] { return bars.map((b, i) => ({ time: b.bucketTsNs, value: values[i] ?? null })); } /** 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 }; } /** SMA N sur série à trous : null dès qu'UNE valeur de la fenêtre est null — moyenner autour d'un trou mentirait sur la période effective (même règle que `smaNullable` de momentum.ts). */ function smaNullable( values: ReadonlyArray<number | null>, period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const out: Array<number | null> = new Array<number | null>(values.length).fill(null); for (let i = n - 1; i < values.length; i++) { let sum = 0; let ok = true; for (let j = i - n + 1; j <= i; j++) { const v = values[j]; if (v === null) { ok = false; break; } sum += v; } if (ok) out[i] = sum / n; } return out; } /** EMA N par segment de valeurs définies consécutives. Un trou reste null et réinitialise uniquement la graine suivante : les valeurs antérieures sont conservées. Chaque reprise attend N valeurs pour sa SMA initiale, puis suit la même récurrence que `emaSeries`, sans zéro synthétique. */ function segmentedEma( values: ReadonlyArray<number | null>, period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const alpha = 2 / (n + 1); const out: Array<number | null> = new Array<number | null>(values.length).fill(null); let count = 0; let sum = 0; let ema = 0; for (let i = 0; i < values.length; i++) { const v = values[i]; if (v === null) { count = 0; sum = 0; continue; } if (count < n) { sum += v; count += 1; if (count < n) continue; ema = sum / n; } else { ema += alpha * (v - ema); } out[i] = ema; } return out; } /** Money Flow Volume de Chaikin pour UNE barre : MFM = ((close − low) − (high − close)) / (high − low) ∈ [−1, +1] MFV = MFM × volume MFM est la position du close dans le range, recentrée : +1 = close au plus haut (toute la barre a été achetée), −1 = close au plus bas. Range NUL (high = low) → `null` : le multiplicateur est un 0/0, la barre ne porte aucune information directionnelle. Les appelants décident quoi en faire — cumul → contribution 0 (cf. en-tête), non cumulé → pas de point. / function moneyFlowVolume(bar: FootprintBar): number | null { const range = bar.high - bar.low; if (!(range > 0)) return null; const mfm = (bar.close - bar.low - (bar.high - bar.close)) / range; return mfm * bar.totalVolume; } /** Ligne A/D (Chaikin) : cumul du Money Flow Volume depuis la première barre chargée. Barre à range nul → contribution 0 (exception documentée en en-tête : un accumulateur ne peut pas porter de trou). CONTINU — pas de reset session (l'A/D est une ligne d'accumulation de long terme). */ function accumDistValues(bars: readonly FootprintBar[]): number[] { const out: number[] = new Array<number>(bars.length); let running = 0; for (let i = 0; i < bars.length; i++) { running += moneyFlowVolume(bars[i]) ?? 0; out[i] = running; } return out; } /** VWMA N sur une fenêtre glissante : Σ(close·volume) / Σ(volume). Σvolume = 0 sur la fenêtre (barres placeholder sans trade) → null : 0/0 n'est pas « 0 ». Warm-up (< N barres) → null. Même formule que `vwma` (averages2.ts) — redéclarée ici plutôt que d'élargir la surface publique d'un autre fichier de famille (sa primitive n'est pas exportée). */ function vwmaSeries( bars: readonly FootprintBar[], period: number, ): Array<number | null> { const n = Math.max(1, Math.floor(period)); const out: Array<number | null> = new Array<number | null>(bars.length).fill(null); let sumPV = 0; let sumV = 0; for (let i = 0; i < bars.length; i++) { sumPV += bars[i].close * bars[i].totalVolume; sumV += bars[i].totalVolume; if (i >= n) { sumPV -= bars[i - n].close * bars[i - n].totalVolume; sumV -= bars[i - n].totalVolume; } if (i >= n - 1) out[i] = sumV > 0 ? sumPV / sumV : null; } return out; } /** Indices de volume de Fosback/Dysart (NVI / PVI) — même moteur, deux déclencheurs : index[0] = base index[i] = index[i−1] × (1 + (close[i] − close[i−1]) / close[i−1]) si `trigger(volume[i], volume[i−1])`, sinon index[i−1] NVI : trigger = volume EN BAISSE (Fosback — l'« argent malin » se positionne les jours calmes). PVI : trigger = volume EN HAUSSE (la foule). Volume ÉGAL → aucun des deux ne bouge (inégalités STRICTES, convention d'origine : une journée sans changement de participation n'est ni l'un ni l'autre). close[i−1] = 0 → contribution 0, l'indice est GELÉ (exception documentée en en-tête : le ratio n'existe pas, et un null perdrait l'ancrage de toute la suite de l'indice — un indice base 1000 sans ancrage ne vaut rien). / function volumeIndexValues( bars: readonly FootprintBar[], base: number, trigger: (vol: number, prevVol: number) => boolean, ): number[] { const out: number[] = new Array<number>(bars.length); let idx = base; for (let i = 0; i < bars.length; i++) { if (i > 0) { const prev = bars[i - 1]; const prevClose = prev.close; if (trigger(bars[i].totalVolume, prev.totalVolume) && prevClose !== 0) { idx *= 1 + (bars[i].close - prevClose) / prevClose; } } out[i] = idx; } return out; } // ── Defs ──────────────────────────────────────────────────────────────────── /** OBV — On Balance Volume (Granville, 1963) : OBV[0] = 0 (graine, cf. convention) OBV[i] = OBV[i−1] + volume[i] si close[i] > close[i−1] = OBV[i−1] − volume[i] si close[i] < close[i−1] = OBV[i−1] si close[i] = close[i−1] POURQUOI : la thèse de Granville est que le volume précède le prix. L'OBV signe le volume ENTIER de la barre par la direction du close — sa PENTE et ses divergences avec le prix sont l'information, jamais son niveau absolu. Convention GRAINE : OBV[0] = 0. L'indicateur n'a pas d'origine absolue (Granville lui-même part d'un nombre arbitraire) ; ancrer à 0 sur la première barre CHARGÉE rend la série reproductible et lisible. Corollaire assumé : charger plus d'historique décale toute la courbe — c'est vrai de tout OBV, ATAS et TradingView compris. Convention ÉGALITÉ : close inchangé → OBV inchangé (règle de Granville, inégalités STRICTES — pas de « ≥ » qui compterait les dojis comme haussiers). CONTINU : pas de reset de session — l'ancrage 17:00 CT ne concerne que les cumuls orderflow type CVD, l'OBV est une accumulation de long terme.

Come leggerlo

  • Granville sosteneva che il volume precede il prezzo; qualunque cosa se ne pensi, il contenuto utilizzabile è la pendenza della linea e i suoi disaccordi con il prezzo, mai il suo livello.
  • Una serie di minimi crescenti dell’OBV sotto un prezzo piatto significa che, in quel tratto, le chiusure in ribasso sono arrivate con meno volume delle chiusure in rialzo.
  • Quando il prezzo segna un nuovo massimo e l’OBV no, le chiusure in rialzo dietro quel massimo hanno portato meno volume delle precedenti: un fatto su quelle barre, non un segnale.
  • Poiché caricare più storico sposta l’intera curva, non costruire nulla su una soglia dell’OBV; costruisci sulla forma.
  • Sui futures intraday confronta l’OBV con il delta cumulato: l’OBV assegna il segno al volume in base alla direzione della chiusura, il delta in base all’aggressore, e divergono proprio dove c’è stato assorbimento.

Parametri e valori predefiniti

La smussatura è 1 per impostazione predefinita e lascia intatta la linea cumulata grezza; valori fino a 200 applicano una smussatura a posteriori che rende più leggibile la pendenza di lungo periodo, nascondendo però le singole barre che l’hanno prodotta. Il colore predefinito è il blu (#2962ff).

On Balance Volume — parametri disponibili nell’applicazione, con i valori predefiniti.
ParametroTipoPredefinitoIntervallo
Smoothingnumber11 – 200

Ciò che non mostra

L’OBV è tutto o niente: un avanzamento di un tick e uno ampio contano allo stesso modo, il che rende la linea nervosa sugli strumenti che chiudono spesso quasi invariati. Usa solo la chiusura, quindi tutto ciò che accade dentro la barra resta invisibile, assorbimento e lato aggressore compresi. L’inizializzazione a zero rende i valori assoluti privi di significato e non confrontabili tra grafici o profondità di storico: una proprietà comune a ogni implementazione dell’OBV, comprese quelle di ATAS e TradingView. Le chiusure uguali congelano la linea, quindi dati di prezzo molto arrotondati o a bassa risoluzione la appiattiscono per ragioni meccaniche.

Vedi tutti gli indicatori

Questa pagina in altre lingue

Frequently asked questions

Come si calcola l’On Balance Volume?
Partendo da un valore iniziale, l’intero volume di ogni barra viene aggiunto quando la sua chiusura è sopra la chiusura precedente e sottratto quando è sotto. Quando le due chiusure sono uguali il totale non cambia. In Senzoukria il valore iniziale è 0 sulla prima barra caricata nel grafico.
L’On Balance Volume si azzera all’apertura della sessione?
No. L’OBV scorre in continuo attraverso le sessioni, perché Granville lo ha concepito come un’accumulazione di lungo periodo. L’ancora di sessione delle 17:00 CT dell’applicazione si applica ai cumuli di sessione come il delta cumulato o il volume di sessione, non all’OBV.
Qual è la differenza tra OBV e delta cumulato?
L’OBV assegna il segno al volume di una barra in base alla direzione della chiusura, quindi dipende solo dai dati OHLC. Il delta cumulato assegna il segno in base al lato aggressore di ogni trade e richiede la classificazione bid/ask del feed. Divergono dove il volume aggressivo non ha spostato la chiusura, che è la firma dell’assorbimento.

Keep reading