Для чего нужна функция SetUpdateCallback?

Страницы: 1
RSS
Для чего нужна функция SetUpdateCallback?, Работа с данными.
 
10 раз прочитал описание функции SetUpdateCallback в QLUA.chm, но так и не понял для чего она служит? Она буквами чем-то похожа на функцию SetEmptyCallback, но с этой функции примерно понятно, она в паре CreateDataSource позволяет получить данные с биржи за текущий интервал времени. Пример, который дается в QLUA.chm Пример получения времени из свечки: - получение времени какой либо свечки по индексу? Но если переводить английские слова в функции , то значить она должна что то типа - установки обновления обратного вызова, значит она по идее должна добавить вновь появившиеся свечи? Может быть есть еще какой-то пример для этой функции?  
человек (не робот)
 
Для определения в обычном скрипте функции обратного вызова (callback) для обработки события - изменения свечи в источнике данных, который запросили по CreateDataSource.
Ее аналогом в скрипте индикатора является функция  OnCalculate.
 
Цитата
Борис Гудылин написал:
для обработки события - изменения свечи в источнике данных,
Спасибо, значит если я правильно понял, то:
1. SetUpdateCallback - приходят только изменения свечек
2.SetEmptyCallback -приходят 3000 последних свечек и в локальном терминале это пришедшие 3000 свечек - частично меняют те, которые уже были ранее?
А синхронизация свечей в таком случае идет по времени , привязанной к свече или у каждой свечи есть свой сквозной идентификатор ?
человек (не робот)
 
Существенная разница при использовании CreateDataSource в том, что в первом случае все свечи от первой до текущей и изменения к текущей вбрасываются в указанную Вами в SetUpdateCallback программу принудительно и настолько быстро, насколько это может QUIK.
Эта программа выполняется в основном потоке QUIK, там, где QUIK последовательно вызывает все функции обратных вызовов (OnCalculate - это индикаторы, OnStop, OnParam, OnTrade, OnOrder, ... много их).
Преимущество - скорость и возможность предварительной фильтрации и обработки получаемых данных, неудобство - необходима аккуратная передача данных в скрипт(ы) Вашего робота (ов) (main), которые выполняются в отдельных потоках, независимо и параллельно с основным потоком и друг с другом, насколько это возможно.
Номер свечи подается на входе, сначала все свечи истории, начиная с первой, а затем текущая и ее изменения.

Во втором случае Вы более сосредоточены в скрипте робота, у Вас не будет принудительного вброса свечек, но Вам  придется самому периодически обращаться к свечкам, ориентируясь на текущий Size и другие поля таблицы полученного источника.

В обоих случаях к данным уже имеющихся свечек (O,H,L,C,V,T, Size) полученного по CreateDataSource источника можно обращаться по номеру (индексу) свечи от 1 до текущего Size.

Если новичок - советую написать простенький индикатор, вставить в него выдачу (message()) номера получаемой свечи и ее параметров. Прочувствуете суть обратного вызова для SetUpdateCallback.

А нюансов будет много. И альтернатив может быть несколько. Например, кто-то обращается к данным свечей через идентификатор графика, без CreateDataSource.
 
Цитата
Борис Гудылин написал:
А нюансов будет много
Спасибо за ответ, да нюансов много и как-то бы их надо понять, от этого наверно будет зависеть точность полученных данных. Что мне как новичку удалось понять из Вашего ответа:
1. Данные в терминал пользователя поступают в 2 потока, один поток это скоростной, для выполнения функций обратного вызова и SetUpdateCallback  и других функций и 2й поток main(), где работает код пользователя.
2. Данные, которые поступают через Первый поток ( название условное, используется просто для разделения о каком потоке речь), могут быть недоступны для кода пользователя во Втором потоке, этот вывод я сделал из Вашей фразы (неудобство - необходима аккуратная передача данных в скрипт(ы) Вашего робота (ов) (main))- что Вы хотели сказать этой фразой? Для того что бы данные передавать аккуратно, надо понимать что под этим подразумевалось?
3.С номерами свечей я примерно разобрался, если в цикле читать массив/таблицу полученных свечей, то где первый индекс, где последний становится примерно понятно.
Код
...
DS:SetEmptyCallback()
...
k_ind=DS:Size();
for i=1,k_ind do
c_ind=tonumber(string.format("%.2f",tonumber(DS:O(i))*k_lot));    --цена с учетом лота
...
Или что вы имели в виду, что надо разбираться с индексами? Мне показалось, это обычный массив с данными.
4. Мне непонятно, что происходит с данными в терминале пользователя, если я допустим в 10 часов запустил робота для тестирования, он покрутился 10 минут и я его отключил. В результате в моем терминале скопились данные ( я работаю пока с минутным интервалом) 3000 свечей за 2 предыдущих дня и за текущий день до 10.10 включительно. Затем я включаю робота в 12 часов тоже на 10 минут и мне снова приходят данные и они перекрываются с теми данными, которые были получены в 10 часов, то есть новые 2 часа понятно это 120 свечей их не было на время с 10.10 до 12.10 с ними все ясно, а вот остальные свечи они каким образом объединяются с теми, которые были получены в 10 часов?  
человек (не робот)
 
Кажется дошло, что значит не подключаться к серверу и правда, все работает, фантастика. Зачем тогда столько придумано разных программ для анализа кода по историческим данным, если достаточно включать робота для сбора данных и запускать его раз в 2 дня на 5 минут и будут на своем компе подгружаться все данные. С которыми потом можно работать штатными функциями, эх сколько я потерял времени пока разбирался с данными и программами для их анализа, а оказалось в родном Квике все это есть. Спасибо большое за подсказку.
человек (не робот)
 
Imho, Вы не с того начали.

С трудом представляю, как без знания решений проблем работы с разделяемыми ресурсами в мультизадачных средах (не суть важно, задачи, процессы, потоки, ...) в условиях асинхронного поступления данных и событий через интернет, когда нормой считается потеря, дублирование, искажение и опережение ранних данных более поздними, когда разработчики пропускают на пользователя часть своих проблем, когда документация оставляет желать лучшего - как в этих условиях новичку быстро и корректно написать робота. У меня нет претензий к разработчикам, "не стреляйте в пианиста, он играет как умеет". Пока еще можно адаптироваться.

Для начала Вам, как программисту, лучше было бы разобраться хотя бы по минимуму с архитектурой QUIK, после этого с архитектурой Вашего робота, обращая внимание на потоки, в которых будут выполняться его функции.
Какой-то минимум есть в документации (файл "Использование Lua в Рабочем месте QUIK.pdf").

Вы можете попробовать не использовать асинхронные выходы (callback), которые выполняются в специально выделенном так называемом "основном" потоке QUIK, ограничившись только потоками main (тут определенно есть злой умысел, main - можно перевести тоже как "основной"). Будет Ваш робот периодически просыпаться, пробегать по таблицам QUIK и Вашим собственным и принимать какие-то решения.

Захотите большей эффективности и сложности, задействуйте функции обратного вызова (callback'и). Одно дело, если в OnStop Вы просто взведете признак, который при очередном просыпании заметит Ваш поток main. Если в callback'е Вы получите более емкие данные (пока поток main спит по sleep() их может накопиться много) и захотите их накопить и передать роботу в поток main, то посмотрите потокобезопасные функции sinsert и sremove.  Разработчики иногда реагируют на замечания и закрывают очередную дыру в межпоточном взаимодействии, но они все равно остаются и лучше изначально строить робота так, чтобы он не бросал монетку - повезет - не повезет.

Определитесь с вариантом доступа к источнику данных, в частности, будете ли Вы работать только по закрытии текущей свечи или Вам важна ее динамика. Много вариантов есть: можно "монтекарлить" по срезам таблицы текущих торгов (OnParam - last) с риском пропустить экстремум, можно привязаться к графику по идентификатору, можно пропускать через себя все сделки (OnAllTrade), про варианты с CreateDataSource Вы уже знаете. У них у всех есть свои достоинства и недостатки, иногда даже опасности, свои временные характеристики.

Потом стоило бы смотреть на прикладную сторону - на торговые операции, получился бы движок робота. И только потом на его основе  реализовывать собственно Ваши стратегии.

На многие вопросы Вам придется отвечать самому, пишите и выполняйте Ваши программы, не бойтесь использовать отладочные выдачи по message или в файл, скорость отладки в LUA очень велика.  
Если Вы исследователь, то пробьетесь.

   
 
Цитата
Борис Гудылин написал:
С трудом представляю, как без знания решений проблем работы с разделяемыми ресурсами в мультизадачных средах
Я думаю, что не боги горшки обжигают, спасибо огромное Вам за помощь, мне очень повезло, что попал на Вас. С мультипоточностью действительно не очень хорошо знаком. По этому пока для себя решил писать простой код миниробота в основном потоке main(), использовать только простые заявки продажа/покупка по рыночной цене, они мне кажется должны срабатывать проще и быстрее и вне общей очереди (со сложными заявками, стоп-лосс, тейк-профит и тд и тп) Работать пока по одному интервалу, по минутному. Всю математику по входу в тренд (по критериям), и выход (аналогично) вложить в самого робота. Для критериев взял пока самый простой индикатор 2МА, с задержкой в процентах от нижней и верхней точки. Индикаторы считаю тоже сам на каждый индекс основного цикла свечей. Цену беру по открытию. Для просмотра всех бумаг ( пока для отладки и анализа пишу дополнительно свой "лог"), на один проход по всем бумагам уходит 3 секунды. Так что мини робот, с задержкой в 57 секунд, смотрит каждую новую минутную свечу. Проверку транзакции делаю по таблице сделок. Пока остановился на таком -самом простом мини роботе, правильный со сложными заявками мне пока не осилить, с чего-то же надо начать. А параллельно буду разбираться дальше со сложными заявками и калбасками...

Цитата
Если в callback'е Вы получите более емкие данные (пока поток main спит по sleep() их может накопиться много) и захотите их накопить и передать роботу в поток main, то посмотрите потокобезопасные функции sinsert и sremove.
вот этого у меня кажется нет, так как единственная функция считывания данных находится прямо в main()
Код
DS = CreateDataSource("TQBR", sins, INTERVAL_M1)
if DS:Size() == 0 then 
  DS:SetEmptyCallback()
  sleep(200)
end
 k_ind=DS:Size();
Надо ли в таком случае данный из одного потока DS:SetEmptyCallback() передавать данные в main()? или они уже там сами будут?, а про функции  sinsert и sremove сейчас почитаю, спасибо.
(в этом алгоритме начальной работы простого мини-робота мне не хватает примитивных графиков, которые бы программно строились по моим расчетам, всего 3 кривых, цена открытия, и 2ЕМА., буду думать как это сделать в автоматическом режиме)
человек (не робот)
 
Вполне возможно, что Вам не хватит возможностей скрипта main и придется задействовать callback'и.

Термин "поток" я использую для обозначения архитектурной единицы ОС Windows, которая претендует на время процессора и другие ресурсы и может выполняться параллельно с аналогичными единицами. При определенных условиях они могут "подраться" за некоторые Ваши таблицы, которые Вы захотите ввести и обрабатывать (модифицировать) сразу в двух потоках. Для предотвращения таких коллизий (организация последовательного доступа) и были введены функции sinsert и sremove  (там еще несколько подобных по назначению есть, посмотрите).    
Не повезло QUIKу, многие термины перегружены разными смысловыми нагрузками, а некоторые объекты обзываются по-разному, это мешает.

В Вашем примере вы неявно находитесь в рамках потока main скрипта и имеете непосредственный доступ к данным источника, без задействования функций обратного вызова (те, что выполняются в основном ;) потоке).  

Зачем роботу графики - я не понимаю, Вы же сами все расчеты должны делать и чувствовать, где находятся Ваши кривые на текущий момент (втемную). Для визуализации или отладки можно использовать штатные графики QUIK и штатные МАшки, если Ваши с ними совпадают по алгоритмам. Если не совпадают - напишите для них свои индикаторы, это просто, и поместите их на нужные графики.

Для отслеживания и визуализации состояния робота постройте таблицу и отображайте ее средствами QUIK.    
 
Цитата
Борис Гудылин написал:
Зачем роботу графики - я не понимаю, Вы же сами все расчеты должны делать и чувствовать, где находятся Ваши кривые на текущий момент (втемную).
Да, Вы правильно поняли идею, расчет ведется в темную, но проверить визуально свою теорию на чем то нужно, причем удобнее это сделать оперативно, в реальном режиме времени, а не по историческим данным.Графики мне нужны не для миниробота, а для себя, просто что бы меньше тратить времени на проверки. Пока склоняюсь к записи данных в текстовый файл, с флагом в конце файла, что можно строить график. А сам график строить какой нибудь другой программой, более менее знакомой, пока больше склоняюсь к двум вариантам или php или LabView. Php имеет смысл использовать что бы убить двух зайцев и отправку смс по завершившейся сделке и график. LabView очень удобна для построения графиков, там есть встроенное масштабирование.

Цитата
Для визуализации или отладки можно использовать штатные графики QUIK и штатные МАшки
Штатные конечно надо будет использовать, но для других целей, для сверки своих расчетов в темную, с реальными ( это можно делать наверно позднее по историческим данным).
Цитата
Термин "поток" я использую для обозначения архитектурной единицы ОС Windows, которая претендует на время процессора и другие ресурсы и может выполняться параллельно с аналогичными единицами.
В потоках я не силен, но на своем практическом опыте ( когда тестировал, по работе, передачу управляющих сигналов через сом порт, задержка была примерно около 20 мс в среднем), а у меня для ожидания новой свечи остается 57 сек , поэтому думаю задержка потоков в системе виндовс помехой для мини робота не будет. А за синхронизацией своих потоков Windows следит сама.
Вывод:  теоретически мини робот работать может. Хотя минус его конечно очевиден , он не сможет работать со сложными заявками (связанные заявки, стоп-лосс, тейк профит и тд) и конечно будет таким роботам уступать в производительности, поэтому я не претендую на нем на большую прибыль, но пусть для начала она будет хоть в плюсе, а не в минусе и то уже приятно. Если успею, то запущу в свободное плаванье на демо счете в понедельник.



#s3gt_translate_tooltip_mini { display: none !important; }
человек (не робот)
 
Цитата
Андрей написал:
А сам график строить какой нибудь другой программой, более менее знакомой, пока больше склоняюсь к двум вариантам или php или LabView.
https://www.youtube.com/watch?v=5-QcZbKl7JE&t=9s
 
Спасибо большое, интересная программа.  :smile:
человек (не робот)
 
http://www.qcustomplot.com/index.php/demos/financialchartsdemo
 
Борис Гудылин, добрый день.
Цитата
Борис Гудылин написал:
Много вариантов есть: можно "монтекарлить" по срезам таблицы текущих торгов (OnParam - last) с риском пропустить экстремум, можно привязаться к графику по идентификатору, можно пропускать через себя все сделки (OnAllTrade), про варианты с CreateDataSource Вы уже знаете. У них у всех есть свои достоинства и недостатки, иногда даже опасности, свои временные характеристики.
Что посоветуете для отслеживания экстремума с минимальной загрузкой скрипта и терминала (скорость не нужна - заявки выставляются ранее, а вот само значение минимума/максимума принципиально для расчетов)? Думала пользоваться именно таблицей текущих торгов, и тут ваше сообщение... Все тики перелопачивать не хотелось бы, а большая свеча может захватить оба экстремума... Эх. Мозг заболел.
 
Цитата
Ирина написал:
Что посоветуете для отслеживания экстремума с минимальной загрузкой скрипта и терминала (скорость не нужна - заявки выставляются ранее, а вот само значение минимума/максимума принципиально для расчетов)? Думала пользоваться именно таблицей текущих торгов, и тут ваше сообщение... Все тики перелопачивать не хотелось бы, а большая свеча может захватить оба экстремума... Эх. Мозг заболел.
Если нужны минимумы и максимумы за текущую торговую сессию, то их можно получить прямо из таблицы текущих торгов через параметры "LOW" и "HIGH". Примерно таким скриптом:
Код
local fRun = true

function OnParam(class_code, sec_code)
    if class_code =="SPBFUT" and sec_code == "SiM8" then
        local low  = getParamEx(class_code, sec_code, "LOW")
        local high = getParamEx(class_code, sec_code, "HIGH")
        if low.result == "1" and high.result == "1" then
            message("low.param_value\t= "..low.param_value.."\nhigh.param_value\t= "..high.param_value)
        end
    end
end

function main()
    while fRun do
        sleep(1000)
    end
end

function OnStop(s)
    fRun = false
end
А вот если нужны минимумы и максимумы за другие периоды внутри торговой сессии или между ними, то тут придётся уже мутить более сложный код с перебором всех значений по таблице всех сделок или по свечкам и пр.
 
Suntor, спасибо большое за хитрое решение - наверняка пригодится.
Но мне да, нужны последние экстремумы, причем период переборки неопределенный (типа трала). Думала, просто запоминать последний максимум/минимум и сравнивать с текущей ценой. А тут вон засада с пропущенными значениями. Придется перебирать. Теперь думаю что "легче" по загрузке, таблица обезличенных сделок что ли? Или всё-таки прибегнуть к колбэкам для меньшего кол-ва итераций. Боюсь я их - повесят квик.
 
Цитата
Ирина написал:
Теперь думаю что "легче" по загрузке, таблица обезличенных сделок что ли? Или всё-таки прибегнуть к колбэкам для меньшего кол-ва итераций. Боюсь я их - повесят квик.
Наверно зависит от того, с чем изначально вы работаете. Если вы работаете на свечках, то свечки и перебирать. А если на тиках, то таблицу обезличенных сделок. Оно просто по коду скрипта так будет получаться удобнее...

«Колбэки» нормально будут работать. Нахождение минимума и максимума простые мат. операции, просто два сравнения и присвоения, их прямо вовнутрь тела ф-ции OnAllTrade поместить и всё нормально будет.
 
Цитата
Ирина написал:
причем период переборки неопределенный (типа трала)
Если это что-то типа скользящего окна... то-есть, экстремум за последние 100 минут скажем... то тут проще всего эти самые 100 минутных свечек и перебирать, причём полностью их перебирать только когда меняется номер последней свечи... когда же сама последняя свеча меняется, то сравнивать только с её минимумами и максимумами... в таком варианте полный перебор будет только раз в минуту...
 
Suntor, спасибо за объяснения, помогаете сориентироваться.

Код только начинаю писать, поэтому показать нечего. Пришла к следующему алгоритму:
При первом запуске скрипта,он перебирает последние тики/цены сделок до нахождения значений "текущая цена"+ х пунктов и "текущая цена"- х пунктов. Проверяет какое из значений было последним и присваивает соответственно 0 и 1 переменным "тренд вверх" и "тренд вниз", перебирает тики после значения "текущая цена" +/- х пунктов, находит и присваивает переменным "минимум", "максимум" значение или nil. Это только при запуске. Дальнейшее определение "тренда" и экстремума получается сравнением цены с его предыдущим значением.
С учетом упорядоченности цен в таблице и растущей индексации от старого к новому тику,
получается, что при получении каждого изменения, перебирать вообще не нужно. Или рациональнее для загрузки получать новые данные порциями и перебирать, зато реже обращаться к терминалу?
При наступлении события "текущая цена" -/+ х пунктов >/< мин./макс. меняется тренд и скрипт перетряхивает заявки, стоп-заявки. Они находятся на удалении от текущей цены, сильные движения редки (и вообще скрипт пишу в помощь рукам), поэтому опоздать с сигналом нестрашно. Но опять же вопрос, а нужна ли эта жертва или
получение каждого тика/сделки не больше грузит терминал, процесс?
Ещё скрипт снимает лимитки по ходу движения, ориентируясь на цену. В остальном, т.е. при работе с заявками оперирует таблицами заявок и стоп-заявок. Вот. И с
Цитата
Suntor написал:
с чем изначально вы работаете.
?
С чем ему работать? Откуда тут лучше брать цену, со свечь, тиков, тлиц обезличеннх селок?  
 
Случайно отправила недоделанное сообщение. Как тут редактировать?
 
В общем, если бреда много, прошу простить, с Луа на этапе знакомства.
 
Цитата
Ирина написал:
Пришла к следующему алгоритму:
Лучше напишите первую версию, если сразу не получится, сюда код киньте, мы посмотрим... так по словесному описанию сложно оценить алгоритм, тем более что при реализации он скорее всего изменится.
Цитата
Ирина написал:
С учетом упорядоченности цен в таблице и растущей индексации от старого к новому тику,
получается, что при получении каждого изменения, перебирать вообще не нужно.
Если у вас начало вашего диапазона не меняется, то тогда полный перебор не нужен. А если начало сдвигается, то нужен.
 
Цитата
Suntor написал:
Лучше напишите первую версию
Почти написала и вернулась к обсуждавшемуся вопросу. Сейчас всё в main. Думаю задействовать OnAllTrade, но не вижу в нём смысла. Прошу развеять сомнения и поправить, если неправильно понимаю принцип работы.

Схема кода такая:
Код
first=getNumberOf("all_trades")

function main()
while true do

if first == getNumberOf("all_trades") then
   sleep(1000)
else

for k=first,getNumberOf("all_trades")-1 do
   local trade = getItem("all_trades", k)
   if trade then
      
      получение сигнала - выставление и снятие заявок;
                     присвоение новых значений переменным
                     
   end
   first = k+1
end

for i=0,getNumberOf("orders")-1 do

   снятие лишних заявок "на ходу" 

end

end
end
end
Торгую si, т.е. сотни сделок в секунду случаются.

Допустим, задействовала я OnAllTrade. Посылает он сигнал main-у, а тот в это время находится где-нить в середине цикла. Что с ним будет?
Допустим, ничего. Тогда что будет с пропущенным сигналом OnAllTrade, потеряется?
Допустим, нет. Тогда за время проведения main-ом своих расчетов накопится много сигналов OnAllTrade. Что будет с ними? Будут обрабатываться в порядке очереди?
Ну и какой смысл в этом колбэке, если нет реакции на каждый тик? А main итак проверяет все новые тики.
 
Цитата
Ирина написал:
Прошу развеять сомнения и поправить, если неправильно понимаю принцип работы.
Для начала, посмотрите пример из документации по QLua (https://arqatech.com/upload/iblock/194/quik_lua.zip)
В файле Использование Lua в Рабочем месте QUIK.pdf в главе 2. Взаимодействие потоков Lua скрипта пример с разбором, как сделать очередь событий от ф-ций обратного вызова и обработать её в main().
Цитата
Ирина написал:
Схема кода такая:
Если долго разглядывать ваш код, то можно познать дзен... шутка... )))
В принципе, если скрипт неторопливый и перерасчитывается раз в секунду, то наверно можно и так сделать как вы. Только обработчик OnStop добавьте и переменную для прерывания цикла в main().
Цитата
Ирина написал:
Ну и какой смысл в этом колбэке, если нет реакции на каждый тик? А main итак проверяет все новые тики.
«Колбэки» нужны, когда вам нужна максимальная скорость реакции на события. Если такой задачи не стоит, то можно и без них обойтись в целом.
 
Цитата
Ирина написал:
Ну и какой смысл в этом колбэке, если нет реакции на каждый тик?
тогда подумайте о том, что тики, пришедшие с биржи, попали к Вам не мгновенно в момент совершения сделки, а через время совершения события в ядре биржи, обработки в очередь на выдачу в буфере выходного потока ядра биржи, затем в буфер входного потока сервера АРКА, затем некая обработка на сервере АРКА, затем в буфер выходного потока с сервера, затем в буфер терминала для обработки в клиенте КВИК и вот уже это вы обрабатываете своим скриптом.
количество и скорость событий не являются ни линейными, ни предопределенными на всех этапах. так стоит ли переживать за такие мелочи? понимайте свой временной горизонт и перебирайте сделки по мере обработки и попадания в Ваши алчные алгоритмы :)
 
Цитата
Suntor написал:
2. Взаимодействие потоков Lua скрипта
Спасибо, такой разбор и искала. Стало понятно, что без очереди ничего не понятно...
Однако тут пишут, что функции insert/remove сами по себе тормозные... И, в моем случае, очередь ещё и неудобна - дублируются переборы вторичных таблиц, где скорость вообще не нужна. А вот ввернуть сам факт появления новой сделки вместо  
Код
if first == getNumberOf("all_trades") then
   sleep(1000)
было бы полезно. Но так и не поняла, собьется поток main при поступлении нового колбэка, без его постановки в очередь, или проигнорирует его (что нестрашно)...
 
Цитата
rinat написал:
так стоит ли переживать за такие мелочи?
А зачем себя в хвост загонять, если разница в буквах кода? (Конкуренты в лице таких же юзеров QUIKа не в счет что ли и ликвидности не добавляют?)
 
Цитата
Ирина написал:
собьется поток main при поступлении нового колбэка?
Например, при таком использовании:
Код
is_run = true
first=getNumberOf("all_trades")

function OnAllTrade(all_trade)
   start = true
end

function main()
   while is_run = true do

      if start = true then
      
         for k=first,getNumberOf("all_trades")-1 do
            first = k+1
         end
      
      end
      start = false

   end
end

function OnStop()
   is_run = false
end
 
Цитата
Suntor написал:
«Колбэки» нужны, когда вам нужна максимальная скорость реакции на события.
В примере с колбэками из "Использование Lua в Рабочем месте QUIK" в main непрерывно проверяется размер таблицы Lua. А без колбэка мог бы также проверяться размер таблицы обезличенных сделок или иной. Чем хуже?
 
Цитата
Ирина написал:
Цитата
Ирина   написал:
собьется поток main при поступлении нового колбэка?
Например, при таком использовании:
Код
       if  start  =   true   then 
      
       end 
      start  =   false  
Сразу прокомментирую две ошибки новичка классических. В условии стоит оператор присвоения «=», а не оператор сравнения «==». В Lua такой код отсекается при компиляторе, но в том же Си/Си++ нужно быть внимательным. И сброс переменной условия происходит вне инструкции проверки, а не внутри неё. То-есть, присвоение start = false должно стоять внутри блока условия. Даже, если это не повлияет численно на алгоритм, это стилистическая и логическая ошибка компоновки... это всё несущественно, просто глаз режет...

По самому коду. В принципе, будет работать и так. Если сильно не придираться. Но если уж писать в рамках этой идеи, то надо бы булеву переменную start заменить на счётчик новых сделок. Который инкрементировать в OnAllTrade, и декрементировать в main. В этом случае, это уже будет выглядеть законченным кодом. И в этом случае, можно даже избавиться от вызова getNumberOf.

Я бы вообще написал вот так, с использованием двух переменных начала и конца. Код компилируется и запускается, но проверить на идущей торговой сессии не могу, так как сегодня праздничный неторговый день.
Код
local fRun = true

local first = getNumberOf("all_trades")-1
local last = first

function OnAllTrade(alltrade)
    last = last+1
end

function main()
    while fRun do
        while first ~= last do
            first = first+1
            local alltrade = getItem("all_trades", first)
            if alltrade then
                message("Новая сделка № "..tostring(alltrade.trade_num))
            end
        end
        sleep(1000)
    end
end

function OnStop(s)
    fRun = false
end
В любом случае, у такого кода, одновременно работающего с OnAllTrade и с таблицей all_trades одна проблема. Это рассинхронизация состояния таблицы all_trades. То-есть, если запустить Quik и скрипт в середине торгового дня, то таблица all_trades будет содержать старые сделки за предыдущую торговую сессию. И параметр first будет инициализирован по размеру этих данных. Потом Quik сбросит всю таблицу all_trades в ноль, и начнёт закачку данных за текущую торговую сессию, что займёт несколько минут. Всё это время будут сыпаться OnAllTrade по получаемым сделкам, а в main цикл выборки из таблицы all_trades будет пытаться получить данные по уже несуществующим индексам. Поэтому, такой код можно запускать только дождавшись полной загрузки всей all_trades таблицы за текущую торговую сессию. Можно смотреть в таблицу всех сделок, и когда она полностью загрузится, уже тогда запускать скрипт. То-есть, это отдельная проблема. Она частично решается если работать со своей очередью куда складывать OnAllTrade, но даже в этом случае, тоже нужно отсекать загрузку старых данных за текущую торговую сессию при первом запуске Quik.
 
Цитата
Ирина написал:
В примере с колбэками из "Использование Lua в Рабочем месте QUIK" в main непрерывно проверяется размер таблицы Lua. А без колбэка мог бы также проверяться размер таблицы обезличенных сделок или иной. Чем хуже?
Тут вопрос не в том, хуже или нет. А в том, что код по другому структурирован. Можно в свою таблицу складывать события, а можно из системной их потом вылавливать. Тут есть свои плюсы и минусы. В том числе и с рассинхроном. См. мой пример в пред. сообщении.
 
Цитата
Suntor написал:
это всё несущественно, просто глаз режет...
На вылавливание таких косячков больше всего времени уходит, так что большое спасибо!

Код у Вас очень гармоничный получился.
Смущает sleep(1000). Раз после цикла стоит, он будет прерываться при поступлении нового колбэка?

Цитата
Suntor написал:
рассинхронизация состояния таблицы all_trades
Не обращала внимания, что происходит с таблицами в вечерний клиринг... спасибо за акцент. Ну буду руками подстраховывать, если что (всё равно скрипт только пол алгоритма выполняет), а вечерняя сессия ещё и вялая обычно - не страшно.

Вообще, уважаемый Suntor, благодарю за помощь в написании моего маленького скрипта! Вашими усилиями он почти готов. :)))
 
Цитата
Ирина написал:
Смущает sleep(1000). Раз после цикла стоит, он будет прерываться при поступлении нового колбэка?
Этот sleep относится к циклу fRun и нужен для того, чтобы скрипт не завис на бесконечном цикле. В этом случае его невозможно будет остановить кнопкой «Остановить» из окна скриптов. Да и весь Quik при этом также зависнит. Его можно ставить меньше по длительности или больше в зависимости от того, что вы в main делаете. Но он там должен быть обязательно.

На «колбэки» содержание кода в main никак не влияет, так как они исполняются в другом потоке.

Цитата
Ирина написал:
Не обращала внимания, что происходит с таблицами в вечерний клиринг...
а вечерняя сессия ещё и вялая обычно - не страшно.
На акциях, где нет «вечерки», тоже самое... это не про то речь. Quik если запустить через несколько дней, то он со старыми данными загрузится, они все в таблицах видны. А когда залогинетесь на сервер, то увидите, что все таблицы сбрасываются, а потом загружаются новыми последними данными. Вот в этом месте будет рассинхрон в работе скриптов. Нужно либо это в коде учитывать, либо ручками следить. Вообще, после некоторой практики приспособитесь к этому. В Quik'е вообще много похожих вещей, за которыми нужно либо самому следить, либо писать нетривиальный код их автоматизации.
Цитата
Ирина написал:
Вообще, уважаемый  Suntor  , благодарю за помощь в написании моего маленького скрипта! Вашими усилиями он почти готов. :)))
Да не за что... )))
 
Цитата
Suntor написал:
Этот sleep ... там должен быть обязательно.
Ну и какой тогда толк от "колбэка"? Что без него main спал и пропускал сигнал, что с ним спит, только ещё и основной поток грузится... Кстати, в примере из "Использование Lua в Рабочем месте QUIK" в main нет sleep. Ошибка? (Я поэтому и хотела "колбэк" применить).

Сдается мне, что не main-ом надо "колбэки" обрабатывать, а "колбэками" main, - только так их скорость будет использована.
 
Цитата
Ирина написал:
Цитата
Suntor   написал:
Этот sleep ... там должен быть обязательно.
Ну и какой тогда толк от "колбэка"?
sleep в main и «колбэки» никак напрямую не связаны... разные вещи. sleep в main нужен для того, чтобы этот самый main не повесил весь Quik с концами...
Цитата
Ирина написал:
Что без него main спал и пропускал сигнал, что с ним спит, только ещё и основной поток грузится...
main ничего не пропускает, а лишь реагирует с задержкой. И так он и должен работать, потому что ваш код изначально строится по схеме «опроса». И «колбэки» вы в эту схему засунули, чтобы лишний раз не дёргать getNumberOf, а я лишь довёл вашу эту схему до совершенства, грубо говоря, и вообще избавился от getNumberOf... Важно то, что вы строите ваш код по принципу опроса системной таблицы all_trades. Можно опрашивать её в main дёргая getNumberOf, сохраняя и сравнивая размер каждый раз, можно через булев флаг выставленный из «колбека» о том что таблица изменилась, а можно подсчётом событий «колбэков» насколько она изменилась, как в моём примере. В любом случае, этот код по схеме «опроса» будет работать с задержкой sleep в потоке main, и в любом случае эта задержка там необходима, иначе всё повиснет.
Цитата
Ирина написал:
Кстати, в примере из "Использование Lua в Рабочем месте QUIK" в main нет sleep. Ошибка?
Он там есть, только спрятан в нижестоящую ф-цию ProcessingCallback... и это пример кода. Если в этом месте менять на свои реальные вычисления, то этот sleep нужно будет передвинуть выше в main. Можете все остальные примеры с первой и до последней страницы пересмотреть в этом документе, там везде в каждом main стоит sleep.
Цитата
Ирина написал:
Сдается мне, что не main-ом надо "колбэки" обрабатывать, а "колбэками" main, - только так их скорость будет использована.
Ваше заблуждение лишь оттого, что вы через «колбэки» пытаетесь сделать код по схеме «опроса», где эти «колбэки» то и не нужны. Они нужны совсем для другого, кода вы строите код по схеме обратного вызова. То-есть, вместо цикла со sleep внутри main, где вы периодично опрашиваете таблицу, нужно поместить код в «колбэки», и он сам будет вызываться и именно в тот момент, когда наступит событие. А не тогда, когда цикл main после sleep наконец проснётся и обнаружит, что пока он спал, таблица all_trades приросла новыми данными. «Колбэки» срабатывают в тот момент, когда по сети информация приходит в Quik. Счёт идёт на миллисекунды... «Колбэки» это более мощное средство, и с его помощью можно имитировать схему «опроса», а вот наоборот уже не получится.
 
Цитата
Suntor написал:
вы через «колбэки» пытаетесь сделать код по схеме «опроса», где эти «колбэки» то и не нужны. Они нужны совсем для другого, кода вы строите код по схеме обратного вызова.
Я о том и говорю. И абсолютно не нужна мне схема "опроса". Просто подозреваю, что если засунуть весь код в "колбэк", терминал атрофируется из-за 100% занятого основного потока, да и "колбэки" не будут успевать обрабатываться. Что похлеще отстающей схемы "опроса" будет.
Немного понятнее стало.
Попробую ловить сигнал дважды: в "колбэк" с выполнением минимума (хотя самое тормозное - транзакции - всё равно из него придется отправлять) + дублирующим "опросом" в мейне с выполнением несрочных операций...
 
Все "глобальные" функции, кот. вызывает "колбэк", тоже выполняются в основном потоке терминала?
Код
function OnAllTrade(price)
   if price >= min_price+X then
      OpenOrders()
      ...
   end
end

function OpenOrders()
   ...
end
 
Цитата
Ирина написал:
И абсолютно не нужна мне схема "опроса". Просто подозреваю, что если засунуть весь код в "колбэк", терминал атрофируется из-за 100% занятого основного потока, да и "колбэки" не будут успевать обрабатываться.
В этом сложность разработки алгоритма. Вы должны рассчитать, насколько ваш код тяжёлый и можно ли его поделить на ту часть, которая быстрая и которую можно поместить в «колбэк», и на ту часть, которая медленная и которую нужно поместить в main, а ещё дополнительно выделить ту часть, которая совсем тяжёлая и вынести её вообще в отдельную DLL, либо вообще в отдельный процесс... это всё отдельная задача проектирования, которую нужно решать и понимать конечную цель всех решений архитектурных.

В документации по Lua дают наиболее общую схему с очередью событий из «колбеков» и обработкой её в main, которая медленная, но не вешает Quik, и поэтому подойдёт большинству начинающих роботописателей. Поэтому она и даётся как пример.

Цитата
Ирина написал:
Все "глобальные" функции, кот. вызывает "колбэк", тоже выполняются в основном потоке терминала?
Да.
Страницы: 1
Читают тему
Наверх