LootX

Синтаксис і типи

нове Оновлено 30 вересня 2026 р. Ця сторінка у PDF

Як влаштований LootScript: виконання по барах, оголошення скрипта, п’ять форм присвоєння, типи й кваліфікатори, na, історія x[n], оператори, умови, switch, цикли, функції й власні типи.

Ця сторінка — короткий опис мови: як виконується скрипт, як оголошувати змінні, які є типи, що таке na, як читати минулі бари, як писати умови, цикли й функції. Всі приклади — повні робочі скрипти: їх можна вставити в редактор і додати на графік.

Як виконується скрипт

Усе, що написане на верхньому рівні файлу, виконується один раз на кожен бар — від найстарішого завантаженого до поточного, рядок за рядком. Тому змінна в LootScript зберігає не одне число, а значення на кожному барі, і до минулих значень можна звертатися.

Loot
indicator("Тело свечи")

body = close - open          // считается заново на каждом баре
plot(body, "Тело", style = plot.style_columns)

На поточному, ще не закритому барі скрипт перераховується з кожним новим тіком, починаючи зі стану, яке було на закритті попереднього бара. Закриті бари при цьому не перераховуються.

Оголошення

Перша інструкція скрипта — рівно одне оголошення: indicator(...), strategy(...) або library(...). Вище нього можуть стояти тільки коментарі і необов’язковий рядок версії #version 1. Без оголошення скрипт не скомпілюється з помилкою «Немає оголошення скрипта — почніть з indicator(“Назва”)».

Loot
#version 1
// Комментарии и строка версии могут стоять выше объявления.
indicator("Размах бара", shortTitle = "Размах", overlay = false)

plot(high - low, "Размах", style = plot.style_histogram)

Головні параметри індикатора: title — назва в списку скриптів, shortTitle — коротке ім’я для легенди, overlay — малювати поверх ціни (true) або в окремій панелі (false, за замовчуванням). Параметри стратегії описані на сторінці Стратегии и тестер.

Змінні і присвоєння

Форма Що робить
x = выражение Оголошує змінну. На кожному барі вона обчислюється заново.
x := выражение Присвоює нове значення вже оголошеній змінній. Тип має співпадати.
var x = выражение Оголошує змінну один раз, на першому барі. Значення переходить на наступні бари.
varip x = выражение Як var, але значення зберігається й між тіками поточного бара.
[a, b, c] = функция(...) Розкладає кілька результатів функції по змінних.

Для зміни вже оголошеної змінної є й короткі форми: +=, -=, *=, /=, %=. Тип можна вказати явно: float level = 0. Імена вбудованих рядів і просторів (close, volume, ta та інших) зайняті — назвати так свою змінну не можна.

Головна відмінність від звичних мов — звичайна змінна не накопичує значення між барами. Для лічильників і сум потрібен var:

Loot
indicator("Счётчик зелёных свечей")

var greens = 0          // объявляется один раз и переживает переход к следующему бару
if close > open {
    greens += 1
}

today = 0               // а эта переменная равна 0 на каждом новом баре
today := today + 1      // поэтому здесь всегда 1

plot(greens, "Зелёных с начала истории")

varip потрібен рідко — наприклад, щоб рахувати тіки всередині бара. На історії тиків немає, тому таке значення на минулих барах буде іншим, ніж було вживу. Якщо значення varip потрапляє на графік, редактор попередить про перерисовку.

Типи

Тип Що зберігає Приклад
int ціле число 14, 1_000_000, 0xFF
float дробове число 2.5, .5, 1e-9
bool істина або неправда true, false
string текст "BTC", 'BTC'
color колір з прозорістю #FF9800, #FF980080, color.teal

Є й складні типи: масиви array<float>, словники map<string, float>, матриці matrix<float>, а також ваші власні типи й перерахування (див. нижче) і графічні об’єкти line, box, label, table.

Правила, через які найчастіше спотикаються:

  • Тип фіксується при оголошенні. Після x = 1 присвоїти x := 2.5 не можна: x — ціле. Пишіть x = 1.0 або float x = 1.
  • Ціле перетворюється в дробове само, назад — тільки явно: math.round, math.floor, math.ceil, math.trunc.
  • Ділення цілих — ціле: 7 / 2 рівно 3. Потрібна дробь — зробіть одне з чисел дробовим: 7.0 / 2.
  • Піднесення до степеня ^ завжди дає дробове число: 2 ^ 3 рівно 8.0.
  • Рядок не можна додати до числа. "Цена: " + close не скомпілюється — пишіть "Цена: " + str.tostring(close).
  • Умова — тільки bool. if volume { … } — помилка; пишіть if volume > 0 { … }.

Кваліфікатори: наскільки значення постійне

Окрім типу в кожного значення є кваліфікатор — наскільки воно постійне під час роботи скрипта. Від слабкого до сильного:

Кваліфікатор Коли відоме значення Приклад
const вже під час компіляції 14, "EMA"
input після зчитування налаштувань, далі не змінюється input.int(14, "Период")
simple при запуску, далі не змінюється крок ціни інструмента
series може змінюватися на кожному барі close, bar_index

На практиці це важливо в одному місці: періоди функцій ta.* повинні бути постійними — літералом або налаштуванням. Інакше функціям довелося б перебудовувати свій стан на кожному барі.

Loot
indicator("Период из настроек")

len = input.int(14, "Период", minval = 2)
plot(ta.rsi(close, len), "RSI")

// ta.rsi(close, bar_index) не скомпилируется:
// «length» в «ta.rsi» требует значение не слабее input, а передано series

na — відсутнє значення

na означає «значення відсутнє»: не вистачає історії для розрахунку, біржа не віддає показник, у даних дірка. na є в будь-якому типі.

  • Арифметика з na дає na: na + 1 — це na.
  • Будь-яке порівняння з na хибне, тому if x > 0 при x = na не виконається.
  • Перевіряйте відсутність тільки через na(x). Запис x == na компілятор відхилить з помилкою «Сравнение с na всегда ложно — используйте na(x)».
  • nz(x) підставляє 0 замість na, nz(x, v) — значення v. Те саме коротше: x ?? v.
  • na на графіку — розрив лінії, а не нуль.
Loot
indicator("Средняя без пустого начала", overlay = true)

avg = ta.sma(close, 50)             // на первых 49 барах — na

line1 = na(avg) ? close : avg       // проверка через na(x)
line2 = avg ?? close                // то же короче

plot(line2, "Средняя или цена", color = color.orange)

Історія: x[n]

x[n] — значення x на барі, який був n барів тому; x[0] — поточне. Працює з будь-яким рядом, у тому числі з вашими змінними.

Loot
indicator("Наклон средней")

ma    = ta.ema(close, 20)
slope = ma - ma[1]                  // изменение за один бар

plot(slope, "Наклон", style = plot.style_histogram,
     color = slope >= 0 ? color.teal : color.red)
  • Якщо n більше числа барів до початку історії, результат — na, а не помилка.
  • n може змінюватися від бара до бара: close[len] при змінному len допустимо.
  • Негативний індекс — помилка: заглядати в майбутні бари не можна.
  • Налаштовувати глибину історії не потрібно: скрипту доступна вся історія, завантажена на графік.

Оператори

Від найвищого пріоритету до найнижчого:

Пріоритет Оператори
1 x[n], вызов f(…), доступ через точку a.b
2 ^ — степень, вычисляется справа налево
3 унарні -, +, not
4 *, /, %
5 +, -
6 <, >, <=, >=
7 ==, !=
8 and
9 or
10 ?? — заміна na
11 ? : — умовний вираз
  • Порівняння не ланцюжаться: замість a < b < c пишіть a < b and b < c.
  • and і or не обчислюють праву частину, якщо відповідь уже ясна по лівій.
  • Степінь вище унарного мінуса: -2 ^ 2 рівне -4. Потрібно 4 — пишіть (-2) ^ 2.
  • Дробові числа порівнюйте з допуском: math.approx(a, b), бо 0.1 + 0.2 == 0.3 хибне.

Умови

Блоки завжди в фігурних дужках. if буває інструкцією і виразом; для простого вибору з двох є ? :.

Loot
indicator("Направление бара")

dir = 0
if close > open {
    dir := 1
} else if close < open {
    dir := -1
}

// if как выражение: обе ветки обязательны
bodySize = if close >= open { close - open } else { open - close }

// условный оператор для простых случаев
barColor = dir > 0 ? color.teal : color.red

plot(bodySize, "Тело", style = plot.style_columns, color = barColor)

switch

switch вибирає першу підходящу гілку. Форма з об’єктом порівнює його зі значеннями гілок, форма без об’єкта перевіряє умови по черзі. Гілка => без умови — гілка за замовчуванням. Провалювання в наступну гілку немає. Коли switch повертає значення, гілка за замовчуванням обов’язкова.

Loot
indicator("Средняя на выбор", overlay = true)

kind = input.string("EMA", "Тип средней", options = ["EMA", "SMA", "WMA"])

ma = switch kind {
    "EMA" => ta.ema(close, 20)
    "SMA" => ta.sma(close, 20)
    =>       ta.wma(close, 20)
}

zone = switch {
    close > ma * 1.02 => 1
    close < ma * 0.98 => -1
    =>                   0
}

plot(ma, "Средняя", color = zone == 1 ? color.teal : zone == -1 ? color.red : color.gray)

Цикли

for i in a .. b перебирає числа від a включно до b не включно. Крок задається словом by, у тому числі від’ємний. Змінна циклу існує тільки всередині циклу і не змінюється в тілі.

Loot
indicator("Зелёные свечи за N баров")

n = input.int(10, "Сколько баров", minval = 1, maxval = 200)

greens = 0
for i in 0 .. n {               // i = 0, 1, …, n − 1
    if close[i] > open[i] {
        greens += 1
    }
}

plot(greens, "Зелёных", style = plot.style_columns)
Loot
indicator("Виды циклов")

total = 0
for i in 0 .. 10 by 2 {         // 0, 2, 4, 6, 8
    total += i
}
for i in 10 .. 0 by -1 {        // 10, 9, …, 1
    if i % 3 == 0 {
        continue                // сразу к следующему шагу
    }
    total += i
}

var closes = array.new<float>(0)
closes.push(close)
if closes.size() > 20 {
    closes.shift()
}
sum = 0.0
for v in closes {               // по элементам массива; for [i, v] in … — с индексом
    sum += v
}

k = 0
while k < 100 {
    k += 7
    if k > 50 {
        break                   // выход из цикла
    }
}

plot(sum / closes.size(), "Средняя из массива")

Бескінечний цикл термінал не зависне: у скрипта є бюджет операцій на бар і ліміт часу. Перевищивши їх, скрипт зупиниться з повідомленням «Скрипт исчерпал бюджет операций на бар — упростите цикл» або «Скрипт превысил лимит времени на проход».

Функції

Функція оголошується словом func. Коротка форма — вираз після =>, довга — тіло в дужках з return. Типи параметрів можна не вказувати — вони виводяться з викликів, а у параметрів можуть бути значення за замовчуванням. Аргументи передаються по порядку або по імені.

Loot
indicator("Z-оценка объёма")

func barRange(h, l) => h - l

func zscore(series float src, input int len) => float {
    m = ta.sma(src, len)
    s = ta.stdev(src, len)
    return s == 0 ? na : (src - m) / s
}

func scaled(x, k = 2.0) => x * k

z = zscore(volume, 50)
plot(z, "Z объёма", style = plot.style_columns, color = z > 2 ? color.orange : color.gray)
plot(scaled(barRange(high, low), k = 0.5), "Полразмаха")
  • Рекурсії немає. Функція не може викликати саму себе, ні прямо, ні через іншу функцію. Повторення пишеться циклом.
  • Стан — у кожного виклику свій. Якщо всередині функції є ta.* або var, два виклики однієї функції ведуть незалежні розрахунки:
Loot
indicator("Два вызова одной функции", overlay = true)

func smooth(src, len) => ta.ema(src, len)

fast = smooth(close, 10)        // своя средняя
slow = smooth(close, 30)        // другая, независимая средняя

plot(fast, "Быстрая", color = color.teal)
plot(slow, "Медленная", color = color.orange)

Функції, потрібні в кількох скриптах, виносять у бібліотеку: скрипт з оголошенням library("Имя", 1), перед функціями — слово export, в іншому скрипті — import Имя/1 as имя. Бібліотека береться з вашої папки скриптів.

Кілька результатів

Деякі функції повертають одразу кілька рядів: ta.bb, ta.macd, ta.kc, ta.dmi, ta.supertrend та інші. Їх результат розкладається по змінних у квадратних дужках; число імен має збігатися з числом результатів.

Loot
indicator("Полосы Боллинджера", overlay = true)

[basis, upper, lower] = ta.bb(close, 20, 2.0)

plot(basis, "Середина", color = color.gray)
plot(upper, "Верх", color = color.teal)
plot(lower, "Низ", color = color.teal)

Власні типи та перерахування

type збирає кілька полів в одну структуру. Об’єкт створюється через Имя.new(...), поля читаються і змінюються через крапку.

Loot
indicator("Последний локальный максимум", overlay = true)

type Swing {
    int   barIndex
    float price
}

var Swing last = Swing.new(barIndex = 0, price = high)

ph = ta.pivothigh(high, 5, 5)
if not na(ph) {
    last.barIndex := bar_index - 5
    last.price := ph
}

plot(last.price, "Максимум", style = plot.style_stepline, color = color.orange)

enum — закритий список варіантів із підписами. Зручніше рядками: опечатка в імені варіанта — помилка компіляції, а не тихо неспрацювавша умова. Разом з input.enum перерахування перетворюється в випадаючий список у налаштуваннях — див. Настройки и отрисовка.

Loot
indicator("Режим рынка")

enum Regime {
    trend = "Тренд"
    flat  = "Флэт"
}

regime = math.abs(close - close[20]) > ta.atr(14) * 3 ? Regime.trend : Regime.flat

plot(regime == Regime.trend ? 1 : 0, "Тренд", style = plot.style_stepline)

Функції ta.* всередині умов

Функції на кшталт ta.ema, ta.rsi або ta.atr пам’ятають свій стан з минулого бара. Якби такий виклик виконувався тільки на частині барів — всередині if або однієї гілки ? : — його розрахунок пропускав би бари й тихо давав некоректні числа.

LootScript цього не допускає: компілятор сам виносить кожен виклик ta.* з умови і виконує його на кожному барі, а умова лише вибирає, використовувати чи результат. Тож такий код рахує RSI правильно:

Loot
indicator("RSI только на зелёных барах")

r = close > open ? ta.rsi(close, 14) : na

plot(r, "RSI", style = plot.style_circles)

Винести виклик не можна, лише якщо його аргумент сам народжується всередині гілки. Тоді компілятор не вгадає й повідомить: «Аргумент «len» нельзя вычислить вне ветки — вынесите вызов ta.* на верхний уровень». Рішення — порахувати аргумент до умови:

Loot
indicator("Аргумент до условия")

// Так нельзя — len объявлена внутри ветки:
// if close > open {
//     len = 10
//     e = ta.ema(close, len)
// }

len = 10
e = ta.ema(close, len)

plot(close > open ? e : na, "EMA на зелёных барах", style = plot.style_circles)

Коментарі та перенесення рядків

  • // — коментар до кінця рядка, /* … */ — блочний, блоки можна вкладати один в одного.
  • Інструкція закінчується з кінцем рядка, крапка з комою не потрібна.
  • Довгий вираз продовжується на наступному рядку, якщо рядок обірвано всередині дужок, закінчується оператором або наступний рядок починається з оператора, ? або :.
Loot
indicator("Перенос строк")

typical = high
        + low
        + close

signal = close > open
    ? typical / 3
    : na

plot(signal, "Типичная цена на зелёных барах", style = plot.style_circles)

Далі

FAQ

Чому мій лічильник у скрипті завжди дорівнює 1?
Звичайна змінна оголошується заново на кожному барі. Щоб значення переходило з бара на бар, оголосіть її через var: var count = 0.
Як перевірити, що значення відсутнє?
Тільки функцією na(x). Запис x == na компілятор відхиляє: будь-яке порівняння з na хибне.
Чи можна викликати ta.rsi або ta.ema всередині if?
Так. Компілятор виконує такі виклики на кожному барі, а умова лише обирає, чи використовувати результат, тому розрахунок не збивається.
Чому період зі змінної не підходить для ta.sma?
Період функцій ta.* має бути постійним: числом або налаштуванням input.int. Значення, яке змінюється від бара до бара, компілятор не прийме.