Нужные функции

Здесь буду выкладывать функции, которые могут пригодиться:

math_round() -- Округляет число до указанной точности
1
2
3
4
5
-- Округляет число до указанной точности
math_round = function(num, idp)
  local mult = 10^(idp or 0)
  return math.floor(num * mult + 0.5) / mult
end
math_average() -- Возвращает среднее значение из переданных чисел
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- Возвращает среднее значение из переданных чисел
math_average = function(...)
   local arg = {...}
   local sum = 0
   local count = 0
   for i=1,#arg do
      if type(arg[i]) == 'number' then
         sum = sum + arg[i]
         count = count + 1
      end
   end
   if count == 0 then
      return 0
   else
      return sum / count
   end
end
GetClassBySec() -- Возвращает код класса по коду бумаги
1
2
3
4
5
6
7
8
-- Возвращает код класса по коду бумаги
GetClassBySec = function(sec_code)
   for class_code in string.gmatch ('QJSIM,TQBR,SPBFUT,SPBOPT,CETS,', '(%P*),') do
      for sec in string.gmatch (getClassSecurities(class_code), '(%P*_*%P*_*%P*),') do
         if sec == sec_code then return class_code end
      end
   end
end
WaitUpdateDataAfterReconnect() -- Ждет подключения к серверу, после чего ждет еще UpdateDataSecQty секунд подгрузки пропущенных данных с сервера
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
RUN                  = true            -- Флаг поддерживающий работу скрипта
UpdateDataSecQty     = 10              -- Количество секунд ожидания подгрузки данных с сервера после возобновления подключения
1
2
3
4
5
6
7
-- Ждет подключения к серверу, после чего ждет еще UpdateDataSecQty секунд подгрузки пропущенных данных с сервера
WaitUpdateDataAfterReconnect = function()
   while RUN and isConnected() == 0 do sleep(100) end
   if RUN then sleep(UpdateDataSecQty * 1000) end
   -- Повторяет операцию если соединение снова оказалось разорвано
   if RUN and isConnected() == 0 then WaitUpdateDataAfterReconnect() end
end
GetMilliseconds() -- Возвращает количество миллисекунд
1
2
3
4
5
-- Возвращает количество миллисекунд
GetMilliseconds = function()
   local dt = os.sysdate()
   return os.time(dt) * 1000 + dt.ms
end
GetServerDateTime() -- Возвращает текущую дату/время сервера в виде таблицы datetime
Для работы функции в скрипте должна быть объявлена глобальная переменная:

1
RUN                  = true            -- Флаг поддерживающий работу скрипта

Для работы функции в скрипте должна присутствовать функция:
WaitUpdateDataAfterReconnect()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
-- Возвращает текущую дату/время сервера в виде таблицы datetime
GetServerDateTime = function()
   local dt = {}
 
   -- Пытается получить дату/время сервера
   while RUN and dt.day == nil do
      dt.day,dt.month,dt.year,dt.hour,dt.min,dt.sec = string.match(getInfoParam('TRADEDATE')..' '..getInfoParam('SERVERTIME'),"(%d*).(%d*).(%d*) (%d*):(%d*):(%d*)")
      -- Если не удалось получить, или разрыв связи, ждет подключения и подгрузки с сервера актуальных данных
      if dt.day == nil or isConnected() == 0 then WaitUpdateDataAfterReconnect() end
   end
 
   -- Если во время ожидания скрипт был остановлен пользователем, возвращает таблицу datetime даты/времени компьютера, чтобы не вернуть пустую таблицу и не вызвать ошибку в алгоритме
   if not RUN then return os.date('*t', os.time()) end
 
   -- Приводит полученные значения к типу number
   for key,value in pairs(dt) do dt[key] = tonumber(value) end
 
   -- Возвращает итоговую таблицу
   return dt
end
StrToTime() -- Приводит время из строкового формата ЧЧ:ММ:СС к формату datetime
Для работы функции в скрипте должна быть объявлена глобальная переменная:

1
RUN                  = true            -- Флаг поддерживающий работу скрипта

Для работы функции в скрипте должна присутствовать функция:
GetServerDateTime()

Так же, должна присутствовать переменная RUN, которая поддерживает работу основного цикла while в функции main.

1
2
3
4
5
6
7
8
9
10
11
-- Приводит время из строкового формата ЧЧ:ММ:СС к формату datetime
StrToTime = function(str_time)
   while RUN and GetServerDateTime().day == nil do sleep(100) end
   if not RUN then return os.date('*t', os.time()) end
   local dt = GetServerDateTime()
   local h,m,s = string.match( str_time, "(%d%d):(%d%d):(%d%d)")
   dt.hour = tonumber(h)
   dt.min = tonumber(m)
   dt.sec = tonumber(s)
   return dt
end
CheckDemo() -- Узнать является ли терминал демо от компании Arqa, или демо брокера Открытие
1
2
3
4
5
6
7
8
9
10
11
12
function main()
   if CheckDemo() then message('DEMO') else message('REAL') end
end
 
-- Функция возвращает true, если это демо от компании Arqa, или брокера Открытие, иначе false
CheckDemo = function()
   if getClassInfo('QJSIM') ~= nil or getClassInfo('SPBFUT').name:find('Фьючерсы') ~= nil then
      return true
   else
      return false
   end
end
GetTotalnet() -- Получает текущую чистую позицию по инструменту
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
5
6
7
8
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
LIMIT_KIND           = 0               -- Тип лимита (акции), для демо счета должно быть 0, для реального 2
CLIENT_CODE          = ''              -- Код клиента, нужен для получения позиции по валюте
BALANCE_TYPE         = 1               -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте)
                                       -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000
                                       -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10
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
-- Получает текущую чистую позицию по инструменту
GetTotalnet = function()
   -- ФЬЮЧЕРСЫ, ОПЦИОНЫ
   if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then
      local num = getNumberOf('futures_client_holding')
      if num > 0 then
         -- Находит размер лота
         local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value)
         if num > 1 then
            for i = 0, num - 1 do
               local futures_client_holding = getItem('futures_client_holding',i)
               if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then
                  if BALANCE_TYPE == 1 then
                     return math.floor(futures_client_holding.totalnet)
                  else
                     return math.floor(futures_client_holding.totalnet/lot)
                  end
               end
            end
         else
            local futures_client_holding = getItem('futures_client_holding',0)
            if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then
               if BALANCE_TYPE == 1 then
                  return math.floor(futures_client_holding.totalnet)
               else
                  return math.floor(futures_client_holding.totalnet/lot)
               end
            end
         end
      end
   -- АКЦИИ
   elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then
      local num = getNumberOf('depo_limits')
      if num > 0 then
         local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value)
         if num > 1 then
            for i = 0, num - 1 do
               local depo_limit = getItem('depo_limits', i)
               if depo_limit.sec_code == SEC_CODE
               and depo_limit.trdaccid == ACCOUNT
               and depo_limit.limit_kind == LIMIT_KIND then
                  if BALANCE_TYPE == 1 then
                     return math.floor(depo_limit.currentbal)
                  else
                     return math.floor(depo_limit.currentbal/lot)
                  end
               end
            end
         else
            local depo_limit = getItem('depo_limits', 0)
            if depo_limit.sec_code == SEC_CODE
            and depo_limit.trdaccid == ACCOUNT
            and depo_limit.limit_kind == LIMIT_KIND then
               if BALANCE_TYPE == 1 then
                  return math.floor(depo_limit.currentbal)
               else
                  return math.floor(depo_limit.currentbal/lot)
               end
            end
         end
      end
   -- ВАЛЮТА
   elseif CLASS_CODE == 'CETS' then
      local num = getNumberOf('money_limits')
      if num > 0 then
         -- Находит валюту
         local cur = string.sub(SEC_CODE, 1, 3)
         local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value)
         if num > 1 then
            for i = 0, num - 1 do
               local money_limit = getItem('money_limits', i)
               if money_limit.currcode == cur
               and money_limit.client_code == CLIENT_CODE
               and money_limit.limit_kind == LIMIT_KIND then
                  if BALANCE_TYPE == 1 then
                     return math.floor(money_limit.currentbal)
                  else
                     return math.floor(money_limit.currentbal/lot)
                  end
               end
            end
         else
            local money_limit = getItem('money_limits', 0)
            if money_limit.currcode == cur
            and money_limit.client_code == CLIENT_CODE
            and money_limit.limit_kind == LIMIT_KIND then
               if BALANCE_TYPE == 1 then
                  return math.floor(money_limit.currentbal)
               else
                  return math.floor(money_limit.currentbal/lot)
               end
            end
         end
      end
   end
 
   -- Если позиция по инструменту в таблице не найдена, возвращает 0
   return 0
end
GetPosPrice() -- Получает цену текущей позиции по инструменту (АКЦИЯ, ФЬЮЧЕРС, ОПЦИОН)
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
5
6
7
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
LIMIT_KIND           = 0               -- Тип лимита (акции), для демо счета должно быть 0, для реального 2
BALANCE_TYPE         = 1               -- Тип отображения баланса в таблице "Таблица лимитов по денежным средствам" (1 - в лотах, 2 - с учетом количества в лоте)
                                       -- Например, при покупке 1 лота USDRUB одни брокеры в поле "Баланс" транслируют 1, другие 1000
                                       -- 1 лот акций Сбербанка может отображаться в таблице "Позиции по инструментов" в поле "Текущий остаток" как 1, или 10

Так же, для работы функции в скрипте должна присутствовать функция:
GetTotalnet()

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
-- Получает цену текущей позиции по инструменту
GetPosPrice = function()
   -- Акции
   if CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' then
      -- Перебирает таблицу "Позиции по инструментам"
      local num = getNumberOf('depo_limits')
      local depo_limit = nil
      for i=0,num-1 do
         depo_limit = getItem('depo_limits', i)
         if depo_limit.sec_code == SEC_CODE
         and depo_limit.trdaccid == ACCOUNT
         and depo_limit.limit_kind == LIMIT_KIND then
            return depo_limit.awg_position_price
         end
      end
   -- Фьючерсы, опционы
   elseif CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then
      local totalnet = GetTotalnet()
      -- Если позиция есть
      if totalnet ~= 0 then
         local abs_totalnet = math.abs(totalnet)
         local sum = 0
         local sum_lots = 0
         local trade = nil
         -- Перебирает сделки
         local num = getNumberOf('trades')
         for i=num-1,0,-1 do
            trade = getItem('trades', i)
            if trade.sec_code == SEC_CODE then
               if (totalnet < 0 and bit.test(trade.flags, 2)) or (totalnet > 0 and not bit.test(trade.flags, 2)) or totalnet == 0 then
                  sum = sum + trade.price*trade.qty
                  sum_lots = sum_lots + trade.qty
                  -- Если найдены все сделки набора позиции
                  if sum_lots >= abs_totalnet then
                     -- Возвращает среднюю цену
                     return sum/sum_lots
                  end
               end
            end
         end
         -- Не удалось найти все сделки набора позиции
         -- Если найдены хоть какие-то сделки набора
         if sum_lots > 0 then
            -- Возвращает среднюю цену найденных
            return sum/sum_lots
         -- Сделок набора не найдено
         else
            -- Возвращает эффективную цену позиции
            local num = getNumberOf('futures_client_holding')
            if num > 0 then
               -- Находит размер лота
               local lot = tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LOTSIZE').param_value)
               local futures_client_holding = nil
               if num > 1 then
                  for i = 0, num - 1 do
                     futures_client_holding = getItem('futures_client_holding', i)
                     if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then
                        return futures_client_holding.avrposnprice
                     end
                  end
               else
                  futures_client_holding = getItem('futures_client_holding', 0)
                  if futures_client_holding.sec_code == SEC_CODE and futures_client_holding.trdaccid == ACCOUNT then
                     return futures_client_holding.avrposnprice
                  end
               end
            end
         end
      end
   end
 
   -- Если не удалось получить значение, возвращает цену последней сделки по инструменту
   return tonumber(getParamEx(CLASS_CODE, SEC_CODE, 'LAST').param_value)
end
GetFreeMoney() -- Возвращает доступные средства
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
ACCOUNT                          = 'SPBFUT00010'     -- Код счета
FIRM_ID                          = 'NC0011100000'    -- Фирма
CLIENT_CODE                      = '10814'           -- Код клиента
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
-- Возвращает доступные средства
GetFreeMoney = function()
   if CLASS_CODE == 'SPBFUT' or CLASS_CODE == 'SPBOPT' then
      local num = getNumberOf('futures_client_limits')
      if num > 0 then
         if num > 1 then
            for i = 0, num - 1 do
               local limit = getItem('futures_client_limits', i)
               if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then
                  return limit.cbplplanned
               end
            end
         else
            local limit = getItem('futures_client_limits', 0)
            if limit.firmid == FIRM_ID and limit.trdaccid == ACCOUNT and limit.limit_type == 0 then
               return limit.cbplplanned
            end
         end
      end
   elseif CLASS_CODE == 'TQBR' or CLASS_CODE == 'QJSIM' or CLASS_CODE == 'CETS' then
      local num = getNumberOf('money_limits')
      if num > 0 then
         if num > 1 then
            for i = 0, num - 1 do
               local limit = getItem('money_limits', i)
               if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then
                  return limit.currentbal
               end
            end
         else
            local limit = getItem('money_limits', 0)
            if limit.currcode == 'SUR' and limit.firmid == FIRM_ID and limit.client_code == CLIENT_CODE and limit.limit_kind == 0 then
               return limit.currentbal
            end
         end
      end
   end
 
   return 0
end
GetCorrectPrice() -- Приводит переданную цену к требуемому для транзакции по инструменту виду
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента

Так же, для работы функции в скрипте должна присутствовать функция:
math_round()

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
-- Приводит переданную цену к требуемому для транзакции по инструменту виду
GetCorrectPrice = function(price) -- STRING
   -- Получает точность цены по инструменту
   local scale = getSecurityInfo(CLASS_CODE, SEC_CODE).scale
   -- Получает минимальный шаг цены инструмента
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- Если после запятой должны быть цифры
   if scale > 0 then
      price = tostring(price)
      -- Ищет в числе позицию запятой, или точки
      local dot_pos = price:find('.')
      local comma_pos = price:find(',')
      -- Если передано целое число
      if dot_pos == nil and comma_pos == nil then
         -- Добавляет к числу ',' и необходимое количество нулей и возвращает результат
         price = price..','
         for i=1,scale do price = price..'0' end
         return price
      else -- передано вещественное число
         -- Если нужно, заменяет запятую на точку
         if comma_pos ~= nil then price:gsub(',', '.') end
         -- Округляет число до необходимого количества знаков после запятой
         price = math_round(tonumber(price), scale)
         -- Корректирует на соответствие шагу цены
         price = math_round(price/PriceStep)*PriceStep
         price = string.gsub(tostring(price),'[%.]+', ',')
         return price
      end
   else -- После запятой не должно быть цифр
      -- Корректирует на соответствие шагу цены
      price = math_round(price/PriceStep)*PriceStep
      return tostring(math.floor(price))
   end
end
GetPriceForMarketOrder() -- Возвращает корректную цену для рыночной заявки по текущему инструменту
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента

Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()

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
-- Возвращает корректную цену для рыночной заявки по текущему инструменту (принимает 'S',или 'B')
GetPriceForMarketOrder = function(operation) -- STRING
   -- Получает минимальный шаг цены инструмента
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- В зависимости от направления
   if operation == 'B' then -- BUY
      -- Пытается получить максимально возможную цену для инструмента
      local PriceMax = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMAX').param_value)
      -- Если максимально возможная цена получена
      if PriceMax ~= nil and PriceMax ~= 0 then
         -- Возвращает ее в нужном для транзакции формате
         return GetCorrectPrice(PriceMax)
      -- Иначе, максимально возможная цена не получена
      else
         -- Получает цену последней сделки
         local Last = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'LAST').param_value)
         -- Возвращает ее в нужном для транзакции формате, увеличив перед этим на 50 шагов цены
         return GetCorrectPrice(Last + 50*PriceStep)
      end
   else                     -- SELL
      -- Пытается получить минимально возможную цену для инструмента
      local PriceMin = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMIN').param_value)
      -- Если минимально возможная цена получена
      if PriceMin ~= nil and PriceMin ~= 0 then
         -- Возвращает ее в нужном для транзакции формате
         return GetCorrectPrice(PriceMin)
      -- Иначе, минимально возможная цена не получена
      else
         -- Получает цену последней сделки
         local Last = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'LAST').param_value)
         -- Возвращает ее в нужном для транзакции формате, уменьшив перед этим на 50 шагов цены
         return GetCorrectPrice(Last - 50*PriceStep)
      end
   end
end
SetOrder() -- Выставляет обычную лимитную заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
trans_id             = os.time()       -- ID транзакции

Так же, для работы функции в скрипте должны присутствовать функции:
GetCorrectPrice()

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
-- Выставляет заявку
SetOrder = function(
   price,      -- Цена заявки
   operation,  -- Операция ('B' - buy, 'S' - sell)
   qty         -- Количество
)
   -- Выставляет заявку
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Заполняет структуру для отправки транзакции
   local T = {}
   T['TRANS_ID']   = tostring(trans_id)     -- Номер транзакции
   T['ACCOUNT']    = ACCOUNT                -- Код счета
   T['CLASSCODE']  = CLASS_CODE             -- Код класса
   T['SECCODE']    = SEC_CODE               -- Код инструмента
   T['ACTION']     = 'NEW_ORDER'            -- Тип транзакции ('NEW_ORDER' - новая заявка)
   T['TYPE']       = 'L'                    -- Тип ('L' - лимитированная, 'M' - рыночная)
   T['OPERATION']  = operation              -- Операция ('B' - buy, или 'S' - sell)
   T['PRICE']      = GetCorrectPrice(price) -- Цена
   T['QUANTITY']   = tostring(qty)          -- Количество
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   -- Если при отправке транзакции возникла ошибка
   if Res ~= '' then
      -- Выводит сообщение об ошибке
      message('Ошибка транзакции открытия/закрытия: '..Res)
   end
end
SetMarketOrder() -- Выставляет рыночную (по сути) заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
trans_id             = os.time()       -- ID транзакции

Так же, для работы функции в скрипте должны присутствовать функции:
GetPriceForMarketOrder()

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
-- Выставляет рыночную (по сути) заявку
SetMarketOrder = function(
   operation,  -- Операция ('B' - buy, 'S' - sell)
   qty         -- Количество
)
   -- Выставляет рыночную заявку
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Заполняет структуру для отправки транзакции
   local T = {}
   T['TRANS_ID']   = tostring(trans_id)    -- Номер транзакции
   T['ACCOUNT']    = ACCOUNT               -- Код счета
   T['CLASSCODE']  = CLASS_CODE            -- Код класса
   T['SECCODE']    = SEC_CODE              -- Код инструмента
   T['ACTION']     = 'NEW_ORDER'           -- Тип транзакции ('NEW_ORDER' - новая заявка)
   T['TYPE']       = 'L'                   -- Тип ('L' - лимитированная, 'M' - рыночная)
   T['OPERATION']  = operation             -- Операция ('B' - buy, или 'S' - sell)
   T['PRICE']      = GetPriceForMarketOrder(operation) -- Цена
   T['QUANTITY']   = tostring(qty)         -- Количество
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   -- Если при отправке транзакции возникла ошибка
   if Res ~= '' then
      -- Выводит сообщение об ошибке
      message('Ошибка транзакции открытия/закрытия по рынку: '..Res)
   end
end
GetOrderAverTradesPrice() -- Возвращает среднюю цену сделок по заявке
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
-- Возвращает среднюю цену сделок по заявке
GetOrderAverTradesPrice = function(order_num)
   -- Находит кол-во исполненных лотов в заявке
   local num = getNumberOf('orders')
   local order = nil
   local order_qty = 0
   for i=num-1,0,-1 do
      order = getItem('orders', i)
      if order.order_num == order_num then
         order_qty = order.qty - order.balance
         break
      end
   end
 
   -- Находит среднюю цену
   local sum = 0
   local find_lots = 0
   local trade = nil
   num = getNumberOf('trades')
   for i=num-1,0,-1 do
      trade = getItem('trades', i)
      if trade.order_num == order_num then
         sum = sum + trade.qty * trade.price
         find_lots = find_lots + trade.qty
         if find_lots == order_qty then break end
      end
   end
 
   return sum/order_qty
end
CheckOrder() -- Проверяет наличие в системе заявки с определенным ID транзакции
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Проверяет наличие в системе заявки с определенным ID транзакции
CheckOrder = function(id)
   -- Перебирает таблицу заявок от последней к первой
   for i=getNumberOf('orders') - 1, 0, -1 do
      -- Получает заявку из строки таблицы с индексом i
      local order = getItem('orders', i)
      -- Если ID транзакции совпадает
      if order.trans_id == id then
         return true
      end
   end
   -- Заявка с нужным ID транзакции не найдена
   return false
end
GetOrderNum() -- Возвращает номер заявки по ее ID транзакции
1
2
3
4
5
6
7
8
9
10
11
12
13
-- Возвращает номер заявки по ее ID транзакции
GetOrderNum = function(id)
   -- Перебирает таблицу заявок от последней к первой
   for i=getNumberOf('orders') - 1, 0, -1 do
      -- Получает заявку из строки таблицы с индексом i
      local order = getItem('orders', i)
      -- Если ID транзакции совпадает
      if order.trans_id == id then
         -- Возвращает номер заявки
         return order.order_num
      end
   end
end
WaitOrderComplete () -- Ожидает исполнения заявки по ID транзакции
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
SEC_CODE             = 'RIM7'          -- Код инструмента
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
-- Ожидает исполнения заявки по trans_id
WaitOrderComplete = function(trans_id)
   -- Находит заявку по trans_id
   local order_line_idx = -1
   while RUN and order_line_idx == -1 do
      sleep(100)
      -- Перебирает таблицу заявок с последней строки к первой
      local number = getNumberOf('orders')
      if number > 0 then
         if number > 1 then
            for i = number-1,0,-1 do
               -- Получает строку таблицы
               local order_line = getItem('orders', i)
               if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then
                  order_line_idx = i
                  break
               end
            end
         else
            -- Получает строку таблицы
            local order_line = getItem('orders', 0)
            if order_line.trans_id == trans_id and order_line.sec_code == SEC_CODE then
               order_line_idx = 0
            end
         end
      end
   end
   -- Ждет когда заявка будет полностью исполнена
   while RUN and getItem('orders', order_line_idx).balance ~= 0 do sleep(100) end
 
   -- Ждет появления всех сделок заявки в таблице сделок (для исключения ошибок дальнейшей обработки события)
   -- Узнает количество лотов в заявке
   local qty = getItem('orders', order_line_idx).qty
   -- Счетчик найденных лотов
   local lots_counter = 0
   -- Индекс строки последней обработанной сделки
   local last_complete_index = -1
   while RUN and lots_counter ~= qty do
      -- Перебирает еще не обработанные строки таблицы сделок
      local last_index = getNumberOf('trades')-1
      local tmp_index = 0
      if last_complete_index + 1 <= last_index then
         for i = last_complete_index + 1, last_index do
            -- Получает строку таблицы
            local trade_line = getItem('trades', i)
            -- Если сделка с нужным ID, и сделка по нужному инструменту
            if trade_line.trans_id == trans_id and trade_line.sec_code == SEC_CODE then
               -- Увеличивает счетчик
               lots_counter = lots_counter + trade_line.qty
               -- Если найдены все сделки
               if lots_counter == qty then
                  break
               end
            end
            tmp_index = i
         end
         last_complete_index = tmp_index
      end
      sleep(100)
   end
end
Set_SL() -- Выставляет 'Стоп лимит' заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
5
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
EXPIRY_DATE          = 'TODAY'         -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД'
trans_id             = os.time()       -- ID транзакции

Так же, для работы функции в скрипте должны присутствовать функции:
GetCorrectPrice()

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
-- Выставляет стоп-лимит заявку
Set_SL = function(
   operation,     -- Операция ('B' - buy, 'S' - sell)
   stop_price,    -- Цена Стоп-Лосса
   qty            -- Количество в лотах
)
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Вычисляет цену, по которой выставится заявка при срабатывании стопа
   local price = stop_price - 50*PriceStep
   if operation == 'B' then price = stop_price + 50*PriceStep end
   -- Заполняет структуру для отправки транзакции на Стоп-лосс
   local T = {}
   T['TRANS_ID']           = tostring(trans_id)
   T['CLASSCODE']          = CLASS_CODE
   T['SECCODE']            = SEC_CODE
   T['ACCOUNT']            = ACCOUNT
   T['ACTION']             = 'NEW_STOP_ORDER'               -- Тип заявки
   T['OPERATION']          = operation                      -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL))
   T['QUANTITY']           = tostring(qty)                  -- Количество в лотах
   T['STOPPRICE']          = GetCorrectPrice(stop_price)    -- Цена Стоп-Лосса
   T['PRICE']              = GetCorrectPrice(price)         -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0)
   T['EXPIRY_DATE']        = EXPIRY_DATE                    -- 'TODAY', 'GTC', или время
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   -- Если при отправке транзакции возникла ошибка
   if Res ~= '' then
      -- Выводит ошибку
      message('Ошибка транзакции стоп-лимит: '..Res)
   end
end
SetTP() -- Выставляет 'Тейк профит' заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
5
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
EXPIRY_DATE          = 'TODAY'         -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД'
trans_id             = os.time()       -- ID транзакции

Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()

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
-- Выставляет "Тейк профит" заявку
SetTP = function(
   operation,     -- Операция ('B', или 'S')
   pos_price,     -- Цена позиции, на которую выставляется стоп-заявка
   qty,           -- Количество лотов
   profit_size    -- Размер профита в шагах цены
)
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Получает минимальный шаг цены
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- Получает максимально возможную цену заявки
   local PriceMax = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMAX').param_value)
   -- Получает минимально возможную цену заявки
   local PriceMin = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMIN').param_value)
   -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит
   local T = {}
   T['TRANS_ID']              = tostring(trans_id)
   T['CLASSCODE']             = CLASS_CODE
   T['SECCODE']               = SEC_CODE
   T['ACCOUNT']               = ACCOUNT
   T['ACTION']                = 'NEW_STOP_ORDER'                                    -- Тип заявки
   T['STOP_ORDER_KIND']       = 'TAKE_PROFIT_STOP_ORDER'                            -- Тип стоп-заявки
   T['OPERATION']             = operation                                           -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL))
   T['QUANTITY']              = tostring(qty)                                       -- Количество в лотах
 
   -- Вычисляет цену профита
   local stopprice = 0
   if operation == 'B' then
      stopprice = pos_price - profit_size*PriceStep
      if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then
         stopprice = PriceMin
      end
   elseif operation == 'S' then
      stopprice = pos_price + profit_size*PriceStep
      if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then
         stopprice = PriceMax
      end
   end
   T['STOPPRICE']             = GetCorrectPrice(stopprice)                          -- Цена Тэйк-Профита
   T['OFFSET']                = '0'                                                 -- отступ
   T['OFFSET_UNITS']          = 'PRICE_UNITS'                                       -- в шагах цены
   local spread = 50*PriceStep
   if operation == 'B' then
      if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then
         spread = PriceMax - stopprice - 1*PriceStep
      end
   elseif operation == 'S' then
      if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then
         spread = stopprice - PriceMin - 1*PriceStep
      end
   end
   T['SPREAD']                = GetCorrectPrice(spread)                             -- Защитный спред
   T['SPREAD_UNITS']          = 'PRICE_UNITS'                                       -- в шагах цены
 
   T['EXPIRY_DATE']           = EXPIRY_DATE                                         -- 'TODAY', 'GTC', или время
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   if Res ~= '' then
      message('Ошибка выставления стоп-заявки: '..Res)
   end
end
SetTP_SL() -- Выставляет 'Тейк профит и Стоп лимит' заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
5
ACCOUNT              = 'SPBFUT00c41'   -- Код счета
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
EXPIRY_DATE          = 'TODAY'         -- Срок действия стоп-заявки: 'TODAY' - до окончания текущей торговой сессии, 'GTC' -до отмены, или время в формате 'ГГГГММДД'
trans_id             = os.time()       -- ID транзакции

Так же, для работы функции в скрипте должна присутствовать функция:
GetCorrectPrice()

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
-- Выставляет "Тейк профит и Стоп лимит" заявку
SetTP_SL = function(
   operation,     -- Операция ('B', или 'S')
   pos_price,     -- Цена позиции, на которую выставляется стоп-заявка
   qty,           -- Количество лотов
   profit_size,   -- Размер профита в шагах цены
   stop_size      -- Размер стопа в шагах цены
)
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Получает минимальный шаг цены
   local PriceStep = tonumber(getParamEx(CLASS_CODE, SEC_CODE, "SEC_PRICE_STEP").param_value)
   -- Получает максимально возможную цену заявки
   local PriceMax = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMAX').param_value)
   -- Получает минимально возможную цену заявки
   local PriceMin = tonumber(getParamEx(CLASS_CODE,  SEC_CODE, 'PRICEMIN').param_value)
   -- Заполняет структуру для отправки транзакции на Стоп-лосс и Тэйк-профит
   local T = {}
   T['TRANS_ID']              = tostring(trans_id)
   T['CLASSCODE']             = CLASS_CODE
   T['SECCODE']               = SEC_CODE
   T['ACCOUNT']               = ACCOUNT
   T['ACTION']                = 'NEW_STOP_ORDER'                                    -- Тип заявки
   T['STOP_ORDER_KIND']       = 'TAKE_PROFIT_AND_STOP_LIMIT_ORDER'                  -- Тип стоп-заявки
   T['OPERATION']             = operation                                           -- Операция ('B' - покупка(BUY), 'S' - продажа(SELL))
   T['QUANTITY']              = tostring(qty)                                       -- Количество в лотах
 
   -- Вычисляет цену профита
   local stopprice = 0
   if operation == 'B' then
      stopprice = pos_price - profit_size*PriceStep
      if PriceMin ~= nil and PriceMin ~= 0 and stopprice < PriceMin then
         stopprice = PriceMin
      end
   elseif operation == 'S' then
      stopprice = pos_price + profit_size*PriceStep
      if PriceMax ~= nil and PriceMax ~= 0 and stopprice > PriceMax then
         stopprice = PriceMax
      end
   end
   T['STOPPRICE']             = GetCorrectPrice(stopprice)                          -- Цена Тэйк-Профита
   T['OFFSET']                = '0'                                                 -- отступ
   T['OFFSET_UNITS']          = 'PRICE_UNITS'                                       -- в шагах цены
   local spread = 50*PriceStep
   if operation == 'B' then
      if PriceMax ~= nil and PriceMax ~= 0 and stopprice + spread > PriceMax then
         spread = PriceMax - stopprice - 1*PriceStep
      end
   elseif operation == 'S' then
      if PriceMin ~= nil and PriceMin ~= 0 and stopprice - spread < PriceMin then
         spread = stopprice - PriceMin - 1*PriceStep
      end
   end
   T['SPREAD']                = GetCorrectPrice(spread)                             -- Защитный спред
   T['SPREAD_UNITS']          = 'PRICE_UNITS'                                       -- в шагах цены
   T['MARKET_TAKE_PROFIT']    = 'NO'                                                -- 'YES', или 'NO'
 
   -- Вычисляет цену стопа
   local stopprice2 = 0
   if operation == 'B' then
      stopprice2 = pos_price + stop_size*PriceStep
      if PriceMax ~= nil and PriceMax ~= 0 and stopprice2 > PriceMax then
         stopprice2 = PriceMax
      end
   elseif operation == 'S' then
      stopprice2 = pos_price - stop_size*PriceStep
      if PriceMin ~= nil and PriceMin ~= 0 and stopprice2 < PriceMin then
         stopprice2 = PriceMin
      end
   end
   T['STOPPRICE2']            = GetCorrectPrice(stopprice2)                         -- Цена Стоп-Лосса
   -- Вычисляет цену, по которой выставится заявка при срабатывании стопа
   local price = 0
   if operation == 'B' then
      price = stopprice2 + 50*PriceStep
      if PriceMax ~= nil and PriceMax ~= 0 and price > PriceMax then
         price = PriceMax
      end
   elseif operation == 'S' then
      price = stopprice2 - 50*PriceStep
      if PriceMin ~= nil and PriceMin ~= 0 and price < PriceMin then
         price = PriceMin
      end
   end
   T['PRICE']                 = GetCorrectPrice(price)                              -- Цена, по которой выставится заявка при срабатывании Стоп-Лосса (для рыночной заявки по акциям должна быть 0)
   T['MARKET_STOP_LIMIT']     = 'NO'                                                -- 'YES', или 'NO'
   T['EXPIRY_DATE']           = EXPIRY_DATE                                         -- 'TODAY', 'GTC', или время
   T['IS_ACTIVE_IN_TIME']     = 'NO'                                                -- Признак действия заявки типа «Тэйк-профит и стоп-лимит» в течение определенного интервала времени. Значения «YES» или «NO»
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   if Res ~= '' then
      message('Ошибка выставления стоп-заявки: '..Res)
   end
end
CheckStopOrder() -- Проверяет наличие в системе стоп-заявки с определенным ID транзакции
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Проверяет наличие в системе стоп-заявки с определенным ID транзакции
CheckStopOrder = function(id)
   -- Перебирает таблицу стоп-заявок от последней к первой
   for i=getNumberOf('stop_orders') - 1, 0, -1 do
      -- Получает стоп-заявку из строки таблицы с индексом i
      local stop_order = getItem('stop_orders', i)
      -- Если ID транзакции совпадает
      if stop_order.trans_id == id then
         return true
      end
   end
   -- Стоп-заявка с нужным ID не найдена
   return false
end
GetStopOrderNum() -- Возвращает номер стоп-заявки по ее ID транзакции
1
2
3
4
5
6
7
8
9
10
11
12
13
-- Возвращает номер стоп-заявки по ее ID транзакции
GetStopOrderNum = function(id)
   -- Перебирает таблицу стоп-заявок от последней к первой
   for i=getNumberOf('stop_orders') - 1, 0, -1 do
      -- Получает стоп-заявку из строки таблицы с индексом i
      local stop_order = getItem('stop_orders', i)
      -- Если ID транзакции совпадает
      if stop_order.trans_id == id then
         -- Возвращает номер стоп-заявки
         return stop_order.order_num
      end
   end
end
CheckStopOrderActive() -- Проверяет по номеру активна ли стоп-заявка
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- Проверяет по номеру активна ли стоп-заявка
CheckStopOrderActive = function(order_num)
   -- Перебирает таблицу стоп-заявок от последней к первой
   for i=getNumberOf('stop_orders') - 1, 0, -1 do
      -- Получает стоп-заявку из строки таблицы с индексом i
      local stop_order = getItem('stop_orders', i)
      -- Если номер транзакции совпадает
      if stop_order.order_num == order_num then
         -- Если стоп-заявка активна
         if bit.test(stop_order.flags, 0) then
            return true
         else
            return false
         end
      end
   end
end
CheckStopOrderCompleted() -- Проверяет по номеру исполнена ли стоп-заявка
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- Проверяет по номеру исполнена ли стоп-заявка
CheckStopOrderCompleted = function(order_num)
   -- Перебирает таблицу стоп-заявок от последней к первой
   for i=getNumberOf('stop_orders') - 1, 0, -1 do
      -- Получает стоп-заявку из строки таблицы с индексом i
      local stop_order = getItem('stop_orders', i)
      -- Если номер транзакции совпадает
      if stop_order.order_num == order_num then
         -- Если стоп-заявка не активна и не снята
         if not bit.test(stop_order.flags, 0) and not bit.test(stop_order.flags, 1) then
            return true
         else
            return false
         end
      end
   end
end
KillOrder() -- Снимает заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
RUN                  = true            -- Флаг поддержания работы "бесконечного" цикла в функции main
trans_id             = os.time()       -- ID транзакции
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
-- Снимает заявку
KillOrder = function(
   order_num    -- Номер снимаемой заявки
)
   -- Находит заявку
   local index = 0
   local find_order = false
   while RUN and not find_order do
      for i=getNumberOf('orders')-1,0,-1 do
         local order = getItem('orders', i)
         if order.order_num == order_num then
            -- Если заявка уже была исполнена (не активна)
            if not bit.test(order.flags, 0) then
               return false
            end
            index = i
            find_order = true
            break
         end
      end
   end
   if not find_order then
      message('Ошибка: не найдена заявка!')
      return false
   end
 
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Заполняет структуру для отправки транзакции на снятие заявки
   local T = {}
   T['TRANS_ID']            = tostring(trans_id)
   T['CLASSCODE']           = CLASS_CODE
   T['SECCODE']             = SEC_CODE
   T['ACTION']              = 'KILL_ORDER'        -- Тип заявки
   T['ORDER_KEY']      = tostring(order_num)      -- Номер заявки, снимаемой из торговой системы
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   -- Если при отправке транзакции возникла ошибка
   if Res ~= '' then
      -- Выводит ошибку
      message('Ошибка снятия заявки: '..Res)
      return false
   end
 
   -- Ожидает когда заявка перестанет быть активна
   local active = true
   while RUN do
      local order = getItem('orders', index)
      -- Если заявка не активна
      if not bit.test(order.flags, 0) then
         -- Если заявка успела исполниться
         if not bit.test(order.flags, 1) then
            return false
         end
         active = false
         break
      end
      sleep(10)
   end
   if active then
      message('Возникла неизвестная ошибка при снятии ЗАЯВКИ')
      return false
   end
 
   return true
end
Kill_SO() -- Снимает стоп-заявку
Для работы функции в скрипте должны быть объявлены глобальные переменные:

1
2
3
4
CLASS_CODE           = 'SPBFUT'        -- Код класса
SEC_CODE             = 'RIM7'          -- Код инструмента
RUN                  = true            -- Флаг поддержания работы "бесконечного" цикла в функции main
trans_id             = os.time()       -- ID транзакции
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
-- Снимает стоп-заявку
Kill_SO = function(
   stop_order_num    -- Номер снимаемой стоп-заявки
)
   -- Находит стоп-заявку
   local index = 0
   local find_so = false
   while RUN and not find_so do
      for i=getNumberOf('stop_orders')-1,0,-1 do
         local stop_order = getItem('stop_orders', i)
         if stop_order.order_num == stop_order_num then
            -- Если стоп-заявка уже была исполнена (не активна)
            if not bit.test(stop_order.flags, 0) then
               return false
            end
            index = i
            find_so = true
            break
         end
      end
   end
   if not find_so then
      message('Ошибка: не найдена стоп-заявка!')
      return false
   end
 
   -- Получает ID для следующей транзакции
   trans_id = trans_id + 1
   -- Заполняет структуру для отправки транзакции на снятие стоп-заявки
   local T = {}
   T['TRANS_ID']            = tostring(trans_id)
   T['CLASSCODE']           = CLASS_CODE
   T['SECCODE']             = SEC_CODE
   T['ACTION']              = 'KILL_STOP_ORDER'        -- Тип заявки
   T['STOP_ORDER_KEY']      = tostring(stop_order_num) -- Номер стоп-заявки, снимаемой из торговой системы
 
   -- Отправляет транзакцию
   local Res = sendTransaction(T)
   -- Если при отправке транзакции возникла ошибка
   if Res ~= '' then
      -- Выводит ошибку
      message('Ошибка снятия стоп-заявки: '..Res)
      return false
   end
 
   -- Ожидает когда стоп-заявка перестанет быть активна
   local active = true
   while RUN do
      local stop_order = getItem('stop_orders', index)
      -- Если стоп-заявка не активна
      if not bit.test(stop_order.flags, 0) then
         -- Если стоп-заявка успела исполниться
         if not bit.test(stop_order.flags, 1) then
            return false
         end
         active = false
         break
      end
      sleep(10)
   end
   if active then
      message('Возникла неизвестная ошибка при снятии СТОП-ЗАЯВКИ')
      return false
   end
 
   return true
end
StackFIFO() -- Создает объект стека FIFO(Первым вошел, первым вышел)
Использование:

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
-- Создает объект стека максимальным размером 3 элемента (при добавлении более старые будут затираться более новыми)
MyStack = StackFIFO(3)
-- Создает 3 элемента
local elem_1 = 'Элемент 1'
local elem_2 = 'Элемент 2'
local elem_3 = 'Элемент 3'
-- Добавляет 3 элемента в стек
MyStack:Push(elem_1)
MyStack:Push(elem_2)
MyStack:Push(elem_3)
-- Получает самый ранний добавленный элемент
local elem = MyStack:Pop()
-- Теперь в elem находится элемент 1, а в стеке остались элементы 2 и 3
-- Добавим еще один элемент в стек
MyStack:Push('Элемент 4')
-- Теперь в стеке 4,2,3
-- Добавим еще один элемент в стек
MyStack:Push('Элемент 5')
-- 5-й элемент затер 2-й и в стеке сейчас 4,5,3
-- Получает самый ранний добавленный элемент
local elem = MyStack:Pop()
-- Теперь в elem элемент 3, а в стеке остались 4,5
 
-- Объект стека предоставляет следующие функции:
-- Возвращает количество элементов в стеке
MyStack:Count()
-- Добавляет запись в стек
MyStack:Push()
-- Извлекает самую старую запись из стека (с удалением)
MyStack:Pop()
-- Возвращает последнюю запись без ее удаления
MyStack:GetLast()
-- Заменяет последний элемент новым
MyStack:ChangeLast(new_elem)
-- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1
MyStack:Array()

Код, который нужно добавить в скрипт:

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
-- Необходимые объявления для ускорения работы стека
local table_insert = table.insert
local table_sinsert = table.sinsert
local table_remove = table.remove
local table_sremove = table.sremove
 
-- КЛАСС СТЕКА (FIFO)
StackFIFO = function(max)
   local Stack = {}
 
   Stack.items       = {}     -- Массив для стека
   Stack.idx_for_add = 1      -- Индекс для добавления следующей, или первой записи
   Stack.idx_for_get = 1      -- Индекс для изъятия следующей, или первой записи
   Stack.count       = 0      -- Количество находящихся в стеке записей
   Stack.max         = max    -- Максимально возможное количество записей в стеке (при переполнении старые записи будут замещаться новыми)
 
   -- Возвращает количество элементов в стеке
   Stack.Count = function(this)
      return this.count
   end
   -- Добавляет запись в стек
   Stack.Push = function(this, NewEntry)
      -- Добавляет запись в стек
      if this.items[this.idx_for_add] ~= nil then table_sremove(this.items, this.idx_for_add) end
      table_sinsert(this.items, this.idx_for_add, NewEntry)
      -- Корректирует счетчик находящихся в стеке записей
      if this.count < this.max then this.count = this.count + 1 end
      -- Увеличивает индекс для добавления следующей записи
      this.idx_for_add = this.idx_for_add + 1
      -- Если индекс больше максимально допустимого, то следующая запись будет добавляться в начало стека
      if this.idx_for_add > this.max then this.idx_for_add = 1 end
      -- Если изъятие записей отстало от записи (новая запись переписала старую), то увеличивает индекс для изъятия следующей записи
      if this.idx_for_add - this.idx_for_get == 1 and this.count > 1 then -- смещение внутри стека
         this.idx_for_get = this.idx_for_get + 1
      -- Добавил в конец, когда индекс для изъятия тоже был в конце и количество не равно 0
      elseif this.idx_for_get - this.idx_for_add == this.max - 1 and this.count > 1 then
         this.idx_for_get = 1
      end
   end
   -- Извлекает самую старую запись из стека (с удалением)
   Stack.Pop = function(this)
      local OldInxForGet = this.idx_for_get
      if this.count == 0 then return nil end
      -- Уменьшает количество записей на 1
      this.count = this.count - 1
      -- Корректирует, если это была единственная запись
      if this.count == -1 then
         this.count = 0
         this.idx_for_get = this.idx_for_add -- Выравнивает индексы
      else -- Если еще есть записи
         -- Сдвигает индекс изъятия на 1 вправо
         this.idx_for_get = this.idx_for_get + 1
         -- Корректирует, если достигнут конец
         if this.idx_for_get > this.max then this.idx_for_get = 1 end
      end
      return this.items[OldInxForGet]
   end
   -- Возвращает последнюю запись без ее удаления
   Stack.GetLast = function(this)
      if this.idx_for_get > 1 then
         return this.items[this.idx_for_get - 1]
      else
         return this.items[#this.items]
      end
   end
   -- Заменяет последний элемент новым
   Stack.ChangeLast = function(this, new_elem)
      if this.idx_for_get > 1 then
         this.items[this.idx_for_get - 1] = new_elem
      else
         this.items[#this.items] = new_elem
      end
   end
   -- Возвращает содержимое в виде массива, где самый старый элемент под индексом 1
   Stack.Array = function(this)
      local Array = {}
 
      for i = this.idx_for_get, #this.items do
         table_insert(Array, this.items[i])
      end
      for i = 1, this.idx_for_get - 1 do
         table_insert(Array, this.items[i])
      end
      return Array
   end
 
   return Stack
end
StaticVar.dll -- Обмен данными между Lua-скриптами в QUIK
Источник: quik2dde.ru

Готовая библиотека - распаковать в каталог с  QUIK файл StaticVar.dll из архива и использовать
   \x32\StaticVar.dll - для QUIK 6.x и 7.x версий
   \x64\StaticVar.dll - для QUIK 8.x версий и более новых

Возможности:

Библиотека позволяет создать общее хранилище данных для нескольких Lua-скриптов, а также сохранять данные между запусками Lua-скрипта (в пределах одного запуска терминала QUIK!). Между запусками - сохраняйте в файлы самостоятельно.
Каждый элемент сохраняется в виде пары "Назначаемое имя параметра" - "Значение".
Поддерживается концепция "пространства имен" (Name Space): скрипт может назначить для себя текущий Name Space, после чего сохраняться и считываться данные будут только в пределах этого пространства. Имена данных, сохраняемых в разных Name Space, могут пересекаться, это будут разные данные. Если Name Space не назначен - используется "глобальное пространство" (по сути обособленное пространство имен nil). В любой момент текущее пространство имен может переключаться. (Name Space рекомендуется использовать только при надобности.)

Поддерживаются функции:

SetVar("var_name", var_data) -- создает переменную с именем "var_name" в текущем Name Space и записывает в нее значение var_data; если передать только 1 параметр или второй параметр задать равным nil - значение с именем "var_name" будет удалено из хранилища

GetVar("var_name")   -- возвращает сохраненное значение с именем "var_name" из текущего Name Space; если переменной с указанным именем нет - вернет nil

UseNameSpace("NameSpace1") -- использовать пространство имен "NameSpace1"; если вызвать без параметров UseNameSpace() (или с пустой строкой "") - активным станет "неименованное" пространство имен; после старта скрипта Lua до вызова UseNameSpace с непустой строкой действует "неименованное" пространство имен

GetCurrentNameSpace() -- получить текущее пространство имен; возвращает строку, если какое-то пространство имет выбрано вызовом GetCurrentNameSpace, либо nil, если используется "неименованное" пространство

GetVarList()  -- возвращает таблицу формата ["имя_переменной"]=значение, содержащую все установленные (и не удаленные) значения для текущего пространства имен; надо понимать, если заполнено много переменных-данных - то таблица будет большая, и ее заполнение окажется накладными

SetVarList(table)  -- из переданной в качестве аргумента таблицы формата ["var_name"]=var_data заполняет данные с указанными именами в текущем пространстве имен; список сохраненных данных не заменяется, а лишь дополняется из таблицы

Clear()  -- удаляет все сохранённые значения для текущего NameSpace (потребовалась для тестов)

ClearAll()  -- все значения из всех NameSpace (потребовалась для тестов)

Корректно сохраняются (из var_data) и считываются следующие типы Lua:
   string
   boolean
   number
   table (любой вложенности)
данные остальных типов при сохранении преобразуется в строку "как получится".

Ограничения: передача данных между разными скриптами только в пределах одного процесса, т.е. одного QUIK;

Простой пример:

1
2
3
4
5
6
7
8
9
10
11
-- Файл test-1.lua
 
require("StaticVar")
 
stv.UseNameSpace("testNS")
 
function main()
    sleep(10000)
    stv.SetVar("xxx", "xxx-test-value")
    message("(test-1) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1)
end
1
2
3
4
5
6
7
8
9
10
-- Файл test-2.lua
 
require("StaticVar")
 
stv.UseNameSpace("testNS")
 
function main()
    sleep(10000)
    message("(test-2) " .. tostring(stv.GetCurrentNameSpace()) .. ".xxx=" .. tostring(stv.GetVar("xxx")), 1)
end

Запускаем сначала test-1.lua, затем test-2.lua. Чрез 10 сек. Будет выведено 2 сообщения:

(test-1) testNS.xxx=xxx-test-value — первый скрипт сохранил значение и отобразил его
(test-2) testNS.xxx=xxx-test-value — второй скрипт отобразил значение, сохраненное первым скриптом

SharedMemory - аналог StaticVar.dll написанный на Lua
Для обеспечения независимости от версии Quik было создано решение SharedMemory, которое позволяет иметь подобие общей памяти между скриптами.
Скачайте архив SharedMemory.zip, распакуйте его. Создайте в корне терминала Quik папку «SharedMemory», поместите в нее файл SharedMemoryManager.lua и запустите его в терминале. Второй файл SharedMemoryClient.lua из архива подключайте к скриптам, которым нужен данный функционал.
Пример использования (в примере файл SharedMemoryClient.lua находится в одной папке со скриптом):

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
require('SharedMemoryClient')
Sharm = nil
 
RUN = true
 
main = function()
   -- Добавление клиента, функция new_SharM принимает один параметр - номер клиента, должен быть уникальным от 1 до 100
   Sharm = new_SharM(1)
 
   -- Решение имеет всего 3 метода:
 
   -- SetVar - устанавливает значение переменной, в примере значение 1 переменной 'Var1' пространства имен 'NS'
   -- устанавливаемое значение может иметь тип boolean, number, string, либо table
   Sharm:SetVar('NS', 'Var1', 1)
 
   -- GetVar - получает значение переменной, в примере значение переменной 'Var1' из пространства имен 'NS'
   local value = Sharm:GetVar('NS', 'Var1')
 
   while RUN do
      -- Значения могут быть изменены в любом из подключенных клиентов
      message('Var1: '..tostring(Sharm:GetVar('NS', 'Var1')))
      sleep(1000)
   end
end
 
OnStop = function()
   -- Delete - удаляет клиента (необязательно)
   Sharm:Delete()
   RUN = false
end
СОХРАНЕНИЕ ПАРАМЕТРОВ СКРИПТА QLUA(LUA) МЕЖДУ ЗАПУСКАМИ
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
main = function()
   local FPath = getScriptPath()..'//.params'
 
   -- Создание таблицы для примера
   local Params = {}
   Params.a = 10
   Params.b = 'qwerty'
   Params.c = true
   Params.d = {}
   Params.d[1] = 100
   Params.d[2] = 'asdfg'
   Params.d[3] = false
   Params.d[4] = {
      ['a'] = 10,
      ['b'] = 'qwerty',
      ['c'] = true
   }
 
   -- Сохраняет таблицу в файл
   SaveTable(Params, FPath)
 
   -- Загружает таблицу из файла
   local NewParams = LoadTable(FPath)
 
   if NewParams ~= nil then message(NewParams.d[4].b) end -- выведет "qwerty"
end
 
-- Сохраняет таблицу в файл
SaveTable = function(Table, FilePath)
 
   local Lines = {}
   local level = 0
 
   function Rec(a)
      local first = true
      level = level + 1
      local s = '' for i=1,level do s = '   '..s end
      for key, val in pairs(a) do
         if not first then Lines[#Lines] = Lines[#Lines]..',' end
         local k = '[\''..key..'\']'
         if type(key) == 'number' then k = '['..key..']' end
         if type(val) ~= 'table' then
            if type(val) == 'string' then
               val = '\''..val..'\''
            else
               val = tostring(val)
            end
            table.insert(Lines, s..k..'='..val)
            first = false
         else
            table.insert(Lines, s..k..'={')
            first = false
            Rec(val)
            table.insert(Lines, s..'}')
            level = level - 1
         end
      end
   end
 
   table.insert(Lines, 'local a = {')
   Rec(Table)
   table.insert(Lines, '}')
   table.insert(Lines, 'return a')
 
   local f = io.open(FilePath, 'w')
   for i=1,#Lines do
      f:write(Lines[i]..'\n')
      f:flush()
   end
   f:close()
end
 
-- Загружает таблицу из файла
LoadTable = function(FilePath)
   local func, err = loadfile(FilePath)
   if not func then
      message('Ошибка загрузки таблицы из файла: '..err)
      return nil
   else
      return func()
   end
end

Данный пример создаст файл «.params» (можно открыть Блокнотом, это обычный текстовый файл, можете назвать его как угодно) со следующим содержимым:

local a = {
   ['a']=10,
   ['d']={
      [1]=100,
      [2]='asdfg',
      [3]=false,
      [4]={
         ['a']=10,
         ['c']=true,
         ['b']='qwerty'
      }
   },
   ['c']=true,
   ['b']='qwerty'
}
return a