//+------------------------------------------------------------------+
//|                                       Output History (indicator) |
//+------------------------------------------------------------------+

#property indicator_chart_window     

#include <hanover --- function header (np).mqh>

extern string    CurrencyPairs                     = "";                // enter list of currency pairs, separated by commas (if blank, use current chart's pair)
extern string    TimeFrames                        = "";                // enter list of timeframes, separated by commas (if blank, use current chart's timeframe)
extern bool      DifferentSubfolderPerTimeFrame    = false;
extern int       LookbackBars                      = 100;               // if zero, use all bars in chart history
extern bool      DescendingDateTimeOrder           = false;
extern bool      OutputHeaderLine                  = true;
extern string    FieldSeparator                    = ",";
extern bool      EncloseValuesInQuotes             = false;
extern string    DateTimeFormat                    = "M/D/Y,H:I";
extern string    PriceFormat                       = "T3.5";
extern string    PriceFormatJPYpairs               = "T5.3";
extern string    VolumeFormat                      = "T10";
extern string    RefreshPeriod                     = "+0";

string     P[40],T[9], Quote, IndiName, header;
int        handle, np, nt, RefreshEveryXMins;
datetime   prev_time;
bool       FirstTime;

//+------------------------------------------------------------------+
int init()  {
//+------------------------------------------------------------------+
  IndiName = NumberToStr(GetUniqueInt(),"'OutHist-'Z6'-'");

  if (StringLen(CurrencyPairs) < 1)    CurrencyPairs = Symbol();
  if (StringLen(TimeFrames) < 1)       TimeFrames    = TFToStr(Period());
  if (LookbackBars < 1)                LookbackBars  = 999999;
  np = StrToStringArray(CurrencyPairs,P);
  nt = StrToStringArray(TimeFrames,T);
  Quote = "";
  if (EncloseValuesInQuotes)  Quote = "\x22";
  
  if (FieldSeparator == "^")     
    FieldSeparator = "\x09";
  DateTimeFormat = StringReplace(DateTimeFormat,"^","\x09");

  RefreshEveryXMins = StrToTF(RefreshPeriod);
  prev_time = -9999;
  
  header = StringReplace("Date,Time,Open,High,Low,Close,Volume",",",FieldSeparator);
  
  del_obj();
  plot_obj();
  return(0);
}

//+------------------------------------------------------------------+
int deinit()  {
//+------------------------------------------------------------------+
//  MessageBox("History output complete","Output History");
  del_obj();
  return(0);
}

//+------------------------------------------------------------------+
void del_obj()  {
//+------------------------------------------------------------------+
  int k=0;
  while (k<ObjectsTotal())   {
    string objname = ObjectName(k);
    if (StringSubstr(objname,0,StringLen(IndiName)) == IndiName)  
      ObjectDelete(objname);
    else
      k++;
  }    
  return(0);
}

//+------------------------------------------------------------------+
int start()  {
//+------------------------------------------------------------------+
  if (RefreshEveryXMins < 0)  {
    if (FirstTime)  {
      del_obj();
      plot_obj();
    }
    FirstTime = false;      
    return(0);
  }  
  if (RefreshEveryXMins == 0) {
    del_obj();
    plot_obj();    
  } else {
    if (prev_time != iTime(Symbol(),RefreshEveryXMins,0))  {
      del_obj();
      plot_obj();
      prev_time = iTime(Symbol(),RefreshEveryXMins,0);
  } }      
  return(0);
}

//+------------------------------------------------------------------+
int plot_obj()  {
//+------------------------------------------------------------------+
  for (int i=0; i<np; i++)  {
    for (int j=0; j<nt; j++)  { 
      out_hist(ExpandCcy(P[i]),StrToTF(T[j]));
  } }    
  return(0);
}

//+------------------------------------------------------------------+
int out_hist(string ccy, int tf)  {
//+------------------------------------------------------------------+
  string fname = ccy + "," + TFToStr(tf) + ".csv";
  if (DifferentSubfolderPerTimeFrame)
    fname = "TF-" + TFToStr(tf) + "\\" + ccy + "," + TFToStr(tf) + ".csv";
  handle = FileOpen(fname, FILE_CSV|FILE_WRITE, ',');
  if (handle<1)    return(0);
  if (OutputHeaderLine) 
    FileWrite(handle,header);      // modify header line if adding more columns
  if (DescendingDateTimeOrder)  {  
    for (int i=0; i<MathMin(LookbackBars,iBars(ccy,tf)); i++)  {
      out_line(ccy,tf,i);
  } } else {
    for (i=MathMin(LookbackBars-1,iBars(ccy,tf)-1); i>=0; i--)   {
      out_line(ccy,tf,i);
  } }
  FileClose(handle);
  return(0);
}

//+------------------------------------------------------------------+
int out_line(string ccy, int tf, int i)  {
//+------------------------------------------------------------------+
  string OHLCFormat = PriceFormat;
  if (StringFind(ccy,"JPY") >= 0)
    OHLCFormat = PriceFormatJPYpairs;
  FileWrite(handle,      Quote + DateToStr(iTime(ccy,tf,i),DateTimeFormat)     + Quote
      + FieldSeparator + Quote + NumberToStr(iOpen(ccy,tf,i),OHLCFormat)       + Quote
      + FieldSeparator + Quote + NumberToStr(iHigh(ccy,tf,i),OHLCFormat)       + Quote
      + FieldSeparator + Quote + NumberToStr(iLow(ccy,tf,i),OHLCFormat)        + Quote
      + FieldSeparator + Quote + NumberToStr(iClose(ccy,tf,i),OHLCFormat)      + Quote
      + FieldSeparator + Quote + NumberToStr(iVolume(ccy,tf,i),VolumeFormat)   + Quote
// you can easily add more columns here using MQL4 functions like iMA, iRSI, iBands, iCustom, etc (simply copy the line above as a 'model')
    );
  return(0);
}

//+------------------------------------------------------------------+
#include <hanover --- extensible functions (np).mqh>