untitled

Pasted Oct 11, 2026, 6:51 AM1 file528 lines

Scan to open on your phone

Point a camera at the QR code - it opens this exact paste, no app needed.

https://codepastes.com/zzgsz18jzz0b4rme
untitled
//+------------------------------------------------------------------+
//|                                EA_Grid_Fibo_NewsFilter_MT5.mq5 |
//|                                  Copyright 2026, Algorithmic Dev |
//+------------------------------------------------------------------+
#property copyright "Algorithmic Dev"
#property link      ""
#property version   "3.30"

#include <Trade\Trade.mqh>
CTrade trade;

//--- INPUT PARAMETERS
input group "=== SETTING TRADING & AUTO-COMPOUNDING ==="
input double   InpLotSize            = 0.01;      // Lot Size Awal
input double   InpLotMultiplier      = 1.3;       // Pengali Lot (1.0 = Fixed Lot)
input ulong    InpMagicNumber        = 888111;    // Magic Number
input ulong    InpSlippage           = 3;         // Max Slippage (Points)

input group "=== RISK & TARGET (DYNAMIC AUTO-COMPOUNDING) ==="
input bool     InpUsePercentageTarget= true;      // Gunakan Target % Balance (Untuk TP/SL)
input double   InpDailyTargetPercent = 3.0;       // Target Profit Harian (% Balance)
input double   InpBasketTPPercent    = 1.0;       // Basket TP (% Balance)
input double   InpBasketSLPercent    = 8.0;       // Basket SL (% Balance) - NEW v3.10
input double   InpDailyTargetUSD     = 15.00;     // Target Profit Harian ($)
input double   InpBasketTPUSD        = 10.00;     // Basket TP ($)
input double   InpBasketSLUSD        = 40.00;     // Basket SL ($) - fallback saat mode % OFF

input group "=== FEATURE 1: TRAILING BASKET PROFIT ==="
input bool     InpUseTrailingBasket  = true;      // Aktifkan Trailing Basket TP
input double   InpTrailingStartUSD   = 7.00;      // Trigger Trailing ($)
input double   InpTrailingStepUSD    = 2.00;      // Step Pengunci Profit ($)
input double   InpTrailingStartPercent = 0.6;     // Trigger Trailing (% Balance)
input double   InpTrailingStepPercent  = 0.2;     // Step Pengunci Profit (% Balance)

input group "=== FEATURE 2: SMART LAYER REDUCTION (PARTIAL CLOSE) ==="
input bool     InpUseSmartReduction  = true;      // Aktifkan Reduksi Layer Cerdas
input int      InpMinLayersForSmart  = 3;         // Minimum Layer untuk Aktifkan Reduction
input double   InpNetProfitToReduce  = 0.50;      // Minimum Profit Gabungan ($) untuk Cut Layer Terjauh

input group "=== FEATURE 3: TREND BIAS FILTER (EMA) ==="
input bool     InpUseEMAFilter       = true;      // Aktifkan Filter Tren EMA
input int      InpEMAPeriod          = 200;       // Periode EMA Filter
input ENUM_TIMEFRAMES InpEMATimeframe= PERIOD_M15; // Timeframe EMA Filter

input group "=== FEATURE 4: SPREAD & ROLLOVER PROTECTION ==="
input double   InpMaxSpreadPips      = 50.0;      // Max Spread Diizinkan (Pips)
input bool     InpBlockRollover      = true;      // Tahan Trade saat Rollover (23:00-00:00 Broker)
input int      InpRolloverStartHour  = 23;        // Jam Mulai Rollover (Broker Time)
input int      InpRolloverEndHour    = 0;         // Jam Selesai Rollover (Broker Time)

input group "=== FEATURE 5: WEEKEND & FRIDAY HARD CLOSE ==="
input bool     InpUseFridayProtection= true;      // Aktifkan Filter Proteksi Akhir Pekan
input int      InpFridayStopHour     = 15;        // Jam Stop Entry Baru pada Hari Jumat (Broker Time)
input bool     InpFridayCloseAll     = true;      // Paksa Close All Posisi pada Jumat Malam

input group "=== SETTING GRID & BASKET ==="
input double   InpBaseGridStepUSD    = 0.80;      // Jarak Grid Dasar 
input bool     InpUseFiboMultiplier  = true;      // Pengali Fibonacci untuk Jarak Grid
input int      InpMaxGridLayers      = 4;         // Batas Maksimum Layer Grid
input bool     InpUseATRGrid         = true;      // Dynamic Grid Step (Berdasarkan ATR)
input int      InpATRPeriod          = 14;        // Periode ATR
input double   InpATRFactor          = 1.5;       // Pengali ATR (grid lebih lebar)
input double   InpMaxSpikeUSD        = 5.00;      // Spike Filter ($)

input group "=== SETTING 3 SESI TRADING (BROKER TIME) ==="
input bool     InpUseSessionFilter   = true;      // Aktifkan Filter Sesi
input bool     InpUseAsiaSession     = true;      // Sesi Asia (00:00 - 08:00)
input int      InpAsiaStartHour      = 0;
input int      InpAsiaEndHour        = 8;
input bool     InpUseLondonSession   = true;      // Sesi London 
input int      InpLondonStartHour    = 9;
input int      InpLondonEndHour      = 16;
input bool     InpUseUSSession       = false;     // Sesi New York (OFF default v3.20)
input int      InpUSStartHour        = 15;
input int      InpUSEndHour          = 22;

input group "=== SETTING NEWS FILTER & STOP TRADE ==="
input bool     InpUseNewsFilter      = true;      // News Filter Native
input int      InpNewsBeforeMins     = 30;        // Menit Tahan Sebelum Berita
input int      InpNewsAfterMins      = 30;        // Menit Tahan Setelah Berita
input bool     InpFilterHighImpact   = true;      // Red Folder
input bool     InpFilterMedImpact    = false;     // Orange Folder
input bool     InpEnableStopTrade    = true;      // Auto Stop jika Target / Basket SL Hit

input group "=== EQUITY PROTECTOR (v3.10) ==="
input bool     InpUseEquityProtector = true;      // Stop total saat drawdown akun berlebih
input double   InpMaxEquityDDPercent = 10.0;      // Max Drawdown Akun (% Balance)

input group "=== EXECUTION SAFETY (v3.20) ==="
input int      InpBasketCooldownMins = 30;        // Jeda antar basket setelah close (menit)

input group "=== HIGH WINRATE FILTERS (v3.30) ==="
input bool     InpUseRSIFilter       = true;      // Entry hanya saat RSI ekstrem (jenuh)
input int      InpRSIPeriod          = 14;        // Periode RSI
input double   InpRSIBuyMax          = 35.0;      // Buy hanya jika RSI < ini
input double   InpRSISellMin         = 65.0;      // Sell hanya jika RSI > ini
input bool     InpUseADXFilter       = true;      // Blokir entry saat tren kuat (musuh grid)
input int      InpADXPeriod          = 14;        // Periode ADX
input double   InpADXMax             = 25.0;      // Max ADX untuk entry
input bool     InpUseTimeStop        = true;      // Tutup basket jika terlalu lama floating
input int      InpMaxBasketHours     = 12;        // Max durasi basket (jam)

input group "=== DASHBOARD DISPLAY ==="
input color    InpBgColor            = C'20,24,35';// Panel Background
input color    InpHeaderColor        = C'30,35,48';// Panel Header
input color    InpTextColor          = clrWhite;  // Text Color
input color    InpProfitColor        = clrLime;   // Profit Color
input color    InpLossColor          = clrRed;    // Loss Color

//--- GLOBAL VARIABLES
datetime g_lastDayChecked     = 0;
bool     g_targetReachedToday = false;
bool     g_stopTradeActive    = false;
bool     g_manualButtonOff    = false;     
string   g_stopReason         = "";
string   g_prefix             = "DB_Panel_";
int      g_handleATR          = INVALID_HANDLE;
int      g_handleEMA          = INVALID_HANDLE;
int      g_handleRSI          = INVALID_HANDLE;
int      g_handleADX          = INVALID_HANDLE;
datetime g_basketStartTime     = 0;      // v3.30: waktu basket mulai dibuka
double   g_basketHighProfit   = 0.0;
datetime g_lastBasketCloseTime = 0;      // v3.20: waktu basket terakhir tutup
int      g_prevOpenCount       = 0;      // v3.20: jumlah posisi tick sebelumnya

const double g_fiboRatios[10] = {1.0, 1.0, 1.618, 2.618, 4.236, 6.854, 11.090, 17.944, 29.034, 46.978};

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
{
   trade.SetExpertMagicNumber(InpMagicNumber);
   trade.SetDeviationInPoints(InpSlippage);

   if(InpUseATRGrid)
   {
      g_handleATR = iATR(_Symbol, PERIOD_CURRENT, InpATRPeriod);
      if(g_handleATR == INVALID_HANDLE)
      {
         Print("Gagal menginisialisasi Indikator ATR.");
         return(INIT_FAILED);
      }
   }

   if(InpUseEMAFilter)
   {
      g_handleEMA = iMA(_Symbol, InpEMATimeframe, InpEMAPeriod, 0, MODE_EMA, PRICE_CLOSE);
      if(g_handleEMA == INVALID_HANDLE)
      {
         Print("Gagal menginisialisasi Indikator EMA.");
         return(INIT_FAILED);
      }
   }

   if(InpUseRSIFilter)
   {
      g_handleRSI = iRSI(_Symbol, InpEMATimeframe, InpRSIPeriod, PRICE_CLOSE);
      if(g_handleRSI == INVALID_HANDLE)
      {
         Print("Gagal menginisialisasi Indikator RSI.");
         return(INIT_FAILED);
      }
   }

   if(InpUseADXFilter)
   {
      g_handleADX = iADX(_Symbol, InpEMATimeframe, InpADXPeriod);
      if(g_handleADX == INVALID_HANDLE)
      {
         Print("Gagal menginisialisasi Indikator ADX.");
         return(INIT_FAILED);
      }
   }

   // v3.10: Grid step memakai satuan harga - EA ini dirancang untuk XAUUSD
   if(StringFind(_Symbol, "XAU") < 0)
      Print("PERINGATAN: EA dioptimalkan untuk XAUUSD. Simbol ", _Symbol, " mungkin tidak cocok (grid step dalam satuan harga).");

   EventSetTimer(1);
   InitDashboardUI();
   UpdateDashboard();
   return(INIT_SUCCEEDED);
}

//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
   EventKillTimer();
   if(g_handleATR != INVALID_HANDLE) IndicatorRelease(g_handleATR);
   if(g_handleEMA != INVALID_HANDLE) IndicatorRelease(g_handleEMA);
   if(g_handleRSI != INVALID_HANDLE) IndicatorRelease(g_handleRSI);
   if(g_handleADX != INVALID_HANDLE) IndicatorRelease(g_handleADX);
   ObjectsDeleteAll(0, g_prefix);
}

//+------------------------------------------------------------------+
//| Expert timer function                                            |
//+------------------------------------------------------------------+
void OnTimer()
{
   UpdateDashboard();
}

//+------------------------------------------------------------------+
//| Chart Event Function                                             |
//+------------------------------------------------------------------+
void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
{
   if(id == CHARTEVENT_OBJECT_CLICK)
   {
      if(sparam == g_prefix + "Btn_Toggle")
      {
         g_manualButtonOff = !g_manualButtonOff; 
         ObjectSetInteger(0, g_prefix + "Btn_Toggle", OBJPROP_STATE, false);
         UpdateDashboard();
      }
   }
}

//+------------------------------------------------------------------+
//| Dynamic Target & Risk Value Getters                              |
//+------------------------------------------------------------------+
double GetDailyTargetUSD()
{
   if(InpUsePercentageTarget)
      return AccountInfoDouble(ACCOUNT_BALANCE) * (InpDailyTargetPercent / 100.0);
   return InpDailyTargetUSD;
}

double GetBasketTPUSD()
{
   if(InpUsePercentageTarget)
      return AccountInfoDouble(ACCOUNT_BALANCE) * (InpBasketTPPercent / 100.0);
   return InpBasketTPUSD;
}

double GetBasketSLUSD()
{
   // v3.10: SL kini mengikuti mode persen bila InpUsePercentageTarget aktif
   if(InpUsePercentageTarget)
      return AccountInfoDouble(ACCOUNT_BALANCE) * (InpBasketSLPercent / 100.0);
   return InpBasketSLUSD;
}

//+------------------------------------------------------------------+
//| Helper Filters & Conditions                                      |
//+------------------------------------------------------------------+
bool IsSpreadOK()
{
   double pipSize = (_Digits == 3 || _Digits == 5) ? _Point * 10.0 : _Point;
   double currentSpread = (SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID)) / pipSize;
   return (currentSpread <= InpMaxSpreadPips);
}

bool IsRolloverTime()
{
   if(!InpBlockRollover) return false;
   MqlDateTime dt;
   TimeToStruct(TimeCurrent(), dt);
   if(InpRolloverStartHour > InpRolloverEndHour)
      return (dt.hour >= InpRolloverStartHour || dt.hour < InpRolloverEndHour);
   return (dt.hour >= InpRolloverStartHour && dt.hour < InpRolloverEndHour);
}

bool IsFridayStop()
{
   if(!InpUseFridayProtection) return false;
   MqlDateTime dt;
   TimeToStruct(TimeCurrent(), dt);
   return (dt.day_of_week == 5 && dt.hour >= InpFridayStopHour);
}

//+------------------------------------------------------------------+
//| Feature 1: Trailing Basket Profit Logic                          |
//+------------------------------------------------------------------+
void CheckTrailingBasket(double totalFloating)
{
   if(!InpUseTrailingBasket || totalFloating <= 0)
   {
      g_basketHighProfit = 0.0;
      return;
   }

   double startUSD = InpTrailingStartUSD;
   double stepUSD  = InpTrailingStepUSD;

   if(InpUsePercentageTarget)
   {
      double bal = AccountInfoDouble(ACCOUNT_BALANCE);
      startUSD = bal * (InpTrailingStartPercent / 100.0);
      stepUSD  = bal * (InpTrailingStepPercent / 100.0);
   }

   if(totalFloating >= startUSD)
   {
      if(totalFloating > g_basketHighProfit)
         g_basketHighProfit = totalFloating;

      double lockFloor = g_basketHighProfit - stepUSD;
      if(totalFloating <= lockFloor && lockFloor > 0)
      {
         CloseAllPositions();
         g_basketHighProfit = 0.0;
      }
   }
}

//+------------------------------------------------------------------+
//| Feature 2: Smart Layer Reduction (Partial Close)                 |
//+------------------------------------------------------------------+
void CheckSmartLayerReduction()
{
   if(!InpUseSmartReduction) return;
   
   int openCount = GetOpenPositionsCount();
   if(openCount < InpMinLayersForSmart) return;

   ulong oldestTicket = 0, newestTicket = 0;
   datetime oldestTime = D'2099.12.31', newestTime = 0;

   for(int i = PositionsTotal() - 1; i >= 0; i--)
   {
      ulong ticket = PositionGetTicket(i);
      if(ticket > 0 && PositionGetString(POSITION_SYMBOL) == _Symbol && PositionGetInteger(POSITION_MAGIC) == InpMagicNumber)
      {
         datetime posTime = (datetime)PositionGetInteger(POSITION_TIME);
         if(posTime < oldestTime) { oldestTime = posTime; oldestTicket = ticket; }
         if(posTime > newestTime) { newestTime = posTime; newestTicket = ticket; }
      }
   }

   if(oldestTicket > 0 && newestTicket > 0 && oldestTicket != newestTicket)
   {
      PositionSelectByTicket(oldestTicket);
      double oldestProfit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);
      
      PositionSelectByTicket(newestTicket);
      double newestProfit = PositionGetDouble(POSITION_PROFIT) + PositionGetDouble(POSITION_SWAP);

      if((oldestProfit + newestProfit) >= InpNetProfitToReduce)
      {
         trade.PositionClose(oldestTicket);
         trade.PositionClose(newestTicket);
         Print("Smart Layer Reduction Triggered! Closed Ticket ", oldestTicket, " and ", newestTicket);
      }
   }
}

//+------------------------------------------------------------------+
//| Pengecekan Status 3 Sesi Trading                                 |
//+------------------------------------------------------------------+
bool IsActiveSession(string &activeSessionName)
{
   if(!InpUseSessionFilter)
   {
      activeSessionName = "ALL SESSIONS (24H)";
      return true;
   }

   MqlDateTime dt;
   TimeToStruct(TimeCurrent(), dt);
   int h = dt.hour;

   bool asia   = InpUseAsiaSession   && (h >= InpAsiaStartHour   && h < InpAsiaEndHour);
   bool london = InpUseLondonSession && (h >= InpLondonStartHour && h < InpLondonEndHour);
   bool us     = InpUseUSSession     && (h >= InpUSStartHour     && h < InpUSEndHour);

   string sessionStr = "";
   if(asia)   sessionStr += "[ASIA] ";
   if(london) sessionStr += "[LONDON] ";
   if(us)     sessionStr += "[NY] ";

   if(asia || london || us)
   {
      activeSessionName = sessionStr;
      return true;
   }

   activeSessionName = "OFF-SESSION (PAUSED)";
   return false;
}

//+------------------------------------------------------------------+
//| Modul Saran Teknikal Spesifik Sesi                               |
//+------------------------------------------------------------------+
string GetSessionTechnicalAdvice(color &adviceColor)
{
   MqlDateTime dt;
   TimeToStruct(TimeCurrent(), dt);
   int h = dt.hour;

   bool isAsia   = (h >= InpAsiaStartHour   && h < InpAsiaEndHour);
   bool isLondon = (h >= InpLondonStartHour && h < InpLondonEndHour);
   bool isUS     = (h >= InpUSStartHour     && h < InpUSEndHour);

   if(isAsia)
   {
      adviceColor = clrLime;
      return "ASIA: Range Scalping (Ideal Standard Grid)";
   }
   if(isLondon && isUS)
   {
      adviceColor = clrOrangeRed;
      return "OVERLAP LDN-NY: Volatilitas Max (Target Cepat Hit)";
   }
   if(isLondon)
   {
      adviceColor = clrGold;
      return "LONDON: Trend Breakout (Pantau Penambahan Layer)";
   }
   if(isUS)
   {
      adviceColor = clrOrange;
      return "NEW YORK: High Volatility (Perhatikan Basket SL)";
   }

   adviceColor = clrGray;
   return "OFF-SESSION: Sesi Tenang (Fokus Penyelesaian Grid)";
}

//+------------------------------------------------------------------+
//| Modul Sistem Rekomendasi Otomatis (Market Recommendation)        |
//+------------------------------------------------------------------+
string GetMarketRecommendation(color &recommendedColor)
{
   if(g_manualButtonOff)
   {
      recommendedColor = clrOrange;
      return "EA PAUSED MANUALLY. TURN ON TO RESUME.";
   }

   if(!IsSpreadOK())
   {
      recommendedColor = clrRed;
      return "HIGH SPREAD DETECTED. ENTRY PAUSED.";
   }

   if(IsRolloverTime())
   {
      recommendedColor = clrOrange;
      return "ROLLOVER PERIOD. ENTRY PAUSED.";
   }

   if(IsFridayStop())
   {
      recommendedColor = clrGold;
      return "FRIDAY FILTER ACTIVE. NO NEW GRIDS.";
   }

   if(IsNewsTime())
   {
      recommendedColor = clrRed;
      return "HIGH IMPACT NEWS NEARBY. HOLD NEW GRIDS.";
   }

   // v3.20: status cooldown antar basket
   if(GetOpenPositionsCount() == 0 && g_lastBasketCloseTime > 0 &&
      (TimeCurrent() - g_lastBasketCloseTime) < InpBasketCooldownMins * 60)
   {
      recommendedColor = clrGold;
      return "COOLDOWN AFTER BASKET CLOSE. WAITING.";
   }

   string sessionName = "";
   if(!IsActiveSession(sessionName))
   {
      recommendedColor = clrGold;
      return "OUTSIDE TRADING SESSION. WAIT FOR OPEN.";
   }

   double floatingPL = AccountInfoDouble(ACCOUNT_PROFIT);
   double maxSL      = GetBasketSLUSD();
   if(maxSL > 0 && floatingPL <= -(maxSL * 0.6))
   {
      recommendedColor = clrRed;
      return "HIGH DRAWDOWN RISK! MONITOR CLOSELY.";
   }

   int openCount = GetOpenPositionsCount();
   if(openCount >= InpMaxGridLayers)
   {
      recommendedColor = clrOrange;
      return "MAX GRID LAYERS REACHED. AWAITING TP.";
   }

   recommendedColor = clrLime;
   if(openCount == 0)
      return "CONDITIONS OPTIMAL. READY FOR FIRST ENTRY.";
   
   return "GRID ACTIVE. MARKET CONDITIONS STABLE.";
}

//+------------------------------------------------------------------+
//| Fungsi Pengecekan News Filter (Calendar Native MT5)              |
//+------------------------------------------------------------------+
bool IsNewsTime()
{
   if(!InpUseNewsFilter) return false;

   static datetime lastCheck = 0;
   static bool isNews = false;

   if(TimeCurrent() - lastCheck < 30) return isNews;
   lastCheck = TimeCurrent();

   datetime fromTime = TimeCurrent() - (InpNewsAfterMins * 60);
   datetime toTime   = TimeCurrent() + (InpNewsBeforeMins * 60);

   MqlCalendarValue values[];
   int count = CalendarValueHistory(values, fromTime, toTime, NULL, NULL);
   
   if(count > 0)
   {
      for(int i = 0; i < count; i++)
      {
         MqlCalendarEvent event;
         if(CalendarEventById(values[i].event_id, event))
         {
            MqlCalendarCountry country;
            if(CalendarCountryById(event.country_id, country))
            {
               string curr = country.currency;
               string sym  = _Symbol;

               if(StringFind(sym, curr) >= 0 || (curr == "USD" && String

20,000 chars · codepastes.com