Функция getDepoEx может приводить к зависаниям терминала
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 11:01:22
В некоторых случаях функция getDepoEx может приводить к зависаниям терминала. Мне удалось локализовать проблему. Так, при открытом графике с включенной настройкой показывать уровень позиции, запрос позиции через getDepoEx по инструменту, график которого открыт, может приводить к зависанию. Предлагаю заинтересованным подтвердить или опровергнуть это. Для этого нужно скачать архив рабочего места QUIK по ссылке: Распаковать в любое место на диске и запустить info.exe В окне "Доступные скрипты" добавить скрипт getDepoEx.lua (лежит в архиве) и запустить его.
Код
function OnInit()
getDepoEx("NC0011100000", "10547", "SBER", "NL0011100043", 20260216)
end
Можно удалить файл info.wnd, чтобы запустить info.exe без настроек. А затем открыть график Сбербанка и включить в настройках графика "уровень позиции".
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 11:07:29
Возможно это и проблема, но, честно говоря, вызов getDepoEx внутри колбека OnInit выглядит странно.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 11:13:50
Цитата
Nikolay написал: вызов getDepoEx внутри колбека OnInit выглядит странно
Для меня странно выглядит сам факт зависания. Во-первых, в руководстве ничего не сказано, что getDepoEx нельзя вызывать внутри OnInit. Во-вторых, если есть ошибка в функции getDepoEx, приводящая к зависанию, мы не знаем, где она может ещё всплыть.
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 11:30:24
Цитата
Йцукен написал: Для меня странно выглядит сам факт зависания. Во-первых, в руководстве ничего не сказано, что getDepoEx нельзя вызывать внутри OnInit. Во-вторых, если есть ошибка в функции getDepoEx, приводящая к зависанию, мы не знаем, где она может ещё всплыть.
Здесь вопрос самой концепции. OnInit - это сигнал, что скрипт запускается и прямо сказано, что перед вызовом функции main(). А т.к. это колбек, то и в потоке интерфейса терминала. Т.е. это некий пограничный момент. Т.к. реализацию работы с потоками мы не знаем, то вполне может происходить некий конфликт - скрипт стартует, формируется доп. поток main. А здесь ему пинок - иди выполни qlua метод. Да, любое зависание основного окна приложения - это ошибка, баг. С этим не поспоришь.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 12:03:37
А где вы предлагаете определять стартовые (при запуске скрипта) позиции по бумагам и деньгам при использовании событийной модели?
Цитата
Nikolay написал: А здесь ему пинок - иди выполни qlua метод.
Так может вообще запретить вызывать qlua-функции в колбэках? Только сюрприз: они все стучатся в основной поток, и main будет ждать завершения функции.
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 12:18:47
Цитата
Йцукен написал: А где вы предлагаете определять стартовые (при запуске скрипта) позиции по бумагам и деньгам при использовании событийной модели?
Можно и в колбеках, если угодно, но не в OnInit точно. Начальное заполнение можно выполнить и при запуске main, в начале тела функции. Это не будет сильно отличаться по времени от OnInit.
Но, по хорошему, прежде чем выполнять какие-то запросы, необходимо дождаться, что данные есть в терминале. Если скрипт стартует вместе с терминалом, а брокер вызывает OnCleanUp, то пока данные не загрузятся, вызывать getDepoEx не имеет смысла. Поэтому - сначала старт скрипта, потом проверка наличия данных, потом запрос данных. Но точно не в OnInit когда вообще даже подключения к серверу может не быть.
Если говорить о событийной модели как таковой, то здесь опять нюансы. Если бы это были управляемые колбеки, созданные самим скриптом, с нормальной поддержкой многопоточности, то да, можно и в них совершать действия. А если это событийная модель в прямом смысле, т.е. это именно событие, которое мы отправляем скрипту в main для обработки, а сам колбек легко нагружает приложение, то уже не так очевидно, что там стоит выполнять что-то.
Когда проверять позицию - это вопрос субъективный. Можно по колбеку OnDepoLimit, но стоит учитывать, что будут постоянные вызовы не связанные с изменением позиции. Можно по новой сделке. А если требуется смотреть не только позицию, то и по изменению в таблице ордеров, например. Все зависит от задачи.
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 12:29:15
Цитата
Йцукен написал: Так может вообще запретить вызывать qlua-функции в колбэках? Только сюрприз: они все стучатся в основной поток, и main будет ждать завершения функции.
Так любой синхронный код, на то и синхронный, что пока вызов идет, то дальше код не исполняется. Здесь ничего нового. И опять - я не знаю как выполняются qlua методы, вызываемые из main. Но если читать документацию
Цитата
Во время выполнения функции main() Lua скрипт не мешает работе основного функционала РМ QUIK, таким образом, внутри функции main() использование функции sleep() не приводит к «подвисанию» РМ QUIK и позволяет периодически приостанавливать скрипт и возобновлять его работу через некоторый промежуток времени.
можно предположить, что все же вызов методов qlua из main организован без вызова основного потока. Но и не без проблем, т.к. если убрать sleep, терминал "умрет".
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 12:54:37
Цитата
Nikolay написал: но не в OnInit точно. Начальное заполнение можно выполнить и при запуске main, в начале тела функции.
Почему? Можете привести ссылку на раздел в документации, запрещающий вызов qlua-функций в OnInit?
Цитата
Nikolay написал: прежде чем выполнять какие-то запросы, необходимо дождаться, что данные есть в терминале
Чтобы узнать, есть ли данные в терминале, необходимо выполнить запрос. Сюрприз.
Цитата
Nikolay написал: Если скрипт стартует вместе с терминалом, а брокер вызывает OnCleanUp, то пока данные не загрузятся, вызывать getDepoEx не имеет смысла. Поэтому - сначала старт скрипта, потом проверка наличия данных, потом запрос данных.
А если скрипт запускается при установленном соединении? Очевидно, что если определять стартовые позиции в main, то есть риск неверной работы скрипта, если в это время будет вызван колбэк OnDepoLimit.
Nikolay написал: Начальное заполнение можно выполнить и при запуске main
Вызов getDepoEx в main скрипта
Код
function main()
getDepoEx("NC0011100000", "10547", "SBER", "NL0011100043", 20260216)
end
не приводит к зависанию терминала. Но, несмотря на отсутствие в main цикла скрипт не завершает свою работу самостоятельно и нагружает один поток процессора на 100%. Вы можете убедиться в этом, скачав архив по ссылке в первом сообщении.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 13:10:14
Цитата
Вызов getDepoEx в main скрипта
Код
function main ()
getDepo Ex( "NC0011100000" , "10547" , "SBER" , "NL0011100043" , 20260216 )
end
не приводит к зависанию терминала. Но, несмотря на отсутствие в main цикла скрипт не завершает свою работу самостоятельно и нагружает один поток процессора на 100%.
Скрипт останавливается кнопкой "Остановить". Но после нескольких циклов запуска-остановки вываливается с ошибкой:
Цитата
ACCESS VIOLATION at address 00007FFE43DE431F
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 13:33:01
Цитата
Йцукен написал: Но, несмотря на отсутствие в main цикла скрипт не завершает свою работу самостоятельно и нагружает один поток процессора на 100%.
Это давно известный факт, и я про него написал выше "если убрать sleep, терминал "умрет""
Цитата
Йцукен написал: Чтобы узнать, есть ли данные в терминале, необходимо выполнить запрос. Сюрприз.
Не совсем. Сначала необходимо узнать есть в таблице записи, запросив размер таблицы. Это все же разные запросы, хоть и тоже метод qlua
Цитата
Йцукен написал: А если скрипт запускается при установленном соединении?
Если запускается при установленном соединении, то да данные есть. Но обычно, все же, скрипты пишутся для работы во всех режимах, а не в одном.
Цитата
Йцукен написал: Очевидно, что если определять стартовые позиции в main, то есть риск неверной работы скрипта, если в это время будет вызван колбэк OnDepoLimit.
Не очевидно совсем. Этот колбек вызывается очень часто, и не только при изменении позиции. Более того, в определенные моменты торговой сессии, там могут быть некорректные данные. Т.е. необходимо не просто брать данные, а понимать можно ли их брать в этот момент времени. Также, корректно сделать ручной запрос перед принятием решения, зависящего от данных в таблице depo_limits. Колбек - это хорошо, но я очень много раз видел, как в терминал пришли сделки, а позиция в depo_limits обновляется с существенной задержкой. Или, что тоже часто, есть сделки выхода из позиции, по идее можно установить обратно ордера на открытие позиции, а брокер не дает и пишет что денег нет. Т.е. данные еще не обновились.
Так что можете использовать колбеки, никто не мешает. Но речь же про OnInit, а не все колбеки как таковые.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 14:04:20
Цитата
Nikolay написал: Это давно известный факт, и я про него написал выше "если убрать sleep, терминал "умрет""
Ну а мне очевидно, что между OnInit и main может вклиниться какой-нибудь колбэк.
Цитата
Nikolay написал: Но обычно, все же, скрипты пишутся для работы во всех режимах, а не в одном.
Вот именно. Поэтому определение стартовых данных в событийной модели целесообразно делать до main.
Цитата
Nikolay написал: Сначала необходимо узнать есть в таблице записи, запросив размер таблицы.
В данном случае размер таблицы "depo_limits" не пустой, в ней четыре строки. Я лишь привёл минимальный код, демонстрирующий ошибку. И как выше написал: независимо куда вы воткнёте getDepoEx, скрипт будет работать некорректно.
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 14:30:54
Цитата
Йцукен написал: Вы код смотрели? При чём тут sleep?
При том, что его там нет. Именно это и приводит к "зависанию" терминала.
Опять читаем документацию
Цитата
Вызов функции sleep() внутри цикла потока main() обязателен. Значение аргумента функции sleep() может быть равно 1, но в этом случае задержка приближена к значению прерывания системного таймера (по умолчанию 15.625мс).
Цитата
Йцукен написал: Ну а мне очевидно, что между OnInit и main может вклиниться какой-нибудь колбэк. Вот именно. Поэтому определение стартовых данных в событийной модели целесообразно делать до main.
И вклинился, и что? Если под этим подразумевается, что в коде вообще не предусмотрено получение вручную данных из таблицы depo_limits, то, конечно, другого варианта как считывать данные в колбеке нет. Но тогда все равно не ясно зачем это делать в служебном колбеке OnInit. Делайте в специализированном OnDepoLimit. Он, если судить по предоставленной событийной модели в документации, все равно вызовется после OnInit. Дайте провести инициализацию скрипта, пусть запустится main. В нем можно считать данные начала. А потом все обрабатывать по приходу OnDepoLimit. Если OnDepoLimit вызовется раньше чем код дойдет до места в main где вызывается getDepoEx, то это ни на что не повлияет, т.к. getDepoEx уже получит актуальные данные.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 14:48:12
В зависимости от назначения бота использую несколько вариантов начального чтения позиции и параметры доступных инструментов. ----------------------- Чаще всего начальное чтение позиций и параметров инструментов делаю в main перед циклом, после идентификации соединения с сервером.
При том, что его там нет. Именно это и приводит к "зависанию" терминала.
Серьёзно? А если нам нужно, чтобы скрипт что-то рассчитал и завершил работу?
Изменил скрипт в таком виде:
Код
function main()
local n = getNumberOf("depo_limits")
message("Number depo_limits:" .. n)
if n > 0 then
getDepoEx("NC0011100000", "10547", "SBER", "NL0011100043", 20260216)
end
message("Завершение работы main.")
end
Скрипт стоит, как вкопанный на getDepoEx: Даже не представляю, куда тут вкрячить sleep?
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 14:56:33
Цитата
Йцукен написал: if n > 0 then getDepoEx("NC0011100000", "10547", "SBER", "NL0011100043", 20260216) end
Ну это, конечно, ошибка если зависает. Если мне нужен простой скрипт для расчета и завершится, то я не ввожу main и любые колбеки. Просто тело скрипта.
Запустил Ваш скрипт у себя, изменив данные и дату limit_kind на сегодняшнюю. Нет проблем. И с вашими данными, очевидно не подходящими, тоже нет проблем.
Nikolay написал: Запустил Ваш скрипт у себя, изменив данные и дату limit_kind на сегодняшнюю.
Очевидно, что getDepoEx приводит к зависаниям не всегда, иначе весь форум бы пестрил от сообщений пользователей о проблеме.
Цитата
Йцукен написал: Мне удалось локализовать проблему. Так, при открытом графике с включенной настройкой показывать уровень позиции, запрос позиции через getDepoEx по инструменту, график которого открыт, может приводить к зависанию.
Но, очевидно, на это влияет не только наличие открытого графика, но ещё и то, какие позиции открыты. Так, при запросе данных по GAZP или с датой расчёта не приводит 20260215 к зависанию.
Цитата
Nikolay написал: И с вашими данными, очевидно не подходящими, тоже нет проблем.
Вы это проверили, запустив скрипт в квике из архива?
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 15:09:29
*Так, при запросе данных по GAZP или с датой расчёта 20260215 не приводит к зависанию.
Пользователь
Сообщений: Регистрация: 27.01.2017
25.02.2026 15:10:10
Цитата
Вы это проверили, запустив скрипт в квике из архива?
Вы это проверили, запустив скрипт в квике из архива?
На своем.
Мы не знаем, какие именно условия приводят к зависанию в getDepoEx, и вы не можете в точности воспроизвести ситуацию, которая могла бы привести к зависанию. Поэтому, ваш тест и выводы, основанные на нём, не конструктивны.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 15:29:50
Цитата
Йцукен написал: Предлагаю заинтересованным подтвердить или опровергнуть это. Для этого нужно скачать архив рабочего места QUIK по ссылке:
В архиве QUIK 12.8.3.4 Проверил на версии 12.8.4.9 - результат аналогичный. Для этого сначала распаковываем файлы из архива по ссылке выше, а потом - из , подтвердив замену файлов.
При том, что его там нет. Именно это и приводит к "зависанию" терминала.
Серьёзно? А если нам нужно, чтобы скрипт что-то рассчитал и завершил работу?
Изменил скрипт в таком виде:
Код
function main ()
local n = getNumberOf ( "depo_limits" )
message ( "Number depo_limits:" .. n)
if n > 0 then
getDepo Ex( "NC0011100000" , "10547" , "SBER" , "NL0011100043" , 20260216 )
end
message ( "Завершение работы main." )
end
Скрипт стоит, как вкопанный на getDepoEx:
Даже не представляю, куда тут вкрячить sleep?
Код
function main ()
local n = getNumberOf ( "depo_limits" )
message ( "Number depo_limits:" .. n)
if n > 0 then
getDepo Ex( "NC0011100000" , "10547" , "SBER" , "NL0011100043" , 20260216 )
end
message ( "Завершение работы main." )
sleep(1)
end
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 15:34:49
, Пардон, я не увидел что Вы main вызываете без цикла. ------------------- Возможно у вас ничего не успевает нормально отработать и вы все вешаете. ---------------------- Это как у автомобиля отвинтить два колеса. И думать что это велосипед.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 15:35:23
Не надо так уродовать скрипт.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 15:45:18
Нафига здесь циклы, слипы? Товарищи, которые тут советуют вкрячить циклы со слипами, вы сначала проверьте свой код, на архиве из первого сообщения. Потом можно предметно что-то обсуждать. Я просто диву даюсь
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 15:49:59
Цитата
Йцукен написал: Нафига здесь циклы, слипы? Товарищи, которые тут советуют вкрячить циклы со слипами, вы сначала проверьте свой код, на архиве из первого сообщения. Потом можно предметно что-то обсуждать. Я просто диву даюсь
Пардон, Ваш скрипт работает. Вы просто все мозги мне засрали своими воплями.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 15:52:06
nikolz, вы сначала проверьте свой код, на архиве из первого сообщения. А коль не можете - брысь из темы.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 16:02:31
Цитата
Йцукен написал: , вы сначала проверьте свой код, на архиве из первого сообщения . А коль не можете - брысь из темы.
Нафига? Я не знаю что Вы там наделали. А разбираться в вашей куче нет желания. поставьте нормальный пакет и будет Вам счастье. возможно Ваш скрипт у вас не работал из-за ошибок. ------------------- вот Ваш скрипт который я запускаю:
Код
function main ()
local n = getNumberOf ( "depo_limits" )
message ( "Number depo_limits:" .. n,1)
if n > 0 then
getDepoEx( "NC0011100000" , "10547" , "SBER" , "NL0011100043" , 20260216 )
end
message ( "Завершение работы main.",1)
end
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 16:10:25
Товарищи, которые пишут тут: "я проверил на своём квике, и у меня не зависает", я и без вас знаю, что скрипт зависает не всегда. В getDepoEx есть ошибка, которая при определенных условиях, может привести к зависанию терминала. Предполагаю, что это зависит от открытых позиций по бумагам. Но, какие именно данные приводят к зависанию - мне не известно. Вам тем более. Поэтому, не надо мне тут писать, не проверив на предложенных данных. Ваши сообщения не несут никакой смысловой нагрузки.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 16:17:32
Цитата
Йцукен написал: Товарищи, которые пишут тут: "я проверил на своём квике, и у меня не зависает", я и без вас знаю, что скрипт зависает не всегда. В getDepoEx есть ошибка, которая при определенных условиях, может привести к зависанию терминала. Предполагаю, что это зависит от открытых позиций по бумагам. Но, какие именно данные приводят к зависанию - мне не известно. Вам тем более. Поэтому, не надо мне тут писать, не проверив на предложенных данных. Ваши сообщения не несут никакой смысловой нагрузки.
Не в обиду, но Вы читали про проблему долгой загрузки которая у меня была. Я ее решал сам затратил на тесты неделю. -------------------------- Все проблемы, о которых писал на форуме решал самостоятельно. ------------------------- Хотите решение - делайте тесты и ищите причину. потом ищите решение сами или пишите на форум поможем. Разработчики ничего делать в ближайшие надцать дней, недель,месяце, лет(не нужное зачеркнуть) с вашей проблемой не будут. --------------------- Спасение утопающих - дело рук самих утопающих.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 16:20:56
и еще.. Если Ваша проблема связана с конкретной ситуацией на рынке, то выложенный Вами пакет ничего не дает. если я его скачаю то я не подключусь к серверу как вы а могу подключится как я. если это на демо сервере, то ваш пакет не нужен.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 16:35:18
nikolz, не в обиду: от вас помощи мне точно не нужно, вы не умеете читать, до вас очень туго доходит (если вообще доходит) смысл написанного. Вы даже первое сообщение не прочитали, зачем залезли в тему со своими комментариями - мне не понятно. Ну а что касается поиска причины, то это уже не ко мне вопрос. Я локализовал проблему, предоставил достаточно данных, чтобы проверить и убедиться в наличии проблемы. Вообще торгую только на срочном рынке. Но вот в демке тестировал фондовую секцию, и в какой-то момент квик завис. Я сохранил все данные, чтобы иметь возможность их предоставить. Для проверки и запуска скрипта подключение к серверу не требуется.
Если это никому не нужно, включая разработчиков, то мне тем более: на боевом квике getDepoEx не использую. Но когда посреди торгов, у вас неожиданно всё зависнет, - прибежите на форум.
Пользователь
Сообщений: Регистрация: 30.01.2015
25.02.2026 16:39:39
Цитата
Йцукен написал: , не в обиду: от вас помощи мне точно не нужно, вы не умеете читать, до вас очень туго доходит (если вообще доходит) смысл написанного. Вы даже первое сообщение не прочитали, зачем залезли в тему со своими комментариями - мне не понятно. Ну а что касается поиска причины, то это уже не ко мне вопрос. Я локализовал проблему, предоставил достаточно данных, чтобы проверить и убедиться в наличии проблемы. Вообще торгую только на срочном рынке. Но вот в демке тестировал фондовую секцию, и в какой-то момент квик завис. Я сохранил все данные, чтобы иметь возможность их предоставить. Для проверки и запуска скрипта подключение к серверу не требуется.
Если это никому не нужно, включая разработчиков, то мне тем более: на боевом квике getDepoEx не использую. Но когда посреди торгов, у вас неожиданно всё зависнет, - прибежите на форум.
Ну и прекрасно. Если бы сразу написали что и как делали, то и вопросов Вам бы я не задавал. По-вашему , я не умею читать По-моему, Вы не умеете писать...программы.
Пользователь
Сообщений: Регистрация: 02.01.2026
25.02.2026 16:41:55
Цитата
nikolz написал: Если бы сразу написали что и как делали, то и вопросов Вам бы я не задавал.
В первом сообщении всё написано. Разуйте глаза уже или брысь из темы.
Пользователь
Сообщений: Регистрация: 12.05.2020
26.02.2026 07:32:55
1.
Цитата
Йцукен написал: Предлагаю заинтересованным подтвердить или опровергнуть это.
Подтверждаю. В выложенном экземпляре QUIK у меня ошибка проявляется.
2.
Цитата
Nikolay написал: Да, любое зависание основного окна приложения - это ошибка, баг.
Согласен. Локализована типичная ошибка синхронизации. В моей песочнице эта ошибка не проявляется.
3.
Цитата
Йцукен написал: Но когда посреди торгов, у вас неожиданно всё зависнет, - прибежите на форум.
Согласен. Такие нетривиальные ошибки надо выкладывать и исправлять (разработчику), а пользователей, сумевших их локализовать, поощрять .
4. Вообще то, многие ошибки, обнаруженные в QUIK, по моему мнению, во многом, следствие существующей дефектной (сложной) его архитектуры , о чем я написал в своей ветке "Что стоило бы изменить в QUIK по-крупному" два года назад.
Думаю имеет место логическая ошибка в библиотеке QMargin, из-за которой не происходит выхода из функции getDepoEx.
Решил проверить, жив ли основной поток, когда main стоит на getDepoEx.
Скрытый текст
Код
local run = true
function OnStop()
run = nil
return 100
end
function OnParam()
if run then
message("OnParam")
run = false
end
end
function main()
local n = getNumberOf("depo_limits")
message("Number depo_limits: " .. n)
if n > 0 then
message("getDepoEx: " .. tostring(getDepoEx("NC0011100000", "10547", "SBER", "NL0011100043", 20260227)))
end
while run do sleep(1000) end
end
При подключении к серверу и запуске скрипта пишет:
Цитата
Number depo_limits: 4 OnParam
Т.е., основной поток вполне себе жив. Но в main не происходит выхода из getDepoEx. После остановки скрипта кнопкой "Остановить" требуется перезапуск квика, потому что нормальная работа Lua-скриптов уже не возможна. Вот такая пасхалочка. При чём здесь настройка "Показывать уровень позиции" на графике - не понятно. Но при снятой галке зависание не наблюдается.
Попутно обнаружилась ещё одна ошибка. В документации сказано:
Цитата
В случае ошибки функция возвращает «nil».
На самом деле, getDepoEx ничего не возвращает. Убедиться в этом можно, выполнив код:
Код
message(tostring(getDepoEx("", "", "", "", 0)))
Будет ошибка:
Цитата
bad argument #1 to 'tostring' (value expected)
И такие функции в QUIK сплошь и рядом, тот же getSecurityInfo:
Код
message(tostring(getSecurityInfo("", "")))
Пользователь
Сообщений: Регистрация: 22.02.2023
26.02.2026 11:27:24
Цитата
Йцукен написал: Попутно обнаружилась ещё одна ошибка. В документации сказано:ЦитатаВ случае ошибки функция возвращает «nil».На самом деле, getDepoEx ничего не возвращает. Убедиться в этом можно, выполнив код:
Тип nil (нуль) имеет одно единственное значение, nil, его главное свойство это отличаться от любых других значений; обычно это означает отсутствие используемого значения. <...> type (v) Возвращает тип любого аргумента, представленный строкой. Возможные результаты этой функции: "nil" (строка, не значение nil), "number", "string", "boolean", "table", "function", "thread" и "userdata".
:
Цитата
Тип nil — это тип с единственным значением, nil, основная задача которого состоит в том, чтобы отличаться от всех остальных значений. Lua использует nil как нечто, не являющееся значением, чтобы изобразить отсутствие подходящего значения.
Всё пройдет. Но это не точно.
Пользователь
Сообщений: Регистрация: 02.01.2026
26.02.2026 12:36:44
Цитата
Ziveleos написал: Тип nil (нуль) имеет одно единственное значение, nil
Цитата
Ziveleos написал: type (v) Возвращает тип любого аргумента
type ожидает аргумент с любым значением, в т.ч. и nil.
потому что type ожидает значение, а getSecurityInfo превращается в процедуру, которая ничего не возвращает, т.е. не передаёт аргумент.
Пользователь
Сообщений: Регистрация: 22.02.2023
26.02.2026 13:22:20
Цитата
Йцукен написал: type ожидает значение, а getSecurityInfo превращается в процедуру, которая ничего не возвращает, т.е. не передаёт аргумент.
Отнюдь. type ожидает аргумент, он так и жалуется: "bad argument #1 to 'type' (value expected)", а nil - это не аргумент, это значение, означающее чистое, незапятнанное, рафинированное ничто. Попробуйте:
Код
message(type())
Есть переменная и есть её значение. Переменная - аргумент, nil - значение. Функции, в том числе и type, работают с аргументами.
Это как раз тот случай, когда в type ничего не передаётся:
Код
message(type(getDepoEx("", "", "", "", 0))) --> bad argument #1 to 'type' (value expected)
message(type(getSecurityInfo("", ""))) --> bad argument #1 to 'type' (value expected)
потому что getDepoEx, getSecurityInfo, в случае ошибки не возвращают ничего (процедуры, другими словами). В отличие от, например,
Код
message(type(getItem("", 0))) --> nil
когда getItem возвращает nil в случае ошибки
Пользователь
Сообщений: Регистрация: 12.05.2020
26.02.2026 16:16:01
Цитата
Йцукен написал: потому что getDepoEx, getSecurityInfo, в случае ошибки не возвращают ничего (процедуры, другими словами).
В синтаксисе Lua есть понятия: результат функции (отсутствие/одно или несколько значений) и выражение. Функция может не возвращать результата, но есть синтаксические конструкции, которые рассматриваются как выражения (это можно посмотреть в описании языка). Например, присвоение: local v = f (). В этом случае вызов функции справа от равенства считается выражением. В выражении функция, не возвращающая результат, заменяется на nil. Результатом выражения может быть только одно значение. Явным способом привести к выражению можно синтаксическую конструкцию, заключив ее в круглые скобки. Например: message(type((getSecurityInfo("", "")))), результат печати: nil
Пользователь
Сообщений: Регистрация: 30.01.2015
26.02.2026 16:28:53
, Сделал несколько тестов для проверки Вашей гипотезы. ------------------- Я с Вами согласен. ----------------------- Эти функции не возвращают nil. -------- Мне лень глубоко копать, но предположу, что в них ошибка связана с неправильным управлением стеком.
Пользователь
Сообщений: Регистрация: 30.01.2015
26.02.2026 16:32:40
Поэтому их результат нельзя передавать в функцию например в type. Надо делать это через присвоение переменной.
Пользователь
Сообщений: Регистрация: 30.01.2015
26.02.2026 16:35:52
Поясняю: Эти функции не возвращают переменную, а возвращают пустой стек. Поэтому если Вы укажите функцию как параметр , как у Вас в примере, то получите ошибку параметра.
Пользователь
Сообщений: Регистрация: 30.01.2015
26.02.2026 16:40:08
это получается СИ функциях для луа, когда в конце return 0; вместо записи в стек nil и возврата return 1