Средства разработки многопоточных скриптов в QUIK., OS_Quesha, свидетельство регистрации в Роспатенте № RU 2020612905. Бесплатная для некоммерческого использования.
Владимир написал: дерево-то можно, а вот граф произвольного вида - уже нельзя
С этим не согласен. Можно. Пакет сереализации, предложенный мною в данной ветке ранее, упаковывает в строку (распаковывает) таблицу Lua произвольной структуры (деревья, сети, цикличесие графы и т.д.).
TGB, А Вы это пробовали когда-нибудь РЕАЛЬНО это сделать? Я практически всю жизнь занимался сложными базами данных, у меня есть две утилитки, которые так и называются: RelToTree и TreeToRel, и я прекрасно знаю, что такое "упаковывать в строку (распаковывать) таблицу (!!!) Lua произвольной структуры" - в частности, на терабайтных базах и, в особенности, на сильно перевязанных базах (иногда с миллионами рёбер на узел графа, да ещё и разных измерений). То, что у Вас "граф" и "таблица" чуть ли не синонимы, говорит о том, что рёбра Вы представляете в виде примитивной таблицы смежности, с которой работать практически невозможно. Я уже не говорю про ошибки, которые имеют пакостную тенденцию накапливаться и плодить ошибки наведённые. Но даже без этого Ваша схема не будет работать НИКОГДА!
TGB, Что "это" Вы "делали не один раз"? Вы можете это сделать - нет, не для схемы транспорта Москвы, а хотя бы вот для этой, достаточно примитивной задачи торговли? Хотя бы в усечённом виде, хотя бы в том, который я описал: счета-валюты-тикеры-заявки-сделки-свечи? Как доступ к элементам получать будете? Как будете, скажем, определять текущее состояние рынка в евровой зоне? Какая вообще будет структура данных - та самая, которую Вы собрались упаковывать-распаковывать?
Это я сказал (профессионализм - это шоры) много лет назад. Цитата точная.
Меня не интересует, что Вы думаете, и я не собираюсь гадать на кофейной гуще. Я задал вопрос: "Насчёт таблицы смежности я прав"? Вы способны на него ответить [Y/N]?
TGB, Я очень редко читаю невнимательно - Вы НЕ ответили на мой вопрос, Вы всего лишь сказали, что Вы ДУМАЕТЕ. А вопрос этот принципиальный: либо Вы ЗНАЕТЕ другой способ представления графа, либо Вы его НЕ знаете (вариант "знаете, но используете этот" я отбрасываю, как абсолютно нереальный).
Это не "свое (особое) мнение" - это ТЕХНОЛОГИЯ! Причём не только представления графа, но и его МОДИФИКАЦИИ - а это "две большие разницы"!
Я почему схему транспорта Москвы упомянул? Однажды мой друг попросил её сделать на базе схем движения пассажирского транспорта, представленных на каком-то сайте администрации Москвы (там было десятка два мелких баз, доступных для скачивания). Я всё это дело объединил, определил "станции пересадок" (по координатной близости остановок) трёх видов: до 10 метров (фактически та же остановка, где можно пересесть на другой автобус или трамвай), до 50 метров (чуть отнесённая) и до 200 метров (это обычно выходы из метро). навесил на это дело территориальные деревья (улицы, районы, округа) и тематические (по названиям остановок) - школы, больницы, университеты, кафе, рестораны, магазины (продовольственные, винные, мебельные и прочие), парки, бассейны, музеи, кинотеатры, и прочая, и прочая, и прочая Не сделал только схему движения автомобилей или пешеходов (перекрёстки ведь тоже "станции пересадок" с улицы на улицу!) - исходных данных в тех базах было маловато, тут уже нужна карта вроде OpenStreetMap, Сделал, и говорю: "В каком формате тебе всю эту кухню выдать? JSON? Какой, нафиг, JSON? У меня нет никаких таблиц, у меня многомерный граф! Формат давай!" А вот формата он так и не сумел придумать - и это только для чтения и представления ПОДГОТОВЛЕННОЙ базы, а не для её модификации! А что может Ваша несчастная "сереализованная таблица Lua"? ДА НИЧЕГО!
Владимир написал: Вы ЗНАЕТЕ другой способ представления графа, либо Вы его НЕ знаете (вариант "знаете, но используете этот" я отбрасываю, как абсолютно нереальный).
У меня есть, смутное, подозрение, что вы слабо представляете, что мне известно о вариантах представления графов. На самом деле, мне стал не интересен этот диалог. Но я ставлю 99 против 1, что последний комментарий будет ваш Сдаюсь
TGB, Это не диалог - это два монолога - Вы же не отвечаете на вопросы. Так что мне НИЧЕГО не известно о Ваших вариантах представления графов. А соревноваться мне с Вами не в чем.
Средства обеспечения устойчивости роботов, создаваемых в OS_Quesha Устойчивость (к сбоям аппаратуры, к ошибкам программ и т.д.) торговых роботов является одним из важнейших требований к ним. Программным средством обеспечения ус-тойчивости является контрольная точка. Контрольная точка программы это значения ее переменных (состояние программы), возникшие при ее функционировании и сохраненные в энергонезависимой памяти для возможности продолжения работы этой программы, начиная с сохраненного состояния, после ее перезапуска по любой причине (сбой аппаратуры, программная ошибка, и т.д.). В идеале, реализация контрольных точек должна быть такой, чтобы работа программы, при включенной контрольной точке, с перезапусками, возникающими в ней по любой причине, функционально не отличалась бы от ее работы без перезапусков. Реально, этот идеал недостижим, и, используя контрольные точки, можно только уменьшить вероятность нарушения функционирования программы при ее перезапусках. Предположим, что только те сбои программы, моменты, возникновения которых попадают в интервалы времени фиксации ее контрольных точек, могут нарушать, из-за неопределенности результата такой фиксации, возможность продолжения ее функционирования. Тогда вероятность нарушения функционирования программы с контрольной точкой пропорциональна длительности фиксации ее контрольных точек. Поэтому в OS_Quesha разработаны специальные решения по уменьшению длительности фиксации контрольных точек. Для обеспечения контрольных точек многопоточных приложений в OS_Quesha используются: 1) служебная папка хранения состояния системы stateOS, в которой размещаются файлы для хранения этого состояния; 2) пакет сереализации таблиц Lua; 3) функции работы с состоянием системы. Файлы хранения состояния текстовые и могут при необходимости анализироваться в любом редакторе. Содержимое этих файлов это таблицы состояний функций, ведущих свои контрольные точки, записанные в соответствии с синтаксисом QLua. Рекомендуется состояния функций, работающих в разных потоках, фиксировать в различные файлы состояния. Файлы состояния, имена которых начинаются с символа @, сохраняют инкрементные состояния. Такие состояния могут быть использованы в случаях больших объемов сохраняемых в них данных. Они обеспечивают быструю запись в их файлы, только возникающих в них изменений. Таким образом, в OS_Quesha обеспечивается независимость длительности фиксации контрольных точек от их размеров. Фиксация контрольных точек функций потобезопасная и выполняется в отдельном потоке. Например, фиксация таблицы состояния размером в 100 элементов (строки длинной не более 400 символов и числа) выполняется за ~1 млсек. Для создания файла состояния, удаления, записи в него таблицы состояния, чтения состояния при перезапуске OS_Quesha, используются основные функции: 1) Очистить / реорганизовать файл состояния; 2) Запись (создание) контрольной точки в файл; 3) Чтение файла контрольной точки. Для управления режимом запуска OS_Quesha в ее глобальных настройках существует параметр Restore_OS_QLua. В этом параметре используются два младших разряда. Нулевой разряд: 0 - запуск (без учета истории функционирования); 1 - перезапуск (продолжение работы). Первый разряд: 0 - не сжимать файлы инкрементных состояния OS при пе-резапуске; 1 – сжимать. Операция сжатия файлов инкрементных состояний обрабатывает, в момент перезапуска OS_Quesha, список команд изменений их состояний и записывает в них, получившиеся итоговые таблицы состояний. В шаблоне TS_QUIK.lua демонстрируется использование инкрементной контрольной точки при обработке лимитированных заявок для хранения истории их состояний с учетом событий, возникающих в QUIKе при обработке этих заявок. В описании модуля сереализации, представленного ранее в данной ветке, приведена общая схема реализации контрольной точки циклических функции (а-ля main), исполь-зуемых в OS_Quesha.
Так как появился QUIK 9.1, то коды и документация OS_Quesha обновлены и в текущий момент времени работоспособны для версий 7<= QUIK <= 9.1: https://cloud.mail.ru/public/2zn2/2tZgedUu4
Дополнительно к тому, что было написано в моих предыдущих комментариях относительно OS_Quesha. 1. То, что написано в них, не относится к начальному «освоению» QLua. Это может оказаться интересным, наверное, тем, кто в этом «поварится» некоторое время, после которого проявятся те проблемы, о которых я пишу. 2. Моя позиция относительно любых средств разработки программ: они должны облегчать жизнь пользователя таких средств. Если есть возможность обеспечить такое, то пользователя надо, освобождать от сложных проблем параллельного программирования или обеспечения надежности разрабатываемых программ. 3. OS_Quesha, обеспечивая многопоточность скрипта, написанного на QLua, полностью (если не используются общие модифицируемые в нескольких потоках данные, для работы с которыми есть средства для «продвинутых» разработчиков) освобождают разработчика таких скриптов от проблем параллельного программирования и обеспечивает их надежность. 4. В продолжение моего комментария, в котором описаны средства обеспечения надежности скриптов QLua с использованием контрольных точек. Известными проблемами любых программ являются: 1) их возможные блокировки при обращении к разделяемым ресурсам (с синхронизацией доступа к ним); 2) их возможные зацикливания (из-за ошибок в них); 3) «утечка» памяти (из-за ошибок в них). Не существует универсальных, автоматических решений этих проблем. Уже хорошим решением может быть: ранняя диагностика таких проблем и это обеспечивается в OS_Quesha. В OS_Quesha выполняется контроль: 1) блокировок ее потоков; 2) зацикливания ее потоков; 3) утечки памяти QLua; 4) утечки памяти самого QUIK. Так как нормальные автоматические обработки описанных выше ситуаций мне не известны (они, как правило, связаны с существенными ошибками в скрипте, или QUIK), то по ним выдается четкая диагностика, а далее есть два варианта: продолжение работы скрипта (с продолжением выдачи упомянутой диагностики) или его перезапуск (возможно с перезапуском QUIK). В обобщенной классификации, OS_Quesha является «форком QLua», и в нем нет тех проблем, которые описаны в моем комментарии, относительно QLua, в соседней ветке «Отладка QUIK 8.13»; https://forum.quik.ru/messages/forum10/message57036/topic6356/#message57036
Реализация очередей в OS_Quesha. 1. Кроме ранее описанного контроля, в системе выполняется периодический контроль текущих размеров всех ее очередей. При создании каждой очереди задается ее предельно-допустимый размер. Если текущий размер, какой то очереди превышает 75% предельно-допустимого, в системе начинает выдаваться об этом сообщение. 2. Существенная особенность построения очередей в OS_Quesha состоит в том, что они строятся на таблицах, в которых после их создания, нет вставок или удалений их полей (записей). В процессе работы с очередями изменяются только значения существующих полей, обеспечивающих запись/чтения этих очередей. Структура таблиц очередей «заморожена». Это обеспечивает в многопоточном режиме возможность эффективной синхронизации работы с очередями на уровне их полей, а не на глобальном уровне самих очередей. Далее выложен работающий код реализации очередей с учетом выше написанного для частного случая, когда один поток в нее пишет, а другой читает (!не допустимы чтения или записи в нескольких потоках):
Код
---- Реализация циклических потокобезопасных очередей без синхронизации для случая, когда один поток в нее пишет, а другой читает (!не допустимы чтения или записи в нескольких потоках)------
local Queue_safe = {
--- size_Queue - размер очереди ----
new = function (self, size_Queue)
local Queue = {}
local cycl = {} -- таблица-массив хранения элементов очереди
for i =1, size_Queue do
cycl[i] = 0
end
Queue.cycl = cycl
Queue.QueueLength = size_Queue --- размер очереди ---
Queue.RecordPointer = 1 --- указатель записи (изменяется только "писателем") ---
Queue.ReadingPointer = 1 --- указатель чтения (изменяется только "читателем") ---
Queue.written_down = 0 --- количество записанных элементов ---
Queue.read = 0 --- количество считанных элементов ---
return setmetatable(Queue, {__index = self}) --- для переключения на Queue_safe при обращение в созданной таблице к push, pop, size ----
end,
--- Записываемое в очередь значение не может быть nil --
-- Результат: 0 - запись выполнена; 1 - запись не выполнена (нет места)
push = function (self, v)
if v == nil then error(' !!! В очередь нельзя записывать nil ') end
if self.written_down - self.read >= self.QueueLength then ----- некуда писать ----
return (1)
end
local cycl = self.cycl
local pwt= self.RecordPointer
cycl [pwt] = v
local pwf = pwt +1
if pwf > self.QueueLength then
pwf=1
end
self.RecordPointer = pwf --- следующая позиция для записи (возможно занятая) --
self.written_down = self.written_down + 1
return (0)
end,
--- Два результата: 1) элемент или nil; 2) признак: 0 - очередь после чтения пуста; > 0 - количество непрочитанных элементов; -1 - очередь пуста в момент чтения;
pop = function (self)
local n = self.written_down - self.read
if n == 0 then
return nil, -1 --- нет данных
end
local cycl = self.cycl
local prt= self.ReadingPointer
local v = cycl [prt]
cycl [prt] = 0 --- чтобы не было "висячих" ссылок на ссылочные объекты ----
prt = prt +1
if prt > self.QueueLength then
prt = 1
end
self.ReadingPointer = prt
self.read = self.read + 1
return v, n - 1
end,
size = function (self)
return self.written_down - self.read
end
}
----------------------------------------------------------------------
------ Тесты -----
local T
local v
--[[
-- 1. Этот фрагмент (использование потокобезопасных функций QLua) (100 000 записей и чтений) выполняется за ~3560 милисекунд ---
T = {}
for j = 1, 100 do
for i = 1, 1000 do --- запись в очередь
table.sinsert (T, 'sd')
end
for i = 1, 1000 do --- чтение из очереди
v = T[1]
table.sremove (T, 1)
end
end
do return end ------
-----------------------------------------------------------------
--]]
-- 2. Этот фрагмент (использование Queue_safe) (100 000 записей и чтений) выполняется за ~55 милисекунд ---
T = Queue_safe:new(1200)
for j = 1, 100 do
for i = 1, 1000 do --- запись в очередь
T: push('sd')
end
for i = 1, 1000 do --- чтение из очереди
v = T: pop()
end
end
--------------------------------------------------------------
Относительно выложенного кода можно отметить следующее. 1. Это сильно упрощенный, работающий вариант реализации очередей, которые используются в OS_Quesha. 2. Особенностью этих очередей, при их создании, является необходимость задания их предельного размера. При записи в очередь, выдается признак успешности этой записи, либо отсутствия места в очереди. 3. Работа с создаваемыми очередями потокобезопасна без синхронизации при их использовании в QLua между колбеками и main. 4. Скорость выполнения операций запись/чтение не зависит от текущей длины очередей (в отличие от очередей, реализуемых с помощью table.sinsert и table.sremove, в которых скорость операций с увеличением текущей длины очереди, резко падает).
TGB, Что такое "предельно допустимый размер" и на кой он нужен? Лично у меня все очереди всегда были "безразмерные". Стек очередей - да, контролировался, и размер его задавался при компиляции - ну так это же стек! Он элементарно может переполниться, например, при неправильном рекурсивном вызове. А очереди-то чего сделается?
Про построение очереди на таблицах тоже ни разу не слышал. У меня были очереди событий, объектов, структур, неоднородных элементов, но таблицы-то здесь каким боком? Таблица по определению имеет два измерения, а очередь - одно. Не этим ли вызвана "«заморозка»?
Ситуации, когда один поток в нее пишет, а другой читает (в моём случае это были не просто потоки, а отдельные процессоры, причём любой из них мог как читать, так и писать) разрешается (по крайней мере, у нас было именно так) через ОЗУ двойного доступа. При этом каждый процесс[ор] должен соблюдать некий протокол взаимодействия, и в этом случае все проблемы с синхронизацией уйдут в небытие. К тому же, у нас все эти процессоры сидели на общей шине - там требуется примерно то же самое, только намного сложнее организованное.
Ну и, наконец, вся задача организации торговли прикладная с головы до пят, и любые попытки привнести сюда системные штучки-дрючки - тем более, глубоко системные, как в данном случае, ни к чему хорошему не приведут.
Владимир написал: вся задача организации торговли прикладная с головы до пят, и любые попытки привнести сюда системные штучки-дрючки - тем более, глубоко системные, как в данном случае, ни к чему хорошему не приведут.
Очень филосовское замечание Где вы видите системные штучки? Код написан на чистом Lua (даже циклов нет ). --- Я не понял ваших замечаний. Что в коде не так? Здесь выложен конкретный код, который, возможно, пригодится для устранения ситуации, описанной в комментарии: https://forum.quik.ru/messages/forum10/message54811/topic5823/#message54811 или для варианта модификации QLua, описанного в п.2 комментария: https://forum.quik.ru/messages/forum10/message57220/topic5823/#message57220 и освобождающего скриптера от проблем параллелизма в QLua, Этот код может оказаться интересным и еще кому-нибудь. При описании кода я коротко отметил его существенную особенность, Для кого-то из читателей будет понятно, почему это сделано так. Что в этом плохого? Вы же можете пользоваться своими "безразмерными" прикладными очередями или, например, использовать безразмерную (очень простую) очередь, код которой приведен в описании упомянутой мною ситуации. Но скорее всего, вам не нужны никакие очереди. Ну и замечательно.
TGB, Ну, во-первых, на код я вообще не смотрел - алгоритмист я. А алгоритмически понятия "синхронизация" или "очередь", "поток", "процесс" именно системные. Во-вторых, чуть не все Ваши посты идут с упоминанием OS_Quesha, а это, как ни крути, операционная СИСТЕМА.
Я и сам системщик - подавляющее большинство написанного мною кода именно такое. Но здесь я прикладник, и знать не знаю ни о каких потоках, очередях и прочей лабуде. Мне нет никакого дела до "проблем параллелизма в QLua" - мой скрипт считает, что он один такой работает, и про потоки и прочее знать ничего не знает - для него есть только прерывания от таймера, клавы или мыши.
Да, здесь мне не нужны никакие очереди - они пригодились бы при программировании в объектах или событиях, для организации сложного диалога. Но здесь всё просто, как трусы по рубль сорок.(с)
Владимир написал: Мне нет никакого дела до "проблем параллелизма в QLua" - мой скрипт считает, что он один такой работает, и про потоки и прочее знать ничего не знает - для него есть только прерывания от таймера, клавы или мыши.
Думать вы так, конечно, можете, а что же вы иногда жалуетесь на непонятные "падения" вашего скрипта? А может быть и кто то еще получает непонятные ситуации? Как системщик вы, наверное, должны понимать, что вам (нам) не обеспечена более-менее надежная среда разработки и исполнения скриптов. Вы что против того, чтобы надежность QLua повышалась? Если нет, то разработчик QUIK должен разбираться, с потоками, синхронизацией и т.д., часто, скрытыми API QUIK, но влияющими работу скриптов. И почему бы, если у кого есть такая возможность, не посодействовать ему, в этом, для нашей пользы?
TGB, Да как же не жаловаться? Для меня в своё время было просто шоком узнать, что интерпретируемый код способен подвесить Квик! "Как системщик я должен понимать", что этого не может быть потому, что не может быть никогда! И мне противно писать свои "компенсаторы" на системные глюки. Я знаю некоторые места: например, при ручной торговле через скрипт Квик иногда подвисает, потому как я подаю заявку прямо из обработчика событий меню - всё никак руки не доходят перенести это дело в мейн. У меня на OnStop стыдно смотреть - у меня там и лог, и дамп состояния, и закрытие таблиц, и чёрта лысого только нет. А что делать? Я не знаю, и знать не хочу, почему в таблицах иногда пропадает текст - слава богу, научился лечить. Но это всё НЕ МОИ ПРОБЛЕМЫ, блин! Кроме того, есть вещи, которые я в принципе не могу сделать сам - не могу вот достучаться программно до своего портфеля. Техподдержка говорила, что таблица "клиентский портфель" недоступна вообще никак - во радость! Осталась надежда, что смогу прочитать хотя бы "позиции по инструментам", да и то слабая. А свечи? Это же уму непостижимо! Мне нужно порядка 20 тысяч свечей - и что делать? Ладно, "мелочь" я считаю сам, но более тяжёлые (от 15 минут и выше) хочу получать с сервера. И что, прикажете 7-8 тысяч графиков заказывать? На каждую сраную свечу свой график? Да здесь не то что "не обеспечена более-менее надежная среда разработки и исполнения скриптов" - здесь вообще ничего не обеспечено. Но торговать (с ужимками и прыжками) всё-таки можно - и на том спасибо!
Владимир написал: TGB, Да как же не жаловаться? Для меня в своё время было просто шоком узнать, что интерпретируемый код способен подвесить Квик! "Как системщик я должен понимать", что этого не может быть потому, что не может быть никогда! И мне противно писать свои "компенсаторы" на системные глюки. Я знаю некоторые места: например, при ручной торговле через скрипт Квик иногда подвисает, потому как я подаю заявку прямо из обработчика событий меню - всё никак руки не доходят перенести это дело в мейн. У меня на OnStop стыдно смотреть - у меня там и лог, и дамп состояния, и закрытие таблиц, и чёрта лысого только нет. А что делать? Я не знаю, и знать не хочу, почему в таблицах иногда пропадает текст - слава богу, научился лечить. Но это всё НЕ МОИ ПРОБЛЕМЫ, блин! Кроме того, есть вещи, которые я в принципе не могу сделать сам - не могу вот достучаться программно до своего портфеля. Техподдержка говорила, что таблица "клиентский портфель" недоступна вообще никак - во радость! Осталась надежда, что смогу прочитать хотя бы "позиции по инструментам", да и то слабая. А свечи? Это же уму непостижимо! Мне нужно порядка 20 тысяч свечей - и что делать? Ладно, "мелочь" я считаю сам, но более тяжёлые (от 15 минут и выше) хочу получать с сервера. И что, прикажете 7-8 тысяч графиков заказывать? На каждую сраную свечу свой график? Да здесь не то что "не обеспечена более-менее надежная среда разработки и исполнения скриптов" - здесь вообще ничего не обеспечено. Но торговать (с ужимками и прыжками) всё-таки можно - и на том спасибо!
Попробую дать несколько советов утопающим: ------------------------- Если пишите робота в индикаторе, то Вы получаете примерно каждый тик вне зависимости от выбранного интервала Поэтому можете сформировать свечи с любым интервалом затрачивая примерно один условный оператор и пару-тройку арифметических операций на каждый из интервалов для получения текущей свечи т е если Ваш индикатор работает на интервале 1 минута, то все остальные выше 1 минуты можете сформировать сами ничего дополнительно не заказывая. ------------------------------ Если работаете в скриптах, то проблема решается аналогично. Заказывайте лишь младший интервал. остальные считаете с затратой два-три оператора на интервал на свечу. ----------------------------- многопоточность реализуется сравнительно просто. каждый скрипт - это отдельный поток. делаете на каждый колбек свой скрипт и получаете много много потоков В каждом колбеке сохраняете данные в мап файле и получаете доступ к данным этого скрипта из других скриптов. ----------------------- Таким способом можете строить своего робота на питоне либо Luajit.
nikolz, Спасибо, родной - советы ОТ ВАС поистине бесценны!
1. Плевать мне на индикаторы - у меня их нет, не было, и не будет.
2. У меня нет выбранных интервалов - я считаю ПО ВСЕМ интервалам сразу. Минимальный интервал у меня 15 секунд, и недельные, скажем, свечи оттуда не получить никак, не говоря уже про "пару-тройку арифметических операций".
3. Многопоточность действительно "реализуется сравнительно просто" - я много раз это делал. А вот "каждый скрипт - это отдельный поток" - это кретинизм. У меня был, есть и будет ОДИН скрипт на все случаи жизни.
4. Я писал и буду писать только на Lua - токо вот питонов здесь не хватало!
Владимир написал: nikolz, Спасибо, родной - советы ОТ ВАС поистине бесценны! ::
1. Плевать мне на индикаторы - у меня их нет, не было, и не будет.
2. У меня нет выбранных интервалов - я считаю ПО ВСЕМ интервалам сразу. Минимальный интервал у меня 15 секунд, и недельные, скажем, свечи оттуда не получить никак, не говоря уже про "пару-тройку арифметических операций".
3. Многопоточность действительно "реализуется сравнительно просто" - я много раз это делал. А вот "каждый скрипт - это отдельный поток" - это кретинизм. У меня был, есть и будет ОДИН скрипт на все случаи жизни.
4. Я писал и буду писать только на Lua - токо вот питонов здесь не хватало!
Если хотите могу показать как оттуда получить свечи и реализовать "пару-тройку арифметических операций". Для этого покажите код где вы работаете со свечами в 15 секунд. ---------------- Относительно других языков я написал Вам для примера. Не хотите изучать английский - говорите а Англии на русском. или по словарю. Это Ваши проблемы. Спасение утопающих-дело рук самих утопающих. Только непонятно, что Вы на форуме сопли размазали .
В качестве справки: Для тестирования скорости обработки колбеков с использованием Event Делаю вот такой тест: (настройку скрипта опускаю) ---------------- function main() while true do mat.waitEv(Event); t=mat.Stop(); messege(tostring(t)); end --------------- function OnParam(class,sec) if class=="SPBFUT" and sec=="SRU1" then tbid=getParamEx(class,sec,"bid") mat.wr(fout,tbid.param_image)); mat.setEv(Event); end --------------------------------- Суть теста следующая поток main остановлен и не потребляет процессор пока не произойдет прерывание колбека ------------------------ В колбеке стартует таймер, пишется в map-file параметр и сбрасывается Event. ---------------------------- При этом запускается поток main и в нем останавливается таймер и выводится время реакции потока на колбек. -------------------- В итоге запаздывание реакции потока main на колбек не более 20 микросекунд.
В моем комментарии https://forum.quik.ru/messages/forum10/message57220/topic5823/#message57220 в п.2 было описано предложение по добавлению интерфейса работы с событиями QUIK. Ниже выложен код модуля реализации этого предложения на «чистом» Qlua, а также шаблон использования этого модуля. В этом шаблоне демонстрируется схема обработки событий фондового рынка и событий таблиц QUIK. Для подключения модуля к шаблону его надо сохранить в файле под именем even_handling_module.lua в папку хранения кода запуска QUIK (info.exe). Код модуля и шаблона можно использовать свободно. При его распространении желательна ссылка на меня. Описание использования модуля приведено в его коде и коде шаблона, описывающего схему обработки событий QUIK. ---- Код модуля:
Код
--[[ TGB ---- Модуль реализации обработки событий QUIK с использованием очередей событий фондового рынка и событий таблиц QUIK ---
Краткая спецификация модуля.
1. Реализуется схема взаимодействия main с колбеками через две потокобезопасные эффективные очереди, одна из которых обслуживает колбеки
фондового рынка, а вторая, колбеки событий таблиц QUIK, созданных скриптером;
2. При работе обработке колбеков есть две функции: <функция подписки на события фондового рынка>
и <функция подписки на события пользовательских таблиц >; в этих функциях скриптер может, в виде списка (в таблице) подписаться на события
в соответствии с существующими именами колбеков; реализация подписки сведена к автоматическому созданию (скрытых) от пользователя
функций колбеков, записывающих свои параметры с добавлением «от кого параметры» в соответствующие очереди;
3. Для работы с очередями по новой схеме есть две функции чтения соответственно очередям;
при чтении очередей в считываемой таблице передаются: <имя события>, <время записи в очередь>, <параметры в том виде, как они описаны, в существующих колбеках>.
При работе по этой схеме, QLua для скриптера становится однопоточным и снимаются многие сложные проблемы.
----
!! Колбеки OnInit и OnStop обрабатываются как обычно.
-------------------------
--]]
---- Функции работы с очередями (выложенные на форуме Старателем) ------
--- При использовании между потоком колбеков и потоком main потокобезопасные
local Queue = {
new = function (self)
return setmetatable({first = 1 , last = 0 }, {__index = self})
end ,
push = function (self, v)
local last = self.last + 1
self[last] = v
self.last = last
return last
end ,
pop = function (self)
local first = self.first
if first > self.last then return nil end
local v = self[first]
self.first = first + 1
self[first] = nil
return v
end ,
size = function (self)
return self.last - self.first + 1
end
}
--------- Создание очередей-----------
local Queue_QUIK = Queue:new()
local Queue_QUIK_tbl = Queue:new()
----- Функции чтения очередей -------
local function Queue_evn_QUIK() return Queue_QUIK: pop() end
local function Queue_evn_QUIK_tbl() return Queue_QUIK_tbl: pop() end
----- Функции запроса текущих размеров очередей -------
local function sizeQueue_evn_QUIK() return Queue_QUIK: size() end
local function sizeQueue_evn_QUIK_tbl() return Queue_QUIK_tbl: size() end
-- Конец Функции работы с очередями ---------------------------------------
local function f_nil () end
--- Переменные событий фондового рынка -------
OnAccountBala nce = f_nil --- изменение позиции по счету
OnAccountPosit ion = f_nil --- изменение позиции по счету
OnAllTr ade = f_nil --- новая обезличенная сделка
OnClea nUp = f_nil --- смена торговой сессии
OnCl ose = f_nil --- закрытие терминала QUIK или выгрузка файла qlua.dll
OnConnec ted = f_nil --- установление связи с сервером QUIK
OnDepoLi mit = f_nil --- изменение бумажного лимита
OnDepoLimitDel ete = f_nil --- удаление бумажного лимита
OnDisconnec ted = f_nil --- отключение от сервера QUIK
OnF irm = f_nil --- получение описания новой фирмы
OnFuturesClientHold ing = f_nil --- изменение позиции по срочному рынку
OnFuturesLimitCha nge = f_nil --- изменение ограничений по срочному рынку
OnFuturesLimitDel ete = f_nil --- удаление лимита по срочному рынку
-- OnI nit = f_nil --- инициализация функции main
OnMoneyLi mit = f_nil --- изменение денежного лимита
OnMoneyLimitDel ete = f_nil --- удаление денежного лимита
OnNegD eal = f_nil --- новая заявка на внебиржевую сделку или изменение параметров существующей заявки на внебиржевую сделку
OnNegTr ade = f_nil --- новая сделка для исполнения или изменение существующей сделки для исполнения
OnOr der = f_nil --- новая заявка или изменение параметров существующей заявки
OnPa ram = f_nil --- изменение текущих параметров
OnQu ote = f_nil --- изменение стакана котировок
-- OnS top = f_nil --- остановка скрипта из диалога управления
OnStopOr der = f_nil --- новая стоп-заявка или изменение параметров существующей стоп-заявки
OnTr ade = f_nil --- новая сделка или изменение параметров существующей сделки
OnTransRe ply = f_nil --- ответ на транзакцию
------
local unsubscribe_tbl = ---- Функции отписки ----
{
['OnAccountBalance'] = function () OnAccountBala nce = f_nil end
, ['OnAccountPosition'] = function () OnAccountPosit ion = f_nil end
, ['OnAllTrade'] = function () OnAllTr ade = f_nil end
, ['OnCleanUp'] = function () OnClea nUp = f_nil end
, ['OnClose'] = function () OnCl ose = f_nil end
, ['OnConnected'] = function () OnConnec ted = f_nil end
, ['OnDepoLimit'] = function () OnDepoLi mit = f_nil end
, ['OnDepoLimitDelete'] = function () OnDepoLimitDel ete = f_nil end
, ['OnDisconnected'] = function () OnDisconnec ted = f_nil end
, ['OnFirm'] = function () OnF irm = f_nil end
, ['OnFuturesClientHolding'] = function () OnFuturesClientHold ing = f_nil end
, ['OnFuturesLimitChange'] = function () OnFuturesLimitCha nge = f_nil end
, ['OnFuturesLimitDelete'] = function () OnFuturesLimitDel ete = f_nil end
-- , ['OnInit'] = function () OnI nit = f_nil end
, ['OnMoneyLimit'] = function () OnMoneyLi mit = f_nil end
, ['OnMoneyLimitDelete'] = function () OnMoneyLimitDel ete = f_nil end
, ['OnNegDeal'] = function () OnNegD eal = f_nil end
, ['OnNegTrade'] = function () OnNegTr ade = f_nil end
, ['OnOrder'] = function () OnOr der = f_nil end
, ['OnParam'] = function () OnPa ram = f_nil end
, ['OnQuote'] = function () OnQu ote = f_nil end
-- , ['OnStop'] = function () OnS top = f_nil end
, ['OnStopOrder'] = function () OnStopOr der = f_nil end
, ['OnTrade'] = function () OnTr ade = f_nil end
, ['OnTransReply'] = function () OnTransRe ply = f_nil end
}
-----
local subscribe_tbl = ---- Функции подписки ----
{
['OnAccountBalance'] = function () OnAccountBala nce = function (...) Queue_QUIK: push ({'OnAccountBalance', os.time (), {...}} ) end end
, ['OnAccountPosition'] = function () OnAccountPosit ion = function (...) Queue_QUIK: push ({'OnAccountPosition', os.time (), {...}} ) end end
, ['OnAllTrade'] = function () OnAllTr ade = function (...) Queue_QUIK: push ({'OnAllTrade', os.time (), {...}} ) end end
, ['OnCleanUp'] = function () OnClea nUp = function (...) Queue_QUIK: push ({'OnCleanUp', os.time (), {...}} ) end end
, ['OnClose'] = function () OnCl ose = function (...) Queue_QUIK: push ({'OnClose', os.time (), {...}} ) end end
, ['OnConnected'] = function () OnConnec ted = function (...) Queue_QUIK: push ({'OnConnected', os.time (), {...}} ) end end
, ['OnDepoLimit'] = function () OnDepoLi mit = function (...) Queue_QUIK: push ({'OnDepoLimit', os.time (), {...}} ) end end
, ['OnDepoLimitDelete'] = function () OnDepoLimitDel ete = function (...) Queue_QUIK: push ({'OnDepoLimitDelete', os.time (), {...}} ) end end
, ['OnDisconnected'] = function () OnDisconnec ted = function (...) Queue_QUIK: push ({'OnDisconnected', os.time (), {...}} ) end end
, ['OnFirm'] = function () OnF irm = function (...) Queue_QUIK: push ({'OnFirm', os.time (), {...}} ) end end
, ['OnFuturesClientHolding'] = function () OnFuturesClientHold ing = function (...) Queue_QUIK: push ({'OnFuturesClientHolding', os.time (), {...}} ) end end
, ['OnFuturesLimitChange'] = function () OnFuturesLimitCha nge = function (...) Queue_QUIK: push ({'OnFuturesLimitChange', os.time (), {...}} ) end end
, ['OnFuturesLimitDelete'] = function () OnFuturesLimitDel ete = function (...) Queue_QUIK: push ({'OnFuturesLimitDelete', os.time (), {...}} ) end end
-- , ['OnInit'] = function () OnI nit = function (...) Queue_QUIK: push ({'OnInit', os.time (), {...}} ) end end
, ['OnMoneyLimit'] = function () OnMoneyLi mit = function (...) Queue_QUIK: push ({'OnMoneyLimit', os.time (), {...}} ) end end
, ['OnMoneyLimitDelete'] = function () OnMoneyLimitDel ete = function (...) Queue_QUIK: push ({'OnMoneyLimitDelete', os.time (), {...}} ) end end
, ['OnNegDeal'] = function () OnNegD eal = function (...) Queue_QUIK: push ({'OnNegDeal', os.time (), {...}} ) end end
, ['OnNegTrade'] = function () OnNegTr ade = function (...) Queue_QUIK: push ({'OnNegTrade', os.time (), {...}} ) end end
, ['OnOrder'] = function () OnOr der = function (...) Queue_QUIK: push ({'OnAccountBalance', os.time (), {...}} ) end end
, ['OnParam'] = function () OnPa ram = function (...) Queue_QUIK: push ({'OnParam', os.time (), {...}} ) end end
, ['OnQuote'] = function () OnQu ote = function (...) Queue_QUIK: push ({'OnQuote', os.time (), {...}} ) end end
-- , ['OnStop'] = function () OnS top = function (...) Queue_QUIK: push ({'OnStop', os.time (), {...}} ) end end
, ['OnStopOrder'] = function () OnStopOr der = function (...) Queue_QUIK: push ({'OnStopOrder', os.time (), {...}} ) end end
, ['OnTrade'] = function () OnTr ade = function (...) Queue_QUIK: push ({'OnTrade', os.time (), {...}} ) end end
, ['OnTransReply'] = function () OnTransRe ply = function (...) Queue_QUIK: push ({'OnTransReply', os.time (), {...}} ) end end
}
-----
-- Подписаться на события фондового рынка --
--- Ключи таблицы - имена событий ----
local function subscribe (tbl)
local err ={}, f
for k, v in next, tbl do
f = subscribe_tbl [k]
if f then f() else err[#err +1] = k end
end
return err
end
-- Отписаться от событий фондового рынка --
--- Ключи таблицы - имена событий ----
local function unsubscribe (tbl)
local err ={}, f
for k, v in next, tbl do
f = unsubscribe_tbl [k]
if f then f() else err[#err +1] = k end
end
return err
end
--- Вывод данных о состоянии подписки на события фондового рынка ---
local function condition_subscribe ()
local tbl= {}
---
tbl['OnAccountBalance'] = OnAccountBalance ~= f_nil or nil
tbl['OnAccountPosition'] = OnAccountPosition ~= f_nil or nil
tbl['OnAllTrade'] = OnAllTrade ~= f_nil or nil
tbl['OnCleanUp'] = OnCleanUp ~= f_nil or nil
tbl['OnClose'] = OnClose ~= f_nil or nil
tbl['OnConnected'] = OnConnected ~= f_nil or nil
tbl['OnDepoLimit'] = OnDepoLimit ~= f_nil or nil
tbl['OnDepoLimitDelete'] = OnDepoLimitDelete ~= f_nil or nil
tbl['OnDisconnected'] = OnDisconnected ~= f_nil or nil
tbl['OnFirm'] = OnFirm ~= f_nil or nil
tbl['OnFuturesClientHolding'] = OnFuturesClientHolding ~= f_nil or nil
tbl['OnFuturesLimitChange'] = OnFuturesLimitChange ~= f_nil or nil
tbl['OnFuturesLimitDelete'] =OnFuturesLimitDelete ~= f_nil or nil
-- tbl['OnInit'] = OnInit ~= f_nil or nil
tbl['OnMoneyLimit'] = OnMoneyLimit ~= f_nil or nil
tbl['OnMoneyLimitDelete'] = OnMoneyLimitDelete ~= f_nil or nil
tbl['OnNegDeal'] = OnNegDeal ~= f_nil or nil
tbl['OnNegTrade'] = OnNegTrade ~= f_nil or nil
tbl['OnOrder'] = OnOrder ~= f_nil or nil
tbl['OnParam'] = OnParam ~= f_nil or nil
tbl['OnQuote'] = OnQuote ~= f_nil or nil
-- tbl['OnStop'] = OnStop ~= f_nil or nil
tbl['OnStopOrder'] = OnStopOrder ~= f_nil or nil
tbl['OnTrade'] = OnTrade ~= f_nil or nil
tbl['OnTransReply'] = OnTransReply ~= f_nil or nil
return tbl
end
----------------------------------------------------------------
---- Обработка событий QUIK ----
----
local tbl_QUIK_fun --- Для хранения функции обработки событий таблиц QUIK ---
local tbl_fun --- Для хранения таблицы функции обработки событий фондового рынка ---
local period = 100 -- период счетчика для выдачи сообшений ---
local event_counter = 0 -- текущее значение циклов "разгребания" очередей событий ---
local event_counter_mess = 0 -- счетчик для выдачи сообщений --
local event_counter_mess = 0 -- счетчик для выдачи сообщений --
local read_latency_max = 0 -- максимальная задержка чтения очередей событий (сек.)--
------------------------------------------------------------------
local tbl_QUIK = {} ---- Общая таблица состояния обработки таблиц QUIK ---
---- Функция обаботки колбеков таблиц QUIK ----
local function callback_tbl_QUIK(...) --- (NUMBER t_id, NUMBER msg, NUMBER par1, NUMBER par2
local par ={...}
par = par[1]
if tbl_QUIK[par] then -- Запись в очередь событий таблиц QUIK. os.time () - дата_время записи ---
Queue_QUIK_tbl: push ({par, os.time (), {...}} )
end
end
-- Подписка на события таблицы QUIK ---
local function subscribe_tbl_QUIK (t_id, f_t)
if tbl_QUIK[t_id] then return nil end
tbl_QUIK_fun = tbl_QUIK_fun or f_t
if SetTableNotificationCallback ( t_id, callback_tbl_QUIK) == 1 then
tbl_QUIK[t_id] = 1
return nil
else
message('!!! Ошибка задания колбека для таблицы: ' .. t_id)
error('!!! Ошибка задания колбека для таблицы: ' .. t_id)
return nil
end
end
-- Отписка от событий таблицы QUIK ----
local function unsubscribe_tbl_QUIK (t_id) -- Отписка от событий таблицы QUIK ---
if tbl_QUIK [t_id] then tbl_QUIK [t_id] = nil end
if next (tbl_QUIK) == nil then tbl_QUIK_fun = nil end
end
-- Состояние подписки на события таблицы QUIK ----
local function condition_subscribe_tbl_QUIK () --- Состояние подписки на события таблиц QUIK ---
return tbl_QUIK
end
-----------------------------------------------
--- Установить функции обработки событий ----
local function install_event_handling_functions(tbl_f)
tbl_fun = tbl_f
event_counter = 0
event_counter_mess = 0
event_counter_max = 0
read_latency_max = 0
--- Подписка на события фондового рынка ---
--- ! Ключи таблицы - имена событий ----
unsubscribe (unsubscribe_tbl) ---- Отписаться от всех событий
subscribe (tbl_f) --- Подписка на события всей таблицы tbl_fun (для записей с функциями обработки событий)
end
---- Функция обработки всех событий QUIK: function handle_events(lim) -----
-- Параметр lim (по умолчанию равен 1000000) определяет максимальное количестко событий, обрабатаваемых за один вызов функции --
--- Если очереди событий пусты, то функция завершается.
-- Результат (их три): 1) количество обработанных событий; 2) максимальное количество событий за один вызов функции;
-- 3) максимальная задержка (в сек.) между записью и чтением событий
local function handle_events(lim)
lim = lim or 1000000
local f_ms
--- Чтение очередей событий -----
local ms_tbl = Queue_QUIK_tbl: pop() -- ms_tbl = {t_id, os.time (), {NUMBER t_id, NUMBER msg, NUMBER par1, NUMBER par2}}
local ms = Queue_QUIK: pop() -- ms_tbl = {<Имя события>, os.time (), {<Параметры события>}}
local os_time, os_time_d
---
while (ms_tbl or ms ) do -- Есть события ---
-------------------------------
os_time = os.time ()
event_counter = event_counter + 1
event_counter_mess = event_counter_mess + 1
if event_counter_mess >= period then
event_counter_mess = 0
message ( '!! Длительный цикл обработки событий: ' .. event_counter )
end
--- Обработка событий таблиц QUIK ---
if ms_tbl then
-- message ( tostring(ms_tbl[1]))
os_time_d = os_time - ms_tbl [2]
if read_latency_max < os_time_d then read_latency_max = os_time_d end
if tbl_QUIK_fun then tbl_QUIK_fun (unpack (ms_tbl[3])) end -- Запуск функции обработки событий таблиц QUIK ---
end
----------- События фондового рынка ---
if type (tbl_fun) == 'table' then
if ms then
os_time_d = os_time - ms [2]
if read_latency_max < os_time_d then read_latency_max = os_time_d end
f_ms = tbl_fun[ms[1]]
-- message ( tostring(ms[3][2]))
if f_ms then f_ms (unpack (ms[3])) end -- Запуск функции обработки событий фондового рынка ---
end
end
if event_counter >= lim then break end
--- Чтение очередей событий -----
ms_tbl = Queue_QUIK_tbl: pop() -- ms_tbl = {t_id, os.time (), {NUMBER t_id, NUMBER msg, NUMBER par1, NUMBER par2}}
ms = Queue_QUIK: pop()
end
--- Ведение счетчиков циклов обработки событий ----
if event_counter_max < event_counter then
event_counter_max = event_counter
end
event_counter_rt = event_counter
event_counter = 0
event_counter_mess = 0
read_latency_max = 0
return event_counter_rt, event_counter_max, read_latency_max
end
-----------------------------------------------
return {
-- Queue = Queue --- Функции работы с очередями ----
-- , Queue_evn_QUIK = Queue_evn_QUIK -- Чтение параметров событий рынка ---
-- , Queue_evn_QUIK_tbl = Queue_evn_QUIK_tbl -- Чтение параметров событий таблиц QUIK ---
sizeQueue_evn_QUIK = sizeQueue_evn_QUIK -- Текущий размер очереди событий рынка ---
, sizeQueue_evn_QUIK_tbl = sizeQueue_evn_QUIK_tbl -- Текущий размер очереди событий таблиц QUIK ---
, subscribe = subscribe -- Подписаться на события фондового рынка --
, unsubscribe = unsubscribe -- Отписаться от событий фондового рынка --
, condition_subscribe = condition_subscribe -- Сотояние подписки на события фондового рынка --
, subscribe_tbl_QUIK = subscribe_tbl_QUIK -- Подписаться на события таблиц QUIK --
, unsubscribe_tbl_QUIK = unsubscribe_tbl_QUIK -- Отписаться от событий таблиц QUIK --
, condition_subscribe_tbl_QUIK = condition_subscribe_tbl_QUIK -- Сотояние подписки на таблицы QUIK --
, install_event_handling_functions = install_event_handling_functions -- Установить функции обработки событий ----
, handle_events = handle_events -- Функция обработки всех событий QUIK -----
} ---
--------------------------------------
---- Код шаблона:
Код
local even_handling_module = require('even_handling_module') -- Подключение модуля обработки событий QUIK ---
---
local subscribe = even_handling_module.subscribe
local unsubscribe = even_handling_module.unsubscribe
local condition_subscribe = even_handling_module.condition_subscribe
local subscribe_tbl_QUIK = even_handling_module.subscribe_tbl_QUIK
local unsubscribe_tbl_QUIK = even_handling_module.unsubscribe_tbl_QUIK
local condition_subscribe_tbl_QUIK = even_handling_module.condition_subscribe_tbl_QUIK
local sizeQueue_evn_QUIK = even_handling_module.sizeQueue_evn_QUIK
local sizeQueue_evn_QUIK_tbl = even_handling_module.sizeQueue_evn_QUIK_tbl
local install_event_handling_functions = even_handling_module.install_event_handling_functions
local handle_events = even_handling_module.handle_events
IsRun = true
function main()
--- Работа с событиями таблиц QUIK -----
----- Функция обработки событий таблиц QUIK -----
-- FUNCTION (NUMBER t_id, NUMBER msg, NUMBER par1, NUMBER par2) ---
-- t_id – идентификатор таблицы; msg – код сообщения; par1 и par2 – значения параметров определяются типом сообщения msg ----
local function tbl_QUIK_fun (t_id, msg, par1, par2)
message ( 'tbl_QUIK_fun (t_id: ' .. t_id)
end
-----
TableQUIK=AllocTable() -- Создание таблицы QUIK --
AddColumn(TableQUIK, 1, "Легенда", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK, 2, "Год", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK, 3, "Месяц", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK, 4, "День", true, QTABLE_STRING_TYPE, 6)
CreateWindow(TableQUIK)
for i=1,10 do -- Цикл заполняет ячейки
InsertRow(TableQUIK,-1)
for j=1,4 do
SetCell(TableQUIK, i, j, tostring(i).."-"..tostring(j))
end
end
TableQUIK1=AllocTable() -- Создание таблицы QUIK --
AddColumn(TableQUIK1, 1, "Легенда", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK1, 2, "Год", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK1, 3, "Месяц", true, QTABLE_STRING_TYPE, 6)
AddColumn(TableQUIK1, 4, "День", true, QTABLE_STRING_TYPE, 6)
CreateWindow(TableQUIK1)
for i=1,10 do -- Цикл заполняет ячейки
InsertRow(TableQUIK1,-1)
for j=1,4 do
SetCell(TableQUIK1, i, j, tostring(i).."-"..tostring(j))
end
end
---
subscribe_tbl_QUIK (TableQUIK, tbl_QUIK_fun) --- Подписка на события TableQUIK
subscribe_tbl_QUIK (TableQUIK1, tbl_QUIK_fun) --- Подписка на события TableQUIK1
-- unsubscribe_tbl_QUIK (TableQUIK) --- Отдписка от событий TableQUIK1
--- Конец Работа с событиями таблиц QUIK -----
--- Работа с событиями фондового рынка ----
--- Функции обработки событий фондового рынка ---
local function F_OnParam(p1, p2)
-- message ( 'Тикер: ' .. tostring(p2))
end
--
local function F_OnAllTrade(t)
message ( 'F_OnAllTrade: ' )
end
local function F_OnConnected(t)
message ( 'F_OnConnected: ' )
end
---- и т.д ----
-------------------------------------------------------------------
------ !!! Для перехода на обработку событий в очередях, в скрипте достаточно к именам функций колбеков добавить префикс 'F_'
--- Таблица функций обработки событий фондового рынка (параметры как в соответствующих колбеках) -----
local tbl_fun =
{
['OnAccountBalance'] = F_OnAccountBalance --- Имя функции обработки события OnAccountBalance --
, ['OnAccountPosition'] = F_OnAccountPosition -- и т.д. ---
, ['OnAllTrade'] = F_OnAllTrade
, ['OnCleanUp'] = F_OnCleanUp
, ['OnClose'] = F_OnClose
, ['OnConnected'] = F_OnConnected
, ['OnDepoLimit'] = F_OnDepoLimit
, ['OnDepoLimitDelete'] = F_OnDepoLimitDelete
, ['OnDisconnected'] = F_OnDisconnected
, ['OnFirm'] = F_OnFirm
, ['OnFuturesClientHolding'] = F_OnFuturesClientHolding
, ['OnFuturesLimitChange'] = F_OnFuturesLimitChange
, ['OnFuturesLimitDelete'] = F_OnFuturesLimitDelete
-- , ['OnInit'] = F_OnInit
, ['OnMoneyLimit'] = F_OnMoneyLimit
, ['OnMoneyLimitDelete'] = F_OnMoneyLimitDelete
, ['OnNegDeal'] = F_OnNegDeal
, ['OnNegTrade'] = F_OnNegTrade
, ['OnOrder'] = F_OnOrder
, ['OnParam'] = F_OnParam
, ['OnQuote'] = F_OnQuote
-- , ['OnStop'] = F_OnStop
, ['OnStopOrder'] = F_OnStopOrder
, ['OnTrade'] = F_OnTrade
, ['OnTransReply'] = F_OnTransReply
}
install_event_handling_functions (tbl_fun) -- Установка таблицы функций обработки событий фондового рынка ---
----
for i, v in next, condition_subscribe() do
message( 'Скрипт подписан на событие фондового рынка ' .. i )
end
--- Работа с событиями фондового рынка ----
-------------------
while IsRun do
---- Функция обработки всех событий QUIK: function handle_events(lim) -----
-- Параметр lim (по умолчанию равен 1000000) определяет максимальное количестко событий, обрабатаваемых за один вызов функции --
--- Если очереди событий пусты, то функция завершается.
-- Результат (их три): 1) количество обработанных событий в вызове функции; 2) максимальное количество обработанных событий за один вызов функции;
-- 3) максимальная задержка (в сек.) между записью и чтением событий (в вызове функции).
local event_counter, event_counter_max, read_latency_max = handle_events() ---- Обработка всех событий QUIK ----
if event_counter > 0 then -- В очередях были события ----
message ( 'event_counter: ' .. event_counter .. '; read_latency_max: ' .. read_latency_max )
end
---- Обработка в main остального -----
---- Конец Обработка в main остального -----
sleep(2)
end
------------------
end
function OnStop()
IsRun = false
DestroyTable(TableQUIK)
DestroyTable(TableQUIK1)
return 10000 -- !! По истечении этого интервала времени (в млсек.), данного скрипту на завершение работы, функция main() завершается принудительно.
-- При этом возможна потеря системных ресурсов. ! Если функция не выдает значение, то по умолчанию оно 5000 (5 сек.)
end
Средства отладки OS_Quesha. В OS_Quesha средства отладки представлены на трех уровнях: 1) Отладка кода; 2) Отладка приложения на уровне взаимодействия их потоков; 3) Отладка стратегий торговли на фондовом рынке. Для отладки кода обеспечены следующие возможности: 1) Ведется потокобезопасный журнал отладки, представляющий собой циклический буфер, реализованный с использованием двух текстовых файлов, между которыми выполняется переключение при заполнении текущего файла. Этот буфер обеспечивает корректную запись сообщений из различных потоков OS_Quesha с высокой частотой. Размер этого буфера задается в глобальных настройках переменной Size_log в кб. События в журнал записываются с точностью до 1 миллисекунды; 2) Печать в скрипте функцией dump_str переменных любых типов, в том числе таблиц QLua со всем их содержимым произвольной вложенности (с существующими метатаблицами); 3) Онлайн печать (при реальной работе) из меню любых глобальных переменных вместе с их содержимым; 4) Использование в скрипте Pcall_dll, обеспечивающей выполнение функций в защищенном режиме, с централизованной выдачей стека вызова функции в случае возникновения исключений. Дополнительно, если это требуется, многопоточное приложение, в котором возникло такое исключение, останавливается для после-дующего анализа возникшей ошибки; 5) Использование функции paramete_control для контроля типов параметров, вызываемых функций; 6) обработка высокочастотных сообщений об ошибках. Для отладки приложения на уровне взаимодействия их потоков можно использовать: 1) Настраиваемый, мало влияющий на функционирование приложения, фильтрую-щий вывод сообщений очередей взаимодействия потоков приложения, с привязкой их ко времени, показывающему динамическую картину, в этих очередях; 2) Команду запуска скриптов из меню отладки, обеспечивающую отладку фрагментов разрабатываемых программ в среде OS_Quesha, в процессе продуктивного функционирования приложения; 3) Команды Останов / Пуск, обеспечивающие «замораживание»/«размораживание» потоков приложения для возможности анализа их состояния. Отладка стратегий торговли на фондовом рынке обеспечивается: 1) Интерфейсом прогона стратегий торговли на внутренних данных QUIK и истории ко-тировок бумаг, хранимых в базах SQLite; 2) Оперативно сохраняемой историей одноминуток и пятиминуток конкретных, заданных в настройках бумаг, хранимых в базах SQLite; 3) Оперативно обновляемой историей данных по 18 параметрам (конкретных, заданных в настройках бумаг), получаемых по событиям OnParam, с задержкой (относительно этих событий) < 1 млсек. и записываемых в вектора в оперативной памяти; 4) Реализацией виртуальных операций на реальном рынке.