Diskussion zum Artikel "Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion"

 

Neuer Artikel Erstellen eines EA, der automatisch funktioniert (Teil 08): OnTradeTransaktion :

In diesem Artikel erfahren Sie, wie Sie das Ereignisbehandlungssystem nutzen können, um Probleme im Zusammenhang mit dem Auftragssystem schnell und effizient zu bearbeiten. Mit diesem System wird der EA schneller arbeiten, sodass er nicht ständig nach den benötigten Daten suchen muss.

Jetzt haben wir endlich die Klasse C_Manager und den EA, die miteinander befreundet sind, in einer viel vollständigeren Form. Beides kann funktionieren und dafür sorgen, dass sie nicht aggressiv oder unfreundlich werden. Der Nachrichtenfluss zwischen dem EA und der Klasse C_Manager entspricht somit dem in Abbildung 02:

Abbildung 02

Abbildung 02. Nachrichtenfluss mit neuen Funktionen


Dieser Ablauf mag zu kompliziert oder völlig unfunktional erscheinen, aber genau das ist bisher umgesetzt worden.

Wenn man sich Abbildung 02 ansieht, könnte man meinen, dass der EA-Code sehr komplex ist. Aber es ist viel einfacher als das, was viele Leute für einen notwendigen Code für einen EA halten. Vor allem, wenn es sich um einen automatisierten EA handelt. Denken Sie an das Folgende: Der EA generiert eigentlich keine Trades. Es ist lediglich ein Mittel oder Werkzeug für die Kommunikation mit dem Handelsserver. Es reagiert also eigentlich nur auf Auslöser, die auf es angewendet werden.

Autor: Daniel Jose

 

Ich habe ein Problem, das mich verwirrt.

Vielen Dank für diesen wunderbaren Artikel. Ich habe ein Problem, das mich verwirrt. Ich habe einen Code geschrieben, um eine Position zu eröffnen.

Er kann den richtigen Wert zurückgeben, wenn er auf einem Demokonto ausgeführt wird, aber er gibt 0 zurück, wenn er auf einem echten Konto ausgeführt wird.

Mein Ziel ist es, nach dem Eröffnen einer Position das Geschäftsticket zurückzugeben.
//+------------------------------------------------------------------+
//|& nbsp; &nbsp ; Test1.mq5 |
//|& nbsp; Copyright 2023, MetaQuotes Ltd.
//|& nbsp; &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;
//+------------------------------------------------------------------+
//| EA Trade Initialisierungsfunktionen & nbsp; &nbsp ; |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   OpenPosition(ORDER_TYPE_BUY, 0.01, 123456);
//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &nbsp; &nbsp nbsp; |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA-Zitierfunktion & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &nbsp; &nbsp nbsp; |
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &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);
  }


 
Yang Wang #:

Olá, Daniel José

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.

Er kann bei der Ausführung im Demo-Modus den korrekten Wert zurückgeben, bei der Ausführung im realen Modus jedoch 0. Können Sie mir sagen, wo das Problem liegt? á o problema?

Meu objetivo é devolver seu ticket de negociação após abrir uma posição.


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 );
  }
 
Daniel Jose #:

Tente verificar o errouverado que está sendo retornado, adicionando a linha destacada logo abaixo.

Nein, mein Ziel ist es, ein Dealticket zurückzugeben.

Es kann ein Deal-Ticket der Position auf dem Demo-Konto zurückgeben, aber einen Nullwert auf dem Real-Konto, warum?

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);
  }
 
Yang Wang #:

Não, meu objetivo é devolver um bilhete de acordo

Er kann das Ticket für die Position in der Demoversion zurückgeben, in der echten Version jedoch nur den Wert Null, wozu?

Eine Zeile, die Sie auffordert, NÃO É... hinzuzufügen. vou repetir. NÃO É para retornar nenhum valor ... ELA SERVE PARA VERIFICAR O ERRO que está dando ao tentar abririr uma posição ... você nÃO deve usar o valor retornado... você deve verificar o ERRO na tabela de erros... Lesen Sie ein DOKUMENTAÇÃO

 

Hallo, ich verfolge diese Serie von Artikeln. Mein Respekt. Es ist wirklich hilfreich.

Ich teste das Ergebnis und nachdem ich eine Order erstellt habe, lösche ich sie. Aber EA erlaubt es nicht mehr, eine neue Order zu erstellen.

Dieser Codeschnipsel:

 case TRADE_TRANSACTION_ORDER_DELETE :
                         if (trans.order == trans.position) (*manager).PendingToPosition();
                         else (*manager).UpdatePosition(trans.position); // ORDER?
                         break ;

Er verwendet trans.position, die im Falle einer Orderlöschung immer 0 ist. Das ist also der Wert, der an UpdatePosition übergeben wird. Die erste Bedingung sendet ihn direkt an die Return-Anweisung.

Ich habe versucht, das Ticket von trans.order zu übergeben, aber der Code ignoriert es, weil m_position null Daten hat, also ist das Ticket 0 (! = m_Position.Ticket):

Nach dieser. Wenn ich versuche, eine neue Bestellung zu erstellen, hat m_ticketPending den Wert der ersten Bestellung, also wird sie nicht erstellt.

EraseTicketPending wird nicht aufgerufen, denn wenn TRADE_ACTION_REMOVE eintrifft, ist diese Bedingung immer falsch, da request .request.TRADE_ACTION_REMOVE immer falsch ist.

 if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && (request.magic == def_MAGIC_NUMBER))

ist immer falsch, da request.magic 0 ist.

Ich werde untersuchen, ob dies in den nächsten Kapiteln behoben wird.

Mit freundlichen Grüßen

 

Ich glaube, ich habe das Problem gefunden.

Wenn die Orderlöschung von der MT5-Benutzeroberfläche aus durchgeführt wird, ist die magische Zahl 0. Also habe ich die Bedingung geändert in

 if ((request.symbol == _Symbol ) && (result.retcode == TRADE_RETCODE_DONE ) && ((request.magic == def_MAGIC_NUMBER) || request.magic == 0 ))

und es scheint zu funktionieren wie erwartet.

Dateien:
 
Yang Wang #:

Hallo, Daniel Jose.

Vielen Dank für diesen wunderbaren Artikel. Ich habe ein Problem, das mich verwirrt. Ich habe einen Code geschrieben, um eine Position zu eröffnen.

Es kann den richtigen Wert zurückgeben, wenn es auf Demo-Konto ausgeführt wird, aber es gibt 0 zurück, wenn es auf einem realen Konto ausgeführt wird, können Sie mir helfen, zu beraten, wo das Problem ist?

Mein Ziel ist es, nach dem Eröffnen einer Position das Geschäftsticket zurückzugeben.


Diese Funktion hat eine offene Position und gibt DEAL TICKET zurück:

//+------------------------------------------------------------------+
//|& nbsp; &nbsp ; Test1.mq5 |
//|& nbsp; Copyright 2023, MetaQuotes Ltd.
//|& nbsp; &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;
//+------------------------------------------------------------------+
//| EA Trade Initialisierungsfunktionen & nbsp; &nbsp ; |
//+------------------------------------------------------------------+
int OnInit()
  {
//---
   EventSetMillisecondTimer(1);
   if(!m_symbol.Name(_Symbol)) // setzt den Symbolnamen
      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; &nbsp; &nbsp nbsp; |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   EventKillTimer();
  }
//+------------------------------------------------------------------+
//| EA-Zitierfunktion & nbsp; &nbsp ; ||
//+------------------------------------------------------------------+
void OnTick()
  {
//---
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &nbsp; &nbsp nbsp; |
//+------------------------------------------------------------------+
void OnTimer()
  {
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &nbsp; &nbsp nbsp; |
//+------------------------------------------------------------------+
bool RefreshRates(void)
  {
//--- Aktualisierungsraten
   if(!m_symbol.RefreshRates())
     {
      Print("RefreshRates error");
      return(false);
     }
//--- Schutz gegen den Rückgabewert "Null"
   if(m_symbol.Ask() == 0 || m_symbol.Bid() == 0)
      return(false);
//---
   return(true);
  }
//+------------------------------------------------------------------+
//|& nbsp; &nbsp nbsp; &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);
  }
//+------------------------------------------------------------------+
 
OnTradeTransaction ist großartig, aber ich habe ein echtes Problem.
Ich fing an, es zu verwenden, um Ereignisse (Öffnen einer Position, Schließen, Ändern) zu fangen, wie ich es vorher in MT4 (Überprüfung ständig die Positionen zu erraten, was passiert ist). In dieser Hinsicht ist der MT5-Ansatz sehr sauber.
ABER WAS GEHT, WENN DER EA WÄHREND EINER STUNDE ABGESCHALTET ODER AUSGESCHALTET IST: Er erhält natürlich keine Ereignisse, aber wenn er neu startet, erhält er nicht die Ereignisse, die er während einer Stunde durcheinander gebracht hat. Also, um zu erraten, was passiert ist, wird es brauchen, um die alte MT4 Weg durch die Analyse der Positionen zu tun, um zu erraten, was passiert ist. Um dieses Problem zu lösen, muss ich die 2 Wege zur Erkennung von Ereignissen beibehalten: den MT5 Weg und den MT4 Weg als Backup.
 
OnTradeTransaction braucht bis zu 5 Sekunden, um Ereignisse bei schwebenden Aufträgen (Änderungen und Löschungen) zu erkennen. Ist das normal?
Bei Marktpositionen geschieht dies sofort.
 
Gad Benisty OnTradeTransaction ist großartig, aber ich habe ein echtes Problem. Ich fing an, es zu verwenden, um Ereignisse (Öffnen einer Position, Schließen, Ändern) zu fangen, wie ich zuvor in MT4 (Überprüfung ständig die Positionen zu erraten, was passiert ist). In dieser Hinsicht ist der MT5-Ansatz sehr sauber. ABER WAS GEHT, WENN DER EA WÄHREND EINER STUNDE ABGESCHALTET ODER AUSGESCHALTET IST: er wird natürlich keine Ereignisse erhalten, aber wenn er neu startet, wird er die Ereignisse, die er während einer Stunde durcheinander gebracht hat, nicht erhalten. Also, um zu erraten, was passiert ist, wird es brauchen, um die alte MT4 Weg durch die Analyse der Positionen zu tun, um zu erraten, was passiert ist. Um dieses Problem zu lösen, muss ich die 2 Wege zur Erkennung von Ereignissen beibehalten: den MT5 Weg und den MT4 Weg als Backup.

Ich stimme zu... deshalb wird während des Starts des Expert Advisors eine Überprüfung der Positionen oder ausstehenden Aufträge durchgeführt. Aber dies wird in einem Artikel ein wenig weiter in dieser gleichen Sequenz gesehen.

Automatisierte Übersetzung durch den Moderator