//+------------------------------------------------------------------+ //| WhaleDetector.mq5 | //| Copyright 2026, Antigravity AI | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2026, Antigravity AI" #property link "https://www.mql5.com" #property version "1.21" #property strict #include //--- Input Parameters input double InpIntensityMultiplier = 4.0; // Intensity Spike Multiplier (x Avg) input int InpIntensityWindowMs = 500; // Burst Window (Milliseconds) input int InpAvgIntWindowSec = 10; // Average Window (Seconds) input int InpAbsorptionPips = 2; // Absorption Move (Max Pips) input bool InpAutoTrade = true; // Place trades on detections? input double InpLotSize = 0.1; // Lot Size for auto-trading input int InpMagicNumber = 987654; //--- Global Variables CTrade m_trade; datetime m_tick_history_ms[]; // Timestamps in milliseconds int m_tick_history_size = 5000; int m_tick_ptr = 0; double m_prev_price = 0; double m_prev_bid = 0; double m_prev_ask = 0; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { m_trade.SetExpertMagicNumber(InpMagicNumber); ArrayResize(m_tick_history_ms, m_tick_history_size); ArrayInitialize(m_tick_history_ms, 0); Print("WhaleDetector v1.21 (Fixed Direction) Initialized."); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { MqlTick tick; if(!SymbolInfoTick(_Symbol, tick)) return; // 1. Log Timestamp long now_ms = GetMicrosecondCount() / 1000; m_tick_history_ms[m_tick_ptr] = (datetime)now_ms; m_tick_ptr = (m_tick_ptr + 1) % m_tick_history_size; // 2. Calculate Intensity int current_intensity = 0; for(int i=0; i= (datetime)(now_ms - InpIntensityWindowMs)) current_intensity++; } int total_ticks_long = 0; for(int i=0; i= (datetime)(now_ms - InpAvgIntWindowSec * 1000)) total_ticks_long++; } double avg_intensity_per_window = (double)total_ticks_long * (InpIntensityWindowMs / (InpAvgIntWindowSec * 1000.0)); if(avg_intensity_per_window < 1.0) avg_intensity_per_window = 1.0; // 3. Whale Detection bool is_whale = (current_intensity >= avg_intensity_per_window * InpIntensityMultiplier); double price = (tick.last != 0) ? tick.last : ((tick.bid + tick.ask) / 2.0); double delta = MathAbs(price - m_prev_price); bool is_absorbed = (is_whale && m_prev_price > 0 && delta < InpAbsorptionPips * _Point * 10); if(is_whale) { string direction = "UNKNOWN"; // Robust Direction Detection if(tick.flags & TICK_FLAG_BUY) direction = "BUY"; else if(tick.flags & TICK_FLAG_SELL) direction = "SELL"; else if(tick.last != 0) { if(tick.last >= tick.ask) direction = "BUY"; else if(tick.last <= tick.bid) direction = "SELL"; } else // Fallback for last == 0 { if(tick.ask > m_prev_ask && m_prev_ask > 0) direction = "BUY"; else if(tick.bid < m_prev_bid && m_prev_bid > 0) direction = "SELL"; else if(tick.flags & TICK_FLAG_ASK) direction = "BUY"; else if(tick.flags & TICK_FLAG_BID) direction = "SELL"; else direction = (price > m_prev_price) ? "BUY" : (price < m_prev_price ? "SELL" : "UNKNOWN"); } if(direction != "UNKNOWN") HandleWhale(tick, current_intensity, avg_intensity_per_window, direction, is_absorbed); } // Dashboard update Comment(StringFormat("WhaleDetector v1.21\n" "-------------------\n" "Intensity: %d / Avg: %.2f\n" "Ratio: %.2fx\n" "Bid: %.5f | Ask: %.5f\n" "Status: %s", current_intensity, avg_intensity_per_window, (double)current_intensity / avg_intensity_per_window, tick.bid, tick.ask, is_whale ? "WHALE!" : "monitoring...")); m_prev_price = price; m_prev_bid = tick.bid; m_prev_ask = tick.ask; } //+------------------------------------------------------------------+ //| Handle Whale Event | //+------------------------------------------------------------------+ void HandleWhale(MqlTick &tick, int intensity, double avg, string direction, bool absorbed) { double price = (tick.last != 0) ? tick.last : (direction == "BUY" ? tick.ask : tick.bid); string name = StringFormat("Whale_%d_%d", TimeCurrent(), GetMicrosecondCount()); ObjectCreate(0, name, OBJ_ARROW, 0, tick.time, price); ObjectSetInteger(0, name, OBJPROP_ARROWCODE, (direction == "BUY") ? 233 : 234); ObjectSetInteger(0, name, OBJPROP_COLOR, (direction == "BUY") ? clrAqua : clrMagenta); ObjectSetInteger(0, name, OBJPROP_WIDTH, absorbed ? 5 : 3); if(InpAutoTrade && PositionsTotal() == 0) { double sl = (direction == "BUY") ? price - 500*_Point : price + 500*_Point; double tp = (direction == "BUY") ? price + 1000*_Point : price - 1000*_Point; if(direction == "BUY") m_trade.Buy(InpLotSize, _Symbol, tick.ask, sl, tp, "Whale Intensity Buy"); else m_trade.Sell(InpLotSize, _Symbol, tick.bid, sl, tp, "Whale Intensity Sell"); } } //+------------------------------------------------------------------+