//+------------------------------------------------------------------+
//| 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_Trade=false;
extern bool             Only_Current=false;
extern bool             Only_Buys=false;
extern bool             Only_Sells=false;
extern string           Only_Symbols="";
extern string           Only_Magics="";
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 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   StartBalance,CurrentBalance,MaxProfit,MaxEquity,MaxDrawdown,RelDrawdown;
double   RecoveryFactor,ProfitFactor,Profitability,NetProfit,PeriodProfit;
double   TotalProfit,TotalLoss,SumReplenishment,SumWithdrawal,SumMargin,Start,Finish;
double   ProfitLoss,Spread,LotValue;
string   Instrument[];
datetime OpenTime_Ticket[][2],CloseTime[];
int      OpenBar[],CloseBar[],Type[];
double   Lots[],OpenPrice[],ClosePrice[],Commission[],Swap[],CurSwap[],DaySwap[],Profit[];
datetime start_time,finish_time;
int      Total,HistoryTotal,OpenTotal;
string   missing_symbols;
bool     alert_upper,alert_lower;
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int init()
  {
   bool filters_off  = (Only_Magics=="") && (Only_Symbols=="") && (Only_Comment=="");
   bool flags_off    = (!Only_Current) && (!Only_Buys) && (!Only_Sells);
   bool total_off    = filters_off && flags_off;

   if(total_off) ShortName="Total";
   else
     {
      if(Only_Magics!="") ShortName=Only_Magics; else ShortName="";
      if(Only_Symbols!="") ShortName=StringConcatenate(ShortName," ",Only_Symbols);
      else if(Only_Current) ShortName=StringConcatenate(ShortName," ",Symbol());
      if(Only_Comment!="") ShortName=StringConcatenate(ShortName," ",Only_Comment);
      if(Only_Sells) Only_Buys=false;
      if(Only_Buys)  ShortName=StringConcatenate(ShortName," Buys");
      if(Only_Sells) ShortName=StringConcatenate(ShortName," Sells");
     }
   if(Only_Trade) ShortName=StringConcatenate(ShortName," Zero");

   SetIndexBuffer(0,Equity);
   SetIndexLabel(0,ShortName+" Equity");
   SetIndexStyle(0,DRAW_LINE);
   SetIndexBuffer(1,Balance);
   SetIndexLabel(1,ShortName+" Balance");
   SetIndexStyle(1,DRAW_LINE);
   SetIndexBuffer(2,Margin);
   SetIndexLabel(2,ShortName+" Margin");
   SetIndexStyle(2,DRAW_HISTOGRAM);
   SetIndexBuffer(3,Free);
   SetIndexLabel(3,ShortName+" Free");
   SetIndexStyle(3,DRAW_LINE);
   SetIndexBuffer(4,Zero);
   SetIndexLabel(4,ShortName+" Zero");
   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);

   alert_upper=true;
   alert_lower=true;

   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()
  {

   MaxProfit=0;
   MaxEquity=0;
   MaxDrawdown=0;
   RelDrawdown=0;
   TotalProfit=0;
   TotalLoss=0;

   HistoryTotal=OrdersHistoryTotal();
   OpenTotal=OrdersTotal();
   Total=HistoryTotal+OpenTotal;
   ArrayResize(OpenTime_Ticket,Total);

   for(int i=0; i<HistoryTotal; i++)
      if(OrderSelect(i,SELECT_BY_POS,MODE_HISTORY))
        {
         if(FilterOrder())
           {
            OpenTime_Ticket[i][0]=OrderOpenTime();
            OpenTime_Ticket[i][1]=OrderTicket();
           }
         else
           {
            OpenTime_Ticket[i][0]=EMPTY_VALUE;
            Total--;
           }
        }

   if(OpenTotal>0)
      for(int i=0; i<OpenTotal; i++)
         if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
           {
            if(FilterOrder())
              {
               OpenTime_Ticket[HistoryTotal+i][0]=OrderOpenTime();
               OpenTime_Ticket[HistoryTotal+i][1]=OrderTicket();
              }
            else
              {
               OpenTime_Ticket[HistoryTotal+i][0]=EMPTY_VALUE;
               Total--;
              }
           }

   ArraySort(OpenTime_Ticket);
   ArrayResize(OpenTime_Ticket,Total);
   ArrayResize(CloseTime,Total);
   ArrayResize(OpenBar,Total);
   ArrayResize(CloseBar,Total);
   ArrayResize(Type,Total);
   ArrayResize(Lots,Total);
   ArrayResize(Instrument,Total);
   ArrayResize(OpenPrice,Total);
   ArrayResize(ClosePrice,Total);
   ArrayResize(Commission,Total);
   ArrayResize(Swap,Total);
   ArrayResize(CurSwap,Total);
   ArrayResize(DaySwap,Total);
   ArrayResize(Profit,Total);

   for(int i=0; i<Total; i++)
      if(OrderSelect((int)OpenTime_Ticket[i][1],SELECT_BY_TICKET))
         ReadOrder(i);

   if(Type[0]<6 && !Only_Trade)
     { Alert("Trading history is not fully loaded."); return; }

   int handle=PrepareFile();

   int start1=0;
   StartBalance=0;
   CurrentBalance=0;

   for(int i=OpenBar[0]; i>=DrawEndBar; i--)
     {
      datetime last_close=0;
      ProfitLoss=0;
      SumMargin=0;

      for(int j=start1; j<Total; j++)
        {
         if(OpenBar[j]<i) break;
         if(CloseBar[start1]>i) start1++;

         if(CloseBar[j]==i && ClosePrice[j]!=0)
           {
            double result=Swap[j]+Commission[j]+Profit[j];
            CurrentBalance+=result;
            if(CloseTime[j]>last_close) last_close=CloseTime[j];
            if(i<=DrawBeginBar) { if(result>0) TotalProfit+=result; else TotalLoss+=result; }
           }

         else if(OpenBar[j]>=i && CloseBar[j]<=i)
           {

            if(Type[j]>5)
              {
               CurrentBalance+=Profit[j];
               if(i==OpenBar[0]) StartBalance+=Profit[j];
               if(!Only_Trade && i<=DrawBeginBar)
                 {
                  if(i!=OpenBar[0])
                    {
                     if(Profit[j]>0) SumReplenishment+=Profit[j];
                     else            SumWithdrawal+=Profit[j];
                    }
                  if(Show_Verticals)
                    {
                     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;

            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) CurSwap[j]+=3*DaySwap[j];
                  else CurSwap[j]+=DaySwap[j];
                 }
               else
                 {
                  if(TimeDayOfWeek(iTime(Instrument[j],0,bar))==1) CurSwap[j]+=3*DaySwap[j];
                  else CurSwap[j]+=DaySwap[j];
                 }
              }

            if(Type[j]==OP_BUY)
              {
               LotValue=ContractValue(Instrument[j],Time[i],Period());
               ProfitLoss+=Commission[j]+CurSwap[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]+CurSwap[j]+(OpenPrice[j]-iClose(Instrument[j],0,bar)-Spread)*Lots[j]*LotValue;
               SumMargin+=Lots[j]*MarketInfo(Instrument[j],MODE_MARGINREQUIRED);
              }

           }
        }

      if(i>DrawBeginBar) continue;

      Equity[i]=NormalizeDouble(CurrentBalance+ProfitLoss,2);
      if(Show_Balance) Balance[i]=NormalizeDouble(CurrentBalance,2);
      if(Show_Info) Drawdown(TotalProfit+TotalLoss+ProfitLoss,Equity[i]);
      if(Show_Margin) Margin[i]=NormalizeDouble(SumMargin,2);
      if(Show_Free)    Free[i]=NormalizeDouble(Equity[i]-SumMargin,2);
      if(Show_Zero)    Zero[i]=0;

      if(i==DrawBeginBar) { Start=NormalizeDouble(Equity[i],2);    start_time=Draw_Begin; }
      if(i==OpenBar[0])   { Start=NormalizeDouble(StartBalance,2); start_time=OpenTime_Ticket[0][0]; }
      if(last_close!=0)   { Finish=Equity[i]; finish_time=last_close; }
      if(ProfitLoss!=0)   { Finish=Equity[i]; finish_time=Time[i]+60*Period(); }
      bool total_zero=TotalProfit==0 && TotalLoss==0 && ProfitLoss==0;
      if(total_zero) { Finish=Start; finish_time=Time[i]+60*Period(); }

      WriteData(handle,i);

     }

   ArrayResize(OpenTime_Ticket,OpenTotal);
   if(OpenTotal>0)
      for(int i=0; i<OpenTotal; i++)
         if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
            OpenTime_Ticket[i][1]=OrderTicket();

   if(File_Write && handle>0) FileClose(handle);

   if(Equity_Min_Alert!=0)
      CreateLine("Alert-Min",OBJ_HLINE,1,Silver,STYLE_DOT,false,"Min equity alert",0,Equity_Min_Alert);
   if(Equity_Max_Alert!=0)
      CreateLine("Alert-Max",OBJ_HLINE,1,Silver,STYLE_DOT,false,"Max equity alert",0,Equity_Max_Alert);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void CalculateLastBar()
  {

   if(DrawEndBar>0) return;

   bool filters_off  = (Only_Magics=="") && (Only_Symbols=="") && (Only_Comment=="");
   bool flags_off    = (!Only_Current) && (!Only_Buys) && (!Only_Sells);
   bool total_off    = filters_off && flags_off;

   if(total_off && !Only_Trade)
     {
      ProfitLoss=AccountProfit();
      Equity[0]=AccountEquity();
      if(Show_Balance) Balance[0]=AccountBalance();
      if(Show_Margin) Margin[0]=AccountMargin();
      if(Show_Free) Free[0]=AccountFreeMargin();
      if(Show_Info) Drawdown(TotalProfit+TotalLoss+ProfitLoss,Equity[0]);
     }

   else
     {
      OpenTotal=ArrayRange(OpenTime_Ticket,0);
      if(OpenTotal>0)
         for(int i=0; i<OpenTotal; i++)
           {
            if(!OrderSelect((int)OpenTime_Ticket[i][1],SELECT_BY_TICKET)) continue;
            if(OrderCloseTime()==0) continue;
            if(!FilterOrder()) continue;
            double result=OrderProfit()+OrderSwap()+OrderCommission();
            if(result>0) TotalProfit+=result; else TotalLoss+=result;
            CurrentBalance+=result;
           }

      ProfitLoss=0;
      SumMargin=0;
      OpenTotal=OrdersTotal();

      if(OpenTotal>0)
         for(int i=0; i<OpenTotal; i++)
           {
            if(!OrderSelect(i,SELECT_BY_POS,MODE_TRADES)) continue;
            if(!FilterOrder()) continue;
            SumMargin+=OrderLots()*MarketInfo(OrderSymbol(),MODE_MARGINREQUIRED);
            ProfitLoss+=OrderProfit()+OrderSwap()+OrderCommission();
           }

      Equity[0]=NormalizeDouble(CurrentBalance+ProfitLoss,2);
      if(Show_Balance) Balance[0]=NormalizeDouble(CurrentBalance,2);
      if(Show_Info) Drawdown(TotalProfit+TotalLoss+ProfitLoss,Equity[0]);
      if(Show_Margin) Margin[0]=NormalizeDouble(SumMargin,2);
      if(Show_Free)    Free[0]=NormalizeDouble(Equity[0]-SumMargin,2);
      if(Show_Zero)    Zero[0]=0;

      ArrayResize(OpenTime_Ticket,OpenTotal);
      if(OpenTotal>0)
         for(int i=0; i<OpenTotal;i++)
            if(OrderSelect(i,SELECT_BY_POS,MODE_TRADES))
               OpenTime_Ticket[i][1]=OrderTicket();
     }

   if(ProfitLoss!=0) { finish_time=TimeCurrent(); Finish=Equity[0]; }
   CreateLine("Equity Level",OBJ_HLINE,1,SteelBlue,STYLE_DOT,false,"",0,Equity[0]);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ShowStatistics()
  {

   double periods=double(finish_time-start_time);
   if(Report_Period==day)     periods=periods/24/60/60;
   if(Report_Period==month)   periods=periods/30/24/60/60;
   if(Report_Period==year)    periods=periods/365/24/60/60;
   if(Report_Period==history) periods=1;
   if(periods==0) periods=1;

   NetProfit=Finish-Start-SumReplenishment-SumWithdrawal;
   PeriodProfit=NetProfit/periods;
   if(Start!=0) Profitability=100*PeriodProfit/Start;
   string text=StringConcatenate(": ",DoubleToStr(PeriodProfit,2)," ",AccountCurrency());
   if(!Only_Trade) text=StringConcatenate(text," (",DoubleToStr(Profitability,2),"%)");

   if(Report_Period==day)     CreateLabel("Net Profit / Day",text,20);
   if(Report_Period==month)   CreateLabel("Net Profit / Month",text,20);
   if(Report_Period==year)    CreateLabel("Net Profit / Year",text,20);
   if(Report_Period==history) CreateLabel("Total Net Profit",text,20);

   text=StringConcatenate(": ",DoubleToStr(MaxDrawdown,2)," "+AccountCurrency());
   if(!Only_Trade) text=StringConcatenate(text," (",DoubleToStr(RelDrawdown,2),"%)");
   CreateLabel("Max Drawdown",text,40);

   if(MaxDrawdown!=0) RecoveryFactor=NetProfit/MaxDrawdown;
   text=StringConcatenate(": ",DoubleToStr(RecoveryFactor,2));
   CreateLabel("Recovery Factor",text,60);

   if(TotalLoss!=0) ProfitFactor=-TotalProfit/TotalLoss;
   text=StringConcatenate(": ",DoubleToStr(ProfitFactor,2));
   CreateLabel("Profit Factor",text,80);

   if(StringLen(missing_symbols)>0)
      CreateLabel("Missing symbols:",missing_symbols,100);

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void AlertMonitoring()
  {
   if(Equity_Max_Alert!=0)
      if(Equity[0]!=EMPTY_VALUE)
         if(Equity[0]>=Equity_Max_Alert)
            if(alert_upper)
              {
               string message=StringConcatenate("Account #",AccountNumber()," equity alert: ",Equity[0]," ",AccountCurrency());
               Alert(message);
               if(Push_Alerts) SendNotification(message);
               alert_upper=false;
              }
   if(Equity_Min_Alert!=0)
      if(Equity[0]!=EMPTY_VALUE)
         if(Equity[0]<=Equity_Min_Alert)
            if(alert_lower)
              {
               string message=StringConcatenate("Account #",AccountNumber()," equity alert: ",Equity[0]," ",AccountCurrency());
               Alert(message);
               if(Push_Alerts) SendNotification(message);
               alert_lower=false;
              }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void ReadOrder(int n)
  {

   OpenBar[n]=iBarShift(NULL,0,OrderOpenTime());
   Type[n]=OrderType();
   if(OrderType()>5) 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();
   if(OrderType()>5 && Only_Trade) Profit[n]=0.0;

   CurSwap[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!="" && StringFind(Only_Magics,DoubleToStr(OrderMagicNumber(),0))==-1) return(false);
   if(Only_Symbols!="" && StringFind(Only_Symbols,OrderSymbol())==-1) return(false);
   else if(Only_Current && OrderSymbol()!=Symbol()) return(false);
   if(Only_Comment!="" && StringFind(OrderComment(),Only_Comment)==-1) return(false);
   if(Only_Buys && OrderType()!=OP_BUY) return(false);
   if(Only_Sells && OrderType()!=OP_SELL) return(false);
   return(true);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void Drawdown(double profit,double equity)
  {
   if(profit>MaxProfit)
     { MaxProfit=profit; MaxEquity=equity; }
   if(MaxDrawdown<MaxProfit-profit)
     {
      MaxDrawdown=MaxProfit-profit;
      if(MaxEquity>0)
        {
         double relative=100*MaxDrawdown/MaxEquity;
         if(RelDrawdown<relative) RelDrawdown=relative;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
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 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,CurrentBalance+ProfitLoss,CurrentBalance);
   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);
  }
//+------------------------------------------------------------------+
