Блог им. vtvladim

Создание на Lua своего индикатора в графике Quik: Часть 2.

Создание на Lua своего индикатора в графике Quik: Часть 2. Пример работы нестандартных индикаторов: спред между инструментами, прогноз Highи Lowследующего интервала; ценовых уровней по объемам

 

В первой части (https://smart-lab.ru/blog/930907.php) были изложены основы принципа создания своего индикатора и некоторые нюансы работы с кодом индикатора графика в Qiuk (подразумевается использование языка программирования Lua).
   В данной статье немного продолжу тему нюансов кодирования индикатора и для иллюстрации приведу простой код индикатора спреда. В конце текста прикреплю видео с демонстрацией работы индикатора спреда и моих собственных индикаторов.
   Небольшое лирическое отступление. Суть данных статей — показать, что делать подобные индикаторы вполне реально и не столь сложно, как может показаться на первый взгляд. Но, безусловно, требует определенных знаний в программировании. Создавать индикаторы из стандартного набора торговой системы Qiuk смысла нет – ведь они уже реализованы. Создавать свой индикатор целесообразно тогда, когда у вас имеется своя идея (метод, способ анализа и т.п.). Приведенный в 1 части код индикатора SMA, написанный разработчиками Quik, давал возможность увидеть текст и структуру кода индикатора, «своими руками» попробовать запустить индикатор и испытать его в работе. Оптимизация кода SMA мне абсолютно не интересна, он был приведен в варианте «как было в инструкции» – эта ремарка для особо нервных программистов. Реально полезную вам расчетную часть кода каждый должен написать самостоятельно в соответствии со своими целями.
   Теперь по теме.
   В предыдущем обсуждении, благодаря коллеге (https://smart-lab.ru/profile/Vkt/, за что ему огромное спасибо) открылся еще один нюанс при кодировании индикаторов. Связан он, как я понимаю, с некоторой недоработкой в самом Quik. А именно: в случае, когда в качестве основного источника данных используется более одного инструмента, верно работает только коллбек источника данных (ИД) первого инструмента. OnCalculate, как известно, по сути является коллбеком ИД в индикаторах. Следовательно, он по идее должен выполнять эту функцию по всем ИД, которые выведены на график. Однако, это происходит «половинчато» — цена у всех инструментов на графике меняется верно, но вот с обращением к значениям ИД в коде возникают проблемы. Проявляется это в следующем: при смене интервала данные второго и последующих инструментов недоступны (хотя графически их цена на графике отображается верно), аналогичная проблема — при смене инструмента и после запуска Quik. При первичном же добавлении индикатора на график все работает нормально. Т.е. коллбек (OnCalculate) начинает правильно работать при добавлении или обновлении индикатора (редактировании – причем в режиме редактирования можно ничего не менять, просто нажать «ОК» — см. видео). Никакими хитростями в коде ситуацию исправить не смог. Ну а какая платформа без греха? В принципе не смертельно – обновить график, но вот когда таких графиков несколько… Можно подписываться на инструменты самостоятельно через CreateDataSource — но в рамках задачи визуализации смысла так делать не вижу (если кто-то сможет «победить» этот нюанс – напишите, интересно будет узнать способ). Как вариант, эту проблему косвенно можно обойти следующим образом: создать несколько графиков вместо одного (для каждого инструмента, по которым считается спред) и присвоить идентификаторы инструментам на каждом графике. Тогда мы избегаем ситуации с несколькими ИД на одном графике и коллбек работает верно. Я этот способ не использую, потому что лишние графики в Quik – это лишние потоки данных со всеми вытекающими последствиями.
   Ниже привожу скрипт расчета спреда (за основу взят код, публично выложенный в обсуждении первой части статьи). Для использования у себя в терминале следует сделать следующее:
   1. Сохраняем текст индикатора в файле с расширением, например Spread.lua, в папке LuaIndicators (если отсутствует – создать), которая находится внутри папки Quik.
   2. Создаем новую вкладку (например, «Спреды», чтобы разделить информацию разного рода)
   3. На вкладке «Спреды» создаем таблицу текущих торгов (с нужными вам инструментами) и график (окно с объемом в графике спреда я считаю лишним и удаляю), «якорим» график с таблицей текущих торгов
   4. Строим на графике цену двух инструментов (например, GOLD-9.23 и GOLD-12.23). Поскольку график заякорен, в таблице выбираем GOLD-9.23, а GOLD-12.23 добавляем. В дальнейшем, при смене инструмента в таблице, на графике сменятся оба инструмента и второй надо будет заменить вручную.
   5. Задаем идентификаторы инструментов: для цены Gold-9 id1, для Gold-12 id2 (правой кнопкой мыши щелкаем на линии цены (или подписи внизу графика) — дополнительно — там есть поле «идентификатор» вписываем id1 (id2) и сохраняем).
   6. Добавляем индикатор (ищем название «2AV_Spread») в новую область. Смотрим на результат. В режиме редактирования пользовательских настроек – если необходимо – меняем начальную дату расчета, цвет и тип линий. Названия идентификаторов НЕ ТРОГАЕМ!
   Величина спреда определяется как (Цена1*K1 — Цена2*K2), а в случае отсутствия одного из значений цены равна предыдущему значению спреда.
   Коэффициенты К1 и К2 – балансировочные. Если инструменты различаются только датой контракта, они должны быть равны 1. В случае разных инструментов (например, Si и его спот), К2 должен быть равен 1000. В общем случае может потребоваться изменение значений обоих коэффициентов (сложная балансировка в пределах вашей фантазии), поэтому коэффициентов два.
   При вставке кода обратите внимание: начальные текстовые значения данных в Settings должны быть заключены в вот такие двойные кавычки "", а не в такие «». Иначе Quik выдаст ошибку и индикатор не запустится (в зависимости от начальных языковых параметров винды кавычки могут вставляться при копировании неверно). 

— индикатор спреда между двумя инструментами

— «id1» и «id2» это идентификаторы графика (не забудьте задать на графике) первого и второго инструмента, K1 и K2 балансировочные коэффициенты

— величина спреда определяется как (Цена1*K1 — Цена2*K2), ее расчет начинается с даты «From_Date» 

Settings =
                     {
                     Name = «2AV_Spread»,
                     Symbol1 = «id1»,
                     K1 = 1,
                     Symbol2 = «id2»,
                     K2 = 1,
                     From_Date = «01.08.2023»,
                     line=
                                 {
                                 {Name = «Spread»,
                                   Color = RGB(128, 0, 2),
                                   Type = 1,Width = 2}
                                 }
                     } 

Cur_Date    = {}
result_prev = 0
 

function Init()
return #Settings.line
end

 

function OnCalculate(index)
         local indx1, indx2, Start_Date, result
         Cur_Date.day   = tonumber(string.sub(Settings.From_Date, 1, 2 ))
         Cur_Date.month = tonumber(string.sub(Settings.From_Date, 4, 5 ))
         Cur_Date.year  = tonumber(string.sub(Settings.From_Date, 7, 10))
         Start_Date = os.time(Cur_Date) 

         if index >= 1 then
                     if os.time(T(index)) >= Start_Date then
                                 indx1, indx2 = Find_Spread(index)
                                 if indx2 == 0 then
                                             result = result_prev  --- нет данных: берем предыдущее значение
                                 else
                                             result = indx2 — indx1    — значение спреда на интервале
                                             result_prev = result   — запоминаем значение спреда
                                 end
                     end    
         return result
         end
end  

function Find_Spread(index)
         local indx1, indx2
         local Data1, Num_candl, Name_Line = getCandlesByIndex(Settings.Symbol1, 0, index-1, 1) 
                     if Num_candl ~= 0 and Num_candl ~= nil then
                                 indx1 = tonumber(Data1[0].close) * Settings.K1
                     else
                                 indx1 = 0
                     end
                     if indx1 ~= 0 then 
                                 Data1, Num_candl, Name_Line = getCandlesByIndex(Settings.Symbol2, 0, index-1, 1)
                                 if Num_candl ~= 0 and Num_candl ~= nil then
                                             indx2 = tonumber(Data1[0].close) * Settings.K2
                                 else
                                             indx2 = 0
                                 end
                     else   — ветка по идее невозможна, но лучше «затыкать» вариант потери данных
                                 indx2 = 0
                     end
         return indx1, indx2
end  

 

Индикаторы прогнозных значений Highи Lowследующего интервала, уровней цены с максимальными объемами

Индикатор High и Low следующего интервала сделан мною для визуализации результатов расчетов алго: моя ТС использует прогнозные экстремумы цены (High/Low) как точки входа /выхода. Желание визуализировать эти расчеты и подтолкнуло меня к освоению темы индикаторов в Quik. А это, в свою очередь, послужило причиной написания статей с целью немного облегчить путь интересующемуся этим вопросом народу.
   Вообще-то я не использую никаких стандартных индикаторов. Совсем. И данный индикатор называю индикатором только по причине того, что в Quik добавление «не родных» линий на график называется индикатором. Данный индикатор (назвал его High_Low) показывает значения прогнозных H и L следующего интервала. Расчет основан на данных OHLCV предыдущих интервалов. Сразу хочу успокоить нервно реагирующих на слова «прогноз» и «следующий интервал» — я в курсе, что такое предсказание невозможно, читал про это, осуждаю и проч. И, да — это не регрессия и не экстраполяция.
   Краткое пояснение по индикатору High_Low:
   Расчет полностью формализован: используется формула, в которой нет привязки к конкретному инструменту или интервалу, нет оптимизируемых параметров и т.д. Но есть несколько методов, скажем так, численного решения, в моей классификации это: линейный, нелинейный, матричный и средний. Зачем так много? Самому не нравится, но это вынужденная мера для достижения более корректной обработки «тяжелых хвостов». В общем случае, характер движения цены на интервале вверх (значение High) и вниз (значение Low) различен. Поэтому методы расчета High и Low на интервале раздельные (разные). Точность расчета существенно связана с ликвидностью инструмента – чем выше ликвидность, тем лучше точность. В коде (реализован на Lua, так исторически получилось, теперь переписывать нет желания) можно задавать конкретный метод расчета прогноза, либо задать авто выбор оптимального (по критерию минимального СКО между фактическими и прогнозными значениями для заданной глубины ретроспективы). Пользовательские настройки содержат: начальную дату расчета, метод расчета и глубину авто поиска оптимального метода. Как это работает продемонстрировано в видео.
   Индикатор уровней цены по объемам (уровни цены с наибольшими объемами) сделал внепланово в качестве бонуса и закрепления полученных знаний по теме индикаторов в Quik. Хотя, по объемам и уровням сам не торгую. Просто из любопытства сделал, интересно было глянуть, да и «запас карман не тянет». Очевидно, что чем меньше задан интервал, тем точнее результат расчета. Для периода от начальной даты по текущий момент определяются по два уровня (дополнительный и основной -с наибольшими объемами.). Пользовательские настройки содержат: начальную дату расчета, способ отбора уровней (по два уровня выше/ниже: либо средней цены за анализируемый период, либо ближайшие к текущей цене), точность определения уровней, флаг отображать (рассчитывать) уровни или нет.
   Оба индикатора реализовал в одном скрипте. В видео показана работа такого индикатора.
   Краткий путеводитель по видео (мин: сек):
00-03:32 => про индикатор спреда;
03:33-15:25 => индикатор High_Low (демонстрируются: расчет прогнозных High и Low, масштабируемость расчетов по интервалам, инструментам и классам активов, управление выводом индикатора. Немного про определение трендов.
15:26-18:15 => индикатор уровней объемов (демонстрируются: расчет уровней, изменение уровней в зависимости от периода расчета (начальной даты), масштабируемость по интервалам, инструментам и классам активов, управление выводом индикатора.

  • обсудить на форуме:
  • QUIK
4.7К | ★13
6 комментариев
За топик — спасибо. Не в качестве критики, а для предостережения: в видео на 9:07 взгляд зацепился за ситуацию, когда в прогнозе High меньше Low (видимо, не до конца разобран вариант, в котором у предыдущей свечи High равен Low). При таком прогнозе на этой свече незатейливый торговый алгоритм может начать бешено покупать-продавать (цена ниже лоу — покупаем, выше хай -продаем)



avatar
Спасибо за замечание. Сейчас трудно понять что там было — возможно клиринг частично попал в интервал или премаркет, по видео не понятно на какой по времени свечке. В последнее время в свечках появились итоги премаркета, раньше их не было, что там засовывают в свечки — хз, но стакан во время премаркета выглядит очень интересно. Не обращали внимания? Согласен, такого не должно быть. А алго конечно такую ситуацию не торгует, она в логике отсечется как минимум. 
Владимиров Владимир, рекомендую тщательно пересмотреть ту часть реализации алгоритма, которая явно или неявно использует в вычислениях разброс High-Low предыдущей свечи. Может, для избежания ситуации деления на ноль в том месте берется какое-то устаревшее значение. На видео на 13:07 в пяти местах видно, что такие свечи продуцируют прогнозные H=L для следующей свечи, так что при редком стечении обстоятельств что-то непредусмотренное после пустой свечи вероятно и вызывает подобное поведение






avatar
Дед Нечипор, Еще раз спасибо за обсуждение по делу, на сайте от этого быстро отвыкаешь ))) 
   Вопрос немного сложнее и шире. Вы правильно заметили, что подобная ситуация возникает после свечек с одинаковыми HL. Но это только часть ответа. На графике кажущееся в силу масштаба равенство экстремумов не всегда в цифрах действительно верно. В OnCalculate индекс — это порядковый номер (по времени) свечки, а в реальном ИД, на который вы подписываетесь — в нем пустых свечек нет. Я «засунул» в индикатор только расчетную часть кода от алго, где работа с реальными свечками (без пустот), а в ИД от графика как сказано выше — есть особенность. Пустые свечки в индикаторе я «затыкаю» предыдущими значениями (в алго это не требуется), а бороться с «практически пустыми» свечками… Не факт что вообще надо, разве что для красоты или на всякий случай. Почему? — В плане алго — эта ситуация не страшна, поскольку эти места бот 100 % пропускает (фильтр по слишком малой величине торгового диапазона, или резкому изменению торгового диапазона). 
   Я по ЕД нашел место с вашего первого сообщения. Это 22-20 вчерашнего дня, когда было две 5-минутки с одной ценой (O=H=L=C). А на видео использовался авто выбор метода расчета, видимо для этих трех интервалов выбрался нелинейный, чтобы сгладить резкое сужение ценового коридора. Вот он и сгладил )), а поскольку расчет по H и L раздельный, то по L сгладилось сильнее. Но это аномалии, которые, я уверен, надо не решать, а обходить. И самое простое и правильное — не ломать и не портить «затычками» расчет, а отсекать активную работу самого алго для этих моментов. Мое мнение — универсальность расчета это подтверждение его работоспособности. Из этих соображений я не использую оптимизационную подгонку под конкретный инструмент (интервал).. 
Владимир, роботов пишите на заказ на lua для Quik?
Напишите в личку, пожалуйста
avatar
Alex, Нет, не пишу на заказ ни роботов, ни индикаторов, ни чего-то иного прочего. Извиняюсь, если не оправдал ожидания ))). Мне это не нужно в плане заработка, для этого есть торговля на бирже. Если какие-то не архисложные вопросы — обращайтесь, попробую помочь СОВЕТОМ, если смогу. 

Читайте на SMART-LAB:
Фото
Актуальный состав портфеля и взгляд на рынок 2026: по-прежнему 0% позитива.
Добрый вечер! С момента предыдущего поста, касающегося моего портфеля, прошел квартал.  Пришло время актуализировать его состав. Также поделюсь...
Фото
Биткоин попробует разыграть «треугольную карту»?
«Цифровое золото» прорвало верхнюю границу восходящего треугольника на уровне 94 500 и сейчас тестирует пробитую горизонталь, формируя серию...
Фото
Индикатор Fractal: торговые сигналы и робот для OsEngine. Видео
В этом видео разбираем индикатор Fractal Билла Вильямса — один из самых известных инструментов в трейдинге. Покажем, как формируются фракталы,...
Фото
Стратегия 2026 по рынку акций от Mozgovik Research: трудный год, но, возможно, последний год низких цен
Сегодня у меня первый день официального отпуска. За окном темная звездная ночь, яркая белая луна, +24С и шум волн Андаманского моря. Неудачный...

теги блога Владимиров Владимир

....все тэги



UPDONW
Новый дизайн