//+------------------------------------------------------------------+ //| PME_Monitor_Dashboard.mq5 | //| Real-time Position Monitoring Dashboard | //+------------------------------------------------------------------+ #property indicator_chart_window #property indicator_plots 0 #include "Modules_PME/DataTypes_PME.mqh" //+------------------------------------------------------------------+ //| Input Parameters | //+------------------------------------------------------------------+ input int InpUpdateSeconds = 1; // Update Frequency (seconds) input int InpDashboardX = 20; // Dashboard X Position input int InpDashboardY = 100; // Dashboard Y Position input color InpTextColor = clrWhite; // Text Color input color InpHeaderColor = clrGold; // Header Color input color InpWarningColor = clrOrange; // Warning Color input color InpDangerColor = clrRed; // Danger Color input color InpSuccessColor = clrLime; // Success Color input bool InpShowAlerts = true; // Show Alert Warnings //+------------------------------------------------------------------+ //| Global Variables | //+------------------------------------------------------------------+ string g_prefix = "PME_MON_"; datetime g_last_update = 0; int g_positions_count = 0; double g_total_profit = 0; double g_total_risk = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { // Set timer EventSetTimer(InpUpdateSeconds); // Create dashboard CreateDashboard(); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { EventKillTimer(); // Remove all dashboard objects ObjectsDeleteAll(0, g_prefix); } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { UpdateDashboard(); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { // Update on new bar if(prev_calculated != rates_total) { UpdateDashboard(); } return(rates_total); } //+------------------------------------------------------------------+ //| Create Dashboard | //+------------------------------------------------------------------+ void CreateDashboard() { int y = InpDashboardY; // Background CreateRectangle(g_prefix + "BG", InpDashboardX - 5, y - 5, 300, 450, clrBlack, STYLE_SOLID, 1, 80); // Header CreateLabel(g_prefix + "HEADER", InpDashboardX, y, "═══ PME POSITION MONITOR ═══", InpHeaderColor, 10, true); y += 25; // Time CreateLabel(g_prefix + "TIME", InpDashboardX, y, "Last Update: --:--:--", InpTextColor, 8); y += 20; // Separator CreateLabel(g_prefix + "SEP1", InpDashboardX, y, "────────────────────────", InpTextColor, 8); y += 15; // Position Summary CreateLabel(g_prefix + "POS_HEADER", InpDashboardX, y, "POSITION SUMMARY", InpHeaderColor, 9, true); y += 18; CreateLabel(g_prefix + "POS_COUNT", InpDashboardX, y, "Active Positions: 0", InpTextColor, 9); y += 15; CreateLabel(g_prefix + "TOTAL_PROFIT", InpDashboardX, y, "Total P/L: $0.00", InpTextColor, 9); y += 15; CreateLabel(g_prefix + "TOTAL_RISK", InpDashboardX, y, "Total Risk: $0.00", InpTextColor, 9); y += 20; // Separator CreateLabel(g_prefix + "SEP2", InpDashboardX, y, "────────────────────────", InpTextColor, 8); y += 15; // Position Details CreateLabel(g_prefix + "DETAIL_HEADER", InpDashboardX, y, "POSITION DETAILS", InpHeaderColor, 9, true); y += 18; // Create slots for up to 5 positions for(int i = 0; i < 5; i++) { CreateLabel(g_prefix + "POS_" + IntegerToString(i) + "_INFO", InpDashboardX, y + (i * 45), "", InpTextColor, 8); CreateLabel(g_prefix + "POS_" + IntegerToString(i) + "_STATUS", InpDashboardX, y + (i * 45) + 12, "", InpTextColor, 8); CreateLabel(g_prefix + "POS_" + IntegerToString(i) + "_RISK", InpDashboardX, y + (i * 45) + 24, "", InpTextColor, 8); CreateLabel(g_prefix + "POS_" + IntegerToString(i) + "_EXIT", InpDashboardX, y + (i * 45) + 36, "", InpWarningColor, 8); } y += 230; // Separator CreateLabel(g_prefix + "SEP3", InpDashboardX, y, "────────────────────────", InpTextColor, 8); y += 15; // Warnings CreateLabel(g_prefix + "WARNING_HEADER", InpDashboardX, y, "WARNINGS", InpHeaderColor, 9, true); y += 18; CreateLabel(g_prefix + "WARNING_1", InpDashboardX, y, "", InpWarningColor, 8); y += 12; CreateLabel(g_prefix + "WARNING_2", InpDashboardX, y + 12, "", InpWarningColor, 8); y += 12; CreateLabel(g_prefix + "WARNING_3", InpDashboardX, y + 24, "", InpDangerColor, 8); } //+------------------------------------------------------------------+ //| Update Dashboard | //+------------------------------------------------------------------+ void UpdateDashboard() { // Update time UpdateLabel(g_prefix + "TIME", "Last Update: " + TimeToString(TimeCurrent(), TIME_SECONDS)); // Get positions int total = PositionsTotal(); double total_profit = 0; double total_risk = 0; // Clear warnings UpdateLabel(g_prefix + "WARNING_1", ""); UpdateLabel(g_prefix + "WARNING_2", ""); UpdateLabel(g_prefix + "WARNING_3", ""); int warning_count = 0; // Process positions for(int i = 0; i < MathMin(total, 5); i++) { ulong ticket = PositionGetTicket(i); if(PositionSelectByTicket(ticket)) { string symbol = PositionGetString(POSITION_SYMBOL); ENUM_ORDER_TYPE type = (ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE); double volume = PositionGetDouble(POSITION_VOLUME); double profit = PositionGetDouble(POSITION_PROFIT); double entry = PositionGetDouble(POSITION_PRICE_OPEN); double current = PositionGetDouble(POSITION_PRICE_CURRENT); double sl = PositionGetDouble(POSITION_SL); double tp = PositionGetDouble(POSITION_TP); datetime open_time = (datetime)PositionGetInteger(POSITION_TIME); total_profit += profit; // Calculate risk if(sl > 0) { double point = SymbolInfoDouble(symbol, SYMBOL_POINT); double tick_value = SymbolInfoDouble(symbol, SYMBOL_TRADE_TICK_VALUE); double sl_points = MathAbs(current - sl) / point; double risk = sl_points * tick_value * volume; total_risk += risk; } // Calculate bars and points int bars = Bars(symbol, PERIOD_CURRENT, open_time, TimeCurrent()); double points = 0; if(type == ORDER_TYPE_BUY) points = (current - entry) / SymbolInfoDouble(symbol, SYMBOL_POINT); else points = (entry - current) / SymbolInfoDouble(symbol, SYMBOL_POINT); // Update position info string pos_info = StringFormat("#%d %s %s %.2f", ticket, symbol, type == ORDER_TYPE_BUY ? "BUY" : "SELL", volume); string status = StringFormat("P/L: %s%.2f (%.0f pts)", profit >= 0 ? "+" : "", profit, points); string risk_info = StringFormat("Bars: %d | SL: %s | TP: %s", bars, sl > 0 ? "YES" : "NO", tp > 0 ? "YES" : "NO"); // Check exit conditions string exit_warning = ""; color status_color = InpTextColor; // Check for potential exits if(bars < 10) { exit_warning = "⏱ New position (< 10 bars)"; status_color = InpSuccessColor; } else if(points >= 30 && points < 50) { exit_warning = "📊 Approaching BE trigger"; status_color = InpWarningColor; } else if(points >= 50) { exit_warning = "📈 In trailing zone"; status_color = InpSuccessColor; } else if(profit < -50) { exit_warning = "⚠️ Significant loss"; status_color = InpDangerColor; } // Check RSI int rsi_handle = iRSI(symbol, PERIOD_CURRENT, 14, PRICE_CLOSE); double rsi_buffer[1]; if(CopyBuffer(rsi_handle, 0, 0, 1, rsi_buffer) > 0) { double rsi = rsi_buffer[0]; if(type == ORDER_TYPE_BUY && rsi > 75) { exit_warning += StringFormat(" RSI:%.0f", rsi); status_color = InpWarningColor; } else if(type == ORDER_TYPE_SELL && rsi < 25) { exit_warning += StringFormat(" RSI:%.0f", rsi); status_color = InpWarningColor; } } IndicatorRelease(rsi_handle); // Update labels UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_INFO", pos_info); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_STATUS", status, profit >= 0 ? InpSuccessColor : InpDangerColor); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_RISK", risk_info); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_EXIT", exit_warning, status_color); // Add warnings if(sl == 0 && warning_count < 3) { UpdateLabel(g_prefix + "WARNING_" + IntegerToString(warning_count + 1), StringFormat("⚠️ #%d has no stop loss!", ticket)); warning_count++; } } } // Clear unused position slots for(int i = total; i < 5; i++) { UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_INFO", ""); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_STATUS", ""); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_RISK", ""); UpdateLabel(g_prefix + "POS_" + IntegerToString(i) + "_EXIT", ""); } // Update summary UpdateLabel(g_prefix + "POS_COUNT", StringFormat("Active Positions: %d", total)); UpdateLabel(g_prefix + "TOTAL_PROFIT", StringFormat("Total P/L: %s%.2f", total_profit >= 0 ? "$" : "-$", MathAbs(total_profit)), total_profit >= 0 ? InpSuccessColor : InpDangerColor); UpdateLabel(g_prefix + "TOTAL_RISK", StringFormat("Total Risk: $%.2f", total_risk)); // Check for global warnings double balance = AccountInfoDouble(ACCOUNT_BALANCE); double equity = AccountInfoDouble(ACCOUNT_EQUITY); double daily_loss = ((balance - equity) / balance) * 100; if(daily_loss > 5 && warning_count < 3) { UpdateLabel(g_prefix + "WARNING_" + IntegerToString(warning_count + 1), StringFormat("⚠️ Daily loss: %.1f%%", daily_loss), InpDangerColor); warning_count++; } // Alert on significant changes if(InpShowAlerts) { static int last_count = 0; if(total < last_count && last_count > 0) { Alert("PME Monitor: Position closed!"); } last_count = total; } } //+------------------------------------------------------------------+ //| Create Label | //+------------------------------------------------------------------+ void CreateLabel(string name, int x, int y, string text, color clr, int size, bool bold = false) { ObjectCreate(0, name, OBJ_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetString(0, name, OBJPROP_TEXT, text); ObjectSetString(0, name, OBJPROP_FONT, bold ? "Arial Bold" : "Arial"); ObjectSetInteger(0, name, OBJPROP_FONTSIZE, size); ObjectSetInteger(0, name, OBJPROP_COLOR, clr); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); } //+------------------------------------------------------------------+ //| Update Label | //+------------------------------------------------------------------+ void UpdateLabel(string name, string text, color clr = clrNONE) { if(ObjectFind(0, name) >= 0) { ObjectSetString(0, name, OBJPROP_TEXT, text); if(clr != clrNONE) ObjectSetInteger(0, name, OBJPROP_COLOR, clr); } } //+------------------------------------------------------------------+ //| Create Rectangle | //+------------------------------------------------------------------+ void CreateRectangle(string name, int x, int y, int width, int height, color clr, ENUM_LINE_STYLE style, int line_width, int transparency = 255) { ObjectCreate(0, name, OBJ_RECTANGLE_LABEL, 0, 0, 0); ObjectSetInteger(0, name, OBJPROP_XDISTANCE, x); ObjectSetInteger(0, name, OBJPROP_YDISTANCE, y); ObjectSetInteger(0, name, OBJPROP_XSIZE, width); ObjectSetInteger(0, name, OBJPROP_YSIZE, height); ObjectSetInteger(0, name, OBJPROP_BGCOLOR, clr); ObjectSetInteger(0, name, OBJPROP_BORDER_TYPE, BORDER_FLAT); ObjectSetInteger(0, name, OBJPROP_WIDTH, line_width); ObjectSetInteger(0, name, OBJPROP_CORNER, CORNER_LEFT_UPPER); ObjectSetInteger(0, name, OBJPROP_STYLE, style); ObjectSetInteger(0, name, OBJPROP_BACK, true); ObjectSetInteger(0, name, OBJPROP_SELECTABLE, false); ObjectSetInteger(0, name, OBJPROP_HIDDEN, true); // Set transparency (0-255, where 255 is opaque) long color_value = (long)clr; long alpha = (255 - transparency) << 24; color_value = (color_value & 0x00FFFFFF) | alpha; ObjectSetInteger(0, name, OBJPROP_BGCOLOR, (color)color_value); } //+------------------------------------------------------------------+