Candles tell you where price went; the tape tells you who pushed it. The trade_volume_by_size source hands your script every bar's tape pre-bucketed into fixed USD order-size bands, one cell per populated bucket: [bucketId, buyVolUsd, sellVolUsd, buyCount, sellCount]. That makes separating whale flow from retail flow a one-line reduction, with months of history behind it.
Whale vs retail flow in USD
The bucket source classifies every trade by USD notional into fixed bands (1 = $0-1K up to 7 = $10M+), so c[0] >= 5 means "half a million dollars and up, per trade":
//@version=2
define(title="Whale vs Retail CVD", position="offchart", axis=true);
timeseries ohlcvData = ohlcv(symbol=currentSymbol, exchange=currentExchange);
timeseries tv = trade_volume_by_size(symbol=currentSymbol, exchange=currentExchange);
var cells = tv.cells;
var whaleFlow = cells.filter((c) => c[0] >= 5).map((c) => c[1] - c[2]).reduce((a, b) => a + b, 0);
var retailFlow = cells.filter((c) => c[0] <= 2).map((c) => c[1] - c[2]).reduce((a, b) => a + b, 0);
var barTrades = cells.map((c) => c[3] + c[4]).reduce((a, b) => a + b, 0);
static whaleCvd = 0
static retailCvd = 0
whaleCvd = whaleCvd + whaleFlow
retailCvd = retailCvd + retailFlow
plotLine(value=whaleCvd, colors=["#ab47bc"], width=2, label=["Whale CVD USD"], desc=["CVD from 500K+ USD order-size buckets"]);
plotLine(value=retailCvd, colors=["#26c6da"], width=2, label=["Retail CVD USD"], desc=["CVD from sub-10K USD order-size buckets"]);
plotHistogram(value=barTrades, colors=["#ff9100"], width=0.8, label=["Trades"], desc=["Total trades per bar across all buckets"]);The divergence between the purple and cyan lines is the signal: whales accumulating into retail selling, or distribution into retail chasing. barTrades sums the per-bucket counts, so the histogram is the honest per-bar trade count without touching individual prints.
The rules of the road
- Values are USD notional (tens of millions on liquid perps). Keep one unit system per script: mixing these series with base-unit volume in one pane flattens the smaller series into an unreadable line at the bottom.
- Data depth is layered. USD buckets: about a week at 1m, months at 1h and 1d.
buy_sell_volume: years (addcurrency="USD"for notional). Long-range CVD belongs tobuy_sell_volume, whale history to the buckets. - Multi-timeframe goes through
htf()(cells concatenate across the bucket);requestBars()andltf()reject array-celled sources. - Live budget: more than a handful of concurrently polling tape scripts per account renders the excess as static tape with a
TAPE_POLL_BUDGET_EXCEEDEDnotice.