//+------------------------------------------------------------------+ //| 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); } //+------------------------------------------------------------------+