ブログタイトルを「FX自動売買システム開発部」から「autoFX」に変更しました!

トレード履歴をCSVファイルに出力するスクリプト

myfxbookも良いけど、自前で管理する方が何かと便利

EAによるトレード結果を分析することは、EAの稼働継続/停止を判断する上でとても大切です。

MT4の[口座履歴]タブでトレード結果を確認できますが、マジックナンバーは分かりませんし、各トレードについてメモを残したり、任意の期間で抽出したり、何らかの指標を計算したりするのには適していません。レポートも出力できますが、html形式なので手軽に加工できず、分析には不向きです。

トレード結果分析といえば、myfxbookが有名ですね。トレード結果を手軽にグラフィカルに分析できる、便利な無料サービスです。主要な指標は自動で計算してくれますし、オシャレでセンスが良い!私も登録しています。

申し分ないサービスなのですが、他人様が作ったサービスでGUIがあるため、どうしても操作の自由が制限されてしまいます。私は欲しいものを欲しい形で手に入れたい!具体的にはトレード結果を望む形式で自由に取得したい!

というわけで、トレード結果分析に必要なトレード履歴データをCSVファイルとして出力できるスクリプトを作成してみました。その名も「OutputTradeHistory」です。特長はマジックナンバーとオーダー時コメントでフィルタリングできるところです。

//+------------------------------------------------------------------+
//|                                           OutputTradeHistory.mq4 |
//|                                     Copyright (c) 2015, りゅーき |
//|                                            https://autofx100.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright (c) 2015, りゅーき"
#property link      "https://autofx100.com/"
#property version   "1.0"
#property show_inputs

//+------------------------------------------------------------------+
//| パラメータ設定情報                                               |
//+------------------------------------------------------------------+
extern bool     DisplayHeader      = false;
extern datetime CloseTimeFrom      = NULL;
extern datetime CloseTimeTo        = D'2038.01.01';
extern string   FileName           = "";
extern string   Help               = "true: AND    false: OR";
extern bool     FilterSwitch       = true;
extern string   CommentFilter1     = "";
extern string   CommentFilter2     = "";
extern string   CommentFilter3     = "";
extern string   MagicNumberFilter1 = "";
extern string   MagicNumberFilter2 = "";
extern string   MagicNumberFilter3 = "";

//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
{
  int historyTotal = OrdersHistoryTotal();

  // トレード履歴の有無チェック
  if(historyTotal <= 0){
    Print("トレード履歴データはありません。");
    return;
  }

  int ticket[];

  ArrayResize(ticket, historyTotal);
  ArrayInitialize(ticket, -1);

  for(int i = 0; i < historyTotal; i++){
    if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
      if(OrderType() == OP_BUY || OrderType() == OP_SELL){
        ticket[i] = OrderTicket();
        OrderPrint();
      }else{
        Print("OK");
        ticket[i] = -1;
      }
    }
  }

  // ファイル名
  string ymdhms = replace(TimeToStr(TimeLocal(), TIME_DATE|TIME_SECONDS), ":", ".");

  if(FileName == ""){
    string flNm = "TradeHistory_" + ymdhms + ".csv";
  }else{
    flNm = "TradeHistory_" + FileName + "_" + ymdhms + ".csv";
  }

  Print("flNm = ", flNm);

  int fileHandle = FileOpen(flNm, FILE_CSV|FILE_WRITE, ",");

  if(fileHandle < 0){
    Print("ファイルハンドルがありません。");
    return;
  }

  // ヘッダー出力
  if(DisplayHeader){
    FileWrite(fileHandle,
              "注文番号",
              "マジックナンバー",
              "コメント",
              "通貨ペア",
              "取引種別",
              "ロットサイズ",
              "約定時刻",
              "約定価格",
              "決済時刻",
              "決済価格",
              "手数料",
              "スワップ損益",
              "トレード損益",
              "総損益",
              "獲得Pips"
             );
  }

  for(i = 0; i < historyTotal; i++){
    if(ticket[i] != -1){
      if(OrderSelect(ticket[i], SELECT_BY_TICKET, MODE_HISTORY)){

        int matchFlg = 0;

        //出力フィルタリング
        if(FilterSwitch){ //AND

          if(MagicNumberFilter1 == "" && MagicNumberFilter2 == "" && MagicNumberFilter3 == ""){
            matchFlg = 1;
          }
          if(MagicNumberFilter1 != "" && StrToInteger(MagicNumberFilter1) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(MagicNumberFilter2 != "" && StrToInteger(MagicNumberFilter2) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(MagicNumberFilter3 != "" && StrToInteger(MagicNumberFilter3) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(matchFlg == 0){
            continue;
          }

          matchFlg = 0;

          if(CommentFilter1 == "" && CommentFilter2 == "" && CommentFilter3 == ""){
            matchFlg = 1;
          }
          if(CommentFilter1 != "" && StringFind(OrderComment(), CommentFilter1) != -1){
            matchFlg = 1;
          }
          if(CommentFilter2 != "" && StringFind(OrderComment(), CommentFilter2) != -1){
            matchFlg = 1;
          }
          if(CommentFilter3 != "" && StringFind(OrderComment(), CommentFilter3) != -1){
            matchFlg = 1;
          }
          if(matchFlg == 0){
            continue;
          }

        }else{ //OR

          if(MagicNumberFilter1 == "" && MagicNumberFilter2 == "" && MagicNumberFilter3 == "" && CommentFilter1 == "" && CommentFilter2 == "" && CommentFilter3 == ""){
            matchFlg = 1;
          }
          if(MagicNumberFilter1 != "" && StrToInteger(MagicNumberFilter1) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(MagicNumberFilter2 != "" && StrToInteger(MagicNumberFilter2) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(MagicNumberFilter3 != "" && StrToInteger(MagicNumberFilter3) == OrderMagicNumber()){
            matchFlg = 1;
          }
          if(CommentFilter1 != "" && StringFind(OrderComment(), CommentFilter1) != -1){
            matchFlg = 1;
          }
          if(CommentFilter2 != "" && StringFind(OrderComment(), CommentFilter2) != -1){
            matchFlg = 1;
          }
          if(CommentFilter3 != "" && StringFind(OrderComment(), CommentFilter3) != -1){
            matchFlg = 1;
          }
          if(matchFlg == 0){
            continue;
          }

        }

        string displayOpenTime  = TimeToStr(OrderOpenTime());
        string displayCloseTime = TimeToStr(OrderCloseTime());

        if(StrToTime(displayCloseTime) < CloseTimeFrom || StrToTime(displayCloseTime) > CloseTimeTo){
          continue;
        }

        string oTicket = ticket[i];

        if(OrderType() == OP_BUY){
          string oType = "BUY";
        }else if(OrderType() == OP_SELL){
          oType = "SELL";
        }else{
          oType = "";
        }

        double oPlice = OrderOpenPrice();
        double cPlice = OrderClosePrice();

        if(StringFind(OrderSymbol(), "JPY") != -1){
          double points = 0.001;
        }else{
          points = 0.00001;
        }

        double total = OrderCommission() + OrderSwap() + OrderProfit();

        int mult = 1;
        if(Digits == 3 || Digits == 5){
          mult = 10;
        }

        if(OrderType() == OP_BUY){
          double calcPips = (cPlice - oPlice) / (points * mult);
        }else if(OrderType() == OP_SELL){
          calcPips = (oPlice - cPlice) / (points * mult);
        }

        FileSeek(fileHandle, 0, SEEK_END);

        FileWrite(fileHandle,
                  oTicket,
                  OrderMagicNumber(),
                  OrderComment(),
                  OrderSymbol(),
                  oType,
                  OrderLots(),
                  displayOpenTime,
                  oPlice,
                  displayCloseTime,
                  cPlice,
                  OrderCommission(),
                  OrderSwap(),
                  OrderProfit(),
                  total,
                  calcPips
                 );
      }
    }
  }

  FileClose(fileHandle);

  return;
}

//+------------------------------------------------------------------+
//|【関数】文字列置換                                                |
//|                                                                  |
//|【引数】 IN OUT  引数名             説明                          |
//|        --------------------------------------------------------- |
//|         ○      aTarget            対象文字列                    |
//|         ○      aSearch            検索文字列                    |
//|         ○      aReplace           置換文字列                    |
//|                                                                  |
//|【戻値】置換された文字列                                          |
//|                                                                  |
//|【備考】なし                                                      |
//+------------------------------------------------------------------+
string replace(string aTarget, string aSearch, string aReplace = "")
{
  string left;
  string right;
  int start=0;
  int rlen = StringLen(aReplace);
  int nlen = StringLen(aSearch);

  while(start > -1){
    start = StringFind(aTarget, aSearch, start);
    if(start > -1){
      if(start > 0){
        left = StringSubstr(aTarget, 0, start);
      }else{
        left="";
      }
      right = StringSubstr(aTarget, start + nlen);
      aTarget = left + aReplace + right;
      start = start + rlen;
   }
 }
 return(aTarget);
}

使い方は至ってシンプル。通常のスクリプトと同じで、チャートにドラッグ&ドロップして、パラメータを入力すればOKです。MT4インストール先\MQL4\Filesに「TradeHistory_yyyy.mm.dd.csv」というCSVファイルが出力されます。yyyy.mm.ddはサーバーの現在日付です。

本スクリプトを使うにあたっては、事前に[口座履歴]タブの任意の場所で右クリックして、[全履歴]を選択しておいてください。これをやっておかないと、全部出力してくれません。

スクリプトのパラメータ内容は以下の通りです。

パラメータ名説明
DisplayHeader見出しを出力する場合はtrue
CloseTimeFrom出力開始となる決済日時(いつから)
CloseTimeTo出力終了となる決済日時(いつまで)
FilterSwitch以下のマジックナンバーとコメントの両方に一致するものだけを出力する場合(AND条件の場合)はtrue、どちらかに一致するものを出力する場合(OR条件の場合)はfalse
MagicNumberFilter1絞込み対象のマジックナンバー1
MagicNumberFilter2絞込み対象のマジックナンバー2
MagicNumberFilter3絞込み対象のマジックナンバー3
CommentFilter1絞込み対象のコメント1(部分一致)
CommentFilter2絞込み対象のコメント2(部分一致)
CommentFilter3絞込み対象のコメント3(部分一致)

FilterSwitchの説明が恐らく「ナンノコッチャ?」って感じだと思いますので、補足します。

MagicNumberFilter1~MagicNumberFilter3はそれぞれがOR条件、CommentFilter1~CommentFilter3もそれぞれがOR条件の関係になっています。

例えば、MagicNumberFilter1=111、MagicNumberFilter2=222と入力した場合は、マジックナンバーが111または222のトレード履歴データを取得し、CSVファイルに出力します。

FilterSwitch=true、MagicNumberFilter1=111、CommentFilter1=TESTと入力した場合は、マジックナンバーが111でかつ注文時のコメントがTESTの文字列を含んでいるトレード履歴データを取得し、CSVファイルに出力します。

FilterSwitch=false、MagicNumberFilter1=111、CommentFilter1=TESTと入力した場合は、マジックナンバーが111または注文時のコメントがTESTの文字列を含んでいるトレード履歴データを取得し、CSVファイルに出力します。

FilterSwitch=true、MagicNumberFilter1=11、MagicNumberFilter1=22、CommentFilter1=Fと入力した場合は、マジックナンバーが11または22でかつ注文時のコメントがFの文字列を含んでいるトレード履歴データを取得し、CSVファイルに出力します。

自作だとこんな感じで自分の思い通りの結果を得ることができて大変便利です!

MQL4プログラミングの最新記事8件

>完全放ったらかしEA 「AutoEndlessCatchRange」

完全放ったらかしEA 「AutoEndlessCatchRange」

「本業が忙しい!」「でも資産運用したい!」そんなあなたに最適なEAです。兼業トレーダーの方はチャートを毎日みて分析してトレードする時間はなかなか確保できないものです。トレードは本EAに任せて、本業やプライベートの時間をもっと増やしませんか?元々は自分自身のために開発したEAですので、手抜き無しのガチものです。

CTR IMG