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

Автор записи: Дмитрий (Admin)
1 звезда2 звезды3 звезды4 звезды5 звезд (Голосов 3, среднее: 5,00 из 5)
Загрузка...

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

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

 

Пример:

 

--- Функция вызывается терминалом QUIK при получении изменения стакана котировок
function OnQuote(class, sec )
   -- 
   if class == "SPBFUT" and sec == "RIM5" then
      ql2 = getQuoteLevel2(class, sec);
      -- Представляет снимок СТАКАНА в виде СТРОКИ
         QuoteStr = "";
         for i = tonumber(ql2.bid_count), 1, -1 do
            if ql2.bid[i].quantity ~= nil then   -- На некоторых ценах могут отсутствовать заявки
               QuoteStr = QuoteStr..tostring(tonumber(ql2.bid[i].quantity))..";"..tostring(tonumber(ql2.bid[i].price))..";";
            else
               QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.bid[i].price))..";";
            end;
         end;
         for i = 1, tonumber(ql2.offer_count), 1 do
            if ql2.offer[i].quantity ~= nil then   -- На некоторых ценах могут отсутствовать заявки
               if i < tonumber(ql2.offer_count) then 
                  QuoteStr = QuoteStr..tostring(tonumber(ql2.offer[i].quantity))..";"..tostring(tonumber(ql2.offer[i].price))..";";
               else 
                  QuoteStr = QuoteStr..tostring(tonumber(ql2.offer[i].quantity))..";"..tostring(tonumber(ql2.offer[i].price));
               end;
            else 
               if i < tonumber(ql2.offer_count) then
                  QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.offer[i].price))..";";
               else
                  QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.offer[i].price));
               end;
            end;
         end;
   end;
end;
 
-- В результате при каждом обновлении стакана по инструменту RTS-6.15 в переменной QuoteStr будет строка, типа:
   -- "15;86130;17;86120;16;86110;22;86100;16;86090;24;86080;26;86070;29;86060;97;86050;51;86040;99;86030;88;86020;143;86010;140;86000;15;85990;49;85980;58;85970;28;85960;49;85950;36;85940;71;85930;115;85920;95;85910;25;85900;5;85890;13;85880;62;85870;3;85860;36;85850;26;85840;11;85830;9;85820;99;85810;86;85800;41;85790;24;85780;2;85770;36;85760;162;85750;22;85740;44;85730;76;85720;229;85710;121;85700;5;85690;5;85680;2;85670;10;85660;148;85650;119;85640;12;86150;19;86160;26;86170;32;86180;71;86190;49;86200;26;86210;20;86220;91;86230;57;86240;47;86250;25;86260;34;86270;41;86280;21;86290;66;86300;36;86310;57;86320;50;86330;34;86340;38;86350;22;86360;17;86370;15;86380;18;86390;13;86400;3;86410;34;86420;29;86430;80;86440;26;86450;68;86460;226;86470;371;86480;30;86490;64;86500;99;86510;11;86520;2;86530;23;86540;9;86550;3;86560;52;86570;23;86580;25;86590;73;86600;17;86610;88;86620;52;86630;150;86640"
   -- Такую строку удобно, в последствии, передавать в C# и разделять на элементы
 
-- Функция getQuoteLevel2() принимает 2 параметра: Код класса и Код бумаги, а возвращает таблицу, которая имеет следующие поля:
bid_count    -- Количество котировок покупки (STRING)
offer_count  -- Количество котировок продажи (STRING)
bid          -- Котировки спроса (покупки) (TABLE)
offer        -- Котировки предложений (продажи) (TABLE)
   -- Таблицы «bid» и «offer» имеют следующую структуру: 
      price     -- Цена покупки / продажи (STRING)
      quantity  -- Количество в лотах (STRING)

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

Добавить комментарий

Получение стакана из QUIK в QLua(Lua): 144 комментария

  1. 1
    2
    3
    4
    5
    6
    7
    
     function Options(sec) -- Функция считает Bid, Offer, Step, Theta
       local glass = getQuoteLevel2(Class_Opt, sec) -- Стакан
       local Offer_2 = tonumber(glass.offer[2].price) -- 2я цена в стакане
       local Offer_1 = tonumber(glass.offer[1].price) -- 1я цена в стакане
       local Bid_1 = tonumber(glass.bid[tonumber(glass.bid_count)].price) -- 1я цена в стакане
       local Bid_2 = tonumber(glass.bid[tonumber(glass.bid_count)-1].price) -- 2я цена в стакане
    .........

    Вот сделал такую штуку и что получилось - теперь если отключить терминал при включенном роботе, то при повторном включении терминала робот отключен, хотя раньше включен был (проверил, из-за этой части кода так происходит) Но вопрос в другом, если в процессе торговой сессии произойдет разрыв связи, то после восстановления связи будет ли робот работать или запускать вручную?

          1. Цитата с форума Квика "Могу предположить, что при запуске в автомате Ваши скрипты обращаются к еще не полученным данным. В результате получаете nil и аварийное завершение. когда пускаете кнопкой все данные уже подгружены и такого не происходит." - Проверил так и есть

              1. getInfoParam('SERVERTIME') а это зачем проверять если первое условие достаточно? и второе, мне на нил проверить - потому что стакан может быть вообще пустым?

                1. У меня просто в роботе нужно время сервера получать, чтобы определять находимся ли внутри определенного временного промежутка, в твоем случае еще вот так нужно проверять, наверно, чтоб наверняка:
                  local glass = getQuoteLevel2(Class_Opt, sec) -- Стакан
                  if glass ~= nil and glass.offer ~= nil then

                  1. Ага все понятно, про стакан в принципе и сам допер, время мне пока что не к чему (задач таких пока не ставлю), я вот такую проверку по времени делаю и все

                    1
                    2
                    
                     Trade = tonumber(getParamEx(Class_Fut, Sec_Fut, "status").param_value) -- Торговля разрешена или нет
                          if Trade == 1 then Trade = true else Trade = false Gray(1, 0) end
                    1. Привет, делал со стаканом что то раньше и бот был - но видимо удалил его, а сейчас есть необходимость вернуться к пройденному материалу и заново все сделать - вот пришел сюда за освежением памяти - классно что все есть.

  2. С Новым Годом! Спасибо за сайт.
    Не понял, зачем строку преобразовывать в число, а потом опять в строку.
    У вас так:
    QuoteStr = QuoteStr..tostring(tonumber(ql2.bid[i].quantity))..";"..tostring(tonumber(ql2.bid[i].price))..";";
    На мой взгляд, можно так:
    QuoteStr = QuoteStr..ql2.bid[i].quantity..";"..ql2.bid[i].price..";";
    Или я не прав?

    1. С Новым Годом! Я сейчас уже не помню, но, вроде бы какой-то смысл в этом был, возможно лишние нули в конце обрезаются. А tostring везде желательно использовать, т.к. если появится значение nil, то простая конкатенация '..' вызовет ошибку, а tostring просто вставить строку 'nil'. А вообще попробуйте так и так, и если не будет никакой разницы, то используйте Ваш вариант.

  3. Добрый день .Скопировал скрипт "Получение стакана из QUIK в QLua(Lua)" -сохранил с разрешением LUA при запуске в Quik выдает ошибку :Syntax error compiling C:\info\Lua скрипты \скакан котировок .LUA:39:=expected near offer_count .
    Quik 6.17 -Подскажите пожайлуста в чем моя ошибка ! Спасибо

    1. Добрый день! Это не готовый скрипт, а пояснение как получать данные стакана, в данном случае, в строках 38, 39 и далее идет описание полей, которые присутствуют в таблице, возвращаемой функцией getQuoteLevel2(), естественно этого не должно быть в коде программы, т.к. это не рабочий код, а часть статьи сайта!

        1. Вот это, рабочая функция:

          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
          
          --- Функция вызывается терминалом QUIK при получении изменения стакана котировок
          function OnQuote(class, sec )
             -- 
             if class == "SPBFUT" and sec == "RIM5" then
                ql2 = getQuoteLevel2(class, sec);
                -- Представляет снимок СТАКАНА в виде СТРОКИ
                   QuoteStr = "";
                   for i = tonumber(ql2.bid_count), 1, -1 do
                      if ql2.bid[i].quantity ~= nil then   -- На некоторых ценах могут отсутствовать заявки
                         QuoteStr = QuoteStr..tostring(tonumber(ql2.bid[i].quantity))..";"..tostring(tonumber(ql2.bid[i].price))..";";
                      else
                         QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.bid[i].price))..";";
                      end;
                   end;
                   for i = 1, tonumber(ql2.offer_count), 1 do
                      if ql2.offer[i].quantity ~= nil then   -- На некоторых ценах могут отсутствовать заявки
                         if i < tonumber(ql2.offer_count) then 
                            QuoteStr = QuoteStr..tostring(tonumber(ql2.offer[i].quantity))..";"..tostring(tonumber(ql2.offer[i].price))..";";
                         else 
                            QuoteStr = QuoteStr..tostring(tonumber(ql2.offer[i].quantity))..";"..tostring(tonumber(ql2.offer[i].price));
                         end;
                      else 
                         if i < tonumber(ql2.offer_count) then
                            QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.offer[i].price))..";";
                         else
                            QuoteStr = QuoteStr.."0;"..tostring(tonumber(ql2.offer[i].price));
                         end;
                      end;
                   end;
             end;
          end;

          Вот это к ней пояснения:

          1
          2
          3
          4
          5
          6
          7
          8
          9
          10
          11
          12
          
          -- В результате при каждом обновлении стакана по инструменту RTS-6.15 в переменной QuoteStr будет строка, типа:
             -- "15;86130;17;86120;16;86110;22;86100;16;86090;24;86080;26;86070;29;86060;97;86050;51;86040;99;86030;88;86020;143;86010;140;86000;15;85990;49;85980;58;85970;28;85960;49;85950;36;85940;71;85930;115;85920;95;85910;25;85900;5;85890;13;85880;62;85870;3;85860;36;85850;26;85840;11;85830;9;85820;99;85810;86;85800;41;85790;24;85780;2;85770;36;85760;162;85750;22;85740;44;85730;76;85720;229;85710;121;85700;5;85690;5;85680;2;85670;10;85660;148;85650;119;85640;12;86150;19;86160;26;86170;32;86180;71;86190;49;86200;26;86210;20;86220;91;86230;57;86240;47;86250;25;86260;34;86270;41;86280;21;86290;66;86300;36;86310;57;86320;50;86330;34;86340;38;86350;22;86360;17;86370;15;86380;18;86390;13;86400;3;86410;34;86420;29;86430;80;86440;26;86450;68;86460;226;86470;371;86480;30;86490;64;86500;99;86510;11;86520;2;86530;23;86540;9;86550;3;86560;52;86570;23;86580;25;86590;73;86600;17;86610;88;86620;52;86630;150;86640"
             -- Такую строку удобно, в последствии, передавать в C# и разделять на элементы
           
          -- Функция getQuoteLevel2() принимает 2 параметра: Код класса и Код бумаги, а возвращает таблицу, которая имеет следующие поля:
          bid_count    -- Количество котировок покупки (STRING)
          offer_count  -- Количество котировок продажи (STRING)
          bid          -- Котировки спроса (покупки) (TABLE)
          offer        -- Котировки предложений (продажи) (TABLE)
             -- Таблицы «bid» и «offer» имеют следующую структуру: 
                price     -- Цена покупки / продажи (STRING)
                quantity  -- Количество в лотах (STRING)

          Чего именно я по Вашему не опубликовал?

    1. Можете добавить getInfoParam('TRADEDATE')..' '..getInfoParam ('LASTRECORDTIME'), это будет строка формата
      "ДД.ММ.ГГГГ ЧЧ:ММ:СС", в которой будет текущая дата торгов и время последней полученной записи с сервера.

  4. В результате при каждом обновлении стакана по инструменту RTS-6.15 в переменной QuoteStr будет строка, типа:
    -- "15;86130;17;86120;16;86110;22;86100;16;86090;24;86080;26;86070;29;86060;97;86050;..."

    А как же из этой строки понять, где купля, где продажа ?

  5. Добрый день!
    Ничего. 1. Брокер может как то программно это блокировать?
    2. Поток от брокера к стакану, к графику свечей и таблицу всех сделок он разный?

    Спасибо!

    1. Добрый день!
      1.Брокер может не предоставлять Вам информацию по каким-то инструментам, но если у Вас в терминале отображается стакан по этому инструменту, значит все в порядке. Работу функции OnQuote брокер не может блокировать.
      2.Если я не ошибаюсь, то стакан поступает в терминал отдельно, таблица всех сделок отдельно, а графики строятся в терминале по тем данным, которые в них настроены, по умолчанию, по Таблице всех сделок, но можно строить по разным параметрам из Текущей таблицы параметров.

      Попробуйте запустить скрипт с таким текстом, при условии, что у Вас открыт стакан по "SRU5":

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      
      Run = true; -- Флаг поддержания работы бесконечного цикла в main
       
      function main() -- Скрипт работает, пока работает main()
         -- "Бесконечный" цикл
         while Run do sleep(100); end;
      end;
       
      function OnQuote(class_code,sec_code) 
         if class_code == "SPBFUT" and sec_code == "SRU5" then
            message(sec_code);
         end;
      end;
       
      function OnStop()
         Run = false; -- Останавливает работу бесконечного цикла в main(), следовательно завершается работа скрипта
      end;

      Будет у Вас выводится сообщение с текстом "SRU5" ?

  6. Здравствуйте! По каким причинам не происходит вызов ф-ции OnQuote. Стакан по инструменту "SRU5" открыт. Проверку организую так

    1
    
     message(tostring(ql2).."  "..tostring(TableQuote.bid_count),1)

    часть скрипта

    1
    2
    3
    4
    5
    6
    7
    
    function OnQuote(class_code,sec_code)
     
                if class_code == "SPBFUT" and sec_code == "SRU5" then
     
     
     
    	         ql2 = getQuoteLevel2(class_code, sec_code)

    Спасибо!

    1. Здравствуйте! Проверьте вот так:

      1
      2
      3
      4
      5
      6
      
      function OnQuote(class_code,sec_code) 
         if class_code == "SPBFUT" and sec_code == "SRU5" then
            ql2 = getQuoteLevel2(class_code, sec_code);
            message(ql2.bid_count);
         end;
      end;

      или вообще вот так, для начала:

      1
      2
      3
      4
      5
      
      function OnQuote(class_code,sec_code) 
         if class_code == "SPBFUT" and sec_code == "SRU5" then
            message(sec_code);
         end;
      end;

      Если и это не будет работать, то вот так:

      1
      2
      3
      
      function OnQuote(class_code,sec_code) 
         message('OnQuote');
      end;

      Это общий алгоритм!
      Чтобы выявить ошибку, нужно убрать все лишнее, а потом добавлять обратно по 1-му элементу, это самый простой способ найти ошибку, если сразу увидеть не получается.