| //+------------------------------------------------------------------+
|
| //| SignalAlerts.mqh |
|
| //| Copyright 2026, Allan Niñal |
|
| //| https://www.allanninal.dev/mql5 |
|
| //+------------------------------------------------------------------+
|
| //| Alert helper of Divergence Signal Alerts: one message to every |
|
| //| channel that is switched on (pop-up, sound, push, e-mail), |
|
| //| silent in the tester. The caller sends one per closed-bar signal.|
|
| //+------------------------------------------------------------------+
|
| // SPDX-License-Identifier: LicenseRef-PolyForm-Noncommercial-1.0.0 (see LICENSE)
|
| #property strict
|
|
|
| #include <ChartKit/CkDebug.mqh>
|
|
|
| input group "Alerts"
|
| input bool InpAlertPopup = true; // Pop-up alert
|
| input bool InpAlertSound = false; // Play a sound
|
| input string InpSoundFile = "alert.wav"; // Sound file (terminal Sounds folder)
|
| input bool InpAlertPush = true; // Push notification (set up MetaQuotes ID in Options)
|
| input bool InpAlertEmail = false; // E-mail (set up in Options)
|
|
|
| //--- send one message to every channel that is switched on
|
| void SignalAlertMessage(const string product,const string msg)
|
| {
|
| if(msg=="")
|
| return;
|
| if(MQLInfoInteger(MQL_TESTER))
|
| {
|
| CkDbg("alert not sent in the Strategy Tester: "+msg);
|
| return;
|
| }
|
| string text=product+": "+msg;
|
| CkDbg("alert: "+msg);
|
| if(InpAlertPopup)
|
| Alert(text);
|
| if(InpAlertSound && InpSoundFile!="")
|
| PlaySound(InpSoundFile);
|
| if(InpAlertPush)
|
| {
|
| if(!TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED))
|
| CkDbg("push not sent: notifications are off in Options");
|
| else
|
| if(!SendNotification(StringSubstr(text,0,255)))
|
| CkDbg("push failed, error "+IntegerToString(GetLastError()));
|
| }
|
| if(InpAlertEmail)
|
| {
|
| if(!TerminalInfoInteger(TERMINAL_EMAIL_ENABLED))
|
| CkDbg("e-mail not sent: e-mail is off in Options");
|
| else
|
| if(!SendMail(product,text))
|
| CkDbg("e-mail failed, error "+IntegerToString(GetLastError()));
|
| }
|
| }
|
|
|
| //--- Object budget: an indicator that draws labels or lines keeps at most OBJ_CAP of them. Past that, the oldest
|
| //--- are deleted as new ones are made, so a 20000-bar history cannot make the chart crawl. Buffers are not affected.
|
| #define OBJ_CAP 2500
|
| string g_objq[];
|
| int g_objn=0,g_objh=0;
|
| void ObjBudgetReset(void)
|
| {
|
| g_objn=0;
|
| g_objh=0;
|
| }
|
| void ObjBudget(const string name)
|
| {
|
| if(ArraySize(g_objq)!=OBJ_CAP)
|
| ArrayResize(g_objq,OBJ_CAP);
|
| if(g_objn<OBJ_CAP)
|
| {
|
| g_objq[(g_objh+g_objn)%OBJ_CAP]=name;
|
| g_objn++;
|
| return;
|
| }
|
| ObjectDelete(0,g_objq[g_objh]);
|
| g_objq[g_objh]=name;
|
| g_objh=(g_objh+1)%OBJ_CAP;
|
| }
|
| //+------------------------------------------------------------------+
|