Skip to content

Instantly share code, notes, and snippets.

@Elvmeen
Created December 21, 2025 22:19
Show Gist options
  • Select an option

  • Save Elvmeen/a7ec746e415a852ca8ab900a5c4a2052 to your computer and use it in GitHub Desktop.

Select an option

Save Elvmeen/a7ec746e415a852ca8ab900a5c4a2052 to your computer and use it in GitHub Desktop.
Watchlist Analyzer
//+------------------------------------------------------------------+
//| MultiTimeframeBullishScanner.mq5|
//| |
//+------------------------------------------------------------------+
#property strict
//--- Input parameters
input ENUM_TIMEFRAMES TF1 = PERIOD_D1; // Daily
input ENUM_TIMEFRAMES TF2 = PERIOD_H4; // 4H
input ENUM_TIMEFRAMES TF3 = PERIOD_H1; // 1H
input ENUM_TIMEFRAMES TF4 = PERIOD_M30; // 30 Minutes
input ENUM_TIMEFRAMES TF5 = PERIOD_M15; // 15 Minutes
input int TimerInterval = 60; // Check interval in seconds
input bool SendPushNotifications = true; // Enable push notifications
input int MaxAlertsPerCandle = 3; // Max alerts per symbol per candle
//--- Structure to track alerts per symbol
class SymbolAlertInfo
{
public:
string symbolName;
datetime candleTime;
int count;
SymbolAlertInfo()
{
symbolName = "";
candleTime = 0;
count = 0;
}
};
//--- Global array to track alerts
SymbolAlertInfo symbolAlerts[];
//+------------------------------------------------------------------+
//| Expert initialization |
//+------------------------------------------------------------------+
int OnInit()
{
Print("Multi-Timeframe Bullish Scanner Started");
Print("Scanning timeframes: ", EnumToString(TF1), ", ", EnumToString(TF2), ", ",
EnumToString(TF3), ", ", EnumToString(TF4), ", ", EnumToString(TF5));
Print("Check interval: ", TimerInterval, " seconds");
Print("Breakout logic: 1H and 4H must break above previous candle high");
Print("Other timeframes: Must close bullish");
EventSetTimer(TimerInterval);
if(SendPushNotifications && !TerminalInfoInteger(TERMINAL_NOTIFICATIONS_ENABLED))
{
Print("WARNING: Push notifications are not enabled in MetaTrader!");
Print("Enable them in: Tools -> Options -> Notifications");
}
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert deinitialization |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
EventKillTimer();
ArrayFree(symbolAlerts);
Print("Multi-Timeframe Bullish Scanner Stopped");
}
//+------------------------------------------------------------------+
//| Timer function - scans watchlist |
//+------------------------------------------------------------------+
void OnTimer()
{
Print("--- Starting watchlist scan ---");
int symbols_total = SymbolsTotal(true); // Market Watch symbols only
int bullishCount = 0;
for(int i = 0; i < symbols_total; i++)
{
string symbol = SymbolName(i, true);
if(SymbolSelect(symbol, true) && IsBullish(symbol))
{
bullishCount++;
Print("BULLISH BREAKOUT: ", symbol, " on all timeframes!");
if(SendPushNotifications)
{
string msg = "🟢 " + symbol + " BULLISH BREAKOUT!\n" +
"1H & 4H breaking above previous high\n" +
"D1, 30M, 15M closed bullish";
SendLimitedPush(symbol, msg);
}
}
}
if(bullishCount == 0)
Print("No bullish breakouts found");
else
Print("Found ", bullishCount, " bullish breakouts");
Print("--- Scan complete ---");
}
//+------------------------------------------------------------------+
//| Check if symbol is bullish on all timeframes |
//+------------------------------------------------------------------+
bool IsBullish(string symbol)
{
// Check TF1 (Daily) - closed bullish
double open_d1 = iOpen(symbol, TF1, 1);
double close_d1 = iClose(symbol, TF1, 1);
if(close_d1 <= open_d1)
{
return false;
}
// Check TF2 (4H) - current candle breaking above previous high
double high_4h_prev = iHigh(symbol, TF2, 1); // Previous candle high
double close_4h_current = iClose(symbol, TF2, 0); // Current candle close
if(close_4h_current <= high_4h_prev)
{
return false;
}
// Check TF3 (1H) - current candle breaking above previous high
double high_1h_prev = iHigh(symbol, TF3, 1); // Previous candle high
double close_1h_current = iClose(symbol, TF3, 0); // Current candle close
if(close_1h_current <= high_1h_prev)
{
return false;
}
// Check TF4 (30M) - closed bullish
double open_30m = iOpen(symbol, TF4, 1);
double close_30m = iClose(symbol, TF4, 1);
if(close_30m <= open_30m)
{
return false;
}
// Check TF5 (15M) - closed bullish
double open_15m = iOpen(symbol, TF5, 1);
double close_15m = iClose(symbol, TF5, 1);
if(close_15m <= open_15m)
{
return false;
}
return true; // All conditions met
}
//+------------------------------------------------------------------+
//| Send limited push notifications (max 3 per symbol per candle) |
//+------------------------------------------------------------------+
void SendLimitedPush(string symbol, string msg)
{
datetime candleStart = iTime(symbol, PERIOD_H1, 0);
int foundIndex = -1;
// Search for symbol in array
for(int i = 0; i < ArraySize(symbolAlerts); i++)
{
if(symbolAlerts[i].symbolName == symbol)
{
foundIndex = i;
break;
}
}
// Symbol not found - first alert
if(foundIndex == -1)
{
int newSize = ArraySize(symbolAlerts) + 1;
ArrayResize(symbolAlerts, newSize);
symbolAlerts[newSize - 1].symbolName = symbol;
symbolAlerts[newSize - 1].candleTime = candleStart;
symbolAlerts[newSize - 1].count = 1;
SendNotification(msg);
Print("Alert sent for ", symbol, " (1/", MaxAlertsPerCandle, ")");
return;
}
// Symbol found - check if same candle
if(symbolAlerts[foundIndex].candleTime == candleStart)
{
// Same candle - check if we've reached limit
if(symbolAlerts[foundIndex].count < MaxAlertsPerCandle)
{
symbolAlerts[foundIndex].count++;
SendNotification(msg);
Print("Alert sent for ", symbol, " (", symbolAlerts[foundIndex].count, "/", MaxAlertsPerCandle, ")");
}
else
{
// Already reached max alerts for this candle
Print("Max alerts reached for ", symbol, " on this candle");
return;
}
}
else
{
// New candle - reset count
symbolAlerts[foundIndex].candleTime = candleStart;
symbolAlerts[foundIndex].count = 1;
SendNotification(msg);
Print("New candle - Alert sent for ", symbol, " (1/", MaxAlertsPerCandle, ")");
}
}
//+------------------------------------------------------------------+
//| OnTick - not used |
//+------------------------------------------------------------------+
void OnTick()
{
// Timer handles all checks
}
//+------------------------------------------------------------------+
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment