Модуль реализации интерфейса обработки событий QUIK с использованием очередей событий

Автор записи: TGB

В существующих (на момент 15.10.21) версиях QUIK, его основной (и единственный) служебный поток обслуживания скриптов пользователя запускает их на выполнение (по команде из меню <Загруженные скрипты>). Этот же служебный поток, транслирует скриптам пользователя события, возникающие в QUIK, запуская все функции обратного вызова (колбеки), всех запущенных на исполнение его скриптов. Таким образом, в каждом работающем скрипте пользователя существует его поток main, а все его колбеки запускаются в отдельном, (единственном) служебном потоке QUIK.
Существуют два вида колбеков:
1) колбеки обслуживающие события фондового рынка;
2) колбеки обслуживающие события, возникающие в созданных пользователем таблицах QIUK.
То, что служебный поток QUIK один обслуживает колбеки всех, запущенных на исполнение скриптов пользователя, является проблемой: если функции колбеков некоторого скрипта выполняются долго, или в них возникают длительные блокировки, то перестают обслуживаться колбеки остальных, работающих скриптов пользователя. Кроме того, в скриптах пользователя необходимо учитывать факт параллелизма выполнения потока main и служебного потока QUIK, выполняющего колбеки. То есть, заниматься, сложным для непрофессионала, параллельным программированием.
Из, всего выше сказанного, можно сделать вывод о том, что: в том виде, как он представлен, в текущий момент времени, интерфейс обработки событий в QLua «сырой» для использования его «широким кругом» пользователей.
Для устранения выше озвученных проблем разработчиком QUIK рекомендуется использовать потокобезопасные очереди для передачи параметров, запус-каемых колбеков, потокам main, в которых должны выполняться функции реакции на такие колбеки (документ «Использование Lua в Рабочем месте QUIK»).
Как это можно реализовать, в удобном и эффективном для пользователя виде, представлено ниже в виде:
1) кода модуля even_handling_module.lua ;
2) шаблона использования этого модуля.
Особенности реализации модуля even_handling_module.lua:
1) код модуля написан на «чистом» QLua;
2) очереди передачи параметров колбеков в скриптах пользователя в его потоки main (в разных скриптах это разные потоки) потокобезопасные и при этом они реализованы без использования синхронизации;
3) при реализации записи/чтения очередей, количество операций (на языке Lua) < 6 и не зависит от текущего размера очередей.
Выше перечисленные особенности реализации модуля even_handling_module.lua обеспечивают минимальное влияние на служебный поток QUIK того, что выполняется в скриптах пользователя, а также удобство использования модуля в скриптах пользователя.
Детальное описание использования модуля even_handling_module.lua приведено в его коде и коде шаблона, описывающего схему обработки событий QUIK.
Для подключения модуля к шаблону его надо сохранить в файле под именем even_handling_module.lua в папку хранения кода запуска QUIK (info.exe).
Коды модуля и скрипта-примера его использования:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
--[[     TGB      ----   Модуль реализации обработки событий QUIK с использованием очередей событий  фондового рынка и событий таблиц QUIK ---
 
                                                                               Краткая спецификация модуля.
1. Реализуется схема взаимодействия main с колбеками через две потокобезопасные эффективные очереди, одна из которых обслуживает колбеки
фондового рынка, а вторая, колбеки событий таблиц QUIK, созданных скриптером;
2. При работе обработке колбеков есть две функции: <функция подписки на события фондового рынка>
 и <функция подписки на события пользовательских таблиц >; в этих функциях скриптер может, в виде списка (в таблице) подписаться на события
 в соответствии с существующими именами колбеков; реализация подписки сведена к автоматическому созданию (скрытых) от пользователя
 функций колбеков, записывающих свои параметры с добавлением «от кого параметры» в соответствующие очереди;
3. Для работы с очередями по новой схеме есть две функции чтения соответственно очередям;
 при чтении очередей в считываемой таблице передаются: <имя события>, <время записи в очередь>, <параметры в том виде, как они описаны, в существующих колбеках>.
                  При работе по этой схеме, QLua для скриптера становится однопоточным и снимаются многие сложные проблемы.
----
                              !!  Колбеки OnInit и OnStop обрабатываются как обычно.
-------------------------
--]]
 
----   Функции работы с очередями------
--- При использовании между потоком колбеков и потоком main  потокобезопасные ---<a id="post-preview" class="preview button" href="https://quikluacsharp.ru/?p=3858&amp;preview=true" target="wp-preview-3858" rel="noopener">Просмотреть</a>
    local new  =   function  ()
        return  {first  =   1 , last  =   0 }
     end
	 ---
    local push  =   function  (self, v)
        local  last  =  self.last  +  1
        self[last]  =  v
        self.last  =  last
        return  last
     end
	 ---
    local 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, first
     end
	 ---
    local size  =   function  (self)
        return  self.last  -  self.first  + 1
     end
-----
--------- Создание очередей-----------
local  Queue_QUIK = new()
local  Queue_QUIK_tbl = new()
----- Функции запроса текущих размеров  очередей -------
local function sizeQueue_evn_QUIK()  return  size (Queue_QUIK)  end
local function sizeQueue_evn_QUIK_tbl()  return size (Queue_QUIK_tbl)  end
--  Конец Функции работы с очередями  ---------------------------------------
 
              local function f_nil ()  end
            ---     Переменные  событий фондового рынка -------
		       OnAccountBalance = f_nil        --- изменение позиции по счету
		 	   OnAccountPosition = f_nil          --- изменение позиции по счету
		 	   OnAllTrade = f_nil                       --- новая обезличенная сделка
		 	   OnCleanUp = f_nil                       --- смена торговой сессии
		 	   OnClose = f_nil                            --- закрытие терминала QUIK или выгрузка файла qlua.dll
		 	   OnConnected = f_nil                    --- установление связи с сервером QUIK
		 	   OnDepoLimit = f_nil                    --- изменение бумажного лимита
		 	   OnDepoLimitDelete = f_nil         --- удаление бумажного лимита
		 	   OnDisconnected = f_nil               --- отключение от сервера QUIK
		 	   OnFirm = f_nil                               --- получение описания новой фирмы
		 	   OnFuturesClientHolding = f_nil        --- изменение позиции по срочному рынку
		 	   OnFuturesLimitChange = f_nil         --- изменение ограничений по срочному рынку
		 	   OnFuturesLimitDelete = f_nil            --- удаление лимита по срочному рынку
--		 	   OnInit = f_nil                                  --- инициализация функции main
		 	   OnMoneyLimit = f_nil                   --- изменение денежного лимита
		 	   OnMoneyLimitDelete = f_nil       --- удаление денежного лимита
		 	   OnNegDeal = f_nil                       --- новая заявка на внебиржевую сделку или изменение параметров существующей заявки на внебиржевую сделку
		 	   OnNegTrade = f_nil                     --- новая сделка для исполнения или изменение существующей сделки для исполнения
		 	   OnOrder = f_nil                             --- новая заявка или изменение параметров существующей заявки
		 	   OnParam = f_nil                           --- изменение текущих параметров
		 	   OnQuote = f_nil                            --- изменение стакана котировок
--		 	   OnStop = f_nil                              --- остановка скрипта из диалога управления
		 	   OnStopOrder = f_nil                    --- новая стоп-заявка или изменение параметров существующей стоп-заявки
		 	   OnTrade = f_nil                            --- новая сделка или изменение параметров существующей сделки
		 	   OnTransReply = f_nil                   --- ответ на транзакцию
------
            local  unsubscribe_tbl =    ---- Функции отписки  ----
		 	{
		 	     ['OnAccountBalance'] = function ()   OnAccountBalance = f_nil   end
		 	   , ['OnAccountPosition'] = function ()   OnAccountPosition = f_nil   end
		 	   , ['OnAllTrade'] = function ()   OnAllTrade = f_nil   end
		 	   , ['OnCleanUp'] = function ()   OnCleanUp = f_nil  end
		 	   , ['OnClose'] = function ()   OnClose = f_nil  end
		 	   , ['OnConnected'] = function ()   OnConnected = f_nil  end
		 	   , ['OnDepoLimit'] = function ()   OnDepoLimit = f_nil  end
		 	   , ['OnDepoLimitDelete'] = function ()   OnDepoLimitDelete = f_nil  end
		 	   , ['OnDisconnected'] = function ()   OnDisconnected = f_nil  end
		 	   , ['OnFirm'] = function ()   OnFirm = f_nil  end
		 	   , ['OnFuturesClientHolding'] = function ()   OnFuturesClientHolding = f_nil  end
		 	   , ['OnFuturesLimitChange'] = function ()   OnFuturesLimitChange = f_nil  end
		 	   , ['OnFuturesLimitDelete'] = function ()   OnFuturesLimitDelete = f_nil  end
--		 	   , ['OnInit'] = function ()   OnInit = f_nil  end
		 	   , ['OnMoneyLimit'] = function ()   OnMoneyLimit = f_nil  end
		 	   , ['OnMoneyLimitDelete'] = function ()   OnMoneyLimitDelete = f_nil  end
		 	   , ['OnNegDeal'] = function ()   OnNegDeal = f_nil  end
		 	   , ['OnNegTrade'] = function ()   OnNegTrade = f_nil  end
		 	   , ['OnOrder'] = function ()   OnOrder = f_nil  end
		 	   , ['OnParam'] = function ()   OnParam = f_nil  end
		 	   , ['OnQuote'] = function ()   OnQuote = f_nil  end
--		 	   , ['OnStop'] = function ()   OnStop = f_nil  end
		 	   , ['OnStopOrder'] = function ()   OnStopOrder = f_nil  end
		 	   , ['OnTrade'] = function ()   OnTrade = f_nil end
		 	   , ['OnTransReply'] = function ()   OnTransReply = f_nil  end
		 	}
 
			----------------
            local  subscribe_tbl =    ---- Функции подписки  ----
		 	{
		 	     ['OnAccountBalance'] = function ()   OnAccountBalance = function (...)  push (Queue_QUIK, {'OnAccountBalance', os.time(), {...}} ) end   end
		 	   , ['OnAccountPosition'] = function ()   OnAccountPosition = function (...)  push (Queue_QUIK, {'OnAccountPosition', os.time(), {...}} ) end    end
		 	   , ['OnAllTrade'] = function ()   OnAllTrade = function (...)  push (Queue_QUIK, {'OnAllTrade', os.time(), {...}} ) end     end
		 	   , ['OnCleanUp'] = function ()   OnCleanUp = function (...)  push (Queue_QUIK, {'OnCleanUp', os.time(), {...}} ) end  end
		 	   , ['OnClose'] = function ()   OnClose = function (...)  push (Queue_QUIK, {'OnClose', os.time(), {...}} ) end  end
		 	   , ['OnConnected'] = function ()   OnConnected = function (...)  push (Queue_QUIK, {'OnConnected', os.time(), {...}} ) end  end
		 	   , ['OnDepoLimit'] = function ()   OnDepoLimit = function (...)  push (Queue_QUIK, {'OnDepoLimit', os.time(), {...}} ) end  end
		 	   , ['OnDepoLimitDelete'] = function ()   OnDepoLimitDelete = function (...)  push (Queue_QUIK, {'OnDepoLimitDelete', os.time(), {...}} ) end  end
		 	   , ['OnDisconnected'] = function ()   OnDisconnected = function (...)  push (Queue_QUIK, {'OnDisconnected', os.time(), {...}} ) end  end
		 	   , ['OnFirm'] = function ()   OnFirm = function (...)  push (Queue_QUIK, {'OnFirm', os.time(), {...}} ) end  end
		 	   , ['OnFuturesClientHolding'] = function ()   OnFuturesClientHolding = function (...)  push (Queue_QUIK, {'OnFuturesClientHolding', os.time(), {...}} ) end  end
		 	   , ['OnFuturesLimitChange'] = function ()   OnFuturesLimitChange = function (...)  push (Queue_QUIK, {'OnFuturesLimitChange', os.time(), {...}} ) end  end
		 	   , ['OnFuturesLimitDelete'] = function ()   OnFuturesLimitDelete = function (...)  push (Queue_QUIK, {'OnFuturesLimitDelete', os.time(), {...}} ) end  end
--		 	   , ['OnInit'] = function ()   OnInit = function (...)  push (Queue_QUIK, {'OnInit', os.time(), {...}} ) end  end
		 	   , ['OnMoneyLimit'] = function ()   OnMoneyLimit = function (...)  push (Queue_QUIK, {'OnMoneyLimit', os.time(), {...}} ) end  end
		 	   , ['OnMoneyLimitDelete'] = function ()   OnMoneyLimitDelete = function (...)  push (Queue_QUIK, {'OnMoneyLimitDelete', os.time(), {...}} ) end  end
		 	   , ['OnNegDeal'] = function ()   OnNegDeal = function (...)  push (Queue_QUIK, {'OnNegDeal', os.time(), {...}} ) end  end
		 	   , ['OnNegTrade'] = function ()   OnNegTrade = function (...)  push (Queue_QUIK, {'OnNegTrade', os.time(), {...}} ) end  end
		 	   , ['OnOrder'] = function ()   OnOrder = function (...)  push (Queue_QUIK, {'OnOrder', os.time(), {...}} ) end  end
		 	   , ['OnParam'] = function ()   OnParam = function (...)  push (Queue_QUIK, {'OnParam', os.time(), {...}} ) end  end
		 	   , ['OnQuote'] = function ()   OnQuote = function (...)  push (Queue_QUIK, {'OnQuote', os.time(), {...}} ) end  end
--		 	   , ['OnStop'] = function ()   OnStop = function (...)  push (Queue_QUIK, {'OnStop', os.time(), {...}} ) end  end
		 	   , ['OnStopOrder'] = function ()   OnStopOrder = function (...)  push (Queue_QUIK, {'OnStopOrder', os.time(), {...}} ) end  end
		 	   , ['OnTrade'] = function ()   OnTrade = function (...)  push (Queue_QUIK, {'OnTrade', os.time(), {...}} ) end  end
		 	   , ['OnTransReply'] = function ()   OnTransReply = function (...)  push (Queue_QUIK, {'OnTransReply', os.time(), {...}} ) end  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 = 500    -- период счетчика для выдачи сообшений о задержке обработки событий фондового рынка ---
local event_counter  = 0  -- текущее значение циклов "разгребания" очередей событий ---
local event_counter_max  = 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 () - дата_время записи ---
		        push (Queue_QUIK_tbl, {par, os.time(), {...}} )
		    end
		end
 
	   -- Подписка на события таблицы QUIK  ---
		local function  subscribe_tbl_QUIK (t_id, f_t)
            if 	tbl_QUIK[t_id]  then return 1 end
			if  tbl_QUIK_fun == nil and f_t == nil  then error ('!!! Ошибка в вызове subscribe_tbl_QUIK. Не задана функция обработки таблиц QUIK' ) end
			if  f_t  and type (f_t) ~= 'function' then error ('!!! Ошибка в вызове subscribe_tbl_QUIK. Второй параметр не функция ' ) end
            if 	f_t  and tbl_QUIK_fun then
                if f_t ~= tbl_QUIK_fun  then error ('!!! Ошибка в вызове subscribe_tbl_QUIK. Функция обработки таблиц QUIK отличается от ранее заданной ') end
            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 0
			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  subscribe (tbl)
		    if tbl_fun == nil then error ('!!! Ошибка в вызове subscribe. Следует установить таблицу функций обработки событий фондового ( в функции install_event_handling_functions ') end
			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 install_event_handling_functions(tbl_f, period_f)
           if  type (tbl_f) ~= 'table' then error ('!!! Ошибка в вызове install_event_handling_functions. Параметр не таблица ' ) end
		   period = period_f or 500  ---- по умолчанию 500  --
           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 = pop (Queue_QUIK_tbl)
	local ms, first_q = pop (Queue_QUIK)
	local os_time, os_time_d
 
	repeat     if ( not (ms_tbl or ms) )   then  break  end    --- ### 2-ой вариант (! из-за ошибки в Lua 5.3 до 15.10.21). Нет событий.  ---
--    while (ms_tbl or ms  )   do                                      --- ### 1-ый вариант. Есть события ---
	  	os_time = 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
          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 (table.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]] if f_ms then f_ms (table.unpack (ms[3])) end -- Запуск функции обработки событий фондового рынка --- end end if event_counter >= lim then break  end
        ---  Чтение очередей событий -----
         ms_tbl = pop (Queue_QUIK_tbl)  --Queue_QUIK_tbl: pop()   -- ms_tbl = {t_id,  os.time (), {NUMBER t_id, NUMBER msg, NUMBER par1, NUMBER par2}}
	     ms, first_q = pop (Queue_QUIK)  --Queue_QUIK: pop()
--	end            --- ### 1-ый вариант. ---
	until false    --- ### 2-ой вариант. ----
 
    ---  Ведение счетчиков циклов обработки событий ----
	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 {
   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  -----
 }  ---
--------------------------------------

============================================================================
Скрипт-пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
-- Шаблон использования модуля even_handling_module
 
local even_handling_module = require('even_handling_module')  -- Подключение модуля обработки событий QUIK  ---
---
local dump_tbl = even_handling_module.dump_tbl
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 .. ', msg: ' .. msg .. ', par1: ' .. tostring(par1) .. ', par2: ' .. tostring(par2) )
	    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)    --- Отдписка от событий TableQUIK
--		unsubscribe_tbl_QUIK (TableQUIK1)    --- Отдписка от событий TableQUIK
   --- Конец  Работа с событиями таблиц 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: ' .. tostring (t) )
    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, 100)   -- Установка таблицы функций обработки событий фондового рынка   ---
    ----
    for i, v in next, condition_subscribe() do
        message( 'Скрипт подписан на событие фондового рынка ' .. i )
    end
     ---  Работа с событиями фондового рынка ----
	local event_counter
	local T_OS_high_sleep
	local T_sleep = 30
    -------------------
    while IsRun do
        ---- Функция обработки всех событий QUIK:  function handle_events(lim)	-----
        --  Параметр lim (по умолчанию равен 1000000)  определяет максимальное количестко событий, обрабатаваемых за один вызов функции --
        --- Если очереди событий пусты, то функция завершается.
        --  Результат (их три):  1) количество обработанных событий в вызове функции; 2) максимальное количество обработанных событий за один вызов функции;
        -- 3) максимальная задержка (в сек.) между записью и чтением событий (в вызове функции).
        event_counter, event_counter_max, read_latency_max = handle_events()  ----   Обработка всех событий QUIK  ----
		if event_counter &gt; 0 then  -- В очередях были события ----
--            message ( 'event_counter: ' .. event_counter ..  ';  read_latency_max: ' .. read_latency_max  )
		end
	    ----  Обработка в main остального -----
 
 
	    ----  Конец Обработка в main остального -----
        sleep(20)
  end
  ------------------
end
 
function OnStop()
     IsRun = false
	 DestroyTable(TableQUIK)
     DestroyTable(TableQUIK1)
	 return 10000   --  !!  По истечении этого интервала времени (в млсек.), данного скрипту на завершение работы, функция main() завершается принудительно.
	                             -- При этом возможна потеря системных ресурсов.   ! Если функция не выдает значение, то по умолчанию оно 5000 (5 сек.)
end