FlowscopeDocs

Large prints

Keep only the trades above a USD notional floor, mark them on the chart and fold them into a per-bar whale delta.

Most of the tape is noise. The prints that move a market are the few large ones. This script reads the trade stream and keeps only prints above a notional floor. For each bar it shows the price of the largest buy and the largest sell as dots on the candle, labels prints above a second, higher threshold with their size, and plots a whale delta histogram with a running total underneath.

large-prints.fs
script "Large prints"

input (
  minUsd = input.float(250_000.0, title: "Minimum print (USD)", min: 1_000.0)
  labelUsd = input.float(2_000_000.0, title: "Label prints from (USD)", min: 1_000.0)
  showLabels = input.bool(true, title: "Label very large prints")
)

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

pane whalePane = pane(title: "Whale delta (USD)", height: 0.22)

plot (
  bigBuy = plot.point(title: "Largest buy", color: color.green, size: 5.0)
  bigSell = plot.point(title: "Largest sell", color: color.red, size: 5.0)
  whaleBars = plot.histogram(title: "Whale delta", on: whalePane)
  whaleTotal = plot.line(title: "Cumulative whale delta", color: color.amber, width: 2, on: whalePane)
)

state (
  buyUsd = 0.0
  sellUsd = 0.0
  topBuyUsd = 0.0
  topSellUsd = 0.0
  topBuyPrice: float? = null
  topSellPrice: float? = null
  running = 0.0
  labelCount = 0
  labels = entities.labelPool(max: 400)
)

// Runs once for every print, oldest first.
on tape.trade(tr) {
  let usd = tr.price * tr.size
  if usd >= minUsd {
    if tr.isBuy {
      buyUsd += usd
      if usd > topBuyUsd {
        topBuyUsd = usd
        topBuyPrice = tr.price
      }
    } else {
      sellUsd += usd
      if usd > topSellUsd {
        topSellUsd = usd
        topSellPrice = tr.price
      }
    }
    if showLabels && usd >= labelUsd {
      labelCount += 1
      let text = str.format("{0:,.0} USD", usd)
      labels.get(labelCount).set(tr.time, tr.price, text, color: tr.isBuy ? color.green : color.red)
    }
  }
}

// Show the bar's large-print summary, live bar included.
on chart.update {
  let delta = buyUsd - sellUsd
  whaleBars.plot(delta, color: delta >= 0.0 ? color.green : color.red)
  whaleTotal.plot(running + delta)
  bigBuy.plot(topBuyPrice)
  bigSell.plot(topSellPrice)
}

// Bank the bar into the running total and start fresh.
on chart.close {
  running += buyUsd - sellUsd
  buyUsd = 0.0
  sellUsd = 0.0
  topBuyUsd = 0.0
  topSellUsd = 0.0
  topBuyPrice = null
  topSellPrice = null
}

How it works

Filter by notional

A trade’s notional is tr.price * tr.size. Filtering by USD rather than by base units means the same setting works across coins. If you prefer coins or contracts, subscribe(data.trades, minSize: 5.0) drops smaller prints before they reach the script, which is cheaper on a busy market; the floor must be known at setup, so it cannot depend on the price.

On a chart, trades reach back as far as the chart keeps them in memory. Older bars have no prints and show an empty histogram.

Trades are events, bars are summaries

on tape.trade(tr) runs once per print. The Trade record has non-null fields, so tr.price, tr.size, tr.isBuy and tr.time need no null checks. State connects the two worlds: the trade handler adds into buyUsd and sellUsd, the chart’s update handler displays the running bar, and its close handler moves the bar into running and resets the accumulators.

History is replayed through the same handlers before the script goes live, so the histogram over past bars is built the same way as the live bar.

Largest print per bar

The dots show where in the bar the largest buy and the largest sell printed. A large buy at the top of a red candle reads very differently from one at the bottom. Plotting null (the reset value) leaves a bar without a dot when no qualifying print of that side occurred.

Bounded labels

The label pool holds 400 labels. Each very large print gets the next counter value as its key; once the pool is full, the oldest label is recycled. str.format("{0:,.0} USD", usd) writes the notional with thousands separators and no decimals.

Variations

  • Scale the dot. Pass size: per point: bigBuy.plot(topBuyPrice, size: math.clamp(topBuyUsd / minUsd, 3.0, 12.0)).
  • Split by size band. Add a second floor and sum two deltas, as in size-band delta.
  • Alert on a print. Declare an alert and trigger it in the trade handler when usd exceeds a threshold. Alerts fire on live data only and at most once per bar.