События в QLua
Добрый день, друзья!
Изучаю QLua, посмотрел несколько примеров, в том числе у Albus'a.
Обычно в цикле пишут sleep(n), при обновлении котировок или любых других значений.
Вопрос к опытным кулуйстам:
1. Есть ли возможность как-то подписаться на событие получения, к примеру, новой котировки, а не перезапускать цикл через n-млсекунд постоянно?
2. Есть ли интерфейс подключения к квику, чтобы программировать не через lua, а, например на c#?
quikluacsharp.ru/
вот, тут всё расскажут, подскажут
на сколько я понимаю на оба вопроса ответ - да
DataSource = CreateDataSource(ClassCode, SecCode, INTERVAL_M1) — подписываемся на источник данных
DataSource:SetUpdateCallback(CallBackDataSource) --назначаем функцию обратного вызова
2. Стандартного интерфейса в квике нет. Нужно писать «прокладку» на С++ для передачи необходимых данных в прогу на С#.
Просторы инета, например https://quikluacsharp.ru/bez-rubriki/s-chego-nachat/
Я не клуист, но судя по этой логике, если бы была возможность подписки на событие, так бы и делали, просто вешали бы коллбек на событие. Скорей всего, там котировки получаются по запросу на сервер. То бишь, pull-технология, она самая распространенная на текущий момент, даже в вебе.
ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_pull
Смотрите какой в цикле запрос.
Для того, чтобы было то что Вы хотите в чистом виде, нужно чтобы сервер квика сам рассылал обновления котировок.
ru.wikipedia.org/wiki/%D0%A2%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D1%8F_push
Не факт что эта фича там есть. Поинтересуйтесь у техподдержки на эту тему
Один нюанс, в quik должна быть открыта таблица обезличенных сделок с необходимым инструментом.
это к примеру, а так есть несколько функций обратного вызова, они описаны в документации
Например OnDisconnected(), можно просто отдельно прописать и он вызовется при разрыве соединения или его необходимо указать и в main?
function OnDisconnected()
message('Disconnected')
end
function OnStop(s)
bStopped = true
end
function main()
bStopped = false
while not bStopped do
sleep(100)
end
end
Интересно, поймут ли меня сейчас?
Если очень кратко, то примерно так — примите во внимание наличие в QUIK независимых потоков Windows, претендующих на использование процессора(ов) ПК.
Все индикаторы (OnCalculate) и все асинхронные выходы (OnStop, OnTrade, OnConnect, OnTransReply, …, много их там) вызываются-выполняются после возникновения каких-либо событий (связь ли разорвалась, в стакане что-то поменялось, ...) последовательно в одном (основном) потоке QUIK. По этой причине крайне нежелательно загружать этот поток длительной обработкой – можно серьезно затормозить работу QUIK, а при зацикливании, например, индикатора – вовсе блокировать.
Все скрипты (main) выполняются каждый в своем отдельном потоке, с претензией на параллельность, насколько это позволяют аппаратные возможности ПК (многоядерность) и возможности Windows по разделению времени процессора(ов) между потоками-претендентами.
Синхронизация потоков и совместная обработка общих данных требует определенной аккуратности от программиста.
Одно дело – когда основной поток в рамках отработки асинхронного выхода OnStop просто взведет где-то флажок, а скрипт его заметит.
Другое – когда в основном потоке и в скрипте (main) вы обновляете одни и те же таблицы или пишете в один и тот же файл – приключения вам гарантированы. Рано или поздно возникнет ситуация, когда вы частично (не до конца) обновили совместно используемый ресурс, но вдруг ваш поток на полуслове прервали, а поток, который получил управление, прошелся своим обновлением по этому же ресурсу. Что получится, когда первый поток снова получит управление и завершит обновление ресурса – непредсказуемо.
Поэтому обычно используют схему периодического засыпания-просыпания скрипта (sleep) со сканированием таблиц QUIK, а возможности асинхронных выходов используются по минимуму. Для передачи данных между основным потоком и скриптом разработчики дали несколько потокобезопасных функций: sinsert, sremove,sconcat.
Схема плоха тем, что периодически, закрывая глаза на происходящие события, вы на какое-то время опаздываете с их обработкой, а, проснувшись, пытаетесь оценить, были ли важные для вас изменения, возможно, напрасно, их может и не быть.
Можно устранить этот дефект с помощью нескольких фукций API Windows.
Например, скрипт (main) ждет наступления какого-либо события с помощью функции WaitForMultipleObjects (в ней есть и отсчет временного интервала), а асинхронные выходы оповещают main о наступлении событий с помощью функции SetEvent. Дополнительно потребуются функции CreateEvent, ResetEvent, CloseHandle.
С уровня LUA эти функции доступны через использование w32.dll. Подробно см. “Вызов WinAPI функций в Lua” (https://quik2dde.ru/viewtopic.php?id=78) .
Если не было опыта работы в многозадачных средах, то придется что-то почитать, типа “Многопоточность и синхронизация. Процессы и потоки” (http://www.kurzenkov.com/Articles/multithreading1.html)
Вполне приличный простой потокобезопасный движок для робота получается, события не пропускаются и нет холостых ходов. LUA + несколько DLL (еще одна на С++ может потребоваться для ускорения мощной арифметики).
Предварительную быструю фильтрацию событий можно делать и в программах асихронных выходов. Например, заказывая источник данных (CreateDataSource) и функцию асинхронного выхода (обратного вызова, SetUpdateCallback), я передаю из нее в скрипт (main) через sinsert/sremove (данные) и SetEvent (событие) только около 10% изменений текущей свечки.
P.S. Еще где-то встречал полезную testc.dll, одна из функций — GetCurrentThreadId (узнать идентификатор потока), для ориентации в многопоточности. О, она и в w32 есть!
В QUIK исследователькой работы очень много, но для программиста это преодолимо.
Кстати, WaitForMultipleObjects ожидаемо используется в самом QUIK (taskinfo показывал).Придётся повозиться с документацией и форумом, т.к. есть не очевидные вещи, с которыми наскоком не разобраться) но если разобраться, даёт неограниченные возможности.
если что пиши в личку, помогу чем смогу