Евгений написал: Если бы каждый график или хотя бы вкладка были в отдельных потоках проблема думаю бы решилась
Так не бывает в Windows. Ну вернее так: можете посмотреть на Google Chrome, он так сделан (там даже отдельные процессы) и на прожорливоть им ресурсов "как не в себя".
1) Если меток несколько сотен - очевидно, что они маленьгого размера. В этом случае gif будет точно меньшего размера, пересохраните картинки в этом формате. Ну просто для пробы помогает ли это. Хотя проблема скорее в большом количестве меток, а не в формате, но попробовать стоит, думаю.
2) Решит ли замена процесора - в момент перемещения графика посмотрите по диспетчеру задач что нагружается: центральный процессор или видеокарточка. Если ЦП - то замена на более мощный поможет, вопрос только в том "на сколько улучшится".
3) Попробуйте в метки не вставлять картинки, а обозначить (метки) только текстом. Найдите подходящий вам символ - и выводите его вместо картинки. Возможно, это будет быстрее работать.
4) Судя по тому, что меток огромное количество - вы наверняка метками пытаетесь нарисовать какой-то график. Переделайте ваш скрипт в индикатор в таком случае, индикаторы работают побыстрее.
Максим написал: под обычный скрипт, чтобы я его мог запустить в терминале, указав в коде нужную мне бумагу.
Не понятно что вы подразумеваете под этой фразой. Какого результата вы хотите достичь? чтобы "обычный скрипт" нарисовал индикатор? чтобы "обычный скрипт" получил данные индикатора и по ним принял какое-то торговое решение? что-то еще?
swerg написал: Было бы очень здорово, если бы вы приводили нормальный полный код, которым получаете указанное вами.
Уточню: нормальный полный, но минимально возможный для воспроизведения проблемы. Бесплатно 5 страниц текста программы мало кто готов разбирать, так что чем короче полный проблемный код - тем выше шансы на успех получения толковой подсказки.
Kolossi написал: Проверил. Нумерация окон меняется конкретно для каждого скрипта-увеличивается с каждым перезапуском начиная с запуска Квика. Запустив два одинаковых скрипта при помощи перезапусков легко получил окна с одинаковыми идентификаторами. Облом.
Один скрипт выводит все таблицы, включая "сводную", другой кидает ему данные через
Дмитрий написал: function OnCalculate (index) plusdi,n,q = getCandlesByIndex ( "SBAdx" , 1 , 0 , getNumCandles ( "SBAdx" )) -- get +DI table minusdi,n,q = getCandlesByIndex ( "SBAdx" , 2 , 0 , getNumCandles ( "SBAdx" )) -- get -DI table return handler() end
function handler(index) if plusdi[index].close ~= nil and minusdi[index].close ~= nil then [/CODE]
1) Правильно ли, что из plusdi[] и minusdi[] значения берутся по индексу index? Ведь в OnCalculate индексы приходят начиная с 1, а в возвращаемых значениях массивов из getCandlesByIndex индексы начитаются с 0...
Наверное правильно будет plusdi[index-1].close и minusdi[index-1].close ?
2) Про оптимизации. Здесь получается, что мы в каждом OnCalculate получаем все свечи с другого графика через getCandlesByIndex(), после чего берём только какое-то одно значение... думаю будет эффективнее написать так:
plusdi = getCandlesByIndex ( "SBAdx" , 1 , index-1 , 1) -- get +DI table minusdi = getCandlesByIndex ( "SBAdx" , 2 , index-1 , 1) -- get -DI table ... и, соответственно, данные брать как plusdi[0].close и minusdi[0].close
Владимир написал: И подобные Вам программисты, гнущие пальцы с вумным видом и немедленно затыкающие хлебальники при первом же щелчке по носу (как это сделали лично Вы в соседней ветке)
Ты, дурач0к, просто достал своей напыщенной тупостью и некомпетентностью. Об тебя мараться не хочется, потому и бегут подальше и не отвечают на твой идиотизм. А ты, глупенький, решил, что сумел кого-то "по носу" достать. Шел бы ты к своим сверстникам по разуму, в старшую группу детского садика.
Формирование звуковых алертов в таблице ”Оповещения” с помощью Lua, Необходимо автоматическое формирование звуковых алертов в таблице ”Оповещения” для роботов-помощников
Юрий написал: Подключение внешних библиотек трудоёмко и не решает проблему для сетки алертов.
Такого быть не может. Казалось бы, как раз из скрипта можно нагородить сколь угодно сложную систему оповещений. Впрочем, есть есть "сетка алертов" - не понятно.
Старатель написал: Я не понял: наблюдаете или нет? Запустите предложенный скрипт на своём демо.
Согласитесь, то, что речь про демо-сервер - вообще не очевидно было по вопросу. А проблема скорее всего именно в сервере, который не заполняет, потому и важно уточнить какой он.
Вставляя проверялку в каждый интерфейсный метод библиотеки, я о чем я и писал сразу. Оно, конечно, затраты на проверялку копеечные - фактически сравнить несколько интов (чем являются указатели) по готовым адресам, особенно если развернуть и убрать вызовы вложенных красивых функций. Но синтаксически все загромождается и загромождается.
ВиталийКак правило, люди крестят Lua и C++, но не QLua. И как я понял исходя даже из этого форума - это немного разные вещи.
Вообще никакой разницы между Lua и QLua нет. Ну с точки зрения программирования, интерфейсов и т.д. QLua - это Lua с добавленными глобальными функциями грубо говоря, и это характерно для любого реального применения Lua где-либо.
Попробую написать подробнее. Напишу как я вижу структуру волшебной библиотеки. Возможно у вас устроено совсем не так, а как-то иначе и указанной проблемы нет, и вы поделитесь вашей структурой. Все "исходные коды" ниже - условны, без соблюдения всех нюансов синтаксиса, чисто для иллюстрации структуры программы.
Код
var
// глобальные переменные, куда будут загружены адреса функций Lua API
lua_pushstring_addr;
lua_pushnumber_addr;
luaL_checkinteger_addr;
luaL_checkstring_addr;
.... и т.д. ....
function LoadLua53()
begin
h := LoadLibrary('Lua53.dll');
lua_pushstring_addr := GetProcAddress(h, 'lua_pushstring');
luaL_checkstring_addr := GetProcAddress(h, 'luaL_checkstring');
....
end;
function LoadLua54()
begin
h := LoadLibrary('Lua54.dll');
lua_pushstring_addr := GetProcAddress(h, 'lua_pushstring');
luaL_checkstring_addr := GetProcAddress(h, 'luaL_checkstring');
....
end;
function luaopen_XXX(L: Plua_State)
begin
if (ХитраяПроверка(L) = Lua54) then
LoadLua54();
else
LoadLua53();
... далее обычный код для luaopen_XXX, ссылки на нужную версию Lua подгружены ...
luaL_newlib(L, ls_lib);
... и т.д. ...
end;
После чего все реализации функций нашей библиотеки пишем обычным образом (без. доп проверок на версию Lua!)
тогда получится так: - скрипт 1 выполняется в Lua53, загрузил нашу библиотеку. Все адреса в глоб. переменных у нас указывают на Lua5.3 и все хорошо.
- скрипт 1 продолжает работать и запустили скрипт 2, для которого указана Lua54. Наша библиотека это определила (необходимость загрузки Lua54), в глоб переменные загрузила адреса из Lua54.dll И второй скрипт работает корректно. Но первый-то скрипт уже будет ходить совсем "не туда"!
Чтобы это исправить - мы должны иметь две полных структуры адресов Lua-API функций для разных версий Lua и вставлять проверку в каждую функцию библиотеку, доступную для Lua-скрипта, переключаясь на адреса нужной версии Lua для каждой интерфейсной функции нашей библиотеки.... Или у вас так и сделано?
Александр В луа 5.4 lua_version просто возращает версию луа 504 не зависимо от того, для какой версии LuaState. Но в целом можно попробовать пошаманить с этим делом.
Ниже вы приводите результаты ваших исследований, за них вам спасибо.
Засада с этим красивым автоматическим определением будет вот где. (предположим что в принципе оно у нас заработало и нам повезло - бинарно интерфейсы совпали) Если пользователь запустит одновременно два скрипта, использующих такую волшебную библиотеку - ему явно не повезёт. Потому что указатели на функции в Lua53.dll / Lua54.dll вы явно храните в глобальных переменных, т.е. в каждый момент времени в них фактически указатели на какую-то одну версию Lua. И даже если разнести указатели в 2 разные структуры по версиям Lua - то придётся в начало каждой интерфейсной функции вставлять хитрую проверку версии переданного стека, а потом еще хитро переключаться на соответствующую версию структуры указателей на функции Lua-API в рамках этой функции, вызванной внутри библиотеки.... Как-то это уже слишком, по-моему.
АлександрНе подходит, т. к. в Lua 5.4 lua_version просто возвращает номер версии, а при передаче в luastate от Lua 5.4 в функцию lua_version от Lua 5.3 происходит ACCESS_VIOLATION.
А, ну и славно, вот и проверили, бинарно не совместимы версии.
Я немного не понял: я вам чем-то обязан, что вы позволяете себе писать именно так? Я писал выше, вариант один: две разные dll для разных версий Lua. Как их загружать в скрипт при условии, что пользователь может выбрать одну из версий Lua - не знаю. Видимо раскладывать dll разных версий Lua по разным папкам и с путями в скрипте играться в зависимости __VERSION, или имена разные давать dll для разных версий Lua и опять же подгружать нужную библу.
Чтобы использовать lua_version надо загрузить нужную dll. Возникает вопрос какую версию dll брать?
Вы не сделаете динамическую загрузку DLL нужной версии. Во-первых потому, что нет интерфейса для понимания того, на какой Lua-стек вам передали указатель, а во вторых потому, что вполне вероятно (но это надо дотошно проверять), что отдельные интерфейсные структуры в 5.3 и 5.4 версиях - разные. И в этом случае вы просто не сможете сделать бинарно совместимые версии dll. Вот и остаётся нам максимум - это проверить, что dll собрана под ту версию Lua, для которой она собрана. Фиговую какашку нам подсунули разработчки QUIK, да. Ведь фактически нельзя теперь просто положить dll в каталог с QUIK и использовать её спокойно, ведь в зависимости от версии Lua, заданной для скрипта, dll либо поедет, либо не поедет.... Да ужж...
Цитата
В луа 5.4 lua_version просто возращает версию луа 504 не зависимо от того, для какой версии LuaState.
Эту фразу не понял. Если вы скомпилировали вашу библиотеку (или динамически подгрузили) lua54.dll - то она вам и вернёт всегда 504 из lua_version. Т.к. эта функция просто возвращает вкомпилированную константу (см. исходники), на LuaState она не смотрит.
TGB, чем вас не устраивает отдельная ветка обсуждения ваших проблем? зачем вы в каждой ветке обсуждаете свою проблему, притом что эта проблема никак не связана с темой ветки? Это так, замечание на будущее.
Цитата
TGB Для обработки всех скриптов пользователя создается один служебный поток (под потоком здесь и далее понимается поток Windows).
В Windows есть понятие "основной поток приложения". В нем и происходит все то, что вы называете "в служебном". Здесь есть картинка https://quik2dde.ru/viewtopic.php?id=16 (замечу что картинку эту ARQA стырила и включила в свою документацию, предварительно формально перерисовав, не спросив ни разрешения, ни даже хотя бы не сказав "спасибо")
Цитата
TGB Известно, что нативные версии Lua однопоточные. Управление автоматической памятью в них тоже однопоточное. Поэтому при внедрении версий Lua в QUIK требуется, наверное, много чего, но, как минимум, необходима переработка автоматического управления памятью с целью обеспечения ее потокобезопасности. И это сложная задача.
..., полностью решённая в исходниках Lua. Там просто можно включить режим сборки "многопоточный". Ну так, если совсем упрощённо. Так что всё "от производителя".
Цитата
TGB Моя программа, на которой «падает» QUIK, тестирует автоматическую память QLua. Похоже, что эта память реализована некорректно, а значит в любых скриптах, в произвольные моменты времени могут возникать ошибки. Так как мой тест специально создает очень большую нагрузку на управление автоматической памятью, то ошибки возникают в течении 2-3 минут. При обычной работе эти ошибки возникают реже и могут проявляться в разных местах.
Я не смотрел вашу программу, однако могу предложить другое объяснение: ваша программа портит память процесса QUIK, после чего он падает. Или подгружаемые вами DLL содержат потоконебезопасный код, из-за которого опять же QUIK падает. Если бы на самом деле управление внутренними хранилищами QUIK было столь потоконебезопасным, то падали бы и обычные скрипты, которые могут нагрузить "автоматческую память" ничуть не хуже. Всё же согласитесь, какого-то тотально-массового падения скриптов QLua явно не наблюдается.
Надеюсь, ответ на вопрос 2) вы теперь сами знаете?
Хотелось бы уточнить у тех. поддержки про новую версию 8.11:
1) Зачем остался в дистрибутиве (в обновлении) файл lua5.1.dll ? как он функционирует?! Вроде его планировали убрать.
2) В списке исправленных недоработок есть несколько пунктов про Lua (пункты 10, 11, 12, 13) Подразумевается, что указанные в них проблемы исправятся только при использовании Lua 5.4 ? или для Lua 5.3 они исправлены тоже?
Делайте сразу расчет портфеля на Lua по вашим формулам. Даже не тешьте себя надеждой, нужная вам формула когда-либо появится в QUIK. Там очень своё видение как рассчитывать параметры.
Виталий написал: И что не так? В этой либе мне нужно использовать CLR, там будут формы. Как сам факт поддержки CLR (без каких-либо вызовов) влияет на выгрузку библиотеки?
Как минимум - вот оно коренное отличие вашей DLL от моей, а вовсе не версия QUIK. Ну и видимо передавайте привет .NET и особенностям ее работы.
Цитата
Виталий написал: (без каких-либо вызовов) влияет на выгрузку библиотеки?
Вы может и не вызываете, но раз хотите .NET - оно там очень могуче напрягается, чтобы вам его предоставить. Вам наверное будет не сложно пока отключить использование .NET и проверить.
Виталий написал: Но повторю еще раз: версия квика у вас не та. У меня 8.10.1.1 - они могут отличаться. Чего я не понимаю, так это почему молчат представители поддержки официальной?! Их как-то нужно призывать по особому в тему?? По мне так уже давно могли бы что-то написать.
И? Я не знаю зачем вы используете именно эту версию. Вам ничего не мешает быстро проверить на 8.9
Цитата
Виталий написал: Чего я не понимаю, так это почему молчат представители поддержки официальной?! Их как-то нужно призывать по особому в тему?? По мне так уже давно могли бы что-то написать.
Выгрузка / не выгрузка DLL - это последнее, что заботит реальных пользователей торгового терминала, даже если они используют какие-то готовые библиотеки. Так что, по-моему, это "проблема" приоритета из нижней десятки всех тех тысяч реальных проблем, которые есть в QUIK.
Ровно такой же скрипт сделал у себя для тестов У меня DLL выгружается (QUIK 8.9) - после запуска и остановки скрипта могу DLL удалять, заново переписывать и т.д. (проверяю просто переписыванием поверх, буквально VS не собирает на то место, откуда запуск) Но проверяю на другом коде DLL. Если дойдёт руки - попробую буквально вашу DLL собрать
path = getScriptPath() .. "\\central-core.dll"
package.loadlib(path, "luaopen_central_core")()
local m = central_core.DoSomething();
message(tostring(m))
function main()
while (true) do
sleep(100)
end
end
У вас луа-скрипт корректно не останавливается. Что ж вы хотите-то?
w32 = require("w32")
-- Возвращает handle главного окна QUIK или 0 при ошибке
-- Если запущено несколько терминалов - выбирается тот QUIK, из которого запущен наш скрипт
function GetQuikMainWindowHandle()
local hQuikWnd = 0
while true do
hQuikWnd = w32.FindWindowEx(0, hQuikWnd, "InfoClass", "")
if hQuikWnd == 0 then
break
end
local t,WinProcId = w32.GetWindowThreadProcessId(hQuikWnd)
if WinProcId == w32.GetCurrentProcessId() then
break
end
end
return hQuikWnd
end
-- Тестовая функция создания пользовательского окна с таблицей
function CreateTableWindow(caption)
local t_id = AllocTable()
AddColumn(t_id, 0, "1", true, QTABLE_INT_TYPE, 15)
AddColumn(t_id, 1, "2", true, QTABLE_INT_TYPE, 15)
local t = CreateWindow(t_id)
SetWindowCaption(t_id, caption)
InsertRow(t_id, -1)
SetCell(t_id, 1, 1, "<<" .. caption .. ">>")
end
-- Основной код
hQuikWnd = GetQuikMainWindowHandle()
-- получим handle окна вкладок, далее все операции по переключению вкладок будем совершать с этим окном
hTabWnd = 0
if hQuikWnd > 0 then
hTabWnd = w32.FindWindowEx(hQuikWnd, 0, "SysTabControl32", "")
if hTabWnd ~= 0 and not w32.IsWindowVisible(hTabWnd) then
-- Если окно вкладок найдено, но отображение вкладок отключено - сбросим в 0
hTabWnd = 0
end
end
if hTabWnd > 0 then
-- Если вкладки в терминале отображаются
-- Сохраним индекс текущей активной вкладки
local prevIdx = w32.TabCtrl_GetCurFocus(hTabWnd)
-- Определим и выведем через message() наименование активной вкладки на момент старта
-- (индекс активной вкладки сохранён ранее, так что здесь получаем / отображаем имя просто так)
-- w32.TabCtrl_GetItemText() вызываем только с 1 параметром, т.к. нас интересует имя активной вкладки
local activeTabName = w32.TabCtrl_GetItemText(hTabWnd)
if activeTabName then
-- т.к. явно проверили, что имя вкладки получить удалось (оно не nil)
-- просто отображаем его без tostring()
message("Активна вкладка: " .. activeTabName)
end
-- Получим индекс вкладки с именем "Графики" (если такая существует)
local idxGr = w32.TabCtrl_GetItemIndexByText(hTabWnd, "Графики")
if idxGr >= 0 then
-- Если вкладка "Графики" найдена
-- переключимся на неё и создадим таблицу на ней, получив имя
w32.TabCtrl_SetCurFocus(hTabWnd, idxGr)
-- Получим название текущей активной вкладки (только что на нее переключились)
local txt = w32.TabCtrl_GetItemText(hTabWnd)
-- Используем tostring(), т.к. TabCtrl_GetItemText при ошибке возвращает nil
CreateTableWindow("Вкладка '" .. tostring(txt) .. "'")
end
-- Получим общее количество вкладок
cnt = w32.TabCtrl_GetItemCount(hTabWnd)
for i = 0, cnt-1 do
-- Переключаемся поочередно на каждую вкладку и создаем таблицу с именем вкладки
w32.TabCtrl_SetCurFocus(hTabWnd, i)
-- Получим название вкладки
-- т.к. получаем название текущей активной вкладки (только что на нее переключились),
-- то второй параметр можно не указывать; но здесь оставлен второй параметр для тестов
local txt = w32.TabCtrl_GetItemText(hTabWnd, i)
-- Используем tostring(), т.к. TabCtrl_GetItemText при ошибке возвращает nil
CreateTableWindow(tostring(txt))
end
-- Переключимся назад на исходную вкладку
w32.TabCtrl_SetCurFocus(hTabWnd, prevIdx)
else
-- Если вкладки в терминале не отображаются
CreateTableWindow("Вкладки отключены")
end
на простейшем скрипте с использованием этой библиотеки: luacdll = require("luacdll") message(tostring(luacdll.GetCurrentThreadId()), 1)
QUIK 8.6 -- после того, как скрипт отработал - dll-файл библиотеки остаётся заблокированным, т.е. dll не выгружена корректно. QUIK 8.9 -- после того, как скрипт отработал - dll-файл библиотеки НЕ остаётся заблокированным, т.е. dll выгружена корректно, dll-файл с библиотекой можно переписать / удалить, не закрывая QUIK.
STRING getScriptPath() Функция возвращает путь, по которому находится запускаемый скрипт, без завершающего обратного слеша («\»). Например, C:\QuikFront\Scripts