Использование Subscribe_Level_II_Quotes

Страницы: 1
RSS
Использование Subscribe_Level_II_Quotes, получение данных стакана без открытия стакана
 
мне нужно по 30 бумагам получить цену закрытия предыдущего дня из ТТП (через getParamEx(class_code,tiket_code,"prevlegalclosepr").param_value)
найти в стакане самый большой объем на продажу и открытие. взять из них цену и вывести процентное соотношение.
чтобы не открывать 30 стаканов (а мне еще заявки ставить). пробую сделать через Subscribe_Level_II_Quotes.
работает медленно, но я пробую так:
из файла в таблицу TIKETS загружен список бумаг. key - код бумаги
function main()
   while is_run do
       for key, value in spairs(tikets) do
           Subscribe_Level_II_Quotes(class_code, key)
           Quotes(key)
 end
end
end

function Quotes(code)
sleep(250)
for i=1, 30 do
q = getQuoteLevel2(class_code, code)
--получаю стакан, перебираю его. добавляю в таблицу в окне данные.
max_bid_price и max_ask_price

prevlegalclosepr=tonumber(getParamEx(class_code, code,"last").param_value)
if (max_bid_price==0) or (max_ask_price==0) then
               delta==0
           else
if max_bid_price >= max_ask_price then
delta = (prevlegalclosepr/max_bid_price)
else
delta = (prevlegalclosepr)
end
           end

SetCell(Таблица, НомерСтрокиПоБумаге, 6, delta)

и т.д.
первая проблема -  перебор 30 строк в таблице это долго. вторая -  если сделаю меньший sleep то часто не получаю данные стакана.

в этой строке
delta = (prevlegalclosepr/max_bid_price)
временами ошибка attempt to perform arithmetic on local 'delta ' (a string value)
причину отловить не могу. механизмов отладки нет (или я не нашел где они).
как мне эффективнее сделать данный алгоритм?
или при инициализации, где я загружаю коды тикетов в таблицу сделать Subscribe_Level_II_Quotes по каждой бумаге, а потом просто перебирать через getQuoteLevel2?
 
не редактируется сообщение

поломался код
Код
 function main()

    while is_run do

        for key, value in spairs(tikets) do

            Subscribe_Level_II_Quotes(class_code, key)

            Quotes(key)

     end

   end

end



function Quotes(code)

   sleep(250)

   for i=1, 30 do

      q = getQuoteLevel2(class_code, code)

--получаю стакан, перебираю его. добавляю в таблицу в окне данные. 

   max_bid_price и max_ask_price



   prevlegalclosepr=tonumber(getParamEx(class_code, code,"last").param_value)

      if (max_bid_price==0) or (max_ask_price==0) then

                delta==0

            else

         if max_bid_price >= max_ask_price then 

            delta = (prevlegalclosepr/max_bid_price)

         else

            delta = (prevlegalclosepr/max_ask_price)

         end

            end

   

   SetCell(Таблица, НомерСтрокиПоБумаге, 6, delta)
 
Цитата
"Eldar пишет:
и т.д.
первая проблема -перебор 30 строк в таблице это долго.
Вынесите Subscribe_Level_II_Quotes в отдельный цикл, перед строкой "while is_run do" заказывать постоянно одни и те же стаканы нет смысла. Плюс, сам цикл "for i=1, 30 do  совершенно не понятен. Зачем он?

Цитата
Eldar пишет:
вторая -если сделаю меньший sleep то часто не получаю данные стакана.
На заказ данных по очередному скакану требуется время, но 250 как-то много. обычно хватает 10-50. Быть может терминал чем-то нагружен? Попробуйте провести эксперимент с sleep(50) но при этом закрыв все посторонние окна в терминале.
Цитата
Eldar пишет:
временами ошибка attempt to perform arithmetic on local 'delta ' (a string value )
Тут проще, если стакан не полный, то при обращении к пустой строке стакана функция выдаст nil, отсюда и ошибка.

Цитата
Eldar пишет:
причину отловить не могу. механизмов отладки нет (или я не нашел где они).
Механизмов отладки много, самый простой это логирование через PrintDbgStr. Также в интернете можно почитать про Decode и ее аналоги.
 
Цитата
Eldar пишет:
поломался код
Какую ошибку пишет?
 
Цитата
Sergey Gorokhov пишет:
Цитата
Eldar пишет:
поломался код
Какую ошибку пишет?
это по форуму. код нечитабельный стал. не вставился тег CODE. может у меня глюк.

Цитата
Sergey Gorokhov пишет:
Вынесите Subscribe_Level_II_Quotes в отдельный цикл, перед строкой "while is_run do" заказывать постоянно одни и те же стаканы нет смысла. Плюс, сам цикл "for i=1, 30 doсовершенно не понятен. Зачем он?
мне надо запросить объемы в стаканах по 30 бумагам.
мне Subscribe_Level_II_Quotes запросить один раз на каждую бумагу в отдельном цикле?  а потом получать стакан по getQuoteLevel2?

Цитата
Sergey Gorokhov пишет:
Тут проще, если стакан не полный, то при обращении к пустой строке стакана функция выдаст nil, отсюда и ошибка.
то есть ставить условие

Код
 if (max_bid_price~=nil) or (max_bid_price==0) then

                delta==0
долго, потому что наверно в цикле делаю Subscribe_Level_II_Quotes, потом иду обрабатывать данные. но попробую уменьшить количество окон и почистить код
 
Цитата
Eldar пишет:
Цитата
Sergey Gorokhov пишет:
Вынесите Subscribe_Level_II_Quotes в отдельный цикл, перед строкой "while is_run do" заказывать постоянно одни и те же стаканы нет смысла. Плюс, сам цикл "for i=1, 30 doсовершенно не понятен. Зачем он?
мне надо запросить объемы в стаканах по 30 бумагам.
мне Subscribe_Level_II_Quotes запросить один раз на каждую бумагу в отдельном цикле?а потом получать стакан по getQuoteLevel2?
Посмотрите код внимательней.

Вот Вы гоняете в цикле все бумаги по очереди:
Код
for key, value in spairs(tikets) do


Далее, для каждой из этих бумаг Вы вызываете функцию Quotes в которой вызываете цикл "for i=1, 30 do"
Таким образом, если в таблице "tikets" у Вас 30 бумаг, то в общем случае, за одну итерацию, цикл "for i=1, 30 do" приведет к тому что функции внутри него будут вызваны 30*30=900 раз.
Конечно, сложно судить не видя полного кода, но на мой взгляд 900 раз вызывать одни и те же функции совершенно излишне.

Цитата
Eldar пишет:

то есть ставить условие

То есть ограничить просмотр строк в стакане количеством этих строк.
Для этого надо использовать параметры "bid_count" и "offer_count"
 
Цитата
Eldar пишет:
мне Subscribe_Level_II_Quotes запросить один раз на каждую бумагу в отдельном цикле?а потом получать стакан по getQuoteLevel2?
Да, так будет оптимальней. Повторные вызовы Subscribe_Level_II_Quotes абсолютно лишние.
 
Цитата
Sergey Gorokhov пишет:
Далее, для каждой из этих бумаг Вы вызываете функцию Quotes в которой вызываете цикл "for i=1, 30 do"
Таким образом, если в таблице "tikets" у Вас 30 бумаг, то в общем случае, за одну итерацию, цикл "for i=1, 30 do" приведет к тому что функции внутри него будут вызваны 30*30=900 раз.
Конечно, сложно судить не видя полного кода, но на мой взгляд 900 раз вызывать одни и те же функции совершенно излишне.
первый цикл - это запрос стаканов по бумагам.
второй цикл - это внесение изменений в таблицу.
 
Цитата
Eldar пишет:
второй цикл - это внесение изменений в таблицу.
Тогда уберите getQuoteLevel2 и все что с ним связано из второго цикла. Ее достаточно взять 1 раз перед циклом "for i=1, 30 do"
 
Цитата
Eldar пишет:
второй цикл - это внесение изменений в таблицу.
У вас в цикле "for i=1, 30 do" нигде не используется переменная-счётчик i. Отсюда, на первый взгляд, в этом цикле вы делаете 30 раз одни и те же действия.  
Надо делать так, как надо. А как не надо - делать не надо.
 
1) на любой взгляд этот цикл "for i=1, 30 do" лишний.

2) Если надо делать такое лишь один раз в сессию то можно и так,
но если это делается всю сессию,
то надо ставить колбек OnQuote(STRING class_code, STRING sec_code).  
 
Цитата
Sergey Gorokhov пишет:
Тогда уберите getQuoteLevel2 и все что с ним связано из второго цикла. Ее достаточно взять 1 раз перед циклом "for i=1, 30 do"
но мне надо получать данные стакана регулярно, а не только один раз.
плюс все же тут не весь код.
мне надо понять логику.
получается что обычно OnQuote работает с открытыми стаканами, но через Subscribe_Level_II_Quotes я подписываюсь на изменения.
то есть в первом цикле делаю Subscribe_Level_II_Quotesпо всем тикетам, а потом отрабатываю через OnQuote (а внутри через getQuoteLevel2) ?
второй цикл не нужен, так как изменить данные нужной строки таблицы вывода я могу через SetCell, где ключем будет код бумаги.
Цитата
Sergey Gorokhov пишет:
То есть ограничить просмотр строк в стакане количеством этих строк.
Для этого надо использовать параметры "bid_count" и "offer_count"
каким образом? я получаю таблицу через getQuoteLevel2. потом получаю таблицу BID и OFFER

Код
bid_count = tonumber(q["bid_count"])
ask_count = tonumber(q["offer_count"])
bid = q["bid"]
ask = q["offer"]
и перебираю данные в

Код
for bid_i=1, bid_count, 1 do
   bid_quantity = tonumber( bid[bid_i]["quantity"] )
   if (bid_quantity > max_bid_count) then
      max_bid_count = bid_quantity
      max_bid_price = bid[bid_i]["price"]
   end
end 
почему я тут могу получить NIL? или если у меня не загрузится стакан, то как раз поэтому у меня NIL и выходит?
 
вопрос немного у другую тему - а могу я автоматически стопануть скрипт, если закрыто окно с таблицей вывода?
 
Цитата
Eldar пишет:
вопрос немного у другую тему - а могу я автоматически стопануть скрипт, если закрыто окно с таблицей вывода?
Да, используйте для этого условие на функцию IsWindowClosed
 
Цитата
Eldar пишет:
почему я тут могу получить NIL? или если у меня не загрузится стакан, то как раз поэтому у меня NIL и выходит?
Выложите полный текст скрипта.
 
Цитата
Sergey Gorokhov пишет:
Выложите полный текст скрипта.
Код
--константы
data_file = "s_test.txt"   --путь к файлу со списком акций и кодов классов

--переменные скрипта
is_run = true      --Режим работы скрипта, работает или остановлен
shares = {}      --Список акций
shares_count = 0   --Количество акций
table_data = nil   --Данные для визуальной таблицы
class_code = "TQBR"     --Код классов
t = nil         --Указатель на визуальную таблицу


--Дополнительый поток
function main()
   while is_run do
      for key, value in spairs(shares) do
         i = i + 1
                   Subscribe_Level_II_Quotes(class_code, key)
         Quotes(key)         
      end
   end
end

function OnInit(quik_path)
   --читаем из файла акции и коды классов
   for line in io.lines(getScriptPath() .. "\\" .. data_file) do
      pos = string.len(line)
      share = string.sub(line, 0, pos)

      share_item = {}
      share_item["class"] = class_code
      shares[share] = share_item
      shares_count = shares_count + 1
   end

   table.sort(shares)

   --содержимое таблицы   
   table_data = {}


   --Создаем структуру, описывающую таблицу
   t = AllocTable()

   --столбцы
   AddColumn(t, 1, "Ticker", true, QTABLE_STRING_TYPE, 10)
   AddColumn(t, 2, "Count Bid", true, QTABLE_INT_TYPE, 10)
   AddColumn(t, 3, "Bid Price", true, QTABLE_STRING_TYPE, 10)
   AddColumn(t, 4, "Count Ask", true, QTABLE_INT_TYPE, 10)
   AddColumn(t, 5, "Ask Price", true, QTABLE_STRING_TYPE, 10)
   AddColumn(t, 6, "Delta", true, QTABLE_STRING_TYPE, 10)

   CreateWindow(t)
   SetWindowCaption(t, "Price_Delta")
   SetWindowPos(t, 200, 200, 500, 600)

   for i=1, shares_count do
      InsertRow(t, -1)
   end
 
   i = 0

   -- заполняем таблицу используя сортировку по ключам
   for key, value in spairs(shares) do
      i = i + 1
      sec_code = key
      SetCell(t, i, 1, tostring(sec_code))
      SetColor(t, i, 1, RGB(150, 150, 150), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
   end
end


function OnStop()
   is_run = false
   for key, value in spairs(shares) do      
      Unsubscribe_Level_II_Quotes(class_code, key)
   end
end

function Quotes(code)
   sleep(150)
   for i=1, shares_count do
      local row = GetCell(t, i, 1)
      row_sec = tostring(row["image"])
           if (row_sec == code) then
              q = getQuoteLevel2(class_code, code)
                   bid_count = tonumber(q["bid_count"])
         ask_count = tonumber(q["offer_count"])

         bid = q["bid"]   --покупатели
         ask = q["offer"]   --продавцы
                   max_bid_count = 0   --количество лотов (максимальный спрос)
         max_ask_count = 0   --количество лотов (максимальное предложение)
         max_bid_price = ""   --цена максимального спроса
         max_ask_price = ""   --цена максимального предложения


         --перебираем всех покупателей и находим самый большой объем
         for ii=1, bid_count, 1 do
            bid_quantity = tonumber( bid[ii]["quantity"] )
            if (bid_quantity > max_bid_count) then
               max_bid_count = bid_quantity
               max_bid_price = bid[ii]["price"]
            end
         end

         --перебираем всех продавцов находим самый большой объем
         for ii=1, ask_count, 1 do
            ask_quantity = tonumber( ask[ii]["quantity"] )
      
            if (ask_quantity > max_ask_count) then
               max_ask_count = ask_quantity
               max_ask_price = ask[ii]["price"]
            end
         end
                   
         SetCell(t, i, 2, tostring(max_bid_count))
         SetColor(t, i, 2, RGB(50, 250, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         SetCell(t, i, 3, tostring(max_bid_price))
         SetColor(t, i, 3, RGB(50, 250, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         SetCell(t, i, 4, tostring(max_ask_count))
         SetColor(t, i, 4, RGB(250, 50, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         SetCell(t, i, 5, tostring(max_ask_price))
         SetColor(t, i, 5, RGB(250, 50, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
          

         if (max_ask_count>max_bid_count) then   
            price_max=max_ask_price
            SetCell(t, i, 2, "")
            SetColor(t, i, 2, RGB(255, 255, 255), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
            SetCell(t, i, 3, "")
            SetColor(t, i, 3, RGB(255, 255, 255), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)   
         elseif (max_ask_count<max_bid_count) then
            price_max=max_bid_price
            SetCell(t, i, 4, "")
            SetColor(t, i, 4, RGB(255, 255, 255), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
            SetCell(t, i, 5, "")
            SetColor(t, i, 5, RGB(255, 255, 255), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)   
         else 
            price_max=max_bid_price
         end
          
         closeprice=tonumber(getParamEx(class_code, code,"last").param_value)
         if (closeprice==0) then
            delta=0
         else
            delta=(tonumber(price_max)/closeprice-1)*100
         end
         
         SetCell(t, i, 6, apply_scale(delta,2))
         if delta>=2 then
            SetColor(t, i, 6, RGB(50, 250, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         elseif delta<=-2 then
            SetColor(t, i, 6, RGB(250, 50, 50), QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         else 
                           SetColor(t, i, 6, RGB(255, 255, 255), QTABLE_DEFAULT_COLOR,QTABLE_DEFAULT_COLOR, QTABLE_DEFAULT_COLOR)
         end
      end
   end   
end
 

ну как-то так
и что по поводу логики подскажете
Цитата
Eldar пишет:
получается что обычно OnQuote работает с открытыми стаканами, но через Subscribe_Level_II_Quotes я подписываюсь на изменения.
то есть в первом цикле делаю Subscribe_Level_II_Quotesпо всем тикетам, а потом отрабатываю через OnQuote (а внутри через getQuoteLevel2) ?
второй цикл не нужен, так как изменить данные нужной строки таблицы вывода я могу через SetCell, где ключем будет код бумаги.
 
Цитата
Eldar пишет:
Код
 for bid_i=1, bid_count, 1 do
   bid_quantity = tonumber( bid[bid_i]["quantity"] )
   if (bid_quantity > max_bid_count) then
      max_bid_count = bid_quantity
      max_bid_price = bid[bid_i]["price"]
   end
end  
почему я тут могу получить NIL? или если у меня не загрузится стакан, то как раз поэтому у меня NIL и выходит?
У нас не воспроизводится.
Приведите полный текст ошибки.
Цитата
Eldar пишет:
и что по поводу логики подскажете
Цитата
Eldar пишет:
получается что обычно OnQuote работает с открытыми стаканами, но через Subscribe_Level_II_Quotes я подписываюсь на изменения.
то есть в первом цикле делаю Subscribe_Level_II_Quotesпо всем тикетам, а потом отрабатываю через OnQuote (а внутри через getQuoteLevel2) ?
второй цикл не нужен, так как изменить данные нужной строки таблицы вывода я могу через SetCell, где ключем будет код бумаги.
Вы программист, Вам решать какую логику использовать.
 
Ошибка тут:

delta=(tonumber(price_max)/closeprice-1)*100


Ошибка плавающая. иногда сразу выскакивает, иногда через час.
Цитата
Sergey Gorokhov пишет:
Вы программист, Вам решать какую логику использовать.
дело в том, что не понятно как работает функция Subscribe_Level_II_Quotes:
1. запрашиваем стакан по тикету. получаем единоразово стакан и обрабатываем через getQuoteLevel2
2. помечаем стакан тикета на отслеживание изменений. отслеживаем изменения стакана через OnQuote.обрабатываем через getQuoteLevel2.
скуповата документация.
Цитата
Sergey Gorokhov пишет:
Да, используйте для этого условие на функцию IsWindowClosed
в этой функции я могу пометить is_run как false и не обрабатывать в main, но скрипт все еще будет запущен.
а мне надо остановить его в коде, как через меню "Остановить". скрипт выполнил расчет, нужный тикет мне показал через message и остановился.
 
плохо, что нельзя свое сообщение редактировать. приходится добавлять.
может мне проще Subscribe_Level_II_Quotes использовать в функции OnInit()?
 
Цитата
Eldar пишет:
дело в том, что не понятно как работает функция Subscribe_Level_II_Quotes:
вызов Subscribe_Level_II_Quotes аналогичен открытию стакана в терминале QUIK.
Без открытия стакана данные в него не поступают. Соответственно OnQuote и getQuoteLevel2 работать не будут
Цитата
Eldar пишет:
в этой функции я могу пометить is_run как false и не обрабатывать в main, но скрипт все еще будет запущен.
Это значит что Вы не понимаете как работает IsWindowClosed
Напишите в функции Quotes так:

Код
function Quotes(code)
   sleep(150)
   for i=1, shares_count do
    if IsWindowClosed(t) then 
      is_run=false
      break 
    end
--остальной код
 
 
Цитата
Eldar пишет:
может мне проще Subscribe_Level_II_Quotes использовать в функции OnInit()?
На Ваше усмотрение
 
Спасибо. что-то проясняется.
например найден BREAK. но так как документация скудная, появился следующий вопрос.
после BREAK не выполнится функция OnStop(), я правильно понимаю?
 
Цитата
Eldar пишет:
Спасибо. что-то проясняется.
например найден BREAK. но так как документация скудная, появился следующий вопрос.
По поводу документации объясняю.
Язык LUA придумали НЕ мы.
Мы взяли готовый язык и добавили в него несколько наших функций.
Поэтому в НАШЕЙ документации только НАШИ функции.
Все функции которые являются стандартными для языка LUA описаны в документации на язык LUA, которая есть в интернете:
http://www.lua.org/docs.html

BREAK приводит к выходу из цикла. Подробнее в документации на LUA
 
так у меня вопросы касаются работы именно в сочетании с quik.
с break понятно.
но тогда все еще не понятен вопрос, как именно ОСТАНОВИТЬ выполнение скрипта. вот как через меню "Доступные скрипты" - Остановить.
и вопрос про функцию Subscribe_Level_II_Quotes по моему мнению тоже резонный.
спасибо за разьяснения, но вроде вопросов все больше и больше. буду пробовать допиливать.
 
Цитата
Eldar пишет:
но тогда все еще не понятен вопрос, как именно ОСТАНОВИТЬ выполнение скрипта. вот как через меню "Доступные скрипты" - Остановить.
Чтобы остановить работу скрипта, нужно остановить работу всех функций и циклов этого скрипта.
Пример уже был дан.
 
Цитата
Eldar пишет:
и вопрос про функцию Subscribe_Level_II_Quotes по моему мнению тоже резонный.
На вопрос где лучше использовать Subscribe_Level_II_Quotes у нас нет и не может быть ответа.
Так как этот вопрос зависит от Вашего видения работы программы.
Можно даже сказать от Вашего вкуса.
Страницы: 1
Читают тему
Наверх