У меня сейчас для заявки в 1 лот алгоритм такой. OnOrder(): если для моей заявки balance == 0 - ставлю один флаг. Пришёл OnTrade()[сделка прошла значит] с моей заявкой - ставлю другой флаг и беру цену из него и в переменную. Функция контроля иcполнения ждёт появления обоих флагов, если пришли, то цену беру из переменной. Так же внутри OnOrder() и OnTrade() использую ещё свои флаги для того чтобы отбрасывать ненужные их вызовы - по сути OnOrder() как только пришёл в балансе ноль - ставлю флаг, следующий вызов проверяет этот флаг и если он есть, то игнорирую вызов, так же и в OnTrade(), как пришла моя сделка - ставлю флаг, чтобы отсекать другие возможные её вызовы. Вот и думаю, может просто достаточно только OnOrder() и брать из неё цену исполнения и достаточно?
Владимир написал: Alexander, Почему нельзя? Можно. Только вот мой личный "рекорд" в ожидании подтверждения исполнения заявки составляет семнадцать с половиной минут, и это наверняка не предел. А робот, тем не менее, написан и работает "вот прям ща". Не со 100%-ной уверенностью, поменьше, но работает. И написан он с головы до пят на чистейшем Lua. ::
Нет, Вы не путайте заявку и сделку. Если заявка именно в 1 лот, то остаток гарантированно в нуле, и сам факт прихода OnTrade говорит о том, что заявка исполнена (обычно в трёх экземплярах). По большому счёту, гарантирует идентификацию только совпадение trans_id, поскольку order_num формируется не нами, и я его, как правило, вообще не знаю. А вот для контроля исполнения заявки лично у меня заведён специальный стек активных заявок, из которого полностью исполненные или снятые заявки удаляются уже по таймеру.
Контроль исполнения заявки, которая например в вашем стеке у которой 1 лот контролируется по balanse == 0?
Короче, ещё спрошу так. Отправил заявку например на покупку 1 лота. В OnTrade() проверил, что order.trans_id == моему TRANS_ID и order.order_num == TRANSACTION_COMPLETED[tostring(order.trans_id)], короче отфильтровал по своей заявке и проверил что order.balance == 0. Этого достаточно для контроля исполнения заявки?
Владимир написал: И я уже говорил, что самый первый вызов OnTrade вовсе не означает, что данные там правильные, и проверка цены на ноль тоже ничего не гарантирует.
Если оно так, то получается что просто нет возможности в квике сделать контроль исполнения заявки. А раз так, то получается, что всё остальное просто не имеет никакого смысла. Какой смысл писать робота или ещё чего, если нельзя осуществить контроль исполнения заявки? Нет уверенности в исполнении - дальше ничего делать нельзя!!! Либо есть возможность со 100%-ной уверенностью программно определить, что заявка исполнена, либо вообще тогда надо закрывать все обсуждения, да и вообще тогда теряет смысл программирования на этом самом Lua.
Alexander написал: Вопросы:1) Возможен ли вызов OnTransReply() на мою поданную заявку с моим TRANS_ID, с trans_reply.trans_id == 0, nil, "0", "" или же trans_reply.trans_id всегда содержит номер заявки? Этот номер заявки измениться не может?2) OnTransReply() вызывается только один раз?3) Возможен ли случай, когда сначала первой будет вызов OnOrder(), а потом уже вызов OnTransReply()? Вроде бы как-то один раз такое проскочило, когда скрипт вылетел с ошибкой исполнения. Но точно не помню, возможно было и так, даже скорее всего так, что был вызов только OnTrade(), а OnTransReply() не вызвался, хотя по факту заявка выставилась. Из-за этого дублирую сохранение номера заявки не только в OnTransReply(), но и в OnOrder().4) Могу ли я быть уверен, что имея самый первый OnOrder() c order.balance == 0, последующие OnOrder() не изменят значение order.balance?5) Могут ли приходить сначала OnTrade() без trade.price, а потом с trade.price? От этого зависит какие именно я могу использовать вызовы OnTrade(), т.е. нужно ли вообще проверять установлено ли в них поле trade.price, или это поле заполнено ценой всегда и не меняется в следующих вызовах?6) Могу ли я быть уверен, что имея самый первый OnTrade() с ценой исполнения trade.price, последующие OnOrder() не изменят значение trade.price? 7) Могу ли я с учётом своего алгоритма контроля исполнения использовать только самые первые вызовы OnOrder(), OnTrade(), OnTransReply(), отфильтровывая все последующие, где я фактически смотрю только на изменение баланса в заявке и жду появления сделки с номером заявки?8) Может быть вообще как-то по другому изменить алгоритм контроля исполнения заявки(приход сделки)? Какой алгоритм контроля посоветуют разработчики с учётом всех этих многочисленных вызовов?
1. Всегда содержит trans_id и этот параметр не меняется. 2. Да. 3. Возможен. В связи с тем, что различные биржи предоставляют интерфейс подключения к своим системам по разным протоколам и разным схемам, в некоторых заявки и сделки доставляются разными не синхронизированными потоками, также не нужно исключать факт потери пакетов. Таким образом возможны ситуации, когда первым будет вызван OnOrder(). 4. Если пришёл OnOrder с balance = 0 - значит заявка исполнилась полностью, т.е. сделки на всё количество в заявке, и что дальше происходит с balance в OnOrder по данной заявке не важно. 5. Да, данный параметр не меняется в последующих вызовах. 6. Да, данный параметр не меняется в последующих вызовах. Если речь об одной заявке и только об одной сделке по ней - то цена не должна меняться. Если же по заявке может быть заключено больше одной сделки - то у каждой сделки может быть своя цена, которая может быть выгоднее цены в заявке. 7. Нет. 8. К сожалению, посоветовать какой-либо алгоритм контроля исполнения заявки мы не можем. Как уже верно заметил выше nikolz - общая рекомендация для сделок и заявок - не "затачивать" алгоритм на определенный порядок вызова OnOrder/OnTrade и их количество.
Хорошо. По пункту 8 вы не советуете конкретный алгоритм. Но это в общем случае не советуете, поскольку вариантов может быть много. Но я спрашиваю конкретно для своего наипростейшего случая, что описал выше. Например - покупка 1 лота. Нужен контроль того, что покупка 1-го лота 100% прошла и только тогда подавать на продажу того же 1-го лота. Какой алгоритм контроля применить посоветует техподдержка? Уж куда проще то? Мой алгоритм подойдёт? Или можно его упростить, например - вообще не использовать OnTrade()? Достаточно проверить OnOrder() где баланс = 0? Сейчас использую и то и то. А надо ли? Вроде работает.
Владимир написал: Alexander, Кроме своего TRANS_ID использовать просто нечего - ничто другое не гарантирует, что транзакция наша. Да и эта айдишка не гарантирует - иногда туда прилетают нули или явно левые айдишки вроде 10, 25 и т.п. Контроль исполнения у меня только по OnTrade, не вижу никакого смысла в использовании ни OnTransReply, ни OnOrder. Никакой очерёдности здесь не соблюдается от слова совсем - задержки в приходе прерываний или изменения содержимого таблиц Квика могут составлять 10 минут и более. Я присобачил какую-то пародию на нечёткий поиск, и у меня точность идентификации заявки, по которой пришла сделка, близка к 100%, но здесь мне очень помогает блокировка: подача заявки запрещена, если предыдущая заявка по этому тикеру не исполнена или не снята. И не только колбэки могут отправляться по нескольку раз, но и заявки могут исполняться в несколько сделок, причём прерывания по ним приходят крест-накрест собачьим шагом. А вот цена в разных сделках по одной заявке может и отличаться. И, наконец, Вы НИ В ЧЁМ не можете быть уверены. В частности, самые первые вызовы OnTrade (остальное прерывания я не использую) могут содержать как раз бракованные данные, а самые вторые или самые третьи - правильные. А могут врать и все до единого. И проверка полей таблиц trans_id со своим номером транзакции не поможет. Я делаю подобную проверку только при снятии неисполненных или частично исполненных заявок, и далеко не всегда там правильные значения, а заявки я снимаю через три минуты активности.
Владимир, привет. Вот и в этой ветке встретились. Мне бы весь этот сыр-бор с колбеками свести к решению моей простой задачи. Мне собственно(во всяком случае пока) надо реализовать элементарный алгоритм. Покупка лота - 1 шт, т.е. автоматом отпадает возможность срабатывания только части заявки потому как 1 лот это 1 лот и его частично исполнить нельзя. Это намного упрощает задачу. Далее всё, что мне нужно это контроль исполнения этой заявки на покупку. Всё. Я должен быть на 100% быть уверен, что моя заявка исполнилась. И если исполнилась, то только тогда подаю следующую уже на продажу, так что тут такой же принцип блокировки - пока не сработает покупка - никакой продажи. На QPILE я это делал так - в цикле пробегал по таблице заявок в поиске своей заявки с номером который мне возвратила send_transaction() в своём результате, смотрел значения поля баланса когда станет равно нулю, как только оно стало равно нулю, то потом в цикле пробегал по таблице сделок и как только в ней появлялась запись с номером моей заявки, я считал что сделка исполнена. Не знаю насколько хорош такой алгоритм, но он работал всегда. Возможно, что достаточно было просто увидеть ноль на балансе в таблице заявок и плюнуть на таблицу сделок, не знаю. Или наоборот, может достаточно было бы и того что сделка появилась в таблице сделок. Но я для надёжности решил использовать и то и то. Перейдя на Lua сначала обрадовался, что есть колбэки и не надо бегать в цикле по таблицам в поиске нужного номера заявки, но не тут то было. С одной стороны всё просто. С другой стороны - куча вопросов. А есть ли гарантия? На данный момент меня интересует пока только одно, могу ли я использовать самый первый вызов OnOrder(), в котором на балансе появился ноль вместо единицы и отбросить все остальные вызовы? Могу ли я использовать только самый первый вызов OnTrade(), который мне показал, что в нём появился номер моей заявки, взять из него цену и быть уверенным, что эта цена не меняется в следующих вызовах, и что вообще есть ли гарантия, что эта цена будет в самом первом этом вызове, т.е. надо ли проверять что цена не ноль, а остальные вызовы отбросить? Если так можно, то суть контроля исполнения оставляю ту же - приход нуля в балансе заявки и(AND) появление сделки. Открытым в принципе остаётся вопрос, а надо ли вообще делать 2 проверки или может быть достаточно только какой-то одной из них? Если вызовы колбэков идут вразнобой, может заменить AND на OR? Может вообще как-то изменить сам алгоритм контроля исполнения? Как? Как лучше?
PS. Разработчики накуралесили конечно знатно, оставив пользователям самим разбираться во всём, потому как много непоняток и нет однозначности. Не мешало бы самим этим разработчикам в документации привести хотя бы элементарный пример контроля исполнения заявки использую колбэки!
Владимир написал: Alexander, Я не знаю, что там происходит - знаю только, что глюков там дохренища, и от версии к версии это число растёт. С загрузкой-то можно и потерпеть, если достаточно редко отключать скрипт, а работа с ТТТ организована вполне себе терпимо, она реально быстрая, и у меня никогда не было проблем со скоростью, даже при очень большом количестве тикеров. Если, конечно, не пользоваться ни стаканами, ни графиками, ни обезличенными сделками - для торговли ничего из этого не требуется. Вот что иногда вылетает, скотина - это сильно раздражает. Время от времени прилетает nil, в т.ч. там, где его уж никак быть не может. Ставлю проверки на nil в тех местах - обычно помогает. Но, по большому счёту, весь софт надо переписывать с нуля, хотя никто этого не делает и делать не собирается.
Ну на меня собственно пока только загрузка долгая давит и тормоза по ходу работы с вкладками и окнами. По самим скриптам пока больших глюков самого квика я не заметил, потому как не так давно начал их писать. А начал я сдуру с QPILE, уж больно хотелось мне видеть разную информацию по опционам в виде отличном от доски опционов, да спреды разные между фьючерсами и базовыми активами в реальном времени с расчётом всяких вариантов купи-продай их и расчётом гарантированной прибыли в процентах годовых. То есть задачи довольно простые. Ах, да ещё надо было скрипт такой чтобы быстро например щёлк мышкой - купил, щёлк - продал, без всяких там окон ввода заявок, чтобы быстро. Вот пришлось по быстрому это накатать на QPILE. Понял, что это такое и что коряво на нём всё, хотя для простых задач пойдёт и это. Но его ограничения в 1 сек на перезапуск скрипта, и даже через какой-то изврат делать замкнутый цикл в отсутствие простого while как-то мне это совсем не в тему. И вот пришлось опять же по быстрому этот Lua познать и переписать скрипты на него. Но по мере написания на этом самом Lua начали появляться свои заморочки, о чём приходится спрашивать опять же на этом форуме. Так что пока в принципе по скорости всё нормально и зависаний как таковых много не было. А простой алгоритм робота у меня и на QPILE нормально и быстро работал. Но раз уж взялся за Lua, то и его переписал, всяких там зависаний тоже пока не замечено.
Отправляю заявку через скрипт Lua - 1 лот, использую свой TRANS_ID на транзакцию. Задача - если сделка произошла, значит надо отправить другую заявку. Т.е. мне нужен контроль исполнения заявки(сделка). Логи показывают, что сначала первой всегда откликается OnTransReply(), потом могут идти 3 вызова OnTrade() и 2 вызова OnOrder() в разной очерёдности. Логика контроля исполнения заявки(по сути приход сделки) была такая: 1) В OnOrder() если пришло изменение заявки, т.е. order.balance == 0 , то -> флаг is_nul = true. 2) В OnTrade() если trade.order_num == номеру моей заявки(получаю его через OnTransReply(), или в OnOrder() если пришла моя TRANS_ID если этот OnOrder() вызвался раньше OnTransReply()[мало ли?] , то -> флаг is_trade = true. 3) Далее если if is_nul and is_trade then -> выставляем нужную заявку.
Я не рассчитывал на то, что колбэки могут отправляться по нескольку раз. Прочитал эту тему, понял, что могут и причём неограниченное число раз. Я не заморачивался и не тестил чем конкретно отличаются пришедшие в колбэках таблицы, но вижу, что OnOrder() где order.balance == 0 - 2 раза, и OnTrade() 3 раза и слава богу цена в нём одна и та же.
Вопросы: 1) Возможен ли вызов OnTransReply() на мою поданную заявку с моим TRANS_ID, с trans_reply.trans_id == 0, nil, "0", "" или же trans_reply.trans_id всегда содержит номер заявки? Этот номер заявки измениться не может? 2) OnTransReply() вызывается только один раз? 3) Возможен ли случай, когда сначала первой будет вызов OnOrder(), а потом уже вызов OnTransReply()? Вроде бы как-то один раз такое проскочило, когда скрипт вылетел с ошибкой исполнения. Но точно не помню, возможно было и так, даже скорее всего так, что был вызов только OnTrade(), а OnTransReply() не вызвался, хотя по факту заявка выставилась. Из-за этого дублирую сохранение номера заявки не только в OnTransReply(), но и в OnOrder(). 4) Могу ли я быть уверен, что имея самый первый OnOrder() c order.balance == 0, последующие OnOrder() не изменят значение order.balance? 5) Могут ли приходить сначала OnTrade() без trade.price, а потом с trade.price? От этого зависит какие именно я могу использовать вызовы OnTrade(), т.е. нужно ли вообще проверять установлено ли в них поле trade.price, или это поле заполнено ценой всегда и не меняется в следующих вызовах? 6) Могу ли я быть уверен, что имея самый первый OnTrade() с ценой исполнения trade.price, последующие OnOrder() не изменят значение trade.price? 7) Могу ли я с учётом своего алгоритма контроля исполнения использовать только самые первые вызовы OnOrder(), OnTrade(), OnTransReply(), отфильтровывая все последующие, где я фактически смотрю только на изменение баланса в заявке и жду появления сделки с номером заявки? 8) Может быть вообще как-то по другому изменить алгоритм контроля исполнения заявки(приход сделки)? Какой алгоритм контроля посоветуют разработчики с учётом всех этих многочисленных вызовов?
Все эти 0, nil, "0", "", которые могут прийти в trans_id в разных частных случаях в OnTrade() или в OnOrder() как я понял для меня не критичны, так как во всех колбэках я проверяю поля таблиц trans_id со своим номером транзакции TRANS_ID.
Владимир написал: А вот при начальной загрузке квик долго загружается - это проблема. Была, потом была подавлена, сейчас опять проявилась у одного из брокеров. И лог засирается со страшной силой - сотни мегов за десятки минут. Чем эта сволочь занимается, мне неведомо.
Вот, грузится точно так же оооочень долго. Умный способ думаю убирать нет смысла, так как он видимо и так лишнего сам загружать не будет. Его как поставил, так и стоит. Обезличенные сделки оставлено только неторговые поручения. Из-за этого вряд ли будет сильно тормозить. А вот что ещё можно изменить? Может быть можно вручную откорректировать какие-нибудь конфигурационные файлы квика? Как я понимаю квик при загрузке тянет с сервера дофига ненужной информации, например возможно данные для графиков или ещё что. Вот это если убрать, то может и ускорится загрузка?
Владимир написал: Alexander, Был тут такой Антон, очень толковый и сильный программист. К сожалению, давно его не вижу. Насколько я помню, он когда-то рассказывал почему всё так происходит, но меня это мало интересовало, и я пропускал всё это мимо ушей. Покопайтесь в его сообщениях, если интересно.
У меня дохлейший по современным меркам комп, специально для торговли купленный. Два гига ОЗУ, два ядра по два гигагерца, два Квика от двух брокеров, в которых болтается несколько сотен тикеров на обслуживании. Нигде никаких особых тормозов не наблюдал - по крайней мере при нагрузках до тысячи тикеров на Квик. Кстати, насколько я помню, настройки "умным способом" и "по существующим таблицам" - разные вещи: ум есть - таблиц не надо. ::
Хорошо. Будет время покопаюсь, может найду сообщения этого Антона. По настройка там так - либо умным способом(там он квик сам смотрит по таблицам} либо по выбранным классам(классы сам выбираешь). Вот поэтому и думаю, что может из-за того, что много вкладок открыто (17 шт.) и на каждой вкладке несколько окон(где-то и 11 шт. есть), то поэтому и подтормаживает. Бывает даже так - сначала например окна двигаешь, мышкой нажимаешь - всё нормально работает , потом бывает просто паузу делаешь - не нажимаешь ничего и потом просто например окно двинуть надо или закрыть его, крестик нажимаешь например на окно сообщения, а оно не закрывается сразу, а закрывается через паузу. Иногда сразу закрывается, а иногда через паузу. И при начальной загрузке у меня квик долго загружается. Не засекал время, но минуты точно. Это нормально?
И вообще квик как-то приторможенно работает. Это интересно у всех так? То вроде шустро, то после переключения окон или ещё чего делаешь действие, например двинуть окно или закрыть окно, а оно тупит-висит, квик думает-думает и только после какой-то задержки срабтывает. Вроде и проц толком не загружет, а тормоза есть. Всё остальное - куча открытых программ всё работает шустро. Память 8 Гб, AMD Athlon X4 860K Quad Core Processor 3.70 GHz. Может настройки какие поменять? У мненя загрузка потоков данных в настройках стоит умным способом по существующим таблицам. Неужели из-за того, что много данных приходится онлайн подтягивать с сервера и обрабатывать? Стояло 10 сек, потом ставил на 1 сек время обновления данных.
Владимир написал: Занимайтесь торговыми алгоритмами, господа, а не написанием нафиг никому не нужных тестов. И будет вам ЩАСТЬЕ!
Согласен. Этим и занимаемся. Просто столкнулся с такой ситуацией, которой как бы быть не должно, но она есть. Пытался понять почему такое у них вообще есть. Для себя просто поставил sleep(50) - всё работает. Но понять хотелось логику работы QUIK что они там замутилитакое и почему, что без задержки ну никак.
nikolz написал: разработчики рекомендуют ставить sleep чайникам и буратинам, как самый простой способ исключить практически монопольный захват процессора одним потоком.
В своё время сталкивался и с потоками на C и всякими там атомарными функциями и прочее. Но это было давно. Сейчас задача простая - написать скрипт и чтобы он не вис. Я просто пытаюсь понять какого хрена если main() это реально отдельный поток в OC, то почему он не виснет если есть sleep() и виснет если его нет? Ну нет sleep() и что? Ну циклится быстро и что? Время выполнения от захода в цикл до повторного захода в него минимально и что? И даже не факт что этот поток будет на 100% грузить одно из ядер процессора. Даже если разрабы API функцией(сейчас даже названий не помню и искать не хочу) вешают main() на отдельное ядро проца и что? OS сама решает какие ещё потоки будут последовательно работать на этом же ядре. И только OS может используя свои привилегии сделать так, что бы какой-то отдельный поток мог один занять ресурсы одного ядра, т.е. чтобы только он один выполнялся на этом ядре а не пользовательский поток QUIK это решает. Так что и без sleep() ничего виснуть не должно по идее и main() должен спокойно работать наравне с другими потоками, которые сочтёт нужным OS. Могу только предположить что есть какие-то прерывания от самого квика, которые во время своего выполнения что-то там делают, не пойми что и мешают main() нормально работать, просто main() по какой-то причине просто не получает управлении из-за того, что-то там у них в прерываниях циклится и не выходит из прерывания.
s_mike@rambler.ru написал: Потоки, о которых пишут разработчики не есть потоки операционной системы в чистом виде. Если не вдаваться в дебри, sleep() нужен обязательно. Поставьте sleep(50) и все станет хорошо, ничего тормозить не будет
Да я тоже начал склоняться к такому, что потоки квика - это явно не потоки ОС.
Т.е. по поводу поста выше если как говорят разрабы main() работает в отдельном потоке, то вообще ничего виснуть не должно. Хоть есть задержка, хоть нет. На то он и отдельный поток. Зачем разрабы рекомендуют ставить sleep(100)? Что не так с потоком?
У меня из main() вызывается простая функция в которой в цикле while жду появления 2-х флагов. Флаги устанавливаются по событиям из 2-х разных коллбэков, один флаг из одного, другой из другого. Скрипт наглухо виснет если в функции while чисто цикл без задержки. Если поставить в цикл sleep(), то не виснет. По этому поводу даже есть пример в файле "Использование Lua в Рабочем месте QUIK.pdf" от разработчиков квика с подобным циклом while и там написано, что: "Если убрать вызов функции sleep() внутри цикла, то скрипт будет загружать на 100% одно из ядер процессора, что позволит увеличить скорость обработки сценариев внутри цикла, но приведёт к более интенсивному использованию ресурсов компьютера." Дело в том, что у меня срабатывает коллбэк OnTransReply(trans_reply) и он выводит message и это окно с message виснет не отвечает, а скрипт работает в цикле. Так почему виснет, а не грузит проц на сто процентов ядро? Вообще почему должно виснуть или грузить проц на 100% одно ядро если main() работает в отдельном потоке? main() вызывает простые функции и они значит тоже работают в одном потоке с ним. Или не так? какая разница вообще не пойму есть задержка в цикле или нет? Моя функция c циклом: function order_done() while is_run do if is_nul and is_trade then is_nul = false is_trade = false return OrderPrice end end end А вот пример из файла про который пишут разрабы квика из их файла, который находится в каталоге Квик\Doc\Lua\Использование Lua в Рабочем месте QUIK.pdf: is_run = true
function OnStop() is_run = false end
function main() while is_run do sleep(100) end end