Извечный вопрос: повторные вызовы OnTrade, Даже при заявке на одну акцию
Пользователь
Сообщений: Регистрация: 26.11.2025
06.01.2026 22:52:46
Создаю заявку из lua-скрипта на покупку ровно одной акции. Т.е. никаких финтов с частичным исполнением не может быть. При исполнении происходят два вызова функции OnTrade. Сделал полную распечатку всей таблицы от обоих вызовов. Отличие только в трёх полях: uid, on_behalf_of_uid, trans_id. При первом вызове все три нулевые, при втором все три - ненулевые.
Вопросы следующие: 1. Гарантируется ли, что вызов OnTrade, в котором эти поля нулевые, является не последним, т.е. я могу его игнорировать, т.к. после него будет следующий? 2. Гарантируется ли, что вызов, в котором эти поля ненулевые, является последним? 3. Являются ли эти три поля синхронными всегда? (Т.е. либо все три равны 0, либо все три не равны 0?) Т.е. можно ли проверять только одно из них, а не все три вместе?
Пользователь
Сообщений: Регистрация: 02.01.2026
06.01.2026 23:45:30
Цитата
User12501 написал: Гарантируется ли, что вызов OnTrade, в котором эти поля нулевые, является не последним
Нет. trans_id и uid в некоторых ситуациях могут иметь и нулевые значения.
Пользователь
Сообщений: Регистрация: 02.01.2026
06.01.2026 23:46:33
Цитата
User12501 написал: Являются ли эти три поля синхронными всегда? (Т.е. либо все три равны 0, либо все три не равны 0?)
Нет
Пользователь
Сообщений: Регистрация: 30.01.2015
07.01.2026 06:33:14
Цитата
User12501 написал: Создаю заявку из lua-скрипта на покупку ровно одной акции. Т.е. никаких финтов с частичным исполнением не может быть. При исполнении происходят два вызова функции OnTrade. Сделал полную распечатку всей таблицы от обоих вызовов. Отличие только в трёх полях: uid, on_behalf_of_uid, trans_id. При первом вызове все три нулевые, при втором все три - ненулевые.
Вопросы следующие: 1. Гарантируется ли, что вызов OnTrade, в котором эти поля нулевые, является не последним, т.е. я могу его игнорировать, т.к. после него будет следующий? 2. Гарантируется ли, что вызов, в котором эти поля ненулевые, является последним? 3. Являются ли эти три поля синхронными всегда? (Т.е. либо все три равны 0, либо все три не равны 0?) Т.е. можно ли проверять только одно из них, а не все три вместе?
Если заявка, по которой пройдет сделка выставлена не скриптом Lua, то trans_id будет нулевой . ------------------------------------------- Должны быть не нулевые , так как определяют клиента на сервере брокера. ----------------------------- Полагаю , что первый раз приходит с биржи, второй - с сервера брокера.
Пользователь
Сообщений: Регистрация: 30.01.2015
07.01.2026 06:33:49
Два других должны быть не нулевые , так как определяют клиента на сервере брокера.
Пользователь
Сообщений: Регистрация: 26.11.2025
09.01.2026 12:24:50
Опять отловил два повторных OnTrade, на этот раз совпадали все поля кроме broker_comission и broker_comission_currency (в первом они были 0 и пусто, во втором правильные). Можно ли как-то конкретно определить полный набор полей, которые я должен проверить, чтобы уверенно знать, что данный вызов OnTrade является последним по данной заявке? Речь только про заявки из скрипта qlua, строго на один лот.
Пользователь
Сообщений: Регистрация: 27.01.2017
09.01.2026 12:37:49
Цитата
User12501 написал: Опять отловил два повторных OnTrade, на этот раз совпадали все поля кроме broker_comission и broker_comission_currency (в первом они были 0 и пусто, во втором правильные). Можно ли как-то конкретно определить полный набор полей, которые я должен проверить, чтобы уверенно знать, что данный вызов OnTrade является последним по данной заявке? Речь только про заявки из скрипта qlua, строго на один лот.
Нельзя ответить на этот вопрос. Например, если поля broker_comission и broker_comission_currency не важны, то этот второй вызов бесполезен, а если важны, то уже нет. Хотя, если говорить о комиссиях брокера, то они их может не транслировать вовсе и можно ждать вечно.
Т.е. все зависит от того, что необходимо. Явно поля количества и суммы важны, и, наверно, brokerref. Остальное уже решать Вам.
В системах с повторяющимися сигналами принято обновлять ранее поступившие данные. Пришли первоначальные данные - записали их с неким ключом. Пришли повторно обновили их и вызвали метод обновления зависимых данных. Т.е. если строить систему на простейшем принципе однократного учета, то будут проблемы. А если обновлять и пересчитывать, то уже нет. Хотя, конечно, обновление данных - это более сложная реализация. Иногда настолько, что проще не делать.
Пользователь
Сообщений: Регистрация: 26.11.2025
09.01.2026 13:21:00
Цитата
Nikolay написал: Например, если поля broker_comission и broker_comission_currency не важны, то этот второй вызов бесполезен, а если важны, то уже нет.
Речь о том, как проигнорировать бесполезный вызов и не посчитать дважды то, что нужно? Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают (спрашивал об этом вот здесь: ). Значит нужно вводить отдельную переменную - количество акций, и при каждом OnTrade обновлять. Но тогда при повторном OnTrade происходит повторное обновление, и пожалуйста - ошибка.
Речь о том, как проигнорировать бесполезный вызов и не посчитать дважды то, что нужно? Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают (спрашивал об этом вот здесь: ). Значит нужно вводить отдельную переменную - количество акций, и при каждом OnTrade обновлять. Но тогда при повторном OnTrade происходит повторное обновление, и пожалуйста - ошибка.
Ошибка т.к. обработка наивная:
pos = pos + sign*traded.qty
Естественно при таком подходе повторный вызов даст искажение данных. А если обработка более сложная, то не будет ошибки. Это уже вопрос реализации, зависящий от конкретной задачи.
Пользователь
Сообщений: Регистрация: 15.06.2023
09.01.2026 14:25:26
Цитата
User12501 написал: Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают
Вы подняли очень важный вопрос. Он касается широкого круга пользователей, и широко обсуждался на форуме и приводились различные боевые подходы. На Ваш вопрос выше, ответ нужно организовывать внутренний учет, не только количества но и других параметров зависящих от конкретной сделки сделки (допустим усреднялись). Вот пример подхода которым, часто пользуюсь на скоростных скриптах:
Код
function OnTrade(trade)
if not WORKING_FLAG then return end
local key = trade.trans_id
local i = tonumber(sdelka[0]);
if working
and key and key>0
and (i==0 and key~=sdelka.id) or (i>0 and sdelka[i][1]~=key)
--and trade.sec_code==symbol --and trade.class_code==class
then
i=i+1;
sdelka[0]=i;
sdelka[i]={};
sdelka[i][0]=sdelka[0];
sdelka[i][1]=trade.trans_id;
sdelka[i][2]=get_date(trade.datetime)
sdelka[i][3]=get_time(trade.datetime)
sdelka[i][4]="B"; if bit.band(trade.flags,4)~=0 then sdelka[i][4]="S"; end;
local dir = sdelka[i][4]=="B" and 1 or sdelka[i][4]=="S" and -1 or 0;
sdelka[i][5]=trade.qty*dir;
sdelka[i][6]=trade.price;
----- comission
sdelka[i][7]=trade.clearing_comission+trade.exchange_comission+trade.tech_center_comission;
sdelka[i][8]=trade.order_num;
sdelka[i][9]=trade.trade_num;
sdelka[i][10]=trade.sec_code;
sdelka.id=trade.trans_id;
Log:info("OnTrade! sdelka "..i .."; "
.."; trans_id="..sdelka[i][1]
.."; "..sdelka[i][2]
.."; "..sdelka[i][3]
.."; "..sdelka[i][4]
.."; "..sdelka[i][5]
.."; "..sdelka[i][6]
.."; comission="..sdelka[i][7]
.."; onum="..sdelka[i][8]
.."; tnum="..sdelka[i][9]
.."; "..sdelka[i][10]
.."\n"
);
--local a,v; for a,v in pairs(sdelka[i) do Log:trace( 'OnTrade! sdelka['..i..']['..tostring(a)..'] = '.. tostring(v) ) end;
end
end;
написал: Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают
Вы подняли очень важный вопрос. Он касается широкого круга пользователей, и широко обсуждался на форуме и приводились различные боевые подходы. На Ваш вопрос выше, ответ нужно организовывать внутренний учет, не только количества но и других параметров зависящих от конкретной сделки сделки (допустим усреднялись). Вот пример подхода которым, часто пользуюсь на скоростных скриптах:
Код
Спасибо. Принцип такого костыля понятен, но очень надеялся, что можно как-то проще. Видимо нельзя.
Пользователь
Сообщений: Регистрация: 15.06.2023
09.01.2026 15:29:03
User12501, И это еще не вся проблематика, ведь нужно данные периодически синхронизировать с данными QUIK.
написал: Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают
Вы подняли очень важный вопрос. Он касается широкого круга пользователей, и широко обсуждался на форуме и приводились различные боевые подходы. На Ваш вопрос выше, ответ нужно организовывать внутренний учет, не только количества но и других параметров зависящих от конкретной сделки сделки (допустим усреднялись). Вот пример подхода которым, часто пользуюсь на скоростных скриптах:
Кстати раз уж вы выложили код, есть вопрос по вот этой строке. Сейчас проверил в тех сделках, которые у себя отлавливал: там есть поле broker_comission, которое я воспринимал как итоговую сумму всех комиссий. И оно больше, чем написанная вами сумма. Например для одного лота MOEX: tech_center_comission = 0 clearing_comission = 0.22 exchange_comission = 0.3 broker_comission = 1.57
Проверка по остатку на счёте показывает, что 1.57 - точное значение итоговой комиссии, т.е. уже включает в себя всё остальное (и ещё что-то).
Пользователь
Сообщений: Регистрация: 15.06.2023
09.01.2026 15:55:59
Привел Вам просто базовую свою заготовку, в качестве примера не более. Если вы пишите на луа 5.4, то нужно отказаться от bit.band в пользу продвинутого метода. Что там точно за комиссии, подсказать тоже не могу так как на каждом рынке есть особенности. Для Фондового API QUIK предлагает предварительный расчет через стандартную функцию. Для оценки можно ее воспользоваться. На срочном есть зависимость от гарантийного обеспечения и курсов ... Что касается моего подхода, то я применяю подход Ральфа Винса, а именно, торговый капитал делю изначально на две части: пассивный и активный. Так как в процессе торговле всегда присутствует пассивная часть, нет необходимости вести четкий учет комиссий, сверяю по клирингу. Здесь более важен учет количества и цены, так как на прямую влияют на управление позицией.
Например если в момент OnTrade мне нужно знать общее количество оставшихся акций
Для этого надо ловить это:
OnDepoLimit - изменение позиции по инструментам
Пользователь
Сообщений: Регистрация: 30.01.2015
09.01.2026 19:02:05
openbal
NUMBER
Входящий остаток
openlimit
NUMBER
Входящий лимит
currentbal
NUMBER
Текущий остаток
currentlimit
NUMBER
Текущий лимит
locked_sell
NUMBER
В продаже. Количество инструментов, заблокированное под исполнение заявок клиента на продажу
locked_buy
NUMBER
В покупке. Количество инструментов в активных заявках клиента на покупку
locked_buy_value
NUMBER
Стоимость инструментов, заблокированных под покупку
locked_sell_value
NUMBER
Стоимость инструментов, заблокированных под продажу
Пользователь
Сообщений: Регистрация: 12.05.2020
10.01.2026 12:51:49
Цитата
VPM написал: И это еще не вся проблематика, ведь нужно данные периодически синхронизировать с данными QUIK.
Зачем синхронизировать с данными QUIK, когда можно их использовать всегда? Зачем обрабатывать "сырые" коллбеки, когда можно проверять циклически, по изменению их размеров, нужные вам таблицы QUIK (таблицы заявок, стоп-заявок, сделок и т.д.)? Вы же в своих стратегиях, наверное, учитываете состояние вашего портфеля, а не занимаетесь подсчетом коллбеков . Коллбеки имеет смысл использовать только там, где без них не обойтись (например, OnTransReply, в которых может быть информация о причине невыполнения транзакции).
Пользователь
Сообщений: Регистрация: 15.06.2023
10.01.2026 13:45:20
Добрый день TGB, то что Вы описываете в определённых стратегиях конечно надежней, но задача далеко не тривиальна, особенно в скоростных алгоритмах. Да и автор вопроса применяет событийный подход. А вопрос звучит так:
Цитата
User12501 написал: Речь о том, как проигнорировать бесполезный вызов и не посчитать дважды то, что нужно? Например если в момент OnTrade мне нужно знать общее количество оставшихся акций, стандартные get-функции не работают (спрашивал об этом вот здесь: ). Значит нужно вводить отдельную переменную - количество акций, и при каждом OnTrade обновлять. Но тогда при повторном OnTrade происходит повторное обновление, и пожалуйста - ошибка.
Плюс учет различных комиссий в принятии решений, насколько помню точность в учете QUIK до шестого знака. Как же тут не сверять свою вторую бухгалтерию?
Пользователь
Сообщений: Регистрация: 02.01.2026
10.01.2026 13:55:24
Цитата
TGB написал: можно проверять циклически, по изменению их размеров, нужные вам таблицы QUIK (таблицы заявок, стоп-заявок, сделок и т.д.)?
Думаю такой подход сложнее, чем обработка колбеков. На примере данной ситуации: если пришедший колбек не содержит значения нужных мне параметров, то я его пропускаю и жду колбек, который их содержит. В случае же обработки таблиц вместо колбеков, нужно хранить не просто индекс последней обработанной строки таблицы, а индексы всех обработанных строк либо общее количество строк и индексы необработанных строк (пропущенных по причине отсутствия в них значений нужных параметров). И циклически проверять, не появились ли новые значения в пропущенных строках.
Пользователь
Сообщений: Регистрация: 27.01.2017
10.01.2026 14:49:21
Учет комиссий не решается колбеками и данными из таблиц. Решается же он через обработку отчетов брокера. Комиссия биржи транслируется вместе с сделкой, поэтому её условно можно считать. Брокера же чаще всего транслирует "ерунду". И только в отчете за день будут точные цифры, т.к. они могу зависеть от оборота за день, типа инструмента и др, и в момент сделки точных банально нет. Так что гораздо проще в алгоритм вбить процент либо величину комиссии и учитывать её. А корректировать через разбор отчета брокера.
Пользователь
Сообщений: Регистрация: 30.01.2015
10.01.2026 15:54:21
Цитата
Nikolay написал: Учет комиссий не решается колбеками и данными из таблиц. Решается же он через обработку отчетов брокера. Комиссия биржи транслируется вместе с сделкой, поэтому её условно можно считать. Брокера же чаще всего транслирует "ерунду". И только в отчете за день будут точные цифры, т.к. они могу зависеть от оборота за день, типа инструмента и др, и в момент сделки точных банально нет. Так что гораздо проще в алгоритм вбить процент либо величину комиссии и учитывать её. А корректировать через разбор отчета брокера.
Комиссия брокера считается в конце дня, так как реально сделки урегулируются лишь после сессии клиринговыми компаниями. Только эти компании могут списывать и зачислять денежные средства в оплату сделок. После получения их отчета, брокер соответственно списывает деньги у клиентов и начисляет свою комиссию.
Пользователь
Сообщений: Регистрация: 12.05.2020
10.01.2026 16:24:45
Цитата
Йцукен написал: Думаю такой подход сложнее, чем обработка колбеков.
Обработка перезапусков скрипта по любой неконтролируемой вами причине у вас не предусмотрена? Пока он перезапускается заявки на бирже могут быть выполнены, а коллбеки пропущены. Вы предполагаете что и коллбеки в работающем скрипте не теряются?
Какие скоростные алгоритмы? Когда есть ограничение архитектуры QUIK. Факторами возможных задержек в нем являются <Реализация скрипта> -> <Реализация QUIK> -> <Используемая аппаратура ПК> -> <Канал связи с брокером> -> <Сервер брокера> -> -> <Канал связи брокера с биржей> -> <Биржа>.
Пользователь
Сообщений: Регистрация: 02.01.2026
10.01.2026 17:17:44
Цитата
TGB написал: Обработка перезапусков скрипта по любой неконтролируемой вами причине у вас не предусмотрена? Пока он перезапускается заявки на бирже могут быть выполнены, а коллбеки пропущены.
При запуске скрипта обработка таблиц происходит в OnInit. Соответственно, все новые колбеки будут получены и обработаны после выхода из OnInit.
Цитата
TGB написал: Вы предполагаете что и коллбеки в работающем скрипте не теряются?
Если колбеки потеряются, то и данные в таблицах квика не будут заполняться.
написал: Обработка перезапусков скрипта по любой неконтролируемой вами причине у вас не предусмотрена? Пока он перезапускается заявки на бирже могут быть выполнены, а коллбеки пропущены.
При запуске скрипта обработка таблиц происходит в OnInit. Соответственно, все новые колбеки будут получены и обработаны после выхода из OnInit.
Цитата
написал: Вы предполагаете что и коллбеки в работающем скрипте не теряются?
Если колбеки потеряются, то и данные в таблицах квика не будут заполняться.
Как много чудесных открытий Вас ждет. Если скрипт был остановлен, например по ошибке, терминал же работает. А во время простоя исполнились ордера, то колбеки пропущены, т.к. событие прошло. Колбек же - это реакция на событие. Иногда брокер может разорвать соединение, вызвать OnClenUp и тогда приедут ВСЕ колбеки с начала сессии. Но это исключение.
OnInit - это событие запуска скрипта, ни коим образом не связанное с таблицами. Если только при запуске Вы сами не проверите что изменилось в таблицах с прошлого запуска.
Пользователь
Сообщений: Регистрация: 02.01.2026
10.01.2026 17:51:45
Цитата
Nikolay написал: А во время простоя исполнились ордера, то колбеки пропущены
Ещё раз:
Цитата
Йцукен написал: При запуске скрипта обработка таблиц происходит в OnInit.
Цитата
Nikolay написал: Если только при запуске Вы сами не проверите что изменилось в таблицах с прошлого запуска.
Скрипт сохраняет, допустим, номер своей активной заявки или id транзакции в файл. И при запуске он в состоянии проверить результат транзакции/заявки, пробежав однократно по соответствующим таблицам.
Цитата
Nikolay написал: брокер может разорвать соединение, вызвать OnClenUp и тогда приедут ВСЕ колбеки с начала сессии
Да и пофиг: скрипт запомнил, какие заявки/сделки (в т.ч. и те, что были в таблицах при запуске скрипта) он обработал и дубли проигнорирует.
Какие скоростные алгоритмы? Когда есть ограничение архитектуры QUIK. Факторами возможных задержек в нем являются <Реализация скрипта> -> <Реализация QUIK> -> <Используемая аппаратура ПК> -> <Канал связи с брокером> -> <Сервер брокера> -> -> <Канал связи брокера с биржей> -> <Биржа>.
Я не очень понимаю, что Вы хотите донести, и о чем спорите? И при этой архитектуре можно строить торговлю спредом, с выставление огромного количества ордеров, а следовательно нужна обработка как ордеров так и сделок. Например, мой алгоритм оставленный мной без присмотра, поймал какую то ошибку (уже и не припомню причину) наделал столько заявок, что брокер заблокировал канал, а затем выставил штраф. Это я к тому что все возможно!
Пользователь
Сообщений: Регистрация: 02.01.2026
10.01.2026 18:24:15
Цитата
VPM написал: мой алгоритм оставленный мной без присмотра, поймал какую то ошибку (уже и не припомню причину) наделал столько заявок, что брокер заблокировал канал, а затем выставил штраф.
Я думаю, тут надо какую-то защиту "от дурака" реализовывать: типа, при превышении заданного порога количества ошибочных транзакций подряд, останавливать скрипт до выяснения причин.
Пользователь
Сообщений: Регистрация: 30.01.2015
10.01.2026 20:05:28
, А как Вам это:
3 февраля 2010 года ошибка в алгоритме HFT-робота компании Infinium Capital Management, торговавшего нефтяными контрактами, привела к неконтролируемому росту заявок и скачку цены на нефть на 1,3% прямо перед закрытием биржи. Примерно за секунду работы робот сгенерировал убытков на $1 млн. ------------------------ С HFT-трейдингом связывают обвал на американском фондовом рынке 6 мая 2010 года. За пять минут индекс DJIA, и без того снижавшийся весь день, потерял около 7%, чтобы ещё через 15 минут отыграть большую часть падения. Многие трейдеры сочли это естественным результатом насыщения рынка роботами: реагируя на продажи, те драматически усилили уже наметившееся движение.
23 марта 2012 года компьютерный HFT-алгоритм, запущенный с терминалов неопознанного трейдера, «убил» попытку американской компании BATS Global Markets провести IPO. Попытка вывести акции на биржу продолжалась ровно 9 секунд, в течение которых бумаги компании обесценились практически до нуля, торги по ним были приостановлены, а через некоторое время руководство компании заявило о полном отказе выходить на биржу в обозримом будущем.
Один из программистов этого робота по секрету поделился, что они не успели протестировать алгоритм, но начальник приказал его запускать в бой. Сказано - сделано.