Snippets

Daniel Sokolowski MetaTrader Export Trade History to CSV

Created by Daniel Sokolowski last modified
/*
DS_ExportHistsoryToCSV.mp4
##########################1

Exports buy/sell orders to a `%AppData%\Roaming\MetaQuotes\Terminal\<INSTLALL ID>\MQL4\Files\history.csv` 
a CSV file. Inspired by 'ExportHistory' script, but re-done and improved for further needs.

TODO,Mar-22: open the exported file in explorer selected or excell, https://www.mql5.com/en/forum/119063
NOTE,Mar-25: leverage just multiplies your money, and allows you to buy more units (lot sizes), it DOES NOT effect your percentages or returns
             what muliplies your wins losses is the fact that 1 lot = 100000, so 1% in price of currency at 1 lot size is actually 1% * 1 lot (100000 units) = 100000%
             or 1% * 0.01 lot size (1000 units) = 1000%
*/

#property version "2017-Mar-11";
#property copyright "None, bug give me credit if you derive";
#property link      "http://danielsokolowski.com/";

#property show_inputs

input int nORDER_NUMBER_TO_START_EXPORTING_FROM = -1; // extern you can modify / input you can't

int start()
  {
   int iFileHandle,iOrderCount,iOrderCurrent;
   iOrderCount = OrdersHistoryTotal();
   iFileHandle = FileOpen("DS_ExportHistoryToCSV-" + TimeCurrent() + ".mq4.csv",FILE_WRITE|FILE_CSV);
   FileWrite(iFileHandle,"Order","Time Open","Type", "Size","Symbol","Price Open","Time Close","Price Close","Profit (after lot size, and currency conversion)","Comment"
   	,"Week Number"
   	,"Time Open as Excell Value"
   	,"Units"
   	,"Win/Loss"
   	,"Price Change (%)"
   	,"Time of Trade Duration (m)"
   	,"Time to Break Even (m)" 
   	,"Time to +0.01% Price Change (m)"
   	,"Time to +0.1% Price Change (m)"
   	,"Max Drown Down for Trade (%) (after spread)"
   	,"Max Drown Down to Break Even (%) (after spread)"
   	
   	);
   
   for (iOrderCurrent=0;iOrderCurrent<iOrderCount;iOrderCurrent++)
   {
      // skip if order not in history
      if (OrderSelect(iOrderCurrent,SELECT_BY_POS,MODE_HISTORY) == false) { continue; }
      
      // skip if order smaller then our `nLatestOrderLastRun`
      if (OrderTicket() < nORDER_NUMBER_TO_START_EXPORTING_FROM) { continue; }
      
      // skip if order not buy or sell
      if (OrderType() != OP_BUY && OrderType() != OP_SELL) { continue; }
      
      // get order type
      string sOrderType = IntegerToString(OrderType());
      if (OrderType() == OP_BUY) { sOrderType = "OP_BUY"; }
      if (OrderType() == OP_SELL) { sOrderType = "OP_SELL"; }
      
      // find time to break even for order
      // ---------------------------------
      MqlRates aSymbolBars[]; 
      // ArraySetAsSerries(aSymbolHighs, true) // we don't want to set this as a time series so we want `0` to be the start of our order bar for the loop
      int iNumberCopied = CopyRates(OrderSymbol(),PERIOD_M1, OrderOpenTime(), TimeCurrent() ,aSymbolBars);
      while (iNumberCopied == -1) { // use loop to wait which is ok: https://docs.mql4.com/series/timeseries_access#synchronized
        int iErrorCode = GetLastError();
        if (iErrorCode > 0) {
        		Alert("=== DS_ExportHistoryToCSV.start(...): aborting due to unexpected error, `iErrorCode=" + iErrorCode + "`."); 
        		return;
        };
        Print("=== DS_ExportHistoryToCSV.start(...): waiting for `" + OrderSymbol() + "` data to populate.");
        Sleep(1000);
        iNumberCopied = CopyRates(OrderSymbol(),PERIOD_M1, OrderOpenTime(), TimeCurrent() ,aSymbolBars);
      }
      
      double dMaxPercentageDownForTrade = 0.0;
      double dMaxPercentageDownToBreakEven = 0.0; 
      string sMinutesToBreakEven = "NOT_YET_OR_NEVER";
      string sMinutesTo0_01PercentageChange = "NOT_YET_OR_NEVER";
      string sMinutesTo0_1PercentageChange = "NOT_YET_OR_NEVER";
      // assert we have all the bars upto to the trade, MQL has a hardcoded internal max, see https://www.mql5.com/en/forum/124619
      // TODO: possibly automate this with https://www.mql5.com/en/forum/167505/page2
      datetime dtTemp = OrderOpenTime();
      double dPrice = OrderOpenPrice();
      if (aSymbolBars[0].time - OrderOpenTime() > 120) { // Mar-15-2017: it seems MQL has something missing ticks, we had order 8620461 that was missing the next minute candle so we extended it to 120sec
      	Alert("=== DS_ExportHistoryToCSV.start(...): error, unable to get all '" + OrderSymbol() + "' historical data, `(aSymbolBars[0].datetime - OrderOpenPrice() > 60) == true` for `OrderTicket()=" + OrderTicket() 
      		+ "`."
      		+ "\n\n\tPerform steps at following link and try again: `https://www.mql5.com/en/forum/124619#comment_3253773`."); 
      	//Alert("=== DS_ExportHistoryToCSV.start(...): unable to get all historical data, `(aSymbolBars[0].datetime - OrderOpenPrice() > 60) == true` for `OrderTicket()=" + OrderTicket() + "`."); 
      	sMinutesToBreakEven = "INSUFICIENT_HISTORICAL_DATA";
      	sMinutesTo0_1PercentageChange = sMinutesToBreakEven;
      	sMinutesTo0_01PercentageChange = sMinutesToBreakEven;
      } else {
	      // loop over the array and find break even point
	      int iCurrentBar;
	      for (iCurrentBar = 0; iCurrentBar < iNumberCopied; iCurrentBar++) {
	        /*if (OrderTicket() == 8622851) {
	      		double price = OrderOpenPrice();
	      		Print("here");
	      	 }
	      	 */
	        if (aSymbolBars[iCurrentBar].time < OrderCloseTime()) {
	        	 if ((aSymbolBars[iCurrentBar].low/OrderOpenPrice() - 1.00)*AccountLeverage()*100 < dMaxPercentageDownForTrade) {
	        	    dMaxPercentageDownForTrade = ((aSymbolBars[iCurrentBar].low/OrderOpenPrice() - 1.00) * 100);
	        	 }
	        }
	        
	        if (sMinutesToBreakEven == "NOT_YET_OR_NEVER") { 
	          if (aSymbolBars[iCurrentBar].high >= OrderOpenPrice()) {
	          	sMinutesToBreakEven = DoubleToString((aSymbolBars[iCurrentBar].time - OrderOpenTime())/60.00,2);
	          }
	          if ((aSymbolBars[iCurrentBar].low/OrderOpenPrice() - 1.00)*AccountLeverage()*100 < dMaxPercentageDownToBreakEven) {
	          	dMaxPercentageDownToBreakEven = (aSymbolBars[iCurrentBar].low/OrderOpenPrice() - 1.00) * 100;
	          }
	          //break;
	        }
	        
	        if (sMinutesTo0_01PercentageChange == "NOT_YET_OR_NEVER" && (aSymbolBars[iCurrentBar].high/OrderOpenPrice()) - 1 >= 0.0001) {
	        	 sMinutesTo0_01PercentageChange = DoubleToString((aSymbolBars[iCurrentBar].time - OrderOpenTime())/60.00,2);
	        	 //break;
	        }
	        
	        
	        if (sMinutesTo0_1PercentageChange == "NOT_YET_OR_NEVER" && (aSymbolBars[iCurrentBar].high/OrderOpenPrice()) - 1 >= 0.001) {
	        	 sMinutesTo0_1PercentageChange = DoubleToString((aSymbolBars[iCurrentBar].time - OrderOpenTime())/60.00,2);
	        	 break;
	        }
	      }
      }
      
      // write the line to file
      FileWrite(iFileHandle
         ,OrderTicket()
         ,TimeToStr(OrderOpenTime())
         ,sOrderType
         ,OrderLots()
         ,OrderSymbol()
         ,OrderOpenPrice()
         ,TimeToStr(OrderCloseTime())
         ,OrderClosePrice()
         ,OrderProfit()
         ,OrderComment()
         
         ,(TimeDayOfYear(OrderOpenTime()) / 7) + 1
         ,DoubleToString((double)OrderOpenTime() / 86400 + 25569) // https://excelribbon.tips.net/T010849_Converting_UNIX_Date_Time_Stamps.html
         ,MarketInfo(OrderSymbol(),MODE_LOTSIZE) * OrderLots() // "Units"
         ,(OrderProfit() < 0 ? "LOSS" : "WIN")
         ,(OrderClosePrice()/OrderOpenPrice()-1.00) * 100 /* converting to % */
         ,DoubleToString((OrderCloseTime() - OrderOpenTime()) / 60.00, 2)
         ,sMinutesToBreakEven
         ,sMinutesTo0_01PercentageChange
         ,sMinutesTo0_1PercentageChange
         ,dMaxPercentageDownForTrade
         ,(sMinutesToBreakEven == "NOT_YET_OR_NEVER") ? "NOT_YET_OR_NEVER" : dMaxPercentageDownToBreakEven // only populate this if we actually have reached break even at some point
         //NOT VERY USEFULL ,(OrderProfit()/OrderOpenPrice() - 1.00) * 100 /* converting to % */ 
      );
  
       
   }
   FileClose(iFileHandle);
   Alert("=== DS_ExportHistoryToCSV.start(...): data exported to `" + TerminalInfoString(TERMINAL_DATA_PATH) + "/DS_ExportHistoryToCSV.mq4.csv`.");
   
   //nORDER_NUMBER_TO_START_EXPORTING_FROM = OrderTicket();
   
   return(0);
  }

Comments (0)