OrderSendAsync не возвращает номер тикета (OnTradeTransaction - ловля блох или асинхронных хаос? )
Уважаемые форумчане,
Хочу поделиться мнением и послушать мнения и опыт коллег, по поводу OrderSend, OrderSendAsync и обработчика OnTradeTransaction. Обработчик OnTrade, на мой взгляд,
Вы отправляете по одному ордеру на один тик, или несколько ордеров подряд, в цикле?
Вы отправляете по одному ордеру на один тик, или несколько ордеров подряд, в цикле?
Я понимаю к чему Вы клоните... Об это я давно уже споткнулся и "излечился от детской иллюзорности восприятия" )).
После исполнения OrderSend, OrderSendAsync управление отдается основному обработчику OnTick(). Если этого не сделать то невозможно получить и обработать транзакции. Когда я писал об однопоточности, я именно это имел в виду.
Это моя, видимо несбыточная, мечта, когда хотя бы OnTick, OnTrade и OnTradeTransaction будут выполняться в
отдельных потоках... У меня, кстати, до сих пор вызывает недоумение появление функции Sleep. Смысл? Тяжелые циклические обработчики там
сделать невозможно из-за однопоточности, а в легких - использование Sleep не имеет смысла, но это уже отдельная тема для разговора ))
Я понимаю к чему Вы клоните... Об это я давно уже споткнулся и "излечился от детской иллюзорности восприятия" )).
После исполнения OrderSend, OrderSendAsync управление отдается основному обработчику OnTick(). Если этого не сделать то невозможно получить и обработать транзакции. Когда я писал об однопоточности, я именно это имел в виду.
Это моя, видимо несбыточная, мечта, когда хотя бы OnTick, OnTrade и OnTradeTransaction
будут выполняться в отдельных потоках... У меня, кстати, до сих пор вызывает недоумение появление функции Sleep. Смысл? Тяжелые
циклические обработчики там сделать невозможно из-за однопоточности, а в легких - использование Sleep не имеет смысла, но это уже
отдельная тема для разговора ))
Хоть я и мало чего понял в этом тексте, я уверен в том, что вы не поняли к чему был мой вопрос.
Если на одном тике был отправлен только один ордер, то в OnTradeTransaction будут все его параметры. Предположительно, TRADE_TRANSACTION_REQUEST
приходит последним не случайно. И поскольку до этого было размещение ордера и сделки в историю, то все нужные параметры мы можем получить из
других структур функции OnTradeTransaction. Но если несколько ордеров подряд, то я не
уверен что будет совпадение. Не получится-ли так, что TRADE_TRANSACTION_REQUEST
от первого отправленного ордера а все параметры от последнего. Это надо внимательно проверять.
Прошу прощения за свои 5 копеек. В том смысле, что по существу проблемы ничего сказать не могу.
Просто я вообще не понимаю зачем нужно всё это отслеживать?
По уму (на мой взгляд), я должен отправить запрос на открытие позиции и получить гарантированный и точный ответ открыта она или нет и её ID. Если будет дополнительная информация о том по какой причине позиция не открыта - замечательно, нет - главное я буду знать, что позиция не открыта. А все промежуточные проверки должны проводиться автоматически.
Уважаемые форумчане,
Хочу поделиться мнением и послушать мнения и опыт коллег, по поводу OrderSend, OrderSendAsync и обработчика OnTradeTransaction. Обработчик OnTrade, на мой взгляд, жалкий рудимент, не заслуживающий большого внимания, в силу ограниченного и упрощенного функционала.
...
Использую только OrderSendAsync при реальной торговле на МОЕХ. Причина - различное время исполнения заявок от нескольких миллисекунд до десятков секунд.
Общий алгоритм:
1. Отправляю в цикле заявки по нескольким инструментам через OrderSendAsync.
2. Ставлю флаг запрета
торговли в true.
3. Фиксирую время отправки заявок.
4. Отслеживаю поступление транзакций в OnTradeTransaction.
5.
После получения подтверждения совершения сделок по всем инструментам сбрасываю флаг запрета торговли в false.
6. Если подтверждения
нет за определенный промежуток времени нет, то сбрасываю флаг запрета торговли в false по тайм ауту.
Рабочий пример использования функции OnTradeTransaction.
//+------------------------------------------------------------------+ //| OnTradeTransaction | //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction& trans, const MqlTradeRequest& request, const MqlTradeResult& result) { // ищем сделку, добавленную в историю if(trans.type==TRADE_TRANSACTION_DEAL_ADD) { // выбираем сделку для дальнейшего анализа HistoryDealSelect(trans.deal); // проверяем что это сделка на вход в рынок if(HistoryDealGetInteger(trans.deal,DEAL_ENTRY)==DEAL_ENTRY_IN && trans.order > 0) { for(int i=0;i<symbols_total;i++) { // проверяем символ сделки if(symbols_set[i].symbol==trans.symbol) { // считаем объем и цену сделки (одна заявка может быть разбита на несколько сделок по разным ценам) symbols_set[i].result_volume+=trans.volume; symbols_set[i].price_open+=trans.volume*trans.price; // если весь объем заявки исполнен, то ставим флаг активности позиции по инструменту = истина и считаем итоговую цену открытия позиции if(symbols_set[i].request_volume==symbols_set[i].result_volume) { symbols_set[i].price_open/=symbols_set[i].result_volume; symbols_set[i].active=true; } } } } // проверяем что это сделка на выход из рынка else if(HistoryDealGetInteger(trans.deal,DEAL_ENTRY)==DEAL_ENTRY_OUT && trans.order > 0) { for(int i=0;i<symbols_total;i++) { // проверяем символ сделки if(symbols_set[i].symbol==trans.symbol) { //считаем закрытий объем, так как одна заявка может быть разбита на несколько сделок symbols_set[i].result_volume-=trans.volume; // если весь объем позиции закрыт, то ставим флаг активности инструмента в ложь и сбрасываем цену открытия в 0 if(symbols_set[i].result_volume==0) { symbols_set[i].active=false; symbols_set[i].price_open=0; } } } } } }
- www.mql5.com
Хоть я и мало чего понял в этом тексте, я уверен в том, что вы не поняли к чему был мой вопрос.
Если на одном тике был отправлен только один ордер, то в OnTradeTransaction будут все его параметры.
Предположительно, TRADE_TRANSACTION_REQUEST приходит последним не случайно. И поскольку до этого было размещение ордера
и сделки в историю, то все нужные параметры мы можем получить из других структур функции OnTradeTransaction.
Но если несколько ордеров подряд, то я не уверен что будет совпадение. Не получится-ли так, что TRADE_TRANSACTION_REQUEST
от первого отправленного ордера а все параметры от последнего. Это надо внимательно проверять.
Алексей, спасибо за Ваш комментарий. Я понял Вашу мысль, но увы, это не тот случай...
Это чистый эксперимент без каких бы то ни было инфлюэнций. Отправка одной позиции - ловля транзакций (лог приложил, если любопытно - можете
взглянуть). И поверьте, в этой теме я давно, и даже используя OrderSend я завершение операции "выставляю" ТОЛЬКО по транзакции. Я бы
наверно и продолжал не нем "сидеть", если бы не "поведенческие" изменения в демо-сервере MetaQuotes, которые я описал выше. И, отчасти, я
даже благодарен этому обстоятельству, потому что это позволило выявить слабые места в обработке, но к сожалению, из доступных методов,
нормального решения и получается, поэтому и появился этот тред.
Вопрос ведь не в том, что в OnTradeTransactionпридут не все транзакции. При правильной обработке, не нарушая поточности обработки, вы получите их ВСЕ, но... Вопрос в том, что при работе с OrderSendAsync, из идентификационных параметров вы гарантировано получаете только result.request_id. При этом result.request_id в транзакции фигурирует только в типе TRADE_TRANSACTION_REQUEST, который вам придет ОДИН раз.
Все остальные транзакции по этому приказу вы сможете идентифицировать только по номеру тикета.
При этом, если ТОРГОВЫЕ ТРАНЗАКЦИИ прошли раньше, чем ТРАНЗАКЦИЯ ЗАПРОСА, то их идентификация превращается в весьма витиеватое занятие.
Прошу прощения за свои 5 копеек. В том смысле, что по существу проблемы ничего сказать не могу.
Просто я вообще не понимаю зачем нужно всё это отслеживать?
По уму (на мой взгляд), я должен отправить запрос на открытие позиции и получить гарантированный и точный ответ открыта она или нет и её ID. Если будет дополнительная информация о том по какой причине позиция не открыта - замечательно, нет - главное я буду знать, что позиция не открыта. А все промежуточные проверки должны проводиться автоматически.
Сергей, Вы абсолютно правы! Я тоже так считаю. OrderSend именно так и должна работать. Оправил - получил гарантированный результат! Со всеми своими недостатками, но железобетонный! Но по факту этого нет...
Если Вы, при анализе результата операции OrderSend, получили 10009 - это ровным счетом ничего не значит. И это не голословное утверждение.
Это факт, который я обнаружил лично (и мне, в одной из тем https://www.mql5.com/ru/forum/304239/page52#comment_11355367
на этом форуме, уважаемый fxsaber внес просветление в этом вопросе
так же). Позволю процитировать: "fxsaber: Синхронный вариант дожидается
размещения ордера (не открытия позиции). Асинхронный - ничего не ждет.". Добавить нечего.
Резюме:
Используя только OrderSend вы, рано или поздно, столкнетесь с ситуацией, когда 10009 - "размещение" есть, а позиции нет.
Надеюсь я ответил на Ваш вопрос: "зачем нужно всё это отслеживать?".
- 2019.04.16
- www.mql5.com
Использую только OrderSendAsync при реальной торговле на МОЕХ. Причина - различное время исполнения заявок от нескольких миллисекунд до десятков секунд.
Общий алгоритм:
1. Отправляю в цикле заявки по нескольким инструментам через OrderSendAsync.
2. Ставлю флаг запрета
торговли в true.
3. Фиксирую время отправки заявок.
4. Отслеживаю поступление транзакций в OnTradeTransaction.
5.
После получения подтверждения совершения сделок по всем инструментам сбрасываю флаг запрета торговли в false.
6. Если
подтверждения нет за определенный промежуток времени нет, то сбрасываю флаг запрета торговли в false по тайм ауту.
Рабочий пример использования функции OnTradeTransaction.
Владимир, большое спасибо за развернутый ответ! Но, к Вашему счастью и к моему сожалению, у Вас ситуация немного проще. У Вас все приказы "обезличены", т.е. выполнены по принципу - "выстрелил-и забыл".
У меня немного другой случай. Мне каждый приказ нужно привязать к "источнику" сигнала, для последующего управления, при этом, если
ТОРГОВЫЕ ТРАНЗАКЦИИ прошли раньше, чем ТРАНЗАКЦИЯ ЗАПРОСА, то их идентификация, без предварительной буферизации всех полученных,
невозможна. А с буферизацией почти все преимущества использования OrderSendAsync теряются из-за появления больших
вычислительных расходов.
............
Надеюсь я ответил на Ваш вопрос: "зачем нужно всё это отслеживать?".
зачем нужно всё это отслеживать? == все промежуточные проверки должны проводиться автоматически
Это я к тому, что, возможно, кто-нибудь, может быть даже MQ, напишет простую библиотеку по работе именно с открытием-закрытием позиции. Чтобы можно было написать
Position.Open(цена, тип, проскальзыване, SL, TP, магик, структура ответа)
она сама проверила все транзакции и заполнила ответ типа
- позиция открыта
- цена открытия
- ID позиции
- тикет
- причина отказа
- ....
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Уважаемые форумчане,
Хочу поделиться мнением и послушать мнения и опыт коллег, по поводу OrderSend, OrderSendAsync и обработчика OnTradeTransaction. Обработчик OnTrade, на мой взгляд, жалкий рудимент, не заслуживающий большого внимания, в силу ограниченного и упрощенного функционала.
Опишу, с точки зрения полученного опыта, достоинства и недостатки торговых функций OrderSend, OrderSendAsync...
OrderSendOrderSendAsync
Коллеги, буду признателен, если хорошо знающий эту тему человек, укажет на мои идеологические заблуждения или подкинет свежую идею.
Немного предыстории и размышлений...
До некоторого момента пользовался OrderSend, но при этом отслеживал окончание транзакции через OnTradeTransaction (поскольку 10009 ровным счетом ничего вам не гарантирует). Все бы ничего, но при тестировании на демо-серверах MetaQuotes одолели меня непредвиденные и, порой, чудовищные задержки OrderSend (более минуты).
Окончательно перешел на OrderSendAsync, но и тут не все гладко пошло - процентов 70% запросов не возвращают номер тикета. Не опустил руки...
Исхода из предпосылки что транзакции типа TRADE_TRANSACTION_REQUEST пройдут заведомо раньше, чем все остальные, написал код:
Соотв-но, делаем анализ маджика и request_id на совпадение, смотрим реальную торговую ошибку.
"Слава богу, что request_id всё же возвращается в результате OrderSendAsync!" - думал я... Но радость была недолгой, когда обнаружил что транзакции типа TRADE_TRANSACTION_(ORDER, DEAL и HISTORY) прошли гораздо раньше REQUEST-a. В результате транзакция остается неотслеженной и не привязанной к запросу, поскольку в структуре MqlTradeTransaction зацепиться не за что, если у тебя нет тикета, после отправки запроса OrderSendAsync.
Красивых решений я не вижу. Единственным выходом, на мой взгляд, может быть "коллекционирование" всех транзакций, в типе TRADE_TRANSACTION_REQUESTловить ID, смотреть ошибку и если повезет - номер тикета, после чего делать ретроспективный анализ транзакций типа TRADE_TRANSACTION_(ORDER, DEAL и HISTORY) на совпадение по тикету. Учитывая, что мониторинг невозможно сделать в отдельном потоке, всё это превращается в какую-то монстро-образную задачу и выигрыш от использования OrderSendAsync просто сводится на "нет". Проще смирится OrderSend и с его огромными задержками.
Кто-нибудь "обошёл" эти асинхронные грабли?
Господа разработчики, идеологи MetaQuotes, может всё же сделать хотя бы тикет обязательным к возвращению функцией OrderSendAsync или request_id сделать сквозным для всех типов транзакций. Без всего этого смысл использования асинхронного режима стремиться к нулю, а трудозатраты неоправданно возрастают.
Благодарю, что хватило сил прочесть до конца ))