Created
December 21, 2025 22:19
-
-
Save Elvmeen/a7ec746e415a852ca8ab900a5c4a2052 to your computer and use it in GitHub Desktop.
Watchlist Analyzer
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| //+------------------------------------------------------------------+ | |
| //| 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