diff --git a/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.1.mq5 b/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.1.mq5 new file mode 100644 index 00000000..a37df95a --- /dev/null +++ b/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.1.mq5 @@ -0,0 +1,312 @@ +//+------------------------------------------------------------------+ +//| 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); +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.mq5 b/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.mq5 new file mode 100644 index 00000000..e85f8f1e --- /dev/null +++ b/Documents/BKP/Qwen/MajorStructure_Bias_EA_1.mq5 @@ -0,0 +1,226 @@ +//+------------------------------------------------------------------+ +//| MajorStructure_Bias_EA.mq5 | +//| Step 1: 4H Major Structure & Bias Logic | +//+------------------------------------------------------------------+ +#property copyright "Professional Trader & AI Assistant" +#property version "1.00" +#property strict + +//--- Input Parameters +input int MajorSwingLookback = 5; // تعداد کندل‌های چپ و راست برای تایید سوئینگ ماژور (در 4H = 5 یعنی 40 ساعت) +input int MaxBarsToScan = 200; // حداکثر تعداد کندل‌های 4H برای جستجو (برای بهینه‌سازی سرعت) + +//--- Global Variables +int lastMajorHighIndex = -1; +int lastMajorLowIndex = -1; +double lastMajorHighPrice = 0; +double lastMajorLowPrice = 0; +datetime lastMajorHighTime = 0; +datetime lastMajorLowTime = 0; + +string biasDirection = "NEUTRAL"; + +//+------------------------------------------------------------------+ +//| Expert initialization function | +//+------------------------------------------------------------------+ +int OnInit() +{ + Print("EA Initialized. Scanning 4H Chart for Major Structure..."); + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +//| Expert deinitialization function | +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + Comment(""); // پاک کردن داشبورد هنگام حذف EA +} + +//+------------------------------------------------------------------+ +//| Expert tick function | +//+------------------------------------------------------------------+ +void OnTick() +{ + // فقط یک بار در هر کندل جدید 4 ساعته محاسبات را انجام می‌دهیم تا CPU درگیر نشود + static datetime lastBarTime = 0; + datetime currentBarTime = iTime(_Symbol, PERIOD_H4, 0); + + if (lastBarTime == currentBarTime) + return; + lastBarTime = currentBarTime; + + // 1. دریافت داده‌های تایم فریم 4 ساعته + double high[], low[]; + datetime time[]; + + ArraySetAsSeries(high, true); + ArraySetAsSeries(low, true); + ArraySetAsSeries(time, true); + + int copiedH = CopyHigh(_Symbol, PERIOD_H4, 0, MaxBarsToScan, high); + int copiedL = CopyLow(_Symbol, PERIOD_H4, 0, MaxBarsToScan, low); + int copiedT = CopyTime(_Symbol, PERIOD_H4, 0, MaxBarsToScan, time); + + if (copiedH <= 0 || copiedL <= 0 || copiedT <= 0) + { + Print("Error copying 4H data."); + return; + } + + // 2. پیدا کردن آخرین سقف ماژور + lastMajorHighIndex = FindMajorSwing(high, true); + if (lastMajorHighIndex != -1) + { + lastMajorHighPrice = high[lastMajorHighIndex]; + lastMajorHighTime = time[lastMajorHighIndex]; + } + + // 3. پیدا کردن آخرین کف ماژور + lastMajorLowIndex = FindMajorSwing(low, false); + if (lastMajorLowIndex != -1) + { + lastMajorLowPrice = low[lastMajorLowIndex]; + lastMajorLowTime = time[lastMajorLowIndex]; + } + + // 4. تعیین بایاس (جهت بازار) بر اساس قانون تازگی + DetermineBias(); + + // 5. نمایش خروجی روی چارت (داشبورد) + DisplayDashboard(); +} + +//+------------------------------------------------------------------+ +//| تابع پیدا کردن سوئینگ ماژور (سقف یا کف) | +//+------------------------------------------------------------------+ +int FindMajorSwing(double &data[], bool isHigh) +{ + // حلقه از کندل‌های قدیمی‌تر به جدیدتر (اندیس بزرگتر به کوچکتر) + // ما از MajorSwingLookback شروع می‌کنیم تا کندل‌های کافی برای مقایسه داشته باشیم + for (int i = MaxBarsToScan - MajorSwingLookback - 1; i >= MajorSwingLookback; i--) + { + bool isMajor = true; + + // بررسی کندل‌های سمت چپ (جدیدتر - اندیس کوچکتر) + for (int j = 1; j <= MajorSwingLookback; j++) + { + if (isHigh) + { + if (data[i] <= data[i - j]) + { + isMajor = false; + break; + } + } + else + { + if (data[i] >= data[i - j]) + { + isMajor = false; + break; + } + } + } + + if (!isMajor) + continue; + + // بررسی کندل‌های سمت راست (قدیمی‌تر - اندیس بزرگتر) + for (int j = 1; j <= MajorSwingLookback; j++) + { + if (isHigh) + { + if (data[i] <= data[i + j]) + { + isMajor = false; + break; + } + } + else + { + if (data[i] >= data[i + j]) + { + isMajor = false; + break; + } + } + } + + // اگر هر دو شرط برقرار بود، این یک سوئینگ ماژور است + if (isMajor) + return i; + } + + return -1; // پیدا نشد +} + +//+------------------------------------------------------------------+ +//| تابع تعیین جهت بازار (Bias) | +//+------------------------------------------------------------------+ +void DetermineBias() +{ + if (lastMajorHighIndex == -1 || lastMajorLowIndex == -1) + { + biasDirection = "NEUTRAL (Data Not Found)"; + return; + } + + // در آرایه‌های سری، اندیس کوچکتر = زمان جدیدتر + if (lastMajorHighIndex < lastMajorLowIndex) + { + // سقف ماژور جدیدتر از کف ماژور است -> بازار نزولی است + biasDirection = "BEARISH (Short Only)"; + } + else if (lastMajorLowIndex < lastMajorHighIndex) + { + // کف ماژور جدیدتر از سقف ماژور است -> بازار صعودی است + biasDirection = "BULLISH (Long Only)"; + } + else + { + biasDirection = "NEUTRAL (Equal Time)"; + } +} + +//+------------------------------------------------------------------+ +//| تابع نمایش داشبورد روی چارت | +//+------------------------------------------------------------------+ +void DisplayDashboard() +{ + string dash = "\n========== 4H MAJOR STRUCTURE ==========\n"; + dash += "Symbol: " + _Symbol + "\n"; + dash += "----------------------------------------\n"; + + if (lastMajorHighIndex != -1) + { + dash += "Last MAJOR HIGH: " + DoubleToString(lastMajorHighPrice, _Digits) + "\n"; + dash += "High Time: " + TimeToString(lastMajorHighTime, TIME_DATE | TIME_MINUTES) + "\n"; + } + else + { + dash += "Last MAJOR HIGH: Not Found\n"; + } + + dash += "----------------------------------------\n"; + + if (lastMajorLowIndex != -1) + { + dash += "Last MAJOR LOW: " + DoubleToString(lastMajorLowPrice, _Digits) + "\n"; + dash += "Low Time: " + TimeToString(lastMajorLowTime, TIME_DATE | TIME_MINUTES) + "\n"; + } + else + { + dash += "Last MAJOR LOW: Not Found\n"; + } + + dash += "========================================\n"; + dash += "CURRENT BIAS (Direction): " + biasDirection + "\n"; + dash += "========================================\n"; + + Comment(dash); + + // چاپ در تب Experts برای لاگ‌گیری + Print("Bias Updated: ", biasDirection, " | High Index: ", lastMajorHighIndex, " | Low Index: ", lastMajorLowIndex); +} +//+------------------------------------------------------------------+ \ No newline at end of file diff --git a/Experts/SmartShadowScanner.ea.mq5 b/Documents/BKP/Qwen/SmartShadowScanner.ea.mq5 similarity index 100% rename from Experts/SmartShadowScanner.ea.mq5 rename to Documents/BKP/Qwen/SmartShadowScanner.ea.mq5 diff --git a/Experts/MajorStructure_Bias_EA.mq5 b/Experts/MajorStructure_Bias_EA.mq5 new file mode 100644 index 00000000..ee489e0e --- /dev/null +++ b/Experts/MajorStructure_Bias_EA.mq5 @@ -0,0 +1,839 @@ +//+------------------------------------------------------------------+ +//| CompleteStructure_MinorZones_EA.mq5 | +//| Major Zones (4H) + Minor Zones (15m) with Full Validation | +//+------------------------------------------------------------------+ +#property copyright "Professional Trader & AI Assistant" +#property version "4.00" +#property strict + +//--- Input Parameters - Major Structure (4H) +input int MajorPivotLookback = 3; +input int MaxBarsToScan = 500; +input color BullishZoneColor = clrLime; +input color BearishZoneColor = clrRed; +input color InvalidZoneColor = clrGray; + +//--- Input Parameters - Minor Structure (15m) +input int MinorWickLookback = 2; +input double WickToBodyRatio = 2.0; +input color MinorHighZoneColor = clrOrange; +input color MinorLowZoneColor = clrDodgerBlue; +input color MinorInvalidColor = clrSilver; +input color EquilibriumColor = clrYellow; + +//--- ساختار داده برای ماژور +struct MajorZone +{ + double zoneHigh; + double zoneLow; + datetime zoneTime; + int barIndex; + bool isValid; +}; + +//--- ساختار داده برای مینور +struct MinorZone +{ + double zoneHigh; + double zoneLow; + datetime zoneTime; + int barIndex; + bool isValid; + bool isLongSignal; // true = سیگنال لانگ (کف مینور), false = سیگنال شورت (سقف مینور) +}; + +//--- آرایه‌های ماژور +MajorZone majorLows[]; +MajorZone majorHighs[]; +int currentLowIndex = -1; +int currentHighIndex = -1; + +//--- آرایه‌های مینور +MinorZone minorLows[]; +MinorZone minorHighs[]; +int currentMinorLowIndex = -1; +int currentMinorHighIndex = -1; + +//--- متغیرهای بایاس و نواحی +string biasDirection = "NEUTRAL"; +double equilibriumPrice = 0; +double premiumZone = 0; +double discountZone = 0; +bool structureValid = false; + +//--- پیشوند آبجکت‌ها +string mzPrefix = "MZ_"; +string qzPrefix = "QZ_"; +string mnPrefix = "MN_"; + +//+------------------------------------------------------------------+ +int OnInit() +{ + ArrayResize(majorLows, 0); + ArrayResize(majorHighs, 0); + ArrayResize(minorLows, 0); + ArrayResize(minorHighs, 0); + Print("EA v4.0 Initialized. Major + Minor Zones with Full Validation."); + return (INIT_SUCCEEDED); +} + +//+------------------------------------------------------------------+ +void OnDeinit(const int reason) +{ + ObjectsDeleteAll(0, mzPrefix); + ObjectsDeleteAll(0, qzPrefix); + ObjectsDeleteAll(0, mnPrefix); + Comment(""); +} + +//+------------------------------------------------------------------+ +void OnTick() +{ + // 1. دریافت داده‌های 4H + double high4H[], low4H[], open4H[], close4H[]; + datetime time4H[]; + + ArraySetAsSeries(high4H, true); + ArraySetAsSeries(low4H, true); + ArraySetAsSeries(open4H, true); + ArraySetAsSeries(close4H, true); + ArraySetAsSeries(time4H, true); + + int copied4H = CopyHigh(_Symbol, PERIOD_H4, 0, MaxBarsToScan, high4H); + CopyLow(_Symbol, PERIOD_H4, 0, MaxBarsToScan, low4H); + CopyOpen(_Symbol, PERIOD_H4, 0, MaxBarsToScan, open4H); + CopyClose(_Symbol, PERIOD_H4, 0, MaxBarsToScan, close4H); + CopyTime(_Symbol, PERIOD_H4, 0, MaxBarsToScan, time4H); + + if (copied4H <= 0) + return; + + // 2. بررسی بی‌اعتباری ماژورهای جاری + CheckCurrentZonesInvalidation(close4H); + + // 3. به‌روزرسانی ماژورها (فقط در کندل جدید 4H) + static datetime lastBarTime4H = 0; + datetime currentBarTime4H = time4H[0]; + + if (lastBarTime4H != currentBarTime4H) + { + lastBarTime4H = currentBarTime4H; + UpdateCurrentZones(high4H, low4H, open4H, close4H, time4H, copied4H); + } + + // 4. اعتبارسنجی ساختاری و بایاس + ValidateStructure(); + DetermineBias(); + + // 5. رسم ماژورها + DrawAllMajorZones(); + + // 6. اگر ساختار معتبر است، مینورها را پردازش کن + if (structureValid) + { + CalculateQuartileZones(); + DrawQuartileZones(); + ProcessMinorZones(); + } + + // 7. داشبورد + DisplayDashboard(); +} + +//+------------------------------------------------------------------+ +//| بررسی بی‌اعتباری ماژورهای جاری | +//+------------------------------------------------------------------+ +void CheckCurrentZonesInvalidation(double &close4H[]) +{ + if (currentLowIndex >= 0 && currentLowIndex < ArraySize(majorLows)) + { + if (majorLows[currentLowIndex].isValid) + { + for (int i = 0; i <= majorLows[currentLowIndex].barIndex; i++) + { + if (close4H[i] < majorLows[currentLowIndex].zoneLow) + { + majorLows[currentLowIndex].isValid = false; + Print("Major Low INVALIDATED at index ", currentLowIndex); + break; + } + } + } + } + + if (currentHighIndex >= 0 && currentHighIndex < ArraySize(majorHighs)) + { + if (majorHighs[currentHighIndex].isValid) + { + for (int i = 0; i <= majorHighs[currentHighIndex].barIndex; i++) + { + if (close4H[i] > majorHighs[currentHighIndex].zoneHigh) + { + majorHighs[currentHighIndex].isValid = false; + Print("Major High INVALIDATED at index ", currentHighIndex); + break; + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| به‌روزرسانی ماژورها | +//+------------------------------------------------------------------+ +void UpdateCurrentZones(double &high4H[], double &low4H[], double &open4H[], double &close4H[], datetime &time4H[], int total) +{ + // مدیریت کف‌ها + bool needNewLow = (currentLowIndex == -1 || !majorLows[currentLowIndex].isValid); + if (needNewLow) + { + bool foundPrevious = false; + for (int i = ArraySize(majorLows) - 1; i >= 0; i--) + { + if (majorLows[i].isValid) + { + currentLowIndex = i; + foundPrevious = true; + break; + } + } + + if (!foundPrevious) + { + MajorZone newLow; + if (FindNewMajorLow(high4H, low4H, open4H, close4H, time4H, total, newLow)) + { + int newSize = ArraySize(majorLows); + ArrayResize(majorLows, newSize + 1); + majorLows[newSize] = newLow; + currentLowIndex = newSize; + } + else + { + currentLowIndex = -1; + } + } + } + + // مدیریت سقف‌ها + bool needNewHigh = (currentHighIndex == -1 || !majorHighs[currentHighIndex].isValid); + if (needNewHigh) + { + bool foundPrevious = false; + for (int i = ArraySize(majorHighs) - 1; i >= 0; i--) + { + if (majorHighs[i].isValid) + { + currentHighIndex = i; + foundPrevious = true; + break; + } + } + + if (!foundPrevious) + { + MajorZone newHigh; + if (FindNewMajorHigh(high4H, low4H, open4H, close4H, time4H, total, newHigh)) + { + int newSize = ArraySize(majorHighs); + ArrayResize(majorHighs, newSize + 1); + majorHighs[newSize] = newHigh; + currentHighIndex = newSize; + } + else + { + currentHighIndex = -1; + } + } + } +} + +//+------------------------------------------------------------------+ +bool FindNewMajorLow(double &high[], double &low[], double &open[], double &close[], datetime &time[], int total, MajorZone &outZone) +{ + int lastMinorHighIdx = -1; + int lastMinorLowIdx = -1; + + for (int i = total - MajorPivotLookback - 1; i >= MajorPivotLookback; i--) + { + if (IsPivot(high, i, true, total, MajorPivotLookback)) + lastMinorHighIdx = i; + if (IsPivot(low, i, false, total, MajorPivotLookback)) + lastMinorLowIdx = i; + + if (lastMinorHighIdx != -1 && i < lastMinorHighIdx && close[i] > high[lastMinorHighIdx]) + { + if (lastMinorLowIdx != -1 && lastMinorLowIdx > lastMinorHighIdx) + { + bool stillValid = true; + for (int j = 0; j <= i; j++) + { + if (close[j] < low[lastMinorLowIdx]) + { + stillValid = false; + break; + } + } + + if (stillValid) + { + outZone.zoneLow = low[lastMinorLowIdx]; + outZone.zoneHigh = open[lastMinorLowIdx]; + outZone.zoneTime = time[lastMinorLowIdx]; + outZone.barIndex = lastMinorLowIdx; + outZone.isValid = true; + return true; + } + } + } + } + return false; +} + +//+------------------------------------------------------------------+ +bool FindNewMajorHigh(double &high[], double &low[], double &open[], double &close[], datetime &time[], int total, MajorZone &outZone) +{ + int lastMinorHighIdx = -1; + int lastMinorLowIdx = -1; + + for (int i = total - MajorPivotLookback - 1; i >= MajorPivotLookback; i--) + { + if (IsPivot(high, i, true, total, MajorPivotLookback)) + lastMinorHighIdx = i; + if (IsPivot(low, i, false, total, MajorPivotLookback)) + lastMinorLowIdx = i; + + if (lastMinorLowIdx != -1 && i < lastMinorLowIdx && close[i] < low[lastMinorLowIdx]) + { + if (lastMinorHighIdx != -1 && lastMinorHighIdx > lastMinorLowIdx) + { + bool stillValid = true; + for (int j = 0; j <= i; j++) + { + if (close[j] > high[lastMinorHighIdx]) + { + stillValid = false; + break; + } + } + + if (stillValid) + { + outZone.zoneHigh = high[lastMinorHighIdx]; + outZone.zoneLow = open[lastMinorHighIdx]; + outZone.zoneTime = time[lastMinorHighIdx]; + outZone.barIndex = lastMinorHighIdx; + outZone.isValid = true; + return true; + } + } + } + } + return false; +} + +//+------------------------------------------------------------------+ +bool IsPivot(double &data[], int idx, bool isHigh, int total, int lookback) +{ + for (int j = 1; j <= lookback; j++) + { + if (idx - j < 0 || idx + j >= total) + continue; + 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 ValidateStructure() +{ + structureValid = false; + + if (currentLowIndex >= 0 && currentHighIndex >= 0) + { + if (majorLows[currentLowIndex].isValid && majorHighs[currentHighIndex].isValid) + { + if (majorHighs[currentHighIndex].zoneHigh > majorLows[currentLowIndex].zoneHigh) + { + structureValid = true; + } + else + { + majorLows[currentLowIndex].isValid = false; + majorHighs[currentHighIndex].isValid = false; + } + } + } +} + +//+------------------------------------------------------------------+ +void DetermineBias() +{ + if (!structureValid) + { + biasDirection = "NEUTRAL"; + return; + } + + if (majorHighs[currentHighIndex].barIndex < majorLows[currentLowIndex].barIndex) + { + biasDirection = "BEARISH"; + } + else if (majorLows[currentLowIndex].barIndex < majorHighs[currentHighIndex].barIndex) + { + biasDirection = "BULLISH"; + } + else + { + biasDirection = "NEUTRAL"; + } +} + +//+------------------------------------------------------------------+ +void DrawAllMajorZones() +{ + for (int i = 0; i < ArraySize(majorLows); i++) + { + string objName = mzPrefix + "Low_" + IntegerToString(i); + + if (ObjectFind(0, objName) < 0) + { + ObjectCreate(0, objName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); + ObjectSetInteger(0, objName, OBJPROP_FILL, true); + ObjectSetInteger(0, objName, OBJPROP_BACK, true); + ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); + } + + color zoneColor = majorLows[i].isValid ? BullishZoneColor : InvalidZoneColor; + ObjectSetInteger(0, objName, OBJPROP_COLOR, zoneColor); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, majorLows[i].zoneHigh); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, majorLows[i].zoneLow); + ObjectSetInteger(0, objName, OBJPROP_TIME, 0, majorLows[i].zoneTime); + ObjectSetInteger(0, objName, OBJPROP_TIME, 1, TimeCurrent()); + } + + for (int i = 0; i < ArraySize(majorHighs); i++) + { + string objName = mzPrefix + "High_" + IntegerToString(i); + + if (ObjectFind(0, objName) < 0) + { + ObjectCreate(0, objName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); + ObjectSetInteger(0, objName, OBJPROP_FILL, true); + ObjectSetInteger(0, objName, OBJPROP_BACK, true); + ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); + } + + color zoneColor = majorHighs[i].isValid ? BearishZoneColor : InvalidZoneColor; + ObjectSetInteger(0, objName, OBJPROP_COLOR, zoneColor); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, majorHighs[i].zoneHigh); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, majorHighs[i].zoneLow); + ObjectSetInteger(0, objName, OBJPROP_TIME, 0, majorHighs[i].zoneTime); + ObjectSetInteger(0, objName, OBJPROP_TIME, 1, TimeCurrent()); + } + + ChartRedraw(); +} + +//+------------------------------------------------------------------+ +void CalculateQuartileZones() +{ + double majorHigh = majorHighs[currentHighIndex].zoneHigh; + double majorLow = majorLows[currentLowIndex].zoneLow; + double range = majorHigh - majorLow; + + equilibriumPrice = majorLow + (range * 0.50); + premiumZone = majorLow + (range * 0.75); + discountZone = majorLow + (range * 0.25); +} + +//+------------------------------------------------------------------+ +void DrawQuartileZones() +{ + string eqName = qzPrefix + "Equilibrium"; + if (ObjectFind(0, eqName) < 0) + { + ObjectCreate(0, eqName, OBJ_HLINE, 0, 0, equilibriumPrice); + ObjectSetInteger(0, eqName, OBJPROP_COLOR, EquilibriumColor); + ObjectSetInteger(0, eqName, OBJPROP_STYLE, STYLE_DASHDOT); + ObjectSetInteger(0, eqName, OBJPROP_WIDTH, 2); + } + else + { + ObjectSetDouble(0, eqName, OBJPROP_PRICE, 0, equilibriumPrice); + } + + string topName = qzPrefix + "Top25"; + if (ObjectFind(0, topName) < 0) + { + ObjectCreate(0, topName, OBJ_HLINE, 0, 0, premiumZone); + ObjectSetInteger(0, topName, OBJPROP_COLOR, clrDarkRed); + ObjectSetInteger(0, topName, OBJPROP_STYLE, STYLE_DOT); + } + else + { + ObjectSetDouble(0, topName, OBJPROP_PRICE, 0, premiumZone); + } + + string botName = qzPrefix + "Bottom25"; + if (ObjectFind(0, botName) < 0) + { + ObjectCreate(0, botName, OBJ_HLINE, 0, 0, discountZone); + ObjectSetInteger(0, botName, OBJPROP_COLOR, clrDarkGreen); + ObjectSetInteger(0, botName, OBJPROP_STYLE, STYLE_DOT); + } + else + { + ObjectSetDouble(0, botName, OBJPROP_PRICE, 0, discountZone); + } + + ChartRedraw(); +} + +//+------------------------------------------------------------------+ +//| پردازش مینورها: بررسی اعتبار + جستجوی جدید | +//+------------------------------------------------------------------+ +void ProcessMinorZones() +{ + // 1. دریافت داده‌های 15 دقیقه + double high15m[], low15m[], open15m[], close15m[]; + datetime time15m[]; + + ArraySetAsSeries(high15m, true); + ArraySetAsSeries(low15m, true); + ArraySetAsSeries(open15m, true); + ArraySetAsSeries(close15m, true); + ArraySetAsSeries(time15m, true); + + int copied15m = CopyHigh(_Symbol, PERIOD_M15, 0, 500, high15m); + CopyLow(_Symbol, PERIOD_M15, 0, 500, low15m); + CopyOpen(_Symbol, PERIOD_M15, 0, 500, open15m); + CopyClose(_Symbol, PERIOD_M15, 0, 500, close15m); + CopyTime(_Symbol, PERIOD_M15, 0, 500, time15m); + + if (copied15m <= 0) + return; + + // 2. بررسی بی‌اعتباری مینورهای جاری + CheckMinorZonesInvalidation(close15m); + + // 3. به‌روزرسانی مینورها (در هر تیک، چون 15 دقیقه سریع‌تر است) + UpdateCurrentMinorZones(high15m, low15m, open15m, close15m, time15m, copied15m); + + // 4. رسم تمام مینورها + DrawAllMinorZones(); +} + +//+------------------------------------------------------------------+ +//| بررسی بی‌اعتباری مینورهای جاری با Close کندل 15 دقیقه | +//+------------------------------------------------------------------+ +void CheckMinorZonesInvalidation(double &close15m[]) +{ + // بررسی کف مینور جاری + if (currentMinorLowIndex >= 0 && currentMinorLowIndex < ArraySize(minorLows)) + { + if (minorLows[currentMinorLowIndex].isValid) + { + for (int i = 0; i <= minorLows[currentMinorLowIndex].barIndex; i++) + { + if (close15m[i] < minorLows[currentMinorLowIndex].zoneLow) + { + minorLows[currentMinorLowIndex].isValid = false; + Print("Minor Low INVALIDATED at index ", currentMinorLowIndex); + break; + } + } + } + } + + // بررسی سقف مینور جاری + if (currentMinorHighIndex >= 0 && currentMinorHighIndex < ArraySize(minorHighs)) + { + if (minorHighs[currentMinorHighIndex].isValid) + { + for (int i = 0; i <= minorHighs[currentMinorHighIndex].barIndex; i++) + { + if (close15m[i] > minorHighs[currentMinorHighIndex].zoneHigh) + { + minorHighs[currentMinorHighIndex].isValid = false; + Print("Minor High INVALIDATED at index ", currentMinorHighIndex); + break; + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| به‌روزرسانی مینورها | +//+------------------------------------------------------------------+ +void UpdateCurrentMinorZones(double &high15m[], double &low15m[], double &open15m[], double &close15m[], datetime &time15m[], int total) +{ + // مدیریت کف‌های مینور (فقط در بایاس صعودی) + if (biasDirection == "BULLISH") + { + bool needNewMinorLow = (currentMinorLowIndex == -1 || !minorLows[currentMinorLowIndex].isValid); + if (needNewMinorLow) + { + bool foundPrevious = false; + for (int i = ArraySize(minorLows) - 1; i >= 0; i--) + { + if (minorLows[i].isValid) + { + currentMinorLowIndex = i; + foundPrevious = true; + break; + } + } + + if (!foundPrevious) + { + MinorZone newMinorLow; + if (FindNewMinorLow(high15m, low15m, open15m, close15m, time15m, total, newMinorLow)) + { + int newSize = ArraySize(minorLows); + ArrayResize(minorLows, newSize + 1); + minorLows[newSize] = newMinorLow; + currentMinorLowIndex = newSize; + Print("New Minor Low Zone found at index: ", newSize); + } + else + { + currentMinorLowIndex = -1; + } + } + } + } + + // مدیریت سقف‌های مینور (فقط در بایاس نزولی) + if (biasDirection == "BEARISH") + { + bool needNewMinorHigh = (currentMinorHighIndex == -1 || !minorHighs[currentMinorHighIndex].isValid); + if (needNewMinorHigh) + { + bool foundPrevious = false; + for (int i = ArraySize(minorHighs) - 1; i >= 0; i--) + { + if (minorHighs[i].isValid) + { + currentMinorHighIndex = i; + foundPrevious = true; + break; + } + } + + if (!foundPrevious) + { + MinorZone newMinorHigh; + if (FindNewMinorHigh(high15m, low15m, open15m, close15m, time15m, total, newMinorHigh)) + { + int newSize = ArraySize(minorHighs); + ArrayResize(minorHighs, newSize + 1); + minorHighs[newSize] = newMinorHigh; + currentMinorHighIndex = newSize; + Print("New Minor High Zone found at index: ", newSize); + } + else + { + currentMinorHighIndex = -1; + } + } + } + } +} + +//+------------------------------------------------------------------+ +//| پیدا کردن کف مینور جدید (ناحیه Wick-to-Body در Discount) | +//+------------------------------------------------------------------+ +bool FindNewMinorLow(double &high[], double &low[], double &open[], double &close[], datetime &time[], int total, MinorZone &outZone) +{ + for (int i = 1; i < total - MinorWickLookback; i++) + { + double bodyTop = MathMax(open[i], close[i]); + double bodyBot = MathMin(open[i], close[i]); + double bodySize = bodyTop - bodyBot; + + double lowerWick = bodyBot - low[i]; + + // شرط 1: شدوی پایینی بلند (حداقل 2 برابر بدنه) + // شرط 2: نوک شدو در ناحیه Discount (زیر 50%) + // شرط 3: بدنه بالای 50% بسته شده + if (lowerWick > 0 && bodySize > 0 && (lowerWick / bodySize) >= WickToBodyRatio) + { + if (low[i] < equilibriumPrice && bodyBot > equilibriumPrice) + { + // بررسی اعتبار: آیا از زمان تشکیل تا الان شکسته شده؟ + bool stillValid = true; + for (int j = 0; j <= i; j++) + { + if (close[j] < low[i]) + { + stillValid = false; + break; + } + } + + if (stillValid) + { + outZone.zoneLow = low[i]; // نوک شدو + outZone.zoneHigh = open[i]; // ابتدای بدنه (Wick-to-Body) + outZone.zoneTime = time[i]; + outZone.barIndex = i; + outZone.isValid = true; + outZone.isLongSignal = true; + return true; + } + } + } + } + return false; +} + +//+------------------------------------------------------------------+ +//| پیدا کردن سقف مینور جدید (ناحیه Wick-to-Body در Premium) | +//+------------------------------------------------------------------+ +bool FindNewMinorHigh(double &high[], double &low[], double &open[], double &close[], datetime &time[], int total, MinorZone &outZone) +{ + for (int i = 1; i < total - MinorWickLookback; i++) + { + double bodyTop = MathMax(open[i], close[i]); + double bodyBot = MathMin(open[i], close[i]); + double bodySize = bodyTop - bodyBot; + + double upperWick = high[i] - bodyTop; + + // شرط 1: شدوی بالایی بلند + // شرط 2: نوک شدو در ناحیه Premium (بالای 50%) + // شرط 3: بدنه زیر 50% بسته شده + if (upperWick > 0 && bodySize > 0 && (upperWick / bodySize) >= WickToBodyRatio) + { + if (high[i] > equilibriumPrice && bodyTop < equilibriumPrice) + { + bool stillValid = true; + for (int j = 0; j <= i; j++) + { + if (close[j] > high[i]) + { + stillValid = false; + break; + } + } + + if (stillValid) + { + outZone.zoneHigh = high[i]; // نوک شدو + outZone.zoneLow = open[i]; // ابتدای بدنه (Wick-to-Body) + outZone.zoneTime = time[i]; + outZone.barIndex = i; + outZone.isValid = true; + outZone.isLongSignal = false; + return true; + } + } + } + } + return false; +} + +//+------------------------------------------------------------------+ +//| رسم تمام مینورها (معتبر و نامعتبر) | +//+------------------------------------------------------------------+ +void DrawAllMinorZones() +{ + // رسم کف‌های مینور + for (int i = 0; i < ArraySize(minorLows); i++) + { + string objName = mnPrefix + "Low_" + IntegerToString(i); + + if (ObjectFind(0, objName) < 0) + { + ObjectCreate(0, objName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); + ObjectSetInteger(0, objName, OBJPROP_FILL, true); + ObjectSetInteger(0, objName, OBJPROP_BACK, true); + ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); + } + + color zoneColor = minorLows[i].isValid ? MinorLowZoneColor : MinorInvalidColor; + ObjectSetInteger(0, objName, OBJPROP_COLOR, zoneColor); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, minorLows[i].zoneHigh); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, minorLows[i].zoneLow); + ObjectSetInteger(0, objName, OBJPROP_TIME, 0, minorLows[i].zoneTime); + ObjectSetInteger(0, objName, OBJPROP_TIME, 1, TimeCurrent()); + } + + // رسم سقف‌های مینور + for (int i = 0; i < ArraySize(minorHighs); i++) + { + string objName = mnPrefix + "High_" + IntegerToString(i); + + if (ObjectFind(0, objName) < 0) + { + ObjectCreate(0, objName, OBJ_RECTANGLE, 0, 0, 0, 0, 0); + ObjectSetInteger(0, objName, OBJPROP_FILL, true); + ObjectSetInteger(0, objName, OBJPROP_BACK, true); + ObjectSetInteger(0, objName, OBJPROP_SELECTABLE, false); + } + + color zoneColor = minorHighs[i].isValid ? MinorHighZoneColor : MinorInvalidColor; + ObjectSetInteger(0, objName, OBJPROP_COLOR, zoneColor); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 0, minorHighs[i].zoneHigh); + ObjectSetDouble(0, objName, OBJPROP_PRICE, 1, minorHighs[i].zoneLow); + ObjectSetInteger(0, objName, OBJPROP_TIME, 0, minorHighs[i].zoneTime); + ObjectSetInteger(0, objName, OBJPROP_TIME, 1, TimeCurrent()); + } + + ChartRedraw(); +} + +//+------------------------------------------------------------------+ +void DisplayDashboard() +{ + string dash = "\n========== COMPLETE STRUCTURE (v4.0) ==========\n"; + dash += "Symbol: " + _Symbol + "\n"; + dash += "------------------------------------------------------\n"; + + if (structureValid) + { + dash += "MAJOR HIGH: " + DoubleToString(majorHighs[currentHighIndex].zoneHigh, _Digits) + "\n"; + dash += "MAJOR LOW: " + DoubleToString(majorLows[currentLowIndex].zoneLow, _Digits) + "\n"; + dash += "------------------------------------------------------\n"; + dash += "Equilibrium (50%): " + DoubleToString(equilibriumPrice, _Digits) + "\n"; + dash += "Premium (75%): " + DoubleToString(premiumZone, _Digits) + "\n"; + dash += "Discount (25%): " + DoubleToString(discountZone, _Digits) + "\n"; + dash += "------------------------------------------------------\n"; + dash += "BIAS: " + biasDirection + "\n"; + dash += "------------------------------------------------------\n"; + + if (currentMinorLowIndex >= 0) + { + dash += "Current Minor Low: " + (minorLows[currentMinorLowIndex].isValid ? "✓ VALID" : " INVALID") + "\n"; + dash += " Zone: " + DoubleToString(minorLows[currentMinorLowIndex].zoneLow, _Digits) + + " - " + DoubleToString(minorLows[currentMinorLowIndex].zoneHigh, _Digits) + "\n"; + } + + if (currentMinorHighIndex >= 0) + { + dash += "Current Minor High: " + (minorHighs[currentMinorHighIndex].isValid ? "✓ VALID" : "✗ INVALID") + "\n"; + dash += " Zone: " + DoubleToString(minorHighs[currentMinorHighIndex].zoneLow, _Digits) + + " - " + DoubleToString(minorHighs[currentMinorHighIndex].zoneHigh, _Digits) + "\n"; + } + } + else + { + dash += "Structure: INVALID - Waiting for valid Major Zones\n"; + } + + dash += "======================================================\n"; + + Comment(dash); +} +//+------------------------------------------------------------------+ \ No newline at end of file