Блог им. Helsk

События в QLua

Добрый день, друзья!

Изучаю QLua, посмотрел несколько примеров, в том числе у Albus'a.
Обычно в цикле пишут sleep(n), при обновлении котировок или любых других значений.

Вопрос к опытным кулуйстам:

1. Есть ли возможность как-то подписаться на событие получения, к примеру, новой котировки, а не перезапускать цикл через n-млсекунд постоянно?
2. Есть ли интерфейс подключения к квику, чтобы программировать не через lua, а, например на c#?
★2
25 комментариев

quikluacsharp.ru/

вот, тут всё расскажут, подскажут 

на сколько я понимаю на оба вопроса ответ  - да

avatar
Igr, видно ссылка неправильная. 
Александр Правилов, не знаю, по моему всё верно, захожу по ссылке 
avatar
1. Да, возможность есть

DataSource = CreateDataSource(ClassCode, SecCode, INTERVAL_M1) — подписываемся на источник данных
DataSource:SetUpdateCallback(CallBackDataSource) --назначаем функцию обратного вызова
2. Стандартного интерфейса в квике нет. Нужно писать «прокладку» на С++ для передачи необходимых данных в прогу на С#.

avatar
Karim, есть где-то литература по этому, примеры может посмотреть?
Александр Правилов, Документация по Quik, раздел по QLua.
Просторы инета, например https://quikluacsharp.ru/bez-rubriki/s-chego-nachat/
avatar
Обычно в цикле пишут sleep(n), при обновлении котировок или любых других значений.

Я не клуист, но судя по этой логике, если бы была возможность подписки на событие, так бы и делали, просто вешали бы коллбек на событие. Скорей всего, там котировки получаются по запросу на сервер. То бишь, 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
Не факт что эта фича там есть. Поинтересуйтесь у техподдержки на эту тему
avatar
По первому вопросу, функция обратного вызова OnAllTrade(alltrade), из описания: «Функция вызывается терминалом QUIK при получении обезличенной сделки».
Один нюанс, в quik должна быть открыта таблица обезличенных сделок с необходимым инструментом.
это к примеру, а так есть несколько функций обратного вызова, они описаны в документации
avatar
Не знаю о каких примерах идет речь, но когда я писал роботов на QLua, то для событийной модели обязательный sleep нужен был только в Main(), дабы робот не загружал процессор на 100%, т.к. Main() был совсем крохотным кусочком кода. Также, например, при подписке на свечки, я ставил sleep, т.к. квику требовалось некоторое время на получение данных и их запись в таблицу. Если попытаться проверить наличие данных сразу после подписки, то часто получал nil.
avatar
Для вызова колбэков их необходимо прописывать в main?
Например OnDisconnected(), можно просто отдельно прописать и он вызовется при разрыве соединения или его необходимо указать и в main?
Александр Правилов, не можно, а нужно отдельно.
avatar
Дмитрий, Вот что-то не срабатывает :(
Александр Правилов, попробуйте

function OnDisconnected()
     message('Disconnected')
end

function OnStop(s)
     bStopped = true
end

function main()
     bStopped = false
     while not bStopped do
          sleep(100)
     end
end

avatar
Дмитрий, уже разобрался, всё ок :) 
Вы лучше подскажите всем, когда разберетесь, как определить оптимальный n. Или задать динамический n (если это возможно).

Интересно, поймут ли меня сейчас?

Если очень кратко, то примерно так — примите во внимание наличие в 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 показывал).
Борис Гудылин, вчера как раз читал про потоки :)
Александр Правилов, вопрос 1 у Вас хороший, мало кто им задается. Кажется, я такого и не встречал здесь. 
Борис Гудылин, получать котироку по факту прихода намного важнее нежели перезапускать цикл, особенно когда нужно быстро реагировать 
По пункту 2 Вам сюда: https://github.com/finsight/QUIKSharp
avatar
по второму пункту S#.API и только он) всё остальное чудовые рыдания.
Придётся повозиться с документацией и форумом, т.к. есть не очевидные вещи, с которыми наскоком не разобраться) но если разобраться, даёт неограниченные возможности.
avatar
Павел Валин, есть рекомендации по форумам? Ссылки? или Литература?
Александр Правилов, http://stocksharp.ru/
если что пиши в личку, помогу чем смогу
avatar
Павел Валин, стокшарп вроде через dde сервер делал коннект с квиком… Посмотрю, чего там есть нынче 
Александр Правилов, давно уже через lua коннектор работает) я DDE даж не застал)))
avatar

теги блога Александр Правилов

....все тэги



UPDONW
Новый дизайн