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

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

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

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

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

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

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

001//+------------------------------------------------------------------+
002//|                                           OutputTradeHistory.mq4 |
003//|                                     Copyright (c) 2015, りゅーき |
004//|                                            https://autofx100.com/ |
005//+------------------------------------------------------------------+
006#property copyright "Copyright (c) 2015, りゅーき"
007#property link      "https://autofx100.com/"
008#property version   "1.0"
009#property show_inputs
010 
011//+------------------------------------------------------------------+
012//| パラメータ設定情報                                               |
013//+------------------------------------------------------------------+
014extern bool     DisplayHeader      = false;
015extern datetime CloseTimeFrom      = NULL;
016extern datetime CloseTimeTo        = D'2038.01.01';
017extern string   FileName           = "";
018extern string   Help               = "true: AND    false: OR";
019extern bool     FilterSwitch       = true;
020extern string   CommentFilter1     = "";
021extern string   CommentFilter2     = "";
022extern string   CommentFilter3     = "";
023extern string   MagicNumberFilter1 = "";
024extern string   MagicNumberFilter2 = "";
025extern string   MagicNumberFilter3 = "";
026 
027//+------------------------------------------------------------------+
028//| Script program start function                                    |
029//+------------------------------------------------------------------+
030void OnStart()
031{
032  int historyTotal = OrdersHistoryTotal();
033 
034  // トレード履歴の有無チェック
035  if(historyTotal <= 0){
036    Print("トレード履歴データはありません。");
037    return;
038  }
039 
040  int ticket[];
041 
042  ArrayResize(ticket, historyTotal);
043  ArrayInitialize(ticket, -1);
044 
045  for(int i = 0; i < historyTotal; i++){
046    if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)){
047      if(OrderType() == OP_BUY || OrderType() == OP_SELL){
048        ticket[i] = OrderTicket();
049        OrderPrint();
050      }else{
051        Print("OK");
052        ticket[i] = -1;
053      }
054    }
055  }
056 
057  // ファイル名
058  string ymdhms = replace(TimeToStr(TimeLocal(), TIME_DATE|TIME_SECONDS), ":", ".");
059 
060  if(FileName == ""){
061    string flNm = "TradeHistory_" + ymdhms + ".csv";
062  }else{
063    flNm = "TradeHistory_" + FileName + "_" + ymdhms + ".csv";
064  }
065 
066  Print("flNm = ", flNm);
067 
068  int fileHandle = FileOpen(flNm, FILE_CSV|FILE_WRITE, ",");
069 
070  if(fileHandle < 0){
071    Print("ファイルハンドルがありません。");
072    return;
073  }
074 
075  // ヘッダー出力
076  if(DisplayHeader){
077    FileWrite(fileHandle,
078              "注文番号",
079              "マジックナンバー",
080              "コメント",
081              "通貨ペア",
082              "取引種別",
083              "ロットサイズ",
084              "約定時刻",
085              "約定価格",
086              "決済時刻",
087              "決済価格",
088              "手数料",
089              "スワップ損益",
090              "トレード損益",
091              "総損益",
092              "獲得Pips"
093             );
094  }
095 
096  for(i = 0; i < historyTotal; i++){
097    if(ticket[i] != -1){
098      if(OrderSelect(ticket[i], SELECT_BY_TICKET, MODE_HISTORY)){
099 
100        int matchFlg = 0;
101 
102        //出力フィルタリング
103        if(FilterSwitch){ //AND
104 
105          if(MagicNumberFilter1 == "" && MagicNumberFilter2 == "" && MagicNumberFilter3 == ""){
106            matchFlg = 1;
107          }
108          if(MagicNumberFilter1 != "" && StrToInteger(MagicNumberFilter1) == OrderMagicNumber()){
109            matchFlg = 1;
110          }
111          if(MagicNumberFilter2 != "" && StrToInteger(MagicNumberFilter2) == OrderMagicNumber()){
112            matchFlg = 1;
113          }
114          if(MagicNumberFilter3 != "" && StrToInteger(MagicNumberFilter3) == OrderMagicNumber()){
115            matchFlg = 1;
116          }
117          if(matchFlg == 0){
118            continue;
119          }
120 
121          matchFlg = 0;
122 
123          if(CommentFilter1 == "" && CommentFilter2 == "" && CommentFilter3 == ""){
124            matchFlg = 1;
125          }
126          if(CommentFilter1 != "" && StringFind(OrderComment(), CommentFilter1) != -1){
127            matchFlg = 1;
128          }
129          if(CommentFilter2 != "" && StringFind(OrderComment(), CommentFilter2) != -1){
130            matchFlg = 1;
131          }
132          if(CommentFilter3 != "" && StringFind(OrderComment(), CommentFilter3) != -1){
133            matchFlg = 1;
134          }
135          if(matchFlg == 0){
136            continue;
137          }
138 
139        }else{ //OR
140 
141          if(MagicNumberFilter1 == "" && MagicNumberFilter2 == "" && MagicNumberFilter3 == "" && CommentFilter1 == "" && CommentFilter2 == "" && CommentFilter3 == ""){
142            matchFlg = 1;
143          }
144          if(MagicNumberFilter1 != "" && StrToInteger(MagicNumberFilter1) == OrderMagicNumber()){
145            matchFlg = 1;
146          }
147          if(MagicNumberFilter2 != "" && StrToInteger(MagicNumberFilter2) == OrderMagicNumber()){
148            matchFlg = 1;
149          }
150          if(MagicNumberFilter3 != "" && StrToInteger(MagicNumberFilter3) == OrderMagicNumber()){
151            matchFlg = 1;
152          }
153          if(CommentFilter1 != "" && StringFind(OrderComment(), CommentFilter1) != -1){
154            matchFlg = 1;
155          }
156          if(CommentFilter2 != "" && StringFind(OrderComment(), CommentFilter2) != -1){
157            matchFlg = 1;
158          }
159          if(CommentFilter3 != "" && StringFind(OrderComment(), CommentFilter3) != -1){
160            matchFlg = 1;
161          }
162          if(matchFlg == 0){
163            continue;
164          }
165 
166        }
167 
168        string displayOpenTime  = TimeToStr(OrderOpenTime());
169        string displayCloseTime = TimeToStr(OrderCloseTime());
170 
171        if(StrToTime(displayCloseTime) < CloseTimeFrom || StrToTime(displayCloseTime) > CloseTimeTo){
172          continue;
173        }
174 
175        string oTicket = ticket[i];
176 
177        if(OrderType() == OP_BUY){
178          string oType = "BUY";
179        }else if(OrderType() == OP_SELL){
180          oType = "SELL";
181        }else{
182          oType = "";
183        }
184 
185        double oPlice = OrderOpenPrice();
186        double cPlice = OrderClosePrice();
187 
188        if(StringFind(OrderSymbol(), "JPY") != -1){
189          double points = 0.001;
190        }else{
191          points = 0.00001;
192        }
193 
194        double total = OrderCommission() + OrderSwap() + OrderProfit();
195 
196        int mult = 1;
197        if(Digits == 3 || Digits == 5){
198          mult = 10;
199        }
200 
201        if(OrderType() == OP_BUY){
202          double calcPips = (cPlice - oPlice) / (points * mult);
203        }else if(OrderType() == OP_SELL){
204          calcPips = (oPlice - cPlice) / (points * mult);
205        }
206 
207        FileSeek(fileHandle, 0, SEEK_END);
208 
209        FileWrite(fileHandle,
210                  oTicket,
211                  OrderMagicNumber(),
212                  OrderComment(),
213                  OrderSymbol(),
214                  oType,
215                  OrderLots(),
216                  displayOpenTime,
217                  oPlice,
218                  displayCloseTime,
219                  cPlice,
220                  OrderCommission(),
221                  OrderSwap(),
222                  OrderProfit(),
223                  total,
224                  calcPips
225                 );
226      }
227    }
228  }
229 
230  FileClose(fileHandle);
231 
232  return;
233}
234 
235//+------------------------------------------------------------------+
236//|【関数】文字列置換                                                |
237//|                                                                  |
238//|【引数】 IN OUT  引数名             説明                          |
239//|        --------------------------------------------------------- |
240//|         ○      aTarget            対象文字列                    |
241//|         ○      aSearch            検索文字列                    |
242//|         ○      aReplace           置換文字列                    |
243//|                                                                  |
244//|【戻値】置換された文字列                                          |
245//|                                                                  |
246//|【備考】なし                                                      |
247//+------------------------------------------------------------------+
248string replace(string aTarget, string aSearch, string aReplace = "")
249{
250  string left;
251  string right;
252  int start=0;
253  int rlen = StringLen(aReplace);
254  int nlen = StringLen(aSearch);
255 
256  while(start > -1){
257    start = StringFind(aTarget, aSearch, start);
258    if(start > -1){
259      if(start > 0){
260        left = StringSubstr(aTarget, 0, start);
261      }else{
262        left="";
263      }
264      right = StringSubstr(aTarget, start + nlen);
265      aTarget = left + aReplace + right;
266      start = start + rlen;
267   }
268 }
269 return(aTarget);
270}

使い方は至ってシンプル。通常のスクリプトと同じで、チャートにドラッグ&ドロップして、パラメータを入力すれば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ファイルに出力します。

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

MT4の無料プログラミング講座

メルマガ登録して、MT4のプログラミング講座を無料で受けちゃおう!

超豪華プレゼントも盛りだくさん♪

MT4プログラミングを習得すると、オリジナルEA運用、作成代行、商品販売等、複数の収入源を手に入れられるよ。副業に最適だね!

↓↓↓ 詳細はこちら ↓↓↓

アイキャッチ

>

エターナル・パートナーPRO ~MT4裁量トレード支援ツール~ 「MT4は裁量トレーダーに優しくない」そう思ったことありませんか?もっと快適にトレードするための強力な売買ツールが必要だと考え、開発したのが「エターナル・パートナーPRO」です。元々は自分自身のために開発したツールですので、手抜き無しのガチものです。既に200名近い方に手に取っていただき、喜びの声が続々と届いております。ぜひご覧ください!

CTR IMG