LuxAlgo. Часть VI: Alert Scripting, язык условий для алертов
В настройках трёх тулкитов LuxAlgo спрятано многострочное текстовое поле. В нём живёт собственный язык: он умеет то, чего не умеет конструктор пользовательских алертов, и умеет описывать не событие, а сюжет из нескольких событий, растянутый на десятки баров. Разбираем язык целиком: словарь, грамматику, побочные эффекты и подводные камни.
Пролог. Язык, который прячется в конце окна настроек
Окно настроек любого тулкита LuxAlgo прокручивается долго: сигналы, оверлеи, оформление, длинный список цветов. В самом низу обнаруживается пустое многострочное поле без подсказки и без примера. На заметки оно не рассчитано: каждая набранная строка разбирается и вычисляется заново на каждом баре графика. Alert Scripting, это отдельный язык описания условий, встроенный в три платных тулкита LuxAlgo (Signals & Overlays®, Price Action Concepts®, Oscillator Matrix®). Задача у языка одна: превратить состояние графика, выраженное словами, в срабатывание алерта TradingView®.
В том же окне рядом живёт Custom Alert Creator (конструктор пользовательских алертов), разобранный в третьей части, и первый разумный вопрос звучит так: зачем текстовое поле, если условие собирается списками. Ответ короткий: конструктор описывает событие, язык описывает сюжет. У языка больше операторов, глубина обращения к истории произвольная, а несколько условий он выстраивает в последовательность, которая ждёт продолжения десятки баров и сбрасывается, если рынок ушёл не туда. Вдобавок он рисует метки, линии и захваченные уровни, то есть отвечает не только «да» или «нет», но и «вот здесь».
Часть V закончилась там, где начинается эта: на конструкторе пользовательских алертов в Oscillator Matrix с его фиксированным числом слотов и потолком по числу шагов. Плейсхолдеры тулкитов, составляющие половину словаря языка, разбирались раньше: структура рынка и блоки в части III, сигналы и оверлеи в части IV, осцилляторы и конфлюэнс в части V. Здесь не объясняется, что такое Smart Trail или смена характера движения (CHoCH), а показывается, как обратиться к ним из текста. Тот же язык встречался во второй части под именем Strategy Scripting, где управлял входами и выходами бэктестера. Часть VII отдана скринерам, где условие задаётся фильтром по колонке.
Порядок глав подчинён одной идее: сначала замкнуть контур обратной связи, потом набирать словарь. В первой главе разбираются три настройки, которых достаточно, чтобы увидеть результат условия глазами и проверять каждый следующий пример руками. Затем идут словари, грамматика операторов, пользовательские плейсхолдеры, последовательности, действия, чужие шаблоны и миграция со старой версии языка. Об источнике стоит сказать честно сразу: документация в нескольких местах противоречит себе самой, расходясь в написании плейсхолдеров, путая имя метода в одном из примеров и повторяя в описании одного знака сравнения формулировку другого. Все такие места отмечены по ходу текста.
Содержание
- Пролог. Язык, который прячется в конце окна настроек
- Глава 1. Контур: поле ввода, подсветка на графике, алерт в TradingView
- Глава 2. Плейсхолдеры рынка, времени и внешних источников
- Глава 3. Три словаря тулкитов: сигналы, структура, осцилляторы
- Глава 4. Операторы: сравнение, логика, пересечение, история
- Глава 5. Пользовательские плейсхолдеры и дисциплина именования
- Глава 6. Последовательности: условие, растянутое во времени
- Глава 7. Действия: что скрипт делает, когда условие истинно
- Глава 8. Готовые шаблоны и чтение чужого кода
- Глава 9. Миграция с v1 на v2
- Эпилог
- Источники
Глава 1. Контур: поле ввода, подсветка на графике, алерт в TradingView
Конструктор пользовательских алертов и его потолок
Alert Scripting, это проприетарный язык, и работает он только внутри трёх названных тулкитов. В открытых индикаторах LuxAlgo и в Library (библиотеке открытых индикаторов) его нет: это не библиотека для Pine Script® и не самостоятельный скрипт, а часть кода тулкита, читающая текст из настроек. Группа настроек с полем ввода лежит в нижней части окна настроек, и в одном экземпляре тулкита живёт ровно один скрипт. Если нужны два независимых условия, придётся добавить на график второй экземпляр того же тулкита.
Отношения языка с конструктором пользовательских алертов не конкурентные, а иерархические. Конструктор остаётся на месте: он удобен, когда условие укладывается в готовые списки, а его результат виден изнутри скрипта как обычный плейсхолдер, о чём подробно во второй главе. Язык берёт на себя всё остальное: сравнения между произвольными величинами, обращение к любому бару истории, отрицание, ветвление через логическое или, последовательности и рисование на графике. Механику самого конструктора пересказывать незачем, она разобрана в третьей части целиком.
Конвейер: от плейсхолдера до уведомления
Устройство языка удобно держать в голове как конвейер из семи звеньев. Плейсхолдеры поставляют данные: цену, объём, время, показания тулкита. Операторы собирают из данных утверждение, которое на каждом баре либо истинно, либо ложно. Пользовательские плейсхолдеры дают утверждению имя, чтобы из имён собирались утверждения покрупнее. Ключевое слово then растягивает утверждение во времени, превращая его в последовательность шагов. Инвалидация сбрасывает недособранную последовательность. Действия навешивают на истинное условие побочный эффект: уведомление, метку, линию, захваченное значение. Наружу результат выходит двумя каналами: подсветкой на графике и вызовом алерта.
{close} > {close[14]}
В этой строке видно почти весь синтаксис. Имя данных всегда стоит в фигурных скобках, и скобки не украшение: без них имя не распознаётся. Число в квадратных скобках, это глубина обращения к истории, то есть сколько баров назад брать значение, поэтому {close[14]} означает закрытие бара четырнадцатибарной давности. Условие целиком читается как «цена сейчас выше, чем была четырнадцать баров назад». Комментарии оформляются двумя косыми чертами: всё после // до конца строки игнорируется, и комментарий ставится как отдельной строкой, так и хвостом после кода.
Порядок вычислений на каждом баре фиксирован, и запомнить его стоит сразу: позже он объяснит несколько неочевидных случаев. Сначала разрешается инвалидация и ручное перемещение по шагам, затем проверяется активный шаг последовательности, и только потом выполняются действия, привязанные к истинным условиям. Физическое расположение строк в поле ввода на этот порядок не влияет.
«Конструктор описывает событие. Язык описывает сюжет: несколько событий, выстроенных в порядок и связанных условием отмены»
Три настройки, которые включают язык
Группа состоит из трёх элементов, и каждый закрывает своё звено контура. Condition Input Field (поле ввода условия) принимает текст, выпадающий список подсветки возвращает результат глазам, переключатель выпускает результат в машину алертов TradingView. Кнопки «проверить» здесь нет, поэтому опечатка в имени плейсхолдера обнаруживается только косвенно: условие не становится истинным ни на одном баре.
Scripted Alert (скриптовый алерт), это переключатель в группе Any alert() Function Call, без которого не работает ничего, связанное с уведомлениями. При выключенном переключателе условие продолжает вычисляться и подсвечиваться на графике, но алерт не сработает никогда, и сообщения об ошибке не будет. Именно сюда стоит смотреть первым делом при жалобе «скрипт не работает»: чаще всего скрипт работает, просто его результату не дали выхода.
Highlight On Chart как встроенный отладчик
Highlight On Chart (подсветка на графике), это самая недооценённая настройка группы и единственный способ отладки, не требующий дописывать в скрипт ничего лишнего. У списка четыре значения: Top, Bottom, Center и None. Любое из первых трёх заставляет тулкит помечать цветным квадратом каждый бар, где итоговое условие оказалось истинным; цвет квадрата по умолчанию синий, а выбранное значение отвечает лишь за высоту, на которой квадрат окажется. Center доступен исключительно в Oscillator Matrix, потому что своя панель с собственной вертикальной шкалой, а значит и середина, есть только у него. Отсюда рабочая привычка: подсветку включают до того, как условие станет сложным, и не выключают, пока квадраты не начнут появляться там, где их ждали.
Четыре шага в диалоге алерта TradingView
Само уведомление создаёт не тулкит, а TradingView, и тулкит выступает лишь источником события. Процедура занимает четыре шага и одинакова для всех трёх тулкитов. Место, на котором чаще всего сбиваются, это второй выпадающий список: в нём нужно выбрать не одно из предустановленных условий тулкита, а строку any alert() function call. Предустановленные условия относятся к встроенным алертам и о скриптовом условии ничего не знают.
Глава 2. Плейсхолдеры рынка, времени и внешних источников
Ряд и триггер: две породы плейсхолдеров
Синтаксис у всех плейсхолдеров одинаковый: имя в фигурных скобках. Различаются они поведением, и это различение важнее любой таблицы главы. Плейсхолдер-ряд возвращает число на каждом баре: его можно сравнить с другим числом, с другим рядом или с самим собой в прошлом. Триггерный плейсхолдер возвращает логическое событие: на этом баре оно либо случилось, либо нет, и никакого числа за ним не стоит. Сравнивать триггер с числом бессмысленно, применять к нему оператор пересечения тоже: пересекаться могут только ряды. Половина ошибок новичка сводится к этому и лечится одним вопросом к имени: «это величина или это происшествие».
Словарь разбит на группы: рыночные данные, время, сессия, дата, внешние источники, конструктор пользовательских алертов, состояние последовательности и по группе на каждый тулкит. Первые шесть работают во всех тулкитах одинаково, тулкитные словари разбираются в следующей главе, состояние последовательности в шестой.
Цена, объём, диапазон
Рыночная группа содержит четыре базовых ряда бара, четыре производных цены, объём и две меры размаха. Производные цены избавляют от арифметики в условии: вместо полусуммы максимума и минимума достаточно взять {hl2}. Различие между {range} и {tr} определяет поведение условий на открытии сессии: первый плейсхолдер, это высота бара, второй, это истинный диапазон, учитывающий гэп относительно предыдущего закрытия.
Время, сессии и абсолютные даты
Временная группа устроена как набор отдельных компонент, а не как одна дата: час, минута, день недели, номер недели и год существуют независимо и сравниваются как обычные числа. Два плейсхолдера требуют осторожности. Первый, {dayofweek}, считает воскресенье первым днём и опирается на время открытия бара, поэтому на ночных сессиях он возвращает значение на единицу меньше календарного торгового дня: условие «только по вторникам» пропустит вечер понедельника, с которого торговый вторник начинается, зато захватит вечер вторника, относящийся уже к торговой среде. Второй, {timeframe}, возвращает таймфрейм графика в минутах и потому позволяет описать условие, которое на 5m и на 1H ведёт себя по-разному. Плейсхолдер {unix_ts} объявлен устаревшим, вместо него используется {time}.
Сессионный плейсхолдер записывается как интервал из двух четырёхзначных времён и истинен на всех барах внутри него. Запись {1430-1645} охватывает промежуток с 14:30 до 16:45. По поведению это скорее фильтр, чем событие: истинным он остаётся весь интервал, поэтому его естественное место, это связка с обычным сравнением через логическое и.
{1430-1645} and {close} > {high[1]}
Плейсхолдер даты описывает не повторяющийся интервал, а точку на оси времени, и записывается по составной схеме: четыре цифры года, месяц, день, разделитель, часы и минуты, затем необязательное смещение относительно UTC. Если смещение опущено, запись понимается как UTC-0. Задача обычно одна: отсечь историю до заданного момента, чтобы условие не срабатывало на давних барах.
{time} >= {2025-01-01T04:00-04:00} and {volume} > {volume[1]}
Отдельного оператора для временного фильтра в языке нет, и он не нужен: условие «только между тринадцатью и пятнадцатью часами» собирается из двух обычных сравнений часа бара.
{hour} >= 13 and {hour} <= 15
Часовой пояс и два исключения из него
В группе настроек есть список Timezone (часовой пояс), сдвигающий разом все временные плейсхолдеры. Значение по умолчанию exchange означает часовой пояс биржи, торгующей открытым символом, а не пояс вашего компьютера. Исключений ровно два: часовой пояс не действует на {time}, потому что метка Unix абсолютна по своей природе, и не действует на плейсхолдер даты, который несёт смещение в самой записи. Именно эта деталь объясняет, почему шаблон нью-йоркской сессии из восьмой главы требует значения UTC-5 и молча промахивается по окну при любом другом.
Внешние плейсхолдеры и мост к конструктору пользовательских алертов
Внешних плейсхолдеров ровно пять, от {external1} до {external5}, и каждый привязывается к серии сторонней программы отдельным выпадающим списком в той же группе настроек. Это единственная дверь, через которую в скрипт попадают данные не от LuxAlgo: чужой индикатор, собственный скрипт на Pine Script, любая серия на графике. Требование одно и обойти его нельзя: индикатор должен быть уже добавлен на график, иначе в списке его не будет. В Strategy Scripting из второй части внешних источников только три, и это одно из немногих реальных различий между двумя воплощениями языка.
Два последних плейсхолдера таблицы снимают ложную дилемму «конструктор или язык». Собранное списками условие доступно из скрипта: {custom_alert_step} отдаёт условия шагов без OR-условия, {custom_alert_or} отдаёт само OR-условие. Всё, что удобнее набрать мышью, попадает в текст одним компактным именем, к которому уже приписывается то, чего в конструкторе не выразить.
Глава 3. Три словаря тулкитов: сигналы, структура, осцилляторы
Соглашения об именах, общие для трёх тулкитов
Суммарный словарь трёх тулкитов насчитывает около ста семидесяти имён, и запоминать его как список бессмысленно. Запоминать нужно восемь элементов, из которых имена собираются: приставки задают сторону, суффиксы задают силу и охват, отдельные частицы отвечают за пересечение, за жизненный цикл области и за момент смены состояния. Когда эти восемь элементов усвоены, таблицы ниже читаются не как перечень, а как комбинаторика, и незнакомое имя угадывается с первой попытки.
Отсюда следует правило, которое пригодится в шестой главе: имя без приставки switch_, это фильтр, имя с приставкой, это триггер. Парный триггер предусмотрен не для каждого состояния, но собрать его вручную можно всегда: состояние истинно сейчас и было ложно баром раньше.
{bullish_smart_trail} and not {bullish_smart_trail[1]}
Signals & Overlays: ряды и события
Словарь Signals & Overlays самый обширный, потому что тулкит показывает больше всего разнородных величин. Кроме цен и линий оверлеев здесь есть закодированный цвет бара, класс ML Classifier (ML-классификатора) от 1 до 4, шесть границ Reversal Zones (зон разворота) от R3 до S3, уровни тейк-профита и стоп-лосса, значение Optimal Sensitivity (оптимальной чувствительности) и четыре процентных показателя панели: Trend Strength (сила тренда), Lux Volatility (волатильность), Squeeze Index (индекс сжатия), Volume Sentiment (настроение по объёму). У Trend Catcher и Trend Tracer есть отдельные ряды направления: 1 вверх, 0 вниз.
Триггерная половина словаря группируется по семействам. Четыре приходится на подтверждающие сигналы, три на контртрендовые, отдельная пара на выходы, по две пары на каждый из четырёх оверлеев (состояние и переключение), плюс положение цены относительно зон разворота и два пороговых события силы тренда относительно 50%. Парные бычьи и медвежьи имена ниже сведены в одну строку: они всегда устроены симметрично.
Price Action Concepts: структура, блоки, уровни
Словарь Price Action Concepts описывает не показания индикаторов, а геометрию. Ряды отдают уровни внутренней и свинговой структуры, объёмы последнего ордер-блока в четырёх разрезах и крайние значения предыдущего дня, недели, месяца и квартала. Особняком стоят {itrend} и {strend}: они кодируют состояние тренда числом, где плюс или минус единица означает CHoCH, а плюс или минус двойка означает слом структуры (BOS). Знак задаёт направление, модуль задаёт тип события.
Триггерная часть словаря богаче событиями, чем интерфейс тулкита богат галочками, потому что у каждой области есть полный жизненный цикл. Область появляется, цена в неё входит, находится внутри, выходит, и рано или поздно цена её отрабатывает. Все стадии выражены отдельными именами, поэтому выразимо и условие «цена вошла в блок и вышла из него, не отработав его».
Oscillator Matrix: осцилляторы, развороты, конфлюэнс
Словарь Oscillator Matrix самый компактный и самый однородный: почти всё здесь измеряется по шкале от 0 до 100. Ряды отдают Money Flow (денежный поток) с двумя его порогами, OverFlow (избыток ликвидности), HyperWave с сигнальной линией и Confluence Meter (измеритель конфлюэнса). Пара рядов конфлюэнса возвращает не процент, а трёхзначный код, где 0 означает отсутствие, 1 слабый конфлюэнс, 2 сильный. Отсюда происходит узнаваемая идиома языка, проверка на равенство двойке.
{bullish_confluence} == 2 and {moneyflow} > {moneyflow[1]}
Три словаря заканчиваются одинаково: {custom_alert_step} и {custom_alert_or} есть в каждом, поэтому мост к конструктору пользовательских алертов доступен в любом тулките. Тулкитные половины словарей при этом не пересекаются: скрипт, обращающийся к Smart Trail, не найдёт этого имени в Price Action Concepts. Отсюда и главная ошибка при работе с готовыми шаблонами из восьмой главы.
Глава 4. Операторы: сравнение, логика, пересечение, история
Словарь без грамматики остаётся списком. Чтобы из плейсхолдеров получилось условие, нужен способ связать их в утверждение, которое на каждом баре оказывается либо истинным, либо ложным. Операторов в языке немного, и они разложены по четырём семействам: сравнение величин, проверка пересечения двух рядов, логическая связка нескольких утверждений и обращение к истории. Три семейства из четырёх ведут себя ровно так, как подсказывает опыт. Четвёртое, логическое, хранит единственную настоящую ловушку языка, и разобрано оно подробнее остальных.
Сравнение шести знаков
Шесть знаков покрывают весь спектр сравнений: >, <, >=, <=, == и !=. Слева и справа от знака стоят величины, сопоставимые как числа: плейсхолдер-ряд, обычное число или другой ряд. Триггерному плейсхолдеру здесь места нет: событие не имеет числового значения, и сравнивать его с числом бессмысленно. Строгое равенство == хорошо на дискретных величинах, где значений мало и все они целые, например {barcolor} == -1 или {bullish_confluence} == 2, и почти бесполезно на цене, где совпадение двух дробных чисел, это лотерея последнего знака.
Одна оговорка о честности источника. В справочнике операторов описание знака <= дословно повторяет описание знака >=: это опечатка страницы, а не особенность языка. Знак работает так, как выглядит.
Пересечения: crossover, crossunder, cross
Три ключевых слова, crossover, crossunder и cross, стоят в справочнике рядом со знаками сравнения, хотя операторами в строгом смысле не являются. Это именованные проверки взаимного положения двух рядов сразу на двух соседних барах. Запись A crossover B означает, что сейчас ряд A выше ряда B, а баром раньше был ниже. crossunder, это то же самое в обратную сторону. cross объединяет оба варианта, и его же можно выразить через произведение разностей: если разность A и B на текущем баре и та же разность на предыдущем имеют разные знаки, произведение отрицательно, а значит, между барами ряды поменялись местами.
Из разложения следуют два практических вывода. Первый: за каждым пересечением спрятан вопрос к предыдущему бару, поэтому меньше двух баров истории ему не хватит, и на самом первом баре графика оно не вычисляется вовсе. Второй: ровное касание пересечением не считается, потому что crossover требует строгого неравенства на предыдущем баре. Если два ряда сошлись в одну точку и разошлись обратно, ключевое слово промолчит.
{close} crossover {open}
{close} > {open} and {close[1]} < {open[1]}
Обе строки подсвечивают одни и те же бары, и проверяется это быстрее, чем доказывается: при включённой подсветке достаточно набрать сначала одну запись, потом другую и сличить результат. Тождество из таблицы перестаёт быть утверждением документации и становится наблюдением.
and, or, not и ловушка приоритета
Связка and держит все части выражения на одном баре: ложна хотя бы одна, ложно и целое. Тот же смысл в конструкторе пользовательских алертов, разобранном в третьей части, набирается иначе: несколько условий получают один и тот же номер шага и потому проверяются вместе. Разница только в цене записи: там на каждое условие уходит отдельный слот с выпадающими списками, здесь хватает одной строки.
{close} > {close[14]} and {hour} >= 13 and {hour} <= 15
Второй пример компактнее и полезнее, потому что описывает знакомую фигуру вообще без тулкитных плейсхолдеров. Два сравнения задают бычий FVG: минимум текущего бара выше максимума позапрошлого, и закрытие прошлого бара тоже выше того же максимума. {high[2]} встречается в строке дважды, и это нормально: обращение к истории, это просто значение, а не одноразовый ресурс.
{low} > {high[2]} and {close[1]} > {high[2]}
С оператором or начинается единственное место языка, где интуиция подводит. Документация формулирует правило так: or имеет приоритет над and, и это противоположно конвенции, к которой привык всякий, кто писал код. Практический смысл правила лучше держать в голове в другой формулировке: строка сначала режется по каждому or на самостоятельные ветви, и дальше каждая ветвь вычисляется сама по себе. Всё, что присоединено через and, принадлежит только своей ветви, а не строке целиком. Пример из документации распадается на две независимые проверки.
{bullish_confirmation+} or {bullish_smart_trail} and not {bullish_smart_trail[1]}
// фактически проверяются две независимые ветви:
// ветвь 1: {bullish_confirmation+}
// ветвь 2: {bullish_smart_trail} and not {bullish_smart_trail[1]}
Ошибка, которую такая строка провоцирует, звучит примерно так: «условие после and фильтрует всю строку». Не фильтрует. Чтобы фильтр действовал и на подтверждающий сигнал, и на состояние Smart Trail, группировкой приходится управлять, и способов для этого два. Первый: продублировать общую часть в каждой ветви, и именно так устроены официальные шаблоны, в которых один и тот же плейсхолдер состояния повторяется дважды. Второй, надёжнее: вынести каждую ветвь в пользовательский плейсхолдер, о котором следующая глава, и собрать итоговую строку из имён, где границы группировки видны глазами.
Оператор not инвертирует следующее за ним условие и потому чаще всего появляется в паре с обращением к истории. Запись not {bullish_smart_trail[1]} читается как «баром раньше состояния не было», и именно из такой пары собирается вручную триггер из фильтра: состояние истинно сейчас и было ложно на предыдущем баре. Это главный способ получить момент смены там, где у тулкита есть только само состояние.
Квадратные скобки: обращение к истории
Запись {ряд[n]} возвращает значение ряда n баров назад, где нуль означает текущий бар, а единица предыдущий. Счёт идёт в барах, а не во времени, и это стоит проговорить: одна и та же глубина [14] на пятнадцатиминутном графике покрывает три с половиной часа, на часовом чуть больше половины суток, а на дневном почти три торговые недели. Скрипт, отлаженный на одном таймфрейме, при переносе на другой сохраняет форму и меняет смысл.
Справочник привязывает оператор к плейсхолдерам-рядам и к пользовательским плейсхолдерам, но примеры самой документации применяют его и к плейсхолдерам состояния, вроде {bullish_smart_trail[1]}, так что практический охват шире формального описания. Ценность оператора в одном: он позволяет спросить «а баром раньше?». Из этого вопроса вырастают и ручные триггеры, и проверки вида «условие держится два бара подряд», о которых речь в следующей главе.
Глава 5. Пользовательские плейсхолдеры и дисциплина именования
Синтаксис определения и повторное использование
Определение занимает отдельную строку и выглядит как присваивание: {имя} = условие. Слева стоит имя в фигурных скобках, справа любое выражение из предыдущей главы. Имя должно быть уникальным в пределах скрипта, а предела на число определений документация не называет. После определения пользовательский плейсхолдер (UDP) ведёт себя как штатный: его сравнивают, комбинируют логическими операторами, вставляют в последовательность и спрашивают о его прошлом через {имя[1]}.
Обращение к истории собственного определения, это главная причина, по которой приём вообще стоит освоить. В примере из документации бычий FVG назван один раз, а вторая строка требует, чтобы он держался два бара подряд. Без имени оба сравнения пришлось бы выписать дважды, со сдвинутыми на бар индексами, и любая правка условия превращалась бы в правку в четырёх местах, одно из которых будет пропущено.
{bull_fvg} = {low} > {high[2]} and {close[1]} > {high[2]}
{bull_fvg} and {bull_fvg[1]}
Разбор сложного условия на части
Источник прямо рекомендует раскладывать сложное условие на именованные части, прежде чем строить из них последовательность, и дело тут не только в читаемости. Второе применение менее очевидно и куда важнее: определение снимает ловушку приоритета из предыдущей главы. Каждая строка с определением вычисляется сама по себе, поэтому границы группировки перестают зависеть от того, как язык разбирает длинную строку с or посередине. Что вы назвали, то и сгруппировано.
{trend_up} = {bullish_smart_trail} and {trend_strength} > 60
{pullback} = {low} < {low[1]} and {close} > {open}
{volume_ok} = {volume} > {volume[1]}
{trend_up} and {pullback} and {volume_ok}
Отсюда простая дисциплина. Имя даётся по смыслу, а не по позиции: {trend_up} читается через месяц, {step2} не читается уже через неделю, потому что порядок шагов к тому времени успевает поменяться. Итоговая строка держится короткой: три имени против девяти сравнений, и это единственное место скрипта, которое обязано читаться как фраза.
Комментарии как способ не потерять мысль
Комментарий начинается с // и живёт до конца строки. Он бывает отдельной строкой перед кодом и хвостом после кода, для языка разницы нет. Привычка, которую стоит завести сразу: сначала выписать сюжет комментариями, по строке на шаг, и только потом заменить каждую строку кодом. Комментарии тогда работают не как пояснение к готовому скрипту, а как план, по которому он пишется.
// цвет бара стал зелёным именно на этом баре
{green_color} = {barcolor} > 0 and not {barcolor[1]} > 0
// цвет бара красный
{red_color} = {barcolor} < 0
{green_color} then {red_color}
@label() = {green_color} // отметка на графике, чтобы видеть первый шаг глазами
Глава 6. Последовательности: условие, растянутое во времени
До этой главы условие описывало один бар: на нём что-то одновременно верно, и этого достаточно для срабатывания. Последовательность меняет масштаб. Она описывает не состояние, а сюжет: сначала случилось одно, потом другое, потом третье, и если по дороге рынок сделал нечто отменяющее, сюжет не состоялся. Конструктор пользовательских алертов тоже умеет шаги, но шаг там собирается из выпадающих списков, а здесь шаг, это полноценное выражение с логикой, историей и пересечениями внутри.
Оператор then и нумерация шагов с нуля
Ключевое слово then делит выражение на шаги: каждый отрезок между двумя then, это один шаг, и внутри шага работает вся грамматика предыдущих глав. Когда очередной шаг оказывается истинным, эстафета переходит к следующему, и проверять его язык начинает уже со следующего бара, а не с того же. Отсюда простая арифметика, которую полезно проделать до написания скрипта: последовательность из трёх шагов не может завершиться быстрее, чем за три бара, а сюжет из шести шагов на часовом графике займёт минимум шесть часов. Как только истинным оказался последний шаг, сюжет считается собранным, а на следующем баре счётчик возвращается к первому шагу.
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open}
Шаги нумеруются с нуля, и эта деталь ломает больше скриптов, чем любая другая особенность языка. В разговоре и в комментариях про «второй шаг» думают как про единицу, и это как раз верно: шаг 1, это второй по счёту. А вот условие {my_sequence.step} == 2, написанное с мыслью о втором шаге, охраняет третий, и скрипт молча работает не так, как задумано. Проверять номера стоит на пальцах, пересчитывая шаги слева направо начиная с нуля.
Последовательность можно оставить безымянной, но тогда к ней не получится обратиться и не получится прикрепить к ней метод, поэтому дальше используется только форма с именем: {my_sequence} = A then B then C. Вторая версия языка сняла ограничение на количество и разрешила несколько последовательностей в одном скрипте, а заодно принесла последовательности в Strategy Scripting, язык бэктестеров, разобранный во второй части. Рекомендация предыдущей главы окупается сразу: три именованных условия и строка сборки читаются как оглавление.
{lower_high} = {high} < {high[1]}
{lower_low} = {low} < {low[1]}
{red_close} = {close} < {open}
{my_sequence} = {lower_high} then {lower_low} then {red_close}
Плейсхолдеры состояния последовательности
Названная последовательность отвечает на два вопроса о себе самой, и оба ответа доступны как обычные ряды, то есть их сравнивают с числами. {my_sequence.step} возвращает номер активного шага, {my_sequence.barssince_step} возвращает число баров, прошедших с момента последней смены шага или инвалидации. Третий плейсхолдер этой группы, {any_active_step}, это триггер, и он допустим только в контексте инвалидации, о котором речь ниже.
Здесь же стоит заметить деталь синтаксиса, на которой легко споткнуться. У плейсхолдеров состояния точка стоит внутри фигурных скобок, {my_sequence.step}, а у методов снаружи, {my_sequence}.invalidate(). Разница не случайна: в первом случае читается значение, во втором вызывается метод у последовательности. И оговорка о честности источника: справочник плейсхолдеров называет триггер {any_active_step}, а руководство по миграции называет его {any_inactive_step}. Написание в документации расходится, так что проверять его надо в интерфейсе.
Встроенная инвалидация через восклицательный знак
Сюжет, растянутый на десяток баров, без условия отмены превращается в вечное ожидание: взведённый шаг будет ждать продолжения хоть неделю, и алерт придёт тогда, когда картина из скрипта уже не имеет отношения к графику. Встроенная инвалидация решает это одним знаком: всё, что стоит после !, это условие сброса. Оно истинно, значит последовательность возвращается на первый шаг, и накопленный прогресс теряется целиком.
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open} ! {close} > {open}
Здесь общий закон вычислений, названный в первой главе, получает практический смысл. Инвалидация всегда разрешается до проверки шага на том же баре, независимо от того, где она физически написана в тексте скрипта. Отсюда следует вывод, неочевидный до первой отладки: одному и тому же бару нельзя одновременно взвести шаг и сбросить последовательность, сброс победит. Если условие очередного шага и условие сброса могут стать истинными на одном баре, шаг не взведётся никогда, и искать причину надо не в порядке строк, а в совместимости самих условий.
«Инвалидация всегда разрешается раньше проверки шага, где бы она ни была написана в тексте скрипта»
Метод invalidate и порядок строк
У той же инвалидации есть вторая форма, метод: {my_sequence}.invalidate() = условие отдельной строкой. Эффект совпадает со встроенной записью, различаются оформление и возможности. Встроенная форма держит весь сюжет в одной строке и хороша, пока строка помещается на экран. Метод отделяет условие сброса от условий шагов и принимает аргумент, которого у знака ! нет. Строку с методом следует размещать выше определения последовательности: язык всё равно разрешит инвалидацию первой, но текст скрипта тогда читается в том же порядке, в каком исполняется.
// метод стоит выше определения: порядок чтения совпадает с порядком исполнения
{my_sequence}.invalidate() = {close} > {open}
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open}
Инвалидация одного шага и инвалидация по длительности
Сброс всей последовательности, это грубый инструмент. Часто отменять надо не сюжет целиком, а конкретную стадию: первый шаг допускает откат, а третий уже нет, потому что после него картина считается сложившейся. Инвалидация конкретного шага записывается двумя равносильными способами. Либо встроенное условие снабжается охраной по номеру шага, либо методу передаётся аргумент step, который принимает и одно число, и список номеров через запятую вида step=1,2,3.
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open} ! {close} > {open} and {my_sequence.step} == 1
{my_sequence}.invalidate(step=1) = {close} > {open}
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open}
Третий вид сброса не про цену, а про терпение. {my_sequence.barssince_step} считает бары, прошедшие с момента, когда текущий шаг начал проверяться, и сравнение этого счётчика с числом ограничивает не сюжет целиком, а ожидание на отдельном шаге: если шаг не дождался продолжения за отведённые ему бары, последовательность возвращается в начало. Границу приходится назначать самому, то есть заранее решать, сколько баров рынку отведено на реакцию. Без такого решения скрипт будет ловить совпадения, разнесённые на сотни баров, и называть их последовательностью.
{my_sequence} = {high} < {high[1]} then {low} < {low[1]} then {close} < {open} ! {my_sequence.barssince_step} > 5
Метод set_step: ручное перемещение по шагам
Сброс, это перемещение на нулевой шаг, то есть частный случай более общего действия. Метод set_step принимает обязательное целое значение и переводит последовательность на указанный шаг. Поддерживаются относительные формы +N и -N, а ниже нуля метод не уходит: отрицательный результат обрезается до нуля, поэтому -1 на первом шаге безопасен и просто ничего не меняет. Как и инвалидация, метод размещается выше определения последовательности.
Практический смысл метода в том, чтобы не выбрасывать сюжет целиком, когда рынок передумал на середине, а откатить его на ту стадию, которой соответствует новое состояние. Несколько строк set_step с разными целями превращают последовательность в подобие автомата состояний: каждое из именованных условий отправляет сюжет туда, где он должен находиться. Отдельно предупредим об опечатке источника: в примере документации метод вызван как .set_value(...), тогда как задокументированное имя, это set_step. В блоке ниже имя исправлено.
{bull} = {close} > {open}
{bear} = {close} < {open}
{bull+} = {close} > {high[1]} and {bull}
{bear+} = {close} < {low[1]} and {bear}
{my_sequence}.set_step(0) = {bull}
{my_sequence}.set_step(1) = {bear}
{my_sequence}.set_step(2) = {bull+}
{my_sequence} = {bull} then {bear} then {bull+} then {bear+}
Глава 7. Действия: что скрипт делает, когда условие истинно
Общая форма действия и привязка к условию
Всё, что скрипт умел до этой главы, сводилось к одному ответу на каждом баре: условие истинно или ложно. Ответ выходил наружу двумя каналами, подсветкой на графике и вызовом алерта, и на этом полномочия языка заканчивались. Действия расширяют их до побочных эффектов. Скрипт может сам составить текст уведомления, поставить на бар метку, провести линию между двумя точками и запомнить число, которое иначе исчезло бы вместе с баром. Форма записи у всех четырёх действий одна: @ключевое_слово(аргументы) = условие. Правая часть со знаком равенства необязательна: если её опустить, действие привяжется к главному условию скрипта, тому самому, которое отвечает за подсветку и за алерт.
Разницу между действием и методом стоит сформулировать одной фразой, потому что синтаксически они похожи. Действие вешается на условие и оставляет след за пределами скрипта: уведомление, метку, линию, опубликованный источник данных. Метод вешается на пользовательский плейсхолдер и переставляет его внутреннее состояние, ничего не рисуя и никого не уведомляя. Оба метода языка, invalidate и set_step, разобраны в предыдущей главе, где они были нужны по смыслу; в сводной таблице ниже они стоят рядом с действиями только ради полноты картины.
Имена аргументов в круглых скобках необязательны. Если имя опущено, значение опознаётся по позиции, и тогда порядок обязан совпасть с сигнатурой до последнего аргумента. Соблазн писать короче велик, но у @label шесть аргументов, четыре из которых представляют собой перечисления с похожими на вид значениями, и запомнить их порядок не в состоянии никто. Разумная привычка: имена ставить всегда, даже когда аргумент один.
@alert и подстановка значений в текст
У действия @alert ровно один аргумент, текст уведомления в кавычках. Если аргумент не задан, телом сообщения становится сам текст условия. На этапе отладки это удобно, потому что уведомление приходит с точной копией сработавшей строки, а в работе неудобно, потому что читать в телефоне выражение из четырёх плейсхолдеров тяжело.
@alert("close is greater than open") = {close} > {open}
Плейсхолдеры внутри строки не остаются буквами. Перед отправкой они подставляются значениями с того бара, на котором сработало условие, и уведомление начинает нести данные, а не только факт срабатывания. Это единственная в языке возможность передать вовне число: цену, объём, номер активного шага, значение осциллятора.
@alert("price is {close}") = {close} > {open}
Напоминание, без которого действие бессмысленно: @alert не отправит ничего, пока в настройках тулкита выключен скриптовый алерт и пока на стороне TradingView не создан алерт с условием any alert() function call. Подсветка на графике от этого не зависит и потому создаёт опасную иллюзию: условие видно глазами, а уведомления не приходят.
@label: шесть аргументов и три перечисления
Метка, это самый подробно настраиваемый элемент языка: @label(y, text, text_color, color, style, size). Вертикальная координата по умолчанию равна {close} в тулкитах, наложенных на ценовой график, и 50 в Oscillator Matrix, у которого своя вертикальная шкала. Текст по умолчанию, это текст условия, и плейсхолдеры в нём подставляются так же, как в уведомлении. Цвет надписи по умолчанию chart.bg_color, цвет подложки chart.fg_color: метка выходит инверсией графика и потому читается и на светлой теме, и на тёмной. Стиль по умолчанию label_down, размер auto.
@label(y={close}, text="Up", text_color="white", color="green", style="label_up", size="small") = {close} > {open}
@line: координаты в барах и в цене
Линия задаётся четырьмя координатами и цветом: @line(x1, y1, x2, y2, color). Вертикальные координаты ведут себя ровно как у метки, с теми же значениями по умолчанию. Горизонтальные допускают две разные записи, и выбор между ними ни на что, кроме читаемости, не влияет. Первый способ, относительное смещение: целое число считается в барах от текущего, отрицательное значение уводит в прошлое, положительное вправо от последнего бара.
@line(x1= -10, y1= {low}, x2= 10, y2= {high}, color= "green") = {close} crossover {close[10]}
Второй способ, абсолютный индекс бара через плейсхолдер {barindex}, к которому применимо обращение к истории. Обе записи ниже дают на графике одну и ту же линию, но вторая читается лучше, когда координаты вычисляются не от текущего бара, а от какого-то события.
@line(x1={barindex[10]}, y1={low}, x2={barindex}, y2={high}, color="green") = {close} crossover {close[10]}
Перечисление цветов общее для трёх аргументов цвета: двух у метки и одного у линии. Из двадцати значений семнадцать, это обычные названия цветов, transparent прячет элемент, не удаляя его из скрипта, а две последние ссылки берут цвета самого графика и подстраивают оформление под тему.
@valuewhen: значение, которое переживает бар
Последнее действие закрывает задачу, которую иначе в языке решить нечем. Плейсхолдеры говорят о текущем баре или о баре с известным номером в прошлом; спросить, каким был максимум на том баре, где случилось пересечение, через квадратные скобки нельзя, потому что номер того бара заранее неизвестен. @valuewhen(source, reference) захватывает значение ряда в момент истинности условия и держит его до следующего срабатывания.
@valuewhen({high}) = {close} crossover {open}
Дальше поведение зависит от второго аргумента, и разница между двумя режимами резче, чем кажется по сигнатуре. Без имени захваченное значение рисуется на графике и вместе с этим публикуется как источник с названием @Valuewhen: его может выбрать любой другой индикатор на том же графике, и скрипт превращается в поставщика данных. С именем значение становится обычным плейсхолдером, доступным в последующих строках, но рисоваться перестаёт.
Практический сюжет, который связывает главу воедино, занимает две строки. Первая захватывает максимум бара с пересечением и даёт этому уровню имя. Вторая ставит метку по захваченному уровню, пока цена держится выше открытия. Сам уровень при этом не рисуется, потому что имя отключило отрисовку, и показывает его именно метка.
@valuewhen({high}, "{cross_high}") = {close} crossover {open}
@label({cross_high}) = {close} > {open}
Одно добавление второй версии языка касается именно этой связки: вертикальные координаты метки и линии стали принимать обращение к истории. Метку можно поставить по цене десятибарной давности, не захватывая её отдельным вызовом, и часть работы @valuewhen становится необязательной там, где смещение известно заранее.
Глава 8. Готовые шаблоны и чтение чужого кода
Как устроена библиотека шаблонов
Отдельная страница документации собирает тридцать три готовых условия, сгруппированных по тулкитам, и предлагает предельно простую процедуру: скопировать строку, вставить в поле ввода условия. Если смотреть на библиотеку так, польза от неё невелика, потому что шаблон описывает чужую идею, чужие пороги и чужой таймфрейм. Полезнее другая рамка. Тридцать три строки, это тридцать три учебных примера, на которых проверяется всё, что разобрано в предыдущих главах, и почти каждая строка содержит хотя бы одну конструкцию, о которую легко споткнуться.
Первое ограничение библиотеки техническое. Шаблон привязан к тулкиту, потому что половина словаря у каждого тулкита своя. Условие для Price Action Concepts, вставленное в поле ввода Signals & Overlays, не найдёт своих плейсхолдеров, и результатом будет не ошибка, а тишина. Второе ограничение тоньше: шаблон подтверждающих сигналов внутри нью-йоркской сессии рассчитан на часовой пояс UTC-5. При любом другом значении окно сдвинется молча, потому что сессионный плейсхолдер вычисляется в том поясе, который выбран в настройках, и никакого предупреждения об этом не будет.
Тридцать три готовых условия по тулкитам
Ниже приведены все три группы в том написании, в котором они опубликованы. Два шаблона в таблицы не поместились, потому что состоят из нескольких строк, и вынесены в отдельные блоки после таблиц.
Три шаблона стоит разобрать построчно, потому что каждый показывает отдельный механизм. Первый, ретест Smart Trail: {bearish_confirmation_any} and {bearish_smart_trail} or {high} crossover {smart_trail_extremity} and {bearish_smart_trail}. Из-за приоритета or строка распадается на два независимых сценария, и оба требуют медвежьего состояния Smart Trail: либо медвежий сигнал внутри этого состояния, либо пробой границы вверх внутри него же. Если бы or связывал слабее, как в большинстве языков программирования, смысл вышел бы другим, а второе упоминание состояния оказалось бы лишним.
Второй, реверсивный сюжет: {confirmation_exits} then {bearish_confirmation_any} then {barcolor} == -1. Здесь три шага, поэтому условие не может завершиться быстрее, чем за три бара: сначала сигнал выхода, потом на любом последующем баре медвежий подтверждающий сигнал, потом красный бар. Инвалидации у шаблона нет, то есть сюжет живёт неограниченно долго, и первым же улучшением была бы граница по длительности.
Третий, пробой ключевого уровня. Пользовательский плейсхолдер применён здесь ровно так, как советует глава о них: четыре имени CHoCH сворачиваются в одно обобщённое, после чего итоговая строка сравнивает цену с максимумом предыдущего дня и остаётся читаемой. Именованные условия встречаются в библиотеке ещё один раз, в соседнем многострочном шаблоне, где две ветви сюжета названы по отдельности, а последняя строка соединяет их через or.
{bullish} = {bullish_confirmation_any} and {bearish_smart_trail[1]} and {volatility} > 50
{bearish} = {bearish_confirmation_any} and {bullish_smart_trail[1]} and {volatility} > 50
{bullish} or {bearish}
{any_choch} = {bullish_ichoch} or {bullish_ichoch+} or {bullish_schoch} or {bullish_schoch+}
{close} > {prev_day_high} and {any_choch}
Пороговые числа, которые кочуют из шаблона в шаблон
Числа в шаблонах местами интереснее самих шаблонов, потому что показывают, какие уровни авторы тулкитов считают значимыми. Сила тренда проверяется на превышение 60 и 70, хотя разделительная линия между трендовым и боковым рынком проходит по 50: авторам нужен не просто тренд, а тренд с запасом. Конфлюэнс проверяется двумя способами, == 2 для сильного и > 0 для любого, и это прямое следствие трёхзначной шкалы. Денежный поток встречается и в пересечениях, и в сравнениях, причём пересекаемые уровни ниже проверяемых: 30 и 50 против 50, 60 и 70.
Почему шаблон нельзя вставлять не глядя
Есть и причина, не связанная ни с торговой идеей, ни с часовым поясом. Написание нескольких плейсхолдеров в библиотеке расходится со справочной страницей того же раздела документации, и расхождение это не косметическое: плейсхолдер с неверным именем не находится, а значит, не находится и всё условие целиком. Проверка занимает минуту, но её надо сделать до того, как алерт будет создан и забыт.
Показательно и то, чего в библиотеке нет вовсе. Ни один из тридцати трёх шаблонов не пользуется мостом к конструктору пользовательских алертов, хотя оба плейсхолдера этого моста доступны в словаре каждого тулкита. Между тем условие, собранное в конструкторе мышью, механика которого разобрана в третьей части, входит в скриптовое одним компактным именем, и для читателя, у которого конструктор уже настроен, это самый короткий путь к первому работающему скрипту.
«Шаблон полезен как заготовка структуры, а не как готовое решение: первым делом в нём проверяют тулкит, часовой пояс и имена плейсхолдеров»
Глава 9. Миграция с v1 на v2
Что добавила вторая версия языка
Эта глава нужна прежде всего тем, у кого сохранились скрипты, написанные до обновления языка. Остальным она полезна иначе: через список изменений видно логику, по которой язык перестраивали. Всё, что управляло состоянием последовательности, стало методами, а разделение шагов из невидимого превратилось в явное. Список добавлений выглядит так.
- Несколько последовательностей в одном скрипте вместо одной.
- Работа последовательностей в Strategy Scripting, то есть в бэктестерах, разобранных во второй части.
- Ключевое слово
thenкак явный разделитель шагов. - Встроенная инвалидация через оператор
!. - Методы
invalidate()иset_step(). - Персональные плейсхолдеры состояния
{имя.step}и{имя.barssince_step}. - Обращение к истории в вертикальных координатах метки и линии.
- Аргумент имени у действия
@valuewhen. - Плейсхолдер, работающий только в инвалидационном контексте.
Соответствия конструкций v1 и v2
Главное изменение записи касается шагов. В первой версии шаг занимал строку, и последовательность собиралась переносами строк, без единого ключевого слова. Во второй версии переносы строк потеряли это значение, а шаги соединяются словом then. Изменение выглядит косметическим, но оно единственное во всём списке, которое ломает старый скрипт тихо: ошибки не будет, просто каждая строка станет самостоятельным условием, а последовательность исчезнет.
{close} > {open} // Step 1
{close} crossover {close[9]} // Step 2
{volume} crossover 10000 // Step 3
{close} > {open} then {close} crossover {close[9]} then {volume} crossover 10000
Три действия, которых больше нет
Из языка исчезли три действия, и первые два заменяются механически. Вместо @invalidate() пишется метод или встроенная инвалидация, вместо @set_step() одноимённый метод. Третье, @filter(), замены в один жест не имеет. Оно задавало условие, которое обязано выполняться на каждом шаге, и во второй версии эта роль отдана пользовательскому плейсхолдеру: фильтр определяется отдельной строкой, а потом подмешивается через and в каждый шаг последовательности. Запись становится длиннее, зато перестаёт быть магией, потому что видно, где именно фильтр действует.
{vol_filter} = {volume} > 5000
{my_sequence} = {close} > {open} and {vol_filter} then {close} crossover {close[9]} and {vol_filter} then {volume} crossover 10000 and {vol_filter}
Ошибки, которые всплывают после переноса
Первая ошибка касается порядка строк. В первой версии инвалидация выполнялась раньше проверки шага по устройству языка, и автору скрипта не нужно было об этом думать. Чтобы воспроизвести то же поведение во второй версии, строки с invalidate() и set_step() размещают выше определения последовательности. Это третье по счёту напоминание одного и того же закона в этой части, и здесь оно уместно как итог: на каждом баре сначала разрешается сброс и перевод шага, потом проверяется сам шаг, и только потом выполняются действия.
// метод стоит выше определения: он должен исполниться первым
{my_sequence}.set_step(0) = {close} < {open}
{my_sequence} = {close} > {open} then {close} crossover {close[9]} then {volume} crossover 10000
Вторая ошибка возникает при отказе от имён аргументов. Во второй версии имена и кавычки стали необязательными, и старые вызовы вида @label(y = "{close}", text = "hello") сокращаются до @label({close}, "hello"). Сокращать можно, но с оговоркой: как только имя опущено, значение опознаётся исключительно по позиции, и пропуск одного необязательного аргумента в середине сигнатуры сдвигает все следующие. Третья ошибка не ошибка автора, а расхождение источника: плейсхолдер для неактивных шагов допустим только внутри инвалидационного контекста, и называется он на разных страницах документации по-разному. Написание надо проверять в интерфейсе тулкита.
Эпилог
Язык, на который ушло девять глав, при взгляде с конца оказывается небольшим. Словарь, девять операторов, три именованных пересечения, квадратные скобки для истории, одно ключевое слово для сборки шагов, четыре действия и два метода. Всё остальное, это комбинаторика: из десятка приставок и примерно ста семидесяти тулкитных имён собираются условия любой сложности, и ограничивает их не язык, а способность автора удержать собственную мысль в голове до конца строки. Наизусть стоит помнить три вещи, и все три противоречат интуиции: or связывает сильнее, чем and; шаги нумеруются с нуля; инвалидация всегда разрешается раньше проверки шага, где бы она ни была написана.
У этой точности есть цена. Условие пришлось выписать символ в символ, и работает оно ровно на одном инструменте, том, что открыт на графике. Часть VII, заключительная, отдана скринерам LuxAlgo, скринерам Signals & Overlays, Price Action Concepts и Oscillator Matrix: там показания тех же тулкитов раскладываются по колонкам таблицы сразу по десяти рынкам, условие задаётся фильтром и сортировкой по колонке, а не текстом, и вместо одного графика перед читателем оказывается срез рынка целиком. Сравнение, которое стоит держать в голове при чтении: язык из этой части даёт точность на одном инструменте, скринер даёт охват без точности, и выбирать между ними приходится по задаче.
Источники
Все факты этой части восходят к семи страницам раздела Alert Scripting в официальной документации LuxAlgo. Общее место языка среди функций тулкитов описывает обзорная страница раздела; настройки, подсветка, последовательности и инвалидация разобраны на странице применения; полный словарь собран в справочнике плейсхолдеров; грамматика в справочнике операторов; действия, методы и все перечисления значений в справочнике действий и методов; тридцать три готовых условия в библиотеке готовых скриптов; список изменений второй версии в руководстве по миграции. Обзорное видео LuxAlgo о возможностях языка доступно по адресу https://www.youtube.com/watch?v=syWuQIl6U4A.
В четырёх местах источник противоречит сам себе, и в тексте части выбран определённый вариант. Плейсхолдер неактивных шагов на разных страницах назван по-разному. В примере с переводом шага метод вызван как set_value, тогда как задокументированное имя, это set_step. Описание оператора <= продублировано с описания >=. Написание нескольких плейсхолдеров в готовых шаблонах не совпадает со справочником. Во всех случаях приоритет отдан справочным страницам, а не примерам. Скриншоты в тексте сделаны автором в TradingView, официальные иллюстрации приведены со ссылкой на страницу-источник.
Похожие посты
LuxAlgo. Часть VII: скринеры, десять рынков в одной таблице
Скринер LuxAlgo сжимает целый тулкит до одной строки таблицы и позволяет держать в поле зрения до десяти тикеров сразу, каждый в своём таймфрейме. Разбираем устройство всех трёх скринеров: элементы и рейтинг, фильтрацию и сортировку, различия между Signals & Overlays, Price Action Concepts и Oscillator Matrix, а также трение, которое возникает при работе.
LuxAlgo. Часть V: Oscillator Matrix, осциллятор, который спорит сам с собой
Пятая часть руководства по LuxAlgo целиком отдана тулкиту Oscillator Matrix. Разбираем, как устроены HyperWave и его сигнальная линия, почему дивергенции упираются в жёсткий предел в 500 линий, что показывают пороги Money Flow, чем кружок отличается от треугольника в сигналах разворота, как считается конфлюэнс и какие семнадцать событий тулкит отдаёт в алерты. В конце: сводка всех опубликованных значений по умолчанию.
LuxAlgo. Часть IV: Signals & Overlays, сигнал, который не является входом
Часть IV руководства по LuxAlgo целиком отдана самому популярному тулкиту компании. Разбираем, почему подтверждающий сигнал по замыслу авторов не является точкой входа, чем контртрендовый режим платит за раннюю правоту, как читать четыре класса ML-классификатора в двух режимах по-разному, зачем одному числу чувствительности три разных способа назначения, что именно рисуют пять оверлеев и почему уровни TP и SL никуда не едут после появления. В конце: девятнадцать предустановленных алертов, конструктор пользовательских алертов и сводка всех опубликованных значений по умолчанию.
Комментарии
Пока нет комментариев. Будьте первым.