//+------------------------------------------------------------------+ //| MajorStructure_Zones_EA.mq5 | //| Step 1.5: BOS Confirmation + Zone Drawing + Bias | //+------------------------------------------------------------------+ #property copyright "Professional Trader & AI Assistant" #property version "1.50" #property strict //--- Input Parameters input int MinorPivotLookback = 3; // تعداد کندل چپ/راست برای شناسایی مینور (در 15m = 3 یعنی 45 دقیقه) input int MaxBarsToScan = 500; // حداکثر کندل‌های 4H برای جستجو input color BullishZoneColor = clrLime; // رنگ ناحیه کف ماژور (حمایت) input color BearishZoneColor = clrRed; // رنگ ناحیه سقف ماژور (مقاومت) input int ZoneTransparency = 80; // شفافیت ناحیه (0-255) //--- Global Variables // نواحی ماژور (High و Low کندل مربوطه) double majorLowZoneHigh = 0, majorLowZoneLow = 0; datetime majorLowZoneTime = 0; int majorLowBarIndex = -1; double majorHighZoneHigh = 0, majorHighZoneLow = 0; datetime majorHighZoneTime = 0; int majorHighBarIndex = -1; string biasDirection = "NEUTRAL"; // نام آبجکت‌های گرافیکی string lowZoneName = "MajorLowZone"; string highZoneName = "MajorHighZone"; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { Print("EA v1.5 Initialized. Scanning for BOS-confirmed Major Zones..."); return (INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { // پاک کردن تمام آبجکت‌های رسم شده ObjectDelete(0, lowZoneName); ObjectDelete(0, highZoneName); Comment(""); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { // فقط یک بار در هر کندل جدید 4 ساعته محاسبات را انجام می‌دهیم static datetime lastBarTime = 0; datetime currentBarTime = iTime(_Symbol, PERIOD_H4, 0); if (lastBarTime == currentBarTime) { // در تیک‌های میانی، فقط ناحیه جاری را تا زمان حال گسترش می‌دهیم ExtendZonesToCurrentTime(); return; } lastBarTime = currentBarTime; // 1. دریافت داده‌های تایم فریم 4 ساعته double high[], low[], close[]; datetime time[]; ArraySetAsSeries(high, true); ArraySetAsSeries(low, true); ArraySetAsSeries(close, true); ArraySetAsSeries(time, true); int copied = CopyHigh(_Symbol, PERIOD_H4, 0, MaxBarsToScan, high); CopyLow(_Symbol, PERIOD_H4, 0, MaxBarsToScan, low); CopyClose(_Symbol, PERIOD_H4, 0, MaxBarsToScan, close); CopyTime(_Symbol, PERIOD_H4, 0, MaxBarsToScan, time); if (copied <= 0) { Print("Error copying 4H data."); return; } // 2. اسکن تاریخی برای شناسایی BOS و نواحی ماژور ScanForMajorZones(high, low, close, time, copied); // 3. تعیین بایاس DetermineBias(); // 4. رسم نواحی روی چارت DrawMajorZones(); // 5. نمایش داشبورد DisplayDashboard(); } //+------------------------------------------------------------------+ //| اسکن تاریخی برای شناسایی نواحی ماژور با تاییدیه BOS | //+------------------------------------------------------------------+ void ScanForMajorZones(double &high[], double &low[], double &close[], datetime &time[], int total) { // ریست کردن متغیرها majorLowBarIndex = -1; majorHighBarIndex = -1; int lastMinorHighIdx = -1; int lastMinorLowIdx = -1; // حلقه از گذشته به حال (اندیس بزرگ به کوچک) for (int i = total - MinorPivotLookback - 1; i >= MinorPivotLookback; i--) { // بررسی آیا کندل i یک سقف مینور است if (IsMinorPivot(high, i, true)) { lastMinorHighIdx = i; } // بررسی آیا کندل i یک کف مینور است if (IsMinorPivot(low, i, false)) { lastMinorLowIdx = i; } // بررسی BOS صعودی: آیا Close کندل i بالاتر از آخرین سقف مینور است؟ if (lastMinorHighIdx != -1 && i < lastMinorHighIdx && close[i] > high[lastMinorHighIdx]) { // BOS صعودی رخ داد -> کف مینور قبلی حالا کف ماژور تایید شده است if (lastMinorLowIdx != -1 && lastMinorLowIdx > lastMinorHighIdx) { majorLowBarIndex = lastMinorLowIdx; majorLowZoneHigh = high[lastMinorLowIdx]; majorLowZoneLow = low[lastMinorLowIdx]; majorLowZoneTime = time[lastMinorLowIdx]; } } // بررسی BOS نزولی: آیا Close کندل i پایین‌تر از آخرین کف مینور است؟ if (lastMinorLowIdx != -1 && i < lastMinorLowIdx && close[i] < low[lastMinorLowIdx]) { // BOS نزولی رخ داد -> سقف مینور قبلی حالا سقف ماژور تایید شده است if (lastMinorHighIdx != -1 && lastMinorHighIdx > lastMinorLowIdx) { majorHighBarIndex = lastMinorHighIdx; majorHighZoneHigh = high[lastMinorHighIdx]; majorHighZoneLow = low[lastMinorHighIdx]; majorHighZoneTime = time[lastMinorHighIdx]; } } } } //+------------------------------------------------------------------+ //| بررسی آیا کندل idx یک پراوت مینور است | //+------------------------------------------------------------------+ bool IsMinorPivot(double &data[], int idx, bool isHigh) { for (int j = 1; j <= MinorPivotLookback; j++) { if (isHigh) { if (data[idx] <= data[idx - j] || data[idx] <= data[idx + j]) return false; } else { if (data[idx] >= data[idx - j] || data[idx] >= data[idx + j]) return false; } } return true; } //+------------------------------------------------------------------+ //| تعیین بایاس بر اساس قانون تازگی | //+------------------------------------------------------------------+ void DetermineBias() { if (majorHighBarIndex == -1 && majorLowBarIndex == -1) { biasDirection = "NEUTRAL (No Major Structure)"; return; } if (majorHighBarIndex == -1) { biasDirection = "BULLISH (Only Major Low Found)"; return; } if (majorLowBarIndex == -1) { biasDirection = "BEARISH (Only Major High Found)"; return; } // در آرایه سری، اندیس کوچکتر = زمان جدیدتر if (majorHighBarIndex < majorLowBarIndex) { biasDirection = "BEARISH (Short Only)"; } else if (majorLowBarIndex < majorHighBarIndex) { biasDirection = "BULLISH (Long Only)"; } else { biasDirection = "NEUTRAL (Equal Time)"; } } //+------------------------------------------------------------------+ //| رسم نواحی ماژور روی چارت | //+------------------------------------------------------------------+ void DrawMajorZones() { // رسم ناحیه کف ماژور (حمایت) if (majorLowBarIndex != -1) { if (ObjectFind(0, lowZoneName) < 0) { ObjectCreate(0, lowZoneName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); ObjectSetInteger(0, lowZoneName, OBJPROP_COLOR, BullishZoneColor); ObjectSetInteger(0, lowZoneName, OBJPROP_FILL, true); ObjectSetInteger(0, lowZoneName, OBJPROP_BACK, true); } ObjectSetDouble(0, lowZoneName, OBJPROP_PRICE, 0, majorLowZoneHigh); ObjectSetDouble(0, lowZoneName, OBJPROP_PRICE, 1, majorLowZoneLow); ObjectSetInteger(0, lowZoneName, OBJPROP_TIME, 0, majorLowZoneTime); ObjectSetInteger(0, lowZoneName, OBJPROP_TIME, 1, TimeCurrent()); } // رسم ناحیه سقف ماژور (مقاومت) if (majorHighBarIndex != -1) { if (ObjectFind(0, highZoneName) < 0) { ObjectCreate(0, highZoneName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); ObjectSetInteger(0, highZoneName, OBJPROP_COLOR, BearishZoneColor); ObjectSetInteger(0, highZoneName, OBJPROP_FILL, true); ObjectSetInteger(0, highZoneName, OBJPROP_BACK, true); } ObjectSetDouble(0, highZoneName, OBJPROP_PRICE, 0, majorHighZoneHigh); ObjectSetDouble(0, highZoneName, OBJPROP_PRICE, 1, majorHighZoneLow); ObjectSetInteger(0, highZoneName, OBJPROP_TIME, 0, majorHighZoneTime); ObjectSetInteger(0, highZoneName, OBJPROP_TIME, 1, TimeCurrent()); } ChartRedraw(); } //+------------------------------------------------------------------+ //| گسترش نواحی تا زمان حال (در هر تیک) | //+------------------------------------------------------------------+ void ExtendZonesToCurrentTime() { if (majorLowBarIndex != -1) { ObjectSetInteger(0, lowZoneName, OBJPROP_TIME, 1, TimeCurrent()); } if (majorHighBarIndex != -1) { ObjectSetInteger(0, highZoneName, OBJPROP_TIME, 1, TimeCurrent()); } ChartRedraw(); } //+------------------------------------------------------------------+ //| نمایش داشبورد روی چارت | //+------------------------------------------------------------------+ void DisplayDashboard() { string dash = "\n========== 4H MAJOR STRUCTURE (BOS) ==========\n"; dash += "Symbol: " + _Symbol + " | Bias: " + biasDirection + "\n"; dash += "--------------------------------------------------\n"; if (majorLowBarIndex != -1) { dash += "MAJOR LOW ZONE (Support):\n"; dash += " High: " + DoubleToString(majorLowZoneHigh, _Digits) + "\n"; dash += " Low: " + DoubleToString(majorLowZoneLow, _Digits) + "\n"; dash += " Time: " + TimeToString(majorLowZoneTime, TIME_DATE | TIME_MINUTES) + "\n"; } else { dash += "MAJOR LOW ZONE: Not Found\n"; } dash += "--------------------------------------------------\n"; if (majorHighBarIndex != -1) { dash += "MAJOR HIGH ZONE (Resistance):\n"; dash += " High: " + DoubleToString(majorHighZoneHigh, _Digits) + "\n"; dash += " Low: " + DoubleToString(majorHighZoneLow, _Digits) + "\n"; dash += " Time: " + TimeToString(majorHighZoneTime, TIME_DATE | TIME_MINUTES) + "\n"; } else { dash += "MAJOR HIGH ZONE: Not Found\n"; } dash += "==================================================\n"; Comment(dash); Print("Bias: ", biasDirection); } //+------------------------------------------------------------------+