web-dev-qa-db-fra.com

Comment puis-je convertir l'alerte Metatrader 4 ou l'indicateur de courrier électronique en Expert Advisor pour ouvrir des trades?

J'ai utilisé un indicateur pour effectuer des transactions. Je n'ai pas développé l'indicateur, donc je n'ai accès qu'au fichier .ex4. Comment puis-je extraire les prises de profit, ouvrir des transactions et arrêter les pertes dans les alertes ou les signaux de courrier électronique pour ouvrir des transactions? Veuillez consulter un exemple des courriels et des alertes ci-dessous.

 enter image description here

 enter image description here

7
iGetIt

Voici un exemple de travail script d'une solution MQL native qui utilise kernel32.dll pour copier le fichier journal de ./MQL4/Logs à ./MQL4/Files. La classe de base abstraite LogSignalParser doit être sous-classée et nécessite l'implémentation de la méthode virtual bool parse().

Edit: @TenOutOfTen souhaiterait un exemple pratique expliquant comment analyser le format de ligne suivant dans un fichier journal:

0 02:20:00.874 SuperIndicator USDCAD,M5: Alert: USDCAD, M5: Super Indicator SELL @ 1.29136, TP 1.28836, SL 1.29286

Étape 1: Enregistrez le LogParser.mqh dans un sens.  

//LogParser.mqh

#property strict
#include <stdlib.mqh>
#include <Arrays\ArrayString.mqh>
#include <Arrays\ArrayObj.mqh>
#import "kernel32.dll"
   bool CopyFileW(string lpExistingFileName,
                  string lpNewFileName,
                  bool   bFailIfExists);
#import
//+------------------------------------------------------------------+
//|                                                              
//+------------------------------------------------------------------+
class Signal : public CObject
{
public:
   string            symbol;
   datetime          signal_time;
   int               order_type;
   double            price_entry;
   double            price_sl;
   double            price_tp;
   virtual int Compare(const CObject *node,const int mode=0) const override
   {
      const Signal *other=node;
      if(this.signal_time>other.signal_time)
         return 1;
      if(this.signal_time<other.signal_time)
         return -1;
      return 0;
   }
   string to_string()
   {
      return StringFormat("%s - %s(%s) @ %.5f, SL=%.5f, TP=%.5f",
         signal_time,
         symbol,
         order_type==OP_BUYLIMIT ? "BUY" : "SELL",
         price_entry,
         price_sl,
         price_tp
      );
   }
};
//+------------------------------------------------------------------+
//|Vector-like collection                                                          
//+------------------------------------------------------------------+
class SignalList : public CArrayObj
{
   public: Signal *operator[](int i){return this.At(i);}
};
//+------------------------------------------------------------------+
//|Abstract abse class: the parse method must be implemented in subclass                                                             
//+------------------------------------------------------------------+
class LogSignalParser : public CObject
{
protected:
   CArrayString      m_rows;
   SignalList        m_signals;
   string            m_log_file_name;
   string            m_ind_name;
public:
                     LogSignalParser(string indicator_name);

                     // parse method must be overridden!
   virtual bool      parse() = 0;
   int               Total();
   Signal           *operator[](int i);
protected:
   bool              _copy_log();
   int               _open_log();
   bool              _parse_rows();
};
//+------------------------------------------------------------------+
LogSignalParser::LogSignalParser(string indicator_name)
{
   m_log_file_name="copy_log.log";
   m_ind_name=indicator_name;
}
//+------------------------------------------------------------------+
bool LogSignalParser::_copy_log(void)
{
   MqlDateTime t;
   TimeLocal(t);
   string data_path = TerminalInfoString(TERMINAL_DATA_PATH)+"\\MQL4";
   string logs_path = data_path + "\\Logs\\";
   string dest_file = data_path + "\\Files\\" + m_log_file_name;
   string log_file=logs_path+StringFormat("%d%02d%02d.log",
                                          t.year,t.mon,t.day);
   return CopyFileW(log_file, dest_file, false);
}
//+------------------------------------------------------------------+
bool LogSignalParser::_parse_rows()
{
   if(!this._copy_log())
      return false;
   int h= this._open_log();
   if(h == INVALID_HANDLE)
      return false;
   m_rows.Clear();
   while(!FileIsEnding(h)){
      string row=FileReadString(h);
      if(StringFind(row,"Alert:") >= 0 && StringFind(row,m_ind_name) >= 0)
         m_rows.Add(row);
   }
   m_rows.Sort();
   FileClose(h);
   return true;
}
//+------------------------------------------------------------------+
int LogSignalParser::_open_log(void)
{
   return FileOpen(m_log_file_name,
      FILE_TXT|FILE_READ|FILE_SHARE_READ|FILE_SHARE_WRITE);
}
//+------------------------------------------------------------------+
int LogSignalParser::Total(void)
{
   return m_signals.Total();
}
//+------------------------------------------------------------------+
Signal* LogSignalParser::operator[](int i)
{
   return m_signals.At(i);
}

Étape 2: Sous-classez la classe LogSignalParser et remplacez parse

//SuperIndicatorParser.mqh
#property strict
#include "LogParser.mqh"
//+------------------------------------------------------------------+
class SuperIndicatorParser : public LogSignalParser
{ 
public:
   SuperIndicatorParser():LogSignalParser("SuperIndicator"){}
   virtual bool parse() override;
};
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+
bool SuperIndicatorParser::parse() override
{
   if(!this._parse_rows())
      return false;
   m_signals.Clear();
   MqlDateTime local;
   TimeLocal(local);
   for(int i=m_rows.Total()-1; i>=0; i--)
   {
      string row=m_rows[i];
      MqlDateTime log_time;
      TimeToStruct(StringToTime(StringSubstr(row, 2, 12)), log_time);
      log_time.year = local.year;
      log_time.mon = local.mon;
      log_time.day = local.day;
      datetime time = StructToTime(log_time); 
      row = StringSubstr(row, StringFind(row, m_ind_name) + StringLen(m_ind_name) + 1);
      StringReplace(row, ",", " ");
      string parts[];
      StringSplit(row, ' ', parts);
      int len = ArraySize(parts);
      string debug = "";
      for(int k=0;k<len;k++)
         debug += "|" + parts[k];
      if(len != 17)
         continue;
      Signal *s      = new Signal();
      s.signal_time  = time;
      s.symbol       = parts[0];
      s.order_type   = parts[8] == "BUY" ? OP_BUYLIMIT : OP_SELLLIMIT;
      s.price_entry  = double(parts[10]);
      s.price_tp     = double(parts[13]);
      s.price_sl     = double(parts[16]);
      m_signals.Add(s);
   }
   m_signals.Sort();
   return true;
}

Étape 3: Utilisation dans le programme MQL (exemple de script)

#property strict
#include "SuperIndicatorParser.mqh"
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
   SuperIndicatorParser parser;
   if(parser.parse()){
      for(int i=parser.Total()-1; i>=0; i--){
         Signal *s = parser[i];
         int ticket = OrderSend(
            s.symbol, s.order_type, 0.1, 
            s.price_entry, 0, s.price_sl, s.price_tp 
         ); 
         if(ticket < 0){
            Print(_LastError);
         }
      }
   }     
}
4
nicholishen

Il n'est pas nécessaire d'extraire les données de votre courrier électronique car l'indicateur envoie également les données via la fonction Alert. Les alertes sont consignées dans le répertoire .\MQL4\Logs dans un fichier texte *.log. Vous pouvez écrire des MQL qui utilisent win32 pour lire le journal, puis créer votre propre analyseur en MQL. 

Une autre option consiste à écrire un script de surveillance pour analyser et analyser le fichier journal et à écrire les résultats dans un fichier csv auquel le responsable de l'évaluation peut accéder. L'avantage de cette méthode est sa facilité de développement par rapport à une solution MQL. Comme elle fonctionne pour tous les symboles, elle évite une situation de concurrence critique dans laquelle plusieurs agents d'exécution tentent de lire le journal en écriture csv simultanément. 

Voici un exemple écrit en Python. 

import csv
import re
import time
from datetime import datetime
from pathlib import Path

MQL_DATA_PATH = Path(
    'C:/Users/user/Desktop/MT-TEST/Vanilla-MT4-v0_0_2/MT4/MQL4'
)
OUTPUT_FILENAME = 'signals.csv'

signal_pattern = re.compile(r'''# regex - verbose mode
    (?P<time>\d\d:\d\d:\d\d).*? # time stamp
    (?P<symbol>[A-Z]{6}\w*),.*? # symbol with ECN suffix
    (?P<type>BUY|SELL).*?       # BUY or SELL command
    (?P<price>\d+\.\d+).*?      # execution price
    (?P<tp>\d+\.\d+).*?         # takeprofit 
    (?P<sl>\d+\.\d+)            # stoploss
''', re.VERBOSE)


def log_to_csv():
    date = datetime.now()
    log_file = MQL_DATA_PATH / 'Logs' / f'{date.strftime("%Y%m%d")}.log'
    with open(log_file) as f:
        log_entries = f.read()
    signals = [s.groupdict() for s in signal_pattern.finditer(log_entries)]
    for signal in signals:
        # correct time to MQL datetime
        signal['time'] = f"{date.strftime('%Y.%m.%d')} {signal['time']}"
    csv_file = MQL_DATA_PATH / 'Files' / OUTPUT_FILENAME
    with open(csv_file, 'w') as f:
        writer = csv.DictWriter(f,
            fieldnames=('time', 'symbol', 'type', 'price', 'tp', 'sl',),
            lineterminator='\n',
        )
        writer.writerows(signals)


def main():
    print(f'Watching MQL log and saving signals to {OUTPUT_FILENAME}')
    print('Press Ctrl+C to exit')
    while True:
        try:
            log_to_csv()
            print(datetime.now().strftime('%Y.%m.%d %H:%M:%S'), end='\r')
            time.sleep(5)
        except KeyboardInterrupt:
            exit()


if __== '__main__':
    main()
2
nicholishen

MT4 ne peut pas lire vos emails. Vous devez utiliser d'autres outils ou un langage plus universel pour lire vos emails, Java.Mail.API ou Pyhton, ou autre chose . Lisez l'email, assurez-vous que le format est correct et qu'il provient de l'expéditeur que vous avez attendez, puis déposez le message dans un fichier disponible pour MT4 - soit son propre dossier (C:\Utilisateurs\Nom d'utilisateur\AppData\Roaming\MetaQuotes\Terminal\12345678E7E35342DB4776F5AE09D64B\MQL4\Files) ou dossier commun (C: Utilisateurs\User1\AppData\Roaming\MetaQuotes\Terminal\Common\Files). Lisez ensuite le fichier à partir de l'application MT4 à l'aide de la fonction FileSearchNext() et exemple dans la documentation MQL4. Après avoir lu le fichier, vous devez l’analyser avec String functions , et créer une demande OrderSend () (vérifiez l’entrée et vérifiez que votre logique permet à votre robot d’envoyer une transaction. Par exemple, vous n’avez pas atteint le maximum. nombre de transactions ouvertes autorisées, temps de négociation, autre logique).

0
Daniel Kniaz