Зависает Квик при запуске скрипта передачи данных под Win10

Страницы: 1
RSS
Зависает Квик при запуске скрипта передачи данных под Win10, При апгрейде Win 7 и 8 до Win 10 возникла проблема - квик зависает при запуске скрипта передачи данных
 
Добрый день!
Возникла проблема - при переходе с Win 7 и 8 на Win 10 стал зависать Quik при запуске скрипта, передающего данные в робота (да и скрипт передачи данных в EasyScalp тоже вешает Quik).
Quik 7.0.4.10. Компы - i7 3930k 32G RAM и i7 5960x 16G RAM.
На Win 7,8 все прекрасно работало. Симптомы следующие:
квик работает штатно. Запускаем скрипт, квик уходит в себя (не реагирует на нажатие мышкой на элементы интерфейса), при этом данные в робота идут, стакан в квике бегает, график инструмента в квике застывает.
Скрипт использует dkjson и zmq для передачи данных через сокеты.

Подскажите, чем можно полечить проблему? Откатывать обратно на Win 7,8 не хочтся :(
 
Добрый день.

Так как несмотря на зависания скрипта все остальные данные успешно "двигаются", то рекомендуем все же обратиться к разработчикам данного скрипта.
 
Цитата
Egor Zaytsev пишет:
Добрый день.

Так как несмотря на зависания скрипта все остальные данные успешно "двигаются", то рекомендуем все же обратиться к разработчикам данного скрипта.
Я разработчик скрипта ) И как использование его под разными версиями Win влияет на квик? Квик в висячем состоянии умудряется i7 5960X @3.3Mhz грузить на 5-9%. Если есть вопросы к коду скрипта готов его показать в этой ветке.
 
Цитата
Alex пишет:
Цитата
Egor Zaytsev пишет:
Добрый день.

Так как несмотря на зависания скрипта все остальные данные успешно "двигаются", то рекомендуем все же обратиться к разработчикам данного скрипта.
Я разработчик скрипта ) И как использование его под разными версиями Win влияет на квик? Квик в висячем состоянии умудряется i7 5960X @3.3Mhz грузить на 5-9%. Если есть вопросы к коду скрипта готов его показать в этой ветке.
В таком случае выложите скрипт, мы посмотрим.
 
Собственно скрипт:

package.cpath = package.cpath .. ";" .. getScriptPath() .. [[\?51.dll]]
--require"QL"
require"zmq"
local json=require("dkjson")
--require"zhelpers"
is_run=false
itosend={}
postosend={}
new_postosend={}
acctosend={}
quottosend={}
candlestosend={}
tradestosend={}
orderstosend={}
stop_orderstosend={}
alltrades_tosend={}
filter_acc=''
instruments={}
accounts={}
positions={}
positions_keys={}
last50CandlesAsString = ""
last_tradedate = ''
session={}

--accounts_list=""
publisher_binding="tcp://127.0.0.1:5563"
subscriber_binding="tcp://127.0.0.1:5562"
accounts_keys={}
is_connected=false
local sfind=string.find
FUT_OPT_CLASSES="SPBFUT"
INSTRUMENT="SiH6"

local nLastNumTrade = 0

local function _bitset(flags, index)
 local n = 1
   n = bit.lshift(1, index)
 if bit.band(flags, n) == 0 then
   return false
 else
   return true
 end
end


function onTradeDate()
 local t={}
 last_tradedate = getInfoParam("TRADEDATE")
 local openbal = getItem("money_limits",0).openbal
 --local varmargin = getItem("futures_client_holding",0).varmargin
 --local positionvalue = getItem("futures_client_holding",0).positionvalue
 --local total_varmargin = getItem("futures_client_holding",0).total_varmargin
 t = {
 sess_date = last_tradedate;
 open_balance = openbal;
 }
 session[#session+1] = json.encode(t)
end

function OnTrade(data)
if is_run and is_connected then
 tradestosend[#tradestosend+1]=json.encode(data)
end
end


function OnOrder(data)
if is_run and is_connected then
 orderstosend[#orderstosend+1]=json.encode(data)
end
end

function OnStopOrder(data)
if is_run and is_connected then
 stop_orderstosend[#stop_orderstosend+1]=json.encode(data)
end
end

function ds_getCandlesByIndex(ds,count)
  local size=ds:Size()
  local t={}
  local first_candle = size - count+1
  local end_candle = size
  if end_candle>size then
   end_candle=size
  end
  if first_candle < 0 then
    first_candle = 0
  end
  --message("in func: " .. string.format("%d, %d, %d\n", first_candle, end_candle, count), 1)

  local s = ""
  for i=first_candle,end_candle do
j = i-first_candle
t[j]={
  open=ds:O(i);
  high=ds:H(i);
  low=ds:L(i);
  close=ds:C(i);
  volume=ds:V(i);
  datetime=string.format("%04d%02d%02d;%02d%02d%02d", ds:T(i).year, ds:T(i).month, ds:T(i).day, ds:T(i).hour, ds:T(i).min, ds:T(i).sec);
}
s = s .. string.format("%s;%1.2f;%1.2f;%1.2f;%1.2f;%1.2f\n", t[j].datetime, t[j].open, t[j].high, t[j].low, t[j].close, t[j].volume)
  end
  --message("in func: " .. string.format("%d, %d, %d\n", first_candle, end_candle, count) .. s, 1)
  return s
end

function OnQuote(class, sec )
if is_run and is_connected and (class=='SPBFUT') and (sec==INSTRUMENT) then
 local ql2 = getQuoteLevel2(class, sec)
 quottosend[#quottosend+1]=json.encode(ql2)
end
end

function cb( index )
last50CandlesAsString = ds_getCandlesByIndex(ds1, 2500)
candlestosend[#candlestosend+1]=last50CandlesAsString
end


function OnParam(class,sec)
if is_run and is_connected and (class=='SPBFUT') and (sec==INSTRUMENT) then
 --local st=os.clock()
 -- or class=='OPTUX' class=='SPBOPT' or
 local i=instruments[sec].Dynamic
 i.LastPrice=tonumber(getParamEx(class,sec,"Last").param_value)
 i.Volatility=tonumber(getParamEx(class,sec,"Volatility").param_value)
 i.TheorPrice=tonumber(getParamEx(class,sec,"theorprice").param_value)
 i.Bid=tonumber(getParamEx(class,sec,'BID').param_value)
 i.Ask=tonumber(getParamEx(class,sec,'OFFER').param_value)
 i.BidVol=tonumber(getParamEx(class,sec,'BIDDEPTH').param_value)
 i.AskVol=tonumber(getParamEx(class,sec,'OFFERDEPTH').param_value)
 i.MaxPrice=tonumber(getParamEx(class,sec,'pricemax').param_value)
 i.MinPrice=tonumber(getParamEx(class,sec,'pricemin').param_value)
 i.PriceStep=tonumber(getParamEx(class,sec,'sec_price_step').param_value)
 i.TradeDate=(getParamEx(class,sec,'trade_date_code').param_value)
 if class=='FUTUX' or class=='SPBFUT' then
  i.SettlePrice=tonumber(getParamEx(class,sec,'settleprice').param_value)
 else
  -- i.SettlePrice=tonumber(getParamEx(instruments[sec].Static.BaseContractClass,static.BaseContract,'last').param_value)
 end
 itosend[#itosend+1]=json.encode(i)
end
end

function OnFuturesClientHolding(hold)
if is_run and is_connected and hold~=nil and (filter_acc=='' or string.find(filter_acc,hold.trdaccid)~=nil) then
 --toLog(log,'New holding update')
 --table.insert(acctosend,jsonhold)
 local key=positions_keys[hold.trdaccid..hold.sec_code]
 if key==nil then
  positions[#positions+1]={
  ['AccountName']=hold.trdaccid,
  ['SecurityCode']=hold.sec_code,
  ['TotalNet']=hold.totalnet,
  ['BuyQty']=hold.openbuys,
  ['SellQty']=hold.opensells,
  ['VarMargin']=hold.varmargin
  }
  positions_keys[hold.trdaccid..hold.sec_code]=#positions
  new_postosend[#new_postosend+1]=json.encode(positions[#positions])
 else
  local t=positions[key]
  t.TotalNet=hold.totalnet
  t.BuyQty=hold.openbuys
  t.SellQty=hold.opensells
  t.VarMargin=hold.varmargin
  postosend[#postosend+1]=json.encode(t)
 end
end
end

function OnStop()
is_run=false
--ds1:close()
--publisher:close()
--context:term()
end

function OnInitDo()
--context=zmq.init(1)
--publisher=context:socket(zmq.PUB)
--publisher:bind("tcp://127.0.0.1:5563")
local id=1
ds1 = CreateDataSource("SPBFUT", INSTRUMENT, INTERVAL_M10)
ds1:SetUpdateCallback(cb)
 
for cl in string.gmatch(FUT_OPT_CLASSES,"%a+") do
 local sec_list=getClassSecurities(cl)
 for sec in string.gmatch(sec_list,"%w+%.?%w+") do
 if cl=='SPBFUT' then
  instruments[sec]={}
  instruments[sec].Static={}
  instruments[sec].Dynamic={}
  local static=instruments[sec].Static
  local dynamic=instruments[sec].Dynamic
  static.Class=cl
  static.Code=sec
  static.FullName=getParamEx(cl,sec,'LONGNAME').param_image
  static.Id=id
  if cl=='FUTUX' or cl=='SPBFUT' then
   static.InstrumentType='Futures'
   static.BaseContractClass='RTSIND'
   static.BaseContract=getParamEx(cl,sec,"OPTIONBASE").param_image..'I'
  else
   static.InstrumentType='Option'
   static.BaseContractClass=getSecurityInfo('',sec).class_code
   static.BaseContract=getParamEx(cl,sec,"OPTIONBASE").param_image
  end

  static.OptionType=getParamEx(cl,sec,"OPTIONTYPE").param_image
  static.Strike=tonumber(getParamEx(cl,sec,"STRIKE").param_value)
 
  static.DaysToMate=getParamEx(cl,sec,"DAYS_TO_MAT_DATE").param_image
  static.MaturityDate=getParamEx(cl,sec,"MAT_DATE").param_image
 
  dynamic.LastPrice=tonumber(getParamEx(cl,sec,'last').param_value)
  dynamic.Volatility=tonumber(getParamEx(cl,sec,'volatility').param_value)
  dynamic.TheorPrice=tonumber(getParamEx(cl,sec,'theorprice').param_value)
  if cl=='FUTUX' or cl=='SPBFUT' then
   dynamic.SettlePrice=tonumber(getParamEx(cl,sec,'settleprice').param_value)
  else
   dynamic.SettlePrice=tonumber(getParamEx(static.BaseContractClass,static.BaseContract,'last').param_value)
  end
  dynamic.Bid=tonumber(getParamEx(cl,sec,'BID').param_value)
  dynamic.Ask=tonumber(getParamEx(cl,sec,'OFFER').param_value)
  dynamic.BidVol=tonumber(getParamEx(cl,sec,'BIDDEPTH').param_value)
  dynamic.AskVol=tonumber(getParamEx(cl,sec,'OFFERDEPTH').param_value)
  dynamic.MaxPrice=tonumber(getParamEx(cl,sec,'pricemax').param_value)
dynamic.MinPrice=tonumber(getParamEx(cl,sec,'pricemin').param_value)
dynamic.PriceStep=tonumber(getParamEx(cl,sec,'sec_price_step').param_value)
  dynamic.TradeDate=(getParamEx(cl,sec,'trade_date_code').param_value)
  dynamic.Id=id
  --dynamic.MsgType='INSTRUMENT'
  id=id+1
  end
 end
end
local sf=string.find

return true
--is_run=true
end

function OnConnected(rep,pub)
--reply:recv()
-- message('Connected',3)
if rep~=nil then
 rep:send('CONNECTED')
end
for k,v in pairs(instruments) do
 if v.Static~=nil then
 pub:send('NEWINSTRUMENT',zmq.SNDMORE)
 pub:send(json.encode(v.Static))
 end
 if v.Dynamic~=nil then
 pub:send('INSTRUMENT',zmq.SNDMORE)
 pub:send(json.encode(v.Dynamic))
 end
end
for k,v in ipairs(accounts) do
 pub:send('NEWACCOUNT',zmq.SNDMORE)
 pub:send(json.encode(v))
end
for k,v in ipairs(positions) do
 pub:send('NEWPOSITION',zmq.SNDMORE)
 pub:send(json.encode(v))
end
trades={}
for i=0,getNumberOf('trades')-1 do
 trades=getItem('trades',i)
 pub:send('TRADES',zmq.SNDMORE)  
 pub:send(json.encode(trades))
end

orders={}
for i=0,getNumberOf('orders')-1 do
 orders=getItem('orders',i)
 pub:send('ORDERS',zmq.SNDMORE)
 pub:send(json.encode(orders))
end

stop_orders={}
for i=0,getNumberOf('stop_orders')-1 do
 stop_orders=getItem('stop_orders',i)
 pub:send('STOP_ORDERS',zmq.SNDMORE)
 pub:send(json.encode(stop_orders))
end

 t={}
 last_tradedate = getInfoParam("TRADEDATE")
 local openbal = getItem("money_limits",0).openbal
 --local varmargin = getItem("futures_client_holding",0).varmargin
 --local positionvalue = getItem("futures_client_holding",0).positionvalue
 --local total_varmargin = getItem("futures_client_holding",0).total_varmargin
 t = {
 sess_date = last_tradedate;
 open_balance = openbal;
 }
 pub:send('SESSION',zmq.SNDMORE)
 pub:send(json.encode(t))
   

local init_candles = ds_getCandlesByIndex(ds1, 1600)
   pub:send('CANDLES',zmq.SNDMORE)
pub:send(init_candles)
 
pub:send('COMMON',zmq.SNDMORE)
pub:send('INITIALSYNCEND')
-- message('INITIALSYNCEND',3)
return true
end

function main()
is_run=OnInitDo()
local context=zmq.init(1)
local publisher=context:socket(zmq.PUB)
local reply=context:socket(zmq.REP)
publisher:bind(publisher_binding)
reply:bind(subscriber_binding)

while is_run do
 msg=reply:recv(zmq.NOBLOCK)
 if msg~=nil then
  -- send info for new connections  
  is_connected=OnConnected(reply,publisher)
 -- message('end onconnect '..tostring(is_connected),3)
 end    

 
 if #itosend~=0 then
  for i=1,#itosend do
   local msg=table.remove(itosend,i)
   if msg~=nil then
    publisher:send("INSTRUMENT",zmq.SNDMORE)
    res=publisher:send(msg)
   end
  end
  --message("#"..#tosend,)2zmq
 end
 
 if #postosend~=0 then
  for i=1,#postosend do
   local msg=table.remove(postosend,i)
   if msg~=nil then
    publisher:send("POSITION",zmq.SNDMORE)
    res=publisher:send(msg)
   end
  end
  --message("#"..#tosend,2)
 end
 
 if #new_postosend~=0 then
  for i=1,#new_postosend do
   local msg=table.remove(new_postosend,i)
   if msg~=nil then
    publisher:send("NEWPOSITION",zmq.SNDMORE)
    res=publisher:send(msg)
   end
  end
  --message("#"..#tosend,2)
 end
 
 if #quottosend~=0 then
  for i=1,#quottosend do
   local msg=table.remove(quottosend,i)
   if msg~=nil then
    publisher:send("NEWQUOTES",zmq.SNDMORE)
    res=publisher:send(msg)
   end
  end
  --message("#"..#tosend,2)
 end
 
 if #candlestosend~=0 then
  for i=1,#candlestosend do
   local msg=table.remove(candlestosend,i)
   if msg~=nil then
    publisher:send("CANDLES",zmq.SNDMORE)
    res=publisher:send(msg)
   end
  end
  --message("#"..#tosend,2)
 end  

 if #tradestosend~=0 then
  for i=1,#tradestosend do
   local msg=table.remove(tradestosend,i)
   if msg~=nil then
    publisher:send("TRADES",zmq.SNDMORE)
    res=publisher:send(msg)    
   end
  end  
 end

 if #orderstosend~=0 then
  for i=1,#orderstosend do
   local msg=table.remove(orderstosend,i)
   if msg~=nil then
    publisher:send("ORDERS",zmq.SNDMORE)
    res=publisher:send(msg)    
   end
  end  
 end
 
 if #stop_orderstosend~=0 then
  for i=1,#stop_orderstosend do
   local msg=table.remove(stop_orderstosend,i)
   if msg~=nil then
    publisher:send("STOP_ORDERS",zmq.SNDMORE)
    res=publisher:send(msg)    
   end
  end  
 end
 
 sleep (500)
end
publisher:close()
reply:close()
context:term()

end
 
Добавьте в начало скрипта создание файла, открытие для редактирования и в разные места скрипта разбросайте запись в файл очередного рапорта о прохождении этого участка. Например "пройдено 1", "пройдено 2" и т.д.
Или отправку во внешний дебагер.
Лучше и продуктивнее Вас на Вашем компьютере это никто не сделает.
При зависании Квик, убивайте его в диспетчере и читайте файл.
 
Для начала окружите флагами строки с обращениями к внешним библиотекам.
 
У меня похожая проблема, только Квик не зависает, а падает иногда с дампом, иногда без. Происходит при создании нового Windows+Lua потока (через С код). От ОС не зависит. К сожалению, возникает не регулярно, поэтому провести подробный анализ не удается. Причем падение похоже происходит при вызове _beginthread, т.е. вообще до обращения к Lua.
 
Здравствуйте,
Просьба прислать нам дампы для анализа на ящик quiksupport@arqatech.com
заранее спасибо
 
Сергей, если насчет дампов вы писали мне, то я их уже присылал (CQ01744854), получил ответ, что проблема у вас не воспроизводится. Как только у меня будет какая-либо дополнительная информация, я ее сразу вам пришлю.

Возможно, дампы от топикстартера дадут новую информацию. Полагаю, если немного изменить окружение работы Квика, он будет падать, а не зависать.
 
Нет, в моем случае Quik не падает. Провел эксперименты еще с рядом lua скриптов. Под Win10 загрузка CPU без запуска скрипта составляет 3-5%. После запуска - 6-10% и квик зависает или тормозит.
Проблемы отмечены со скриптами экспорта данных EasyScalp, Cofite LiveTrade Scalping. То есть это проблема системная, связанная с взаимодействием Quik и Win10. Причем на i7 3930k DDR3 проблема проявляется в меньшей степени, чем на i7 5960X DDR4 (тормозит, зависает реже).
Не плохо было бы самим разработчикам поставить Win10 и протестировать работу LUA скриптов под ней.
 
Разработчикам всяких EasyScalp нет желания посоветовать тоже самое?
 
Вы совершенно верно заметили что анализ проблемы производительности скриптов
EasyScalp, Cofite LiveTrade Scalping следует адресовать непосредственно разработчикам этих скриптов.
 
В своем скрипте нашел источник проблем, это коллбэк на обновление информации по свечам:
function cb( index )  
last50CandlesAsString = ds_getCandlesByIndex(ds1, 2500)
candlestosend[#candlestosend+1]=last50CandlesAsString
end

Пока приделал костыль, свечи запрашиваются и отсылаются не при каждом вызове коллбэка, а один раз из 10. Совсем нехороший вариант, но пока ничего лучше не придумал. Может кто придумал более эффективный способ? Можно, конечно, хранить БД по свечкам на локальном компе и запрашивать меньше данных у квика, но это тоже не очень универсальный вариант.
 
Alex
Из приведенного кода не совсем понятно что он делает.
Он при каждом изменении сохраняет последние 50 свечек?
Если так то возможно проблема в логике кода и не надо сохранять последние 50 свечек, а только одну которая изменилась?
Для этого есть функции ds:O(index), ds:H(index), ds:L(index), ds:C(index), ds:V(index)

А если надо получить старые свечки, то не брать постоянно одни и те же свечи в колбэке (смысла нет т.к. они не меняются) а хранить их в какой-нибудь таблице в памяти и добавлять туда новые значения той же table.insert
 
Да, код весьма не элегантен, но на старой винде вполне работал.
Код запрашивает у квика последние 2500 свечей при каждом изменении, да. Затем переводит их в строку и передает боту. Такой подход позволяет снизить риск пропуска свечей в данных. Бот при получении новой строки просто трет в себе старые свечи )
 
То что на старой винде он "вполне работал" совсем ничего не значит.
Просто потому что это разные операционные системы.
Если считаете что именно в этом причина, ищите различия в самих системах. С Ваших слов код же одинаковый, а значит проблем в нем в нет.
Или же все таки прислушаться к совету и привести его в порядок и тогда на любой системе он будет работать нормально.
Это и есть та оптимизация с которой сталкиваются любые программисты
 
Цитата
Код запрашивает у квика последние 2500 свечей при каждом изменении, да. Затем переводит их в строку и передает боту.
:shock:  

Возможно, в этой теме найдёте что-то полезное для себя: CreateDataSource
Надо делать так, как надо. А как не надо - делать не надо.
 
Код
Для этого есть функции ds:O(index), ds:H(index), ds:L(index),   ds:C(index), ds:V(index) 


Кстати, подскажите пожалуйста, что это такое - ds: , в справке вижу примеры, но не могу понять, как этим пользоваться. Напрямую не срабатывает, ds нечто не существующее.
Можете привести полный пример работы?
 
Уже увидел ))
Код
ds = CreateDataSource (ClassCode, SecCode, Interval)for i = 1, ds:Size() do  -- не уверен, что тут нумерация начинается с 1, а не с 0
  Candles[i] = ds:C(i)
end
 
Я не программист. Но чувствую, что в использовании луа зарыта какая-то лажа. Это средство получения данных с ПК?
 
Цитата
Лёня Голиков написал:
Это средство получения данных с ПК?
нож - это орудие убийства? Пока нет тела - нет и дела.
 
Цитата
тот самый написал:
Цитата
Лёня Голиков   написал:
Это средство получения данных с ПК?
нож - это орудие убийства? Пока нет тела - нет и дела.
С ними заодно что-ли? Луа умеет работать с библиотеками винды? Умеет запускать предустановленные приложения (для работы с фото, видео редакторами, архиваторами) с загрузкой цп меньше 1%? Работать с сетевыми устройствами? И что такое low level programming?
Что это?
https://forum.quik.ru/messages/forum10/message6500/topic677/#message6500
Именно в этом месте только додумки, пусть знающие обратят внимание.
 
правомерность использования LUA в среде операционной системы и QUIK-а - это забота антивируса и его эвристик.
Страницы: 1
Читают тему
Наверх