Concepts
Coordinates
How a script places shapes: pane px, time in epoch ms, raw prices, and converting between them.
Pane px
Everywhere a script sees x and y, they are pane px: CSS px from the top-left corner of its pane's data area. The pane spans 0 to frame.width and 0 to frame.height. This holds for g calls, hit shapes, pointer events and widget Rect placement, on every surface, so a script moves between surfaces unchanged.
y grows downward: a higher price has a smaller y.
Time and price
- Time is epoch ms (
Date.now()style). A bar'stimeis its open time. - Price is the raw instrument price, e.g.
5012.25.
Converting (chart surfaces)
| Call | Returns | Note |
|---|---|---|
frame.timeToX(time) | number | null | the center of the bar slot at time, extrapolated beyond the loaded bars. null without bars. |
frame.xToTime(x) | number | null | null without bars |
frame.barTimeAt(time) | number | null | open time of the bar that holds time |
frame.priceToY(price) | number | on this pane's price scale |
frame.yToPrice(y) | number | |
frame.formatPrice(price) | string | as the price axis shows it |
Always check timeToX for null:
const x = frame.timeToX(p.time);
if (x === null) continue;What is in view
frame.visibleTime.from/.to: epoch ms at the left and right edge. Skip everything outside, it costs draw time and is clipped anyway.frame.visiblePrice.from/.to: price at the bottom and top edge.frame.barSpacing: px between neighboring bar centers. A bar isbarSpacingwide around its x.
The first visible bar starts half a bar left of its center. To not miss it, start from frame.barTimeAt(frame.visibleTime.from).
Crisp lines
frame.dpr is the device pixel ratio. To put an edge on a device pixel: Math.round(y * frame.dpr) / frame.dpr.