Все записи автора Дмитрий (Admin)

Разрабатываем роботов для торговли на бирже через терминал QUIK с 2015 года

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

Bot

  • Торговый терминал Quik
  • Всегда ОТКРЫТЫЙ КОД
  • БЫСТРЫЙ ЯЗЫК QLua
  • ИНДИВИДУАЛЬНЫЕ РЕШЕНИЯ
  • БЕССРОЧНАЯ ТЕХ. ПОДДЕРЖКА
  • ПОДРОБНЕЕ

С связи с ситуацией в стране и мире
понимаем, что материальное положение у всех разное
и предлагаем Вам

САМИМ НАЗНАЧАТЬ СТОИМОСТЬ РАЗРАБОТКИ 

РАССРОЧКА без % и без банков

Наша команда готова в кратчайшие сроки, по адекватным ценам автоматизировать Ваши торговые стратегии.
Создать индикаторы по Вашим заданиям.
Сделать для Вас любые другие вспомогательные инструменты.

QUIKМосковская Биржа

Совместное написание робота/индикатора по Skype, обучение
2000 р/час
Простой робот - 1 час
Средний по сложности робот - 3 часа

По поводу обучения.
Я не педагог, я практик, по этому, своими словами и никакой "воды".
Созваниваемся по Skype, я включаю демонстрацию своего экрана, пишу код, объясняю, отвечаю на вопросы.
В конце занятия отправляю Вам видеозапись.

Автоматизация работы трейдера. Скорость и точность. Торгуйте уверенно.

С чего начать самостоятельное обучение?

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

LogoNew
Во первых, Вам потребуются удобные среды разработки (программы, где Вы сможете писать свой код), о том, где их взять и как установить прочтите здесь. Минимально для написания скриптов QLua Вам понадобится только Notepad++, но мы рекомендуем Visual Studio Code с плагинами
Russian Language Pack for Visual Studio Code и Lua

Во вторых, получите терминал QUIK с демо-счетом, можете получить его либо в компании Arqa (разработчик терминала) по данной ссылке, либо у практически любого брокера.

И в третьих, начинайте изучать QLua.
Рекомендую начать с разделов меню "QLua(Lua) основы", в частности со статьи "База скрипта в QLua (lua)", остальные статьи данного раздела используйте как справочники при написании скрипта, в них практически к каждой функции есть пример кода с комментариями.
Смотреть полностью...

Компиляция скрипта QLua(Lua)

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

Qlua-основыЧтобы скомпилировать(получить байт-код) Ваш скрипт, Вам понадобится файл luac.exe, находится в корневом каталоге Вашей LuaForWindows, если у Вас ее еще нет, то установите отсюда code.google.com
Затем, положите в папку с Вашим скриптом копию файла luac.exe, создайте в этой папке текстовый файл, добавьте в него строчку:
luac.exe -o MyScript.luac MyScript.lua
"MyScript" замените на имя Вашего скрипта и сохраните этот файл под любым названием, главное с расширением .bat
Теперь выполните этот файл и в папке появится еще один файл с расширением .luac, перекиньте его куда-нибудь, поменяйте его расширение на .lua и запускайте в терминале как обычный скрипт.

Тот же результат можно получить программным путем:

1
2
3
local f = io.open(FilePathLuac, 'wb')        -- FilePathLuac по этому пути будет создан скомпилированный файл, например: "C:\\MyScript.lua"
f:write(string.dump(loadfile(FilePathSrc)))  -- FilePathSrc путь к Вашему исходному файлу .lua
f:close()

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

Сохранение параметров скрипта 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

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