Indicators is where your own indicators live. Paste one written in Pine Script v5 or v6 (the language of TradingView) and Veeman tells you, before you save anything, exactly what runs: every input, every output, which outputs can reach a backtest and why the others can't.
The module compiles, previews, inspects, verifies and saves indicators, and a saved indicator can decide a backtest's entries and exits (Use in backtest). Showing it in Rewind comes in a next release; EasyLanguage arrives in a later phase.
Note
Veeman never rewrites your script. It keeps it as you wrote it, license and copyright lines included (only Windows line endings become plain line breaks, as in any editor), and runs it on its own servers: no code of the script runs in your browser.
There are three ways in:
.pine or .txt file, or choose one;The script compiles a moment after you stop typing. When it isn't all exact, the import report opens first: the constructs that work differently, with their line and what happens to them in Veeman, and a summary of inputs and outputs. Open anyway opens the script; Cancel drops it. Closing the report (✕, Esc or a click outside) keeps the script open. A script that is all exact opens directly, with a one-line summary.
Every function and variable of the language has a class. The editor shows it when you hover a name, and the import report and the Checks tab count them.
alertcondition becomes an event you can use; nothing is sent.barstate.islast and last_bar_index know where the data ends: in the preview that is the last bar shown. timenow is the close of the bar being computed, never the real clock.The script as a whole gets a level: Exact; Runs with differences (some Veeman semantics); Some outputs display-only; Runs · tables skipped (or drawings, or both).
Each problem has a code (like IND-P-0301), a message that says what happened and what to do, and its
place in the text: errors are underlined in red, warnings in amber, and the message sits under the
line. Some come with a quick fix, one click away:
max → Use math.max;high[1]), see below.Pine v5 and v6 run with their own rules (type conversions, na in conditions, division of integers,
timeframe.period…): the version comes from //@version and the chip next to the name shows it.
Each output of the script becomes a typed output. The Outputs tab lists them with their pane (on the price or in their own pane) and where they will be usable.
plot(): a value per bar. Its style (line, step line, histogram, columns, circles, area) is kept for the preview.hline(): a constant, usually a threshold.plotshape() and plotchar(): 1 on the bars where the shape is drawn, 0 elsewhere. With location.absolute the value is the price where it's drawn.plotarrow(): the value itself, up when positive, down when negative.bgcolor(): 1 on the bars with a background color, 0 elsewhere.alertcondition(): 1 on the bars where the condition holds.An output is display only when its values could not have been known at that bar. It still shows in the preview (line, step and area plots dashed), and the Outputs tab gives the reason and its line:
barstate.islast, last_bar_index, last_bar_time);Veeman checks this without running the script, by following every value back to where it comes from,
through variables, conditions, state, loops (a break decided by barstate.islast counts) and your own
functions. Arrays are followed as a whole: until arrays get their own tracking, a value that looks ahead
or knows where the data ends, stored in any array, makes every output that reads an array display
only.
request.security() with lookahead = barmerge.lookahead_on on a higher timeframe shows the
requested bar while it is still forming: on a 5-minute chart, high from the daily bar is the day's
final high from the first bar of the day. That never happens in a backtest, so the outputs built on
it stay display only. The quick fix offsets the expression by one bar (high[1]: yesterday's high,
known all day long). The same request with lookahead_off waits for the bar to close.
Reading the open or the time of the requested bar with lookahead_on is fine: they are known
when the bar starts.
Tables, labels, lines, boxes and polylines arrive in a later phase. Until then a script that uses them
still runs: the lines that build them are skipped and shown struck through, nothing else changes.
A value read back from a drawing (label.get_y, a point's price…) is na, so an output that uses it
is display only. When a construct like barstate.islast only drives a skipped table, it doesn't count
as a difference.
The preview runs the script on Veeman's data, on the symbol and timeframe of the Timing tab: the last 1, 5 or 20 sessions on intraday charts, the last 3 months, year or 3 years on the daily chart. The warm-up the indicator needs is computed before the window, so the first bar shown is already settled; when it isn't, the bars are shaded warming up.
Values are at bar close: a bar's value uses data up to its close and never changes afterwards. A runtime error (an index out of range, a loop that never ends…) is shown with the bar where it happened.
Veeman has no chart-data export: the preview draws the window on screen, and backtests read the indicator's full history on Veeman's servers.
Click a bar in the preview: next to every line of the script that declares a global variable (one per name, not the ones inside your functions), the editor shows its value at that bar's close. Long texts are cut at 200 characters. ← and → step bar by bar (in the editor header or with the arrow keys on the chart).
log.info(), log.warning() and log.error() write to the console under the preview, with the bar
time of each message, for the bars of the window. A run keeps up to 2,000 messages, counting the ones
written during the warm-up before the window, so the console can show fewer; a message longer than 1,000
characters is cut.
You can check, on your own platform, that Veeman computes your script exactly as it does there. The check uses no market data of the platform.
Make a verification copy
In Checks (or the ⋯ menu), Veeman makes a copy of the script: the same logic, with the chart's
prices replaced by synthetic series computed from each bar's time (whole numbers and multiples of
0.25, exact everywhere), one full-precision plot per output, one for bar_index and one that marks
the bars your platform computes live. The license and copyright lines stay at the top.
Run it on your platform
Open a chart with the same symbol as the Timing tab, at any timeframe: Veeman recognizes the timeframe from the export's bar times and compares on that one. Paste the copy into a new indicator, add it to the chart and export the chart data as CSV.
Drop the export here
The file is read in your browser: the price columns (open, high, low, close, volume) are removed there, and only the bar times and the values computed by the script are sent.
Veeman runs the same copy on the bars of your export and compares each output: identical to the last bit, within 64 units in the last place when a transcendental function is involved, or within a relative 10⁻⁹. The report gives, per output, the share of bars that match within those limits, the largest difference and the first bar where they differ. A copy can be made for up to 31 outputs (each one takes a second plot, and the platform allows 64), and an export can have up to 50,000 rows.
The copy's prices depend only on the bar time, so what matters is that both sides run on the same bars. Bars your platform has and Veeman's data doesn't (on SPX, the minutes after the 16:00 close, or a session more recent than Veeman's data) are added for the comparison; bars Veeman has and the export doesn't (on the VIX, minutes without a price change) are left out. The report says how many, and why.
Bars your platform computed live, because the market was open when you exported, run through the calculation but aren't compared. On a live bar a request to another timeframe shows the period still forming (the hour, the day, the week in progress), and the values change until the bar closes. Veeman computes every bar as history, as backtests read it. The report says how many bars were live.
Tip
Functions that read the chart's prices by themselves, like ta.atr, can't be pointed at the synthetic
prices: the verify dialog says so, and small differences there can come from the two data feeds.
ta.vwap needs volume, which Veeman's data doesn't have, so on Veeman's side it is na on every bar.
On a saved indicator the result stays on it (the export isn't kept). A change to the script takes it off, because it verified a different script; edits that don't change what runs (comments, or the default values of numbers, switches and options) keep it.
Save (⌘S) keeps the indicator in your library, or in the space you are working in. A new version is recorded each time the script or its default inputs change; Versions lists them with the script of each one, and Restore brings an old one back as a new version, so nothing is lost. Besides the current one, up to 50 earlier versions are kept, and at most 1,000,000 characters of them (scripts, inputs and notes); the oldest go first. Restoring from a space's history works the same way: a new version, with the history kept.
In a shared space, if someone saved a newer version while you were editing, saving asks you what to do instead of overwriting their work: Reload their version, or Save as copy. Leaving the page with unsaved changes asks first.
Use in backtest opens the backtest composer with the indicator already in Only if, with a first condition to complete: on its first line output that can reach a backtest, or else on its first usable output (an event starts as an already complete «is on»). If the composer has no entry time yet, the floating window is set to the whole session, so the position opens at the first minute the indicator says so; an entry time or window you already set stays (Custom indicators has the details). It needs a saved indicator with no unsaved changes (a backtest reads the indicator from your library), a script that compiles, and at least one output a backtest can read. From the composer the same indicator can also close positions, or open them at each of its signals (an event, or a condition that starts to hold): see Custom indicators and Indicator signal.
A backtest reads each output at the close of its bar, the rule of the Reads line under Timing: at 10:31 a 5-minute indicator gives the bar that closed at 10:30. Display-only outputs never reach it. Every run keeps the script it used, so changing or deleting the indicator later doesn't change a saved backtest.
Six templates written by Veeman: RSI(2) pullback, Opening range, VIX/VIX3M term structure, Trend filter · SMA 200 daily, ATR channel, Bollinger squeeze. Each compiles exact, with every output able to reach a backtest.
import); maps and matrices;
request.security() inside a function, inside a loop when it reads the loop's variables, or with a
symbol or timeframe that changes from bar to bar; strategies. A script that uses them doesn't compile,
with an error that names the construct.close[5000]), as on TradingView; a
chain of more than 180 ?: or unary operators, a sum of more than about 200 terms, or 99 nested if
is refused (split it into variables); a script whose functions call each other so much that its checks
would take too long is refused with Script too complex to analyze.str.repeat with a large count) stops with String is too long.high or hl2); a source input you pick in the Inputs tab is the series the preview
reads.request.security() can read
any of them.