#ifndef EA_ICT_CL__DRAWING_MQH #define EA_ICT_CL__DRAWING_MQH /** Draws one swing point (arrow + label + optional key-level line) on chart. */ inline void DrawOneSwingPoint( string prefix, ENUM_TIMEFRAMES tf, string tag, bool isHigh, int barIdx, double price, color clr, bool isKL, int arrowSz = 2, int fontSize = 8) { string arrowObjName = prefix + "ARR_" + tag; string textObjName = prefix + "TXT_" + tag; string keyLevelObjName = prefix + "KL_" + tag; datetime barTime = iTime(_Symbol, tf, barIdx); if (ObjectFind(0, arrowObjName) < 0) ObjectCreate(0, arrowObjName, OBJ_ARROW, 0, barTime, price); ObjectSetInteger(0, arrowObjName, OBJPROP_ARROWCODE, isHigh ? 234 : 233); ObjectSetInteger(0, arrowObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, arrowObjName, OBJPROP_WIDTH, arrowSz); ObjectSetInteger(0, arrowObjName, OBJPROP_ANCHOR, isHigh ? ANCHOR_BOTTOM : ANCHOR_TOP); ObjectMove(0, arrowObjName, 0, barTime, price); double barRange = iHigh(_Symbol, tf, barIdx) - iLow(_Symbol, tf, barIdx); double textY = isHigh ? price + barRange * 0.3 : price - barRange * 0.3; if (ObjectFind(0, textObjName) < 0) ObjectCreate(0, textObjName, OBJ_TEXT, 0, barTime, textY); ObjectMove(0, textObjName, 0, barTime, textY); ObjectSetString (0, textObjName, OBJPROP_TEXT, tag); ObjectSetInteger(0, textObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, textObjName, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, textObjName, OBJPROP_ANCHOR, isHigh ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER); if (isKL) { datetime endTime = iTime(_Symbol, tf, 0); if (ObjectFind(0, keyLevelObjName) < 0) ObjectCreate(0, keyLevelObjName, OBJ_TREND, 0, barTime, price, endTime, price); ObjectSetInteger(0, keyLevelObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, keyLevelObjName, OBJPROP_STYLE, STYLE_DASH); ObjectSetInteger(0, keyLevelObjName, OBJPROP_WIDTH, 1); ObjectSetInteger(0, keyLevelObjName, OBJPROP_RAY_RIGHT, false); ObjectMove(0, keyLevelObjName, 0, barTime, price); ObjectMove(0, keyLevelObjName, 1, endTime, price); } else ObjectDelete(0, keyLevelObjName); } /** Draws H1 swing points (H0/H1/L0/L1) when debug draw enabled. */ inline void DrawMiddleSwingPoints() { if (!InpDebugDraw) return; if (g_MiddleTrend.idxH0 <= 0 || g_MiddleTrend.idxH1 <= 0 || g_MiddleTrend.idxL0 <= 0 || g_MiddleTrend.idxL1 <= 0) { ObjectsDeleteAll(0, PREFIX_SWING_MIDDLE); return; } bool isUp = (g_MiddleTrend.trend == DIR_UP); bool isDown = (g_MiddleTrend.trend == DIR_DOWN); DrawOneSwingPoint( PREFIX_SWING_MIDDLE, InpMiddleTF, "H0", true, g_MiddleTrend.idxH0, g_MiddleTrend.h0, clrAqua, isDown, 2, 8 ); DrawOneSwingPoint( PREFIX_SWING_MIDDLE, InpMiddleTF, "H1", true, g_MiddleTrend.idxH1, g_MiddleTrend.h1, C'0,140,160', false, 2, 8 ); DrawOneSwingPoint( PREFIX_SWING_MIDDLE, InpMiddleTF, "L0", false, g_MiddleTrend.idxL0, g_MiddleTrend.l0, clrYellow, isUp, 2, 8 ); DrawOneSwingPoint( PREFIX_SWING_MIDDLE, InpMiddleTF, "L1", false, g_MiddleTrend.idxL1, g_MiddleTrend.l1, C'160,140,0', false, 2, 8 ); } /** Draws M5 swing points when debug draw enabled. */ inline void DrawTriggerSwingPoints() { if (!InpDebugDraw) return; if (g_TriggerTrend.idxH0 <= 0 || g_TriggerTrend.idxH1 <= 0 || g_TriggerTrend.idxL0 <= 0 || g_TriggerTrend.idxL1 <= 0) { ObjectsDeleteAll(0, PREFIX_SWING_TRIGGER); return; } bool isUp = (g_TriggerTrend.trend == DIR_UP); bool isDown = (g_TriggerTrend.trend == DIR_DOWN); DrawOneSwingPoint( PREFIX_SWING_TRIGGER, InpTriggerTF, "h0", true, g_TriggerTrend.idxH0, g_TriggerTrend.h0, C'180,100,255', isDown, 1, 7 ); DrawOneSwingPoint( PREFIX_SWING_TRIGGER, InpTriggerTF, "h1", true, g_TriggerTrend.idxH1, g_TriggerTrend.h1, C'100,60,160', false, 1, 7 ); DrawOneSwingPoint( PREFIX_SWING_TRIGGER, InpTriggerTF, "l0", false, g_TriggerTrend.idxL0, g_TriggerTrend.l0, C'255,160,40', isUp, 1, 7 ); DrawOneSwingPoint( PREFIX_SWING_TRIGGER, InpTriggerTF, "l1", false, g_TriggerTrend.idxL1, g_TriggerTrend.l1, C'160,100,20', false, 1, 7 ); } /** Draws one MSS marker (arrow + label + horizontal level) at given time/level. */ inline void DrawMSSMarker( string mssId, ENUM_TIMEFRAMES tf, datetime mssTime, double mssLevel, MarketDir mssBreak) { if (!InpDebugDraw || mssTime == 0) return; string arrowObjName = PREFIX_MSS_MARKER + mssId + "_ARR"; string labelObjName = PREFIX_MSS_MARKER + mssId + "_LBL"; string levelObjName = PREFIX_MSS_MARKER + mssId + "_KL"; bool isBull = (mssBreak == DIR_UP); color clr = isBull ? clrLime : clrTomato; int barShift = MyBarShift(_Symbol, tf, mssTime); if (barShift < 0) return; double closeAtMss = iClose(_Symbol, tf, barShift); if (ObjectFind(0, arrowObjName) < 0) ObjectCreate(0, arrowObjName, OBJ_ARROW, 0, mssTime, closeAtMss); ObjectSetInteger(0, arrowObjName, OBJPROP_ARROWCODE, isBull ? 233 : 234); ObjectSetInteger(0, arrowObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, arrowObjName, OBJPROP_WIDTH, 2); ObjectSetInteger(0, arrowObjName, OBJPROP_ANCHOR, isBull ? ANCHOR_TOP : ANCHOR_BOTTOM); ObjectMove(0, arrowObjName, 0, mssTime, closeAtMss); double barRange = iHigh(_Symbol, tf, barShift) - iLow(_Symbol, tf, barShift); double labelY = isBull ? closeAtMss - barRange * 0.4 : closeAtMss + barRange * 0.4; if (ObjectFind(0, labelObjName) < 0) ObjectCreate(0, labelObjName, OBJ_TEXT, 0, mssTime, labelY); ObjectMove(0, labelObjName, 0, mssTime, labelY); ObjectSetString (0, labelObjName, OBJPROP_TEXT, isBull ? "▲MSS" : "▼MSS"); ObjectSetInteger(0, labelObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, labelObjName, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, labelObjName, OBJPROP_ANCHOR, isBull ? ANCHOR_LEFT_UPPER : ANCHOR_LEFT_LOWER); datetime endTime = iTime(_Symbol, tf, 0); if (ObjectFind(0, levelObjName) < 0) ObjectCreate(0, levelObjName, OBJ_TREND, 0, mssTime, mssLevel, endTime, mssLevel); ObjectSetInteger(0, levelObjName, OBJPROP_COLOR, clr); ObjectSetInteger(0, levelObjName, OBJPROP_STYLE, STYLE_DOT); ObjectSetInteger(0, levelObjName, OBJPROP_WIDTH, 1); ObjectSetInteger(0, levelObjName, OBJPROP_RAY_RIGHT, false); ObjectMove(0, levelObjName, 0, mssTime, mssLevel); ObjectMove(0, levelObjName, 1, endTime, mssLevel); } /** Draws MSS markers for all FVGs that were triggered by MSS (usedCase == 2). */ inline void DrawMSSMarkers() { if (!InpDebugDraw) return; for (int i = 0; i < g_FVGCount; i++) { if (g_FVGPool[i].status != FVG_USED || g_FVGPool[i].usedCase != 2) continue; if (g_FVGPool[i].mssTime == 0) continue; string tid = "T_" + IntegerToString(g_FVGPool[i].id); DrawMSSMarker( tid, InpTriggerTF, g_FVGPool[i].mssTime, g_FVGPool[i].mssEntry, g_FVGPool[i].direction == DIR_UP ? DIR_UP : DIR_DOWN ); } } /** Helper: creates or moves a rectangle. */ inline void SetRect(string name, datetime t1, double p1, datetime t2, double p2, color clr) { if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, p1, t2, p2); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectMove(0, name, 0, t1, p1); ObjectMove(0, name, 1, t2, p2); } /** Helper: creates or moves a horizontal trend line. */ inline void SetHLine(string name, datetime t1, double p, datetime t2, color clr, int style, int width) { if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_TREND, 0, t1, p, t2, p); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_STYLE, style); ObjectSetInteger(0, name, OBJPROP_WIDTH, width); ObjectSetInteger(0, name, OBJPROP_RAY_RIGHT, false); ObjectMove(0, name, 0, t1, p); ObjectMove(0, name, 1, t2, p); } /** Helper: creates or moves a text label at a chart coordinate. */ inline void SetText(string name, datetime t, double p, string txt, color clr, int fontSize, int anchor) { if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_TEXT, 0, t, p); ObjectMove(0, name, 0, t, p); ObjectSetString (0, name, OBJPROP_TEXT, txt); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, fontSize); ObjectSetInteger(0, name, OBJPROP_ANCHOR, anchor); } /** Draws one order record in TradingView style (TP/SL zones, entry line, labels). */ inline void DrawOneOrderHist(int idx) { string sid = IntegerToString(g_OrderHist[idx].id); string pfx = PREFIX_ORDER_HIST + sid + "_"; bool isBuy = (g_OrderHist[idx].direction > 0); double entry = g_OrderHist[idx].entry; double sl = g_OrderHist[idx].stopLoss; double tp = g_OrderHist[idx].takeProfit; int res = g_OrderHist[idx].result; datetime tStart = g_OrderHist[idx].signalTime; datetime tEnd; if (res == 0) tEnd = iTime(_Symbol, InpTriggerTF, 0) + PeriodSeconds(InpTriggerTF) * 10; else tEnd = g_OrderHist[idx].closeTime; if (tEnd <= tStart) tEnd = tStart + PeriodSeconds(InpTriggerTF) * 10; double slPips = MathAbs(entry - sl) / _Point; double tpPips = MathAbs(tp - entry) / _Point; double rr = (slPips > 0) ? tpPips / slPips : 0; color entClr, tpZoneClr, slZoneClr, tpLineClr, slLineClr, resultClr; if (res == 1) { entClr = C'0,180,80'; tpZoneClr = C'10,70,30'; slZoneClr = C'40,15,15'; tpLineClr = C'38,200,91'; slLineClr = C'120,50,50'; resultClr = C'0,220,100'; } else if (res == -1) { entClr = C'220,50,50'; tpZoneClr = C'15,40,15'; slZoneClr = C'90,12,12'; tpLineClr = C'50,120,50'; slLineClr = C'229,57,53'; resultClr = C'229,57,53'; } else { entClr = isBuy ? C'33,150,243' : C'255,152,0'; tpZoneClr = C'15,60,30'; slZoneClr = C'75,12,12'; tpLineClr = C'38,166,91'; slLineClr = C'229,57,53'; resultClr = entClr; } double tpTop = isBuy ? tp : entry; double tpBot = isBuy ? entry : tp; SetRect(pfx + "TP", tStart, tpTop, tEnd, tpBot, tpZoneClr); double slTop = isBuy ? entry : sl; double slBot = isBuy ? sl : entry; SetRect(pfx + "SL", tStart, slTop, tEnd, slBot, slZoneClr); SetHLine(pfx + "ENT", tStart, entry, tEnd, entClr, STYLE_SOLID, 2); SetHLine(pfx + "TPL", tStart, tp, tEnd, tpLineClr, STYLE_DASH, 1); SetHLine(pfx + "SLL", tStart, sl, tEnd, slLineClr, STYLE_DASH, 1); datetime lblT = tEnd + PeriodSeconds(InpTriggerTF); string entTxt; if (res == 0) entTxt = StringFormat("%s %.3f | %.2f lot", isBuy ? "BUY LIM" : "SELL LIM", entry, g_OrderHist[idx].lot); else entTxt = StringFormat("%s %.3f | %.2f lot | %s", isBuy ? "BUY" : "SELL", entry, g_OrderHist[idx].lot, (res == 1) ? "WIN" : (res == -1) ? "LOSS" : "X"); SetText(pfx + "ELBL", lblT, entry, entTxt, entClr, 8, ANCHOR_LEFT); SetText(pfx + "TPLBL", lblT, tp, StringFormat("TP %.3f | +%.0fp (%.1fR)", tp, tpPips, rr), tpLineClr, 7, isBuy ? ANCHOR_LEFT_LOWER : ANCHOR_LEFT_UPPER); SetText(pfx + "SLLBL", lblT, sl, StringFormat("SL %.3f | -%.0fp", sl, slPips), slLineClr, 7, isBuy ? ANCHOR_LEFT_UPPER : ANCHOR_LEFT_LOWER); if (res != 0) { string resTxt = (res == 1) ? StringFormat("✓ +$%.2f", g_OrderHist[idx].profit) : (res == -1) ? StringFormat("✗ $%.2f", g_OrderHist[idx].profit) : "✗ cancelled"; SetText(pfx + "RES", lblT, (entry + sl) / 2.0, resTxt, resultClr, 8, ANCHOR_LEFT); } else { SetText(pfx + "RES", lblT, (entry + sl) / 2.0, StringFormat("Risk %.1f%% | %.0f:%.0fp | %.1fR", InpRiskPercent, slPips, tpPips, rr), C'140,140,140', 7, ANCHOR_LEFT); } } /** Deletes all chart objects for one order history record. */ inline void DeleteOrderHistObjects(int id) { string sid = IntegerToString(id); string pfx = PREFIX_ORDER_HIST + sid + "_"; ObjectDelete(0, pfx + "TP"); ObjectDelete(0, pfx + "SL"); ObjectDelete(0, pfx + "ENT"); ObjectDelete(0, pfx + "TPL"); ObjectDelete(0, pfx + "SLL"); ObjectDelete(0, pfx + "ELBL"); ObjectDelete(0, pfx + "TPLBL"); ObjectDelete(0, pfx + "SLLBL"); ObjectDelete(0, pfx + "RES"); } /** Draws all order history records; cleans up records older than ORDER_HIST_DAYS. */ inline void DrawAllOrders() { if (!InpDebugDraw) return; datetime cutoff = TimeCurrent() - ORDER_HIST_DAYS * 86400; for (int i = g_OrderHistCount - 1; i >= 0; i--) { if (g_OrderHist[i].closeTime > 0 && g_OrderHist[i].closeTime < cutoff) { DeleteOrderHistObjects(g_OrderHist[i].id); for (int j = i; j < g_OrderHistCount - 1; j++) g_OrderHist[j] = g_OrderHist[j + 1]; g_OrderHistCount--; continue; } DrawOneOrderHist(i); } } /** Draws one FVG record (rectangle + mid line + label) by pool index. */ inline void DrawOneFVGRecord(int idx) { if (!InpDebugDraw || idx < 0 || idx >= g_FVGCount) return; string sid = IntegerToString(g_FVGPool[idx].id); string rectN = PREFIX_FVG_POOL + "RECT_" + sid; string midN = PREFIX_FVG_POOL + "MID_" + sid; string lblN = PREFIX_FVG_POOL + "LBL_" + sid; datetime rectEnd; if (g_FVGPool[idx].status == FVG_PENDING) rectEnd = iTime(_Symbol, InpMiddleTF, 0); else if (g_FVGPool[idx].touchTime > 0) { int shift = MyBarShift(_Symbol, InpTriggerTF, g_FVGPool[idx].touchTime); rectEnd = (shift >= 0) ? iTime(_Symbol, InpTriggerTF, shift) : iTime(_Symbol, InpMiddleTF, 0); } else { int shift = MyBarShift(_Symbol, InpMiddleTF, g_FVGPool[idx].usedTime); rectEnd = (shift >= 0) ? iTime(_Symbol, InpMiddleTF, shift) : iTime(_Symbol, InpMiddleTF, 0); } if (rectEnd <= g_FVGPool[idx].createdTime) rectEnd = iTime(_Symbol, InpMiddleTF, 0); color fillColor; if (g_FVGPool[idx].status == FVG_PENDING) fillColor = (g_FVGPool[idx].direction == DIR_UP) ? C'0,50,110' : C'90,25,0'; else if (g_FVGPool[idx].status == FVG_TOUCHED) fillColor = (g_FVGPool[idx].direction == DIR_UP) ? C'0,120,220' : C'220,75,0'; else if (g_FVGPool[idx].usedCase == 2) fillColor = C'0,100,0'; else if (g_FVGPool[idx].usedCase == 1) fillColor = C'70,0,0'; else fillColor = C'50,50,50'; if (ObjectFind(0, rectN) < 0) ObjectCreate( 0, rectN, OBJ_RECTANGLE, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high, rectEnd, g_FVGPool[idx].low ); ObjectSetInteger(0, rectN, OBJPROP_COLOR, fillColor); ObjectSetInteger(0, rectN, OBJPROP_FILL, true); ObjectSetInteger(0, rectN, OBJPROP_BACK, true); ObjectMove( 0, rectN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high ); ObjectMove(0, rectN, 1, rectEnd, g_FVGPool[idx].low); color midColor = (g_FVGPool[idx].status == FVG_USED) ? C'60,60,60' : clrSilver; if (ObjectFind(0, midN) < 0) ObjectCreate( 0, midN, OBJ_TREND, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].mid, rectEnd, g_FVGPool[idx].mid ); ObjectSetInteger(0, midN, OBJPROP_COLOR, midColor); ObjectSetInteger(0, midN, OBJPROP_STYLE, STYLE_DOT); ObjectSetInteger(0, midN, OBJPROP_WIDTH, 1); ObjectSetInteger(0, midN, OBJPROP_RAY_RIGHT, false); ObjectMove( 0, midN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].mid ); ObjectMove(0, midN, 1, rectEnd, g_FVGPool[idx].mid); string sym = (g_FVGPool[idx].direction == DIR_UP) ? "▲" : "▼"; string stTxt = ""; if (g_FVGPool[idx].status == FVG_TOUCHED) stTxt = " [T]"; else if (g_FVGPool[idx].usedCase == 2) stTxt = " [TRIG]"; else if (g_FVGPool[idx].usedCase == 1) stTxt = " [BRK]"; else if (g_FVGPool[idx].status == FVG_USED) stTxt = " [EXP]"; if (ObjectFind(0, lblN) < 0) ObjectCreate( 0, lblN, OBJ_TEXT, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high ); ObjectMove( 0, lblN, 0, g_FVGPool[idx].createdTime, g_FVGPool[idx].high ); ObjectSetString( 0, lblN, OBJPROP_TEXT, StringFormat( "FVG#%d %s%s", g_FVGPool[idx].id, sym, stTxt ) ); ObjectSetInteger(0, lblN, OBJPROP_COLOR, fillColor); ObjectSetInteger(0, lblN, OBJPROP_FONTSIZE, 8); ObjectSetInteger(0, lblN, OBJPROP_ANCHOR, ANCHOR_LEFT_LOWER); } /** Draws all FVGs in pool (calls DrawOneFVGRecord for each). */ inline void DrawFVGPool() { if (!InpDebugDraw) return; for (int i = 0; i < g_FVGCount; i++) DrawOneFVGRecord(i); } /** Draws debug panel (bias, H1/M5 trend, risk, state, pool, active FVG, order). */ inline void DrawContextDebug() { if (!InpDebugDraw) return; #define LBL(name,txt,y,clr) \ if (ObjectFind(0, name) < 0) \ ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); \ ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); \ ObjectSetInteger(0, name, OBJPROP_XDISTANCE, 10); \ ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); \ ObjectSetInteger(0, name, OBJPROP_FONTSIZE, 9); \ ObjectSetInteger(0, name, OBJPROP_COLOR, clr); \ ObjectSetString (0, name, OBJPROP_TEXT, txt); LBL(PREFIX_DEBUG_PANEL + "HDR", "── ICT EA v4.3 ──", 10, clrSilver) color cMT = (g_MiddleTrend.trend == DIR_UP) ? clrLime : (g_MiddleTrend.trend == DIR_DOWN) ? clrTomato : clrGray; LBL( PREFIX_DEBUG_PANEL + "MT", StringFormat( "H1 : %s KL=%.5f", EnumToString(g_MiddleTrend.trend), g_MiddleTrend.keyLevel ), 34, cMT ) color cTT = (g_TriggerTrend.trend == DIR_UP) ? clrLime : (g_TriggerTrend.trend == DIR_DOWN) ? clrTomato : clrGray; LBL( PREFIX_DEBUG_PANEL + "TT", StringFormat( "M5 : %s KL=%.5f", EnumToString(g_TriggerTrend.trend), g_TriggerTrend.keyLevel ), 58, cTT ) if (g_ActiveFVGIdx >= 0 && g_ActiveFVGIdx < g_FVGCount && g_FVGPool[g_ActiveFVGIdx].usedCase == 2 && g_FVGPool[g_ActiveFVGIdx].mssTime > 0) { int ai = g_ActiveFVGIdx; color cM = (g_FVGPool[ai].direction == DIR_UP) ? clrLime : clrTomato; LBL( PREFIX_DEBUG_PANEL + "MSS", StringFormat( "MSS : %s entry=%.5f SL=%.5f @ %s (FVG#%d)", (g_FVGPool[ai].direction == DIR_UP) ? "▲" : "▼", g_FVGPool[ai].mssEntry, g_FVGPool[ai].mssSL, TimeToString(g_FVGPool[ai].mssTime, TIME_MINUTES), g_FVGPool[ai].id ), 82, cM ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "MSS"); double lostPct = (g_DailyRisk.startBalance > 0) ? (g_DailyRisk.startBalance - g_DailyRisk.currentBalance) / g_DailyRisk.startBalance * 100.0 : 0.0; color cR = g_DailyRisk.limitHit ? clrRed : (lostPct > InpMaxDailyLossPct * 0.7) ? clrOrange : clrLime; LBL( PREFIX_DEBUG_PANEL + "RISK", StringFormat("Risk : %.2f%% / %.2f%%", lostPct, InpMaxDailyLossPct), 106, cR ) color cS = (g_State == EA_IDLE) ? clrSilver : (g_State == EA_WAIT_TOUCH) ? clrOrange : (g_State == EA_WAIT_TRIGGER) ? clrYellow : clrLime; LBL( PREFIX_DEBUG_PANEL + "ST", StringFormat("State: %s", EnumToString(g_State)), 130, cS ) if (g_BlockReason != BLOCK_NONE) { LBL( PREFIX_DEBUG_PANEL + "BLK", StringFormat("Block: %s", EnumToString(g_BlockReason)), 154, clrTomato ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "BLK"); int countPending = 0; int countTouched = 0; int countUsed = 0; for (int i = 0; i < g_FVGCount; i++) { if (g_FVGPool[i].status == FVG_PENDING) countPending++; else if (g_FVGPool[i].status == FVG_TOUCHED) countTouched++; else countUsed++; } LBL( PREFIX_DEBUG_PANEL + "POOL", StringFormat( "Pool : P=%d T=%d U=%d (%d/%d)", countPending, countTouched, countUsed, g_FVGCount, MAX_FVG_POOL ), 178, clrDodgerBlue ) if (g_ActiveFVGIdx >= 0 && g_ActiveFVGIdx < g_FVGCount) { int ai = g_ActiveFVGIdx; LBL( PREFIX_DEBUG_PANEL + "ACT", StringFormat( "Act : #%d %s [%.5f–%.5f] %s", g_FVGPool[ai].id, EnumToString(g_FVGPool[ai].direction), g_FVGPool[ai].low, g_FVGPool[ai].high, EnumToString(g_FVGPool[ai].status) ), 202, clrDeepSkyBlue ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "ACT"); if (g_PendingTicket > 0 && g_OrderPlan.valid) { LBL( PREFIX_DEBUG_PANEL + "ORD", StringFormat( "Order: %s #%llu @ %.5f SL=%.5f TP=%.5f", (g_OrderPlan.direction > 0) ? "BUY" : "SELL", g_PendingTicket, g_OrderPlan.entry, g_OrderPlan.stopLoss, g_OrderPlan.takeProfit ), 226, clrGold ) } else ObjectDelete(0, PREFIX_DEBUG_PANEL + "ORD"); #undef LBL ChartRedraw(0); } /** Draws London and NY session zones (background color) on visible chart range. */ inline void DrawSessionMarkers() { if (!InpDebugDraw) return; int firstBar = (int)ChartGetInteger(0, CHART_FIRST_VISIBLE_BAR); int visibleBars = (int)ChartGetInteger(0, CHART_VISIBLE_BARS); if (visibleBars <= 0) return; ENUM_TIMEFRAMES chartTf = (ENUM_TIMEFRAMES)ChartPeriod(0); datetime firstTime = iTime(_Symbol, chartTf, firstBar); int lastBarIdx = firstBar - visibleBars + 1; if (lastBarIdx < 0) return; datetime lastTime = iTime(_Symbol, chartTf, lastBarIdx); double yHigh = 0; double yLow = 1e300; for (int i = firstBar; i >= lastBarIdx && i >= 0; i--) { double h = iHigh(_Symbol, chartTf, i); double l = iLow(_Symbol, chartTf, i); if (h > yHigh) yHigh = h; if (l < yLow) yLow = l; } double range = yHigh - yLow; if (range < _Point) return; double margin = MathMax(range * 0.02, 10 * _Point); yHigh += margin; yLow -= margin; const color clrLondon = (color)C'50,75,115'; const color clrNY = (color)C'115,80,50'; ObjectsDeleteAll(0, PREFIX_SESSION); for (int d = 0; d <= 200; d++) { datetime dayStart = iTime(_Symbol, PERIOD_D1, d); if (dayStart > lastTime) break; if (dayStart + 86400 < firstTime) continue; long startL = (long)InpLondonStartHour * 3600; long endL = (long)InpLondonEndHour * 3600; long startN = (long)InpNYStartHour * 3600; long endN = (long)InpNYEndHour * 3600; if (InpLondonStartHour < InpLondonEndHour) { datetime t1 = (datetime)(dayStart + startL); datetime t2 = (datetime)(dayStart + endL); if (t2 > firstTime && t1 < lastTime) { string name = PREFIX_SESSION + "L_" + IntegerToString(d); if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, yHigh, t2, yLow); ObjectSetInteger(0, name, OBJPROP_COLOR, clrLondon); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectMove(0, name, 0, t1, yHigh); ObjectMove(0, name, 1, t2, yLow); } } else { datetime t1 = (datetime)(dayStart + startL); datetime t2 = (datetime)(dayStart + 86400 + endL); if (t2 > firstTime && t1 < lastTime) { string name = PREFIX_SESSION + "L_" + IntegerToString(d); if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, yHigh, t2, yLow); ObjectSetInteger(0, name, OBJPROP_COLOR, clrLondon); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectMove(0, name, 0, t1, yHigh); ObjectMove(0, name, 1, t2, yLow); } } if (InpNYStartHour < InpNYEndHour) { datetime t1 = (datetime)(dayStart + startN); datetime t2 = (datetime)(dayStart + endN); if (t2 > firstTime && t1 < lastTime) { string name = PREFIX_SESSION + "N_" + IntegerToString(d); if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, yHigh, t2, yLow); ObjectSetInteger(0, name, OBJPROP_COLOR, clrNY); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectMove(0, name, 0, t1, yHigh); ObjectMove(0, name, 1, t2, yLow); } } else { datetime t1 = (datetime)(dayStart + startN); datetime t2 = (datetime)(dayStart + 86400 + endN); if (t2 > firstTime && t1 < lastTime) { string name = PREFIX_SESSION + "N_" + IntegerToString(d); if (ObjectFind(0, name) < 0) ObjectCreate(0, name, OBJ_RECTANGLE, 0, t1, yHigh, t2, yLow); ObjectSetInteger(0, name, OBJPROP_COLOR, clrNY); ObjectSetInteger(0, name, OBJPROP_FILL, true); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectMove(0, name, 0, t1, yHigh); ObjectMove(0, name, 1, t2, yLow); } } } } /** Draws all debug visuals: swings, MSS markers, FVG pool, orders, debug panel. */ inline void DrawVisuals() { DrawSessionMarkers(); DrawContextDebug(); DrawMiddleSwingPoints(); DrawFVGPool(); DrawTriggerSwingPoints(); DrawMSSMarkers(); DrawAllOrders(); } #endif // EA_ICT_CL__DRAWING_MQH