Отправка транзакций из OnParam

Страницы: 1
RSS
Отправка транзакций из OnParam
 
Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция.
Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает.
Поэтому вопросы.
1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура?
2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam.
Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.  
 
Цитата
Let_it_go написал:
Заметил, что отправка транзакций - выставление и снятие заявок - трудоёмкая операция.
Торгую 50-ю акциями. Если у меня висит 50 заявок, то при их массовом одновременном снятии квик подвисает на несколько секунд. При быстром выставлении такого же числа заявок он тоже зависает.
Поэтому вопросы.
1. Наблюдения верны? Отправка транзакций - ресурсоёмкая процедура?
2. Хочу отправлять транзакции из OnParam. Это плохая идея? С точки зрения логики работы программы это было бы очень удобно. Сейчас у меня отправка заявок идёт в функции main, там в бесконечном цикле перебираются одна за другой 50 акций на соблюдение условия выставления/снятия. Хочу перенести этот блок в OnParam.
Заявок ставится много, они всё время перевыставляются. В день отправляется до 10 тысяч заявок, то есть с учётом снятия это 20 000 транзакций.  
Добрый день.

1. Нет, отправка 50 транзакций не должна подвешивать рабочее место QUIK.

2. Если в  OnParam  будут выполняться долгие циклы по перебору 50 инструментов и проверять не  выполнилось ли условие для отправки транзакции, то тут могут наблюдаться зависания.

Выложите свой скрипт, мы посмотрим.
 
функция для снятия всех заявок.
в неё передаётся таблица с тикерами.
Код
function CleanActive (ticker_list) --переписать её, чтобы искать с конца.
   local row={}
   for i=0,getNumberOf("orders")-1,1 do
      row=getItem("orders",i)   
      local sec=row.sec_code
      if table_contains(ticker_list, sec) and orderflags2table(row.flags).active then
         res,ms=killOrder(tostring(row.order_num),sec,row.class_code)
      end
   end
end
Код
function table_contains(table, element)   
   for _, value in pairs(table) do
      if value == element then return true end
   end
   return nil
end   
Я запускаю CleanActive из OnStop и из самого начала функции main. Это очень часто вешает квик, приходится его убивать через окно с процессами.
 
Цитата
Let_it_go написал:
Я запускаю CleanActive из OnStop и из самого начала функции main. Это очень часто вешает квик, приходится его убивать через окно с процессами.
Добрый день.
Функция OnStop() это тоже функция обратного вызова, соответственно тяжелые и долгие операции в ней будут подвешивать терминал. Допустим у Вас на момент остановки скрипта в терминале 10 000 заявок, при этом большинство из них сняты (делаю вывод из вашего описания из #1 поста), тогда в функции CleanActive() скрипт будет пробегать по всем заявкам, это 10 000 итераций, так же в таблице ticker_list у Вас, допустим, 50 инструментов, линейный пробег по всем еще увеличивает количество итераций (берем среднее значение=25, т.к. не обязательно, что инструмент row.sec_code будет самым последним), итого 10 000 * 25=250 000 итераций. Пока все эти циклы будут выполняться, терминал будет ждать завершения OnStop() и соответственно висеть. Могу только посоветовать оптимизировать логику работы функции CleanActive - использовать функцию SearchItems для поиска всех активных заявок по инструментам из ticker_list. Так же можно убрать линейный забег в функции table_contains, этим Вы уже в разы уменьшите количество итераций, в интернете много примеров как это сделать, вот например:
Код
function addToTable(table, key)
    table[key] = true
end

function removeFromTable(table, key)
    table[key] = nil
end

function tableContains(table, key)
    return table[key] ~= nil
end

Если будут затруднения с использованием функции SearchItems, пишите.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Nikolay Pavlov,
посмотрел описание функции SearchItems. Почему вы её рекламируете по сравнению с
Код
for i=0,getNumberOf("orders")-1,1 do
В ней тоже задаётся список строчек  с какой по какую искать. Если у меня за день 10 000 заявок, скрипт будет пробегать по всем. Разве не так?
 
Nikolay Pavlov,
переменная ticker_list из моего примера:
Код
1=SBER;2=GAZP;3=GMKN;4=LKOH;................
Ключ - число, значение - тикер.
Ваш совет:
Код
function tableContains(table, key)    
return table[key] ~= nil
end
не подойдёт в чистом виде.
Разве что переделать тикер лист в
Код
'SBER'=1; 'GAZP' = 2; 'GMKN' = 3;
тогда ваша функция сработает. Но и в этом случае она где-то там невидимо для меня будет перебирать всю таблицу в поисках ключа.
Спасибо за помощь!
 
Цитата
Let_it_go написал:
Разве что переделать тикер лист в Код'SBER'=1; 'GAZP' = 2; 'GMKN' = 3;тогда ваша функция сработает. Но и в этом случае она где-то там невидимо для меня будет перебирать всю таблицу в поисках ключа.Спасибо за помощь!
Добрый день.
Вам нужно переделать ticker_list в набор вида:
Код
'SBER'=true; 'GAZP'=true; 'GMKN'=true;...
Для этого, Вам достаточно в месте, где Вы формируете таблицу ticker_list использовать вышеописанную функцию:
Код
function addToTable(table, key)
    table[key] = true
end
в этом случае, перебора никакого не будет, (даже "где-то там невидимо..."), т.к. обращение выполняется напрямую по ключу, это в разы быстрее чем перебирать все значения таблицы в цикле. Нужно просто вместо вашей старой функции table_contains использовать:
Код
function tableContains(table, key)
    return table[key] ~= nil
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Цитата
Let_it_go написал:
посмотрел описание функции SearchItems. Почему вы её рекламируете по сравнению с Кодfor i=0,getNumberOf("orders")-1,1 doВ ней тоже задаётся список строчек  с какой по какую искать. Если у меня за день 10 000 заявок, скрипт будет пробегать по всем. Разве не так?
Данная функция сделает это гораздо быстрее.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Nikolay Pavlov,
спасибо за совет!
вопрос по SearchItems. Никогда с ней не работал.

Хочу получить мои сделки за сегодня по BANEP
Код
function fn (t)
   if t.sec_code=='BANEP' then
      return true
   end
end

tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn, "qty,class_code, sec_code")
в результате таблица tbl выглядит так:
Цитата
1=0;2=1;3=2;4=3;5=4;6=5;7=6;8=7;9=8;10=9;11=10;12=11;13=12;14=13;15=14;16=15;17=16;18=17;19=18;20=19;21=20;22=21;23=22;24=23;25=24;26=25;27=26;28=27;29=28;30=29;31=30;32=31;33=32;34=33;35=34;36=35;37=36;38=37;39=38;40=39;41=40;42=41;43=42;44=43;45=44;46=45;47=46;48=47;49=48;50=49;51=50;52=51;53=52;54=53;55=54;56=55;57=56;58=57;59=58;60=59;61=60;62=61;63=62;64=63;65=64;66=65;67=66;68=67;69=68;70=69;71=70;72=71;73=72;74=73;75=74;76=75;77=76;78=77;79=78;80=79;81=80;82=81;83=82;84=83;85=84;86=85;87=86;88=87;89=88;90=89;
у меня за день и правда 90 сделок, но не понятно в чём толк этой функции?
----------------

Если написать чуть-чуть иначе:
Код
function fn (t)
   if t.sec_code=='BANEP' then
      return t
   end
end

tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn)

то он пишет такое:
Цитата
1=18;2=20;3=21;
19,21,22 - это номера моих сделок с Башнефтью. С учётом сдвига всё верно. Но как получить все поля по этим сделкам?
 
Цитата
Let_it_go написал:
19,21,22 - это номера моих сделок с Башнефтью. С учётом сдвига всё верно. Но как получить все поля по этим сделкам?
Функция возвращает только индексы заявок, которые удовлетворяют условиям Вашей функции fn(), дальше нужные заявки нужно забрать функцией row=getItem("orders",i), где i, это индекс из таблицы, которую вернула функция SearchItems.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Так же стоит обратить внимание на то, что написано в документации по функции SearchItems

  • fn – функция обратного вызова, возвращающая одно из следующих
    значений:
    • true – текущий индекс учитывается в результате;
    • false – текущий индекс не учитывается в результате;
    • nil – поиск прерывается, функция SearchItems возвращает таблицу с индексами,
      найденными ранее, включая текущий индекс.
Так что Вам лучше переписать функцию fn, вот пример чтобы выбрать все активные заявки из Вашего списка ticker_list (если функцию table_contains() так же переписать на поиск по ключу, как я писал выше, все должно отрабатывать быстро):
Код
function fn (ord_sec_code, ord_flags)
   if table_contains(ticker_list, ord_sec_code) and orderflags2table(ord_flags).active  then
      return true
   else
      return false
   end
end

tbl=SearchItems('trades', 0, getNumberOf("trades")-1, fn, "sec_code,flags")
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Конечно же должно быть обращение к таблице 'orders'
Код
function fn (ord_sec_code, ord_flags)
   if table_contains(ticker_list, ord_sec_code) and orderflags2table(ord_flags).active  then
      return true
   else
      return false
   end
end

tbl=SearchItems('orders', 0, getNumberOf("orders")-1, fn, "sec_code,flags")
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Nikolay Pavlov,
спрошу про другой случай.
Я знаю, что в нужной мне таблице только один элемент с нужным параметром. Например, я ищу в depo_limits текущий остаток по SBER. Как мне в SearchItems оборвать поиск сразу после того как SBER был найден?

Я делаю что-то в таком духе:
Код
function fn(t)
    if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then 
        return true
    else
        return false
    end
end

tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)

и второй вопрос, как мне в функцию fn передать переменную sec?
 
Если пользовательская функция сравнения в search items возвращает nil,  то поиск прерывается и текущий элемент в таблице результатов не попадает.

значит,  необходимо перед вызовом searchitems создать флаг
ин иницализировать его скажем в nil, при нахождении вашего единственного элемента таблицы изменить флаг на true.

при этом в самом начале пользовательский функции сравнения проверять этот флаг.  Если он true,  значит на пред итерации был найден ваш элемент и необходимо прервать поиск - вернуть nil из функции сравнения.  
www.bot4sale.ru

Пасхалочка для Алексея Иванникова: https://forum.quik.ru/messages/forum10/message63088/topic7052/#message63088
 
Цитата
Let_it_go написал:
и второй вопрос, как мне в функцию fn передать переменную sec?
Добрый день.
По первому вопросу s_mike Вам дал исчерпывающий ответ. По второму вопросу про переменную sec, достаточно ее объявить на уровень выше объявления функции fn, она будет видна внутри функции fn, это можно сделать на глобальном уровне, или же непосредственно перед вызовом функции SearchItems, например:
Код
sec='SBER'
client_code='12345'

function main()
  
  function fn(t)
    if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then 
        return true
    else
        return false
    end
  end

  --или здесь...
  --sec='SBER'
  --client_code='12345'

  tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)

end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
 
Nikolay Pavlov,
посмотрите пожалуйста, это оно?
Код
function fn(t)
   if stop_search then return nil end --stop_search - это флаг. Изначально равен nil
    if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
      stop_search=true
        return true
    else
        return false
    end
end


function get_position (sec)
   stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
   tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)
   limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
   local lot=lot[sec]--lot[sec] ранее определена
   return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
end
 
Вот рабочий вариант, внедрённый в робота. Увы, приходится объявлять переменную paper как глобальную, потому что sec внутри fn не видна.
Код
function fn(t)

    if stop_search then return nil end --stop_search - это флаг. Изначально равен nil

    if t.sec_code == paper and t.client_code==client_code and t.limit_kind==2 then
      stop_search=true      
        return true
    else
        return false
    end

end

function get_position (sec)
   paper=sec
   stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
   tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)   
   if tbl_indxs then
      limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
      local lot=lot[sec]--lot[sec] ранее определена
      return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
   else
      return 0,0,0,0
   end
end
 
Цитата
Let_it_go написал:
Увы, приходится объявлять переменную paper как глобальную, потому что sec внутри fn не видна.
Потому что у Вас функции get_position и fn объявлены на одном уровне, а переменная sec это локальная переменная функции get_position, сделайте вот так, и должно работать:
Код
function get_position (sec)

  function fn(t)

      if stop_search then return nil end --stop_search - это флаг. Изначально равен nil

      if t.sec_code == sec and t.client_code==client_code and t.limit_kind==2 then
        stop_search=true      
          return true
      else
          return false
      end

  end

   stop_search=nil --убиваем флаг, выставленный на прежних запусках функции.
   tbl_indxs=SearchItems('depo_limits', 0, getNumberOf("depo_limits")-1, fn)   
   if tbl_indxs then
      limit = getItem("depo_limits", tbl_indxs[1]) --найден 1 индекс, его и берём.
      local lot=lot[sec]--lot[sec] ранее определена
      return limit.currentbal/lot,limit.locked_buy/lot, limit.locked_sell/lot, limit.awg_position_price
   else
      return 0,0,0,0
   end
end
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf' https://arqatech.com/upload/Public/quik_lua.zip
Страницы: 1
Читают тему
Наверх