Gold_Fibo_EA_v1.27_AntiWick_Fusion.mq5
Zeroboyz - MQL5 Expert Advisor Source Code
360 lines
#property version "1.27_AntiWick_Fusion"
#property strict
#include <Trade\Trade.mqh>
CTrade trade;
// Input parameters
input int InpBuySpikePoints = 800; // Dual Engine input
input int InpSellSpikePoints = 800;
input int InpTrendPoints = 1000;
input int InpTrendBars = 5;
input int InpMinSameDirCandles = 3;
// Anti-Wick Filter inputs
input double InpWickRatioMax = 0.35;
input double InpMinBodyRatio = 0.50;
// v1.25 Protections inputs
input bool InpUseEMATrendFilter = true;
input int InpEMAPeriod = 200;
input ENUM_TIMEFRAMES InpEMATimeframe = PERIOD_M5;
input bool InpEnableWhipsawFilter = true;
input int InpMomentumBreakoutPts = 150;
// Scale-out Multi-Position inputs
input int InpNumPositions = 4;
input double InpBaseLot = 0.01;
input int InpTakeProfitPts1 = 300;
input int InpTakeProfitPts2 = 600;
input int InpTakeProfitPts3 = 900;
input int InpTakeProfitPts4 = 1200;
// Risk & Limits inputs
input double InpDailyLossLimitUSD = 50;
input double InpMaxDailyGivebackUSD = 30;
input int InpMaxWinsPerDay = 5;
// POE2 Warp / Rage Quit Stun inputs
input double InpWarpProfitUSD = 100;
input int InpWarpCooldownMin = 30;
input int InpMaxLossStreak = 2;
input int InpRageQuitStunMin = 60;
// Time & Friday inputs
input bool InpUseTimeFilter = false;
input int InpStartHour = 8;
input int InpEndHour = 20;
input bool InpUseFridayClose = true;
input int InpFridayCloseHour = 21;
// Magic number
input int InpMagicNumber = 127001;
// Global variables for daily statistics
datetime g_lastResetDate = 0;
double g_dailyProfitUSD = 0.0;
int g_dailyWins = 0;
int g_consecutiveLosses = 0;
datetime g_lastWarpTime = 0;
datetime g_lastRageQuitTime = 0;
// EMA handle
int g_emaHandle = INVALID_HANDLE;
//+------------------------------------------------------------------+
//| Expert initialization function |
//+------------------------------------------------------------------+
int OnInit(){
// Initialize EMA if required
if(InpUseEMATrendFilter){
g_emaHandle = iMA(_Symbol, InpEMATimeframe, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
if(g_emaHandle == INVALID_HANDLE){
Print("Failed to create EMA handle");
return INIT_FAILED;
}
}
// Reset daily stats
g_lastResetDate = DateCurrent();
g_dailyProfitUSD = 0.0;
g_dailyWins = 0;
g_consecutiveLosses = 0;
g_lastWarpTime = 0;
g_lastRageQuitTime = 0;
return INIT_SUCCEEDED;
}
//+------------------------------------------------------------------+
//| Expert deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
if(g_emaHandle != INVALID_HANDLE){
IndicatorRelease(g_emaHandle);
}
}
//+------------------------------------------------------------------+
//| Expert tick function |
//+------------------------------------------------------------------+
void OnTick(){
// Daily reset at midnight server time
if(DateCurrent() != g_lastResetDate){
g_lastResetDate = DateCurrent();
g_dailyProfitUSD = 0.0;
g_dailyWins = 0;
g_consecutiveLosses = 0;
}
// Apply time filter if enabled
if(InpUseTimeFilter){
int hour = TimeHour(TimeCurrent());
if(hour < InpStartHour || hour > InpEndHour) return;
}
// Friday close check
if(CheckFridayClose()) return;
// Warp and Rage Quit cooldowns
if(CheckWarpCooldown()) return;
if(CheckRageQuitStun()) return;
// Daily loss & giveback limits
if(CalculateNetDailyProfit() <= -InpDailyLossLimitUSD) return;
if(g_dailyProfitUSD < 0 && MathAbs(g_dailyProfitUSD) > InpMaxDailyGivebackUSD) return;
// Determine direction
bool isBuy = IsSpike(true) && IsTrend(true);
bool isSell = IsSpike(false) && IsTrend(false);
// Anti-Wick filter
if(!CheckAntiWick(isBuy, isSell)) return;
// EMA trend alignment
if(InpUseEMATrendFilter && !IsEMATrendAligned(isBuy, isSell)) return;
// Whipsaw detection
if(InpEnableWhipsawFilter && DetectWhipsaw()) return;
// Execute positions if signal present
if(isBuy) ExecuteMultiplePositions(ORDER_TYPE_BUY);
if(isSell) ExecuteMultiplePositions(ORDER_TYPE_SELL);
// Manage existing positions (breakeven, trailing)
ManagePositions();
}
//+------------------------------------------------------------------+
//| Check for Friday close condition |
//+------------------------------------------------------------------+
bool CheckFridayClose(){
if(!InpUseFridayClose) return false;
datetime now = TimeCurrent();
if(TimeDayOfWeek(now) == 5){ // Friday
int hour = TimeHour(now);
if(hour >= InpFridayCloseHour) {
CloseAllPositions();
return true;
}
}
return false;
}
//+------------------------------------------------------------------+
//| Warp cooldown check |
//+------------------------------------------------------------------+
bool CheckWarpCooldown(){
if(g_lastWarpTime==0) return false;
datetime now = TimeCurrent();
if((now - g_lastWarpTime) < (InpWarpCooldownMin*60)) return true;
return false;
}
//+------------------------------------------------------------------+
//| Rage Quit stun check |
//+------------------------------------------------------------------+
bool CheckRageQuitStun(){
if(g_lastRageQuitTime==0) return false;
datetime now = TimeCurrent();
if((now - g_lastRageQuitTime) < (InpRageQuitStunMin*60)) return true;
return false;
}
//+------------------------------------------------------------------+
//| Calculate net daily profit in USD (approx using SymbolInfoDouble) |
//+------------------------------------------------------------------+
double CalculateNetDailyProfit(){
double profit = 0.0;
for(int i=PositionsTotal()-1; i>=0; i--){
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC) != InpMagicNumber) continue;
profit += PositionGetDouble(POSITION_PROFIT);
}
// Convert to USD if needed - assuming account currency is USD for simplicity
g_dailyProfitUSD = profit;
return profit;
}
//+------------------------------------------------------------------+
//| Anti-Wick filter implementation |
//+------------------------------------------------------------------+
bool CheckAntiWick(bool buySignal, bool sellSignal){
MqlRates rates[];
int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, 1, rates);
if(copied <= 0) return false;
double high = rates[0].high;
double low = rates[0].low;
double open = rates[0].open;
double close = rates[0].close;
double body = MathAbs(close - open);
double totalRange = high - low;
double upperWick = high - MathMax(open, close);
double lowerWick = MathMin(open, close) - low;
double wickRatio = (buySignal) ? upperWick/totalRange : lowerWick/totalRange;
double bodyRatio = body/totalRange;
if(wickRatio > InpWickRatioMax) return false;
if(bodyRatio < InpMinBodyRatio) return false;
return true;
}
//+------------------------------------------------------------------+
//| Spike detection function |
//+------------------------------------------------------------------+
bool IsSpike(bool isBuy){
// Simple implementation: compare current candle range against input points
MqlRates rates[];
if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 2, rates) < 2) return false;
double range = rates[0].high - rates[0].low;
int points = isBuy ? InpBuySpikePoints : InpSellSpikePoints;
return (range * _Point) >= points * _Point;
}
//+------------------------------------------------------------------+
//| Trend detection function |
//+------------------------------------------------------------------+
bool IsTrend(bool isBuy){
// Count consecutive candles in same direction meeting trend points
MqlRates rates[];
int copied = CopyRates(_Symbol, PERIOD_CURRENT, 0, InpTrendBars+1, rates);
if(copied < InpTrendBars+1) return false;
int sameDirCount = 0;
for(int i=1; i<=InpTrendBars; i++){
double prevClose = rates[i].close;
double curClose = rates[i-1].close;
if(isBuy && curClose > prevClose) sameDirCount++;
if(!isBuy && curClose < prevClose) sameDirCount++;
}
return sameDirCount >= InpMinSameDirCandles && (sameDirCount * _Point) >= InpTrendPoints * _Point;
}
//+------------------------------------------------------------------+
//| EMA trend alignment check |
//+------------------------------------------------------------------+
bool IsEMATrendAligned(bool isBuy, bool isSell){
if(g_emaHandle == INVALID_HANDLE) return false;
double ema[];
if(CopyBuffer(g_emaHandle, 0, 0, 2, ema) < 2) return false;
double lastClose = Close[0];
double prevEma = ema[1];
double curEma = ema[0];
if(isBuy) return lastClose > curEma && curEma > prevEma;
if(isSell) return lastClose < curEma && curEma < prevEma;
return false;
}
//+------------------------------------------------------------------+
//| Whipsaw detection function |
//+------------------------------------------------------------------+
bool DetectWhipsaw(){
// Simple volatility based whipsaw detection
MqlRates rates[];
if(CopyRates(_Symbol, PERIOD_CURRENT, 0, 5, rates) < 5) return false;
double sumRange = 0.0;
for(int i=0;i<5;i++) sumRange += rates[i].high - rates[i].low;
double avgRange = sumRange/5.0;
// If current range exceeds threshold based on momentum breakout points
double curRange = rates[0].high - rates[0].low;
return curRange > (InpMomentumBreakoutPts * _Point) && curRange > 2*avgRange;
}
//+------------------------------------------------------------------+
//| Execute multiple positions with scaling |
//+------------------------------------------------------------------+
void ExecuteMultiplePositions(ENUM_ORDER_TYPE type){
// Determine existing position count for this magic number
int existing = 0;
for(int i=PositionsTotal()-1;i>=0;i--){
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC)!=InpMagicNumber) continue;
if(PositionGetInteger(POSITION_TYPE)==type) existing++;
}
if(existing >= InpNumPositions) return; // max positions reached
// Determine lot size based on position index
double lot = InpBaseLot * MathPow(2, existing);
// Determine TP based on position index
int tpPts = 0;
switch(existing){
case 0: tpPts = InpTakeProfitPts1; break;
case 1: tpPts = InpTakeProfitPts2; break;
case 2: tpPts = InpTakeProfitPts3; break;
case 3: tpPts = InpTakeProfitPts4; break;
}
double price = (type==ORDER_TYPE_BUY) ? SymbolInfoDouble(_Symbol,SYMBOL_ASK) : SymbolInfoDouble(_Symbol,SYMBOL_BID);
double tpPrice = (type==ORDER_TYPE_BUY) ? price + tpPts*_Point : price - tpPts*_Point;
trade.SetExpertMagicNumber(InpMagicNumber);
bool result = trade.PositionOpen(_Symbol, type, lot, price, 0, tpPrice, "");
if(result){
Print("Opened position ",EnumToString(type)," lot=",lot);
} else {
Print("Failed to open position: ",trade.ResultComment());
}
}
//+------------------------------------------------------------------+
//| Manage open positions (breakeven, trailing) |
//+------------------------------------------------------------------+
void ManagePositions(){
for(int i=PositionsTotal()-1;i>=0;i--){
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC)!=InpMagicNumber) continue;
ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
double openPrice = PositionGetDouble(POSITION_PRICE_OPEN);
double curPrice = (posType==POSITION_TYPE_BUY) ? SymbolInfoDouble(_Symbol,SYMBOL_BID) : SymbolInfoDouble(_Symbol,SYMBOL_ASK);
double profit = PositionGetDouble(POSITION_PROFIT);
// Breakeven at 50% of TP distance
double tp = PositionGetDouble(POSITION_TP);
double breakevenPrice = (posType==POSITION_TYPE_BUY) ? openPrice + (tp - openPrice)/2 : openPrice - (openPrice - tp)/2;
if(posType==POSITION_TYPE_BUY && curPrice >= breakevenPrice && PositionGetDouble(POSITION_SL)==0.0){
trade.PositionModify(ticket, breakevenPrice, 0.0);
}
if(posType==POSITION_TYPE_SELL && curPrice <= breakevenPrice && PositionGetDouble(POSITION_SL)==0.0){
trade.PositionModify(ticket, breakevenPrice, 0.0);
}
// Trailing stop 30% of TP distance
double trail = 0.3 * MathAbs(tp - openPrice);
double newSL = (posType==POSITION_TYPE_BUY) ? curPrice - trail : curPrice + trail;
if(newSL > PositionGetDouble(POSITION_SL)){
trade.PositionModify(ticket, newSL, 0.0);
}
}
}
//+------------------------------------------------------------------+
//| Close all positions (used for Friday close) |
//+------------------------------------------------------------------+
void CloseAllPositions(){
for(int i=PositionsTotal()-1;i>=0;i--){
ulong ticket = PositionGetTicket(i);
if(PositionGetInteger(POSITION_MAGIC)!=InpMagicNumber) continue;
trade.PositionClose(ticket);
}
}
//+------------------------------------------------------------------+
//| Expert shutdown |
//+------------------------------------------------------------------+
void OnDeinit(const int reason){
// Already defined earlier - keep for completeness
if(g_emaHandle!=INVALID_HANDLE) IndicatorRelease(g_emaHandle);
}
//+------------------------------------------------------------------+