FlowscopeDocs

Size-band delta

Split each bar's delta into retail, mid-size and whale flow from the trade stream, and flag stretches where whales and retail trade against each other.

Not every buyer is the same. A thousand small market buys and one block of the same size say different things about who is moving the market. This script classifies every print by its notional and keeps a separate delta for small, mid-size and large traders.

You pick where retail ends and where whale size begins. One pane shows the whale delta as columns with the retail delta as a line on top. A second pane shows cumulative delta per group, restarting every day. When whales have been net buyers over the last few bars while retail sold (or the reverse), a marker appears on the price chart.

size-band-delta.fs
script "Size-band delta"

input (
  retailUsd = input.float(10_000.0, title: "Retail below (USD)", min: 100.0)
  whaleUsd = input.float(250_000.0, title: "Whales from (USD)", min: 1_000.0)
  lookback = input.int(20, title: "Comparison window (bars)", min: 3, max: 200)
  minWhaleUsd = input.float(2_000_000.0, title: "Min whale delta in window (USD)", min: 0.0)
)

data (
  chart = subscribe(data.ohlcv)
  tape = subscribe(data.trades)
)

pane (
  barPane = pane(title: "Delta by size (USD)", height: 0.2)
  cumPane = pane(title: "Cumulative delta by size, daily", height: 0.2)
)

plot (
  whaleBars = plot.histogram(title: "Whale delta", on: barPane)
  retailLine = plot.line(title: "Retail delta", color: color.yellow, width: 2, on: barPane)
  whaleCum = plot.line(title: "Whales", color: color.cyan, width: 2, on: cumPane)
  midCum = plot.line(title: "Mid-size", color: color.gray, on: cumPane)
  retailCum = plot.line(title: "Retail", color: color.yellow, on: cumPane)
  whalesBuy = plot.marker(title: "Whales buy, retail sells", color: color.green, shape: shape.up)
  whalesSell = plot.marker(title: "Whales sell, retail buys", color: color.red, shape: shape.down)
)

state (
  retail = 0.0
  mid = 0.0
  whale = 0.0
  retailDay = 0.0
  midDay = 0.0
  whaleDay = 0.0
  whaleWindow = rolling<float>(200)
  retailWindow = rolling<float>(200)
  lastTime: time? = null
)

// Signed notional of each print, sorted into its size group.
on tape.trade(tr) {
  let usd = tr.price * tr.size
  let signed = tr.isBuy ? usd : 0.0 - usd
  if usd < retailUsd {
    retail += signed
  } else if usd < whaleUsd {
    mid += signed
  } else {
    whale += signed
  }
}

on chart.update {
  whaleBars.plot(whale, color: whale >= 0.0 ? color.green : color.red)
  retailLine.plot(retail)
  whaleCum.plot(whaleDay + whale)
  midCum.plot(midDay + mid)
  retailCum.plot(retailDay + retail)
}

on chart.close {
  // Restart the daily lines on the first bar of a new day.
  let t = chart.time ?? time.fromUnixSeconds(0)
  let newDay = time.isNewPeriod(t, lastTime, 1D)
  lastTime = t
  whaleDay = newDay ? whale : whaleDay + whale
  midDay = newDay ? mid : midDay + mid
  retailDay = newDay ? retail : retailDay + retail

  // Who was on which side over the last `lookback` bars.
  whaleWindow.push(whale)
  retailWindow.push(retail)
  let whaleSum = whaleWindow.sumLast(lookback)
  let retailSum = retailWindow.sumLast(lookback)
  let buyStretch = whaleSum >= minWhaleUsd && retailSum < 0.0
  let sellStretch = whaleSum <= 0.0 - minWhaleUsd && retailSum > 0.0
  whalesBuy.plot(buyStretch ? chart.low : null)
  whalesSell.plot(sellStretch ? chart.high : null)

  retail = 0.0
  mid = 0.0
  whale = 0.0
}

How it works

Classify each print

A print’s notional is tr.price * tr.size; its sign comes from the aggressor, tr.isBuy. An if / else if chain sorts it into one of three groups. The thresholds are in USD, so the same settings mean the same trader size on every coin.

Bars and days

The trade handler only adds. on chart.update shows the running bar, on chart.close banks it: the daily sums restart when time.isNewPeriod sees a new day, and the per-bar sums go back to zero. The cumulative lines show the banked day plus the forming bar, so the live bar moves them too.

Who is on the other side

Two rolling<float> windows keep each bar’s whale and retail delta. sumLast(lookback) adds the newest lookback values. When whales bought at least minWhaleUsd over that window while retail was net short, the green marker appears under the bar; the red one marks the reverse. The windows hold 200 values, the input’s maximum.

History

On a chart, trades reach back as far as the chart keeps them in memory; earlier bars read zero in every group. For a long history of total delta, use data.vd instead, as in plots and panes.

Variations

  • Count instead of size. Add counters per group to separate one block from a burst of medium prints.
  • Three-way markers. Mark bars where mid-size traders lead both other groups.
  • Feed a strategy. Use the whale window sum as a filter in the CVD breakout strategy.