Footprints
The buy and sell volume at each price row inside a bar, the data the Footprint chart draws, with its busiest rows, delta extremes and Extremes readings.
A footprint splits each bar into price rows and shows who traded at each one: sells that hit the bid and buys that lifted the ask. The Footprint chart type draws it; a script reads the same data with the fp names. Footprints come with Pro and Elite. On other plans every fp value is na and the legend says why; the script still compiles and runs.
#Where the data comes from
fp reads the Footprint chart's own data for the chart's own market and exchange, in the chart's order: the live footprint built from the trades, then ChartDeck's recording, then days rebuilt from the trade archive. Another exchange is never used; on an aggregated chart the values are the aggregated footprint the chart draws, summed over the exchanges ChartDeck records. A market or timeframe without footprints (they exist for 1-minute to 1-day bars) reads na, and the legend says so.
Every value reads the bar's rows on the recorded grid: 50 rows per 1 % of the bar's close (BTC: $20 rows). That is the grid the chart's own marks are read on. The rows the chart draws follow your zoom; the values a script reads do not, so a script gives the same answer at any zoom, in Bar replay and on ChartDeck's servers.
#One value per bar
| Name | Gives |
|---|---|
fp.available | true when the bar has footprint rows |
fp.row_size | the row height in price behind the values below |
fp.buy_vol, fp.sell_vol, fp.delta | buys, sells and buys minus sells, summed over the rows (base coin) |
fp.poc | the middle of the busiest row (the bar's point of control) |
fp.max_sell_px, fp.max_sell_qty | the row with the most sells: its middle and its sell volume |
fp.max_buy_px, fp.max_buy_qty | the same for buys |
fp.min_delta_px, fp.min_delta | the row with the most negative delta: where sellers hit hardest |
fp.max_delta_px, fp.max_delta | the row with the most positive delta |
fp.low_delta, fp.high_delta | the net delta of the bar's low and high zone (the bottom and top 25 % of its rows, 2 at least) |
fp.low_read, fp.high_read | the chart's Extremes reading of that zone: 1 initiative, -1 responsive, 0 neither side clear |
Prices are the middle of a row. When two rows tie, the lower one counts. A bar with fewer than 4 rows has no zones: its low_ and high_ values are na. The Extremes readings use the chart's default settings; the chart also leaves out bars much quieter than the others in view, which depends on the view, so a script compares volumes itself.
//@chartscript 1
indicator("Footprint point of control", { overlay: true })
plot(fp.poc, "POC", { color: color.orange, style: plot.style_circles })
plotshape(fp.low_read == 1, "Selling at the low", shape.triangledown, location.belowbar, color.red)
plotshape(fp.high_read == 1, "Buying at the high", shape.triangleup, location.abovebar, color.green)#Lower timeframes
The per-bar values work inside requests. On a 5-minute chart, request.lower_tf("1", ...) gives each bar the values of its 1-minute bars, oldest first:
//@chartscript 1
indicator("Hardest selling inside the bar", { overlay: true })
const [px, d] = request.lower_tf("1", [fp.min_delta_px, fp.min_delta])
let worst: float = na
let at: float = na
for (let i = 0; i < d.size(); i++) {
if (!na(d.get(i)) && (na(worst) || d.get(i) < worst)) {
worst = d.get(i)
at = px.get(i)
}
}
plot(at, "Row of the hardest 1-minute selling", { color: color.red, style: plot.style_cross })#The rows themselves
fp.rows(back) returns the rows of a bar, low to high, as fp.row values with price (the row's middle), buy, sell and delta. back counts bars: 0 is this bar. A bar wider than 400 rows gives the 400 around its point of control. fp.delta_at(price, back) gives the delta of the row holding a price, and fp.since() the time of the first bar with rows. These three read the chart's own bars: inside a request they read na.
//@chartscript 1
indicator("Delta at the low", { overlay: true })
const atLow = fp.delta_at(low)
plotshape(atLow < 0 && close > fp.min_delta_px, "Sellers at the low, close above", shape.circle, location.belowbar, color.orange)#Where the history starts
fp.since() is the time of the first bar with footprint rows among the bars your script runs on. Give it a timeframe and it says where the footprint the script reads at that timeframe starts: on a 5-minute chart that reads request.lower_tf("1", fp.*), fp.since("1") is the first 1-minute bar with rows, usually much later than fp.since() because a script reads about 10,000 bars of each timeframe (7 days of 1-minute bars, 35 days of 5-minute bars). Bars before it read na, never 0, and fp.available is false there.
//@chartscript 1
indicator("Footprint history", { overlay: true })
const d = request.lower_tf("1", fp.min_delta)
if (barstate.islast) {
if (na(fp.since("1"))) {
legend.info("No 1-minute footprints here")
} else {
legend.info("1-minute footprint history starts at " + str.format_time(fp.since("1"), "yyyy-MM-dd HH:mm") + " UTC")
}
}
plot(array.size(d), "1-minute bars read")#The forming bar, replay and history
The newest bar's values move until it closes, as its footprint does: use barstate.isconfirmed for a value that will not change. In Bar replay a script keeps running and sees only the bars that had closed at the replay clock.
A script reads about the newest 10,000 bars of each timeframe (42 pages of 240 bars), counted separately for the chart's bars and for each requested timeframe. Older bars read na, never 0, and fp.available is false there; so do bars before the recording started. A script never starts a rebuild from the trade archive: days the archive has not rebuilt yet are na until someone opens them on a Footprint chart. A script whose run is longer than that (a 20,000-bar run on Elite) gets footprints on its newest 10,000 bars only.
All fp values together count as one of your plan's data series per script, once for the chart and once per requested timeframe. A script on ChartDeck's servers (a protected script, a script alert) reads the same pages with the same rules, so it gives the same values as on the chart.
A footprint is a reading aid, not a forecast: it shows what traded, not what will.