//
// EA Studio Data Export
// Copyright 2018, Forex Software Ltd.
//
// Use this script in MT4 to export historical files for Expert Advisor Studio
// The files are saved in the MT5's \MQL4\Files folder with .json extension.
// Drag and drop the files in the Tools -> Data Import drop box.
//

#property copyright "Forex Software Ltd."
#property version   "3.3"
#property strict
#property show_inputs

static input int    Maximum_Bars = 100000; // Maximum count of bars
static input int    Spread       = 0;      // Spread [points] (0 - current)
static input double Commission   = 10;     // Commission in currency

// Commission in currency per lot. It is normally used by the ECN brokers.
// Example: 10 - it means 5 USD for the entry and 5 USD for the exit per round lot.

ENUM_TIMEFRAMES periods[] = {PERIOD_M1, PERIOD_M5, PERIOD_M15, PERIOD_M30, PERIOD_H1, PERIOD_H4, PERIOD_D1};
string comment = "";

void OnStart()
{
    const ENUM_INIT_RETCODE initRetcode = ValidateInit();

    if (initRetcode == INIT_FAILED) return;

    RefreshRates();
    for (int p = 0; p < ArraySize(periods); p++)
    {
        string fileName = _Symbol + PeriodToStr(periods[p]) + ".json";
        string data     = GetSymbolData(_Symbol, periods[p]);
        SaveFile(fileName, data);
    }
}

string GetSymbolData(string symbol, ENUM_TIMEFRAMES period)
{
    string name         = symbol;
    int    digits       = (int) SymbolInfoInteger(symbol, SYMBOL_DIGITS);
    int    maxBars      = MathMin(TerminalInfoInteger(TERMINAL_MAXBARS), Maximum_Bars);
    string server       = AccountInfoString(ACCOUNT_SERVER);
    string company      = AccountInfoString(ACCOUNT_COMPANY);
    string terminal     = TerminalInfoString(TERMINAL_NAME);
    string baseCurrency = StringSubstr(symbol, 0, 3);
    string priceIn      = StringSubstr(symbol, 3, 3);
    int    spread       = GetSpread();

    if (server == "")
    {
        server = "Unknown";
    }

    MqlRates rates[]; ArraySetAsSeries(rates,true);

    int bars = 0;
    if (period == PERIOD_D1)
    {
       datetime from = D'2007.01.01 00:00';
       datetime to   = TimeCurrent();
       bars = CopyRates(symbol, period, from, to, rates);
    }
    else
    {
       bars = CopyRates(symbol, period, 0, maxBars, rates);
    }

    if (bars < 300)
        return ("");

    int      multiplier = (int) MathPow(10, digits);
    datetime millennium = D'2000.01.01 00:00';

    string time   = "";
    string open   = "";
    string high   = "";
    string low    = "";
    string close  = "";
    string volume = "";

    for (int i = bars - 1; i >= 0; i--)
    {
      string comma = i > 0 ? "," : "";

      StringAdd(time,   IntegerToString((rates[i].time-millennium) / 60) + comma);
      StringAdd(open,   DoubleToString(rates[i].open,  digits) + comma);
      StringAdd(high,   DoubleToString(rates[i].high,  digits) + comma);
      StringAdd(low,    DoubleToString(rates[i].low,   digits) + comma);
      StringAdd(close,  DoubleToString(rates[i].close, digits) + comma);
      StringAdd(volume, IntegerToString(rates[i].tick_volume)  + comma);
    }

    string symbolData = "{"+
         "\"ver\":"            + "3"                                                      +  ","+
         "\"terminal\":\""     + terminal                                                 +"\","+
         "\"company\":\""      + company                                                  +"\","+
         "\"server\":\""       + server                                                   +"\","+
         "\"symbol\":\""       + name                                                     +"\","+
         "\"period\":"         + PeriodToStr(period)                                      + "," +
         "\"baseCurrency\":\"" + baseCurrency                                             +"\","+
         "\"priceIn\":\""      + priceIn                                                  +"\","+
         "\"lotSize\":"        + IntegerToString((int) MarketInfo(symbol,MODE_LOTSIZE))   + "," +
         "\"stopLevel\":"      + IntegerToString((int) MarketInfo(symbol,MODE_STOPLEVEL)) + "," +
         "\"tickValue\":"      + DoubleToString(MarketInfo(symbol,MODE_TICKVALUE),digits) + "," +
         "\"minLot\":"         + DoubleToString(MarketInfo(symbol,MODE_MINLOT),2)         + "," +
         "\"maxLot\":"         + DoubleToString(MarketInfo(symbol,MODE_MAXLOT),2)         + "," +
         "\"lotStep\":"        + DoubleToString(MarketInfo(symbol,MODE_LOTSTEP),2)        + "," +
         "\"serverTime\":"     + IntegerToString((TimeCurrent()-millennium)/60)           + "," +
         "\"swapLong\":"       + DoubleToString(MarketInfo(symbol,MODE_SWAPLONG),2)       + "," +
         "\"swapShort\":"      + DoubleToString(MarketInfo(symbol,MODE_SWAPSHORT),2)      + "," +
         "\"swapType\":"       + IntegerToString((int) MarketInfo(symbol,MODE_SWAPTYPE))  + "," +
         "\"swapThreeDays\":"  + IntegerToString(SymbolInfoInteger(_Symbol,SYMBOL_SWAP_ROLLOVER3DAYS)) + "," +
         "\"commission\":"     + DoubleToString(Commission,2)                             + "," +
         "\"bid\":"            + DoubleToString(MarketInfo(symbol,MODE_BID),digits)       + "," +
         "\"ask\":"            + DoubleToString(MarketInfo(symbol,MODE_ASK),digits)       + "," +
         "\"spread\":"         + IntegerToString(spread)                                  + "," +
         "\"digits\":"         + IntegerToString(digits)                                  + "," +
         "\"bars\":"           + IntegerToString(bars)                                    + "," +
         "\"time\":["          + time                                                     + "],"+
         "\"open\":["          + open                                                     + "],"+
         "\"high\":["          + high                                                     + "],"+
         "\"low\":["           + low                                                      + "],"+
         "\"close\":["         + close                                                    + "],"+
         "\"volume\":["        + volume                                                   + "]" +
         "}";

    comment += symbol + PeriodToStr(period) + ", " + IntegerToString(bars) + " bars" + "\n";
    Comment(comment);

    return (symbolData);
}

void SaveFile(string fileName, string data)
{
    ResetLastError();
    int file_handle = FileOpen(fileName, FILE_WRITE|FILE_IS_TEXT);
    if (file_handle != INVALID_HANDLE)
    {
        FileWrite(file_handle, data);
        FileClose(file_handle);
    }
}

string PeriodToStr(ENUM_TIMEFRAMES period)
{
   int seconds = PeriodSeconds(period);
   string text = IntegerToString(seconds / 60);
   return (text);
}

int GetSpread()
{
   if (Spread > 0) return (Spread);

   int    digits  = (int) SymbolInfoInteger(_Symbol, SYMBOL_DIGITS);
   double bid     = MarketInfo(_Symbol, MODE_BID);
   double ask     = MarketInfo(_Symbol, MODE_ASK);
   double spread  = (ask - bid) * MathPow(10, digits);
   int    rounded = RoundNumber(spread);

   return (rounded);
}

int RoundNumber(double number)
{
   int figures = number < 1000 ? 2 : 3;
   int multiplier = (int) MathPow(10, figures - 1);
   int result = (int) (MathCeil(number / multiplier)* multiplier);
   return (result);
}

ENUM_INIT_RETCODE ValidateInit()
{
   return (INIT_SUCCEEDED);
}