Skip to content
ChartDeck ChartScript docs Account Open the terminal

What converts

Exactly what the Pine importer converts, rewrites, comments out or refuses: versions, names, requests, inputs, strategies and libraries.

This page lists what the importer does with each part of a Pine script. The result is written in ChartScript's own syntax (braces, const / let, state, &&, options objects; see Syntax below), and every change of meaning or name is also listed in the import report, with its line, so you never have to guess.

The import dialog: a paste box, an Add files button and a Convert button

#At a glance

AreaResult
Pine version 5 and 6 indicators and librariesConverted
Pine version 4Converted, through a version 4 → 5 pass first
Pine versions 1 to 3Converted only when the script is simple (no security call, and the result parses); otherwise refused
StrategiesConverted as indicators: plots, drawings and alert conditions are kept; orders and strategy results become comments (strategies are not available yet)
Drawings: labels, lines, boxes, tables, linefills, polylines, chart.pointKept as they are: the names are the same
barcolor, gradient fillKept
Other timeframes and markets (request.security)Rewritten to request.tf / request.market
AlertsRewritten to alert.on / alert.send
Protected, invite-only or obfuscated textRefused: the source has to be readable
Libraries your script importsConverted with the script when you add their files at the same time

#What you can give the importer

  • Paste one script into the box, or add files (.pine or .txt, up to 5 MB each, up to 20 files at once). You can also drop files on the dialog.
  • Add a script and its libraries together: each library is matched to its import line by the title in its library("…") call, converted first, and the import line is pointed at version 1 of your copy (the version it gets when you save it).
  • A script without a //@version= line is read as version 1.

#Versions

Version lineWhat happens
//@version=6Converted directly. ChartScript follows the version 6 rules, so few meaning changes are reported
//@version=5Converted directly, with the version 5 rules that differ from version 6 handled (see below)
//@version=4Converted through a version 4 → 5 pass: study becomes indicator, functions get their namespaces, typed input() calls, transp, iff and more (see below)
//@version=1 to 3, or noneRead as version 4 when the script is simple. A script that uses security, or that does not parse after conversion, is refused with: convert the script to version 5 or later in its original editor first

The converted script starts with //@chartscript 1 on line 1, and your //@version= line stays as a comment (// (imported) @version=5). Comments and blank lines are kept. Line numbers do not stay the same: closing braces } take lines of their own, and Pine's several declarations on one line (a = 1, b = 2) become one per line. The import report therefore gives every item's line in the converted script, which is the text you see in the editor.

#License

What the header saysWhat happens
An SPDX-License-Identifier: line, or a recognized license text (Mozilla Public License 2.0, Creative Commons, MIT, Apache 2.0, GNU licenses, BSD, CC0, Unlicense)The header is kept word for word and the card shows the license
A non-commercial license (Creative Commons NonCommercial)Shown plainly on the card: personal, non-commercial use only; keep the author's credit and the license
No license lineYou must tick This is my own script or I have the right to use it before Save to My scripts is enabled

#Syntax

The importer prints the converted script in ChartScript's syntax. These rewrites never change what the script computes, so they are not listed in the report one by one. Pine to ChartScript names has the full table.

PineChartScript
x = econst x = e, or let x = e when the script changes x later
float x = nalet x: float = na
x := ex = e
var x = e / varip x = estate x = e / live state x = e
and, or, not&&, ||, !
if c and an indented blockif (c) { … }
switch s with v => …switch (s) { case v: … default: … }
for i = 0 to 9 (both bounds are numbers)for (let i = 0; i <= 9; i++) { … }
for i = 0 to n - 1 (a bound that is not a plain number)for (let i = 0 to n - 1) { … }, the range loop, which keeps Pine's meaning exactly (it counts down when the start is above the end)
for x in arr, for [i, x] in arrfor (const x of arr), for (const [i, x] of arr)
while cwhile (c) { … }
f(x) => e and multi-line functionsconst f = (x) => e, function f(x) { … return v }
method f(Zone this, …)method Zone.f(…) { … }, with this inside
type and enum with indented fieldstype Zone { … }, enum Side { … }
import user/Name/1 as Ximport * as X from "@user/Name@1"
named arguments name = valuean options object { name: value } as the last argument
strings across several linestemplate literals `…`

The range loop is chosen whenever the importer cannot tell from the text which way the loop counts. When you know the loop always counts up, you can rewrite for (let i = 0 to n - 1) as for (let i = 0; i < n; i++); see Loops.

#Declarations and keywords

PineChartScriptReport group
//@version=N//@chartscript 1 (the old line kept as a comment)Renamed (FYI)
study(...) (version 4)indicator(...)Renamed (FYI)
strategy(...)indicator(...); settings an indicator does not have (initial_capital, commission_value …) are removedMeaning changed
indicator(timeframe = ...)the argument is removed: the script runs on the chart's timeframeNot drawn yet
variplive state (same meaning)Renamed (FYI)
your own name that ChartScript uses (market, flow, input, timeframe, alert, request, map …)the name plus _ (market_)Renamed (FYI)
a function and a variable with the same name (Pine keeps them apart)the function becomes name_f()Renamed (FYI)

#Market information

PineChartScript
syminfo.tickeridmarket.id
syminfo.tickermarket.symbol
syminfo.prefixmarket.venue
syminfo.basecurrency / syminfo.currencymarket.base / market.quote
syminfo.mintickmarket.tick
syminfo.typemarket.kind ("perp", "spot" or "other")
syminfo.pointvalue, timezone, description, root, pricescale, minmovemarket.pointvalue, timezone, description, root, pricescale, minmove
syminfo.mincontract / syminfo.main_tickeridmarket.min_qty / market.main_id
syminfo.sessionsession.regular
any other syminfo.* fieldna, listed under Data substituted
syminfo.type == "crypto"(market.kind == "perp" || market.kind == "spot"), true on every ChartDeck coin market
syminfo.type == "swap" / "futures"market.kind == "perp" ("futures" is listed under Meaning changed: ChartDeck's only kinds are "perp", "spot" and "other")
bid, askfloat(na), listed under Data substituted

#Other timeframes and markets

request.security becomes request.tf on the chart's own market and request.market on another one. Its lookahead and the shape of the expression decide the at mode ({ at: … }). The three modes are explained in Other timeframes and markets.

Pine callChartScriptReport
request.security(syminfo.tickerid, "D", close[1], lookahead = barmerge.lookahead_on) (the usual no-repaint form)request.tf("D", close, { at: request.close })Renamed (FYI)
lookahead on, expression known when the higher bar opens (open, time, inputs, high[1] …){ at: request.start } (the compiler proves it)Renamed (FYI)
lookahead on, expression not known at the open (close, ta.highest(high, 5) …){ at: request.close }: the last closed valueMeaning changed: the original looked into the future on past bars
lookahead on, expression not known at the open, timeframe from an input whose default is the chart's{ at: request.developing }Meaning changed
lookahead off (the default), higher timeframe{ at: request.developing }: the higher bar so far, on history and liveMeaning changed: history will not match the original's bar for bar
the chart's own market and timeframe ("" or timeframe.period)just the expression, in bracketsRenamed (FYI)
gaps = barmerge.gaps_on{ gaps: true }—
another market as text, "BINANCE:ETHUSDT.P"request.market("BINANCE:ETHUSDT", …): a .P or PERP suffix becomes the perpetual's idData substituted: an unknown market gives na
a market built while the script runs ("BINANCE:" + base + "USDT")request.market(…) with the same expressionData substituted
ticker.heikinashi(syminfo.tickerid) as the marketkept: the Heikin-Ashi candles are built from the chart market's barsRenamed (FYI)
request.security_lower_tf(syminfo.tickerid, tf, expr)request.lower_tf(tf, expr)Renamed (FYI)
request.security_lower_tf on another marketkept as a commentNot drawn yet
request.financial, economic, dividends, earnings, splits, quandl, seed, currency_rate, footprintfloat(na)Data substituted
the original platform's own Request library (futures open interest) and its callsthe import becomes a comment; its calls give naData substituted

Here is what a typical converted request looks like. The original asked for the previous day's high and low and today's open with lookahead on; all three are known when the day opens, so the importer chose { at: request.start }:

ChartScriptOpen in editor
//@chartscript 1
indicator("Daily levels", { overlay: true })
const [dOpen, pdHigh, pdLow] = request.tf("1D", [open, high[1], low[1]], { at: request.start })
plot(dOpen, "Day open", color.gray)
plot(pdHigh, "Previous day high", color.green)
plot(pdLow, "Previous day low", color.red)

#Alerts

PineChartScriptReport group
alertcondition(cond, title, message)alert.on(cond, title, message)Renamed (FYI)
alert(message, freq)alert.send(message, freq)Renamed (FYI)

#Inputs

PineChartScriptReport group
input(14), input(1.5), input(true), input("text"), input(color.red), input(close)input.int, input.float, input.bool, input.string, input.color, input.source, chosen from the default valueRenamed (FYI)
version 4 input(..., type = input.integer) (also as the third argument)the typed input (input.int), type removedRenamed (FYI)
input.resolutioninput.timeframeRenamed (FYI)
input.symbol("BINANCE:BTCUSDT.P")input.market("BINANCE:BTCUSDT")Renamed (FYI)
active = cond{ enabled_if: cond }Renamed (FYI)

#Version 4 names

Pine version 4ChartScript
ema, sma, rsi, atr, crossover, highest, pivothigh … (every un-namespaced indicator function)ta.ema, ta.sma …
abs, max, min, round, pow, sqrt, log …math.abs, math.max …
tostring, tonumberstr.tostring, str.tonumber
tr, vwap, obv, accdist …ta.tr, ta.vwap, ta.obv, ta.accdist …
period, interval, isintraday, isdaily …timeframe.period, timeframe.multiplier, timeframe.isintraday …
tickerid, tickermarket.id, market.symbol
security(...)as request.security above
iff(c, a, b)c ? a : b
transp = 50folded into the color: color.new(c, 50) (dropped when no color was given)
fill(...) / bgcolor(...) without transpcolor.new(c, 90): version 4 drew them 90% transparent
heikinashi(tickerid), tickerid(prefix, symbol)ticker.heikinashi(…), ticker.new(…)
study(resolution = ...)the timeframe argument, then removed as above
versions 1 to 3: bare color names (red) and styles (style = histogram)color.red, plot.style_histogram, hline.style_dashed

#Version 4 and 5 rules

ChartScript uses the version 6 rules. Where version 4 or 5 behaved differently, the importer rewrites the code so it keeps doing what the author saw, or tells you that the result can differ.

Older ruleWhat the importer doesReport group
5 / 2 gave 2 when both numbers are whole literalswraps it: int(5 / 2)Meaning changed
another whole-number division (len / 2)keeps the fraction (2.5) and tells you; wraps int(…) where a whole number is requiredMeaning changed
a bool could be na (bool(na), cond ? true : na)falseMeaning changed
a number could be a condition (if volume)!na(x) && x != 0, the old meaningMeaning changed
and / or ran both sides on every bara stateful call on the right side (x and ta.crossover(a, b), && in the result) is moved to its own line just above, so it still runs on every bar—
timeframe.period == "D""1D" (also "W" → "1W", "M" → "1M")Meaning changed
color.red, color.teal, color.yellow had other shadeswritten out as the old hex values, so the script looks the same—
label.new text was black by default{ textcolor: color.black } is added where none was given—

Checks that apply to every version: x == na (always false) becomes na(x), and a whole-number division given to a declared int (int s = ms / 1000) is wrapped in int(…).

#Strategies

Strategies are not available in ChartScript yet. A strategy is imported as an indicator so you keep everything that does not trade:

Part of the strategyWhat happens
strategy("Name", ...)becomes indicator("Name", ...); settings an indicator does not have are removed and listed
strategy.entry, strategy.exit, strategy.close, strategy.position_size …each line using them is kept as a comment (// [import] …)
lines that use a value from those lineskept as comments too
plots, drawings, alertconditionkept

The report sums this up under Meaning changed: This is a strategy. Strategies are not supported yet: it is imported as an indicator.

#Libraries

SituationResultReport group
you added the library's file with the scriptconverted, and the import points to your copy (import * as Name from "@you/Name@1")Renamed (FYI)
the library is missingthe import cannot resolve: add its file and convert againBlocking
a public library from the original platform's own publishersChartDeck does not download libraries: copy its source from its page (check its license) and import it with your scriptBlocking

#What is kept as a comment

A line the importer cannot convert is never deleted. It is commented out with the marker // [import], together with every later line that depends on a name it declared. If that empties a block, na is put in the block so the block still has a value. Today this affects:

  • strategy orders and strategy results (see above);
  • request.security_lower_tf on another market;
  • chart.left_visible_bar_time and chart.right_visible_bar_time, which are not available yet.

#What is refused

SituationMessage
The source is protected, invite-only or obfuscated (very long lines)This script's source is not open; it can't be imported.
Version 1 to 3 with security, or not parseableScripts written for versions 1 to 3 are not supported: convert the script to version 5 or later in its original editor first.
A compile error the importer could not fixthe error, with its line, under Blocking: fix it in the editor

#After conversion

The importer compiles the result straight away. It applies only fixes that are safe for an import (the na(x), bool and whole-number cases above), compiles again, and lists every warning or error that is left. A warning that also applies to the original script (for example a ta.* call inside an if) is listed under Renamed (FYI), because the behavior did not change.

Saving checks the size: a script can hold up to 2 MB of code on every plan (comments and blank lines do not count). The save message tells you the size and the limit when an import is larger.

The ChartScript documentation is in English for now; translations will follow.