CreateDataSource возвращает пустой набор данных, Функция CreateDataSource возвращает пустой набор данных, сообщений об ошибках нет
Пользователь
Сообщений: Регистрация: 27.06.2017
27.06.2017 13:12:34
добрый день. терминал Quik 7.11.1.5. пример кода скрипта:
Код
function main()
arrTickers = { "MICEXINDEXCF", "MICEX10INDEX", "MICEXBMI", "MICEXCGS", "MICEXCHM", "MICEXFNL",
"MICEXM&M", "MICEXMNF", "MICEXO&G","MICEXPWR","MICEXSC", "MICEXTLC", "MICEXTRN",
"MICEXINNOV", "MICEXMBICP", "MICEXMBITR" }
for n = 1, 16, 1 do
strTicker = arrTickers[ n ]
dsData, strError = CreateDataSource( "INDX", strTicker, INTERVAL_MN1 )
if dsData == nil then
message( "CreateDataSource( "..strTicker.." ) error: "..strError, 3 )
else
if dsData:Size() == 0 then
if strError == nil then
message( "CreateDataSource( "..strTicker.." ) is empty", 2 )
else
message( "CreateDataSource( "..strTicker.." ) is empty: "..strError, 2 )
end
else
message( "CreateDataSource( "..strTicker.." ) success "..dsData:Size() )
end
end
sleep( 3000 )
end
end
в результате работы скрипта все наборы данных пустые - dsData:Size() == 0, ошибок нет - strError == nil. графики необходимых интервалов для соответствующих инструментов в терминале открыты. что я делаю не так и почему так происходит? самое интересное что две недели назад то же самое работало без проблем ... заранее большое спасибо за ответы
Пользователь
Сообщений: Регистрация: 30.01.2015
27.06.2017 13:22:24
Вода из крана начинает капать с некоторой задержкой после того как вы начали поворачивать вентиль.
здесь то же самое. Данные будут несколько позже.
Пасхалочка для Алексея Иванникова:
Пользователь
Сообщений: Регистрация: 27.06.2017
27.06.2017 13:27:39
Цитата
написал: Вода из крана начинает капать с некоторой задержкой после того как вы начали поворачивать вентиль. здесь то же самое. Данные будут несколько позже.
то есть такую процедуру надо делать в конце дня? после обеда? или когда? как узнать когда наступило это время? прошу прощения за вопросы которые может быть имеют очевидные ответы - новичок в этом деле. спасибо за помощь
Пользователь
Сообщений: Регистрация: 30.01.2015
27.06.2017 14:14:02
Процедуру можно делать в тот момента когда она вам нужна.
Схематично эта процедура стучится к брокеру с просьбой послать терминалу данные по требуемому вам инструменту.
весточек должны доставить (dhl или голуби), сервер после ее получения докушает чай, отошлет назад данные (может снова голубями), потом терминал их рассует по полкам т только после этого они станут доступны вам.
сколько времени пройдет на все эти пассы -гетзвестно. Но явно больше, чем выполняется один оператор lua в вашей программе.
Пасхалочка для Алексея Иванникова:
Пользователь
Сообщений: Регистрация: 27.06.2017
27.06.2017 16:30:34
Цитата
написал: Процедуру можно делать в тот момента когда она вам нужна. Схематично эта процедура стучится к брокеру с просьбой послать терминалу данные по требуемому вам инструменту. ... сервер после ее получения докушает чай, отошлет назад данные (может снова голубями), потом терминал их рассует по полкам только после этого они станут доступны вам. сколько времени пройдет на все эти пассы -гетзвестно. Но явно больше, чем выполняется один оператор lua в вашей программе.
логика работы процедуры понятна, большое спасибо. в документации написано что есть возможность установить для получаемого набора данных функцию обратного вызова - SetUpdateCallback - для обработки изменившихся данных. насколько я понимаю, данная функция будет вызываться столько раз, сколько данных (свечей) есть в наборе (это как минимум), кроме этого она будет вызываться каждый раз по мере изменения последней свечи. если изменения последней свечи можно каким-то образом обработать, то все равно непонятно когда переставать получать данные - я же не знаю сколько данных на сервере брокера (сколько свечей). также в документации написано, что есть у функции GetDataSource необязательный параметр STRING param, про который написано только что если этот параметр не задан, то заказываются данные на основании Таблицы обезличенных сделок, если задан – данные по этому параметру. однако возможные значения этого параметра не приводятся. так как все-таки делать-то - через функцию обратного вызова и сравнивать даты свечей с тем, что необходимо получить или использовать какое-то значение этого необязательного параметра?! где тогда взять это значение, непонятно ...
Пользователь
Сообщений: Регистрация: 27.06.2017
27.06.2017 17:28:46
вот так вот нормально будет?
Код
function main()
strTicker = "MICEXINDEXCF";
dsData, strMessage = CreateDataSource( "INDX", strTicker, INTERVAL_MN1 )
if dsData == nil then
message( "CreateDataSource( "..strTicker.." ) error: "..strMessage, 3 )
end
tmTic = os.time()
while dsData:Size() == 0 do
sleep( 5000 )
message( "Waiting for "..os.difftime( os.time(), tmTic ).." seconds so far .." )
end
tmTac = os.time()
message( "Getting data took "..os.difftime( tmTac, tmTic ).." seconds. Data source size: "..dsData:Size() )
-- Do something with the data ...
dsData:Close()
end
можно не с нулем сравнивать а с каким-либо значением, но в любом случае это по-моему бред, джентльмены, хоть и работает. вопрос с параметрами все-таки остается открытым - подскажите пожалуйста где можно посмотреть возможные значения
Пользователь
Сообщений: Регистрация: 31.01.2015
28.06.2017 05:49:13
Примерно так и надо делать при инициализации скрипта. Только цикл ожидания лучше сделать другим:
Код
ждём, пока не будет ds:Size() > 0, периодически засыпая на 100 мс, но не более 15-20 секунд
Практика показывает, что если за это время не пришли данные, то дальше ждать бесполезно.
Пользователь
Сообщений: Регистрация: 19.10.2016
29.06.2017 20:10:20
Ставлю ожидание на 30 секунд, однако, всё равно возвращает пустые значения. Что-то долго голуби летят, или я чего-то не так делаю?
Код
DS,Error = CreateDataSource(CLASS_CODE, cur_sec, INTERVAL);
-- Проверка
if DS == nil then
message('Входила:ОШИБКА получения доступа к свечам! ');
end;
t=0;
while DS:Size() == 0 and t<30000 do
sleep( 1000 )
t=t+1000;
end
if t>29000 then message(cur_sec.." Empty") end;
При этом, что характерно - если у меня открыт график с каким-либо инструментом, он без проблем выцепит данные с него. Однако по задумке требуется работать с большим количеством инструментов и содержать армию графиков не вариант (собсно, cur_sec у меня и содержит название инструмента, берёт верно)
Пользователь
Сообщений: Регистрация: 27.06.2017
29.06.2017 20:35:45
Цитата
Егор Масалкин написал: Ставлю ожидание на 30 секунд, однако, всё равно возвращает пустые значения. Что-то долго голуби летят, или я чего-то не так делаю? ... При этом, что характерно - если у меня открыт график с каким-либо инструментом, он без проблем выцепит данные с него ...
у меня работает вот такой код (что в принципе то же самое):
попробуйте после вызова функции CreateDataSource() добавить следующую строку: if (not dsData:SetEmptyCallback()) then message("Server returns no data") end Если сообщение у вас появится, вероятнее всего, что проблема на стороне брокера (возможно, "слетели" какие-то настройки либо появились новые ограничения частного характера).
Пользователь
Сообщений: Регистрация: 27.06.2017
30.06.2017 09:43:15
Цитата
Andrei2016 написал: попробуйте после вызова функции CreateDataSource() добавить следующую строку:
Код
if (not dsData:SetEmptyCallback()) then message("Server returns no data") end
Если сообщение у вас появится, вероятнее всего, что проблема на стороне брокера (возможно, "слетели" какие-то настройки либо появились новые ограничения частного характера).
Andrei2016, попробую обязательно, хотя и не понятно почему на основании этого можно делать какие-то выводы. после закрытия торговой сессии на фондовом рынке все равно должна работать возможность получения данных через CreateDataSource, я правильно понял? а необязательный параметр STRING param - кто-нибудь знает возможные значения?
Добрый день. Для определения кода параметра, включите в настройках рабочего места Quik настройку Формальное представление данных (раздел 'Программа->Буфер обмена'), добавьте в Таблицу текущих торгов необходимые параметры, скопируйте ее содержимое в буфер обмена (Ctrl+C) и вставьте, например, в блокнот, и Вы увидите, какие значения нужно передавать в STRING param.
Перед тем как задать вопрос, убедитесь, что решение Вашей задачи не описано в официальном мануале - 'Использование Lua в Рабочем месте QUIK.pdf'
Пользователь
Сообщений: Регистрация: 27.06.2017
30.06.2017 10:23:18
Цитата
Nikolay Pavlov написал: Для определения кода параметра, включите в настройках рабочего места Quik настройку Формальное представление данных (раздел 'Программа->Буфер обмена'), добавьте в Таблицу текущих торгов необходимые параметры, скопируйте ее содержимое в буфер обмена (Ctrl+C) и вставьте, например, в блокнот, и Вы увидите, какие значения нужно передавать в STRING param.
в документации про возможные значения параметра ничего не написано, упоминается Таблица обезличенных сделок, а не текущих параметров. тайные знания и волшебство какое-то ... спасибо, Nikolay Pavlov
Пользователь
Сообщений: Регистрация: 23.01.2015
30.06.2017 10:32:06
Цитата
Alexegin написал: в документации про возможные значения параметра ничего не написано,
Таблица торгов, меняется в зависимости от рынка. На разных рынках разные параметры. Даже более того, на одном рынке, у разных брокеров, набор может быть разным. Таким образом, даже если бы в документации были описаны параметры, то не факт что они у Вас есть. В связи с чем, правильней всего с начала посмотреть что Вам нужно в таблице, а потом узнать какой для этого нужен заголовок. И пути два. Либо через DDE (что надежней), либо через документацию info.chm -Раздел 8. Алгоритмический язык QPILE --Функции для получения значений Таблицы текущих торгов ---Значения параметров функций
через документацию не надежней т.к. как уже говорилось и еще раз, набор параметров в таблице торгов может быть разным. описать вообще все возможные варианты параметров к сожалению не представляется возможным.
Таблица торгов, меняется в зависимости от рынка. На разных рынках разные параметры. Даже более того, на одном рынке, у разных брокеров, набор может быть разным. Таким образом, даже если бы в документации были описаны параметры, то не факт что они у Вас есть. В связи с чем, правильней всего с начала посмотреть что Вам нужно в таблице, а потом узнать какой для этого нужен заголовок. И пути два. Либо через DDE (что надежней), либо через документацию info.chm. -Раздел 8. Алгоритмический язык QPILE --Функции для получения значений Таблицы текущих торгов ---Значения параметров функций
через документацию не надежней т.к. как уже говорилось и еще раз, набор параметров в таблице торгов может быть разным. описать вообще все возможные варианты параметров к сожалению не представляется возможным.
большое спасибо, Sergey Gorokhov. я лишь говорю о том, что в соответствующем разделе документации по Lua (а не QPILE) нет никакой информации ни о возможных значениях параметров, ни о том где это можно посмотреть, ни о том о чем вы пишите тем более.
а после закрытия торговой сессии фондовой секции функция CreateDataSource должна работать или нет, не подскажите? или это от брокера зависит и надо у него спрашивать (ВТБ24)?
Sergey Gorokhov написал: а какая разница, если параметры одни и те же?
ну не знаю ... просто если я при использовании Lua читаю про функцию CreateDataSource в соответствующем разделе соответствующего документа, у меня почему-то не возникает мыслей посмотреть значения параметров другого языка для другой функции другой таблицы - наверное потому что про это ничего не написано?
Ваш код работает. Но как только меняют параметры, пишу dsData, strMessage = CreateDataSource( "SPBFUT", "RIU7", INTERVAL_MN1 )
то выдаёт, что размер будет 0. НО как только я делаю график, то он спокойно получает данные... но ведь он с сервера должен брать свечи, а не с графика?
ну серьёзно... может я такой аутист что правильно не могу переписать коды? Но нет... может опять какая-то беда с фьючерами?
Пользователь
Сообщений: Регистрация: 27.06.2017
30.06.2017 17:01:22
Цитата
Егор Масалкин написал: Ваш код работает. Но как только меняют параметры, пишу
то выдаёт, что размер будет 0. НО как только я делаю график, то он спокойно получает данные... но ведь он с сервера должен брать свечи, а не с графика?
еще раз проверьте коды класса и инструмента - отображается после нажатия в терминале Alt+I при соответствующей выбранной строке в Таблице текущих параметров
попробуйте следующий код - просто скопируйте и сохраните в файле test.lua:
Код
function main()
dsData, strMessage = CreateDataSource( "SPBFUT", "RIU7", INTERVAL_MN1 )
if dsData == nil then
message( "CreateDataSource() error: "..strMessage, 3 )
else
tmTac = os.time()
repeat
sleep( 1000 )
until ( dsData:Size() == 0 ) or ( os.difftime( os.time, tmTac ) <= 15 )
tmTic = os.time()
if dsData:Size() == 0 then
message( "CreateDataSource() returned empty dataset. Waiting timeout: "..os.difftime( tmTic, tmTac ), 2 )
else
message( "CreateDataSource() success. Waiting timeout: "..os.difftime( tmTic, tmTac ) )
end
dsData:Close()
end
end
Цитата
Егор Масалкин написал: ну серьёзно... может я такой аутист что правильно не могу переписать коды? Но нет... может опять какая-то беда с фьючерами?
скорее всего просто досадная ошибка, которую вы в упор не видите - так бывает
Пользователь
Сообщений: Регистрация: 19.10.2016
11.07.2017 11:56:08
Методом проб и ошибок понял в чем ошибка.
Проблема была в функции OnInit(), в которой я писал весь код. Как только я поменял на функцию main, что было у товарища , всё сразу заработало.
Пользователь
Сообщений: Регистрация: 27.06.2017
11.07.2017 14:27:23
Цитата
Егор Масалкин написал: Методом проб и ошибок понял в чем ошибка. Проблема была в функции OnInit(), в которой я писал весь код. Как только я поменял на функцию main, что было у товарища , всё сразу заработало.
еще одно добавление (полученное опять же методом проб и ошибок):
Использую вот такой код для получения большого количества свечек. Он их сбрасывает в файлы но можно что угодно делать. Возвращает (возможно пустой) список инструментов которые заглохли, их можно повторно запросить, в случае ошибки не возвращает ничего. Входные данные это массив объектов в формате { class = "TQBR", sec = "SBER", int = "TICK", param = "" }.
Код
local _is_running = 1
function OnStop ( )
_is_running = 0
return 10000
end
function isOnline ( )
return isConnected ( ) + _is_running == 2
end
local function dumpbatch ( batch, timeout, batchsize )
local batchsize = batchsize or 8
local timeout = timeout or 2
local basestr = getScriptPath ( ) .. "/dump/"
local filestr = basestr .. "%s %s %s%s.csv"
local liststr = basestr .. "_list.txt"
local stallstr = basestr .. "_stall.txt"
local intervals = {
['TICK'] = INTERVAL_TICK,
['1'] = INTERVAL_M1, ['2'] = INTERVAL_M2, ['3'] = INTERVAL_M3, ['4'] = INTERVAL_M4, ['5'] = INTERVAL_M5, ['6'] = INTERVAL_M6, ['10'] = INTERVAL_M10, ['15'] = INTERVAL_M15, ['20'] = INTERVAL_M20, ['30'] = INTERVAL_M30,
['1H'] = INTERVAL_H1, ['2H'] = INTERVAL_H2, ['4H'] = INTERVAL_H4, ['D'] = INTERVAL_D1, ['W'] = INTERVAL_W1, ['M'] = INTERVAL_MN1 }
do -- sanitization
assert ( type ( batch ) == 'table', "Invalid argument: 'batch' is not 'table'." )
assert ( type ( batchsize ) == 'number', "Invalid argument: 'batchsize' is not 'number'." )
assert ( type ( timeout ) == 'number', "Invalid argument: 'timeout' is not 'number'." )
for i = 1, #batch do
assert ( type ( batch[ i ] ) == 'table', "Invalid batch item: not 'table'.")
assert ( type ( batch[ i ].class ) == 'string', "Invalid batch item: 'class' is not 'string'." )
assert ( type ( batch[ i ].sec ) == 'string', "Invalid batch item: 'sec' is not 'string'." )
assert ( type ( batch[ i ].int ) == 'string', "Invalid batch item: 'int' is not 'string'." )
assert ( type ( batch[ i ].param ) == 'string', "Invalid batch item: 'param' is not 'string'." )
assert ( intervals[ batch[ i ].int ], "Invalid batch item: 'int' is not a valid time interval ( TICK, 1, 2, 3, 4, 5, 6, 10, 15, 20, 30, 1H, 2H, 4H, D, W, M )." )
end
end
local runbatch, stalled = { }, { }
while #batch + #runbatch > 0 do
if #runbatch < batchsize and #batch > 0 then -- process batch item
local entry = table.remove ( batch )
local fname = string.format ( filestr, entry.class, entry.sec, entry.int, entry.param )
local file = io.open ( fname, "r" )
if file then file:close ( ); goto runbatch end -- skip existing dumps
for i = 1, #stalled do -- skip stalled securities
if entry.class == stalled[ i ].class and entry.sec == stalled[ i ].sec then
table.insert ( stalled, entry )
goto runbatch
end
end
local source, error
if entry.param ~= "" then
source, error = CreateDataSource ( entry.class, entry.sec, intervals[ entry.int ], entry.param )
else
source, error = CreateDataSource ( entry.class, entry.sec, intervals[ entry.int ] )
end
if source then
source:SetEmptyCallback ( )
table.insert ( runbatch, { entry = entry, source = source, fname = fname, time = 0 } )
else
message ( string.format ( "Failed to create data source: %s\n%s %s %s %s" , error, entry.class, entry.sec, entry.int, entry.param ) )
end
end
::runbatch::
for e = #runbatch, 1, -1 do -- run batch
local entry = runbatch[ e ]
if entry.source:Size ( ) == 0 then
entry.time = entry.time + 0.100
if entry.time >= timeout then
table.insert ( stalled, entry.entry )
table.remove ( runbatch, e )
end
else
local file = io.open ( entry.fname, "w" )
local source = entry.source
for i = 1, source:Size ( ) do
file:write ( string.format ( "%04d%02d%02d,%02d%02d,%f,%f,%f,%f,%f\n",
source:T ( i ).year, source:T ( i ).month, source:T ( i ).day, source:T ( i ).hour, source:T ( i ).min,
source:O ( i ), source:H ( i ), source:L ( i ), source:C ( i ), source:V( i ) ) )
end
file:close ( )
source:Close ( )
file = io.open ( liststr, "a" )
file:write ( string.format ( "%s\n", entry.fname ) )
file:close ( )
table.remove ( runbatch, e )
end
end
if #runbatch > 0 then sleep ( 100 ) end
if not isOnline ( ) then return end
end
local file = io.open ( stallstr, "w" )
for i = 1, #stalled do
file:write ( string.format ( "%s %s %s %s\n", stalled[ i ].class, stalled[ i ].sec, stalled[ i ].int, stalled[ i ].param ) )
end
file:close ( )
return stalled
end