---
title: Volume Indicators
description: Money Flow Index and On-Balance Volume — volume-weighted indicators that confirm price moves and flag divergences.
---

Volume indicators incorporate volume data in their calculations to provide insight into buying and selling pressure, money flow, and market participation strength.

| Type | Description |
| --- | --- |
| **Money Flow Index (MFI)** | Volume-weighted RSI that measures buying and selling pressure using both price and volume data. Overbought above **80**, oversold below **20**. |
| **On-Balance Volume (OBV)** | Cumulative volume indicator that adds volume on up bars and subtracts volume on down bars to show volume flow relative to price. |

| Function | Description |
| --- | --- |
| [`mfi`](#mfi) | Money Flow Index — volume-weighted momentum |
| [`obv`](#obv) | On-Balance Volume — cumulative volume flow |
| [`vwap`](#vwap) | Volume-Weighted Average Price (v3) |
| [`cum`](#cum) | Cumulative sum of a series (v3) |

{% hint style="info" %}
**v3 accuracy note.** The volume family is reference-validated to `1e-6` over the test corpus. For volume-weighted *moving averages* see [`vwma`](moving-averages.md#vwma); for aggregated multi-exchange volume flows see [Multi-Source](../core-concepts/multi-source.md).
{% endhint %}

<a id="mfi"></a>

## mfi - Money Flow Index

`mfi(source: TimeSeries, period?: number = 14): number` — Money Flow Index. Measures volume-weighted momentum and returns a value from 0 to 100.

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series with volume |
| `period` | number | Number of periods (default: `14`) |

**Returns:** `number` — MFI value from 0 to 100.

```javascript
var mfiData = mfi(source=trade, period=14);
```

<a id="obv"></a>
## obv - On-Balance Volume

`obv(source: TimeSeries): number` — On-Balance Volume. Shows cumulative volume flow by adding volume when price rises and subtracting volume when price falls.

| Parameter | Type | Description |
| --- | --- | --- |
| `source` | TimeSeries | Source data series with volume |

**Returns:** `number` — OBV value.

```javascript
var obvData = obv(source=trade);
```

<a id="vwap"></a>
## vwap - Volume-Weighted Average Price (v3)

`vwap(anchor?)` — Volume-Weighted Average Price. Without an anchor it is the cumulative VWAP of the loaded data; with one it resets at calendar boundaries.

| Parameter | Type | Description |
| --- | --- | --- |
| `anchor` | string \| number | `"day"`, `"week"`, `"month"` (UTC boundaries) or raw milliseconds. Omit for cumulative. Must be at least the chart interval. |

```javascript
//@version=2
// The institutional intraday line: resets at each UTC day boundary
plotLine(vwap(anchor="day"), colors=["#eab308"], width=2, label=["dVWAP"])

// Weekly anchor for swing context
plotLine(vwap(anchor="week"), colors=["#94a3b8"], width=1, label=["wVWAP"])

Two properties worth knowing:

1. **Anchored VWAP is stable under lazy-loading.** Each session computes only from its own bars, so scrolling back and loading older history cannot change later sessions' values. (The unanchored cumulative form *does* shift when history loads: its anchor is the data edge.)
2. **The leading partial session is honest.** If the loaded window starts mid-session, that first session shows `na` rather than a value computed from half its bars: standard warmup semantics. In practice day anchors are almost always fully covered by any intraday load.
3. **Long anchors need enough loaded history.** On engine `3.0.10`, the 300-hour monthly VWAP probe compiled and ran but produced no finite monthly VWAP values; the same probe at 800 hours passed and produced 414 finite monthly VWAP values. See [Special Indicators](special-indicators.md#anchored-vwap-data-requirement).
```

<a id="cum"></a>
## cum - cumulative sum (v3)

`cum(source, priceIndex?)` — running total of a series from the start of the data. The primitive behind OBV-style accumulation and custom anchored math:

```javascript
//@version=2
timeseries trade = ohlcv(symbol=currentSymbol, exchange=currentExchange);
// Cumulative signed volume (a simple delta proxy)
timeseries signedVol = trade.close >= trade.open ? trade.volume : -trade.volume
plotLine(cum(source=signedVol), colors=["#22d3ee"], label=["Cum delta proxy"])
```
## Best Practices

<table data-view="cards"><tbody>
<tr><td>Volume Quality</td><td>High volume during breakouts confirms the move. Low-volume breakouts are often false signals that reverse quickly.</td><td></td></tr>
<tr><td>Divergence Analysis</td><td>Watch for divergences between price and volume indicators. When price makes new highs but volume indicators do not, be cautious.</td><td></td></tr>
</tbody></table>
