Зависает Квик при запуске скрипта передачи данных под 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 не хочтся :(
Так как несмотря на зависания скрипта все остальные данные успешно "двигаются", то рекомендуем все же обратиться к разработчикам данного скрипта.
Я разработчик скрипта ) И как использование его под разными версиями Win влияет на квик? Квик в висячем состоянии умудряется i7 5960X @3.3Mhz грузить на 5-9%. Если есть вопросы к коду скрипта готов его показать в этой ветке.
Так как несмотря на зависания скрипта все остальные данные успешно "двигаются", то рекомендуем все же обратиться к разработчикам данного скрипта.
Я разработчик скрипта ) И как использование его под разными версиями Win влияет на квик? Квик в висячем состоянии умудряется i7 5960X @3.3Mhz грузить на 5-9%. Если есть вопросы к коду скрипта готов его показать в этой ветке.
--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
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
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()
Добавьте в начало скрипта создание файла, открытие для редактирования и в разные места скрипта разбросайте запись в файл очередного рапорта о прохождении этого участка. Например "пройдено 1", "пройдено 2" и т.д. Или отправку во внешний дебагер. Лучше и продуктивнее Вас на Вашем компьютере это никто не сделает. При зависании Квик, убивайте его в диспетчере и читайте файл.
У меня похожая проблема, только Квик не зависает, а падает иногда с дампом, иногда без. Происходит при создании нового Windows+Lua потока (через С код). От ОС не зависит. К сожалению, возникает не регулярно, поэтому провести подробный анализ не удается. Причем падение похоже происходит при вызове _beginthread, т.е. вообще до обращения к Lua.
Сергей, если насчет дампов вы писали мне, то я их уже присылал (CQ01744854), получил ответ, что проблема у вас не воспроизводится. Как только у меня будет какая-либо дополнительная информация, я ее сразу вам пришлю.
Возможно, дампы от топикстартера дадут новую информацию. Полагаю, если немного изменить окружение работы Квика, он будет падать, а не зависать.
Нет, в моем случае Quik не падает. Провел эксперименты еще с рядом lua скриптов. Под Win10 загрузка CPU без запуска скрипта составляет 3-5%. После запуска - 6-10% и квик зависает или тормозит. Проблемы отмечены со скриптами экспорта данных EasyScalp, Cofite LiveTrade Scalping. То есть это проблема системная, связанная с взаимодействием Quik и Win10. Причем на i7 3930k DDR3 проблема проявляется в меньшей степени, чем на i7 5960X DDR4 (тормозит, зависает реже). Не плохо было бы самим разработчикам поставить Win10 и протестировать работу LUA скриптов под ней.
Вы совершенно верно заметили что анализ проблемы производительности скриптов 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 свечей при каждом изменении, да. Затем переводит их в строку и передает боту. Такой подход позволяет снизить риск пропуска свечей в данных. Бот при получении новой строки просто трет в себе старые свечи )
То что на старой винде он "вполне работал" совсем ничего не значит. Просто потому что это разные операционные системы. Если считаете что именно в этом причина, ищите различия в самих системах. С Ваших слов код же одинаковый, а значит проблем в нем в нет. Или же все таки прислушаться к совету и привести его в порядок и тогда на любой системе он будет работать нормально. Это и есть та оптимизация с которой сталкиваются любые программисты
Для этого есть функции 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 Именно в этом месте только додумки, пусть знающие обратят внимание.