Обсуждение статьи "Как построить советник, работающий автоматически (Часть 08): OnTradeTransaction"
У меня проблема, которая ставит меня в тупик.
Спасибо за такую замечательную статью. У меня есть проблема, которая меня смущает. Я написал код для открытия позиции.
Он может вернуть правильное значение при запуске на демо-счете, но возвращает 0 при запуске на реальном счете, не могли бы вы мне подсказать, где проблема?
//+------------------------------------------------------------------+ //|& nbsp;   ; Test1.mq5 | //|& nbsp; Copyright 2023, MetaQuotes Ltd.| //|& nbsp;   ; https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #include <Trade\Trade.mqh> CTrade m_trade; CDealInfo m_deal; //+------------------------------------------------------------------+ //| Функции инициализации торговли советника & nbsp;   ; | //+------------------------------------------------------------------+ int OnInit() { //--- EventSetMillisecondTimer(1); OpenPosition(ORDER_TYPE_BUY, 0.01, 123456); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); } //+------------------------------------------------------------------+ //| EA Quotation Function & nbsp;   ; || //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ void OnTimer() { } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ ulong OpenPosition(const ENUM_ORDER_TYPE type, const double lot, const long magic) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); m_trade.SetExpertMagicNumber(magic); if(m_trade.PositionOpen(_Symbol, type, lot, (type == ORDER_TYPE_BUY) ? ask : bid, 0, 0)) { ulong deal_ticket = m_trade.ResultDeal(); if(HistoryDealSelect(deal_ticket)) m_deal.Ticket(deal_ticket); string flag = (m_deal.DealType() == DEAL_TYPE_BUY) ? "buy" : "sell"; printf(StringFormat("open deal ticket= #%%d order ticket= #%%d %%s %%.2f %%s at %%.%df", _Digits), deal_ticket, m_deal.Order(), flag, m_deal.Volume(), _Symbol, m_deal.Price()); return(deal_ticket); } return(0); }
Ола, Даниэль Хосе
Obrigado por dedicar um artigo tão maravilhoso. Estou com um problema que me confunde. Eu escrevi um código para abrir uma posição.
Ele pode retornar o valor correto quando é executado em conta demo, mas retorna 0 quando é executado em uma conta real, você pode me ajudar a informar onde est в чем проблема?
Tente verificar o erro que está sendo retornado, adicionando a linha destacada logo abaixo.
ulong OpenPosition( const ENUM_ORDER_TYPE type, const double lot, const long magic) { double ask = SymbolInfoDouble ( _Symbol , SYMBOL_ASK ); double bid = SymbolInfoDouble ( _Symbol , SYMBOL_BID ); m_trade.SetExpertMagicNumber(magic); if (m_trade.PositionOpen( _Symbol , type, lot, (type == ORDER_TYPE_BUY ) ? ask : bid, 0 , 0 )) { ulong deal_ticket = m_trade.ResultDeal(); if ( HistoryDealSelect (deal_ticket)) m_deal.Ticket(deal_ticket); string flag = (m_deal.DealType() == DEAL_TYPE_BUY ) ? "buy" : "sell" ; printf ( StringFormat ( "open deal ticket= #%%d order ticket= #%%d %%s %%.2f %%s at %%.%df" , _Digits ), deal_ticket, m_deal.Order(), flag, m_deal.Volume(), _Symbol , m_deal.Price()); return (deal_ticket); } Print("Error: ", m_trade.ResultRetcode()); return ( 0 ); }
Проверьте ошибку, которую вы отправляете на повтор, добавив к ней логотип, расположенный ниже.
Нет, моя цель - вернуть тикет сделки.
Он может возвращать тикет сделки позиции на демо-счете, но возвращать нулевое значение на реальном счете, это для чего?
ulong OpenPosition(const ENUM_ORDER_TYPE type, const double lot, const long magic) { double ask = SymbolInfoDouble(_Symbol, SYMBOL_ASK); double bid = SymbolInfoDouble(_Symbol, SYMBOL_BID); m_trade.SetExpertMagicNumber(magic); if(m_trade.PositionOpen(_Symbol, type, lot, (type == ORDER_TYPE_BUY) ? ask : bid, 0, 0)) return(m_trade.ResultDeal()); return(0); }
Нет, моя цель - раздобыть миллиард долларов .
ele pode retornar ticket de negociação da posição na conta Demo, mas retornar valor zero na conta Real, isso é para quê?
A linha que mandei você adicionar NÃO É... вы повторяете. NÃO É para retornar nenhum valor ... ELA SERVE PARA VERIFICAR O ERRO que está dando ao tentar abrir uma posição ... вы не должны использовать восстановленную ценность... вы должны проверить ОШИБКУ на вкладке ошибок... Veja a DOCUMENTAÇÃO
Здравствуйте, я слежу за этой серией статей. Мое почтение. Это действительно полезно.
Я тестирую результат и после создания ордера удаляю его. Но советник больше не позволяет создать новый ордер.
Вот этот фрагмент кода:
case TRADE_TRANSACTION_ORDER_DELETE : if (trans.order == trans.position) (*manager).PendingToPosition(); else (*manager).UpdatePosition(trans.position); // ORDER? break ;
Он использует trans.position, который в случае удаления ордера всегда равен 0. Таким образом, это значение передается в UpdatePosition. Его первое условие отправляет его непосредственно в оператор return.
Я попытался передать тикет trans.order, но код игнорирует его, потому что m_position имеет нулевые данные, поэтому тикет равен 0 (! = m_Position.Ticket):
После этого. Когда я пытаюсь создать новый заказ, m_ticketPending имеет значение первого заказа, поэтому он не создается.
EraseTicketPending не вызывается, потому что когда приходит TRADE_ACTION_REMOVE, это условие всегда ложно, так как request .request.TRADE_ACTION_REMOVE всегда ложно.
if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && (request.magic == def_MAGIC_NUMBER))
всегда ложно, поскольку request.magic равен 0.
Я выясню, будет ли это исправлено в следующих главах.
С уважением,
Кажется, я нашел проблему.
Когда удаление ордера происходит из пользовательского интерфейса MT5, магическое число равно 0. Поэтому я изменил условие на
if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && ((request.magic == def_MAGIC_NUMBER) || request.magic == 0 ))
и, кажется, все работает так, как ожидалось.
Привет, Даниэль Хосе.
Спасибо за такую замечательную статью. У меня есть проблема, которая ставит меня в тупик. Я написал код для открытия позиции.
Он может вернуть правильное значение при запуске на демо-счете, но он возвращает 0 при запуске на реальном счете, не могли бы вы помочь мне подсказать, где проблема?
Эта функция открывает позицию и возвращает DEAL TICKET:
//+------------------------------------------------------------------+ //|& nbsp;   ; Test1.mq5 | //|& nbsp; Copyright 2023, MetaQuotes Ltd.| //|& nbsp;   ; https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #include <Trade\Trade.mqh> #include <Trade\SymbolInfo.mqh> CTrade m_trade; CDealInfo m_deal; CSymbolInfo m_symbol; input double TakeProfit = 0; input double StopLoss = 0; input string PositionComment = ""; double m_point; //+------------------------------------------------------------------+ //| Функции инициализации торговли советника & nbsp;   ; | //+------------------------------------------------------------------+ int OnInit() { //--- EventSetMillisecondTimer(1); if(!m_symbol.Name(_Symbol)) // задает имя символа return(INIT_FAILED); RefreshRates(); m_trade.SetMarginMode(); m_trade.SetTypeFillingBySymbol(m_symbol.Name()); m_trade.SetDeviationInPoints(INT_MAX); int adjust = (m_symbol.Digits() == 3 || m_symbol.Digits() == 5) ? 10 : 1; m_point = m_symbol.Point() * adjust; //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); } //+------------------------------------------------------------------+ //| EA Quotation Function & nbsp;   ; || //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ void OnTimer() { } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ bool RefreshRates(void) { //--- частота обновления if(!m_symbol.RefreshRates()) { Print("RefreshRates error"); return(false); } //--- защита от возврата значения "ноль". if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0) return(false); //--- return(true); } //+------------------------------------------------------------------+ //|& nbsp;   nbsp;   nbsp; | //+------------------------------------------------------------------+ ulong OpenPosition(const ENUM_ORDER_TYPE type, const double volume, const long magic) { ulong deal_ticket = 0; double sl = 0; double tp = 0; m_trade.SetExpertMagicNumber(magic); RefreshRates(); double ask = m_symbol.Ask(); double bid = m_symbol.Bid(); switch(type) { case ORDER_TYPE_BUY: if(TakeProfit > 0) tp = m_symbol.NormalizePrice(ask + TakeProfit * m_point); if(StopLoss > 0) sl = m_symbol.NormalizePrice(bid - StopLoss * m_point); break; case ORDER_TYPE_SELL: if(TakeProfit > 0) tp = m_symbol.NormalizePrice(bid - TakeProfit * m_point); if(StopLoss > 0) sl = m_symbol.NormalizePrice(ask + StopLoss * m_point); break; } static datetime from_date = iTime(m_symbol.Name(), PERIOD_D1, 0); ulong time = GetTickCount64(); if(m_trade.PositionOpen(m_symbol.Name(), type, volume, (type == ORDER_TYPE_BUY) ? ask : bid, sl, tp, PositionComment)) { ulong open_execution = GetTickCount64() - time; do { ulong order_ticket = m_trade.ResultOrder(); HistorySelect(from_date, TimeTradeServer()); int total = HistoryDealsTotal(); for(int i = total - 1; i >= 0; i--) { if(!m_deal.SelectByIndex(i)) continue; if(m_deal.Symbol() != m_symbol.Name()) continue; if(m_deal.Entry() != DEAL_ENTRY_IN) continue; if(m_deal.Order() != order_ticket) continue; printf(StringFormat("open #%%I64u %%s %%.2f %%s at %%.%df done in %%I64u ms", m_symbol.Digits()), m_deal.Order(), (type == ORDER_TYPE_BUY) ? "buy" : "sell", m_deal.Volume(), m_deal.Symbol(), m_deal.Price(), open_execution); from_date = m_deal.Time(); deal_ticket = m_deal.Ticket(); break; } } while(deal_ticket == 0); } return(deal_ticket); } //+------------------------------------------------------------------+
Я начал использовать его для отлова событий (открытие позиции, закрытие, модификация), как я делал это раньше в MT4 (постоянно проверяя позиции, чтобы угадать, что произошло). В этом аспекте подход MT5 очень чист.
НО ЧТО ПРОИСХОДИТ, ЕСЛИ советник падает или выключается в течение часа: он, конечно, не получит никаких событий, но когда он перезапустится, он не получит событий, которые он испортил в течение 1 часа. Поэтому, чтобы угадать, что произошло, ему придется действовать старым способом MT4, анализируя позиции, чтобы угадать, что произошло. Чтобы решить эту проблему, я должен сохранить 2 способа обнаружения событий: способ MT5 и способ MT4 в качестве резервного.
Для рыночных позиций это происходит мгновенно.
Согласен... именно поэтому при запуске эксперта происходит проверка позиций или отложенных ордеров. Но об этом говорится в статье чуть дальше в этой же последовательности.
Автоматический перевод применен модератором
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования

Опубликована статья Как построить советник, работающий автоматически (Часть 08): OnTradeTransaction:
В этой статье я покажу вам, как использовать систему обработки событий, для быстрой и лучшей обработки вопросов, связанных с системой ордеров, чтобы советник работал быстрее. Таким образом, ему не придется постоянно искать информацию.
Теперь в наиболее полном виде у нас наконец-то появились дружественные друг другу класс C_Manager и советник. Они до такой степени дружны, что оба могут работать и следить за тем, чтобы не стать агрессивными или недружелюбными. Таким образом, поток сообщений между советником и классом C_Manager выглядит так, как показано на рисунке 02:
Рисунок 02 - Поток сообщений с новыми реализованными функциями
Данный поток может показаться вам слишком сложным или совсем нефункциональным, но это именно то, что реализуется в данный момент.
Глядя на рисунок 02, можно подумать, что код советника очень сложный, но он намного проще того, что многие люди считают необходимым для кода, реально используемого в советнике. Особенно в автоматизированном советнике. Помните следующее: на самом деле советник не генерирует никаких сделок, это всего лишь средство или инструмент для связи с торговым сервером. Таким образом, он действительно реагирует только на те триггеры, которые к нему применяются.
Автор: Daniel Jose