Skip to main content

Drawing Tools

TradeScript chart with multiple user-created drawing overlays visible on price data
The visible result is the same whether a user creates a drawing from the toolbar or the host creates it through ChartApi; identity and persistence differ.

Lines, rays, ranges, Fibonacci tools, text, icons, markers, position tools, and chart annotations are all the same kind of object once they are on the chart. Only their origin differs, and there are exactly three origins:

PathWho creates itEntry pointDetails
User-createdThe user, interactivelyDrawing toolbar or selectDrawingToolbelow
API-createdThe host, programmaticallychart.createDrawing(...)Overlays
PersistedRestored from storageloadDrawings / setDrawingsPersistence

For exact native tool ids, labels, groups, and documented style paths, see the generated Drawing Tool Reference.

User-created drawings

The left drawing toolbar arms a tool; the user then places its anchor points on the chart. The resulting object is a normal drawing — it appears in chart.listDrawings() and can be updated, styled, or removed through the same APIs as API-created drawings.

Left drawing toolbar with the line-tools family expanded showing trend, ray, and channel tools ready for placement Each toolbar entry represents a tool family. Selecting a tool arms interactive placement; the chart leaves placement mode when the drawing completes or is cancelled.

Drawing family flyout listing the individual tools inside one toolbar group with their names and icons Family flyouts expose the individual tool ids documented in the reference. External toolbars list the same catalog through listDrawingTools().

Host code drives the same interactive path:

TaskTradeScript API
List available toolschart.listDrawingTools()
Select a tool for interactive placementchart.selectDrawingTool(toolId)
Read the selected toolchart.getSelectedDrawingTool()
Follow completion or cancellationchart.on('drawing-tool-change', ...)
Set magnet modesetMagnetMode / getMagnetMode

External drawing toolbars should use listDrawingTools() for the catalog, selectDrawingTool(toolId) to arm placement, and on('drawing-tool-change', ...) to follow completion or cancellation.

Line labels

Every line tool can carry its own text label — there is no separate "labelled line" tool. Hover a placed line and an + Add text prompt appears at its midpoint; click it and type. The label follows the line's angle and moves with it, and the styling turns bare text into a badge.

Three horizontal lines carrying the same label rendered as bare text, a square badge, and a rounded pill, each annotated with the style key that produces it One label mechanism, three shapes. borderVisible turns text into a badge; borderRadius decides square or pill; textPosition places it above, on, or below the line.

The text lives in metadata.lineText and the badge styling in metadata.styles.*:

ControlStyle pathNotes
Label textmetadata.lineTextEmpty or absent means no label
Positionmetadata.styles.textPositionabove (default), center, below
Typemetadata.styles.textColor / fontSize / fontWeight / fontStyleText color falls back to the line color
Backgroundmetadata.styles.backgroundVisible / backgroundColor / backgroundOpacityOff by default
Bordermetadata.styles.borderVisible / borderColor / borderSize / borderStyleBorder color falls back to the line color
Shapemetadata.styles.borderRadius0 is a square badge; higher values round it into a pill
Paddingmetadata.styles.paddingX / paddingYWidens automatically once the label becomes a badge
import type { ChartApi } from '@tradescript/pro/sdk/core';

declare const chart: ChartApi;

await chart.createDrawing({
type: 'horizontalStraightLine',
points: [{ time: 1719878400000, value: 105.52 }],
styles: { line: { color: '#2962FF', size: 1 } },
metadata: {
lineText: 'Support 105.52',
styles: {
textPosition: 'center',
borderVisible: true,
borderRadius: 13,
backgroundVisible: true,
backgroundColor: '#0b1017',
},
},
});

Users reach the same controls through the line's settings panel: select the line, open its gear, and the Text section holds position, type, background and border. The exact set of label paths a tool publishes is listed per tool in the generated Drawing Tool Reference — a line tool that renders no label publishes none of them.

API-created drawings

The host creates drawings directly from data — no user interaction involved. The full create/update/style/remove workflow lives in Overlays; the core operations are:

TaskTradeScript API
Create a drawingchart.createDrawing(drawing)
Read or list drawingschart.getDrawing(id) / chart.listDrawings()
Update or removechart.updateDrawing(id, patch) / chart.removeDrawing(id)
Change visibility, lock, or ordersetDrawingVisibility, setDrawingLock, setDrawingZOrder
Group or ungroupgroupDrawings, ungroupDrawings
import type { ChartApi } from '@tradescript/pro/sdk/core';

declare const chart: ChartApi;

const drawingId = await chart.createDrawing({
type: 'segment',
points: [
{ time: 1719878400000, value: 188.2 },
{ time: 1720137600000, value: 194.6 },
],
styles: { line: { color: '#1677FF', size: 1 } },
});

await chart.updateDrawingProperties(drawingId, {
styles: { line: { color: '#22c55e' } },
});

After the create call, a straight segment connects the two data-space anchor points on the main pane; after the update, the same drawing (same id) renders green instead of blue.

Native drawing handles

Use chart.getDrawing(id) for a cloned snapshot of one drawing. Use chart.duplicateDrawing(id, overrides?) to clone an existing drawing while deep-merging styles and metadata. Use chart.getDrawingHandle(id) for repeated reads, catalog-validated property edits, point edits, duplication, visibility, lock state, z-order, grouping, and removal. The handle uses the same public behavior as the direct drawing methods.

Symbol and image drawings

Use icon and emoji drawings for glyph-backed symbols, including explicit metadata.value and optional metadata.styles for color, size, weight, and font family. Use image drawings for application-owned visual assets. Provide TradeScript drawing options directly; external asset identifiers are not drawing options.

Styling defaults

Use chart.customization().setDrawingDefaultStyles(toolId, styles) to set documented style paths for future drawings created with a specific tool ID. Entries under metadata set documented controls such as arrow heads, bar-pattern type, simulation, and label/card fields. Existing drawings keep their current values until you update that drawing.

Only use style paths listed in the Drawing Tool Reference. A drawing tool with no listed style paths does not have a public default-style schema yet.

validateCustomizationState(...) validates drawingDefaultStyles against the native catalog. inspectDrawingNativeStyles(toolId, styles) exposes the same catalog check for create/update flows. updateDrawingProperties(...) rejects unsupported native style fields before mutation and deep-merges nested styles and metadata; updateDrawing(...) remains an open patch channel and reports validation warnings for unsupported style fields on known native drawing tools without rewriting the host payload.

Persisted drawings

Drawings survive reloads through the storage path — snapshot APIs on the chart plus a ChartStorageAdapter owned by the host. The ownership diagram, identity rules, and failure behavior live in Persistence.

TaskTradeScript API
Snapshot all drawingsgetDrawings, setDrawings
Persist separatelysaveDrawings, loadDrawings

The SDK exposes DrawingDefinition, DrawingSnapshot, and DrawingState for drawing persistence. A restored drawing keeps its id, geometry, styles, visibility, lock state, grouping, and z-order — it is indistinguishable from the moment it was saved.

Smart drawings

Smart drawings sit between indicators and hand-placed drawings: the chart computes them from your bars in the chart worker and projects the results onto locked overlays marked Auto. Toggling one never arms the pointer, and the overlays it produces stay out of drawing storage, sharing, undo, and user drawing counts.

ToolWhat it finds
autoLevelsSession high and low, previous-day high and low, premarket high and low, and the opening range
autoLevelsRangeThe high and low of a span you draw, plus the support and resistance solved from the price action inside it
autoLevelsVisibleThe same levels, solved from the bars currently on screen and re-solved as you pan and zoom
hodLodBreakBars that take out the running session high or low
vwapBreakSession-anchored VWAP plus the closes that cross it
patternRecognitionDouble top and bottom, head and shoulders and its inverse, and ascending, descending, and symmetrical triangles

What your feed must supply first

Smart drawings compute from your bars, so three source facts decide whether they can produce anything. Each missing fact is reported as a typed state, never guessed around — if you enable the tools and see nothing drawn, check these before anything else.

RequirementSupplied byMissing it means
Session windowsMarketDataFeed.resolveSessionCalendar plus supportsSessionCalendarEvery tool reports session-calendar-unavailable and draws nothing
Bar finalityBar.state on history and realtime, plus supportsBarFinalityBar-close confirmation reports bar-finality-unavailable; switch a tool to intrabar to run without it
VolumeBar.volume on every session barVWAP reports volume-unavailable; absent volume is never treated as zero

Adding a session calendar has one visible side effect worth knowing before you ship it: session background shading is on by default, so the chart starts painting pre-market, regular, and after-hours bands across the plot. That is sessionBackground.show in chart settings — turn it off through displaySettings if you want the calendar's precision without the bands.

sdk.chart.mount({ ...options, displaySettings: { sessionBackground: false } });

Pick a schedule that matches the instrument, too. A 24/7 symbol on an equities calendar spends most of its time outside regular hours, and the session-scoped tools (HOD/LOD Break, VWAP Break) will have no current session to work in even though Auto Levels still returns previous-session levels. Use CONTINUOUS_SESSION_SCHEDULE for crypto and US_EQUITIES_SESSION_SCHEDULE for listed equities.

The session calendar is the one most integrations miss. Build one from a declarative schedule:

import { US_EQUITIES_SESSION_SCHEDULE, createSessionCalendarProvider } from '@tradescript/pro/sdk';

const sessionCalendar = createSessionCalendarProvider(US_EQUITIES_SESSION_SCHEDULE);

const feed: MarketDataFeed = {
...yourFeed,
onReady: async () => ({ ...(await yourFeed.onReady?.()), supportsSessionCalendar: true }),
resolveSessionCalendar: async (request) => await sessionCalendar(request),
};

Enable the tools

Listing a tool in tools offers it in the toolbar; it stays switched off until someone toggles it. Use enabledByDefault when you want results on first paint. A user's saved choice always wins over both.

const widget = sdk.chart.mount({
mount: '#chart',
symbol: 'BTCUSDT',
interval: '1m',
datafeed: feed,
features: {
smartDrawings: {
enabled: true,
tools: ['autoLevels', 'hodLodBreak', 'vwapBreak', 'patternRecognition'],
enabledByDefault: ['autoLevels', 'vwapBreak'],
defaults: {
autoLevels: { openingRangeMinutes: 15 },
hodLodBreak: { confirmation: 'bar-close' },
vwapBreak: { confirmation: 'bar-close', source: 'hlc3-volume' },
patternRecognition: { confirmedOnly: true, maxResults: 20 },
},
},
},
});

const chart = widget.chart();
chart.setSmartDrawingEnabled('autoLevels', true);
chart.updateSmartDrawingSettings('autoLevels', { openingRangeMinutes: 30 });

const state = chart.getSmartDrawingState('autoLevels');
chart.dismissSmartDrawingResult('autoLevels', state.results[0].resultId);
const keptId = chart.keepSmartDrawingResult('autoLevels', state.results[1].resultId);

Tune the solved levels

autoLevelsRange and autoLevelsVisible solve support and resistance from the bars in their span. Prices the market was rejected at are resistance and prices it bounced off are support, so an area that flipped reports as one of each.

Each solved level arrives as two results that share a colour: a zone tinting the band its touches fell in, and a horizontal-level at the band's midline, labelled with its side and touch count. Resistance is red and support is green; the span's own high and low take amber and sky so those two colours only ever mean support and resistance.

maxResults defaults to 6 and is split between the two sides, so both are represented whichever is stronger. Four more settings control the solver.

SettingControls
pivotWingBars either side of a turn before it counts as a pivot. Raise it for fewer, more structural levels
minimumTouchesTurns a price must have produced before it is reported
zoneWidthAtrPercentHalf-height of each band as a percentage of ATR, which also decides whether two nearby touches are one level or two
zonesSet false to draw the midlines without the bands
chart.updateSmartDrawingSettings('autoLevelsVisible', {
pivotWing: 5,
minimumTouches: 3,
zoneWidthAtrPercent: 60,
maxResults: 6,
});

keepSmartDrawingResult is the only path that turns a computed result into a normal drawing. The copy it creates is editable, persistent, and yours; the managed original is suppressed so you do not end up with two of them. Dismissing a result suppresses its stable id so it does not reappear on the next recalculation, scoped to the tool, symbol, and interval.

Smart drawings never infer a fact they were not given. Bar-close confirmation needs real finality, so set Bar.state to final or developing on both history and realtime updates and declare supportsBarFinality on the feed — finality is never derived from a bar timestamp or the wall clock. Session windows come from resolveSessionCalendar, volume is required for VWAP, and an absent volume is never treated as zero. When a required fact is missing the tool reports a typed state such as bar-finality-unavailable, session-calendar-unavailable, or volume-unavailable instead of guessing.

Detection runs only in the chart worker; there is no main-thread fallback, so a disabled or failed worker leaves tools reporting worker-unavailable.

Next steps

  • Drawing Tool Reference — every tool's id, family, capabilities, and supported style paths.
  • Overlays — create, update, style, and remove drawings through ChartApi.
  • Drawing Persistence — the save and restore sequence, identity, and versioning rules.
  • Drawing Storage — embedded versus separate storage records in your backend.