//+------------------------------------------------------------------+
//|                                                iExposurePro.mq5  |
//|                          Enhanced version of iExposure MT5       |
//|                                  Added: Profit in Points,        |
//|                                  Trade History display           |
//|                                  Individual positions/deals      |
//+------------------------------------------------------------------+
#property copyright "Enhanced iExposure Pro"
#property link      ""
#property strict

#property indicator_separate_window
#property indicator_plots 0
#property indicator_buffers 1
#property indicator_minimum 0.0
#property indicator_maximum 0.1

#define SYMBOLS_MAX 4096
//--- Individual position data indices
#define POS_TICKET      0
#define POS_TYPE        1
#define POS_VOLUME      2
#define POS_OPENPRICE   3
#define POS_CURRPRICE   4
#define POS_PROFIT      5
#define POS_SWAP        6
#define POS_POINTS      7
#define POS_SL          8
#define POS_TP          9
#define POS_FIELDS     10

//--- Individual history deal data indices
#define HST_TICKET      0
#define HST_TYPE        1
#define HST_VOLUME      2
#define HST_CLOSEPRICE  3
#define HST_PROFIT      4
#define HST_COMMISSION  5
#define HST_SWAP        6
#define HST_POINTS      7
#define HST_TIME        8
#define HST_FIELDS      9

//--- Input parameters
input color InpColor         = LightSeaGreen;   // Exposure text color
input bool  InpShowHistory   = false;            // Show trade History
input int   InpHistoryDays   = 30;               // History lookback (days)
input color InpHistoryColor  = DimGray;          // History text color
input color InpSeparatorColor= Goldenrod;        // Separator line color
input int   InpHorizSpacing  = 90;               // Horizontal column spacing (pixels)
input int   InpVertSpacing   = 16;               // Vertical row spacing (pixels)

string ExtName="Exposure Pro";

//--- Exposure column definitions (9 columns)
#define EXP_COLS 9
string ExtCols[EXP_COLS]= {"Ticket",
                            "Symbol",
                            "Type",
                            "Volume",
                            "Open Price",
                            "Current",
                            "Profit",
                            "Swap",
                            "Pts"
                           };
int    ExtShifts[EXP_COLS];
int    ExtLines=-1;
bool   ExtHeadersCreated=false;
double PosData[SYMBOLS_MAX][POS_FIELDS];
string PosSymbol[SYMBOLS_MAX];
int    PosTotal=0;

//--- History column definitions (9 columns)
#define HIST_COLS 9
string HistCols[HIST_COLS]= {"Ticket",
                              "Symbol",
                              "Type",
                              "Volume",
                              "Close Price",
                              "P&L",
                              "Comm",
                              "Swap",
                              "Pts"
                             };
int    HistShifts[HIST_COLS];
int    ExtHistLines=-1;
bool   ExtHistHeadersCreated=false;
double HistDealData[SYMBOLS_MAX][HST_FIELDS];
string HistDealSymbol[SYMBOLS_MAX];
int    HistDealTotal=0;

double ExtMapBuffer[];
long   chartid = 0;
//+------------------------------------------------------------------+
//| Recalculate column positions based on horizontal spacing input   |
//+------------------------------------------------------------------+
void RecalcShifts()
  {
   int i;
   for(i=0; i<EXP_COLS; i++)
      ExtShifts[i]=10+i*InpHorizSpacing;
   for(i=0; i<HIST_COLS; i++)
      HistShifts[i]=10+i*InpHorizSpacing;
  }
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
void OnInit()
  {
   IndicatorSetString(INDICATOR_SHORTNAME,ExtName);
   SetIndexBuffer(0,ExtMapBuffer,INDICATOR_CALCULATIONS);
   PlotIndexSetInteger(0,PLOT_DRAW_TYPE,DRAW_NONE);
   IndicatorSetInteger(INDICATOR_DIGITS,0);
   PlotIndexSetDouble(0,PLOT_EMPTY_VALUE,0.0);
   //--- Reset state so all objects are freshly created
   ExtLines=-1;
   ExtHistLines=-1;
   ExtHeadersCreated=false;
   ExtHistHeadersCreated=false;
   RecalcShifts();
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   int windex=ChartWindowFind(chartid,ExtName);
   if(windex>0)
      ObjectsDeleteAll(windex);
  }
//+------------------------------------------------------------------+
//| Create a label object if it does not exist                       |
//+------------------------------------------------------------------+
bool EnsureLabel(long chart_id, string name, int subwin, int x, int y)
  {
   if(ObjectFind(chart_id,name)>=0)
      return(true);
   if(ObjectCreate(chart_id,name,OBJ_LABEL,subwin,0,0))
     {
      ObjectSetInteger(chart_id,name,OBJPROP_XDISTANCE,x);
      ObjectSetInteger(chart_id,name,OBJPROP_YDISTANCE,y);
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+
//| Set label text, font size and color                              |
//+------------------------------------------------------------------+
void SetLabelText(string name, string txt, color clr)
  {
   ObjectSetString(chartid,name,OBJPROP_TEXT,txt);
   ObjectSetString(chartid,name,OBJPROP_FONT,"Arial");
   ObjectSetInteger(chartid,name,OBJPROP_FONTSIZE,9);
   ObjectSetInteger(chartid,name,OBJPROP_COLOR,clr);
  }
//+------------------------------------------------------------------+
//| 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[])
  {
   string name;
   int    col,windex=ChartWindowFind(chartid,ExtName);
//----
   if(windex<0)
      return(rates_total);
//---- Create all static labels (headers, separator, history title) once
   if(!ExtHeadersCreated)
     {
      //--- Exposure headers
      for(col=0; col<EXP_COLS; col++)
        {
         name="Head_"+string(col);
         if(EnsureLabel(chartid,name,windex,ExtShifts[col],InpVertSpacing))
            SetLabelText(name,ExtCols[col],InpColor);
        }
      //--- Separator label
      name="Separator_Label";
      EnsureLabel(chartid,name,windex,10,0);
      //--- History title
      name="Hist_Header";
      EnsureLabel(chartid,name,windex,10,0);
      //--- History column headers
      for(col=0; col<HIST_COLS; col++)
        {
         name="HistHead_"+string(col);
         if(EnsureLabel(chartid,name,windex,HistShifts[col],0))
            SetLabelText(name,HistCols[col],InpHistoryColor);
        }
      ExtHeadersCreated=true;
      ExtLines=0;
      ExtHistLines=0;
     }

//---- Analyse open positions
   PosTotal=0;
   ArrayInitialize(PosData,0.0);
   int total=AnalyzePositions();

//---- Update Exposure section (individual positions)
   UpdateExposure(total,windex);

//---- Analyse and update History section if enabled
   if(InpShowHistory)
     {
      HistDealTotal=0;
      ArrayInitialize(HistDealData,0.0);
      int histTotal=AnalyzeHistoryDeals();
      UpdateHistorySection(histTotal,windex,total);
     }
   else
     {
      HideHistoryObjects(windex,total);
     }

//---- to avoid minimum==maximum
   int bars=iBars(_Symbol,_Period);
   ExtMapBuffer[bars-1]=-1;

   ChartRedraw();
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| Update the Exposure section (one row per open position)          |
//+------------------------------------------------------------------+
void UpdateExposure(int total, int windex)
  {
   string name;
   int    i,col,line=0;
   string sym;

   if(total>0)
     {
      for(i=0; i<PosTotal; i++)
        {
         if(PosData[i][POS_TICKET]<=0)
            continue;
         line++;
         int y_dist=InpVertSpacing*(line+1)+1;

         //--- Create label objects for new lines
         if(line>ExtLines)
           {
            for(col=0; col<EXP_COLS; col++)
              {
               name="Line_"+string(line)+"_"+string(col);
               if(ObjectCreate(chartid,name,OBJ_LABEL,windex,0,0))
                  ObjectSetInteger(chartid,name,OBJPROP_XDISTANCE,ExtShifts[col]);
              }
            ExtLines++;
           }

         //--- Set Y position for this line
         for(col=0; col<EXP_COLS; col++)
           {
            name="Line_"+string(line)+"_"+string(col);
            ObjectSetInteger(chartid,name,OBJPROP_YDISTANCE,y_dist);
           }

         sym=PosSymbol[i];
         int digits=(int)SymbolInfoInteger(sym,SYMBOL_DIGITS);
         ulong ticket=(ulong)PosData[i][POS_TICKET];
         string typeStr=(PosData[i][POS_TYPE]==0 ? "BUY" : "SELL");

         //--- Column 0 - Ticket (last 8 digits for readability)
         name="Line_"+string(line)+"_0";
         SetLabelText(name,string(ticket),InpColor);

         //--- Column 1 - Symbol
         name="Line_"+string(line)+"_1";
         SetLabelText(name,sym,InpColor);

         //--- Column 2 - Type
         name="Line_"+string(line)+"_2";
         SetLabelText(name,typeStr,InpColor);

         //--- Column 3 - Volume
         name="Line_"+string(line)+"_3";
         SetLabelText(name,DoubleToString(PosData[i][POS_VOLUME],2),InpColor);

         //--- Column 4 - Open Price
         name="Line_"+string(line)+"_4";
         SetLabelText(name,DoubleToString(PosData[i][POS_OPENPRICE],digits),InpColor);

         //--- Column 5 - Current Price
         name="Line_"+string(line)+"_5";
         SetLabelText(name,DoubleToString(PosData[i][POS_CURRPRICE],digits),InpColor);

         //--- Column 6 - Profit
         name="Line_"+string(line)+"_6";
         double pr=PosData[i][POS_PROFIT];
         color prColor=(pr>=0 ? clrGreen : clrRed);
         SetLabelText(name,DoubleToString(pr,2),prColor);

         //--- Column 7 - Swap
         name="Line_"+string(line)+"_7";
         double sw=PosData[i][POS_SWAP];
         SetLabelText(name,DoubleToString(sw,2),InpColor);

         //--- Column 8 - Pts
         name="Line_"+string(line)+"_8";
         SetLabelText(name,DoubleToString(PosData[i][POS_POINTS],1),InpColor);
        }
     }

   //--- Remove excess lines
   if(total<ExtLines)
     {
      for(line=ExtLines; line>total; line--)
        {
         for(col=0; col<EXP_COLS; col++)
           {
            name="Line_"+string(line)+"_"+string(col);
            ObjectSetString(chartid,name,OBJPROP_TEXT," ");
           }
        }
      ExtLines=total;
     }
  }
//+------------------------------------------------------------------+
//| Update the History section (one row per DEAL_ENTRY_OUT)          |
//+------------------------------------------------------------------+
void UpdateHistorySection(int histTotal, int windex, int exposureLines)
  {
   string name;
   int    i,col,line=0;

   int histBaseLine = (exposureLines>0 ? exposureLines : 0) + 3;

   //--- Separator line
   name="Separator_Label";
   string sepText="";
   for(i=0; i<70; i++) sepText+="-";
   ObjectSetInteger(chartid,name,OBJPROP_XDISTANCE,10);
   ObjectSetInteger(chartid,name,OBJPROP_YDISTANCE,InpVertSpacing*(histBaseLine-2)+1);
   SetLabelText(name,sepText,InpSeparatorColor);

   //--- History title
   name="Hist_Header";
   ObjectSetInteger(chartid,name,OBJPROP_XDISTANCE,10);
   ObjectSetInteger(chartid,name,OBJPROP_YDISTANCE,InpVertSpacing*(histBaseLine-1)+1);
   SetLabelText(name,"===== TRADE HISTORY =====",InpHistoryColor);

   //--- History column headers
   for(col=0; col<HIST_COLS; col++)
     {
      name="HistHead_"+string(col);
      ObjectSetInteger(chartid,name,OBJPROP_XDISTANCE,HistShifts[col]);
      ObjectSetInteger(chartid,name,OBJPROP_YDISTANCE,InpVertSpacing*histBaseLine+1);
      SetLabelText(name,HistCols[col],InpHistoryColor);
     }

   //--- Draw history data lines
   if(histTotal>0)
     {
      for(i=0; i<HistDealTotal; i++)
        {
         if(HistDealData[i][HST_TICKET]<=0)
            continue;
         line++;
         int dataLine=histBaseLine+line;
         int y_dist=InpVertSpacing*(dataLine+1)+1;

         //--- Create label objects if needed
         if(line>ExtHistLines)
           {
            for(col=0; col<HIST_COLS; col++)
              {
               name="HistLine_"+string(line)+"_"+string(col);
               if(ObjectCreate(chartid,name,OBJ_LABEL,windex,0,0))
                  ObjectSetInteger(chartid,name,OBJPROP_XDISTANCE,HistShifts[col]);
              }
            ExtHistLines++;
           }

         //--- Set Y position
         for(col=0; col<HIST_COLS; col++)
           {
            name="HistLine_"+string(line)+"_"+string(col);
            ObjectSetInteger(chartid,name,OBJPROP_YDISTANCE,y_dist);
           }

         ulong ticket=(ulong)HistDealData[i][HST_TICKET];
         string typeStr=(HistDealData[i][HST_TYPE]==0 ? "BUY" : "SELL");
         string sym=HistDealSymbol[i];
         string timeStr=TimeToString((datetime)HistDealData[i][HST_TIME],TIME_SECONDS);

         //--- Column 0 - Ticket
         name="HistLine_"+string(line)+"_0";
         SetLabelText(name,string(ticket),InpHistoryColor);

         //--- Column 1 - Symbol
         name="HistLine_"+string(line)+"_1";
         SetLabelText(name,sym,InpHistoryColor);

         //--- Column 2 - Type
         name="HistLine_"+string(line)+"_2";
         SetLabelText(name,typeStr,InpHistoryColor);

         //--- Column 3 - Volume
         name="HistLine_"+string(line)+"_3";
         SetLabelText(name,DoubleToString(HistDealData[i][HST_VOLUME],2),InpHistoryColor);

         //--- Column 4 - Close Price
         int digits=(int)SymbolInfoInteger(sym,SYMBOL_DIGITS);
         name="HistLine_"+string(line)+"_4";
         SetLabelText(name,DoubleToString(HistDealData[i][HST_CLOSEPRICE],digits),InpHistoryColor);

         //--- Column 5 - P&L
         name="HistLine_"+string(line)+"_5";
         double pl=HistDealData[i][HST_PROFIT];
         color plColor=(pl>=0 ? clrGreen : clrRed);
         SetLabelText(name,DoubleToString(pl,2),plColor);

         //--- Column 6 - Commission
         name="HistLine_"+string(line)+"_6";
         SetLabelText(name,DoubleToString(HistDealData[i][HST_COMMISSION],2),InpHistoryColor);

         //--- Column 7 - Swap
         name="HistLine_"+string(line)+"_7";
         SetLabelText(name,DoubleToString(HistDealData[i][HST_SWAP],2),InpHistoryColor);

         //--- Column 8 - Pts
         name="HistLine_"+string(line)+"_8";
         SetLabelText(name,DoubleToString(HistDealData[i][HST_POINTS],1),InpHistoryColor);
        }
     }

   //--- Remove excess history lines
   if(histTotal<ExtHistLines)
     {
      for(line=ExtHistLines; line>histTotal; line--)
        {
         for(col=0; col<HIST_COLS; col++)
           {
            name="HistLine_"+string(line)+"_"+string(col);
            ObjectSetString(chartid,name,OBJPROP_TEXT," ");
           }
        }
      ExtHistLines=histTotal;
     }
  }
//+------------------------------------------------------------------+
//| Hide all history-related objects when ShowHistory is false       |
//+------------------------------------------------------------------+
void HideHistoryObjects(int windex, int exposureLines)
  {
   string name;
   int    i,col;

   name="Separator_Label";
   ObjectSetString(chartid,name,OBJPROP_TEXT,"");

   name="Hist_Header";
   ObjectSetString(chartid,name,OBJPROP_TEXT,"");

   for(col=0; col<HIST_COLS; col++)
     {
      name="HistHead_"+string(col);
      ObjectSetString(chartid,name,OBJPROP_TEXT,"");
     }

   if(ExtHistLines>0)
     {
      for(i=1; i<=ExtHistLines; i++)
        {
         for(col=0; col<HIST_COLS; col++)
           {
            name="HistLine_"+string(i)+"_"+string(col);
            ObjectSetString(chartid,name,OBJPROP_TEXT," ");
           }
        }
     }
   ExtHistLines=0;
  }
//+------------------------------------------------------------------+
//| Analyse open positions - one row per individual position         |
//+------------------------------------------------------------------+
int AnalyzePositions()
  {
   int    i,total=PositionsTotal();
   string symbol;
   double point,pts;

   for(i=0; i<total; i++)
     {
      if(!PositionGetTicket(i))
         continue;
      long pType=PositionGetInteger(POSITION_TYPE);
      if(pType!=POSITION_TYPE_BUY && pType!=POSITION_TYPE_SELL)
         continue;

      if(PosTotal>=SYMBOLS_MAX)
         break;

      int idx=PosTotal;
      symbol=PositionGetString(POSITION_SYMBOL);
      PosSymbol[idx]=symbol;

      PosData[idx][POS_TICKET]=(double)PositionGetInteger(POSITION_TICKET);
      PosData[idx][POS_TYPE]=(pType==POSITION_TYPE_BUY ? 0 : 1);
      PosData[idx][POS_VOLUME]=PositionGetDouble(POSITION_VOLUME);
      PosData[idx][POS_OPENPRICE]=PositionGetDouble(POSITION_PRICE_OPEN);
      PosData[idx][POS_PROFIT]=PositionGetDouble(POSITION_PROFIT);
      PosData[idx][POS_SWAP]=PositionGetDouble(POSITION_SWAP);
      PosData[idx][POS_SL]=PositionGetDouble(POSITION_SL);
      PosData[idx][POS_TP]=PositionGetDouble(POSITION_TP);

      //--- Current market price
      if(pType==POSITION_TYPE_BUY)
         PosData[idx][POS_CURRPRICE]=SymbolInfoDouble(symbol,SYMBOL_BID);
      else
         PosData[idx][POS_CURRPRICE]=SymbolInfoDouble(symbol,SYMBOL_ASK);

      //--- Profit in points
      point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      pts=0;
      if(point>0)
        {
         if(pType==POSITION_TYPE_BUY)
            pts=(PosData[idx][POS_CURRPRICE]-PosData[idx][POS_OPENPRICE])/point;
         else
            pts=(PosData[idx][POS_OPENPRICE]-PosData[idx][POS_CURRPRICE])/point;
        }
      PosData[idx][POS_POINTS]=pts;

      PosTotal++;
     }

   return(PosTotal);
  }
//+------------------------------------------------------------------+
//| Analyse closed deals - one row per DEAL_ENTRY_OUT deal           |
//+------------------------------------------------------------------+
int AnalyzeHistoryDeals()
  {
   datetime fromTime=TimeCurrent()-InpHistoryDays*86400;
   datetime toTime=TimeCurrent();
   int      i,index,total;
   ulong    ticket;
   string   symbol;
   double   point,pointValue;

   if(!HistorySelect(fromTime,toTime))
      return(0);

   total=HistoryDealsTotal();
   if(total<=0)
      return(0);

   for(i=0; i<total; i++)
     {
      ticket=HistoryDealGetTicket(i);
      if(ticket<=0)
         continue;

      //--- Only DEAL_ENTRY_OUT (position closing deals)
      long entry=HistoryDealGetInteger(ticket,DEAL_ENTRY);
      if(entry!=DEAL_ENTRY_OUT)
         continue;

      long dealType=HistoryDealGetInteger(ticket,DEAL_TYPE);
      if(dealType!=DEAL_TYPE_BUY && dealType!=DEAL_TYPE_SELL)
         continue;

      symbol=HistoryDealGetString(ticket,DEAL_SYMBOL);
      if(symbol=="")
         continue;

      if(HistDealTotal>=SYMBOLS_MAX)
         break;

      index=HistDealTotal;
      HistDealSymbol[index]=symbol;

      HistDealData[index][HST_TICKET]=(double)ticket;
      HistDealData[index][HST_TYPE]=(dealType==DEAL_TYPE_BUY ? 0 : 1);
      HistDealData[index][HST_VOLUME]=HistoryDealGetDouble(ticket,DEAL_VOLUME);
      HistDealData[index][HST_CLOSEPRICE]=HistoryDealGetDouble(ticket,DEAL_PRICE);
      HistDealData[index][HST_PROFIT]=HistoryDealGetDouble(ticket,DEAL_PROFIT);
      HistDealData[index][HST_COMMISSION]=HistoryDealGetDouble(ticket,DEAL_COMMISSION);
      HistDealData[index][HST_SWAP]=HistoryDealGetDouble(ticket,DEAL_SWAP);
      HistDealData[index][HST_TIME]=(double)HistoryDealGetInteger(ticket,DEAL_TIME);

      //--- Calculate points from P&L
      point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      double totalPL=HistDealData[index][HST_PROFIT]+
                     HistDealData[index][HST_COMMISSION]+
                     HistDealData[index][HST_SWAP];
      if(point>0 && totalPL!=0)
        {
         double vol=HistDealData[index][HST_VOLUME];
         if(vol>0)
           {
            pointValue=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE);
            if(pointValue>0)
               HistDealData[index][HST_POINTS]=totalPL/(vol*pointValue);
           }
        }

      HistDealTotal++;
     }

   return(HistDealTotal);
  }
//+------------------------------------------------------------------+
