добрый день. терминал 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. графики необходимых интервалов для соответствующих инструментов в терминале открыты. что я делаю не так и почему так происходит? самое интересное что две недели назад то же самое работало без проблем ... заранее большое спасибо за ответы
s_mike@rambler.ru написал: Вода из крана начинает капать с некоторой задержкой после того как вы начали поворачивать вентиль. здесь то же самое. Данные будут несколько позже.
то есть такую процедуру надо делать в конце дня? после обеда? или когда? как узнать когда наступило это время? прошу прощения за вопросы которые может быть имеют очевидные ответы - новичок в этом деле. спасибо за помощь
Процедуру можно делать в тот момента когда она вам нужна.
Схематично эта процедура стучится к брокеру с просьбой послать терминалу данные по требуемому вам инструменту.
весточек должны доставить (dhl или голуби), сервер после ее получения докушает чай, отошлет назад данные (может снова голубями), потом терминал их рассует по полкам т только после этого они станут доступны вам.
сколько времени пройдет на все эти пассы -гетзвестно. Но явно больше, чем выполняется один оператор lua в вашей программе.
s_mike@rambler.ru написал: Процедуру можно делать в тот момента когда она вам нужна. Схематично эта процедура стучится к брокеру с просьбой послать терминалу данные по требуемому вам инструменту. ... сервер после ее получения докушает чай, отошлет назад данные (может снова голубями), потом терминал их рассует по полкам только после этого они станут доступны вам. сколько времени пройдет на все эти пассы -гетзвестно. Но явно больше, чем выполняется один оператор lua в вашей программе.
логика работы процедуры понятна, большое спасибо. в документации написано что есть возможность установить для получаемого набора данных функцию обратного вызова - SetUpdateCallback - для обработки изменившихся данных. насколько я понимаю, данная функция будет вызываться столько раз, сколько данных (свечей) есть в наборе (это как минимум), кроме этого она будет вызываться каждый раз по мере изменения последней свечи. если изменения последней свечи можно каким-то образом обработать, то все равно непонятно когда переставать получать данные - я же не знаю сколько данных на сервере брокера (сколько свечей). также в документации написано, что есть у функции GetDataSource необязательный параметр STRING param, про который написано только что если этот параметр не задан, то заказываются данные на основании Таблицы обезличенных сделок, если задан – данные по этому параметру. однако возможные значения этого параметра не приводятся. так как все-таки делать-то - через функцию обратного вызова и сравнивать даты свечей с тем, что необходимо получить или использовать какое-то значение этого необязательного параметра?! где тогда взять это значение, непонятно ...
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
можно не с нулем сравнивать а с каким-либо значением, но в любом случае это по-моему бред, джентльмены, хоть и работает. вопрос с параметрами все-таки остается открытым - подскажите пожалуйста где можно посмотреть возможные значения
Ставлю ожидание на 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 у меня и содержит название инструмента, берёт верно)
Егор Масалкин написал: Ставлю ожидание на 30 секунд, однако, всё равно возвращает пустые значения. Что-то долго голуби летят, или я чего-то не так делаю? ... При этом, что характерно - если у меня открыт график с каким-либо инструментом, он без проблем выцепит данные с него ...
у меня работает вот такой код (что в принципе то же самое):
попробуйте после вызова функции CreateDataSource() добавить следующую строку: if (not dsData:SetEmptyCallback()) then message("Server returns no data") end Если сообщение у вас появится, вероятнее всего, что проблема на стороне брокера (возможно, "слетели" какие-то настройки либо появились новые ограничения частного характера).
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' https://arqatech.com/upload/Public/quik_lua.zip
Nikolay Pavlov написал: Для определения кода параметра, включите в настройках рабочего места Quik настройку Формальное представление данных (раздел 'Программа->Буфер обмена'), добавьте в Таблицу текущих торгов необходимые параметры, скопируйте ее содержимое в буфер обмена (Ctrl+C) и вставьте, например, в блокнот, и Вы увидите, какие значения нужно передавать в STRING param.
в документации про возможные значения параметра ничего не написано, упоминается Таблица обезличенных сделок, а не текущих параметров. тайные знания и волшебство какое-то ... спасибо, Nikolay Pavlov
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. НО как только я делаю график, то он спокойно получает данные... но ведь он с сервера должен брать свечи, а не с графика?
ну серьёзно... может я такой аутист что правильно не могу переписать коды? Но нет... может опять какая-то беда с фьючерами?
то выдаёт, что размер будет 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
Цитата
Егор Масалкин написал: ну серьёзно... может я такой аутист что правильно не могу переписать коды? Но нет... может опять какая-то беда с фьючерами?
скорее всего просто досадная ошибка, которую вы в упор не видите - так бывает
Проблема была в функции OnInit(), в которой я писал весь код. Как только я поменял на функцию main, что было у товарища Alexegin, всё сразу заработало.
Егор Масалкин написал: Методом проб и ошибок понял в чем ошибка. Проблема была в функции OnInit(), в которой я писал весь код. Как только я поменял на функцию main, что было у товарища Alexegin , всё сразу заработало.
еще одно добавление (полученное опять же методом проб и ошибок):
Использую вот такой код для получения большого количества свечек. Он их сбрасывает в файлы но можно что угодно делать. Возвращает (возможно пустой) список инструментов которые заглохли, их можно повторно запросить, в случае ошибки не возвращает ничего. Входные данные это массив объектов в формате { 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