читайте внимательно документацию. Там стоит звездочка - т е надо читать сноску, а в сноске написано: (*) В зависимости от настроек сервера QUIK, величина может выражаться в лотах или в штуках. Уточните единицы измерения у обслуживающего брокера.
Функция getBuySellInfoEx возвращает два параметра:
Цитата
is_long_allowed = 1; //Признак того, является ли бумага разрешенной для покупки на заемные средства. Возможные значения: «1» – разрешена, «0» – не разрешена. is_short_allowed = 1; //Признак того, является ли бумага разрешенной для покупки на заемные средства. Возможные значения: «1» – разрешена, «0» – не разрешена.
То есть бумага для которой я запрашивал getBuySellInfoEx - имеет возможность торговли с плечом.
Но параметр так же возвращенный функцией getBuySellInfoEx:
Ваше пожелание зарегистрировано. Мы постараемся рассмотреть его и сообщить Вам результаты анализа. Впоследствии, по результатам анализа, будет приниматься решение о реализации пожелания в будущих версиях ПО.
Quikos написал: Подскажите, возможна ли остановка и запуск скрипта из другого скрипта ?
К примеру так: первый скрипт следит за соединение Квика - если соединение разрывается, то первый скрипт останавливает второй скрипт. Первый скрипт ждет пока восстановится соединение и как только соединение восстанавливается первый скрипт запускает второй скрипт.
скрипт - это всего лишь текст на языке луа. Почему не можете все написать в одном романе, зачем второй?
А Вы можете изъяснятся точно, точно так же, как пишите код, а не про Романов писать ?
В настоящий момент в QLua нет функции, которая позволяла бы запустить в Рабочем месте QUIK какой-либо загруженный скрипт. Возможно, для Ваших целей подойдет стандартная Lua-функция require - с ее помощью можно запустить внешний по отношению к терминалу скрипт, то есть не работающий напрямую с терминалом.
Отметим, что описанный Вами алгоритм можно реализовать в одном скрипте: 1) используя функцию isConnected для отслеживания наличия соединения с сервером и условные операторы для выполнения определенного блока кода; 2) используя функции обратного вызова OnDisconnected и OnConnected , исполняющие заданный код в случае отключения терминала от сервера QUIK или установления связи с сервером соответственно. Более подробная информация о применении указанных функций доступна в Руководстве пользователя интерпретатора QLua ( https://arqatech.com/upload/iblock/194/quik_lua.zip) .
При выборе описанного подхода нет необходимости в запуске дополнительных скриптов.
Это не поможет, так как при вызове хотя бы одной функция SetUpdateCallback:Close() - дальнейшая подписка на прием данных через CreateDataSource - НЕ работает в запущенном скрипте. Чтобы CreateDataSource - опять работал, нужно выгрузить скрипт и опять его запустить.
Kolossi написал: Как и повода жаловаться на SetUpdateCallback.
Хотите сказать - у Вас описываемого мной косяка разрабов не наблюдается ?
Нет не наблюдается. Просто может быть потому что я сразу подстраховался и забил. Жалко времени на это тратить. Реальная функция из скрипта, была написана на ранних версиях квика и с тех пор не трогалась: Полагаю счетчик и повтор решили возможную проблему.
С вероятностью 99,9% - Вы просто ее не замечаете, так как она наблюдается именно сразу после запуска Квика и после Первого запуска скрипта, на второй, третий и последующий разы - данная пробелма не наблюдается до тех пор пока Вы не перезапустите Квик заново.
При этом разработчики - собаки сутулые - в течении годов ничего с этим не делают.
local code_class1 = "TQBR"
local code_paper1 = "GAZP"
local interval1 = INTERVAL_TICK
local code_class2 = "TQBR"
local code_paper2 = "SBER"
local interval2 = INTERVAL_TICK
------------------------
local function my_cb_CDS (idx,tabl)
message (tostring(tabl.sec) .. "," .. tostring(idx), 1 )
Sleep( 100 );
end
-----------------------------------------------------------------------------------------------------------int main:-----------------------------------------------------------------------------------------------------
function main ()
while not stopped do
if tab1 = = nil then tab1 = CreateDataSource (code_class1, code_paper1, interval1);
if tab1 then
tab1.clas = code_class1; tab1.sec = code_paper1; tab1.int = interval1;
tab1: SetUpdateCallback ( function (idx) my_cb_CDS(idx,tab1) end )
end
end
if tab2 = = nil then tab2 = CreateDataSource (code_class2, code_paper2, interval2);
if tab2 then
tab2.clas = code_class2; tab2.sec = code_paper2; tab2.int = interval2;
tab2: SetUpdateCallback ( function (idx) my_cb_CDS(idx, tab2) end )
end
end
-------------------------
-- message(tostring(my_table1:Size()),1)
sleep ( 1000 )
end
-------------------------
end -- end main()
function OnInit (script_path)
end
Данный код так же Не работает с Первого раза, ТОЛЬКО со Второго раза.
nikolz написал: Переписал Ваш скрипт , но действительно, если таблица обезличенных сделок не открыта, то руками запускается со второго раза, а автоматом - с первого. Очевидно это какая-то особенность или ошибка библиотеки QLUA.
Причем для некоторых акций - запускается с первого раза, а для некоторых со второго. Навряд ли такое поведение можно называть "особенностью" - это явный косяк.
nikolz написал: Скрипт запускаете руками или автоматом с запуском квика? Если автоматом, то в скрипте надо делать ожидание. ---------------- Проще, если вам нужны тики, то просто подпишитесь на них через меню и они будут приходить при старте квика без проблем.
Скрипт запускается полностью вручную.
Это хорошо, что можно подписаться через меню. Но это явный косяк в API.
чтобы понять причину надо смотреть ваш скрипт.
Скрипт простейший:
Код
function my_callback_CreateDataSource(my_table_data_, code_class_, code_paper_, interval_, cntr)
message(code_paper_)
end
-----------------------------------------------------------------------------------------------------------int main:-----------------------------------------------------------------------------------------------------
function main()
local code_class1 = "TQBR"
local code_paper1 = "GAZP"
local interval1 = INTERVAL_TICK
local code_class2 = "TQBR"
local code_paper2 = "SBER"
local interval2 = INTERVAL_TICK
local my_table1, error_desc1 = CreateDataSource(code_class1, code_paper1, interval1) --Вызываем собсвенно CreateDataSource
------------------------Проверка на ошибки:-------------------
if error_desc1 ~= nil then
message("Error")
end
--------------------------------------------------------------
message(tostring(my_table1.Size()))
if my_table1.Size() == 0 then
message("data requested from the server")
end
local my_table2, error_desc2 = CreateDataSource(code_class2, code_paper2, interval2) --Вызываем собсвенно CreateDataSource
------------------------Проверка на ошибки:-------------------
if error_desc2 ~= nil then
message("Error")
end
--------------------------------------------------------------
message(tostring(my_table2.Size()))
if my_table2.Size() == 0 then
message("data requested from the server")
end
my_table1:SetUpdateCallback(function(idx)my_callback_CreateDataSource(my_table_data1, code_class1, code_paper1, interval1) end)
my_table2:SetUpdateCallback(function(idx)my_callback_CreateDataSource(my_table_data2, code_class2, code_paper2, interval2) end)
-------------------------
while not stopped do
sleep(1)
end
-------------------------
end -- end main()
И если бы была ошибка в скрипте - то на второй раз запуска скрипта, колбек так же бы не вызывался, НО на второй раз все рабоатет, как и ожидается. Но только на второй раз.
Параметр Тип Описание money_open_limit NUMBER Входящий лимит по денежным средствам money_limit_locked_nonmarginal_value NUMBER Стоимость немаржинальных бумаг в заявках на покупку money_limit_locked NUMBER Заблокированное в заявках на покупку количество денежных средств money_open_balance NUMBER Входящий остаток по денежным средствам money_current_limit NUMBER Текущий лимит по денежным средствам money_current_balance NUMBER Текущий остаток по денежным средствам money_limit_available NUMBER Доступное количество денежных средств
Вызвал функцию getMoney() - она вернула условно следующие значения:
Там где нули пока что не интересует, там, где 1000 руб - функия вернула корректно, при условии, что у меня не было открытых позиций.
Я специально купил одну акцию и стоиомсть портфеля начала соовтевтнно изменятся, но при вызове getMoney() - возвращается все та же - 1000. Я закрыл сделку - стоимость изменилась - условно стала 998, но при вызове getMoney() - возвращается все та же - 1000.
Это так и должно быть ? Если да, то, как тогда получить кол-во доступных средств на конкретный данный момент в который вызвается getMoney() ? Под доступными средвами я имею ввиду, если у меня была 1000 на счете, я купил одну какую то акцию по 100 рублей - дсотупно мне стало 900, вот как эти 900 получить ?
nikolz написал: Скрипт запускаете руками или автоматом с запуском квика? Если автоматом, то в скрипте надо делать ожидание. ---------------- Проще, если вам нужны тики, то просто подпишитесь на них через меню и они будут приходить при старте квика без проблем.
Скрипт запускается полностью вручную.
Это хорошо, что можно подписаться через меню. Но это явный косяк в API.
Заказываю тики через CreateDataSource:SetUpdateCallback().
Запускаю Квик: -Загружаю скрипт. -Запускаю скрипт. -Скрипт вызывает CreateDataSource. -CreateDataSource возвращает нулевую таблицу, что говорит о том, что данные придут позже в колбек. -Колбек больше НИКОГДА не вызывается.
Выгружаю Скрипт и СРАЗУ же его запускаю - данные сразу же начинают приходить.
У функции getMoney() - какие то не понятные параметры, которая она принимает:
из примера:
Цитата
-- Параметры для запроса берутся из таблицы "Лимиты по дененым средствам" -- client_code = "Код клиента" -- firmid = "Фирма" -- tag = "Группа" -- currcode = "Валюта"
У меня в таблице лимиты по денежным средствам - из перечисленного есть только код клиента, который я естественно и так знаю. Все остальное вообще не понятно ничего.
Что за фирма ? Что за группа ? Кармен или машина времени ? Валюта ?? Что валюта ? Рубли? Так и писать РУБЛИ ??
Для кого это описание написано ? Для ясновидящих ? А зачем оно им ?
OnDisconnected: Функция вызывается терминалом QUIK при отключении от сервера QUIK.
isConnected: Функция предназначена для определения состояния подключения клиентского места к серверу. Возвращает «1», если клиентское место подключено и «0», если не подключено.
Kolossi написал: Quikos, если я поставлю заявку на покупку и она в итоге сработает, а потом куплю выставленную кем-то на продажу, т.е. совершу две покупки - одну лимитную, одну по рынку, то в ленте сделок эти две сделки будут обозначены одна как "покупка" другая как "продажа". Потому что в любой сделке присутствует и покупка и продажа в равных долях, а в ленте отражается та часть сделки которая "по рынку". Как-то так.
Так совершение сделки "по рынку" - это по сути такое же выставление заявки на покупку к примеру, просто сразу совпадающее с предложением. Навряд ли это где то это отдельно фиксируется.
nikolz написал: Если Вам очень важно знать все ли свечи Вы приняли, то просто проверьте дату и время последней и сравните с текущем временем и датой.
nikolz, а как для ds с тиковым интервалом?
Таблица ds тиков - заполняется вся не сразу, только что проверил в цикле с паузой 3 мс. Сначала 0,736, 775, 993, 1057, 5697, 7099, 11184... кстати да встает вопрос, как определить, когда таблица то в итоге заполнилось полностью.
С интервалом начиная от 1 минуты - вроде бы размер приходить сразу полностью заполненный окончательно.
Когда я запрашиваю SetUpdateCallback от CreateDataSource - по тикам - из приход строго упорядоченные ?
То есть не может быть ситуации:
Это два последних тика для 29 минуты:
-вызвался callback - пришел тик, время условно: 15:29:59 - теоретически этот тик должен относится к последней сделке на данный конкретный момент. -вызвался callback - пришел тик, время условно: 15:29:59 - теоретически этот тик должен относится к последней сделке на данный конкретный момент, НО фактически этот тик относится к сделке, которая была ДО предыдущего тика.
То есть не может быть такой ситуации, что я учту второй тик - как цену закрытия 29 минуты, НО фактически цена закрытия - будет в первом тике - так как именно он относится к последней сделке в этой 29 минуте. ?
Подскажите пожалуйста, когда я запрашиваю таблицу исторических свечей через CreateDataSource, то таблица сразу приходит заполненная окончательным размером или размер меняется по мере заполнения ?
Теоретически таблица сразу должна заполнится итоговым размером. Правильно ?
Владимир написал: Quikos, Я когда-то спрашивал техподдержку, и ответ меня убил наповал: они считают свечи именно из ТОС, биржа транслирует только её. И уже на основании посчитанных ими свечей и работает вся эта глючная и тормознутая лабуда типа SetUpdateCallback или CreateDataSource или что там у них есть.
И далее из той же темы:
Цитата
2) Если создавать источник данных функцией CreateDataSource() НЕ по тиковому интервалу, а например по минутному, заказ обезличенных сделок не выполняется, т.к. с сервера QUIK заказываются непосредственно свечки;
Или Вы обманываете или Вас обманули или в той теме обманули.
Владимир написал: Quikos, Я когда-то спрашивал техподдержку, и ответ меня убил наповал: они считают свечи именно из ТОС, биржа транслирует только её. И уже на основании посчитанных ими свечей и работает вся эта глючная и тормознутая лабуда типа SetUpdateCallback или CreateDataSource или что там у них есть.
Ха, вот нашел про Таблицу Обезличенных Сделок и OnAllTrade() - тут:https://forum.quik.ru/forum10/topic1610/ И вроде как это не совпадает с тем, что Вы написали:
Цитата
Nikolay Pavlov 1) Для срабатывания OnAllTrade() не обязательно должна быть открыта таблица обезличенных сделок, достаточно выполнить заказ обезличенных сделок в меню Система/Заказ данных/Поток обезличенных сделок. Сделать это можно вручную, проставив галочки на необходимых классах и отфильтровав инструменты, если это необходимо, или же непосредственно из скрипта Lua создав ТИКОВЫЙ источник данных для обезличенных сделок функцией CreateDataSource() и заказать их трансляцию выполнив метод SetEmptyCallback() для созданного источника данных.
Повторяю: я считаю все свечи сам, причём не эту японскую дрянь, а как среднее арифметическое значений курса за период, считаю, что это даёт куда более достоверную информацию. Считаю именно опросом ТТТ, для десятков и сотен тикеров, по десятку таймфреймов у каждого, начиная с 10-секундных и кончая часовыми. Просто, быстро, надёжно, информативно, работает как часы вот уже несколько лет, прямо с момента создания, и плевать мне сто раз на все реконнекты и пропущенные данные. Зачем искать на свою задницу приключений?
Вы почти убедили меня использовать таблицу обезличенных сделать и самом формировать временные свечи, но CerateDataSourse - все равно в некоторых случая придется использовать (правда не SetUpdatecallback) - чтобы получить историю свечей в случае, если я к примеру 1-2 дня не запускал терминал.
Владимир написал: Quikos, 1. ЕСЛИ "скрипт получает каждые данные изменившейся цены и дату/время" ТО это таблица обезличенных сделок, т.е. один из самых тормознутых и глючных способов определения свечей. 2. ПОФИГ, произошёл ре-коннект или нет, имеем поступление новых данных, которые то ли уже приходили, то ли ещё нет, и определять нужно именно это.
Нет - это SetUpdateCallback CreateDataSource.
Поэтому после ре-коннекта - мне нужно будет проверить всю приходящую таблицу на предмет пропущенных свечей - во время отсутствия коннекта и только после проверки и учета пропущенных данных - опять принимать данные изменившейся цены.
-Соединение установлено -Скрипт получает каждые данные изменившейся цены и дату/время и упаковывает в свечи по интервалу. -Предположим произошел дисконнект Квика. -Через 5 минут произошел опять коннект и данные опять начали приходить, но прежде, чем принимать после дисконнекта данные - нужно заполнить 5 минутный пропущенный промежуток. -А для этого, нужно как то определить, что произошел ре-коннект.
Michael Bulychev написал: Добрый день. ошибки, которые может вернуть CreateDataSource: - "invalid context" - функция вызвана вне main или других зарезервированных функций; - "unknown class code"; - "unknown param name" - не найден такой параметр на заданном классе; - "static param" - параметр в ТТП есть, но он берется из описания бумаги (getSecurityInfo); - "CreateNetDataSource failed" - это ошибка общего характера, например не хватило памяти.
Или в Квике или в Lua - где то явно ошибка.
Я вызываю CreateDataSource из DLL - проверяя ID потока из которого я вызываю. ID потока всегда на каждый вызов CreateDataSource- одинаков, НО примерно на 50 или 100ый вызов CreateDataSourceпоявляется ошибка "invalid context" - хотя до этого момента все вызовы CreateDataSource - были успешны.
Собственно вопрос: если я заказываю стакан с помощью Subscribe_Level_II_Quotes, после отключения скрипта - он автоматически будет отписан, то есть эквивалентен вызову Unsubscribe_Level_II_Quotes ?
-вот я вызываю CreateDataSource -в отдельном потоке запускаю функцию - которая каждые 100 мс - проверяю размер таблицы -Как только размер таблицы (к примеру данные запрашивались на сервере) становится больше 0, то значит данные таблицы свечей получены -Завершаю функцию.
Вроде бы все нормально, но есть случай - когда по какому то инструменту/акции - просто нету вообще свечей, то есть акция есть - а торгов по ней вообще на данный момент еше не было. И в итоге получается, что функция будет крутится вечно, так как размер таблицы будет всегда возвращаться нулевым.
Возможно ли, как то определить - что нулевой размер таблицы - это не потому что данные с севера еще не пришли, а потому что размер таблицы - нулевой - Фактически, потому что данных свечей по акции физически еще не существует.
Anton Belonogov написал: Михаил Понамаренко, действительно, при исполнении Lua-скриптов есть ошибка доступа к depo_limits, иногда приводящая к зависанию приложения. Мы исправим её в ближайшем очередном релизе Рабочего места QUIK. Приносим извинения за причинённые неудобства.
У вас при выпуске новых версий, что даже - элементарных тестов нет ?
Подскажите, возможна ли остановка и запуск скрипта из другого скрипта ?
К примеру так: первый скрипт следит за соединение Квика - если соединение разрывается, то первый скрипт останавливает второй скрипт. Первый скрипт ждет пока восстановится соединение и как только соединение восстанавливается первый скрипт запускает второй скрипт.
То есть, чтобы опять заказывать - SetUpdateCallback - нужно физически останавливать скрипт в Квике, и опять физически запускать. Ну это же явно какой то косяк ?
global_cntr=0;
------------------------------------------------------------------------------------------------my_callback_CreateDataSource_SBER:Начало-----------------------------------------------------------------------------------------------
function my_callback_CreateDataSource_SBER(my_table_data_history_candle_, code_class_, code_paper_, interval_, interval_string_, idx)
message("SIZE_TABLE:" ..tostring(my_table_data_history_candle_:Size()) .. "\n" .. ":" .. code_paper_ ..":" .. interval_string_..":" ..tostring(my_table_data_history_candle_:C(idx)) )
if global_cntr == 13 then -- на 13 вызов callback`а Сбера отписываемся от колбека Сбера
my_table_data_history_candle_:Close() --отписываемся от callback`а SBER.
message("CLOSE SBER CALLBACK")
end
global_cntr=global_cntr+1
end
---------------------------------------------------------------------------------------------my_callback_CreateDataSource_SBER:Конец-----------------------------------------------------------------------------------------------
------------------------------------------------------------------------------------------------my_callback_CreateDataSource_GAZP:Начало-----------------------------------------------------------------------------------------------
function my_callback_CreateDataSource_GAZP(my_table_data_history_candle_, code_class_, code_paper_, interval_, interval_string_, idx)
message("my_callback_CreateDataSource_HISTORY_2 - НЕ ВЫЗЫВАЕТСЯ")
end
------------------------------------------------------------------------------------------------my_callback_CreateDataSource_GAZP:Конец-----------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------int main:-----------------------------------------------------------------------------------------------------
function main()
message("start")
local code_class_1= "TQBR"
local code_paper_1= "SBER"
local intervakla_1= INTERVAL_M1
local intervakla_string_1 = "INTERVAL_M1"
local my_table_1, error_desc_1 = CreateDataSource(code_class_1, code_paper_1, intervakla_1)
------------------------Проверка на ошибки:-------------------
if error_desc_1 ~= nil then
message("1:" .. error_desc_1)
end
--------------------------------------------------------------
status = my_table_1:SetUpdateCallback(function(idx)my_callback_CreateDataSource_SBER(my_table_1, code_class_1, code_paper_1, intervakla_1, intervakla_string_1, idx) end) --Подписываемся на колбек Сбера.
--Ждем пока не вызовется 13-ый по счета вызов колбек Сбера в котором произойдет отписка от колбека. После чего - подписываемся на SetUpdateCallback для Газпрома:
while not stopped do
sleep(1)
if global_cntr == 14 then
message("START_2")
code_class_2= "TQBR"
code_paper_2= "GAZP"
intervakla_2= INTERVAL_M5
intervakla_string_2 = "INTERVAL_M5"
my_table_2, error_desc_2 = CreateDataSource(code_class_2, code_paper_2, intervakla_2)
------------------------Проверка на ошибки:-------------------
if error_desc_2 ~= nil then
message("1:" .. error_desc_2)
end
--------------------------------------------------------------------------
--Ошибок нет:
message("START_SetUpdateCallback_2")
status1 = my_table_2:SetUpdateCallback(function(idx)my_callback_CreateDataSource_GAZP(my_table_2, code_class_2, code_paper_2, intervakla_2, intervakla_string_2, idx) end)
message(tostring(status1)) --Статус 0: ошибок нет, НО my_callback_CreateDataSource_GAZP - НИКОГДА НЕ ВЫЗОВЕТСЯ.
global_cntr = global_cntr + 1
message("END")
break
end
end
-------------------------
while not stopped do
sleep(1)
end
-------------------------
message("NOT END")
end -- end main()
так как в документации о поведении функции ничего нет, то следовательно это поведение функции по факту. -------------------------- Например, Земля круглая - по факту, так как о том, какой она должна быть по замыслу автора, неизвестно. Автор недоступен.
В каком смысле нет и поведение по факту ? В документации к SetUpdateCallback - сказано, что функция запрашивает данные на сервере и они должны прийти в callback-функцию, НО они не приходят. И никаких дополнительных описаний в SetUpdateCallback- нет. А значит - это поведение SetUpdateCallback является ОШИБКОЙ - которая противоречит описанию функции.
В какой то рандомный момент работы dll-скрипта - вызов функции lua_pcall() - просто вешает Квик. Это не обязательно первый вызов lua_pcall - это именно рандомный вызов. То есть Квик просто зависает и все - не ошибок ничего - просто виснет и все.Причем lua_pcall() - не возвращается, то есть код после lua_pcall - не выполянется. Квик тупо виснет в какой то момент именно на lua_pcall() и дальше Квик уже ничего не выполняет. И как тут разобраться в чем проблема ? Квик даже дамп ошибки не создаёт.
Владимир написал: Quikos, Функция здешняя. Насколько я помню, недокументированная. for l in F:lines() do s=l:sub(1,1); if s=="_" then load(l:sub(2))();end; end; Т.е. если строка в файле начинается с символа подчёркивания, скрипт выполняет её как если бы она была набита прямо в коде. Этим способом я сообщаю скрипту номер счёта, код клиента, количество денег, который ему разрешено использовать и т.д.
1)Так это не Lua C api.
2)Использовать недокументированные функции - чтобы получить недокументированный результат ? Это странно.