//+------------------------------------------------------------------+ //| 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 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