//+------------------------------------------------------------------+ //| AV_Monitor.mq5 | //| Copyright 2022, Anja Vogel | //| https://www.anjavogel.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2022, Anja Vogel" #property link "https://www.anjavogel.com" #define VERSION "1.07" #property version VERSION string indicatorName = "AV Monitor V" + VERSION; string indicatorShortname = "Monitor V" + VERSION; #property description "Ansicht:" #property description "Die Balance Linie startet rechts im Chart bei der aktuellen Balance." #property description "Die Long- und Shortpositionen starten dagegen links im Chart bei der Start-Balance." #property description "Die Prozentwerte in der Legende beziehen sich ebenso auf die Start-Balance." #property description " " #property description "Filterung:" #property description "Benutze 0 im Feld Magic zur Filterung von EAs ohne Magic und von händischen Trades." #property description "Lasse das Feld leer um alle anzuzeigen." #property indicator_separate_window // Diese Level werden überschrieben: #property indicator_level1 0 // Null-Linie #property indicator_level2 0 // StopOutLevel #property indicator_level3 0 // MarginCall #property indicator_level4 0 // Start-Balance #property indicator_buffers 6 #property indicator_plots 6 // 1. Farbchema: clrYellow, clrYellow, clrDodgerBlue, clrMediumSeaGreen, clrRed, clrChocolate // 2. Farbchema: clrKhaki, clrKhaki, clrLightSkyBlue, clrDarkSeaGreen, clrLightCoral, clrRosyBrown #property indicator_label1 "Balance" #property indicator_type1 DRAW_LINE #property indicator_color1 clrKhaki #property indicator_style1 STYLE_SOLID #property indicator_width1 3 #property indicator_label2 "Aktuelle Balance" #property indicator_type2 DRAW_LINE #property indicator_color2 clrKhaki #property indicator_style2 STYLE_DASH #property indicator_width2 1 #property indicator_label3 "Aktuelle Equity" #property indicator_type3 DRAW_LINE #property indicator_color3 clrLightSkyBlue #property indicator_style3 STYLE_DASH #property indicator_width3 1 #property indicator_label4 "Long-Positionen" #property indicator_type4 DRAW_LINE #property indicator_color4 clrDarkSeaGreen #property indicator_style4 STYLE_DOT #property indicator_width4 2 #property indicator_label5 "Short-Positionen" #property indicator_type5 DRAW_LINE #property indicator_color5 clrLightCoral #property indicator_style5 STYLE_DOT #property indicator_width5 2 #property indicator_label6 "Aktuelle Margin" #property indicator_type6 DRAW_LINE #property indicator_color6 clrRosyBrown #property indicator_style6 STYLE_DASH #property indicator_width6 1 input group "Ansichts-Einstellungen" input double Begin_Balance = 10000.0; // Start-Balance input bool Show_BalanceAndEquity = true; // Balance & Equity input bool Show_BuyAndSell = true; // Short- & Longpositionen input bool Show_Zero = false; // Null-Linie input group " " input group "Legende" input color Text_Neutral = clrDarkGray; // Schriftfarbe input int Text_Size = 11; // Schriftgröße input ENUM_BASE_CORNER Text_Corner = CORNER_RIGHT_LOWER; // Positionierung input int Text_Position = 250; // Abstand (15 links, 250 rechts) input group " " input group "Filter-Einstellungen" input datetime Draw_Begin = D'2022.10.13 00:00'; // Start-Datum input string Only_Symbol = ""; // Nur folgendes Symbol input string Only_Magic = ""; // Nur folgende Magic input group " " input group "Entwicklung / Logging" input bool develop = false; // Entwickler double Balance[]; double currentBalance[]; double currentEquity[]; double buyBalance[]; double sellBalance[]; double currentMargin[]; double lastChartMax = 0; double lastChartMin = 0; static int totalBars; //+------------------------------------------------------------------+ // OnInit() //+------------------------------------------------------------------+ int OnInit() { IndicatorSetString(INDICATOR_SHORTNAME, indicatorShortname); IndicatorSetInteger(INDICATOR_DIGITS, 2); // Buffer SetIndexBuffer(0, Balance, INDICATOR_CALCULATIONS); SetIndexBuffer(1, currentBalance, INDICATOR_CALCULATIONS); SetIndexBuffer(2, currentEquity, INDICATOR_CALCULATIONS); SetIndexBuffer(3, buyBalance, INDICATOR_CALCULATIONS); SetIndexBuffer(4, sellBalance, INDICATOR_CALCULATIONS); SetIndexBuffer(5, currentMargin, INDICATOR_CALCULATIONS); // Level IndicatorSetString(INDICATOR_LEVELTEXT, 0, "Zero"); /*if (AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE) == ACCOUNT_STOPOUT_MODE_MONEY) { IndicatorSetString(INDICATOR_LEVELTEXT, 1, "Stop Out: " + AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)); IndicatorSetDouble(INDICATOR_LEVELVALUE,1, AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)); } if (AccountInfoInteger(ACCOUNT_MARGIN_SO_MODE) == ACCOUNT_STOPOUT_MODE_PERCENT) { IndicatorSetString(INDICATOR_LEVELTEXT, 1, "Stop Out: " + AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)*AccountInfoDouble(ACCOUNT_MARGIN)/100); IndicatorSetDouble(INDICATOR_LEVELVALUE,1, AccountInfoDouble(ACCOUNT_MARGIN_SO_SO)*AccountInfoDouble(ACCOUNT_MARGIN)/100); } IndicatorSetString(INDICATOR_LEVELTEXT, 2, "Margin Call: " + AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL)); IndicatorSetDouble(INDICATOR_LEVELVALUE,2, AccountInfoDouble(ACCOUNT_MARGIN_SO_CALL)); */ if (Begin_Balance > 0) { IndicatorSetString(INDICATOR_LEVELTEXT, 3, "Start: " + TimeToString(Draw_Begin,TIME_DATE)); IndicatorSetDouble(INDICATOR_LEVELVALUE,3, Begin_Balance); } totalBars = iBars(NULL, 0); return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ // OnDeinit() //+------------------------------------------------------------------+ void OnDeinit(const int reason) { ObjectDelete(0,"Balance"); ObjectDelete(0,"currentBalance"); ObjectDelete(0,"currentEquity"); ObjectDelete(0,"buyBalance"); ObjectDelete(0,"sellBalance"); ObjectDelete(0,"currentMargin"); ObjectDelete(0,"Begin_Balance"); ObjectDelete(0,"Only_Symbol"); ObjectDelete(0,"Only_Magic"); } //+------------------------------------------------------------------+ // OnTradeTransaction() //+------------------------------------------------------------------+ void OnTradeTransaction(const MqlTradeTransaction &trans, const MqlTradeRequest &request, const MqlTradeResult &result) { // 0,2,3,6,10 0,9,6,2,3 //Print("OnTradeTransaction() --------------------- ", trans.type); } //+------------------------------------------------------------------+ // OnCalculate() //+------------------------------------------------------------------+ 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[]) { ArraySetAsSeries(time, true); ArraySetAsSeries(open, true); ArraySetAsSeries(close, true); ArraySetAsSeries(Balance, true); ArraySetAsSeries(currentBalance, true); ArraySetAsSeries(currentEquity, true); ArraySetAsSeries(buyBalance, true); ArraySetAsSeries(sellBalance, true); ArraySetAsSeries(currentMargin, true); datetime start = TimeCurrent(); datetime end = TimeCurrent(); double result = 0.0; double resultBuys = 0.0; double resultSells = 0.0; string symbol = NULL; int lastValue = 0; // Für Addition bool hasDeals = false; double max = Begin_Balance; double min = Begin_Balance; if (prev_calculated == 0) { ArrayInitialize(Balance, EMPTY_VALUE); ArrayInitialize(buyBalance, EMPTY_VALUE); ArrayInitialize(sellBalance, EMPTY_VALUE); } if (Show_BalanceAndEquity) { Balance[0] = AccountInfoDouble(ACCOUNT_BALANCE); ArrayInitialize(currentBalance, AccountInfoDouble(ACCOUNT_BALANCE)); ArrayInitialize(currentEquity, AccountInfoDouble(ACCOUNT_EQUITY)); ArrayInitialize(currentMargin, AccountInfoDouble(ACCOUNT_MARGIN)); max = MathMax(Balance[0], currentEquity[0]); min = MathMin(Balance[0], currentEquity[0]); } else { ArrayInitialize(currentBalance, EMPTY_VALUE); ArrayInitialize(currentEquity, EMPTY_VALUE); ArrayInitialize(currentMargin, EMPTY_VALUE); } if (Show_Zero) min = MathMin(min, 0.0); int periods = 0; if (Bars(NULL, 0) != totalBars || prev_calculated != rates_total || Minute() % 6 == 0) { totalBars = Bars(NULL, 0); periods = iBarShift(NULL,PERIOD_CURRENT,Draw_Begin); } else { return(rates_total); } // Berechnung der Balance anhand der Deals (von rechts nach links) for (int i=1; i <= periods; i++) { // Perioden // Vorbelegung if (Show_BalanceAndEquity) { currentBalance[i] = AccountInfoDouble(ACCOUNT_BALANCE); currentEquity[i] = AccountInfoDouble(ACCOUNT_EQUITY); currentMargin[i] = AccountInfoDouble(ACCOUNT_MARGIN); } start = time[i]; // Bar 1 end = (i == 1 ? TimeCurrent() : time[i-1]); // Bar 0 // Vorbelegung if (start < (int)Draw_Begin) { Balance[i] = Begin_Balance; // Min/Max für Fensteroptimierung min = MathMin(min, Balance[i]); max = MathMax(max, Balance[i]); continue; } HistorySelect(start,end); // Deals für Zeitraum in den Cache laden int historyDeals = HistoryDealsTotal(); for (int j=0; j < historyDeals; j++) { // Deals in der Periode ulong ticket = HistoryDealGetTicket(j); if (ticket > 0) { if (!FilterDeal(ticket)) continue; // Bugfix: if (HistoryDealGetInteger(ticket, DEAL_TIME) >= start && HistoryDealGetInteger(ticket, DEAL_TIME) < end) { hasDeals = true; result += HistoryDealGetDouble(ticket, DEAL_PROFIT); result += HistoryDealGetDouble(ticket, DEAL_COMMISSION); result += HistoryDealGetDouble(ticket, DEAL_SWAP); // bei DEAL_ENTRY_OUT alles umgekehrt: if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_SELL) { resultBuys += HistoryDealGetDouble(ticket, DEAL_PROFIT); resultBuys += HistoryDealGetDouble(ticket, DEAL_COMMISSION); resultBuys += HistoryDealGetDouble(ticket, DEAL_SWAP); } else if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_BUY) { resultSells += HistoryDealGetDouble(ticket, DEAL_PROFIT); resultSells += HistoryDealGetDouble(ticket, DEAL_COMMISSION); resultSells += HistoryDealGetDouble(ticket, DEAL_SWAP); } } } } // den letzten Wert merken für die Addition unten if (result != 0.0) lastValue = i; // Liniendaten befüllen if (i == 0) Balance[0] -= result; else Balance[i] = Balance[i-1] - result; buyBalance[i] = resultBuys; sellBalance[i] = resultSells; // Min/Max für Fensteroptimierung if (Show_BalanceAndEquity) { min = MathMin(min, Balance[i]); max = MathMax(max, Balance[i]); } // Werte zurück setzen result = 0.0; resultBuys = 0.0; resultSells = 0.0; } // Addition der reinen Sells und Buys (von links nach rechts) if (Show_BuyAndSell && lastValue > 0) { // Linie ab lastValue in Vergangenheit zeichnen for (int l=lastValue; l <= periods; l++) { buyBalance[l] += Begin_Balance; sellBalance[l] += Begin_Balance; } // Linie ab lastValue in Zukunft zeichnen for (int k = lastValue; k > 1; k--) { buyBalance[k-1] += buyBalance[k]; sellBalance[k-1] += sellBalance[k]; // Min/Max für Fensteroptimierung min = MathMin(min, buyBalance[k-1]); max = MathMax(max, buyBalance[k-1]); min = MathMin(min, sellBalance[k-1]); max = MathMax(max, sellBalance[k-1]); } // aktueller Wert bleibt auf dem letztem Wert (und nicht auf Balance zurück) buyBalance[0] = buyBalance[1]; sellBalance[0] = sellBalance[1]; } // Fensteroptimierung if (min == max) { max *= 1.1; min *= 0.9; } if (hasDeals) { if (lastChartMax != (int)MathCeil(max + 0.16*(max-min))) { lastChartMax = (int)MathCeil(max + 0.16*(max-min)); IndicatorSetDouble(INDICATOR_MAXIMUM, lastChartMax); } if (lastChartMin != (int)MathFloor(min - 0.16*(max-min))) { lastChartMin = (int)MathFloor(Show_Zero ? 0 : min - 0.16*(max-min)); IndicatorSetDouble(INDICATOR_MINIMUM, lastChartMin); } } else { if (lastChartMax != (int)MathCeil(Begin_Balance*1.5)) { lastChartMax = (int)MathCeil(Begin_Balance*1.5); IndicatorSetDouble(INDICATOR_MAXIMUM, lastChartMax); } if (lastChartMin != (int)MathFloor(Show_Zero ? Show_Zero : Begin_Balance/2)) { lastChartMin = (int)MathFloor(Show_Zero ? 0 : Begin_Balance/2); IndicatorSetDouble(INDICATOR_MINIMUM, lastChartMin); } } // Legende string text = ""; int x = Text_Position; int y = 0, add = 0; switch (Text_Corner) { case CORNER_RIGHT_UPPER: case CORNER_LEFT_UPPER: y = 2; add = 20; break; case CORNER_LEFT_LOWER: case CORNER_RIGHT_LOWER: y = 30; add = -20; y += Show_BalanceAndEquity ? 4*MathAbs(add) : 0; y += Show_BuyAndSell ? 2*MathAbs(add) : 0; y += Only_Magic != "" ? 1*MathAbs(add) : 0; y += Only_Symbol != "" ? 1*MathAbs(add) : 0; break; } if (Only_Symbol != "") { text = "Symbol " + Only_Symbol; DrawLabel("Only_Symbol",x,y+=add, text, develop ? clrOrange : Text_Neutral); } if (Only_Magic != "") { text = "Magic " + Only_Magic; DrawLabel("Only_Magic",x,y+=add, text, develop ? clrOrange : Text_Neutral); } if (Show_BalanceAndEquity) { text = indicator_label1 + " " + (string)NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE),2); DrawLabel("Balance",x,y+=add,text, develop ? clrOrange : indicator_color1); text = indicator_label2 + " " + (string)NormalizeDouble(AccountInfoDouble(ACCOUNT_BALANCE)/Begin_Balance*100,1) + " %"; DrawLabel("currentBalance",x,y+=add,text, develop ? clrOrange : indicator_color2); text = indicator_label3 + " " + (string)NormalizeDouble(AccountInfoDouble(ACCOUNT_EQUITY)/Begin_Balance*100,1) + " %"; DrawLabel("currentEquity",x,y+=add,text, develop ? clrOrange : indicator_color3); text = indicator_label6 + " " + (string)NormalizeDouble(AccountInfoDouble(ACCOUNT_MARGIN),2); DrawLabel("currentMargin",x,y+=add,text, develop ? clrOrange : indicator_color6); } else { ObjectDelete(0,"Balance"); ObjectDelete(0,"currentBalance"); ObjectDelete(0,"currentEquity"); ObjectDelete(0,"currentMargin"); } if (Show_BuyAndSell) { text = indicator_label4 + " "; if (hasDeals) text += (string)NormalizeDouble(buyBalance[0], 2); else text += "-"; DrawLabel("buyBalance",x,y+=add, text, develop ? clrOrange : indicator_color4); text = indicator_label5 + " "; if (hasDeals) text += (string)NormalizeDouble(sellBalance[0], 2); else text += "-"; DrawLabel("sellBalance",x,y+=add, text, develop ? clrOrange : indicator_color5); } else { ObjectDelete(0,"buyBalance"); ObjectDelete(0,"sellBalance"); } // Daten entfernen, falls sie nicht angezeigt werden sollen if (!Show_BalanceAndEquity) { ArrayFill(Balance,0,ArraySize(Balance),EMPTY_VALUE); ArrayFill(currentBalance,0,ArraySize(currentBalance),EMPTY_VALUE); ArrayFill(currentEquity,0,ArraySize(currentEquity),EMPTY_VALUE); ArrayFill(currentMargin,0,ArraySize(currentMargin),EMPTY_VALUE); } if (!Show_BuyAndSell) { ArrayFill(buyBalance,0,ArraySize(buyBalance),EMPTY_VALUE); ArrayFill(sellBalance,0,ArraySize(sellBalance),EMPTY_VALUE); } return(rates_total); } //+------------------------------------------------------------------+ // Filter für die Deals //+------------------------------------------------------------------+ bool FilterDeal(ulong ticket) { if (HistoryDealGetInteger(ticket, DEAL_ENTRY) == DEAL_ENTRY_IN) return(false); if (Only_Magic != "" ) { if ((int)HistoryDealGetInteger(ticket, DEAL_MAGIC) != (int)Only_Magic) return(false); } if (Only_Symbol != "") if (StringFind(Only_Symbol, HistoryDealGetString(ticket, DEAL_SYMBOL)) == -1) return(false); // im Original 0,1 ok und größer 5 (0 = DEAL_TYPE_BUY & 1 = DEAL_TYPE_SELL ) if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_BALANCE) return(false); // = 2 if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_CREDIT) return(false); // = 3 if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_CHARGE) return(false); // = 4 if (HistoryDealGetInteger(ticket, DEAL_TYPE) == DEAL_TYPE_CORRECTION) return(false); // = 5 return(true); } //+------------------------------------------------------------------+ // Zeichne Label bzw. Legende //+------------------------------------------------------------------+ bool DrawLabel(string name = "Label", int x = 0, int y = 0, string text = "Label", color clr = clrGainsboro) // clrGray { // Label bereits vorhanden? if (ObjectFind(0, name) < 0) { // erstellen if (!ObjectCreate(0, name, OBJ_LABEL, ChartWindowFind(), 0, 0)) { return(false); } ObjectSetInteger(0,name,OBJPROP_XDISTANCE,x); ObjectSetInteger(0,name,OBJPROP_YDISTANCE,y); ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_UPPER); ObjectSetString(0,name,OBJPROP_FONT,"Lucida Console"); ObjectSetInteger(0,name,OBJPROP_BACK,false); ObjectSetInteger(0,name,OBJPROP_SELECTABLE,true); ObjectSetInteger(0,name,OBJPROP_CORNER,Text_Corner); ObjectSetInteger(0,name,OBJPROP_FONTSIZE,Text_Size); ObjectSetInteger(0,name,OBJPROP_HIDDEN,!develop); } // aktualisieren ObjectSetString(0,name,OBJPROP_TEXT,text); ObjectSetInteger(0,name,OBJPROP_COLOR,clr); return(true); } //+------------------------------------------------------------------+ // Logge Information, nur wenn eingeschaltet (gut bei Nutzung in mehreren Charts) //+------------------------------------------------------------------+ void out(string text) { if (develop) Print(_Symbol, " ----------- ", text, " ----------- "); } //+------------------------------------------------------------------+ int Day() { MqlDateTime tm; TimeCurrent(tm); return(tm.day); } int DayOfWeek() { MqlDateTime tm; TimeCurrent(tm); return(tm.day_of_week); } int DayOfYear() { MqlDateTime tm; TimeCurrent(tm); return(tm.day_of_year); } int Hour() { MqlDateTime tm; TimeCurrent(tm); return(tm.hour); } int Minute() { MqlDateTime tm; TimeCurrent(tm); return(tm.min); } int Month() { MqlDateTime tm; TimeCurrent(tm); return(tm.mon); } int Seconds() { MqlDateTime tm; TimeCurrent(tm); return(tm.sec); } int Year() { MqlDateTime tm; TimeCurrent(tm); return(tm.year); }