Блог им. jatotrade_com

QLua скринер в 10 строк кода. Или "за базар отвечаю".

Всем привет!
Никогда не давайте обещаний которые не можете выполнить. Во-первых — это портит карму. Во-вторых, за сказанное нужно отвечать. В далеких (не очень) 90-х, если человек не держал слова, к нему приезжали «санитары» с электроприборами, типа дрель, паяльник, утюг — все перечислять не буду, чтобы не пугать читателя, т.к. пост многие найдут полезным не только для торговли, но и для написания собственного кода. Так вот, пообещал я человеку, дело было так:
QLua скринер в 10 строк кода. Или "за базар отвечаю".
Мой родной язык, помимо русского, Common Lisp. С недавних пор породнился с Питоном. А тут луа, да еще с Квиком вперемешку. Не фиг было обещания давать. Больше времени потратил на изучение структур данных луа и особенностей QLua. Сам код был написан за пару часов, как увидите ниже — чё там писать-то...
Как я обещал — пользователь Смартлаба Weddy получает код бесплатно, как и остальные участники тусовки. Ну а я, в качестве вознаграждения получаю приобретенный опыт. Проверял сегодня — работает с любым Квиком (6, 7, 8). Конечно дополнительных «наворотов» я не делал, как в идеале желал Weddy, но это уже детали.
Сам код отображает изменение цены в процентах для любого количества тикеров, которые вы запишите в переменную tickers в виде пар (код-бумаги и код-класса) за N-последних дней (переменная days_before). Все обновляется в режиме онлайн и работает очень быстро (Квик не замечает нагрузки этого скрипта). Инструментами могут быть любые торгуемые на МОЕХ тикеры — акции, облигации, фьючерсы, опционы и т.д. В таблице показаны изменения текущей цены к цене закрытия «вчера», «позавчера», три дня, неделю назад, 10, 30, 44, 67, 90 торговых сессий назад.
«Вживую» выглядит так:

QLua скринер в 10 строк кода. Или "за базар отвечаю".
Ну и сам код:
-- ©2020 by Evgeny Shibaev
-- Таблица, отображающая в процентах рост(падение) инструмента финансового рынка за определенное количество дней
-- Какие инструменты(тикеры) отслеживаем. Таблица пар тикер - площадка
tickers = {SiU0 = "SPBFUT", RIU0 = "SPBFUT", BRN0 = "SPBFUT", GZU0 = "SPBFUT", SRU0 = "SPBFUT", GAZP = "TQBR", SBER = "TQBR", YNDX = "TQBR",
           GMKN = "TQBR", MGNT = "TQBR", SU26207RMFS9 = "TQOB"}
-- За ппоследние n-дней
days_before = {1, 2, 3, 5, 10, 30, 44, 67, 90} -- эквивалентно "вчера", "позавчера", 3-дня назад, 7 и 30 торговых сессий назад.
sources = {} -- Список источников данных по количеству тикеров
rows = {} -- Список строк в таблице по количеству тикеров
screener = AllocTable() -- Указатель на саму таблицу
stopped = false -- Остановка скрипта
     
-- Функция вызывается перед вызовом main
function OnInit(path)
   -- "Ticker"- название первого столбца в таблице
   AddColumn(screener, 0, "Ticker", true, QTABLE_STRING_TYPE, 15)
   -- Названия остальных столбцов в таблице по количеству days_before
   for column, days in ipairs(days_before) do
       AddColumn(screener, days, days.." day(s)", true, QTABLE_STRING_TYPE, 11)
   end
   CreateWindow(screener)
  -- Даем название  таблице
   SetWindowCaption(screener, "Percent change for last days")
   for ticker, board in pairs(tickers) do
       --Для каждого тикера создаем источник данных - "дневки"
       sources[ticker] = CreateDataSource(board, ticker, INTERVAL_D1)
       --Устанавливаем коллбэк функцию для каждого тикера. Она вызывается при изменении цены тикера. "А что, так можно было?"
       sources[ticker]:SetUpdateCallback(function(index) InvalidateCallback(index, ticker) end)
       --Для каждого тикера определяем строку в таблице и запоминаем ее в rows
       rows[ticker] = InsertRow(screener, -1)
       --В первом столбце каждой строки будет имя тикера
       SetCell(screener, rows[ticker], 0, ticker)
   end
end

-- Коллбэк функция вызывается при изменении значения текущей цены тикера. Обновляет строку тикера в таблице сразу, как происходит изменение.
function InvalidateCallback(index, ticker)
   for column, days in ipairs(days_before) do
      -- Определяем процентр изменения цены тикера за days-дней
      percent = Change(ticker, days)
      -- Выводим в соответствующую ячейку таблицы процентр изменения
      SetCell(screener, rows[ticker], days, string.format("%.2f", percent).."%")
      -- Подкрашиваем ячейку соответственно росту(падению) и величины роста(падения)
      SetColor(screener, rows[ticker], days, BCellColor(percent), FCellColor(percent), BCellColor(percent), FCellColor(percent))
   end
end

--Функция определяет на сколько процентов выросла или упала бумага относительно N-дней назад
function Change(ticker, days_before)
  len = sources[ticker]:Size() --Сколько всего "дневных" свечей в источнике данных конкретного тикера
  --Возвращаем рост(падение) в процентах текущей цены от цены закрытия days_before-торговых сессий назад
  return (sources[ticker]:C(len) - sources[ticker]:C(len - days_before)) / sources[ticker]:C(len - days_before) * 100
end

-- Цвет текста в ячейке. Если рост - то цвет "зеленый", падение - "красный"
function FCellColor(change) if change > 0 then return RGB(0,128,0) else return RGB(158,0,0) end end

-- Маленькая "тепловая карта". Делает фон ячейки более интенсивным, взависимости от величины роста(падения)
function BCellColor(change)
  bright = math.floor(255 - math.min(math.abs(change*10), 110),1)
  if change > 0 then return RGB(bright,255,bright) else return RGB(255,bright,bright) end
end

-- Функция вызывается перед остановкой скрипта
function OnStop(signal) stopped = true end

-- Функция вызывается перед закрытием квика
function OnClose() stopped = true end;

-- Основная функция выполнения скрипта
function main()
  while not stopped do sleep(1) end
end  	  

Всем хороших выходных, и постарайтесь выполнить все данные вами обещания!
Код вы можете также найти в конце страницы https://www.jatotrade.com/download
Или по прямой ссылке. Подписаться на мой канал в ютьюбе можно здесь. Там много чего интересного.

ЗЫ: точный способ узнать код класса бумаги спросить на iss.moex например для опциона на RI127500BG0A
https://iss.moex.com/iss/securities.xml?q=RI127500BG0A В ответе найдете в поле primary_boardid=«ROPD»:
<row id=«411357163» secid=«RI127500BG0A» shortname=«RTS-9.20M020720CA127500» regnumber="" name=«Нед. марж. амер. Call 127500 с исп. 2 июля на фьюч. контр. RTS-9.20» isin="" is_traded=«1» emitent_id="" emitent_title="" emitent_inn="" emitent_okpo="" gosreg="" type=«option» group=«futures_options» primary_boardid=«ROPD» marketprice_boardid=""/>


 





  • обсудить на форуме:
  • Quik Lua
★52
55 комментариев
Да, смартлабовцы они такие, на что хочешь разведут и без всякых паяльников)))
avatar
А чё ты говорить? И так все ясно.)
avatar
Запилить еще можно средний дневной объем. И среднее движение от открытия до закрытия.
avatar

Ииии Евгений врывается в топ самых полезных авторов Смарт-лаба))

 

Скринер штука полезная для некоторых стилей торговли.

avatar
Replikant_mih, «за Державу обидно», то-бишь Смартлаб 
Спасибо за труд!
Йонатан Берсон, да, и вам за оценку, уже много кто поблагодарил — вот только Weddy жду, ради него все и затевал))
Евгений Шибаев, тут же просто такая штука… много кто что говорит, но мало делает) 
Йонатан Берсон, ну это не только на Смартлабе, во всей стране так, особенно в телевизоре…
Евгений Шибаев, вот бы еще пару дней назад, когда у меня был Д.Р., то заданный Вашим постом тон вообще бы смотрелся красиво:
«Как я обещал — пользователь Смартлаба Weddy получает КО ДНЮ РОЖДЕНИЯ код бесплатно»  )))
Ну а если серьезно, то большое спасибо за Ваш труд и помощь!!!
Ну а если попытаться понаглеть, то хотел бы обратить внимание на нюанс из моего ТЗ :):
чтоб в таблицу можно было выбрать интересующие инструменты и по ним отображалось по каждому инструменту изменение текущей цены по отношению к цене с задаваемым условием: за неделю, месяц, или особенно здорово например от последнего хай/лой за последние хх дней/ определенной даты.

Т.е. источником моей мечты о сканере было то обстоятельство, что большинство он-лайн сканеров показывает изменение цены за те, или иные периоды по отношению к цене закрытия. И как-то не попадались сканеры, где изменение отражалось бы по отношению к high/low цены дня точки отсчета.
Идея здесь простая. Вот 19.01.2020 был хай индекса ММВБ. Хотелось бы задать эту дату и увидеть в таблице изменение текущих цен инструментов по отношению к их хаям в заданный день. Посмотреть в сравнении кто на сколько больше/меньше упал.
И наоборот. 15.03.2020 был лоу по индексу ММВБ. Посмотреть, сравнить кто на сколько отскочил со своих лоев на ту дату.
Наверно для анализа акций удобней было бы задавать для таблицы вообще лишь класс TQBR, без вбивания кодов 260+ инструментов. Хотя у выборки с определенным набором инструментов есть своя ценность, при сужении акцента отслеживания.
avatar
Weddy, 
заменить можно указанием собственного ориентира, а внутредневной-недельный-квартальный саб бы подхватывался
Олайвир Стокс, сорри, но для меня написанное не понятно в практической реализации. В отличие от доброго автора топика я не владею луа
avatar
Weddy, 
это к выражению «самые дорогие ошибки — в неверной концепции», в данном случае, это выразилось в непрозрачности алгоритма что требуется — производитель реализовал алгоритм не тот, что представлял потребитель

верна суть алгоритма? — отображение текущего отклонения от заданной цены, для удобства в окно сообщения отклонение от дневных\месячных\годовых экстремумов
Олайвир Стокс, 
от дневных\месячных\годовых экстремумов
от дневных экстремумов с возможностью указать тот день, с экстремумом которого сравнимается текущая цена. С месячными/годовыми наверное еще сложнее с заданием параметров точки отсчета
avatar
Weddy, 
принимает на вход дату
выводит максимальные цены с отношением к текущей цене в виде таблицы нескольких инструментов, так?
Weddy, с Прошедшим! Здоровья и удачи! Ну, если вы раньше сказали я бы постарался прям ко дню рождения сделать. Боюсь правда, если создать прецедент, то я все свободное время буду кодить для смартлабовцев, у которых ДР «на подходе», они же умеют разжалобить... 
По поводу хай-лоу — мне главное как вы хотите видеть это представленное в таблице. Если задавать даты по столбцам, то часто будет что хай Газпрома по дате не приходится на хай Сбербанка по дате.
Поэтому предлагаю вариант — вы задаете как сейчас период в количестве торговых сессий, скрипт вычисляет хай-лоу за этот период, а затем «расстояние в процентах» текущей цены от этих хай-лоу. Шпильки (выбросы цены) также будут учтены в этом случае. давайте на неделе как время будет — подкорректирую.
Насчет вбивания кодов — вы все равно будете «вбивать» имя тикера, скопируйте просто 260+ строк с уже готовым кодом и всё.
Евгений Шибаев, 
Все же не понял мысль здесь:
задаете как сейчас период в количестве торговых сессий, скрипт вычисляет хай-лоу за этот период, а затем «расстояние в процентах» текущей цены от этих хай-лоу

1) Если я задам days_before = {12}, то скрипт вычислит хай-лоу за весь период 12 дней, или в день 12 дней назад? Это разные варианты, каждый имеет свою ценность. Если можно задать переключатель, то здорово. А так я имел в виду вариант хай/лоу в 12-й день от текущего. чтоб можно было увидеть разницу с определенным днем (как писал например, с днем хаев индексов, див.отсечек, других ключевых дат).
2) Как понимаю надо переключатель чтоб задать хай или лоу определять.
3) Хорошо бы выводил в столбец определенное значение хай/лоу, чтоб легко проверить то ли сделал. По крайней мере на начальном тестовом этапе.
4) Вычислить кол-во торговых дней до желаемой даты отсчета конечно можно. Хотя вбить конкретную дату было бы быстрее и безошибочнее.

Поясните еще это:
Насчет вбивания кодов — вы все равно будете «вбивать» имя тикера, скопируйте просто 260+ строк с уже готовым кодом и всё.

— т.е луа не позволяет после указания кода класса самой заполнить таблицу имеющимися на бирже тикерами и надо именно указать каждый тикер?
— откуда «скопируйте просто 260+ строк »? Мне пока пришло в голову лишь вывести через DDE в эксель таблицу текущих торгов, там уже удалить лишние столбцы, и формулами попытаться связать в требуемый синтаксис MGNT = «TQBR»,
avatar
Weddy, хай-лоу не нужно определять вам, за вас это сделает скрипт. Вы просто определите интервал, за который определять хай-лоу. Вот как на картинке примерно — за 30 и 15 дней.

На счет кода класса, вы получите несколько тысяч тикеров одного кода класса — если вы их все отслеживаете — поздравляю, вы обеспеченный человек — в этом случае можно дать указание секретарше вбить напротив тикера "=" и код класса вручную ))) без обид....
Евгений Шибаев, да я понимаю что скрипт сам будет определять хай-лоу.
Вы просто определите интервал, за который определять хай-лоу.

Ну я же не об этом писал ранее:
Вот 19.01.2020 был хай индекса ММВБ. Хотелось бы задать эту дату и увидеть в таблице изменение текущих цен инструментов по отношению к их хаям в заданный день.
Т.е., я задал дату, это в примере 19.01.2020. И задал, что надо определять хай. Скрипт определил дневной хай цены по инструменту который был именно на этот день, а не в течение месяцев после.  Это например 224,5 руб. В условные 16:27 сегодняшних торгов цена по инструменту 194,56руб. Скрипт выводит относительное изменение между этими 2-мя ценами.
Если же для даты 19.01.2020 задано определять лоу, а не хай, то соответственно скрипт отображает изменение цены от лоу дня 19.01.2020 до текущих 194,56руб.

Не знаю насколько сложен переключатель задания определять хай или лоу нужного дня. Возможно проще скрипту определить и хай и лоу заданного дня (19.01.2020 в примере) и вывести в строке оба относительного показателя «хай 19.01.2020 к текущей цене» и «лоу 19.01.2020 к текущей цене»
вы получите несколько тысяч тикеров одного кода класса
я исходил из того, что на ММВБ всего 260+ акций, а не несколько тысяч. А так, скринер как раз для того и нужен, чтобы из большой массы выловить те инструменты, которые внимательнее рассмотреть, отслеживать. И как раз избежать ситуации, чтобы отслеживать тысячи.
avatar
Вот всегда интересовала мотивация кодеров — заморочиться, написать чего то и выложить в открытый доступ. Респект и уважуха, конечно, от профессионального халявщика. Но напуркуа? Кодеры живут вечно?
avatar
Mezantrop, кодеры нет, но коды да!
Евгений Шибаев, 
АААА!
Я памятник себе воздвиг нерукотворный
К нему не зарастет народная тропа?
avatar
Mezantrop, That thine alms may be in secret: and thy Father which seeth in secret himself shall reward thee openly. Matthew 6:4. Чтобы милостыня твоя была тайной, и Отец Твой, видящий тайное воздаст тебе явно. Евангелие от Матфея Глава 6, стих 4.
Евгений Шибаев, 
Боюсь обидеть, извиняюсь, если что...
Какое отношение сборник древнееврейских мифов имеет к народностям, проживающим исторически в лицемерии?
avatar
Mezantrop, да все норм, просто не поняли друг друга.
Mezantrop, 
тренируешься ожидая из вне благодарность?
Олайвир Стокс, 
Да неее...
У благодарности очень низкие котировки, а фундаментал вообще грустный...
Пятничное…
avatar
Mezantrop, 
У благодарности очень низкие котировки

Иисус вернул зрение 12 слепым, и только трое сказали спасибо.. .. 
avatar
Wallstep, 
Это он Вам сам сказал?
avatar
Mezantrop, конечно, вчера звонил.…. еще и смс скинул. .. 
avatar
Wallstep, 
Вы по аккуратней...
Расширенное сознание может назад не вернутся…
avatar
Mezantrop, ради саморазвития и спортивного интереса
avatar
Валерий, 
Логичнее же все то же самое замутить в рамках коммерческого проекта? Напуркуа благотворительность? При чем это массово — полезного халявного кода — полинета.
Если как оставить о себе память — более менее понятно — компенсация навязанной манипуляции. Если с другой целью — не понятно…
avatar
Mezantrop, вот такие как вы, никада не поймут таких как мы. Просто что-то взять и запилить покайфу. Чтоб работало. У вас адреналин только от денег выделяется?
avatar
4kk, 
У меня много что,  много от чего, выделяется ...
Но два безвозвратных ресурса: время и здоровье — обычно трачу с личной пользой…
avatar
Ого кто-то Lisp вспомнил!!! Вот это круто!
Свой Мужик, да вроде я и не забывал его))) А вот кстати — стиль лисповика в коде чувствуется?
Евгений Шибаев, ой 20+ лет прошло уже кроме названия и то что под автокад который ещё тогда под DOS был по моему, писал не вспомню ничего :(
Свой Мужик, 

Эх помница на автолиспе ваял я код под автокад.
Бабули впрочем были против («био-копир наш был не рад») 
Одно и то же рисовали толпой, годами — это скука! 
Поставил плоттер (струйный правда), а мне сказали, что я — сука. :) 
avatar
Носорог, да да да под автокад )))
Носорог, я и сейчас на автолиспе себе рутину на работе автоматизирую
avatar
Валерий, а у меня первая любовь — Паскаль. Понятно что до неё были бэйсик и даже программируемые калькуляторы. Из-за паскаля многие годы игнорировал си, а зря — в итоге все сиподобные нотации мне не заходят. Писать конечно могу, но как на неродном языке, а на Паскале я думал — сразу код себе представлял, оставалось его набить на клаве.

И вот когда стал выбор между мультичартс и тс лабом, я выбрал первый как только прочитал, что его EasyLanguage — это Pascal.

Выбор возможно иррациональный, уж как то долго я его осваиваю, куча граблей. Хочется верить что в тс лабе все проще. Но все равно какой это кайф было вспомнить первую любовь :) 
avatar
отличная штука, а как сделать тоже самое но только применительно к объемам?
avatar
Alexandr, думаю что так:

function Change(ticker, days_before)
len = sources[ticker]:Size() --Сколько всего «дневных» свечей в источнике данных конкретного тикера
--Возвращаем рост(падение) в процентах текущего объема от объема закрытия days_before-торговых сессий назад
return (sources[ticker]:V(len) — sources[ticker]:V(len — days_before)) / sources[ticker]:V(len — days_before) * 100
end
Здесь только нюанс — в таком варианте объем имеет смысл смотреть в конце дня, т.к. особенно вначале, он будет показывать отрицательное изменение — или я не так понял ТЗ?)))

Тимофею напомните по теме сосредоточения общеполезных материалов технического характера
Лисп -это жестко…
за халяву большое спасибо. Но есть вопрос
\Screener.lua:29: attempt to index field '?' (a nil value)
это потому что сейчас торгов нет? или я что то не так сделал?
avatar
Andy, у меня показывает даже сейчас, правда я подключен к Финамовскому серверу. Возможно, если вы вчера не подключались, и сейчас нет соединения с биржей, то 29-строка — не может найти источник данных. Так что в понедельник все должно нормально заработать.
А вообще по использованию — не было времени проверить, но нужно учитывать следующее — у фьючерсов и, например акций «время жизни» разное, фьючерс может существовать полгода — год, а акция 10 лет и более.
Поэтому корректно было бы сделать дубликат кода скрипта, и в один скрипт поместить список акций, а в другой список фьючей. Получатся две таблицы, тогда для акций можно будет задавать большее количество дней отдельно от фьючей.
Евгений Шибаев, спасибо, проверю во время работы биржи. Фьючи не пользую, посмотрю на акциях.
avatar
Хоть раз в месяц, что-то полезное можно на смарте найти. Кроме ежедневного нытья.
avatar
Евгений, подскажите пжл, как изменить чтобы были фактические объемы? Если бы ещё ставилось дата и время в названии столбцов, то просто супер
avatar
Alexandr, если в просто screener то функция Change для объемов примет такой вид:

function Change(ticker, days_before)
len = sources[ticker]:Size() --Сколько всего «дневных» свечей в источнике данных конкретного тикера
--Возвращаем рост(падение) в процентах текущей цены от цены закрытия days_before-торговых сессий назад
return (sources[ticker]:V(len) — sources[ticker]:V(len — days_before)) / sources[ticker]:V(len — days_before) * 100
end

Дата в названии столбцов — это финальная часть ТЗ Weddy, постараюсь в течение недели сделать)))
Евгений, а как сделать таблицу с открытым интересом?
avatar
Alexandr, если навскидку, попробуйте при заказе данных запросить так:
sources[ticker] = CreateDataSource(board, ticker, INTERVAL_D1, «NUMCONTRACTS»). В этом случае в качестве параметра будет количество открытых позиций. Если не получится, я сам попробую на реальных торгах завтра — отпишу.
Огромное спасибо за хороший пример на Lua
avatar

теги блога Евгений Шибаев

....все тэги



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