Продолжение мониторинга после 2-х торговых дней без перезагрузки. Сейчас, за 3 часа до начала торгов, QUIK занимает в памяти 3 Гб. Работающие скрипты занимают: - до очередной сборки мусора: 29М+39М+49М+49М+22М+57М+21М+17М+16М+16М+0.2М+0.2М = 315.4М - после этой сборки мусора: 14М+19М+31М+21М+18М+54М+9М+9М+9М+9М+0.1М+0.1М = 193.2М
Так что ситуация более-менее стабильная и похожая на ситуацию предыдущего дня.
Вчера перед началом торгов (после смены торговой даты) терминал занимал в памяти 1 Гб.
Боевую систему, понятное дело, прислать нет возможности. С другой стороны, можно написать скрипты, похожие по своей логике на те, что работают в боевых системах. Если несколько пользователей пришлют вам свои примеры скриптов, то можно будет сделать что-то типа стенда нагрузочного тестирования (хотя, по идее, у вас уже должен такой быть). На этом стенде гонять скрипты в большом количестве несколько дней и смотреть, когда и что глючить начинает.
Вчера, за 30 минут до начала торгов, был перезаказ данных с очисткой всего. Сейчас, за 2 часа до начала торгов, QUIK занимает в памяти 2.6 Гб. Работающие скрипты занимают: - до очередной сборки мусора: 16М+29М+38М+52М+28М+62М+10М+15М+15М+14М+0.2М+0.2М = 279.4М - после этой сборки мусора: 12М+18М+28М+21М+17М+52М+8М+8М+8М+8М+0.1М+0.1М = 180.2М Получается, что основное потребление памяти идёт от внутренних структур терминала, а нет от самих lua-скриптов. Перед торгами будет сброс данных при смене торговой даты. Посмотрим, что там будет.
А вообще, кажется, что пределы по памяти у терминала (4 Гб) весьма близки. И стратегически решать проблемы можно только либо оптимизациями внутренних структур терминала, либо переходом на 64-битную версию. Предположим, что торговая активность вырастет в 2 раза. Терминал просто не переварит данные за один день, не говоря уж о работающих скриптах. Рост торговой активности наблюдаю с 2013 года: количество записей за день выросло с 6 миллионов до почти 20 миллионов, т.е. почти в 3 раза, примерно то же самое с количеством тиков по Si.
Интересно, что изменилось с момента, когда была активна вот эта тема: https://forum.quik.ru/forum8/topic432/ Особенно см. комментарии Виталия Скоробогатова.
Заведите себе объект, который вычисляет количество отправленных заявок в последнюю секунду (реализация через очередь). Если количество заявок больше, скажем, 45, не отправляйте новые. Понятно, что ограничение неприятное и неудобное, но спамить сервер тоже не правильно.
local Tt = tmpParam.DAYS_TO_MAT_DATE / YearLen --"T-t" время до истечения срока опциона (период опциона);
значение tmpParam.DAYS_TO_MAT_DATE является целым, то будет получаться погрешность при вычислении времени Tt до истечения срока опциона. Эта погрешность будет относительно небольшой, если до квартальной экспирации ещё долго (как сейчас), а непосредственно перед экспирацией это уже ощутимо. Биржа считает время до истечения точно, вычисляя разницу между текущим моментом и моментом экспирации и переводя в доли года. Давно исследовал этот вопрос, даже разбирался для RI момент экспирации считается 18:45 или 19:00.
Если стакан, который наблюдался на момент отправки заявки к моменту попадания заявки на биржу не изменится, то произойдут несколько сделок для тех ценовых уровней, где цена лимиток из стакана лучше или равна цене в Вашей заявке, после чего остаток останется стоять в виде лимитной заявки. Это в случае, если был указан параметр транзакции "PUT_IN_QUEUE". В случаях "FILL_OR_KILL", "KILL_BALANCE" будет по-другому.
Если же биржевой стакан как-то поменяется, то результаты (сделки и остаток в заявке) будут соответствовать обновлённому стакану. Может, например, что вообще сделок не будет, а Ваша заявка встанет в стакан, если рынок успеет "убежать".
Вопросы, по-видимому, к разработчикам и продвинутым пользователям.
В настоящий момент у меня в терминале идёт получение данных в ТТП по примерно 20 акциям и 20 фьючерсам, в таблицу обезличенных сделок идёт информация по всем акциям и фьючерсам, открыто 13 вкладок с графиками, стаканами и разного рода таблицами (всего 83 окна, включая созданные lua-скриптами), работает 12 торговых lua-скриптов (вызывают примерно раз в час функцию collectgarbage).
Перед началом вчерашней торговой сессии (дата уже сменилась на 21.06.2017) были перезаказаны данные со всеми отмеченными галочками. После завершения вчерашней торговой сессии на текущий момент (торговая дата ещё 21.06.2017) терминал занимает 3.1 Гб оперативной памяти.
Операционная система Windows 10 x64 версия 1607.
Вопросы:
1) насколько близки пределы по выделенной памяти, количеству lua-скриптов, после достижения которых будет выскакивать out of memory или появляться другие проблемы?
2) можно ли как-нибудь понять, сколько памяти тратится на работу lua-скриптов (чтобы решить, имеет ли смысл снижать её потребление)?
Один вариант реал-тайм проверки состоит в том, чтобы считать, что вечерняя сессия начинается в 19:00, но отслеживать, идут ли обезличенные сделки по классу SPBFUT. Признак того, что вечерняя сессия открыта -- время >= 19:00 и были сделки после этого времени.
У себя в коде, если по классу SPBFUT нет сделок в последние N секунд нет сделок, считаю, что сессия закрыта и торгов нет. Хорошо помогает, когда биржа глючит, торги остановлены, но статус, по-прежнему, пишет "торгуется".
Если хочется 100% надёжности, то, похоже, только задание расписания торгов поможет.
Andrei2016 написал: Дополнительно еще один вопрос к разработчикам:
возможна ли в штатном режиме работы ситуация, когда ответный вызов OnTransReply() на отправленную программным образом заявку не поступит вовсе? Если да, то прошу пояснить в каких конкретно случаях такое возможно.
Я хоть и не разработчик, но могу сказать, что в при штатной работе программы OnTransReply приходит всегда. На практике при проблемах с интернетом ответы OnTransReply могут пропадать (очень редко).
Optimus1 Optimus1 написал: Подскажите пожалуйста, я вывожу значение RSI в созданною таблицу, значение выводится и все бы хорошо, но значение выводится с 9 знаками после запятой, не очень удобно для восприятия, подскажите, как можно сократить до 1 знака после запятой ?
Код
local rsiFormatted = string.format("RSI=%.1f", rsiValue)
Поскольку команда разработчиков занималась встраиванием lua в терминал, то ей легче, чем простым пользователям, поставить диагноз, что именно пошло не так в lua. А с тем, что если квик в этом случае зависает намертво, то это ошибка квик, -- я согласен. Можно сделать более качественную обработку исключений, даже если они не в языке lua, а в реализации lua. Так что хотелось бы технических подробностей и фикса проблемы зависания терминала.
А не могли бы разработчики QUIK посмотреть, что происходит в этот момент в lua и терминале, и описать, что что конкретно там происходит? Интересно узнать.
Zoya Skvorcova написал: Светлана Серикова , Добрый день. Есть возможность запускать рабочее место QUIK из командной строки с ключом –clear . Для этого нажмите правой клавишей мыши по ярлыку и выберите свойства. В закладке Ярлык в поле Объект добавьте параметр -clear Строка должна выглядеть примерно так "C:\Квик\QUIK Junior\info.exe -clear"
Если ноутбук гарантийный и внезапно сломался, то выполнить указанную выше команду ДО отправки в мастерскую невозможно. Так что проблема с безопасностью действительно есть.
Цитата
А я в таком случае винчестер дома оставляю.
Ноутбук гарантийный, как было сказано в первом посте, так что вынимать винчестер означает потерять гарантию.
_sk_ написал: Потом приходит следующая сделка, а она, как оказалось, относится к предыдущей 5-минутке. Будет ли вызвана функция OnCalculate() для FEES с предыдущим значением I? Если нет, то окажется, что свеча подменилась, а мы не в курсе. Если да, то это нарушение "обновления посередине".
Вопрос о том, как поведёт себя QUIK, когда по одному инструменту уже начал рисоваться новый бар, а по другому инструменту - вдруг приходит сделка по предыдущему бару? У меня есть подозрения, что Квику без разницы когда и что он получил. Он просто нарисует, то что пришло.
Нужно, чтобы разработчики пояснили, что будет. Неплохо бы в явном виде опубликовать стандарт, про который Сергей Горохов говорил.
на примере индикатора RSI подскажите пожалуйста что нужно изменить, чтобы код работал на новой версии КВИКа?
Попробовал написать индикатор RSI, в котором используется простое сглаживание по окну (не экспоненциальное, как в коде QUIK) и не используется data source. Получился вариант, приведённый ниже.
Предлагаю обсудить, правильный он или нет, а также то, можно ли как-то этот пример улучшить.
Код
--
-- Реализация индикатора RSI_Simple.
--
Settings = {
Name = "RSI_Simple",
period = 14,
priceType = "Typical", -- Open, High, Low, Close, Volume, Median, Typical, Weighted
line = {
{ Name = "RSI_Simple", Type = TYPE_LINE, Color = RGB(255, 0, 0), },
}
}
function Init()
func = rsiSimple()
return #Settings.line
end
function OnCalculate(index)
return func(index, Settings)
end
local function getPrice(i, priceType)
local s = priceType and string.upper(string.sub(priceType, 1, 1)) or "C"
if s == "O" then
return O(i)
elseif s == "H" then
return H(i)
elseif s == "L" then
return L(i)
elseif s == "C" then
return C(i)
elseif s == "V" then
return V(i)
elseif s == "M" then
return (H(i) + L(i)) / 2
elseif s == "T" then
return (H(i) + L(i) + C(i)) / 3
elseif s == "W" then
return (O(i) + H(i) + L(i) + C(i)) / 4
else
return C(i)
end
end
function rsiSimple()
local window = {} -- окно с рядом цен, по которым строится индикатор
local from = 1 -- индекс начала данных в окне
local to = 0 -- индекс конца данных в окне (если to < from, данных нет)
local lastIndex = 0 -- номер свечи, имеющей цены, при последнем вызове OnCalculate()
local sumUp = 0 -- сумма всех положительных изменений цен за исключением приращения на формирующемся баре
local sumDn = 0 -- сумма всех отрицательных изменений цен за исключением приращения на формирующемся баре
local lastIndicatorValue -- значение индикатора при последнем вызове OnCalculate()
return function(index, settings)
local period = 14
local priceType = "Typical"
if settings then
period = settings.period or period
priceType = settings.priceType or priceType
end
if index == 1 then
window = {}
from = 1
to = 0
lastIndex = 0
sumUp = 0
sumDn = 0
lastIndicatorValue = nil
end
if CandleExist(index) then
local currPrice = getPrice(index, priceType)
if index ~= lastIndex then
-- Новая свеча
if to - from + 1 == period + 1 then
-- Окно заполнено, т.е. имеет длину period + 1, нужно удалить первый элемент и уменьшить суммы
local delta = window[from + 1] - window[from]
if delta > 0 then
sumUp = sumUp - delta
elseif delta < 0 then
sumDn = sumDn - (-delta)
end
window[from] = nil
from = from + 1
end
-- Учёт предыдущей свечи как сформированной, внесём вклад в суммы
if to - 1 >= from then
local delta = window[to] - window[to - 1]
if delta > 0 then
sumUp = sumUp + delta
elseif delta < 0 then
sumDn = sumDn + (-delta)
end
end
to = to + 1
end
lastIndex = index
-- Новая свеча или обновление старой свечи
window[to] = currPrice
if to > from then
local prevPrice = window[to - 1]
local delta = currPrice - prevPrice
local sumUp = sumUp
local sumDn = sumDn
if delta > 0 then
sumUp = sumUp + delta
elseif delta < 0 then
sumDn = sumDn + (-delta)
end
if to - from + 1 == period + 1 then
lastIndicatorValue = (sumUp + sumDn <= 0) and 50 or (100 * sumUp / (sumUp + sumDn))
else
lastIndicatorValue = nil
end
else
lastIndicatorValue = nil
end
end
return lastIndicatorValue
end
end
Sergey Gorokhov написал: Небольшой эксперимент покажет что индикатор по FEES даже не заметит появления значений по SRH7. Связано это с тем что по FEES изменений не было. В случае если в одном окне установить график по нелеквиду и по активному инструменту, Вы увидите что OnCalculate сработает по нелеквиду и CandleExist покажет false на пропущенных свечках только, после того как на нелеквиде появится нормальное значение.
Хорошо. Этот момент неплохо бы отразить в документации, чтобы пользователям было понятно без дополнительных экспериментальных исследований.
Возможно, что я неточно выразился. Имелось в виду, что упорядочивание сделок в квике в таблице всех сделок таково, что время сделки не является монотонно возрастающим. Пример я привёл в своём посте.
Квик как-то должен справляться в таких случаях, объединяя потоки сделок с разных рынков. Хотелось узнать у разработчиков, как именно это происходит в указанном мною случае. А они пока молчат.
обновления посередине быть не может, если Вы об этом.
Хорошо, если это так на самом деле. Только подтвердите, что в описанном ниже случае это тоже так.
Известно, что в данных об обезличенных сделках на фондовом и срочном рынке время задаётся разными часами, которые иногда могут разойтись на несколько миллисекунд. См., например, сегодняшнюю таблицу за 2-х секундный период 10:03:21 -- 10:03:22:
Допустим, что подобное произошло бы в 10:04:59 -- 10:05:00, а в терминале наложены графики SRH7 и FEES. Когда пришла сделка по SRH7, то началась новая 5-минутка. По идее, в этот момент квик может начать вызывать OnCalculate() для пары графиков, в результате видим, что на FEES случилась пустая свеча с T(I) = 10:05.
Потом приходит следующая сделка, а она, как оказалось, относится к предыдущей 5-минутке. Будет ли вызвана функция OnCalculate() для FEES с предыдущим значением I? Если нет, то окажется, что свеча подменилась, а мы не в курсе. Если да, то это нарушение "обновления посередине".
По идее, наиболее корректным действием было бы пересчитать весь индикатор, начиная с индекса 1.
А теперь вопрос: как реализована обработка таких ситуаций в QUIK?
Я понимаю, что это очень редко бывает, но всё равно интересно.
Уже сейчас можно сделать вторую нумерацию. Просто добавив переменную счетчик, которая будет увеличиваться на +1 при CandleExist
ОК.
Я правильно понимаю, что индексы-аргументы OnCalculate() от одного вызова к другому: * либо повторяются; * либо увеличиваются на 1; * либо сбрасываются в 1.
Т.е., например, последовательности ..., 100, 101, 102, 101, 102, 103, ... быть не может?
Ответ на этот вопрос неплохо бы в документацию добавить.
Интересно. Это совсем рушит логику кода из INDICATORS.ZIP.
Наверное, нужен некий способ понять, какому индексу J в DS соответствует индекс I на баре, для которого вызван OnCalculate.
Есть предложение вызывать OnCalculate() с двумя параметрами: номер индекса I бара на графике и номер индекса О в DS. Если бар пустой, пусть J будет nil. Или обеспечить функции трансляции I -> J, J -> I.
Есть у кого-нибудь опытного в индикаторостроении мысли на эту тему? Как сделать удобнее?
Пока кажется, что при вычислении каждого индикатора пользователю нужно будет сначала решать проблему компрессии (выбрасывания пустых баров), а потом уже вычисления индикатора. Несколько неудобно получилось, хоть и более гибко для терминала.
Просьба ответить на мои вопросы из двух предыдущих постов. Если в документации неправильный пример, его точно надо оттуда убирать и, может быть, заменять на правильный.
Ещё вопрос о правильности примера в документации QLua, содержащегося в разделе с описанием функции CandleExist. Там есть пример, вычисляющий MovingAverage. Может быть, я чего-то не понимаю, но OnCalculate(index) может вызываться с одним и тем же индексом index несколько раз подряд на формирующейся свече. Кажется, что в этом случае в примере из документации среднее будет неправильным.
Функции O(I), H(I), L(I), C(I), V(I) в качестве индекса I используют порядковый номер свечи на графике, включая "дыры".
Вопрос:data source ds имеет ту же нумерацию ds:O(I), ds:H(I), ds:L(I), ds:C(I), ds:V(I) или здесь индекс I относится к источнику данных, где нет "дыр" между свечками?
В файловом архиве имеется файл ftp://ftp.quik.ru/public/INDICATORS.zip, который содержит код индикаторов технического анализа. Этот код новички могут рассматривать как пособие по созданию собственных индикаторов.
Однако, в связи с нововведением
Цитата
Изменен вывод информации функциями O, H, L, C, V, T по свечкам, сформированным на пустых интервалах. Теперь, для таких свечек, функция T возвращает время интервала, а функции O, H, L, C, V возвращают nil. Для корректной проверки существования свечи на графике добавлена новая функция CandleExist(). Подробное описание приведено в п. 7.2.5 Руководства пользователя Интерпретатора языка Lua.
в терминале QUIK 7.7, теперь на графиках бывают отсутствующие свечи со значениями nil в качестве цен. Соответственно, предложенные индикаторы перестают работать, т.к. раньше такого не было.
Не могли бы разработчики скорректировать исходный код этих индикаторов, чтобы они учитывали особенность нововведения?
У нас была похожая проблема: с началом торговой сессии останавливалась трансляция данных в таблицу обезличенных сделок. Решилась путём обновления серверного ПО (версия сервера QUIK от 7 декабря, кажется). Действительно, это может сделать только брокер.
Временное решение нашей проблемы было такое: в 10:00 МСК разорвать соединение с сервером и установить его снова.