BitstampChartDownloader

Author: avoitenko
Price Data Components
Series array that contains open prices of each barSeries array that contains close prices for each bar
0 Views
0 Downloads
0 Favorites
BitstampChartDownloader
ÿþ//+------------------------------------------------------------------+

//|                                      BitstampChartDownloader.mq5 |

//+------------------------------------------------------------------+

#property copyright "avoitenko"

#property link      "https://www.mql5.com/en/users/avoitenko"

#property version   "1.01"

#property strict

#property description "Script for downloading OHLC history charts from the Bitstamp crypto exchange"

#property script_show_inputs



#include <jason-1.12.mqh>

#include <Files\FileTxt.mqh>

#include <Files\FileBin.mqh>



// REST API Documentation: https://www.bitstamp.net/api/#what-is-api

#define BASE_URL "https://www.bitstamp.net"



//+------------------------------------------------------------------+

sinput string           InpBaseURL            = "https://www.bitstamp.net";// WebRequest Base URL

input string            InpSymbolName         = "BTCUSD";                  // Symbol

input ENUM_TIMEFRAMES   InpTimeframe          = PERIOD_H1;                 // Timeframe

input uint              InpHistoryLengthDays  = 150;                       // History Length, days



const string InpTWSymbolName = "TW@"+InpSymbolName;



//+------------------------------------------------------------------+

void OnStart()

  {

   ulong gtcBegin = GetMicrosecondCount();

   int copyTotal=0;

//--- time

   datetime serverTime = TimeGMT();

   PrintFormat("Local UTC time: %s", TimeToString(serverTime));



//---

   datetime timeStart = serverTime - InpHistoryLengthDays * 86400;

   PrintFormat("Begin download from time: %s", TimeToString(timeStart));



   MqlRates finalArray[];

   const int maxIterations = 2 * (int)InpHistoryLengthDays * 86400 / PeriodSeconds(InpTimeframe)/720;

   PrintFormat("Max Iterations %d", maxIterations);



//---

   int iteration=0;

   while(iteration++ < maxIterations && !_StopFlag)

     {

#ifdef _DEBUG

      PrintFormat("Iteration #%d",iteration);

#endif



      //---

      MqlRates data[];

      if(!GetHistoryData(InpSymbolName, InpTimeframe, timeStart, data))

        {

         PrintFormat("Error GetHistoryData");

         return;

        }



      //---

      int total = ArraySize(data);

      if(total < 2)

        {

         break;

        }



      //---

      for(int i=0; i<total && !_StopFlag; i++)

        {

         if(data[i].time > timeStart)

           {

            //--- add candle, one by one

            int size = ArraySize(finalArray);

            ArrayResize(finalArray, size+1, 1000);

            finalArray[size] = data[i];

           }

        }



      //--- apply new start time

      timeStart = data[total-1].time;

      copyTotal+= total;



      PrintFormat("Downloaded %d bars, new start time is %s",total, TimeToString(timeStart));





     }



#ifdef __MQL5__

//--- create custom symbol

   CreateCustomSymbol(InpTWSymbolName, InpTimeframe, finalArray);

   double delaySec = (GetMicrosecondCount()-gtcBegin)/1000000.0;



//--- print delay

   PrintFormat("Custom symbol '%s' %s has been created, delay %.2f seconds",

               InpTWSymbolName,

               EnumToString(InpTimeframe),

               delaySec);



#else

//--- create history .hst file

   WriteHistoryToFile(InpTWSymbolName, InpTimeframe, finalArray);



   double delaySec = (GetMicrosecondCount()-gtcBegin)/1000000.0;



//--- print delay

   PrintFormat("%s %s: %d bars have been written to files, delay %.2f seconds",

               InpTWSymbolName,

               EnumToString(InpTimeframe),

               copyTotal,

               delaySec);



#endif









  }







//+------------------------------------------------------------------+

//|   CreateCustomSymbol                                             |

//+------------------------------------------------------------------+

#ifdef __MQL5__

bool CreateCustomSymbol(const string symbol, const ENUM_TIMEFRAMES tf, MqlRates& data[])

  {



//--- check existance

   bool isCustom=false;

   const bool customExists = SymbolExist(symbol,isCustom) && isCustom;

   if(!customExists)

     {



      //--- create a new one

      if(!CustomSymbolCreate(symbol, "Custom\\"+symbol, NULL))

        {

         PrintFormat("Error CustomSymbolCreate %d",GetLastError());

        }

     }



//--- udpate chart

   if(CustomRatesUpdate(symbol,data)<0)

     {

      PrintFormat("Error CustomRatesUpdate %d",GetLastError());

     }



//--- select

   SymbolSelect(symbol,true);



//--- open the chart

   ChartOpen(symbol,tf);



//---

   return true;

  }

#endif





//+------------------------------------------------------------------+

bool GetHistoryData(const string symbol,

                    const ENUM_TIMEFRAMES tf,

                    const datetime fromTime,

                    MqlRates& data[])

  {



//---

   string inpSymbol = symbol;

   StringToLower(inpSymbol);



// https://www.bitstamp.net/api/v2/ohlc/eurusd/?start=1672546681&step=3600&limit=1000

   string url = StringFormat("%s/api/v2/ohlc/%s/?step=%d&start=%d&limit=1000",

                             InpBaseURL,

                             inpSymbol,

                             PeriodSeconds(tf),

                             fromTime

                            );

   string result;

//---

   int err = GetRequest(url,result);

   if(err == -1)

     {

      PrintFormat("Error WebRequest, please add an URL: '%s' to the settings",InpBaseURL);

      return false;

     }

   else

      if(err != 200)

        {

         PrintFormat("Error getRequest %d",err);

         return false;

        }



//--- parse json

   CJAVal json(NULL,jtOBJ);

   if(!json.Deserialize(result))

     {

      PrintFormat("Error Deserialize");

      return false;

     }



   /*

   //--- handling error

      if(json.HasKey("error"))

        {

         int errorTotal = ArraySize(json["error"].m_e);

         if(errorTotal>0)

           {

            Print(json["error"].m_e[0].ToStr());

            return false;

           }

        }

   */



//---

   if(!json.HasKey("data"))

     {

      PrintFormat("field 'data' not found");

      return false;

     }

//---

   CJAVal jData = json["data"];

   if(!jData.HasKey("ohlc"))

     {

      PrintFormat("field 'ohlc' not found");

      return false;

     }

//---

   CJAVal jOHLC =jData["ohlc"];



//---

   int total = ArraySize(jOHLC.m_e);

   if(total < 1)

     {

      PrintFormat("data array is empty");

      return false;

     }

//---

//Print("array size = ", total);

//---

   for(int i=0; i<total && !_StopFlag; i++)

     {

      //---

      CJAVal bar = jOHLC.m_e[i];

      //---

      MqlRates temp= {};

      //---

      temp.time = (datetime)StringToInteger(bar["timestamp"].ToStr());

      temp.open = StringToDouble(bar["open"].ToStr());

      temp.high = StringToDouble(bar["high"].ToStr());

      temp.low = StringToDouble(bar["low"].ToStr());

      temp.close = StringToDouble(bar["close"].ToStr());

      temp.tick_volume = (long)round(StringToDouble(bar["volume"].ToStr()));



      //--- save

      int dataSize = ArraySize(data);

      ArrayResize(data,dataSize+1,1000);

      data[dataSize] = temp;

     }

//---

   return true;

  }



//+------------------------------------------------------------------+

int GetRequest(string url,string& result)

  {

   char data[];

   char resultData[];

   string resultHeaders;

   int errCode = WebRequest("GET",url,"",5000,data,resultData,resultHeaders);

   result = CharArrayToString(resultData);

   return errCode;

  }



//+------------------------------------------------------------------+

bool WriteHistoryToFile(const string symbol,

                        const ENUM_TIMEFRAMES period,

                        const MqlRates& data[])

  {





   CFileTxt FileTxt;

   CFileBin FileBin;



   int copyTotal = ArraySize(data);

   if(copyTotal <= 0)

     {

      return false;

     }



   int digits = 5;

   int periodMinutes = PeriodSeconds(period)/60;



//--- open files

   FileTxt.Open(symbol + IntegerToString(periodMinutes) + ".csv", FILE_WRITE);

   FileBin.Open(symbol + IntegerToString(periodMinutes) + ".hst", FILE_ANSI | FILE_WRITE);



//---

   int fileVersion = 401;

   string strCopyright = "Copyright 2000-2022, MetaQuotes Ltd";

   int unused [13] = {};



//--- write header

   FileBin.Seek(0, SEEK_SET);

   FileBin.WriteInteger(fileVersion);

   FileBin.WriteString(strCopyright, 64);

   FileBin.WriteString(symbol, 12);

   FileBin.WriteInteger(periodMinutes);

   FileBin.WriteInteger(digits);

   FileBin.WriteInteger(0);

   FileBin.WriteInteger(0);

   FileBin.WriteArray(unused, 0, 13);



#define Delimiter ","



//--- write csv header

   FileTxt.WriteString("Date" + Delimiter +

                       "Time" + Delimiter +

                       "Open" + Delimiter +

                       "High" + Delimiter +

                       "Low" + Delimiter +

                       "Close" + Delimiter +

                       "Volume\n");





   for(int i = 0; i < copyTotal && !_StopFlag; i++)

     {

      string strLine = TimeToString(data[i].time, TIME_DATE)

                       + Delimiter + TimeToString(data[i].time, TIME_MINUTES)

                       + Delimiter + DoubleToString(data[i].open, digits)

                       + Delimiter + DoubleToString(data[i].high, digits)

                       + Delimiter + DoubleToString(data[i].low, digits)

                       + Delimiter + DoubleToString(data[i].close, digits)

                       + Delimiter + DoubleToString(data[i].tick_volume, 0)

                       + "\n";



      FileTxt.WriteString(strLine);

      FileBin.WriteStruct(data[i]);

     }



//---

   FileTxt.Close();

   FileBin.Close();





   return true;

  }

//+------------------------------------------------------------------+

Comments

Markdown supported. Formatting help

Markdown Formatting Guide

Element Markdown Syntax
Heading # H1
## H2
### H3
Bold **bold text**
Italic *italicized text*
Link [title](https://www.example.com)
Image ![alt text](image.jpg)
Code `code`
Code Block ```
code block
```
Quote > blockquote
Unordered List - Item 1
- Item 2
Ordered List 1. First item
2. Second item
Horizontal Rule ---