105 lines
3.9 KiB
MQL5
105 lines
3.9 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| MarketBookQuasiTicks.mq5 |
|
|
//| Copyright 2022, MetaQuotes Ltd. |
|
|
//| https://www.mql5.com |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "2022, MetaQuotes Ltd."
|
|
#property link "https://www.mql5.com"
|
|
#property description "Subscribe to market books for specified list of symbols."
|
|
#property description "Extract Ask/Bid prices from received books and produce quasi-tick events for multiple symbols."
|
|
|
|
#property indicator_chart_window
|
|
#property indicator_plots 0
|
|
|
|
#define N_LINES 25 // number of lines in multicomment
|
|
#include "..\..\Include\Comments.mqh"
|
|
|
|
input string SymbolList = "EURUSD,GBPUSD,XAUUSD,USDJPY"; // SymbolList (comma,separated,list)
|
|
|
|
const string WorkSymbols = StringLen(SymbolList) == 0 ? _Symbol : SymbolList;
|
|
string symbols[];
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator initialization function |
|
|
//+------------------------------------------------------------------+
|
|
void OnInit()
|
|
{
|
|
const int n = StringSplit(WorkSymbols, ',', symbols);
|
|
for(int i = 0; i < n; ++i)
|
|
{
|
|
if(!MarketBookAdd(symbols[i]))
|
|
{
|
|
PrintFormat("MarketBookAdd(%s) failed with code %d", symbols[i], _LastError);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Market book notification handler |
|
|
//+------------------------------------------------------------------+
|
|
void OnBookEvent(const string &symbol)
|
|
{
|
|
MqlBookInfo mbi[];
|
|
if(MarketBookGet(symbol, mbi)) // retrieve current book
|
|
{
|
|
int half = ArraySize(mbi) / 2; // estimation of the middle slot
|
|
bool correct = true;
|
|
for(int i = 0; i < ArraySize(mbi); ++i)
|
|
{
|
|
if(i > 0) // find the middle of the book
|
|
{
|
|
if(mbi[i - 1].type == BOOK_TYPE_SELL
|
|
&& mbi[i].type == BOOK_TYPE_BUY)
|
|
{
|
|
half = i;
|
|
}
|
|
|
|
if(mbi[i - 1].price <= mbi[i].price)
|
|
{
|
|
correct = false;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(correct) // extract best Bid/Ask prices from proper book
|
|
{
|
|
// mbi[half - 1].price // Ask
|
|
// mbi[half].price // Bid
|
|
OnSymbolTick(symbol, mbi[half].price);
|
|
}
|
|
}
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Custom indicator iteration function (dummy) |
|
|
//+------------------------------------------------------------------+
|
|
int OnCalculate(const int rates_total, const int prev_calculated, const int, const double &price[])
|
|
{
|
|
return rates_total;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Finalization handler |
|
|
//+------------------------------------------------------------------+
|
|
void OnDeinit(const int)
|
|
{
|
|
for(int i = 0; i < ArraySize(symbols); ++i)
|
|
{
|
|
if(!MarketBookRelease(symbols[i]))
|
|
{
|
|
PrintFormat("MarketBookRelease(%s) failed with code %d", symbols[i], _LastError);
|
|
}
|
|
}
|
|
Comment("");
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Multisymbol tick custom event |
|
|
//+------------------------------------------------------------------+
|
|
void OnSymbolTick(const string &symbol, const double price)
|
|
{
|
|
const string message = StringFormat("%s %s",
|
|
symbol, DoubleToString(price, (int)SymbolInfoInteger(symbol, SYMBOL_DIGITS)));
|
|
ChronoComment(message);
|
|
}
|
|
//+------------------------------------------------------------------+
|