mql5/Experts/WhaleDetector.mq5

142 lines
6.1 KiB
MQL5

2026-02-16 15:55:33 +03:00
//+------------------------------------------------------------------+
//| WhaleDetector.mq5 |
//| Copyright 2026, Antigravity AI |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2026, Antigravity AI"
#property link "https://www.mql5.com"
2026-02-17 13:40:44 +03:00
#property version "1.21"
2026-02-16 15:55:33 +03:00
#property strict
#include <Trade\Trade.mqh>
//--- Input Parameters
2026-02-17 13:40:44 +03:00
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;
2026-02-16 15:55:33 +03:00
//--- Global Variables
CTrade m_trade;
2026-02-17 13:40:44 +03:00
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;
2026-02-16 15:55:33 +03:00
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
m_trade.SetExpertMagicNumber(InpMagicNumber);
2026-02-17 13:40:44 +03:00
ArrayResize(m_tick_history_ms, m_tick_history_size);
ArrayInitialize(m_tick_history_ms, 0);
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
Print("WhaleDetector v1.21 (Fixed Direction) Initialized.");
2026-02-16 15:55:33 +03:00
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick()
{
MqlTick tick;
if(!SymbolInfoTick(_Symbol, tick)) return;
2026-02-17 13:40:44 +03:00
// 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<m_tick_history_size; i++)
{
if(m_tick_history_ms[i] >= (datetime)(now_ms - InpIntensityWindowMs)) current_intensity++;
}
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
int total_ticks_long = 0;
for(int i=0; i<m_tick_history_size; i++)
{
if(m_tick_history_ms[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);
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
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);
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
if(is_whale)
2026-02-16 15:55:33 +03:00
{
2026-02-17 13:40:44 +03:00
string direction = "UNKNOWN";
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
// Robust Direction Detection
2026-02-16 15:55:33 +03:00
if(tick.flags & TICK_FLAG_BUY) direction = "BUY";
else if(tick.flags & TICK_FLAG_SELL) direction = "SELL";
2026-02-17 13:40:44 +03:00
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
2026-02-16 15:55:33 +03:00
{
2026-02-17 13:40:44 +03:00
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");
2026-02-16 15:55:33 +03:00
}
2026-02-17 13:40:44 +03:00
if(direction != "UNKNOWN")
HandleWhale(tick, current_intensity, avg_intensity_per_window, direction, is_absorbed);
2026-02-16 15:55:33 +03:00
}
2026-02-17 13:40:44 +03:00
// 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;
2026-02-16 15:55:33 +03:00
}
//+------------------------------------------------------------------+
2026-02-17 13:40:44 +03:00
//| Handle Whale Event |
2026-02-16 15:55:33 +03:00
//+------------------------------------------------------------------+
2026-02-17 13:40:44 +03:00
void HandleWhale(MqlTick &tick, int intensity, double avg, string direction, bool absorbed)
2026-02-16 15:55:33 +03:00
{
double price = (tick.last != 0) ? tick.last : (direction == "BUY" ? tick.ask : tick.bid);
2026-02-17 13:40:44 +03:00
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);
2026-02-16 15:55:33 +03:00
2026-02-17 13:40:44 +03:00
if(InpAutoTrade && PositionsTotal() == 0)
2026-02-16 15:55:33 +03:00
{
2026-02-17 13:40:44 +03:00
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");
2026-02-16 15:55:33 +03:00
}
}
//+------------------------------------------------------------------+