forked from rosh/MQL5Book
139 lines
5.2 KiB
MQL5
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);
| |
}
| |
//+------------------------------------------------------------------+
|