MQL5Book/Indicators/p6/MarketBookVolumeAlert.mq5
super.admin 1c8e83ce31 convert
2025-05-30 16:09:41 +02:00

139 lines
5.2 KiB
MQL5

//+------------------------------------------------------------------+
//| MarketBookVolumeAlert.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 symbol and monitor changes with large volumes."
#property indicator_chart_window
#property indicator_plots 0
#define N_LINES 25 // number of lines in multicomment
#include "..\..\Include\Comments.mqh"
input string WorkSymbol = ""; // WorkSymbol (if empty, use current chart symbol)
input bool CountVolumeInLots = false;
input double VolumeLimit = 0;
const string _WorkSymbol = StringLen(WorkSymbol) == 0 ? _Symbol : WorkSymbol;
double contract;
int digits;
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
void OnInit()
{
MarketBookAdd(_WorkSymbol);
contract = SymbolInfoDouble(_WorkSymbol, SYMBOL_TRADE_CONTRACT_SIZE);
digits = (int)MathRound(MathLog10(contract));
Print(SymbolInfoDouble(_WorkSymbol, SYMBOL_SESSION_BUY_ORDERS_VOLUME));
Print(SymbolInfoDouble(_WorkSymbol, SYMBOL_SESSION_SELL_ORDERS_VOLUME));
}
#define VOL(V) (CountVolumeInLots ? V / contract : V)
//+------------------------------------------------------------------+
//| Market book notification handler |
//+------------------------------------------------------------------+
void OnBookEvent(const string &symbol)
{
if(symbol != _WorkSymbol) return;
static MqlBookInfo mbp[]; // previous table
MqlBookInfo mbi[];
if(MarketBookGet(symbol, mbi)) // retrieve current book
{
if(ArraySize(mbp) == 0)
{
ArrayCopy(mbp, mbi);
return;
}
int j = 0;
for(int i = 0; i < ArraySize(mbi); ++i)
{
bool found = false;
for( ; j < ArraySize(mbp); ++j)
{
if(MathAbs(mbp[j].price - mbi[i].price) < DBL_EPSILON * mbi[i].price) // mbp[j].price == mbi[i].price
{
if(VOL(mbi[i].volume_real - mbp[j].volume_real) >= VolumeLimit)
{
NotifyVolumeChange("Enlarged", mbp[j].price, VOL(mbp[j].volume_real), VOL(mbi[i].volume_real));
}
else
if(VOL(mbp[j].volume_real - mbi[i].volume_real) >= VolumeLimit)
{
NotifyVolumeChange("Reduced", mbp[j].price, VOL(mbp[j].volume_real), VOL(mbi[i].volume_real));
}
found = true;
++j;
break;
}
else if(mbp[j].price > mbi[i].price)
{
if(VOL(mbp[j].volume_real) >= VolumeLimit)
{
NotifyVolumeChange("Removed", mbp[j].price, VOL(mbp[j].volume_real), 0.0);
}
// keep loop incrementing ++j to lower prices
}
else // mbp[j].price < mbi[i].price
{
break;
}
}
if(!found) // unique price
{
if(VOL(mbi[i].volume_real) >= VolumeLimit)
{
NotifyVolumeChange("Added", mbi[i].price, 0.0, VOL(mbi[i].volume_real));
}
}
}
if(ArrayCopy(mbp, mbi) <= 0)
{
Print("ArrayCopy failed:", _LastError);
}
if(ArrayResize(mbp, ArraySize(mbi)) <= 0) // shrink if required
{
Print("ArrayResize failed:", _LastError);
}
}
}
//+------------------------------------------------------------------+
//| 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)
{
MarketBookRelease(_WorkSymbol);
Comment("");
}
//+------------------------------------------------------------------+
//| Multisymbol tick custom event |
//+------------------------------------------------------------------+
void NotifyVolumeChange(const string action, const double price,
const double previous, const double volume)
{
const string message = StringFormat("%s: %s %s -> %s",
action,
DoubleToString(price, (int)SymbolInfoInteger(_WorkSymbol, SYMBOL_DIGITS)),
DoubleToString(previous, digits),
DoubleToString(volume, digits));
ChronoComment(message);
}
//+------------------------------------------------------------------+