Market Data Service is a high-performance financial data API that provides comprehensive Symbol prices of different markets through both RESTful endpoints and real-time WebSocket connections.

MarketDataSender.mq5 8.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. //+------------------------------------------------------------------+
  2. //| MarketDataSender.mq5 |
  3. //| Copyright 2025, MetaQuotes Software Corp. |
  4. //| https://www.mql5.com |
  5. //+------------------------------------------------------------------+
  6. #property copyright "Copyright 2025, MetaQuotes Software Corp."
  7. #property link "https://www.mql5.com"
  8. #property version "1.00"
  9. #property description "Sends historical candles and live prices to REST API"
  10. #property script_show_inputs
  11. #include <Trade\SymbolInfo.mqh>
  12. #include <JAson.mqh> // Include JSON library
  13. //--- REST API Configuration
  14. input string ApiBaseUrl = "http://localhost:3000"; // Base URL of your API
  15. input string ApiKey = ""; // Optional API key if required
  16. //--- Historical Data Configuration
  17. input int HistoricalCandleCount = 1000; // Number of historical candles to send
  18. input ENUM_TIMEFRAMES HistoricalTimeframe = PERIOD_H1; // Timeframe for historical data
  19. //--- Global variables
  20. CJAson json;
  21. CSymbolInfo symbolInfo;
  22. string symbols[];
  23. datetime lastSentTime = 0;
  24. //+------------------------------------------------------------------+
  25. //| Expert initialization function |
  26. //+------------------------------------------------------------------+
  27. int OnInit()
  28. {
  29. // Get all symbols
  30. int count = SymbolsTotal(true);
  31. ArrayResize(symbols, count);
  32. for(int i = 0; i < count; i++)
  33. {
  34. symbols[i] = SymbolName(i, true);
  35. }
  36. // Send initial historical data
  37. SendHistoricalData();
  38. return(INIT_SUCCEEDED);
  39. }
  40. //+------------------------------------------------------------------+
  41. //| Expert tick function |
  42. //+------------------------------------------------------------------+
  43. void OnTick()
  44. {
  45. // Send live prices every second
  46. if(TimeCurrent() - lastSentTime >= 1)
  47. {
  48. SendLivePrices();
  49. lastSentTime = TimeCurrent();
  50. }
  51. }
  52. //+------------------------------------------------------------------+
  53. //| Send historical candle data |
  54. //+------------------------------------------------------------------+
  55. void SendHistoricalData()
  56. {
  57. for(int s = 0; s < ArraySize(symbols); s++)
  58. {
  59. string symbol = symbols[s];
  60. // Get historical candles
  61. MqlRates rates[];
  62. int copied = CopyRates(symbol, HistoricalTimeframe, 0, HistoricalCandleCount, rates);
  63. if(copied <= 0) continue;
  64. // Prepare JSON payload
  65. CJAsonArray candlesArray;
  66. for(int i = 0; i < copied; i++)
  67. {
  68. CJAson candleObj;
  69. candleObj.Add("symbolId", GetSymbolId(symbol)); // You need to implement GetSymbolId()
  70. candleObj.Add("openTime", TimeToString(rates[i].time, TIME_DATE|TIME_MINUTES|TIME_SECONDS));
  71. candleObj.Add("closeTime", TimeToString(rates[i].time + PeriodSeconds(HistoricalTimeframe), TIME_DATE|TIME_MINUTES|TIME_SECONDS));
  72. candleObj.Add("open", rates[i].open);
  73. candleObj.Add("high", rates[i].high);
  74. candleObj.Add("low", rates[i].low);
  75. candleObj.Add("close", rates[i].close);
  76. candleObj.Add("volume", rates[i].tick_volume);
  77. candlesArray.Add(candleObj);
  78. }
  79. // Create final payload
  80. CJAson payload;
  81. payload.Add("candles", candlesArray);
  82. // Send to API
  83. string url = ApiBaseUrl + "/api/candles/bulk";
  84. string result;
  85. string headers = "Content-Type: application/json";
  86. if(StringLen(ApiKey) > 0) headers += "\r\nAuthorization: Bearer " + ApiKey;
  87. int res = WebRequest("POST", url, headers, 5000, payload.GetJson(), result);
  88. // Handle response
  89. if(res == 200)
  90. {
  91. Print("Successfully sent historical data for ", symbol);
  92. }
  93. else
  94. {
  95. Print("Error sending historical data for ", symbol, ": ", res, " - ", result);
  96. }
  97. }
  98. }
  99. //+------------------------------------------------------------------+
  100. //| Send live prices |
  101. //+------------------------------------------------------------------+
  102. void SendLivePrices()
  103. {
  104. CJAsonArray pricesArray;
  105. for(int s = 0; s < ArraySize(symbols); s++)
  106. {
  107. string symbol = symbols[s];
  108. if(!symbolInfo.Name(symbol)) continue;
  109. symbolInfo.RefreshRates();
  110. CJAson priceObj;
  111. priceObj.Add("symbolId", GetSymbolId(symbol));
  112. priceObj.Add("price", symbolInfo.Last());
  113. priceObj.Add("bid", symbolInfo.Bid());
  114. priceObj.Add("ask", symbolInfo.Ask());
  115. priceObj.Add("bidSize", symbolInfo.VolumeBid());
  116. priceObj.Add("askSize", symbolInfo.VolumeAsk());
  117. pricesArray.Add(priceObj);
  118. }
  119. // Create final payload
  120. CJAson payload;
  121. payload.Add("prices", pricesArray);
  122. // Send to API
  123. string url = ApiBaseUrl + "/api/live-prices/bulk";
  124. string result;
  125. string headers = "Content-Type: application/json";
  126. if(StringLen(ApiKey) > 0) headers += "\r\nAuthorization: Bearer " + ApiKey;
  127. int res = WebRequest("POST", url, headers, 5000, payload.GetJson(), result);
  128. // Handle response
  129. if(res == 200)
  130. {
  131. Print("Successfully sent live prices");
  132. }
  133. else
  134. {
  135. Print("Error sending live prices: ", res, " - ", result);
  136. }
  137. }
  138. //+------------------------------------------------------------------+
  139. //| Initialize symbol map from database |
  140. //+------------------------------------------------------------------+
  141. bool InitializeSymbolMap()
  142. {
  143. // Fetch existing symbols from API
  144. string url = ApiBaseUrl + "/api/symbols";
  145. string result;
  146. string headers = "Content-Type: application/json";
  147. if(StringLen(ApiKey) > 0) headers += "\r\nAuthorization: Bearer " + ApiKey;
  148. int res = WebRequest("GET", url, headers, 5000, "", result);
  149. if(res != 200)
  150. {
  151. Print("Failed to fetch symbols: ", res, " - ", result);
  152. return false;
  153. }
  154. // Parse response
  155. CJAson parser;
  156. if(!parser.Parse(result))
  157. {
  158. Print("Failed to parse symbols response");
  159. return false;
  160. }
  161. // Create lookup table
  162. CJAsonArray symbolsArray = parser.GetArray("data");
  163. int dbSymbolCount = symbolsArray.Size();
  164. for(int s = 0; s < ArraySize(symbols); s++)
  165. {
  166. string mt5Symbol = symbols[s];
  167. bool found = false;
  168. // Search for matching symbol in database
  169. for(int i = 0; i < dbSymbolCount; i++)
  170. {
  171. CJAson dbSymbol = symbolsArray.GetObject(i);
  172. string dbSymbolName = dbSymbol.GetString("symbol");
  173. if(dbSymbolName == mt5Symbol)
  174. {
  175. symbolIdMap[s] = (int)dbSymbol.GetInt("id");
  176. found = true;
  177. break;
  178. }
  179. }
  180. // Create symbol if not found
  181. if(!found)
  182. {
  183. int newId = CreateSymbol(mt5Symbol);
  184. if(newId > 0)
  185. {
  186. symbolIdMap[s] = newId;
  187. Print("Created new symbol: ", mt5Symbol, " (ID: ", newId, ")");
  188. }
  189. else
  190. {
  191. Print("Failed to create symbol: ", mt5Symbol);
  192. return false;
  193. }
  194. }
  195. }
  196. return true;
  197. }
  198. //+------------------------------------------------------------------+
  199. //| Create new symbol in database |
  200. //+------------------------------------------------------------------+
  201. int CreateSymbol(string symbol)
  202. {
  203. string url = ApiBaseUrl + "/api/symbols";
  204. string result;
  205. string headers = "Content-Type: application/json";
  206. if(StringLen(ApiKey) > 0) headers += "\r\nAuthorization: Bearer " + ApiKey;
  207. // Extract exchange and instrument type from symbol name
  208. string parts[];
  209. StringSplit(symbol, '_', parts);
  210. string exchange = (ArraySize(parts) > 1) ? parts[0] : "MT5";
  211. string instrumentType = "forex"; // Default, can be improved
  212. // Prepare payload
  213. CJAson payload;
  214. payload.Add("symbol", symbol);
  215. payload.Add("exchange", exchange);
  216. payload.Add("instrumentType", instrumentType);
  217. payload.Add("isActive", true);
  218. int res = WebRequest("POST", url, headers, 5000, payload.GetJson(), result);
  219. if(res != 201)
  220. {
  221. Print("Error creating symbol: ", res, " - ", result);
  222. return -1;
  223. }
  224. // Parse response to get new ID
  225. CJAson parser;
  226. if(!parser.Parse(result))
  227. {
  228. Print("Failed to parse create symbol response");
  229. return -1;
  230. }
  231. return (int)parser.GetObject("data").GetInt("id");
  232. }
  233. //+------------------------------------------------------------------+
  234. //| Get symbol ID from map |
  235. //+------------------------------------------------------------------+
  236. int GetSymbolId(string symbol)
  237. {
  238. for(int i = 0; i < ArraySize(symbols); i++)
  239. {
  240. if(symbols[i] == symbol)
  241. {
  242. return symbolIdMap[i];
  243. }
  244. }
  245. return -1;
  246. }
  247. //+------------------------------------------------------------------+