TRA Script
Язык для собственных индикаторов и торговых стратегий в Trade Lab Pro. Скрипт выполняется последовательно на каждой свече и может обращаться к истории значений, рисовать на графике и моделировать сделки на истории.
Справочник описывает возможности текущего движка. Статус совместимости каждой функции доступен в каталоге API; наличие имени в каталоге само по себе не означает завершённую совместимость.
TRA Script
A language for custom indicators and trading strategies in Trade Lab Pro. Scripts execute bar by bar, access historical values, draw on the chart and simulate historical trades.
This documentation describes the current engine. The API catalog records compatibility for each function; a catalog entry alone does not imply complete compatibility.
Правила написания TRA Script 2
Документация открыта без регистрации. Начните с небольшого индикатора ниже, затем используйте разделы и каталог функций. Примеры относятся к текущему движку TRA Script 2.
- Заголовок. Укажите
//@tra=2в первой строке. Объявите один индикатор черезindicator("Название", overlay=true). Для отдельной панели используйтеoverlay=false. - Имена и значения. Используйте понятные имена из латинских букв, цифр и подчёркивания, начиная с буквы или подчёркивания. Регистр важен:
basisиBasis— разные имена. Дробные числа пишутся с точкой; строки — в кавычках. Логические значения:trueиfalse. Комментарий начинается с//. - Объявление и изменение.
basis = ta.ema(close, 20)объявляет переменную.basis := closeменяет уже объявленную. Тип можно указать явно:float,int,bool,string,color.varсохраняет состояние между свечами. - Порядок расчёта. Код выполняется сверху вниз на каждой свече.
close— текущее закрытие,close[1]— предыдущее. В начале истории значения могут отсутствовать: проверяйтеna(value)или используйтеnz(value, replacement). Отрицательный индекс истории не используйте. - Выражения. Арифметика:
+ - * / %; сравнения:> >= < <= == !=; логика:and or not. Условный выбор:condition ? yes : no. Скобки задают порядок операций. - Блоки и функции. Вложенный блок
if/else, цикла или функции выделяйте одинаковым отступом, например четырьмя пробелами. Функция объявляется через=>и возвращает последнее выражение. Примеры циклов и коллекций приведены ниже. - Параметры и отрисовка. Используйте
input.*для настроек пользователя. Значения выводятся черезplot(), метки — черезplotshape()иplotchar(), уровни — черезhline(). Имена аргументов пишите точно, напримерtitle=иcolor=. - Проверка. В редакторе нажмите «Проверить», исправьте указанные ошибки и сохраните скрипт. Сверьте значения и рисунки на нескольких свечах. При импорте Pine прочитайте отчёт: неподдержанная конструкция требует адаптации, а наличие имени в каталоге не гарантирует полного переноса.
- Header. Put
//@tra=2on the first line. Declare one indicator usingindicator("Name", overlay=true). Useoverlay=falsefor a separate pane. - Names and values. Use Latin letters, digits and underscores, starting with a letter or underscore. Names are case-sensitive. Decimal numbers use a dot; strings use quotes. Boolean values are
trueandfalse. Comments start with//. - Declare and update.
basis = ta.ema(close, 20)declares a variable;basis := closeupdates an existing one. Optional types includefloat,int,bool,stringandcolor.varretains state between bars. - Execution order. Code runs top to bottom on each bar.
closeis the current close;close[1]is the previous close. Initial history may be missing: checkna(value)or usenz(value, replacement). Do not use negative history offsets. - Expressions. Arithmetic:
+ - * / %; comparison:> >= < <= == !=; logic:and or not. Conditional choice:condition ? yes : no. Parentheses control operation order. - Blocks and functions. Indent nested
if/else, loops and function bodies consistently, for example with four spaces. Functions use=>and return the last expression. Loop and collection examples appear below. - Inputs and visuals.
input.*creates user settings. Useplot()for series,plotshape()andplotchar()for markers, andhline()for levels. Spell named arguments exactly, for exampletitle=andcolor=. - Validation. Click Validate in the editor, fix reported errors, and save. Compare values and visuals on multiple bars. Read the Pine import report: unsupported constructs need adaptation, and a catalog entry alone does not guarantee full compatibility.
Полный пример: EMA и сигнал пересечения
//@tra=2
indicator("EMA crossing", overlay=true)
length = input.int(20, "Period", minval=1)
basis = ta.ema(close, length)
crossed = ta.crossover(close, basis)
plot(basis, title="EMA", color=color.aqua, linewidth=2)
plotshape(crossed, title="Crossing", style=shape.triangleup, location=location.belowbar, color=color.lime)
alertcondition(crossed, title="EMA crossing", message="Close crossed above EMA")
Period появится в настройках. EMA рассчитывается по закрытию каждой свечи. Треугольник и уведомление возникают при пересечении цены снизу вверх. Измените название, период и цвета, затем проверьте результат на графике.
Первый индикатор
Откройте «Создать скрипт», введите название и код, затем нажмите «Проверить». После успешной проверки сохраните скрипт — он появится в библиотеке и на графике.
//@tra=2
indicator("My EMA", overlay=true)
length = input.int(20, "Length", minval=1)
basis = ta.ema(close, length)
plot(basis, title="EMA", color=color.aqua, linewidth=2)indicator() создаёт индикатор. overlay=true размещает его поверх цены, overlay=false — в отдельной панели. strategy() создаёт стратегию с отчётом тестера.
Свечи и состояние
open, high, low, close, volume относятся к текущей свече. close[1] — закрытие предыдущей свечи. bar_index — номер свечи, начиная с нуля. Обычное объявление пересчитывается на каждой свече; var инициализируется один раз и сохраняет изменения.
var float total = 0.0
total += volume
float buffer = 0.0
buffer := nz(buffer[1]) * 0.9 + (close - open)
plot(buffer)Знак = объявляет переменную, := изменяет уже объявленную. na означает отсутствующее значение; проверяйте его через na(value). nz(value, replacement) заменяет отсутствующее значение. История не должна обращаться к будущим свечам.
Параметры
input.int, input.float, input.bool, input.string, input.color, input.symbol и input.source создают настройки. Укажите понятное название, допустимые границы, шаг, группу и подсказку. Шестерёнка на графике открывает параметры; изменения применяются после сохранения.
period = input.int(34, "Period", minval=2, maxval=500)
memory = input.float(0.90, "Memory", minval=0.5, maxval=0.99, step=0.01)
show = input.bool(true, "Show signal")
mode = input.string("Fast", "Mode", options=["Fast", "Slow"])
Функции, условия и циклы
Отступы определяют блоки. Поддерживаются if/else, for, while, break и continue. Пользовательская функция объявляется через => и возвращает последнее выражение блока. Каждый отдельный вызов имеет собственную историю локальных переменных.
pressure(float source, float memory) =>
float result = 0.0
result := nz(result[1]) * memory + source
result
up = pressure(math.max(close - open, 0), 0.9)
down = pressure(math.max(open - close, 0), 0.9)
plot(up - down)
[basis, upper, lower] = ta.bb(close, 20, 2.0)
Инструкции, циклы и серийные расчёты.
//@tra=2
indicator("Inline function")
normalise(source, length) => mean=ta.sma(source,length), deviation=ta.stdev(source,length), (source-mean)/deviation
plot(normalise(close,20), "Deviation")
Функции объявляются в глобальной области. Одно имя может иметь несколько вариантов с разным числом обязательных аргументов или их типами: int, float, bool, string, color, коллекции и собственные типы. Целое число может передаваться в float; обратное преобразование требует int(). Необязательные параметры и переименование аргументов не различают перегрузки. Именованные аргументы учитываются при выборе варианта. Метод требует тип первого аргумента и вызывается через объект; метод другого типа не подменяет встроенную операцию массива. Каждый вариант и отдельный вызов сохраняют свою историю. Рекурсивные вызовы запрещены.
//@tra=2
indicator("Function variants")
adjust(int value) => value + 10
adjust(float value) => value + 20.0
plot(adjust(1), "Integer")
plot(adjust(1.0), "Float")
plot(adjust(close), "Price")
Функция читает переменные глобальной области, а её аргументы и локальные переменные изолированы от вызывающей функции. Совпадение имени аргумента с глобальной переменной не меняет глобальное значение. Аргументы и глобальные скалярные переменные нельзя переназначать внутри функции. Содержимое переданного массива или поля переданного объекта можно изменять: они передаются по ссылке.
Явные квалификаторы const, simple и series проверяются в объявлениях и аргументах пользовательских функций. const принимает только значения, доступные при компиляции, и запрещает переназначение. simple принимает const, input и simple, а series допускает изменение по свечам. Неквалифицированный аргумент наследует свойство переданного значения; аргумент с указанным типом по умолчанию получает series. Квалификатор результата передаётся последующим вызовам. Для ссылочных типов квалификатор всегда series. Исходные аргументы функций должны быть const; при исходном na нужен тип. Полный статический анализ всех ветвей и автоматическое понижение квалификатора типизированных аргументов по требованиям встроенных функций ещё разрабатываются.
//@tra=2
indicator("Qualifiers")
const int base = 14
add(const int value) => value + 1
selected(simple int value) => value
length = input.int(20, "Length", minval=1)
plot(add(base), "Constant")
plot(selected(length), "Input")
Массивы, карты и матрицы
Массив хранит упорядоченные значения.
values = array.from(1.0, 2.0, 3.0)
window = values.slice(1, 3)
window.set(-1, 4.0)
plot(values.get(2)) // 4
var map<string, float> levels = map.new<string, float>()
levels.put("last", close)
plot(levels.get("last"))
m = matrix.new<float>(2, 2, 0.0)
m.set(0, 0, 1.0)
m.set(1, 1, 1.0)
plot(m.det()) // 1
Карта связывает уникальные ключи со значениями.
Свои типы, методы и перечисления
type задаёт поля объекта.
type Counter
int count = 0
method increment(Counter this, int step = 1) =>
this.count += step
this.count
var Counter counter = Counter.new()
plot(counter.increment())
enum Direction
longSide = "Long"
shortSide = "Short"
direction = input.enum(Direction.longSide, "Direction")
Даты и периоды
time — время открытия свечи в миллисекундах Unix.
timestamp использует часовой пояс биржи.
//@tra=2
indicator("Trading time", overlay=true)
opening = timestamp("Europe/Moscow", 2026, 1, 1, 10, 0)
newDay = timeframe.change("1D")
plotshape(newDay and time >= opening, style=shape.flag, color=color.aqua)
plot(hour(time, "UTC"), "UTC hour", display=display.data_window)
Форматирование времени и часовых поясов.
//@tra=2
indicator("Time labels", overlay=true)
var panel=table.new(position.top_right,2,2,bgcolor=color.black)
if barstate.islast
table.cell(panel,0,0,"Exchange",text_color=color.white)
table.cell(panel,1,0,str.format_time(time,"dd.MM.yyyy HH:mm z"),text_color=color.aqua)
table.cell(panel,0,1,"UTC",text_color=color.white)
table.cell(panel,1,1,str.format_time(time,"yyyy-MM-dd HH:mm:ss.SSS Z","UTC"),text_color=color.white)
Объём и VWAP
Встроенные объёмные серии рассчитываются по OHLCV.
VWAP поддерживает условия сброса и границы отклонения.
//@tra=2
indicator("VWAP bands", overlay=true)
[average, upper, lower] = ta.vwap(hlc3, timeframe.change("1D"), 2)
center = plot(average, "VWAP", color=color.yellow)
top = plot(upper, "Upper", color=color.aqua)
bottom = plot(lower, "Lower", color=color.aqua)
fill(top, bottom, color.new(color.aqua, 90))
Строки
Строки заключаются в кавычки.
//@tra=2
indicator("Text example", overlay=true)
if barstate.islast
message = str.repeat("[TRA]", 2, " · ")
label.new(bar_index, high, message, textcolor=color.white)
log.info, log.warning и log.error записывают сообщения в журнал редактора. Аргументы после текста подставляются в {0}, {1} и следующие поля. Журнал показывает уровень, строку исходного кода и время свечи. Хранятся последние 1000 сообщений; текст одного сообщения ограничен 4096 символами.
str.tostring преобразует числа, логические значения, массивы и матрицы в текст. В числовой маске 0 требует цифру, # разрешает убрать лишние нули, запятая разделяет разряды, а % в конце умножает значение на 100. format.mintick округляет по шагу цены инструмента; format.percent добавляет знак процента без умножения. str.format поддерживает нумерованные заполнители, числовые маски, integer/currency/percent, а также даты и время в UTC. Апострофы выделяют буквальный текст; два апострофа дают один. Та же логика применяется к форматированным сообщениям log.*.
//@tra=2
indicator("Formatted values", overlay=true)
var panel=table.new(position.bottom_right,1,2)
if barstate.islast
table.cell(panel,0,0,str.format("Price: {0,number,0.00}",close))
table.cell(panel,0,1,str.format("Volume: {0}",str.tostring(volume,format.volume)))
Отрисовка и окно данных
plot() рисует серии, hline() — уровни, plotshape() — сигналы. bgcolor() задаёт цвет фона свечи, а box, line и label создают изменяемые объекты. color.new(color, transparency) использует прозрачность от 0 до 100. Служебные серии с display.data_window видны в окне данных и не меняют шкалу графика.
var box area = na
if bar_index == 10
area := box.new(bar_index, high, bar_index + 10, low,
bgcolor=color.new(color.blue, 90))
if not na(area)
box.set_right(area, bar_index)
plot(volume, "Volume data", display=display.data_window)
plotshape рисует выбранную фигуру при выполнении условия.
Текст таблиц, подписей и прямоугольных областей может иметь числовой размер шрифта, стандартное или моноширинное семейство и полужирное либо курсивное начертание. text.format_bold + text.format_italic объединяет оба стиля, text.format_none сбрасывает их. Начертание меняется также через label.set_text_formatting, box.set_text_formatting и table.cell_set_text_formatting. Для box параметры text_halign и text_valign задают положение текста, text.wrap_auto переносит текст по ширине области, а text.wrap_none оставляет исходные строки.
//@tra=2
indicator("Styled text", overlay=true)
var panel=table.new(position.bottom_right,1,1)
if barstate.islast
table.cell(panel,0,0,"TRA Script",text_size=18,
text_font_family=font.family_monospace,
text_formatting=text.format_bold+text.format_italic)
Другие инструменты и таймфреймы
request.security(symbol, timeframe, expression) вычисляет выражение в контексте другого источника. Источник должен быть доступен терминалу. Параметры gaps и lookahead управляют синхронизацией. В Replay внешние данные ограничены доступной свечой, а в обезличенном задании запросы внешних источников запрещены.
proxy = input.symbol("", "Turnover proxy")
symbol = proxy == "" ? syminfo.tickerid : proxy
turnover = request.security(symbol, timeframe.period, volume * hlc3,
gaps=barmerge.gaps_off, lookahead=barmerge.lookahead_off)
Стратегии и тестер
Стратегия описывает правила создания и отмены заявок. Тестер моделирует их на истории выбранного инструмента. Рыночная заявка, созданная после расчёта свечи, по умолчанию исполняется на открытии следующей. Комиссии и проскальзывание задаются в strategy().
//@tra=2
strategy("EMA crossover", overlay=true,
initial_capital=100000,
default_qty_type=strategy.fixed,
default_qty_value=10,
commission_type=strategy.commission.percent,
commission_value=0.05,
slippage=1)
fast = ta.ema(close, input.int(12, "Fast", minval=1))
slow = ta.ema(close, input.int(26, "Slow", minval=1))
if ta.crossover(fast, slow)
strategy.entry("Long", strategy.long)
if ta.crossunder(fast, slow)
strategy.close("Long")
plot(fast, color=color.aqua)
plot(slow, color=color.orange)Внутри исторической свечи тестер использует последовательный путь OHLC.
Чистый результат — сумма результатов закрытых сделок.
strategy.opentrades.* и strategy.closedtrades.* позволяют читать цену и время входа, объём со знаком направления, комиссии и прибыль отдельной сделки. Для закрытых сделок доступны также данные выхода. Нумерация начинается с 0; отсутствующий номер возвращает na. Прибыль учитывает комиссии, процент рассчитывается относительно стоимости входа. strategy.default_entry_qty(fill_price) рассчитывает объём по настройкам стратегии и стоимости одного пункта инструмента.
//@tra=2
strategy("Trade information", overlay=true)
if bar_index % 20 == 0
strategy.entry("Long", strategy.long, comment="Entry")
if bar_index % 20 == 10
strategy.close("Long", comment="Exit")
latest = strategy.closedtrades - 1
plot(strategy.closedtrades.profit(latest), "Trade result",
display=display.data_window)
plot(strategy.closedtrades.commission(latest), "Fees",
display=display.data_window)
Максимальное благоприятное и неблагоприятное движение сделки читается через max_runup и max_drawdown, а доля от стоимости входа — через версии с суффиксом _percent. Это положительные величины без комиссий. Учитываются только цены до выхода: максимум или минимум свечи после закрытия сделки не попадает в расчёт. Частичное закрытие распределяет результат пропорционально закрытому объёму. Эти показатели доступны в таблице сделок и CSV. Общая просадка стратегии учитывает движение цены внутри свечи и сравнивает капитал с предыдущим максимумом реализованного капитала.
//@tra=2
strategy("Trade excursions", overlay=true)
if bar_index % 20 == 0
strategy.entry("Long", strategy.long)
if bar_index % 20 == 10
strategy.close("Long")
latest = strategy.closedtrades - 1
plot(strategy.closedtrades.max_runup(latest), "Favorable",
display=display.data_window)
plot(strategy.closedtrades.max_drawdown(latest), "Adverse",
display=display.data_window)
Импорт Pine
Редактор распознаёт заголовок //@version=5 или //@version=6. Импорт переводит объявление языка в //@tra=2, сохраняя блоки, типы, функции и исходные строки. Неподдержанная функция выдаёт ошибку с номером строки; потерянная логика не заменяется фиктивными значениями.
Официальный справочник Pine v6 · OsEngine
Справочник API и совместимость
Найдите функцию, переменную или константу по имени или выберите раздел. Раскройте запись, чтобы увидеть сигнатуру и статус реализации. Статусы относятся к текущей версии TRA Script.
Статическая система типов ещё развивается: полная проверка квалификаторов const/simple/series, совместимость вложенных типов коллекций пока не завершены. При выборе перегрузок только по квалификаторам вызов может быть неоднозначным. Это не является полной совместимостью системы типов Pine.
Метки поддерживают круг, квадрат, ромб, треугольники, стрелки, кресты, флаг, текст с обводкой и указатели вверх, вниз, в стороны и по углам. style_none выводит только текст; style_label_center центрирует прямоугольную метку. Положение указателя определяет сторону текста относительно координаты. Для yloc.abovebar и yloc.belowbar используется high или low указанной свечи, в том числе при xloc.bar_time. Стили line.style_arrow_left, line.style_arrow_right и line.style_arrow_both рисуют наконечники на концах линии. Размеры текста таблиц/блоков и меток различаются: normal соответствует 14 для таблицы и 12 для метки; huge — 36 и 24. Числовой размер задаётся отдельно. Геометрия рисуется средствами браузера, поэтому пиксельное совпадение шрифтов с другим терминалом не гарантируется.
//@tra=2
indicator("Pointer and arrow", overlay=true)
if barstate.islast
label.new(bar_index - 10, close, "Price", style=label.style_label_left, size=size.normal)
line.new(bar_index - 20, low, bar_index, high, style=line.style_arrow_both)
plot(close, "Price", color=color.blue)
Ограничения выполнения
| Ресурс | Лимит |
|---|---|
| Исходный код | 200 000 |
| Свечи одного расчёта | 25 000 |
| Параметры input | 100 |
| Итерации одного цикла | 10 000 |
| Глубина вызовов функций | 64 |
| Элементы массива | 100 000 |
| Уникальные внешние источники | 40 |
| Данные серверного расчёта | 8 MB |
| Результат серверного расчёта | 16 MB |
| Время одного расчёта | 20 s |
| Пары карты | 50 000 |
| Элементы матрицы | 100 000 |