web-dev-qa-db-ja.com

Metatrader 4アラートまたはEメールインジケーターシグナルをエキスパートアドバイザーに変換して取引を開始するにはどうすればよいですか?

私は取引を行うためにインジケーターを使用しています。インジケーターを開発しなかったので、.ex4ファイルにしかアクセスできません。オープントレードへのアラートまたは電子メールシグナルで、テイクプロフィット、オープントレード、ストップロスの値を抽出するにはどうすればよいですか?以下の電子メールとアラート信号のサンプルを参照してください。

enter image description here

enter image description here

7
iGetIt

これは、_kernel32.dll_を使用してログファイルを_./MQL4/Logs_から_./MQL4/Files_にコピーするネイティブMQLソリューションの実例scriptです。 LogSignalParser抽象基本クラスはサブクラス化する必要があり、virtual bool parse()メソッドの実装が必要です。

編集:@TenOutOfTenは、ログファイル内の次の行形式を解析する方法の実用的な例を求めています。

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

ステップ1:_LogParser.mqh_を意味のある場所に保存します。

_//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);
}
_

ステップ2:LogSignalParserクラスをサブクラス化し、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;
}
_

ステップ3:MQLプログラムで使用(サンプルスクリプト)

_#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

インジケーターもAlert関数を介してデータを送信しているため、メールからデータを取得する必要はありません。アラートは、.\MQL4\Logsテキストファイルの*.logディレクトリに記録されます。 win32を使用してログを読み取るMQLを作成し、MQLで独自のパーサーを作成できます。

もう1つのオプションは、ログファイルをスキャンして解析し、EAがアクセスできるcsvに結果を書き込むウォッチドッグスクリプトを作成することです。この方法の利点は、MQLソリューションと比較して開発が非常に簡単であり、すべてのシンボルに対して機能するため、複数のEAが同時にログ書き込みcsvを読み取ろうとする潜在的な競合状態を回避できることです。

これは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 __name__ == '__main__':
    main()
2
nicholishen

MT4はあなたのメールを読むことができません。電子メール、Java.Mail.API、Pyhton、またはその他のものを読むには、他のツールまたはより普遍的な言語を使用する必要があります。電子メールを読み、フォーマットが正しく、期待する送信者からのものであることを確認してから、MT4で使用できるファイル(C:\ Users\UserName\AppData\Roaming \)にメッセージを書き留めます。 MetaQuotes\Terminal\12345678E7E35342DB4776F5AE09D64B\MQL4\Files)または共通フォルダー(C:\ Users\User1\AppData\Roaming\MetaQuotes\Terminal\Common\Files)。次に、MQL4ドキュメントのFileSearchNext() functionと example を使用して、MT4アプリケーションからファイルを読み取ります。ファイルを読み取った後、String functions でファイルを解析し、OrderSend()リクエストを作成する必要があります(おそらく入力を確認し、ロジックでロボットが取引を送信できることを確認してください。許可されたオープントレード、取引時間、その他のロジックの最大値に達しました)。

0
Daniel Kniaz