//+------------------------------------------------------------------+ //| Equity Monitor | //| Monitoring balance, equity, margin, profitability and drawdown | //+------------------------------------------------------------------+ //| Original idea and code by Xupypr (Igor Korepin) | //| Remake by transcendreamer | //+------------------------------------------------------------------+ #property copyright "Equity Monitor - original by Xupypr - remake by transcendreamer" #property description "Monitoring balance, equity, margin, profitability and drawdown" #property strict #property indicator_separate_window #property indicator_buffers 5 #property indicator_color1 SteelBlue #property indicator_color2 OrangeRed #property indicator_color3 SlateGray #property indicator_color4 ForestGreen #property indicator_color5 Gray #property indicator_width1 1 #property indicator_width2 1 #property indicator_width3 1 #property indicator_width4 1 #property indicator_width5 1 extern string ______FILTERS______="______FILTERS______"; extern bool Only_Trading=false; extern bool Only_Current=false; extern bool Only_Buys=false; extern bool Only_Sells=false; extern bool Only_Magics=false; extern int Magic_From=0; extern int Magic_To=0; extern string Only_Symbols=""; extern string Only_Comment=""; extern string ______PERIOD______="______PERIOD______"; extern datetime Draw_Begin=D'2012.01.01 00:00'; extern datetime Draw_End=D'2035.01.01 00:00'; enum reporting {day,month,year,history}; extern reporting Report_Period=history; extern string ______ALERTS______="______ALERTS______"; extern double Equity_Min_Alert=0; extern double Equity_Max_Alert=0; extern bool Push_Alerts=false; extern string ______LINES______="______LINES______"; extern bool Show_Balance=true; extern bool Show_Margin=false; extern bool Show_Free=false; extern bool Show_Zero=false; extern bool Show_Info=true; extern bool Show_Verticals=true; extern string ______OTHER______="______OTHER______"; extern ENUM_BASE_CORNER Text_Corner=CORNER_LEFT_UPPER; extern color Text_Color=Magenta; extern string Text_Font="Tahoma"; extern int Text_Size=12; extern bool File_Write=false; extern string FX_prefix=""; extern string FX_postfix=""; string ShortName,Unique; int DrawBeginBar,DrawEndBar,Window; double Equity[],Balance[],Margin[],Free[],Zero[]; double ResultBalance,ResultProfit,GrowthRatio; double ProfitLoss,Spread,SumMargin,LotValue; double PeakProfit,PeakEquity,MaxDrawdown,RelDrawdown; double SumProfit,SumLoss,NetProfit; double RecoveryFactor,ProfitFactor,Profitability; string Instrument[]; datetime OpenTime_Ticket[][2],CloseTime[]; int OpenBar[],CloseBar[],Type[]; double Lots[],OpenPrice[],ClosePrice[],Commission[],Swap[],CumSwap[],DaySwap[],Profit[]; datetime start_time,finish_time; int Total,HistoryTotal,OpenTotal; string missing_symbols; bool alert_upper_active,alert_lower_active; bool using_filters; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { using_filters=false; if(Only_Symbols!="") using_filters=true; if(Only_Comment!="") using_filters=true; if(Only_Current) using_filters=true; if(Only_Buys) using_filters=true; if(Only_Sells) using_filters=true; if(Only_Magics) using_filters=true; if(!using_filters) ShortName="Total"; else ShortName=""; if(Only_Symbols!="") ShortName=StringConcatenate(ShortName," ",Only_Symbols); else if(Only_Current) ShortName=StringConcatenate(ShortName," ",Symbol()); if(Only_Magics) ShortName=StringConcatenate(ShortName," #",Magic_From,":",Magic_To); if(Only_Comment!="") ShortName=StringConcatenate(ShortName," [",Only_Comment,"]"); if(Only_Buys && !Only_Sells) ShortName=StringConcatenate(ShortName," Buys"); if(Only_Sells && !Only_Buys) ShortName=StringConcatenate(ShortName," Sells"); if(Only_Trading) ShortName=StringConcatenate(ShortName," Trading"); SetIndexBuffer(0,Equity); SetIndexBuffer(1,Balance); SetIndexBuffer(2,Margin); SetIndexBuffer(3,Free); SetIndexBuffer(4,Zero); SetIndexLabel(0,"Equity"); SetIndexLabel(1,"Balance"); SetIndexLabel(2,"Margin"); SetIndexLabel(3,"Free"); SetIndexLabel(4,"Zero"); SetIndexStyle(0,DRAW_LINE); SetIndexStyle(1,DRAW_LINE); SetIndexStyle(2,DRAW_HISTOGRAM); SetIndexStyle(3,DRAW_LINE); SetIndexStyle(4,DRAW_LINE); ShortName =StringConcatenate(ShortName," Equity"); if(Show_Balance) ShortName=StringConcatenate(ShortName," Balance"); if(Show_Margin) ShortName=StringConcatenate(ShortName," Margin"); if(Show_Free) ShortName=StringConcatenate(ShortName," Free"); Unique=(string)ChartID()+(string)ChartWindowFind(); DrawBeginBar=iBarShift(NULL,0,Draw_Begin); DrawEndBar=iBarShift(NULL,0,Draw_End); if(Equity_Max_Alert!=0) alert_upper_active=true; else alert_upper_active=false; if(Equity_Min_Alert!=0) alert_lower_active=true; else alert_lower_active=false; IndicatorDigits(2); return(0); } //+------------------------------------------------------------------+ //| Custom indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { DeleteAll(); return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { if(!CheckConditions()) return(0); bool restart=false; if(CheckNewBar()) restart=true; if(CheckNewOrder()) restart=true; if(CheckNewAccount()) restart=true; if(restart) CalculateHistoryBars(); CalculateLastBar(); if(Show_Info) ShowStatistics(); AlertMonitoring(); return(0); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckConditions() { if(!OrderSelect(0,SELECT_BY_POS,MODE_HISTORY)) { return(false); } if(Period()>PERIOD_D1) { Alert("Period must be D1 or lower."); return(false); } return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CalculateHistoryBars() { PrepareData(); if(Type[0]<6 && !Only_Trading) { Alert("Trading history is not fully loaded."); return; } int handle=PrepareFile(); ResultBalance=0; ResultProfit=0; PeakProfit=0; PeakEquity=0; MaxDrawdown=0; RelDrawdown=0; start_time=0; finish_time=0; int bar_seconds=PeriodSeconds(PERIOD_CURRENT); int start_from=0; for(int i=OpenBar[0]; i>=DrawEndBar; i--) { ProfitLoss=0; SumMargin=0; for(int j=start_from; ji) start_from++; if(CloseBar[j]==i && ClosePrice[j]!=0) { double result=Swap[j]+Commission[j]+Profit[j]; ResultProfit+=result; ResultBalance+=result; if(CloseTime[j]>finish_time) finish_time=CloseTime[j]; } else if(OpenBar[j]>=i && CloseBar[j]<=i) { if(Type[j]>5) { ResultBalance+=Profit[j]; if(i>DrawBeginBar) continue; if(!Show_Verticals) continue; string text=StringConcatenate(Instrument[j],": ",DoubleToStr(Profit[j],2)," ",AccountCurrency()); CreateLine("Balance "+TimeToStr(OpenTime_Ticket[j][0]),OBJ_VLINE,1,OrangeRed,STYLE_DOT,false,text,Time[i],0); continue; } if(i>DrawBeginBar) continue; if(!CheckSymbol(j)) continue; if(start_time==0) start_time=MathMax(OpenTime_Ticket[j][0],Time[i]); int bar=iBarShift(Instrument[j],0,Time[i]); int day_bar=TimeDayOfWeek(iTime(Instrument[j],0,bar)); int day_next_bar=TimeDayOfWeek(iTime(Instrument[j],0,bar+1)); if(day_bar!=day_next_bar && OpenBar[j]!=bar) { int mode=(int)MarketInfo(Instrument[j],MODE_PROFITCALCMODE); if(mode==0) { if(TimeDayOfWeek(iTime(Instrument[j],0,bar))==4) CumSwap[j]+=3*DaySwap[j]; else CumSwap[j]+=DaySwap[j]; } else { if(TimeDayOfWeek(iTime(Instrument[j],0,bar))==1) CumSwap[j]+=3*DaySwap[j]; else CumSwap[j]+=DaySwap[j]; } } if(Type[j]==OP_BUY) { LotValue=ContractValue(Instrument[j],Time[i],Period()); ProfitLoss+=Commission[j]+CumSwap[j]+(iClose(Instrument[j],0,bar)-OpenPrice[j])*Lots[j]*LotValue; SumMargin+=Lots[j]*MarketInfo(Instrument[j],MODE_MARGINREQUIRED); } if(Type[j]==OP_SELL) { LotValue=ContractValue(Instrument[j],Time[i],Period()); Spread=MarketInfo(Instrument[j],MODE_POINT)*MarketInfo(Instrument[j],MODE_SPREAD); ProfitLoss+=Commission[j]+CumSwap[j]+(OpenPrice[j]-iClose(Instrument[j],0,bar)-Spread)*Lots[j]*LotValue; SumMargin+=Lots[j]*MarketInfo(Instrument[j],MODE_MARGINREQUIRED); } } } if(i>DrawBeginBar) continue; if(Only_Trading) {Equity[i]=NormalizeDouble(ResultProfit+ProfitLoss,2);} else {Equity[i]=NormalizeDouble(ResultBalance+ProfitLoss,2);} if(Show_Balance) {Balance[i]=NormalizeDouble(Only_Trading?ResultProfit:ResultBalance,2);} if(Show_Margin) {Margin[i]=NormalizeDouble(SumMargin,2);} if(Show_Free) {Free[i]=NormalizeDouble(ResultBalance+ProfitLoss-SumMargin,2);} if(Show_Zero) {Zero[i]=0;} if(Show_Info) {Drawdown();} if(ProfitLoss!=0) finish_time=Time[i]+PeriodSeconds(PERIOD_CURRENT); WriteData(handle,i); } Profitability(); if(File_Write && handle>0) FileClose(handle); ArrayResize(OpenTime_Ticket,OpenTotal); if(OpenTotal>0) for(int i=0; i0) return; if(OpenTotal>0) for(int i=0; i0) for(int i=0; i0) for(int i=0; i0) CreateLabel("Missing symbols:",missing_symbols,100); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void AlertMonitoring() { if(alert_upper_active) if(Equity[0]!=EMPTY_VALUE) if(Equity[0]>=Equity_Max_Alert) { string message=StringConcatenate("Account #",AccountNumber()," equity alert: ",Equity[0]," ",AccountCurrency()); Alert(message); if(Push_Alerts) SendNotification(message); alert_upper_active=false; } if(alert_lower_active) if(Equity[0]!=EMPTY_VALUE) if(Equity[0]<=Equity_Min_Alert) { string message=StringConcatenate("Account #",AccountNumber()," equity alert: ",Equity[0]," ",AccountCurrency()); Alert(message); if(Push_Alerts) SendNotification(message); alert_lower_active=false; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Profitability() { int Count=OrdersHistoryTotal(); datetime CloseTime_Ticket[][2]; ArrayResize(CloseTime_Ticket,Count); for(int i=0; i5) { if(BalanceValue!=0) GrowthRatio*=(1+IntervalProfit/BalanceValue); BalanceValue+=IntervalProfit; IntervalProfit=0; BalanceValue+=OrderProfit(); } if(OrderType()<=1) if(OrderCloseTime()>=Draw_Begin && OrderCloseTime()<=Draw_End) { double result=OrderProfit()+OrderSwap()+OrderCommission(); IntervalProfit+=result; if(result>0) SumProfit+=result; else SumLoss+=result; } } if(IntervalProfit!=0) if(BalanceValue!=0) GrowthRatio*=(1+IntervalProfit/BalanceValue); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void PrepareData() { HistoryTotal=OrdersHistoryTotal(); OpenTotal=OrdersTotal(); Total=HistoryTotal+OpenTotal; ArrayResize(OpenTime_Ticket,Total); for(int i=0; i5) Instrument[n]=OrderComment(); else Instrument[n]=OrderSymbol(); Lots[n]=OrderLots(); OpenPrice[n]=OrderOpenPrice(); if(OrderCloseTime()!=0) { CloseTime[n]=OrderCloseTime(); CloseBar[n]=iBarShift(NULL,0,OrderCloseTime()); ClosePrice[n]=OrderClosePrice(); } else { CloseTime[n]=0; CloseBar[n]=0; ClosePrice[n]=0; } Commission[n]=OrderCommission(); Swap[n]=OrderSwap(); Profit[n]=OrderProfit(); CumSwap[n]=0; int swapdays=0; for(int bar=OpenBar[n]-1; bar>=CloseBar[n]; bar--) { if(TimeDayOfWeek(iTime(NULL,0,bar))!=TimeDayOfWeek(iTime(NULL,0,bar+1))) { int mode=(int)MarketInfo(Instrument[n],MODE_PROFITCALCMODE); if(mode==0) { if(TimeDayOfWeek(iTime(NULL,0,bar))==4) swapdays+=3; else swapdays++; } else { if(TimeDayOfWeek(iTime(NULL,0,bar))==1) swapdays+=3; else swapdays++; } } } if(swapdays>0) DaySwap[n]=Swap[n]/swapdays; else DaySwap[n]=0.0; if(Lots[n]==0) { string ticket=StringSubstr(OrderComment(),StringFind(OrderComment(),"#")+1); if(OrderSelect(StrToInteger(ticket),SELECT_BY_TICKET,MODE_HISTORY)) Lots[n]=OrderLots(); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool FilterOrder() { if(OrderType()>5) return(true); if(OrderType()>1) return(false); if(Only_Magics) if(OrderMagicNumber()Magic_To) return(false); if(Only_Comment!="") if(StringFind(OrderComment(),Only_Comment)==-1) return(false); if(Only_Symbols!="") if(StringFind(Only_Symbols,OrderSymbol())==-1) return(false); if(Only_Symbols=="") if(Only_Current) if(OrderSymbol()!=Symbol()) return(false); if(Only_Buys && OrderType()!=OP_BUY) return(false); if(Only_Sells && OrderType()!=OP_SELL) return(false); return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void Drawdown() { if(ResultProfit+ProfitLoss>=PeakProfit) { PeakProfit=ResultProfit+ProfitLoss; PeakEquity=ResultBalance+ProfitLoss; } double current_drawdown=PeakProfit-ResultProfit-ProfitLoss; if(current_drawdown>MaxDrawdown) { MaxDrawdown=current_drawdown; if(PeakEquity==0) PeakEquity=DBL_MAX; RelDrawdown=current_drawdown/PeakEquity; } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ double ContractValue(string symbol,datetime time,int period) { double value=MarketInfo(symbol,MODE_LOTSIZE); string quote=SymbolInfoString(symbol,SYMBOL_CURRENCY_PROFIT); if(quote!="USD") { string direct=FX_prefix+quote+"USD"+FX_postfix; if(MarketInfo(direct,MODE_POINT)!=0) { int shift=iBarShift(direct,period,time); double price=iClose(direct,period,shift); if(price>0) value*=price; } else { string indirect=FX_prefix+"USD"+quote+FX_postfix; int shift=iBarShift(indirect,period,time); double price=iClose(indirect,period,shift); if(price>0) value/=price; } } if(AccountCurrency()!="USD") { string direct=FX_prefix+AccountCurrency()+"USD"+FX_postfix; if(MarketInfo(direct,MODE_POINT)!=0) { int shift=iBarShift(direct,period,time); double price=iClose(direct,period,shift); if(price>0) value/=price; } else { string indirect=FX_prefix+"USD"+AccountCurrency()+FX_postfix; int shift=iBarShift(indirect,period,time); double price=iClose(indirect,period,shift); if(price>0) value*=price; } } return(value); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CreateLabel(string name,string str,int y) { string objectname=StringConcatenate(name," ",Unique); if(ObjectFind(objectname)==-1) { ObjectCreate(objectname,OBJ_LABEL,Window,0,0); ObjectSet(objectname,OBJPROP_XDISTANCE,10); ObjectSet(objectname,OBJPROP_YDISTANCE,y); ObjectSet(objectname,OBJPROP_COLOR,indicator_color1); ObjectSet(objectname,OBJPROP_CORNER,Text_Corner); ObjectSet(objectname,OBJPROP_COLOR,Text_Color); } ObjectSetText(objectname,name+str,Text_Size,Text_Font); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void CreateLine(string name,int type,int width,color clr,int style,bool ray,string str, datetime time1,double price1,datetime time2=0,double price2=0) { string objectname=StringConcatenate(name," ",Unique); if(ObjectFind(objectname)==-1) { ObjectCreate(objectname,type,Window,time1,price1,time2,price2); ObjectSet(objectname,OBJPROP_WIDTH,width); ObjectSet(objectname,OBJPROP_RAY,ray); } ObjectSetText(objectname,str); ObjectSet(objectname,OBJPROP_COLOR,clr); ObjectSet(objectname,OBJPROP_TIME1,time1); ObjectSet(objectname,OBJPROP_PRICE1,price1); ObjectSet(objectname,OBJPROP_TIME2,time2); ObjectSet(objectname,OBJPROP_PRICE2,price2); ObjectSet(objectname,OBJPROP_STYLE,style); ObjectSet(objectname,OBJPROP_SELECTABLE,false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void DeleteAll() { int objects=ObjectsTotal()-1; for(int i=objects;i>=0;i--) { string name=ObjectName(i); if(StringFind(name,Unique)!=-1) ObjectDelete(name); } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ int PrepareFile() { if(!File_Write) return(-1); string filename=StringConcatenate(AccountNumber(),"_",Period(),".csv"); int handle=FileOpen(filename,FILE_CSV|FILE_WRITE); if(handle<0) { Alert("Error #",GetLastError()," while opening data file."); return(handle); } uint bytes=FileWrite(handle,"Date","Time","Equity","Balance"); if(bytes<=0) Print("Error #",GetLastError()," while writing data file."); return(handle); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ void WriteData(int handle,int i) { if(!File_Write) return; if(handle<=0) return; string date=TimeToStr(Time[i],TIME_DATE); string time=TimeToStr(Time[i],TIME_MINUTES); uint bytes=FileWrite(handle,date,time,ResultBalance+ProfitLoss,ResultBalance); if(bytes<=0) Print("Error #",GetLastError()," while writing data file."); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckSymbol(int j) { if(MarketInfo(Instrument[j],MODE_POINT)!=0) return(true); if(StringFind(missing_symbols,Instrument[j])==-1) { missing_symbols=StringConcatenate(missing_symbols," ",Instrument[j]); Print("Missing symbols in Market Watch: "+Instrument[j]); } return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckNewAccount() { static int number=-1; if(number!=AccountNumber()) { DeleteAll(); IndicatorShortName(Unique); Window=WindowFind(Unique); IndicatorShortName(ShortName); ArrayInitialize(Balance,EMPTY_VALUE); ArrayInitialize(Equity,EMPTY_VALUE); ArrayInitialize(Margin,EMPTY_VALUE); ArrayInitialize(Free,EMPTY_VALUE); ArrayInitialize(Zero,EMPTY_VALUE); number=AccountNumber(); missing_symbols=""; return(true); } else return(false); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckNewBar() { static datetime saved_time; if(Time[0]==saved_time) return(false); saved_time=Time[0]; return(true); } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ bool CheckNewOrder() { static int orders; if(OrdersTotal()==orders) return(false); orders=OrdersTotal(); return(true); } //+------------------------------------------------------------------+