Полагаю,что есть единственный способ знать как давно была совершена сделка. ------------------ Ранее уже говорил, что единственный способ не торговать по вчерашним сделкам, это синхронизация времени компьютера по серверу реального времени или GNSS и сравнение времени сделки с точным временем. ----------------- В итоге мы будем всегда знать на сколько запоздала информация о сделке. Другого способа не существует.
Для тестирования торговых роботов не хватает истории торгов. Просьба сделать возможность конвертации данных из текстового формата в формат файлов с данными типа .dat , либо выложить формат этих файлов.
используйте сервер точного времени и не будете месяцами ничего согласовывать. Биржа тоже его использует. погрешность будет не более 10 мс. Это меньше, чем задержка интернета.
nikolz написал: зачем Вы данные всех сделок собираете в таблицу QLUA
Ничего никуда не собираю, сижу примус починяю, а тут и добрый совет подоспел. Попал тксть под раздачу.
тогда поясните, что вы делаете в функции колбека: ------------------------------- function OnAllTrade (v) recursion_level = recursion_level + 1 counter = counter + 1 if recursion_level > max_recursion_level then max_recursion_level = recursion_level end if tabid then SetCell (tabid, rowid, 1 , tostring(max_recursion_level)) SetCell (tabid, rowid, 2 , tostring(counter)) end recursion_level = recursion_level - 1 end -------------------------
Михаил Понамаренко написал: Сегодня выпустил своего простенького робота сеточника на демо-счёт. Пока трудится без капризов, но потребление памяти, с учётом, что робот практически не накапливает данные впечатляет. Мусоровоз приезжает систематически, но загружает не весь мусор.
У меня достаточно сложные роботы, висят круглосуточно постоянно (пока на версии 8.8.4.3 с 14 сентября), память показывается в данном окне 300-600 KB и в этих пределах крутится. У вас просто нереальные цифры.
очевидно это у вас версия 7 на XP у меня тоже 7 версия кушает 600 КB а вот верия 8.3 на win10 даже без робота кушает 6.8МБ
Коля Маржин написал: У меня до сегодня был прекрасный интерфейс к роботу на библиотеке qvcl, но в связи с тем что сегодня все квики только 64bit а qvcl там не работает, то было принято решение запускать gui на 32bit Lua отдельном от quik.
Всё запустилось и основной необходимый мне функционал работает (кнопочки жмутся, данные шлются в квик через файл), но весь код который после инициализации окна ShowModal не запускается пока окно не закроется - я не могу обновлять данные в окне автоматически (вслед за обновлённым файлом настроек окна). Если окно инициировать по Show и после него ставить вечный цикл с синтетическим sleep на основе ping (в неквиковом lua функции sleep нет) то окно зависает. Есть у кого-нибудь идея, как, не закрывая окно, после его инициализации сделать цикл типа функции main в квиковом lua из которого можно было бы менять настройки окна?
1) попробуйте Coroutines; 2) если не поможет, то создайте второй поток.
Anton написал: Идея с рекурсией не подтверждается пока, потестил с перезаказами ТВС следующим скриптом
Код
local run = true
local tabid = nil
local rowid = nil
local counter = 0
local recursion_level = 0
local max_recursion_level = 0
function OnInit ()
tabid = AllocTable ()
if 0 = = AddColumn (tabid, 1 , 'recursion level' , true , QTABLE_STRING_TYPE, 16 ) then
DestroyTable (tabid)
tabid = nil
error( "AddColumn failed" )
end
if 0 = = AddColumn (tabid, 2 , 'counter' , true , QTABLE_STRING_TYPE, 16 ) then
DestroyTable (tabid)
tabid = nil
error( "AddColumn failed" )
end
if 0 = = CreateWindow (tabid) then
DestroyTable (tabid)
tabid = nil
error( "CreateWindow failed" )
end
rowid = InsertRow (tabid, - 1 )
if - 1 = = rowid then
DestroyTable (tabid)
tabid = nil
rowid = nil
error( "InsertRow failed" )
end
end
function OnAllTrade (v)
recursion_level = recursion_level + 1
counter = counter + 1
if recursion_level > max_recursion_level then
max_recursion_level = recursion_level
end
if tabid then
SetCell (tabid, rowid, 1 , tostring(max_recursion_level))
SetCell (tabid, rowid, 2 , tostring(counter))
end
recursion_level = recursion_level - 1
end
function OnStop ()
if tabid then
local t = tabid
tabid = nil
DestroyTable (t)
rowid = nil
end
run = false
end
function main ()
while run do
sleep ( 1000 )
end
end
Результат - уровень рекурсии стоит 1 как влитой. Кому не лень прошу повторить упражнения, может где двоечка хотя бы выскочит, тогда будем знать, что хотя бы в принципе такое возможно. Также можно попробовать понагружать OnAllTrade перед выводом в таблицу чем-нибудь. Вариант sleep(100) попробовал, загружает квик до почти зависания, но это и логично, надо бы чем-нибудь поинтересней.
зачем Вы данные всех сделок собираете в таблицу QLUA - это же тормозуха. Собирайте в таблицу луа, либо в массив на C и будет вам счастье.
Михаил Понамаренко написал: Вчерашний тест, можно сказать, успешный: 54 тысячи заявок, 14 тысяч сделок, расчёт кода робота каждые 500мс, затраченной памяти 2Гб. Но главное - ни одного зависания. Всё очень быстро и точно (в сравнении с QPILE). В реальной торговле в таком режиме использовать не собираюсь и затраты памяти будут не существенные. Поэтому вопрос не критичный, скорее для возможного улучшения работы. Но это первый день краш-теста.
Очевидно, что у Вас неправильно написана программа. Вы либо банально не даете работать сборщику либо плодите много мусорных объектов как глобальные . Для начала поставьте контроль занятой памяти и при размере больше заданного запускайте сборщик мусора.
Не правильно, я вообще ничего не лепил и у меня преобразования не было, но я в коде исторически использовал "%.f", т.к. надеялся, что если преобразование типов случайно пройдет, то в строку не добавится ".0" в конце. Код .0 не добавлял, а вот сам номер изменил даже при преобразовании целого числа в строку, о чем я и написал.
вот это "%.f" и есть преобразование из целого в вещественное. В документации сказано: Стандартный Lua использует 64-битные целые (integer) и вещественные числа двойной точности (double 64-bit) В итоге у Вас 64 битное целое не умещается в 64 битное вещественное, т к для мантиссы всего 53 бита Проблема решается если целое число преобразовать в вещественное расширенной точности (long double ), но луа не поддерживает данный формат, а железо поддерживает. Поэтому если надо, то пишите свою функцию на API C.
Александр М написал: В связи с переходом биржи мы дождались 19 знаков.
Уважаемые разработчики и коллеги, может кто подскажет, почему результат разный и что надо подставить в string.format, чтобы он стал одинаковый? Как вы понимаете, необходимо, чтобы Номер заявки или сделки в виде строки всегда был нормальным числом, идентичным самому числу.
Результат: "bad argument #2 to 'format' (number has no integer representation)"
Правильно я понял, что Вы где надо и не надо лепили к числам ".0" В итоге получали переполнение разрядной сетки мантиссы, т к в отличии от целого числа на нее в 64 битах меньше места? Ну батенька, надо учить мат.часть.
Александр М написал: print(a)print(tostring(a))print(a+1)print(tostring(a+1))
сделал так: а=9152336732254970146 print(a) print(tostring(a)) --------------------- результат: 9152336732254970146 9152336732254970146 ---------------- что не так?
Михаил Понамаренко написал: Сегодня выпустил своего простенького робота сеточника на демо-счёт. Пока трудится без капризов, но потребление памяти, с учётом, что робот практически не накапливает данные впечатляет. Мусоровоз приезжает систематически, но загружает не весь мусор.
Если хотите решение проблемы, то выкладывайте скрипт. Телепатов на форуме нет.
а можно подробнее про ошибку. у меня Lua 5.3 работает корректно вот пример: a=1952336732254970146 print(a) print(tostring(a)) print(a+1) print(tostring(a+1)) ------- результат: 1952336732254970146 1952336732254970146 1952336732254970147 1952336732254970147 ---------------- что не так?
Anton написал: По-любому все потоки в квике, привязанные к луа, будут шарить одну луа-машину и, таким образом, выполняться по очереди. Поэтому я не понимаю цели подобных изысканий. Ну, создали еще 100 потоков, получили 100 дополнительных переключений контекста, поймали и героически преодолели кучку косяков с синхронизацией. И в чем профит? Кроме, конечно, прокачивания скилла, тоже занятие не сказать чтобы вредное, если есть куда потом этот скилл продать.
По-моему Вы ошибаетесь. VMLua (луа машин) не одна, а одна+число скриптов. Одна - в основном потоке, где будут последовательно вызываться все колбеки QLUA и еще по одной на каждый скрипт (main - создает свою VMLua) ------------------------------- В итоге колбеки QLUA вызываются в очередь, а потоки main могут работать параллельно. Поэтому, если мы делаем копию получаемых данных, то их обработка может выполнятся параллельно. ------------------ Но в отличии от запуска независимых задач, нет надобности перебрасывать все данные во все параллельные задачи. В том то и суть параллельных потоков. Если мы строит робота, который работает со множеством инструментов, то запуск отдельного скрипта (main) на каждый инструмент, позволяет нам организовать параллельную работу с инструментами. При этом большинство модулей будет универсальными и будут запущены в единственном экземпляре. ----------------- В существующем варианте QLUA в каждом скрипте для различных инструментов надо повторять все колбеки QLUA . В итоге мы получаем многократный вызов одних и тех же колбеков в различных скриптах. ---------------- В моем варианте для 1000 инструментов будет один модуль обработки например ТТП А в существующей версии QOUA таких вызовов будет 1000 на каждое изменение ТТП и все они будут вызываться последовательно. В итоге получается ужас какой-то.
nikolz написал: Проблема многопоточности и проблема синхронизации потоков - это синонимы.
Да, так. Надо пойти дальше и спросить, а в чем проблема синхронизации потоков. Она в синхронизации доступа к данным и только. У каждого потока есть свой (нативный) стек, поток также может выделить tls из кучи, и если он никуда больше не ходит, ему никакая синхронизация не требуется. Как только появляется какое-то разделяемое между потоками состояние, возникает проблема синхронизации доступа к нему. Посмотрим на примере. Берем два потока, совместно использующих один int. Если потоки лезут в этот int без синхронизации, имеем проблемы (даже int с точки зрения процессора не атомарен, атомарно можно его прочитать, но модифицировать уже нет). Защищаем int критической секцией. Все, проблем нет. Но если у нас два разделяемых int'а, появляется выбор: одна общая критическая секция на все разделяемое состояние или у каждого поля своя. Второй вариант это отличный способ огрести проблем: во-первых, появляется возможность дедлока, во-вторых, появляется проблема атомарности изменения обоих полей сразу. То есть лучше выбрать вариант раз с одной критической секцией на все разделяемое состояние, ценой более длительных блокировок всех потоков. В луа самом по себе вариант раз и использован, но есть нюансы*. А в квике получился вариант два, результаты которого в основном и вылезают то тут то там. Внутри квика это еще можно разрулить, зная, что и в каком порядке лочить, но как только к этой запутанной системе дан доступ внешнему кодеру через луа, открыт ящик пандоры, кодер завсегда придумает, как упорядочить свои обращения к состоянию так, чтобы повесить весь квик или получить неконсистентные результаты. Автор топика не раз просил арку дать возможность синхронизации из луа, но это, увы, не решит проблему, в квике нет одного общего лока на все, а еще один лок сделает только хуже.
Радикальный способ решения проблем - как раз приведенный в статье, межпоточное взаимодействие, по определению требующее синхронизации, локализуется в виде очередей сообщений, а каждый поток работает только со своим состоянием и ему никакая дополнительная синхронизация не нужна в принципе. Это еще не процессы (луа-то общий и нативный процесс тоже общий, хоть авторы и выбрали путающую терминологию), это просто собрали всю синхронизацию в одном месте и избавили конечного кодера от размышлений о ней. Как конкретно решили мне не нравится, но путь правильный.
Цитата
nikolz написал: Проблемы такого решения хорошо известны.
Можно ссылок или ключевиков? Винда как-то работает на сообщениях и ничего страшного, даже порт завершения позже придумали, то есть вперли-таки сообщения в само ядро (и молодцы).
* Если посмотреть в сорцы луа, увидим прекрасную вещь: сам по себе интерпретатор всегда работает под локом ( пруф: поищите lua_lock /lua_unlock в этой функции ). То есть, если выполняется только луа-код без вызовов функций, он весь атомарен (и другие потоки ждут). Лок снимается только перед вызовом си-функции. При этом встроенные библиотеки луа тоже состоят из си-функций, поэтому лок может быть снят (и тут же захвачен снова библиотечной функцией) в непредсказуемых местах, что убивает-таки атомарность изменения состояния как целого даже в луа без квика, при этом средств синхронизации со стороны луа не предоставлено. То есть луа защищает консистентность своего состояния, но не консистентность состояния пользовательского кода, с точки зрения луа-кодера он в той же ситуации, в какой и без луа, вот тебе потоки и рули как хочешь. Поэтому и говорю, что проблема не луа-специфичная, проблема в ожиданиях от луа чего-то, чего он не дает, хоть в нем и есть lua_lock.
Возможно ваши рассуждения правильны, возможно нет. Но это не имеет значение, так как решения проблемы нет, кроме как указанная вами ссылка - т е созданием изолированных задач.
Я достаточно подробно изучал исходники луа, что решить проблему много поточности в своих приложениях и ускорения обмена данными из луа в си. кое что получилось, не утверждаю, что все.
Можно много рассуждать и строить правдоподобные гипотезы о том , почему что-то не работает. но это лишь трата времени на переливание из пустого в порожнее, если не доказано как это исправить.
и самый халявный вариант. Создаем в облаке ORACLE бесплатный виртуальный сервер и ставим на нем например MQTT брокер. В итоге можно реализовать обмен информацией по подписке. Можно и любой другой вариант обмена информацией со своим компом с QUIK
рассказываю еще один простой способ 1) покупаем SIM800L+USBUART adapter - цена на али 2 доллара 2) берем карточку от любого оператора с самым дешевым тарифом и подключаем к USB. 3) на LUA через UART, с помощью AT команд, можем посылать SMS, UDP и TCP пакеты, голосовые сообщения.
Дмитрий написал: Здравствуйте! По названиям параметров ТТП, к которым можно обращаться с помощью функции getParamEx, иногда бывает трудно однозначно понять, что эти параметры означают и/или как рассчитываются их значения. Подскажите, пожалуйста, где можно взять подробное и актуальное описание всех параметров, которые транслируются с Московской биржи? Если оно есть на сайте биржи, то подскажите ссылку.
Описание полей любой таблицы в т числе и ТТП можно легко получить используя вывод через DDE сервер в excel. Для получения имен параметров надо установить флажок "Формальные заголовки" С заголовками столбцов"
Я имел в виду, что даже по русскоязычным названиям параметров из QUIK не всегда можно однозначно понять, что именно они означают.
было бы удивительно, если бы по названию можно было бы определить что это такое. Безусловно, надо читать описание параметров в документации биржи. Но оно Вам надо?
Погряз в рутине с заявками и сделками. На соседних ветках тут уже были предложены решения. В частности, от уважаемого _sk_ , например.
Но, блин, это ж надо операционную систему написать...
Кто как борется с неоднозначностями?
Например, прилетает мне сделка в OnTrade(). И я знаю наверняка, что прилетит еще её дубль, а может, и в третий раз сработает. Как узнать, это просто дубль пришел или моя заявка последовательно разбирается частями? В отличие от OnOrder(), в OnTrade() нет поля остатка balance (что и логично). Есть только qty. И чем тогда отличается повторное срабатывание от нового на такой же объем? trade_num у них одинаковые. Все остальное (order_num, trans_id, ...) тоже. Заявка-то одна была.
В саму заявку тоже не очень посмотришь. Во-первых, порядок срабатывания OnOrder(), OnTrade() достоверно не предопределен. Во-вторых, там свои неоднозначности. Допустим, использую я move_order. Прилетает сделка, а заявка еще пришла, а если пришла в OnOrder() и "исполнена", то надо еще разобраться, что это означает: а) успела исполниться старая заявка до перестановки, б) успешно переставилась, в) исполнилась уже новая после перестановки.
Есть ли компактные решения менее 1000 строк? :)
Спасибо!
А что страшного в том, что прилетит дубль? Храните сделки в таблице и обновляйте ее состояние. Если прилетел дубль, то он ничего не обновит. Не имеет значение сколько раз прилетит информация о сделке. ------------------------ Когда сделка завершена, то ее состояние "не активна" и мы ее просто не замечаем -------------------- В каждой сделке можно найти номер заявки которая ее создала Таким образом сделка однозначно отслеживается по заявке которая ее создает
nikolz написал: Чтобы ускорить работу надо функцию выставления заявки запускать в отдельном потоке,
А как это ускорит работу?
Никак
Ну если не можете запустить выставление заявки в отдельном потоке, то запустите все остальное в другом потоке. Например , можно в отдельных потоках запускать алгоритмы принятия решений роботом для различных рынков (бумаг) можно в отдельных потоках запускать любые функции, которые не связаны с основным потоком КВИК. В отдельных потоках дополнительно к main можно запускать любые действия внутри колбеков и тем самым ускорять их исполнение. ----------------- Так как узким местом териминала КВИК является его хранилище, то, чтобы обеспечить параллельную работу потоков, надо всю информацию, поступающую в терминал квик, дублировать в свои таблицы и файлы и работать не с хранилищем терминала, а со своей базой данных. --------------------
Дмитрий написал: Здравствуйте! По названиям параметров ТТП, к которым можно обращаться с помощью функции getParamEx, иногда бывает трудно однозначно понять, что эти параметры означают и/или как рассчитываются их значения. Подскажите, пожалуйста, где можно взять подробное и актуальное описание всех параметров, которые транслируются с Московской биржи? Если оно есть на сайте биржи, то подскажите ссылку.
Описание полей любой таблицы в т числе и ТТП можно легко получить используя вывод через DDE сервер в excel. Для получения имен параметров надо установить флажок "Формальные заголовки" С заголовками столбцов"
Duke2 написал: Evgenii, Main зациклен, просто в выдержку кода не попало зацикливание. Спасибо все равно
дело в том что поток колбеков и поток Main - это разные потоки. Если функция выставления заявки будет работать в майн, то это ничего не даст, кроме лучшей читаемости текста программы. -------------------------- Чтобы ускорить работу надо функцию выставления заявки запускать в отдельном потоке, а в цикле майн проверять завершение работы этой функции. ----------------- Если есть желание это сделать, то рекомендую почитать книгу Дж.Рихтер Создание эффективных WIN-32 приложений с учетом специфики 64-разрядной версии Windows
nikolz написал: не надо отслеживать новые версии и исправлять то, что перестает работать
Это, конечно, важный плюс, спору нет. Но если один мейн рушится, что с остальными делать? Очевидно, тоже прибивать и завершать весь скрипт, т.к. очень сомнительно, что большинство скриптов следуют RAII (до предыдущей версии это было физически невозможно даже и никто не бухтел, т.е. буквально никто этим не морочился). В таком раскладе мультипликативно снижаем общую надежность скрипта, если (утрированно) надежность одного мейна 0.5 и всего скрипта тоже, то при двух таких мейнах надежность скрипта в целом уже 0.25.
Указанная Вами проблема легко решается. -------------------------------- Дело в том, что в моем решении создание роботов разделяется на отдельные ,самостоятельные и не требующие нового программирования модули. Ранее я уже намекал на такое решение. Это решение легко представить, если ответить на вопрос -Чем отличаются роботы торгующие акциями друг от друга? ---------------------------- Они отличаются лишь торговым алгоритмом. В моем варианте, я сделал модуль для работы кучу общих модулей - модуль для стакана, модуль для счета, модуль для сделок, модуль для заявок, модуль стопов и т д. Все эти модули являются универсальными и одинаковыми для любого робота. ----------------------------------- В итоге, разработка робота сводится к программированию лишь алгоритма принятия решения. Этот алгоритм можно написать на более простом и близком к естественному языку. ---------------------------------- В итоге нет надобности изучать LUA, изучать QLUA. Надо изучать именно закономерности рынка и написать алгоритм состояний робота и логику изменения этих состояний. ---------------------------------- В итоге любой буратино может легко реализовать свой гениальный алгоритм, как стать миллионером на поле чудес.
nikolz написал: если бы все было так просто, то проблему многопоточности в луа не поднимали бы на форумах уже лет ..надцать.
Это именно проблемы многопоточности как таковой, а не многопоточности в луа. В приведенной статье тоже. Как раз автор пришел в конце к правильному выводу, асинхронность рулит. Надо только не забывать, что нынче практически все процессоры многоядерные, даже контроллеры многие, так что многопоточность все равно будет присутствовать, главное ее локализовать и не позволить ей разползтись по всему коду. Конкретно в квике уже отступать некуда, архитектура выбрана такая и трудно предположить, как ее можно обратно-совместимо поправить. Теперь только костыли лепить.
Многие решали, в том числе и основоположники . К сожалению, конкретно в их решении очереди блокирующие, эдакий qnx получился.
Дискуссия схоластическая, но замечу, что Вы путаете понятия Проблема многопоточности и проблема синхронизации потоков - это синонимы. т е первое это есть второе. Проблема именно луа а не многопоточности. Как решать задачу синхронизации потоков в конкретном софте хорошо разжевано у Рихтера. Но в луа проблема в том, что есть сборщик мусора и много сторонних библиотек. -------------------------- Вы не внимательно прочитали статью, на которую ссылаетесь. --------------------------- цитата: "В этой работе мы исследуем модель, основанную на выполнении потоков без общей памяти, которые используют передачу сообщений для синхронизации и общения." Т е это фактически многозадачное решение, а не многопоточное. ------------------------------ и далее цитата: "Связь между процессами Lua происходит исключительно через сообщения. Cвязь с передачей сообщений может быть медленнее по сравнению с общей памятью." =============== Т е упрощенно, запускаем несколько независимых VMLua как несколько задач, а потом пересылаем данные между ними в виде сообщений OC. Проблемы такого решения хорошо известны.
verder написал: Каков оптимальный способ программно остановить исполнение скрипта на QLua? Например, код диагностирует некую внутреннюю ошибку по своей логике, выкидывает message и сразу останавливает работу скрипта во всех потоках.
в main есть бесконечный цикл поставьте в нем переменную и присваивайте ей nil при ошибке. В итоге скрипт завершит работу
Я определения текущего количества фьючерсов в портфеле я использую функцию getFuturesHolding. Обратил внимание, что если по тикеру ранее не было сделок, то функция возвращает Nil, а не 0 как я предполагал. Если сделки ранее были, то количество бумаг отображается корректно.
Можно ли как-нибудь выйти из этой ситуации?
просто написать local x=0; -- текущее количество фьючерсов if ( getFuturesHolding...) then x= getFuturesHolding... end -- читаем текущее количество
nikolz написал: Есть очень простое решения проблемы статуса сессии. Делаем раз - синхронизируем компьютер по серверу времени. Это позволяет нам синхронизироваться с временем биржи с погрешностью не более 0.01 сек Делаем два - пишем константы начала и конца сессий Делаем три - где надо и не надо просто сравниваем текущее время с константами и решаем какое сейчас состояние сессии без каких либо кодов с биржи ------------------------ Самое смешное в том, что биржа(брокер) свои коды формируют точно так же.
Как для автомобиля - крутить рукоятку если стартер не заводит автомобиль - простое решение ). Я перешел к пользованию статусом сессии именно потому, что однажды, пользуясь простым решением, забыл перевести сезонное время (я живу в стране где его надо переводить) и потерял прилично денег на этом.
полагаю что потеряли вы не по причине что забыли перевести время. это лишь вариант самоуспокоения. Если Вы включили комп позже начала сессии, то никакие сигналы Вам не помогут. и статус сессии здесь не причем. Конечно решать Вам, я лишь изложил свой опыт решения данной проблемы
Что я выше описал, это на стороне qlua.dll, то есть аркино производство. В самой lua53.dll правки если и есть, то крайне незначительные, практически все строка в строку ложится на сорцы луа из репозитория, как выше из разбора дампа видно.
Цитата
nikolz написал: Проблема многопоточности в луа - это проблема луа.
Луа дает lua_lock/lua_unlock и на этом его проблемы с многопоточностью закончены. Можно поспорить, здорово ли, что в некоторых функциях 5.3 вытащили часть обращений к стеку из-под лока, если говорить о проблемах луа. Но вот как сделаны эти самые локи (и не только), это уже вопросы к арке.
Ва заблуждаетесь, если бы все было так просто, то проблему многопоточности в луа не поднимали бы на форумах уже лет ..надцать. Вот, например, результат попытки решения критическими секциями (look, unlook) и таких воплей в инете много. -------------------- Тоже решал эту проблему, но не уверен, что нашел окончательное решение .
добавлю свои пять копеек. Если это особенности VMLua то разработчики ничего исправлять не будут. VMLua написана не ими. Они лишь встраивают ее в КВИК и сделали dll интерфейса на луа с хранилищем терминала и обменом с сервером КВИК. --------------------- Проблема многопоточности в луа - это проблема луа. Есть различные решения этой проблемы, но они никак не связаны с КВИК.
Есть очень простое решения проблемы статуса сессии. Делаем раз - синхронизируем компьютер по серверу времени. Это позволяет нам синхронизироваться с временем биржи с погрешностью не более 0.01 сек Делаем два - пишем константы начала и конца сессий Делаем три - где надо и не надо просто сравниваем текущее время с константами и решаем какое сейчас состояние сессии без каких либо кодов с биржи ------------------------ Самое смешное в том, что биржа(брокер) свои коды формируют точно так же.
Добавлю свои пять копеек к решению проблемы. ----------------------------------------- Обычно такая проблема возникает, если есть массивы, которые определяются лишь при старте индикатора. В результате, при смене тайма, они остаются не пустыми. В итоге нарушается индексация и возникают отсутствующие элементы ------------------------- Проблему решаем так: ---------------------------- Создаем специальную функцию инициализации всех переменных индикатора. ----------------------- Эту функцию вызываем в двух местах - в Init() - здесь можно и не вызывать, но делаю это, так как Init как бы для этого создана. Вызывается в индикаторе один раз при запуске и не влияет на скорость исполнения. и в onCalculate() при индексе равном 1 Например так: -------------------------------- function OnCalculate(k) if k==1 then -- вызываем функцию инициализации end -------------------------- Если будете выполнять данное правило, то проблем при переключении тайма не будет.
Вадим написал: Кажется я понял, что колбэк функция возвращает два состояния заявки - старое и новое
Заявка на Покупку Дата Номер Флаг Dec/Hex/Bin Thu Aug 13 21:55:00 2020: 26203598248162 25 / #19 / 00011001 Thu Aug 13 21:55:00 2020: 26203598248162 25 / #19 / 00011001 Thu Aug 13 22:12:43 2020: 26203598248162 25 / #19 / 00011001 Thu Aug 13 22:12:43 2020: 26203598248162 26 / #1A / 00011010
Заявка на Продажу Дата Номер Флаг Dec/Hex/Bin Thu Aug 13 21:56:27 2020: 26203598274028 29 / #1D / 00011101 Thu Aug 13 21:56:27 2020: 26203598274028 29 / #1D / 00011101 Thu Aug 13 22:24:21 2020: 26203598274028 29 / #1E / 00011101 Thu Aug 13 22:24:21 2020: 26203598274028 30 / #1E / 00011110
В случае первого появления заявки оба состояния новые В случае последующих изменений старое+новое состояние
Воспринимайте колбек, как сигнал на бесчисленное множество событий, из которых Вам надо очень малое число. Поэтому не надо пытаться их все понять. --------------- Надо всегда ставить фильтр лишь того, что нужно. Остальное - игнорировать. В реалии событий может быть хоть тысяча, но вам нужно лишь два. Вместо того , чтобы выяснять что это за событие, определитесь что же конкретно нужно Вам. ----------------------- В итоге роботу будут безразличны все события в мире, кроме тех, которые нужны Вам.
Сама постановка задачи ассоциируется примерно с таким: Надо на автомобиль поставить ракетный двигатель. Даже страшно представить что будет с таким хотелкиным, если ему это сделать , но скорее всего он и сам не знает, зачем это реально надо.
Сергей написал: Прежде всего, я нигде, вроде, не просил написать скрипт на Луа, или каком-либо еще языке, достаточно было изложить общий принцип организации выборки. Прямой, обратный, с использованием специальных функций, что-то еще. По существу последнего ответа, спасибо, хоть какая-то конкретика, по крайней мере понятно, как организована сортировка в таблице позиций. Уж, как это обработать в скрипте, дело действительно индивидуальное.
сталкивался с такой ситуацией. Ее исключить можно если контролировать размер таблицы. -------------- Полагаю, что лучшим способом, является не лазить постоянно в хранилище терминала, так как это очень накладная операция, а создавать свои таблицы и отслеживать в них появление и удаление строк в соответствии с колбеками.
Старатель написал: Andrey Bezrukov, Никакого архива, конечно же, не будет. В этом нет смысла. Вероятность воспроизвести точно такую же ситуацию не высока, и ваш ответ ("проблема не воспроизводится") очевиден. Вы можете только подтвердить или опровергнуть гипотезу:
Цитата
Старатель написал: Первый список загружается вместе с QUIK. Второй загружается вместе с файлом настроек уже после того, как стартуют скрипты.
А заодно проверить в своём коде терминала, что в момент подмены списков таблица trade_accounts сначала очищается, а затем вставляются списки из info.wnd. И в этот момент как раз существует гипотетическая вероятность получения nil из вышеприведённого кода. Как-то так, других вариантов у меня нет.
И зарегистрировать пожелание на доработку: стартовать скрипты после полной загрузки настроек. Если, конечно пользы от этого будет больше, чем вреда.
Пример ещё нескольких функций, которые зависят от последовательности загрузки настроек: getNumCandles, getLinesCount, getCandlesByIndex
Попробуйте решить подобную проблему путем контроля времени пинга до сервера. --------------- примечание: Решал эту проблему давно, поэтому не уверен, что один этот параметр использовал, но помню, что решил. В настоящее время встраиваю роботов в индикаторы, поэтому подобные скрипты где-то в архивах пылятся.
Игорь Б написал: Myfilefile = "\\MyData.txt"; i = 0; while i == 0 do Myfile = io.open(getScriptPath()..Myfilefile,"r+"); -- Если файл занят if Myfile == nil then sleep(100); else i = 1; end; end;
у вас просто неправильно сделана реакция на if Myfile == nil then если Myfile == nil это означает что файл не открыт т е вам надо проверять на ni и если не открыт то делать его открытие, а не спать.
Боюсь те, кто этим смог бы грамотно воспользоваться, могут это сами и сделать, как автор идеи, в частности. Всем остальным буратинам это не нужно и вредно.
с Вами не согласен по трем причинам: 1) Если это решение будет официальное, то не надо отслеживать новые версии и исправлять то, что перестает работать . Как это есть сейчас. 2) Буратинам будет еще легче писать свои хотелки так как нет надобности одно и тоже программировать в множестве роботов Все будет существенно проще 3) если это реализуют, то размещу следующее пожелание, в котором создание роботов превращается в написание лишь алгоритма, а все или почти функции QLUA скрываются в обертке Т е буратинам даже не надо изучать луа. Просто пишут почти на естественном языке что хотят и все работает.
Добрый день, Прошу разработчиков рассмотреть следующее предложение по развитию QLUA. ---------------- Суть проблемы. При создании нескольких скриптов приходится дублировать внешнюю среду функции main в каждом скрипте Т е все колбеки и все глобальные переменные Но так как все это исполняется в одном потоке создается существенное торможение работы терминала при большом числе скриптов. -------------------- Решение - предложение. Решить проблему можно двумя путями. Вариант1 Реализовать возможность создание в одном скрипте множество функций main Т е реализовать механизм запуска нескольких потоков в одном скрипте Ввариант2 Реализовать возможность работы множеству скриптов с одной глобальной областью Этот вариант реализуется, например, путем подмены указателя глобальной таблицы скрипта на указатель общей глобальной области Этот вариант я реализовал лет восемь назад для win32 и LUA 5.1, Теперь надо все переделывать на 64 и 5.3 ------------------- Поэтому предлагаю это сделать для всех буратин.
Nikolay написал: Это, конечно, похвально написать свой RabbitMQ, но, в результате, получится схема не меньшей сложности. Т.е. мы пишем свой терминал. Он будет собирать события терминала, исполнять команды скриптов и читать их ответы, передавать им поток данных.
При этом мы итак находимся внутри такого окружения... Что мешает написать скрипт исполняющий сразу несколько алгоритмов, по многим инструментам. Будет один скрипт, одно окружение. А колбеки Квика слишком ненадежная конструкция. Проще без них. Хотя, конечно, от части из них отказаться сложно, как, например, OnTransReply.
вообще-то я написал о том, что сделал сам лет ...надцать назад, т е фактически сразу как внедрили VMlua в квик. А перед этим примерно года за два я сам в переписке с руководством разработчика предлагал внедрить вместо QPILE LUA. не утверждаю, что они меня послушались, но в результате появился луа в квике. --------------------- Тот механизм, о котором я написал, позволяет очень просто делать много роботов по различным алгоритмом для одного инструмента. Колбеки не дублируются в скриптах Каждый колбек существует в своем скрипте и вызывается всего один раз квиком для получения данных вне зависимости от числа роботов. Роботы получают требуемые данные от этого скрипта. т е потоки синхронизируются и обмениваются данными , а также чтобы не дублировать код, могут запускать функции других скриптов через механизм колбеков между скриптами. Сравнительно просто в этом варианте отдавать данные совершенно независимым процессам. ----------------------- Но если не мечтать о вечном, то проще всего делать роботов как индикаторы.
nikolz написал: Каждый скрипт условно можно разделить на три части1) действия вне колбеков и функции main - это отдельный поток и VM Lua2) функция main каждого скрипта - это отдельный поток и VMLua3) вызов и исполнение функций колбек осуществляется в одном основном потоке термина.
Не совсем оно так, стейт для тела скрипта и колбеков один и выполняется в основном потоке квика, стейт для мейна второй и выполняется в специально для него созданном потоке. То есть ваш п.1 лишний, нет отдельного стейта для тела.
Ваши мысли насчет 128 ядер это из разряда давайте загрузим проц бесполезной работой, чо он простаивает-то. В любом случае ваши 100500 потоков будут сериализоваться на доступе к общим ресурсам, т.е. в основном (в таком количестве) они будут крутить спинлок. Для примера предлагаю прогу из directx sdk, где можно отрисовать одно и то же либо одним потоком, либо многими. Запустите и убедитесь, что проц оно жрет в N раз больше, а fps растет процентов на 5.
Я вам предлагаю для примера посмотреть алгоритм БПФ либо нейронной сети
Иван Ру написал: Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов: 1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.) 2. Отдельных классов (стратегия, позиция и т.п.)
Существующая структура QLUA имеет существенный недостаток. Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах. В итоге получается дублирование одних и тех же действий многократно. Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются, а скрипты могут запускать функции друг у друга и получать данные из других скриптов.. ------------------------- В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
Признаться, все более склоняюсь в сторону такой модели, в первую очередь из-за разрастания скрипта и усложнения его логики из-за чего работа и модификация скрипта становится все более затруднительной... Полагаю можно использовать такую структуру: - базовый скрипт, который определяет статус сессии и агрегирует информацию из коллбэков - описание классов (стратегия, позиция и т.п.) - типовые универсальные модули, например, удаление устаревшей части данных таблиц (цены, бид аск и т.п.), ежедневное определение ключевых временных точек сессии в формате posix, визуализация и логгирование информации и т.п. - собственно скрипты с описанием стратегий, логики определение сигналов на вход и выход и сопутствующих действий...
Если кто-то поделится своим видением организационной структуры - буду признателен
Поясню свое прежнее беспокойство - у меня большинство скриптов работает одновременно с большим числом инструментов, предполагается большой объем расчетов, опасаюсь, что в тех случаях когда они осуществляются не в теле основного потока (main), а путем многократного вызова функции, это может негативно сказаться на быстродействии скрипта.
Проблема усложняется тем, что разработчики не утруждают себя документацией по API к их библиотеке, нигде не описывают интерфейс взаимодействия скриптов с терминалом на уровне API C for LUA. На основе ответов основного разработчика QLUA(не будем показывать пальцем) , по-моему мнению, схема взаимодействия скриптов с терминалом следующая: ------------------------------- Каждый скрипт условно можно разделить на три части 1) действия вне колбеков и функции main - это отдельный поток и VM Lua 2) функция main каждого скрипта - это отдельный поток и VMLua 3) вызов и исполнение функций колбек осуществляется в одном основном потоке термина. --------------------------- В итоге получаем следующее. Если Вы не профессионал , то скорее всего будете много делать в колбеках - так проще . Все колбеки будете вызывать в каждом из скриптов. ------------------------------- Получается прикольно. Даже если у Вас суперкомпьютер с 128 ядрами , то все колбеки будут тупо работать на одном ядре и в одном потоке, в котором крутится еще и основное ядро терминала КВИК. ------------------ Сейчас версию 7 заменяют на версию 8 В итоге XP с одним ядром не работает вообще. Но зато у Вас теперь win10 64 бита и ядер хоть 128. А что реально в сухом остатке? -------------------------- Представим что на телегу прикрутить двигатель от болида формулы 1, а впереди телеги все та же лошадь . Вопрос, насколько быстрее эта телега теперь довезет Вас из пункта А в пункт В? ----------------------------------------- Конечно есть решение костыльное - ничего не делать в колбеках, а делать все в main. Но резонно спросить разработчиков, а о чем думали они когда разрабатывали концепцию встраиваемой виртуальной машины? -------------------------------- Да и это костыльное решение не решает проблему многократного дублирования кода в различных скриптах. --------------------------------- На самом деле все могло быть существенно проще и исполняться существенно быстрее, но именно это никому не требуется. -------------------------- На рынке всегда решается лишь одна задача, за разработку инструмента для решения которой платят разработчикам, - как у буратины отобрать пять золотых. ----------------------------------- В итоге для целей конструирование игрушечных роботов, чем занимаются посетители данного форума, все сделано просто замечательно. ==================================================================================== "Теперь попросим на трибуну начальника транспортного цеха. Пусть доложит об изыскании внутренних резервов. "
Иван Ру написал: Интересно мнение форумчан - как предпочитаете писать скрипты - все в одном файле или в виде конструктора - с подгрузкой отдельных файлов: 1. Отдельных функций/процедур (выставление заявки, считывание определенных данных и т.п.) 2. Отдельных классов (стратегия, позиция и т.п.)
Существующая структура QLUA имеет существенный недостаток. Все колбеки вызываются из одного потока и каждый из них повторяется в различных скриптах. В итоге получается дублирование одних и тех же действий многократно. Я устранил эту проблему и сделал механизм при котором колбеки в скриптах не повторяются, а скрипты могут запускать функции друг у друга и получать данные из других скриптов.. ------------------------- В итоге не только повышается скорость, но и размер кода сокращается в десятки раз.
Иван Ру написал: Вот так ругается на строку кода в цикле расположенном в пределах main, где пытаюсь считать статус соединения... while is_run do sleep (50) if isConnected() == 1 then .. -- не могу понять, что тут написал не так, ругается на эту строку ... end