2026-10-21 16:07:21 +08:00 | | | //+------------------------------------------------------------------+
|
| | | //| SignalAlerts.mqh |
|
| | | //| Copyright 2026, Allan Niñal |
|
| | | //| https://www.allanninal.dev/mql5 |
|
| | | //+------------------------------------------------------------------+
|
| | | //| MT4 edition of the Divergence alert helper: 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
|
| | |
|
2026-10-31 09:12:09 +08:00 | | | #include <ChartKit/CkDebug.mqh>
|
| | |
|
2026-10-21 16:07:21 +08:00 | | | input bool InpAlertPopup = true; // Pop-up alert
|
| | | input bool InpAlertSound = false; // Play a sound
|
| | | input string InpSoundFile = "alert.wav"; // Sound file (terminal Sounds folder)
|
2026-10-31 14:28:42 +08:00 | | | input bool InpAlertPush = true; // Push notification (set up MetaQuotes ID in Options)
|
2026-10-21 16:07:21 +08:00 | | | input bool InpAlertEmail = false; // E-mail (set up in Options)
|
| | |
|
| | | //--- chart timeframe as text (M15, H1, ...)
|
| | | string TfName()
|
| | | {
|
| | | switch(_Period)
|
| | | {
|
| | | case PERIOD_M1: return("M1");
|
| | | case PERIOD_M5: return("M5");
|
| | | case PERIOD_M15: return("M15");
|
| | | case PERIOD_M30: return("M30");
|
| | | case PERIOD_H1: return("H1");
|
| | | case PERIOD_H4: return("H4");
|
| | | case PERIOD_D1: return("D1");
|
| | | case PERIOD_W1: return("W1");
|
| | | case PERIOD_MN1: return("MN1");
|
| | | }
|
| | | return("M"+IntegerToString(_Period));
|
| | | }
|
| | |
|
| | | //--- send one message to every channel that is switched on
|
| | | void SignalAlertMessage(const string product,const string msg)
|
| | | {
|
2026-10-31 09:12:09 +08:00 | | | if(msg=="")
|
| | | return;
|
| | | if(IsTesting())
|
| | | {
|
| | | CkDbg("alert not sent in the Strategy Tester: "+msg);
|
2026-10-21 16:07:21 +08:00 | | | return;
|
2026-10-31 09:12:09 +08:00 | | | }
|
2026-10-21 16:07:21 +08:00 | | | string text=product+": "+msg;
|
2026-10-31 09:12:09 +08:00 | | | CkDbg("alert: "+msg);
|
2026-10-21 16:07:21 +08:00 | | | if(InpAlertPopup)
|
| | | Alert(text);
|
| | | if(InpAlertSound && InpSoundFile!="")
|
| | | PlaySound(InpSoundFile);
|
2026-10-31 09:12:09 +08:00 | | | 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;
|
2026-10-21 16:07:21 +08:00 | | | }
|
| | | //+------------------------------------------------------------------+
|