ctx.atk.* Bridge Reference
Reference for the ctx.atk.* bridge namespace in ATK PyneScript V6 — tables, rectangles, shape text, polylines, candlesticks, volume profiles, and fill_between.
ctx.atk.* Overview#
The ctx.atk.* bridge provides ATK-native composite renderers that go beyond what static plot declarations can express. All bridge calls belong exclusively inside build_visuals(frame, params, ctx).
| Helper | Use it for |
|---|---|
ctx.atk.table | Dashboards and summary cards. Build the payload in the frame builder and render it here. |
ctx.atk.rectangles | Grouped support, resistance, or regime zones that belong together as a batch. |
ctx.atk.volume_profile | Renders a pre-computed volume profile payload. Does not calculate the profile itself. |
ctx.atk.shape_text | Arrow shapes with text labels at specified coordinates. |
ctx.atk.polyline | Multi-point connected path lines. |
ctx.atk.rectangle_ray | A projected rectangle that extends to the right edge. |
ctx.atk.plot_line | ATK bridge line linked to a frame column, usable with fill_between. |
ctx.atk.fill_between | Fill between two ATK bridge lines created by ctx.atk.plot_line. |
ctx.atk.candlestick | Full OHLCV candle rendering through the ATK bridge. |
ctx.atk.horizontal_bar | Horizontal profile bars at specified price levels. |
ctx.atk.dual_horizontal_bar_fixed | Two overlaid horizontal profile bar layers at fixed x coordinates. |
build_visuals Contract#
def build_visuals(frame, params=None, ctx=None):
if frame is None or frame.empty or ctx is None:
return None
table_payload = dict(frame.attrs.get("visual_table_payload") or {})
zone_payload = dict(frame.attrs.get("visual_zone_payload") or {})
profile_payload = dict(frame.attrs.get("volume_profile_payload") or {})
outputs = []
if table_payload:
outputs.append(ctx.atk.table(key="summary_table", **table_payload))
if zone_payload:
outputs.append(ctx.atk.rectangles(key="zone_batch", **zone_payload))
if profile_payload:
outputs.append(ctx.atk.volume_profile(profile_payload, key="volume_profile", orient="right"))
return outputsctx.atk.table#
Build the payload in build_indicator_frame, store it in frame.attrs, then render in build_visuals.
frame.attrs["visual_table_payload"] = {
"position": "top-left",
"title": "Signal Summary",
"columns": 2,
"rows": 3,
"cells": [
{"column": 0, "row": 0, "text": "Metric", "text_color": "#ffffff", "bgcolor": "#0f172a"},
{"column": 1, "row": 0, "text": "Value", "text_color": "#ffffff", "bgcolor": "#0f172a"},
{"column": 0, "row": 1, "text": "Close"},
{"column": 1, "row": 1, "text": f"{float(last['close']):.2f}", "text_color": "#00c853"},
],
}
# In build_visuals:
return ctx.atk.table(key="annotated_dashboard", **payload)ctx.atk.shape_text, polyline, rectangles, rectangle_ray#
# In build_visuals — all geometry prepared in frame builder:
return [
ctx.atk.shape_text(
key="atk_shape_marks",
points=[(float(last["index"]), float(last["close"]))],
shapes=[Shape.ArrowUp],
shape_sizes=[12.0],
shape_colors=["#2962ff"],
texts=["LONG"],
text_sizes=[9.0],
text_colors=["#ffffff"],
fonts=["Arial"],
weights=[500],
locations=[Location.Above],
positions=[Position.AboveBar],
),
ctx.atk.polyline(
key="atk_polyline_path",
points=[
(float(first["index"]), float(first["close"])),
(float(prev["index"]), float(prev["high"])),
(float(last["index"]), float(last["close"])),
],
line_color="#ffd600",
line_width=1.0,
show_points=True,
),
ctx.atk.rectangles(
key="atk_rectangles_zone",
data={
"rectangles": [(float(prev["index"]), float(prev["low"] - 0.2),
float(last["index"]), float(last["high"] + 0.2))],
"line_colors": ["#00c853"],
"line_widths": [1.0],
"fill_colors": ["#00c853"],
"fill_alphas": [26],
},
),
ctx.atk.rectangle_ray(
key="atk_rectangle_ray_zone",
x=float(prev["index"]),
h1=float(prev["low"] - 0.3),
h2=float(last["high"] + 0.3),
border_color="#ff6d00",
fill_color="#ff6d00",
border_width=1,
),
]ctx.atk.plot_line and fill_between#
def build_visuals(frame, params=None, ctx=None):
return [
ctx.atk.plot_line(key="atk_fast_line", source="fast", color="#00c853"),
ctx.atk.plot_line(key="atk_slow_line", source="slow", color="#f23645"),
ctx.atk.fill_between(
key="atk_fast_slow_fill",
line1="atk_fast_line",
line2="atk_slow_line",
color="rgba(41,98,255,0.12)",
fill_alpha=31,
),
]ctx.atk.volume_profile#
# In build_indicator_frame:
try:
payload = calculate_volume_profile(frame.copy(), look_back, row_size, value_area_pct)
except Exception:
payload = {}
frame.attrs["volume_profile_payload"] = dict(payload or {})
# In build_visuals:
payload = dict(frame.attrs.get("volume_profile_payload") or {})
return ctx.atk.volume_profile(
payload,
key="dual_volume_profile",
orient="right",
up_color="#0126A0",
down_color="#ffa32b",
value_area_title="VA",
poc_title="POC",
)build_visuals is render-only. Never compute TA, call request.security, or mutate the frame inside build_visuals. Prepare everything in build_indicator_frame or build_signal_frame, store static config in frame.attrs, then derive current anchors from the live frame slice passed in.
chart.point Recipes#
chart.point creates coordinate anchors for object-style visuals. Use from_index for bar-position anchors and from_time for absolute timestamp anchors.
from source import box, chart, line
# Index-based anchors — easiest for local bar objects.
trend = line.new(
chart.point.from_index(10, 100.0),
chart.point.from_index(20, 105.0),
key="trend_line",
color="#2962ff",
)
# Time-based anchor update.
line.set_xy2(trend, chart.point.from_time(1700000600, 106.0))
zone = box.new(
chart.point.from_index(12, 108.0),
chart.point.from_index(20, 99.0),
key="zone_box",
text="ZONE",
bgcolor="rgba(41,98,255,0.08)",
)line, label, box Recipes#
| Namespace | Best first methods | What to remember |
|---|---|---|
line | new, set_xy1, set_xy2, set_color | Use stable keys if the same conceptual object should persist and update. |
label | new, set_text, set_color | Choose labels when a point needs a message, not just a marker. |
box | new, set_lefttop, set_rightbottom, set_bgcolor | Boxes are best for zones and ranges, not simple one-point annotations. |
def build_visuals(frame, params=None, ctx=None):
if frame is None or frame.empty or ctx is None:
return None
last = frame.iloc[-1]
anchor = frame.iloc[max(len(frame) - 10, 0)]
ctx.label.new(
key="last_close_label",
x=int(last["index"]),
y=float(last["close"]),
text="LAST",
color="#2962ff",
style="label_down",
)
range_box = ctx.box.new(
key="recent_range_box",
left=int(anchor["index"]),
top=float(last["high"]),
right=int(last["index"]),
bottom=float(last["low"]),
bgcolor="rgba(41,98,255,0.08)",
)
ctx.box.set_lefttop(range_box, x=int(anchor["index"]), y=float(last["high"] + 0.5))
return ctx.line.new(
key="close_slope_line",
x1=int(anchor["index"]),
y1=float(anchor["close"]),
x2=int(last["index"]),
y2=float(last["close"]),
color="#ffd600",
)- Download ATK shape zone bridge example
- Download ATK table bridge example
- Download chart.point showcase
See also: