StatementToCSVのメンテナンス

一昨日のこと、MT4から取引履歴をCSVに落とそうとして、いつものようにStatementToCSVを稼働させましたが、、、

 

おや?明細が1行で途切れてしまう。

 

0822-zerod

 

 

 

 

 

 

悪名高い、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; }  
}

 

 

コメントを残す