Архив рубрики: QUIK + QLua

Сохранение параметров скрипта QLua(Lua) между запусками

Автор записи: Дмитрий (Admin)

Блоки кода

Функции сохранения и загрузки параметров с примером использования
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
function main()
   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

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Пример простого торгового движка "Simple Engine" QLua(Lua)

Автор записи: Дмитрий (Admin)

Блоки кода
Данный движок не предоставляет полный функционал для разработки скриптов на QLua(Lua), но показывает на сколько проще и эффективней становится разработка при таком подходе.

В примере движка реализован следующий функционал:Смотреть полностью...

Проверка выставления заявки по отправленной транзакции QLua(Lua)

Автор записи: Дмитрий (Admin)

Блоки кода

Блок кода QLua
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
-- ПРОВЕРКА ВЫСТАВЛЕНИЯ ЗАЯВКИ ПО ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ
-- для примера отправляется транзакция на выставление лимитированной заявки на покупку по определенной цене
 
ACCOUNT       = "SPBFUT00k59" -- Код счета
CLASS_CODE    = "SPBFUT"      -- Код класса
SEC_CODE      = "RIH6"        -- Код инструмента
 
OpenPrice     = 73000         -- Цена выставления заявки
 
run           = true          -- Флаг работы цикла while в функции main
 
trans_id      = os.time()     -- Текущие дата и время в секундах хорошо подходят для уникальных номеров транзакций
 
LastStatus    = nil           -- Последний статус транзакции, который был выведен в сообщении
 
-- Основная функция скрипта, пока работает эта функция, работает скрипт
function main()
  -- Отправляет транзакцию на открытие позиции
  TransOpenPos()
  -- Пока работает данный цикл, работает скрипт
  while run do sleep(1) end
end
-- Срабатывает при остановке скрипта
function OnStop() run = false end
 
-- Отправляет транзакцию на открытие позиции
function TransOpenPos()
  -- Выставляет заявку на открытие позиции
  -- Получает ID для следующей транзакции
  trans_id = trans_id + 1
  -- Заполняет структуру для отправки транзакции
  local Transaction={
    ['TRANS_ID']  = tostring(trans_id),   -- Номер транзакции
    ['ACCOUNT']   = ACCOUNT,              -- Код счета
    ['CLASSCODE'] = CLASS_CODE,           -- Код класса
    ['SECCODE']   = SEC_CODE,             -- Код инструмента
    ['ACTION']    = 'NEW_ORDER',          -- Тип транзакции ('NEW_ORDER' - новая заявка)
    ['OPERATION'] = 'B',                  -- Операция ('B' - buy, или 'S' - sell)
    ['TYPE']      = 'L',                  -- Тип ('L' - лимитированная, 'M' - рыночная)
    ['QUANTITY']  = '1',                  -- Количество
    ['PRICE']     = tostring(OpenPrice)   -- Цена
  }
  -- Отправляет транзакцию
  local Res = sendTransaction(Transaction)
  if Res ~= '' then message('TransOpenPos(): Ошибка отправки транзакции: '..Res) else message('TransOpenPos(): Транзакция отправлена') end
end
 
-- Функция вызывается терминалом, когда с сервера приходит новая информация о транзакциях
function OnTransReply(trans_reply)
   -- Если пришла информация по нашей транзакции
   if trans_reply.trans_id == trans_id then
      -- Если данный статус уже был обработан, выходит из функции, иначе запоминает статус, чтобы не обрабатывать его повторно
      if trans_reply.status == LastStatus then return else LastStatus = trans_reply.status end
      -- Выводит в сообщении статусы выполнения транзакции
      if       trans_reply.status <  2    then
         -- Статусы меньше 2 являются промежуточными (0 - транзакция отправлена серверу, 1 - транзакция получена на сервер QUIK от клиента),
         -- при появлении такого статуса делать ничего не нужно, а ждать появления значащего статуса
         -- Выходит из функции
         return
      elseif   trans_reply.status == 3    then -- транзакция выполнена
         message('OnTransReply(): По транзакции №'..trans_reply.trans_id..' УСПЕШНО ВЫСТАВЛЕНА заявка №'..trans_reply.order_num..' по цене '..trans_reply.price..' объемом '..trans_reply.quantity)
      elseif   trans_reply.status >  3    then -- произошла ошибка
         message('OnTransReply(): ОШИБКА выставления заявки по транзакции №'..trans_reply.trans_id..', текст ошибки: '..trans_reply.result_msg)
      end
   end
end

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Получение результатов выполнения отправленной транзакции QLua(Lua)

Автор записи: Дмитрий (Admin)

Блоки кодаЭта статья начинает серию статей с примерами блоков кода, которые применяются при написании скриптов на QLua(Lua), каждый блок выполняет свою определенную задачу.

С каждой новой статьей блок кода будет усложняться своей функциональностью.

Эти блоки удобно брать и вставлять в свои скрипты, где нужно решить задачу, реализованную в блоке.

Блок кода QLua
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
-- ПОЛУЧЕНИЕ РЕЗУЛЬТАТОВ ВЫПОЛНЕНИЯ ОТПРАВЛЕННОЙ ТРАНЗАКЦИИ
-- для примера отправляется транзакция на выставление лимитированной заявки на покупку по определенной цене
 
ACCOUNT       = "SPBFUT00k59" -- Код счета
CLASS_CODE    = "SPBFUT"      -- Код класса
SEC_CODE      = "RIH6"        -- Код инструмента
 
OpenPrice     = 73000         -- Цена выставления заявки
 
run           = true          -- Флаг работы цикла while в функции main
 
trans_id      = os.time()     -- Текущие дата и время в секундах хорошо подходят для уникальных номеров транзакций
 
LastStatus    = nil           -- Последний статус транзакции, который был выведен в сообщении
 
-- Основная функция скрипта, пока работает эта функция, работает скрипт
function main()
  -- Отправляет транзакцию на открытие позиции
  TransOpenPos()
  -- Пока работает данный цикл, работает скрипт
  while run do sleep(1) end
end
-- Срабатывает при остановке скрипта
function OnStop() run = false end
 
-- Отправляет транзакцию на открытие позиции
function TransOpenPos()
  -- Выставляет заявку на открытие позиции
  -- Получает ID для следующей транзакции
  trans_id = trans_id + 1
  -- Заполняет структуру для отправки транзакции
  local Transaction={
    ['TRANS_ID']  = tostring(trans_id),   -- Номер транзакции
    ['ACCOUNT']   = ACCOUNT,              -- Код счета
    ['CLASSCODE'] = CLASS_CODE,           -- Код класса
    ['SECCODE']   = SEC_CODE,             -- Код инструмента
    ['ACTION']    = 'NEW_ORDER',          -- Тип транзакции ('NEW_ORDER' - новая заявка)
    ['OPERATION'] = 'B',                  -- Операция ('B' - buy, или 'S' - sell)
    ['TYPE']      = 'L',                  -- Тип ('L' - лимитированная, 'M' - рыночная)
    ['QUANTITY']  = '1',                  -- Количество
    ['PRICE']     = tostring(OpenPrice)   -- Цена
  }
  -- Отправляет транзакцию
  local Res = sendTransaction(Transaction)
  if Res ~= '' then message('TransOpenPos(): Ошибка отправки транзакции: '..Res) else message('TransOpenPos(): Транзакция отправлена') end
end
 
-- Функция вызывается терминалом, когда с сервера приходит новая информация о транзакциях
function OnTransReply(trans_reply)
   -- Если пришла информация по нашей транзакции
   if trans_reply.trans_id == trans_id then
      -- Если данный статус уже был обработан, выходит из функции, иначе запоминает статус, чтобы не обрабатывать его повторно
      if trans_reply.status == LastStatus then return else LastStatus = trans_reply.status end
      -- Выводит в сообщении статусы выполнения транзакции
      if       trans_reply.status == 0    then message('OnTransReply(): Транзакция отправлена серверу')
      elseif   trans_reply.status == 1    then message('OnTransReply(): Транзакция получена на сервер QUIK от клиента')
      elseif   trans_reply.status == 2    then message('OnTransReply(): Ошибка при передаче транзакции в торговую систему. Так как отсутствует подключение шлюза Московской Биржи, повторно транзакция не отправляется')
      elseif   trans_reply.status == 3    then message('OnTransReply(): ТРАНЗАКЦИЯ ВЫПОЛНЕНА !!!')
      elseif   trans_reply.status == 4    then message('OnTransReply(): Транзакция не выполнена торговой системой. Более подробное описание ошибки отображается в поле «Сообщение» (trans_reply.result_msg)')
      elseif   trans_reply.status == 5    then message('OnTransReply(): Транзакция не прошла проверку сервера QUIK по каким-либо критериям. Например, проверку на наличие прав у пользователя на отправку транзакции данного типа')
      elseif   trans_reply.status == 6    then message('OnTransReply(): Транзакция не прошла проверку лимитов сервера QUIK')
      elseif   trans_reply.status == 10   then message('OnTransReply(): Транзакция не поддерживается торговой системой')
      elseif   trans_reply.status == 11   then message('OnTransReply(): Транзакция не прошла проверку правильности электронной цифровой подписи')
      elseif   trans_reply.status == 12   then message('OnTransReply(): Не удалось дождаться ответа на транзакцию, т.к. истек таймаут ожидания. Может возникнуть при подаче транзакций из QPILE')
      elseif   trans_reply.status == 13   then message('OnTransReply(): Транзакция отвергнута, так как ее выполнение могло привести к кросс-сделке (т.е. сделке с тем же самым клиентским счетом)')
      end
   end
end

Если у Вас появились какие-то вопросы, задайте их в комментариях под статьей !!!

Получение в QLua(Lua) данных из графиков и индикаторов

Автор записи: Дмитрий (Admin)

QUIK-Qlua-poluchenie-dannyhЧтобы получить доступ к графику(не индикатору) какого-либо инструмента нужно создать источник данных при помощи функции CreateDataSource().
ВАЖНО!!! Для получения новых данных, кроме тех, что уже есть в открытом графике на текущий момент (тем более, если он не открыт), требуется использовать одну из следующих функций: SetUpdateCallback(), или SetEmptyCallback(), о которых будет написано ниже.

Описание функции CreateDataSource()
-- Функция предназначена для создания таблицы Lua и позволяет работать со свечами, полученными с сервера QUIK, а также реагировать на их изменение.
ds, Error = CreateDataSource (class_code, sec_code, interval [, param]);
   -- Параметры:
      -- class_code - (STRING) код класса, например "SPBFUT"
      -- sec_code   - (STRING) код бумаги, например "RIZ5"
      -- interval   - (NUMBER) константа, обозначающая тайм-фрейм графика, например INTERVAL_M5 (полный список: https://quikluacsharp.ru/qlua-osnovy/spisok-konstant-tajm-frejmov-grafikov/)
      -- param      - (STRING) необязательный параметр. Если параметр не задан, то заказываются данные на основании таблицы всех сделок, если задан – данные по этому параметру, например "BID" (возможные параметры смотрите ниже)
   -- Возвращаемые значения:
      -- ds         - (TABLE) таблица с данными по свечам графика
      -- Error      - (STRING) строка ошибки в случае неудачной попытки получить доступ к данным (тогда ds будет nil)
 
-- Если график, к которому нужно подключиться не открыт в терминале, то данные заказываются с сервера, на их получение нужно время,
-- по этому, рекомендуется добавлять вот такое ожидание, прежде, чем обращаться к ds:
-- Ждет, пока данные будут получены с сервера (на случай, если такой график не открыт)
while (Error == "" or Error == nil) and ds:Size() == 0 do sleep(1) end
if Error ~= "" and Error ~= nil then message("Ошибка подключения к графику: "..Error) end
 
-- Примеры (одновременно можно подключаться к нескольким источникам данных):
ds1 = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "last");
ds2 = CreateDataSource("QJSIM", "SBER", INTERVAL_M1);
ds3, Error = CreateDataSource("SPBFUT", "RIU3", INTERVAL_M1, "bid");
if ds3 == nil then message('Ошибка подключения: '..Error); end;
Смотреть полностью...

Пример скрипта QLua (Lua), выполняющего торговые операции в терминале QUIK

Автор записи: Дмитрий (Admin)

OpenClose
Скрипт позволяет открывать и закрывать позиции следующего типа:
- покупается 2, выбранных при помощи кнопок, колл-опциона на фьючерс на индекс РТС,
- продается 1, выбранный при помощи кнопок, фьючерс на индекс РТС.

Когда есть открытая данным скриптом позиция, в таблице отображается информация о ней (профит, баланс, ср.цена, дата открытия).

Профит вычисляется по формуле: "Текущая цена, по которой можно закрыть позицию" - "Цена открытия позиции" - "Комиссия 8 р. на каждый лот".

Так же, выполняется запись в лог-файл ("Log.txt") выполняемых скриптом операций и в файле состояния ("State.txt") хранится информация о текущих выбранных инструментах и о текущей, открытой скриптом позиции.Смотреть полностью...

Получение данных из таблиц QUIK в QLua(Lua)

Автор записи: Дмитрий (Admin)

QUIK-Qlua-poluchenie-dannyh Для получения данных из таблиц терминала QUIK удобно пользоваться 3-мя функциями: getItem(), getNumberOf() и getParamEx().

Пример:

-- Перебирает строки таблицы "Позиции по клиентским счетам (фьючерсы)", ищет Текущие чистые позиции по инструменту "RIH5"
for i = 0,getNumberOf("FUTURES_CLIENT_HOLDING") - 1 do
   -- ЕСЛИ строка по нужному инструменту И чистая позиция не равна нулю ТО
   if getItem("FUTURES_CLIENT_HOLDING",i).sec_code == "RIH5" and getItem("FUTURES_CLIENT_HOLDING",i).totalnet ~= 0 then
      -- ЕСЛИ текущая чистая позиция > 0, ТО открыта длинная позиция (BUY)
      if getItem("FUTURES_CLIENT_HOLDING",i).totalnet > 0 then
         IsBuy = true;
         BuyVol = getItem("FUTURES_CLIENT_HOLDING",i).totalnet;	-- Количество лотов в позиции BUY
      else   -- ИНАЧЕ открыта короткая позиция (SELL)
         IsSell = true;
         SellVol = math.abs(getItem("FUTURES_CLIENT_HOLDING",i).totalnet); -- Количество лотов в позиции SELL
      end;
   end;
end;

Далее перечислены таблицы, их идентификаторы и поля, к которым можно обращаться:Смотреть полностью...

Получение стакана из QUIK в QLua(Lua)

Автор записи: Дмитрий (Admin)

QUIK-Qlua-poluchenie-dannyh
Для получения стакана в QLua(Lua) служит функция обратного вызова OnQuote(). Эта функция вызывается терминалом QUIK при получении изменения стакана котировок. Для получения данных самого стакана служит функция getQuoteLevel2().

В терминале должен быть открыт стакан по нужному инструменту!!!

 

Пример:Смотреть полностью...

Получение обезличенных сделок из QUIK в QLua(Lua)

Автор записи: Дмитрий (Admin)

QUIK-Qlua-poluchenie-dannyh   Для получения обезличенных сделок в QLua(Lua) служит функция обратного вызова OnAllTrade(). Эта функция вызывается терминалом QUIK каждый раз при получении новой обезличенной сделки по инструменту, на который есть подписка. Чтобы сделать подписку на нужные инструменты, необходимо пройти: "Связь" -> "Заказ всех сделок...". В окне "Выбор инструментов для заказа всех сделок" выбрать нужные инструменты и нажать кнопку "Сохранить". Так же,  в терминале должно быть открыто окно "Таблицы" -> "Таблица всех сделок", в котором должно быть настроено отображение нужных инструментов (правой кнопкой мыши в окне -> "Редактировать таблицу").

 

Пример:Смотреть полностью...