一昨日のこと、MT4から取引履歴をCSVに落とそうとして、いつものようにStatementToCSVを稼働させましたが、、、
おや?明細が1行で途切れてしまう。
悪名高い、zero divideですか。。。
これ、Pepperstoneで動かすと起きないんですけど、MyfXXXXXXで動かすと起きてしまうんですよ。
MT4の標準関数から、ブローカー設定(レートの小数点以下桁数)を取得する処理のところで0桁と返って来てしまい、pips単位に逆算するときに0割りが起きてしまっています。
以前は、XAU/USDのみで同事象が起きていましたが、ここ最近は、EUR/CADやXXX/JPYで起きてしまい、ちょっと使い物にならなくなっていました。
というところで、対策更新です。
流石に、成績集計に致命的な問題となってしまうので、こればっかりは。。。
いつもの場所に掲載すると共に、このページにも概要やソースコードを記録しておきます。
いつもの通り、ご利用は自由です。。。
対策方法:
ブローカーから、特定の通貨レートの小数点桁数が取得できない場合のハンドリングを追加。
具体的には、MarketInfo(OrderSymbol(), MODE_DIGITS)が0を返した場合、小数点以下0桁ですの意味となり、そんなことあり得ないので
ここを起点に、ブローカーからの取得エラーとみなす。
上記の場合は、ソースコード中にあらかじめ標準的な小数点以下5桁レートのブローカーの設定を定義し、
その値を使用することで0割エラーを回避し、且つ処理結果をまっとうなものにする。
//+------------------------------------------------------------------+ //| StatementToCSV.mq4 | //| Copyright 2014, Life with FX | //| http://lifewithfx.jp | //+------------------------------------------------------------------+ #property copyright "Copyright 2014, Life with FX" #property link "http://lifewithfx.jp" #property version "1.40" #property strict #property show_inputs extern string CSVOutputFolder = "-- MT4 MQL4/Files folder --"; extern bool OutputRecordDescendingOrder = false; extern bool OutputHeaderRecord = true; extern string ReportPeriod = "-- PeriodFilter: Order close time base --"; extern bool UsePeriodFilter = false; extern int ReportFromDate = 20140331; extern int ReportToDate = 20159999; //+------------------------------------------------------------------+ //| Script program start function | //+------------------------------------------------------------------+ int OnStart() { int hFile = -1; int historyTotal = OrdersHistoryTotal(); if(historyTotal <= 0) { Print("No History Data. Skip process..."); return(0); } int ticket[]; ArrayResize(ticket, historyTotal); ArrayInitialize(ticket, -1); for(int i=0; i<historyTotal; i++) { if(OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) { switch(OrderType()) { case OP_BUY: case OP_SELL: ticket[i] = OrderTicket(); break; default: ticket[i] = -1; } } } // output filename StatementCSV_YYYYMMDD_HHMM.csv string fileName = "StatementCSV_" + Year(); if(Month() < 10) { fileName = fileName + "0" + Month(); } else { fileName = fileName + Month(); } if(Day() < 10) { fileName = fileName + "0" + Day() + "_"; } else { fileName = fileName + Day() + "_"; } if(Hour() < 10) { fileName = fileName + "0" + Hour(); } else { fileName = fileName + Hour(); } if(Minute() < 10) { fileName = fileName + "0" + Minute(); } else { fileName = fileName + Minute(); } fileName = fileName + ".csv"; Print("output filename: " + fileName); //get handle hFile = FileOpen(fileName, FILE_BIN|FILE_WRITE, ","); if(hFile < 0) { Print("error abort: output file creation error!!"); return(-1); } // CSV Record Header string header = "Ticket,OrderType,OrderSymbol,OrderLots,OrderOpenTime,OrderOpenPrice,OrderCloseTime,OrderClosePrice,OrderProfitInPips,OrderCommission,OrderSwap,OrderProfit,TradeProfit,OrderMagicNumber,OrderComment,OrderCommentShort" + "\n"; if (OutputHeaderRecord) { FileWriteString(hFile, header, StringLen(header)); } const string ITEM_SEPARATOR = ","; int startIdx; int idxStep; int ordersLastIdx = historyTotal - 1; double pipScale; double pipScaleDigits; double takeprice; double takepips; if (!OutputRecordDescendingOrder) { startIdx = 0; idxStep = 1; } else { startIdx = ordersLastIdx; idxStep = -1; } for (int i = startIdx; !(i < 0 || ordersLastIdx < i) ; i += idxStep) { if(ticket[i] != -1) { if(OrderSelect(ticket[i], SELECT_BY_TICKET, MODE_HISTORY)) { // PeriodRangeFilter string closeDateStr = TimeToStr(OrderCloseTime(), TIME_DATE); int closeDateInt = StrToInteger(StringSubstr(closeDateStr, 0, 4) + StringSubstr(closeDateStr, 5, 2) + StringSubstr(closeDateStr, 8, 2)); if (!UsePeriodFilter) { // OK } else if (ReportFromDate <= closeDateInt && closeDateInt <= ReportToDate) { // OK } else { continue; } // scale setting if (MarketInfo(OrderSymbol(), MODE_DIGITS) != 0) { pipScale = MarketInfo(OrderSymbol(), MODE_POINT) * 10; pipScaleDigits = MarketInfo(OrderSymbol(), MODE_DIGITS); } else { pipScale = getPipScale(OrderSymbol()); pipScaleDigits =getPipScaleDigits(OrderSymbol()); } string output = ticket[i] + ITEM_SEPARATOR; switch(OrderType()) { case OP_BUY: output = output + "BUY" + ITEM_SEPARATOR; break; case OP_SELL: output = output + "SELL" + ITEM_SEPARATOR; break; default: output = output + "" + ITEM_SEPARATOR; } output = output + OrderSymbol() + ITEM_SEPARATOR; output = output + DoubleToStr(OrderLots(),2) + ITEM_SEPARATOR; output = output + TimeToStr(OrderOpenTime()) + ITEM_SEPARATOR; output = output + NormalizeDouble(OrderOpenPrice(), pipScaleDigits) + ITEM_SEPARATOR; output = output + TimeToStr(OrderCloseTime()) + ITEM_SEPARATOR; output = output + NormalizeDouble(OrderClosePrice(), pipScaleDigits) + ITEM_SEPARATOR; switch(OrderType()) { case OP_BUY: takeprice = (OrderClosePrice() / pipScale) - (OrderOpenPrice() / pipScale); takepips = NormalizeDouble(takeprice, pipScaleDigits); output = output + takepips + ITEM_SEPARATOR; break; case OP_SELL: takeprice = (OrderOpenPrice() / pipScale) - (OrderClosePrice() / pipScale); takepips = NormalizeDouble(takeprice, pipScaleDigits); output = output + takepips + ITEM_SEPARATOR; break; } output = output + NormalizeDouble(OrderCommission(), 2) + ITEM_SEPARATOR; output = output + NormalizeDouble(OrderSwap(), 2) + ITEM_SEPARATOR; output = output + OrderProfit() + ITEM_SEPARATOR; output = output + (NormalizeDouble(OrderSwap(), 2) + NormalizeDouble(OrderCommission(), 2) + OrderProfit()) + ITEM_SEPARATOR; output = output + OrderMagicNumber() + ITEM_SEPARATOR; output = output + OrderComment() + ITEM_SEPARATOR; output = output + StringSubstr(OrderComment(), 0, 2); output = output + "\n"; FileSeek(hFile, 0, SEEK_END); FileWriteString(hFile, output, StringLen(output)); } } } if(0 < hFile) { FileClose(hFile); } Print ("works fine: finished!!"); return(0); } double getPipScale(string symbol) { if (symbol == "EURUSD") { return 0.0001;} else if (symbol == "AUDCAD") { return 0.0001;} else if (symbol == "AUDCHF") { return 0.0001;} else if (symbol == "AUDJPY") { return 0.01;} else if (symbol == "AUDNZD") { return 0.0001;} else if (symbol == "AUDSGD") { return 0.0001;} else if (symbol == "AUDUSD") { return 0.0001;} else if (symbol == "CADCHF") { return 0.0001;} else if (symbol == "CADJPY") { return 0.01;} else if (symbol == "CHFJPY") { return 0.01;} else if (symbol == "EURAUD") { return 0.0001;} else if (symbol == "EURCAD") { return 0.0001;} else if (symbol == "EURCHF") { return 0.0001;} else if (symbol == "EURGBP") { return 0.0001;} else if (symbol == "EURJPY") { return 0.01;} else if (symbol == "EURNZD") { return 0.0001;} else if (symbol == "GBPAUD") { return 0.0001;} else if (symbol == "GBPCAD") { return 0.0001;} else if (symbol == "GBPCHF") { return 0.0001;} else if (symbol == "GBPJPY") { return 0.01;} else if (symbol == "GBPNZD") { return 0.0001;} else if (symbol == "GBPUSD") { return 0.0001;} else if (symbol == "NZDJPY") { return 0.01;} else if (symbol == "NZDUSD") { return 0.0001;} else if (symbol == "USDCAD") { return 0.0001;} else if (symbol == "USDCHF") { return 0.0001;} else if (symbol == "USDHKD") { return 0.0001;} else if (symbol == "USDJPY") { return 0.01;} else if (symbol == "USDMXN") { return 0.0001;} else if (symbol == "USDPLN") { return 0.0001;} else if (symbol == "USDSEK") { return 0.0001;} else if (symbol == "USDSGD") { return 0.0001;} else if (symbol == "USDZAR") { return 0.0001;} else if (symbol == "XAGEUR") { return 0.01;} else if (symbol == "XAGUSD") { return 0.01;} else if (symbol == "XAUEUR") { return 0.1;} else if (symbol == "XAUUSD") { return 0.1;} else if (symbol == "ZARJPY") { return 0.01;} else { return 0.0001; } } double getPipScaleDigits(string symbol) { if (symbol == "EURUSD") { return 5;} else if (symbol == "AUDCAD") { return 5;} else if (symbol == "AUDCHF") { return 5;} else if (symbol == "AUDJPY") { return 3;} else if (symbol == "AUDNZD") { return 5;} else if (symbol == "AUDSGD") { return 5;} else if (symbol == "AUDUSD") { return 5;} else if (symbol == "CADCHF") { return 5;} else if (symbol == "CADJPY") { return 3;} else if (symbol == "CHFJPY") { return 3;} else if (symbol == "EURAUD") { return 5;} else if (symbol == "EURCAD") { return 5;} else if (symbol == "EURCHF") { return 5;} else if (symbol == "EURGBP") { return 5;} else if (symbol == "EURJPY") { return 3;} else if (symbol == "EURNZD") { return 5;} else if (symbol == "GBPAUD") { return 5;} else if (symbol == "GBPCAD") { return 5;} else if (symbol == "GBPCHF") { return 5;} else if (symbol == "GBPJPY") { return 3;} else if (symbol == "GBPNZD") { return 5;} else if (symbol == "GBPUSD") { return 5;} else if (symbol == "NZDJPY") { return 3;} else if (symbol == "NZDUSD") { return 5;} else if (symbol == "USDCAD") { return 5;} else if (symbol == "USDCHF") { return 5;} else if (symbol == "USDHKD") { return 5;} else if (symbol == "USDJPY") { return 3;} else if (symbol == "USDMXN") { return 5;} else if (symbol == "USDPLN") { return 5;} else if (symbol == "USDSEK") { return 5;} else if (symbol == "USDSGD") { return 5;} else if (symbol == "USDZAR") { return 5;} else if (symbol == "XAGEUR") { return 3;} else if (symbol == "XAGUSD") { return 3;} else if (symbol == "XAUEUR") { return 2;} else if (symbol == "XAUUSD") { return 2;} else if (symbol == "ZARJPY") { return 3;} else { return 5; } }