//------------------------------------------------------------------------------------
//   TradeHistory_V3.mq4
//   by ST2050
//   Индикатор выводит информацию о последних N сделках из истории
//
//   История версий:
//   v1 - базовый функционал 
//   v2 - добавлена фильтрация по дате StartFromDate
//   v3 - добавлена фильтрация по Magic
//   v4 - добавлена индикация о перекрытии убытка
//   v4.1 - добавлена сортировка по дате закрытия
//
//------------------------------------------------------------------------------------
#property indicator_chart_window
#property copyright "ST2050 from tradelikeapro.ru forum"

//---------------------------------------------------------------------------------------------
//  Внешние ресурсы
//---------------------------------------------------------------------------------------------
#import "user32.dll"
int GetWindowRect(int hwnd, int& lpRect[]);

//---------------------------------------------------------------------------------------------
//  Внешние переменные
//---------------------------------------------------------------------------------------------
extern int     HistOrdersCount  = 8;      // Количество ордеров из истории, макс. 50
extern bool    CompensationAll = false;   // Выводить галочки компенсации убытков для всех ордеров
                                          //   false - только последнее перекрытие убытков и последующие неперекрытые
extern bool    OverInMoney = false;       // false - показывать факты перекрытия галочками, true - суммами
extern int     GUI_WindowNumber = 0;      // Номер окна, где выводить данные
                                          //   0 - график, >1 номер подвала
extern bool    GUI_Left         = false;  // true - слева, false = справа
extern int     GUI_Right_Offset = 213;    // При расположении справа - расстояние от правого края
extern int     GUI_X            = 10;
extern int     GUI_Y            = 10;
extern int     GUI_LabelsYDist  = 14;
extern string  GUI_FontName     = "Arial";
extern int     GUI_FontSize     = 9;
extern color   GUI_FontColor    = C'80,80,80';
extern color   GUI_FontNagative = Maroon;
extern datetime StartFromDate   = D'2015.01.01 00:00';
extern bool    FilterMagic      = false;  // Фильтровать по магику, false - все ордера
extern int     Magic            = 0;      // true+0=только ручная торговля
//---------------------------------------------------------------------------------------------
//  Внутренние переменные
//---------------------------------------------------------------------------------------------

string IndName = "TradeHistoty";
string LabelsPrefix = "TradeHistoty_lbl_";

int _GUI_WindowNumber = 0;
int _GUI_X;
int _GUI_Y;
int    _GUI_Window_Width = 0;                                     // ширина окна, вычисляется в CalculateWindowRect
int    _GUI_Window_Height = 0;                                    // высота окна, вычисляется в CalculateWindowRect
bool   _FlagWindowWidthChanged = false;                           // флаг, что ширина окна изменилась

double _ArrayOrdersNumsZA[250,5];
string _ArrayOrdersStrings[250,3];
int iSymbol;
int MaxOrdersCount;

//---------------------------------------------------------------------------------------------
int OnInit()
 {
  RemoveObjects(IndName);

  IndicatorShortName(IndName);
  
  // Вычисляем номер окна
  if (GUI_WindowNumber <0) _GUI_WindowNumber = 0;
  else _GUI_WindowNumber=GUI_WindowNumber;
  
  //Вычисляем размер окна
  CalculateWindowRect();
  
  if (HistOrdersCount>50) HistOrdersCount=50;
  MaxOrdersCount = HistOrdersCount*5;
  
  return(INIT_SUCCEEDED);
 }

//---------------------------------------------------------------------------------------------
int deinit()
{
   RemoveObjects(IndName);
   return(0);
}  
  
//---------------------------------------------------------------------------------------------
int start() {
 
  CreateObjectsOnPanel();
  _FlagWindowWidthChanged = false;

  return(0);
}

//---------------------------------------------------------------------------------------------
void OnChartEvent(const int id,
                  const long &lparam,
                  const double &dparam,
                  const string &sparam)
{
  if(CHARTEVENT_CHART_CHANGE)
  {
    // Вычисляем размер окна
    CalculateWindowRect();
    // Если ширина окна изменилась, пересоздаем объекты
    if (_FlagWindowWidthChanged)
    {
      CreateObjectsOnPanel();
    }
  }
}

//---------------------------------------------------------------------------------------------
void CreateObjectsOnPanel()
{
  RemoveObjects(IndName);

  int _aGUI_Y = _GUI_Y;
  string _Caption;
  string _Separator = "------------------------------------------------";
  if (OverInMoney) _Separator = _Separator + "----------";
  _Caption = "Last  "+HistOrdersCount+"  trades";
  if (FilterMagic) _Caption=_Caption+" (Magic="+Magic+") ";
  _Caption=_Caption+":";
  
  CreateLabel(LabelsPrefix+"Caption1", _Caption, _GUI_X, _aGUI_Y, GUI_FontColor);
  _aGUI_Y = _aGUI_Y + GUI_LabelsYDist;
  CreateLabel(LabelsPrefix+"Caption2", _Separator, _GUI_X, _aGUI_Y, GUI_FontColor);

  int _OrdCount = OrdersHistoryTotal();
  MqlDateTime _structOCT;
  string _sDayOfWeek, _sCloseDate, _sOrderType, _sOrderProfit, _sCompensation;
  int i, _aGUI_X;
  bool _Buy, _Sell;
  double _OrderProfit, _TotalProfit, _CompensationProfit = 0;
  color _Color;
  
  iSymbol=0;
  
   for (i=OrdersHistoryTotal(); i>=0; i--)
   {
     if (OrderSelect(i,SELECT_BY_POS,MODE_HISTORY) == true)
     {
       if (OrderSymbol()==Symbol())
       {
         if(OrderCloseTime()<StartFromDate) continue;
         if ((FilterMagic) && (OrderMagicNumber()!=Magic)) continue;
         
         _Buy = OrderType() == OP_BUY;
         _Sell = OrderType() == OP_SELL;
         if (_Buy || _Sell)
         {
         
            iSymbol = iSymbol+1;
            TimeToStruct(OrderCloseTime(),_structOCT);
            _sDayOfWeek = GetDayOfWeekNameFromInt(_structOCT.day_of_week);
            _sCloseDate = LeadZeroDate(_structOCT.day)+"."+LeadZeroDate(_structOCT.mon);
            if (_Buy) _sOrderType = "Buy";
              else _sOrderType = "Sell";
            _OrderProfit = OrderProfit();

            _ArrayOrdersNumsZA[iSymbol,0] = OrderCloseTime();
            _ArrayOrdersNumsZA[iSymbol,1] = iSymbol;
            _ArrayOrdersNumsZA[iSymbol,2] = OrderLots();
            _ArrayOrdersNumsZA[iSymbol,3] = _OrderProfit;
            
            _ArrayOrdersStrings[iSymbol,0] = _sDayOfWeek;
            _ArrayOrdersStrings[iSymbol,1] = _sCloseDate;
            _ArrayOrdersStrings[iSymbol,2] = _sOrderType;
            
             if (iSymbol>=MaxOrdersCount) break;
        }
        
        } // if (OrderSymbol()==Symbol())
      } //if (OrderSelect
   } // for i
   
   bool _SortOK=false;
   
   ArraySort(_ArrayOrdersNumsZA,iSymbol,1,MODE_ASCEND);
   while (!_SortOK) _SortOK=CorrectSortingByProfit(true);
   
   int _iCount;
   if (HistOrdersCount>iSymbol) _iCount = iSymbol;
   else _iCount=HistOrdersCount;

   for (i=iSymbol-_iCount+1; i<=iSymbol; i++)
   {
      // Calculate compensation profit
      _CompensationProfit=_CompensationProfit+_ArrayOrdersNumsZA[i,3];
      _ArrayOrdersNumsZA[i,4]=_CompensationProfit;
      if (_CompensationProfit>0) _CompensationProfit=0;
   }

   ArraySort(_ArrayOrdersNumsZA,iSymbol,1,MODE_DESCEND);
   _SortOK=false;
   while (!_SortOK) _SortOK=CorrectSortingByProfit(false);
   int _iSymbolThis;
   bool _ProfitCompensatedStop;

   if (iSymbol>HistOrdersCount) iSymbol=HistOrdersCount;

   for (i=1; i<=iSymbol; i++)
   {
     _aGUI_Y = _aGUI_Y + GUI_LabelsYDist;
     _aGUI_X = _GUI_X + GUI_FontSize*2+ GUI_FontSize*5 + GUI_FontSize*3;
     CreateLabel(LabelsPrefix+"OrderLot"+i,  _ArrayOrdersNumsZA[i,2], _aGUI_X, _aGUI_Y, GUI_FontColor);
     _aGUI_X = _GUI_X + GUI_FontSize*2+ GUI_FontSize*5 + GUI_FontSize*3 + GUI_FontSize*4+1;
     _OrderProfit = _ArrayOrdersNumsZA[i,3];
     _Color=GetColorForProfit(_OrderProfit);
     _sOrderProfit = LeadPlusPositive(_OrderProfit);
     CreateLabel(LabelsPrefix+"OrderProfit"+i, _sOrderProfit, _aGUI_X, _aGUI_Y, _Color);
     
     _iSymbolThis=_ArrayOrdersNumsZA[i,1];
     _sDayOfWeek = _ArrayOrdersStrings[_iSymbolThis ,0];
     _sCloseDate = _ArrayOrdersStrings[_iSymbolThis ,1];
     _sOrderType = _ArrayOrdersStrings[_iSymbolThis ,2];

     _aGUI_X = _GUI_X;
     CreateLabel(LabelsPrefix+"OrderCloseDW"+i, _sDayOfWeek, _aGUI_X, _aGUI_Y, GUI_FontColor);
     _aGUI_X = _GUI_X + GUI_FontSize*2;
     CreateLabel(LabelsPrefix+"OrderCloseTime"+i, _sCloseDate, _aGUI_X, _aGUI_Y, GUI_FontColor);
     _aGUI_X = _GUI_X + GUI_FontSize*2+ GUI_FontSize*5+2;
     CreateLabel(LabelsPrefix+"OrderType"+i, _sOrderType, _aGUI_X, _aGUI_Y, GUI_FontColor);
     
      _CompensationProfit=_ArrayOrdersNumsZA[i,4];
      if (OverInMoney)
        _sCompensation=LeadPlusPositive(_CompensationProfit);
      else
      {
        if (_CompensationProfit<0)_sCompensation=CharToStr(251);
        else _sCompensation=CharToStr(252);
      }
      
       if ((i>1)&&(!CompensationAll) && (!_ProfitCompensatedStop))
         _ProfitCompensatedStop=(_CompensationProfit>=0);

       if (!_ProfitCompensatedStop)
       {

        _aGUI_X = _GUI_X + GUI_FontSize*2+ GUI_FontSize*5 + GUI_FontSize*3 + GUI_FontSize*4+3 + GUI_FontSize*6-1;
        _Color=GetColorForProfit(_CompensationProfit);
        if (OverInMoney)
        CreateLabel(LabelsPrefix+"CompensationProfit"+i, _sCompensation, CORNER_LEFT_UPPER, _aGUI_X, _aGUI_Y, "Arial", GUI_FontSize, _Color);
        else
        CreateLabel(LabelsPrefix+"CompensationProfit"+i, _sCompensation, CORNER_LEFT_UPPER, _aGUI_X, _aGUI_Y, "Wingdings", GUI_FontSize+2, _Color);
      }
      
      //Total profit
      _TotalProfit = _TotalProfit + _OrderProfit;
      
   }
  
  //Итого
  _aGUI_Y = _aGUI_Y + GUI_LabelsYDist;
  CreateLabel(LabelsPrefix+"Caption3", _Separator, _GUI_X, _aGUI_Y, GUI_FontColor);
  _aGUI_Y = _aGUI_Y + GUI_LabelsYDist;
  CreateLabel(LabelsPrefix+"Caption4", "Total", _GUI_X, _aGUI_Y, GUI_FontColor);
  _aGUI_X = _GUI_X + GUI_FontSize*2+GUI_FontSize*5 + GUI_FontSize*3 + GUI_FontSize*4+1;
  _sOrderProfit = LeadPlusPositive(_TotalProfit);
  _Color=GetColorForProfit(_TotalProfit);
  CreateLabel(LabelsPrefix+"TotalProfit", _sOrderProfit, _aGUI_X, _aGUI_Y, _Color);
 
}

bool CorrectSortingByProfit(bool aAZ)
{
   if (iSymbol==0) return(true);

   int i;
   double _PrevOrderCloseTime, _PreviSymbol, _PrevOrderLots, _Prev_OrderProfit, _Prev_Compensation;
   bool _Result = true;
   bool _NeedResort;
   
   _PrevOrderCloseTime = _ArrayOrdersNumsZA[1,0];
   _PreviSymbol = _ArrayOrdersNumsZA[1,1];
   _PrevOrderLots = _ArrayOrdersNumsZA[1,2];
   _Prev_OrderProfit = _ArrayOrdersNumsZA[1,3];
   _Prev_Compensation = _ArrayOrdersNumsZA[1,4];
   
   //Alert(iSymbol);
   
   for (i=2; i<=iSymbol; i++)
   {
      if(_PrevOrderCloseTime == _ArrayOrdersNumsZA[i,0])
      {
        if (aAZ)
           _NeedResort=(_Prev_OrderProfit > _ArrayOrdersNumsZA[i,3]);
         else
           _NeedResort=(_Prev_OrderProfit < _ArrayOrdersNumsZA[i,3]);
           
         if((_NeedResort))
         {
            _Result=false;
            _ArrayOrdersNumsZA[i-1,1]=_ArrayOrdersNumsZA[i,1];
            _ArrayOrdersNumsZA[i-1,2]=_ArrayOrdersNumsZA[i,2];
            _ArrayOrdersNumsZA[i-1,3]=_ArrayOrdersNumsZA[i,3];
            _ArrayOrdersNumsZA[i-1,4]=_ArrayOrdersNumsZA[i,4];
            
            _ArrayOrdersNumsZA[i,1]=_PreviSymbol;
            _ArrayOrdersNumsZA[i,2]=_PrevOrderLots;
            _ArrayOrdersNumsZA[i,3]=_Prev_OrderProfit;
            _ArrayOrdersNumsZA[i,4]=_Prev_Compensation;
         }   
      }
      _PrevOrderCloseTime = _ArrayOrdersNumsZA[i,0];
      _PreviSymbol = _ArrayOrdersNumsZA[i,1];
      _PrevOrderLots = _ArrayOrdersNumsZA[i,2];
      _Prev_OrderProfit = _ArrayOrdersNumsZA[i,3];
      _Prev_Compensation = _ArrayOrdersNumsZA[i,4];
   }
  
  return(_Result);
}

string GetDayOfWeekNameFromInt(int aDayOfWeek)
{
  string _Result;
  switch(aDayOfWeek)
  {
    case 1: _Result="пн"; break;
    case 2: _Result="вт"; break;
    case 3: _Result="ср"; break;
    case 4: _Result="чт"; break;
    case 5: _Result="пт"; break;
    case 6: _Result="сб"; break;
    case 7: _Result="вс"; break;
    default: _Result="?"+aDayOfWeek;
  }
  return(_Result);
}


string LeadZeroDate(int aNumber)
{
  string _Result;
  if (aNumber<10) _Result="0"+aNumber;
  else _Result=aNumber;
  return(_Result);
}

string LeadPlusPositive(double aNumber)
{
  string _Result;
  if (aNumber>0) _Result="+ "+aNumber;
  if (aNumber==0) _Result="   "+aNumber;
  if (aNumber<0) _Result="-  "+(-1*aNumber);
  return(_Result);
}

color GetColorForProfit(double aProfit)
{
  color _Result;
  if (aProfit<0) _Result=GUI_FontNagative;
    else _Result=GUI_FontColor;
  return(_Result);
}

//---------------------------------------------------------------------------------------------
//
//  Работа с объектами на графике
//
//---------------------------------------------------------------------------------------------

//---------------------------------------------------------------------------------------------
//  Удаляет свои объекты с графика
//  Процедура не моя, где взял не помню
//---------------------------------------------------------------------------------------------
void RemoveObjects(string Prefix)
{
   for(int k=ObjectsTotal()-1; k>=0; k--) 
     {
      string Obj_Name=ObjectName(k);                           // Запpашиваeм имя объeкта
      string Head=StringSubstr(Obj_Name,0,StringLen(Prefix)); // Извлeкаeм первыe симолы
      if (Head==Prefix)// Найдeн объeкт, ..
         {
         ObjectDelete(Obj_Name);
         }                  
     }
}

//---------------------------------------------------------------------------------------------
//  Создает Label (упрощенный вызов)
//---------------------------------------------------------------------------------------------

void CreateLabel(string aLabelName, string aLabelText, int aXDISTANCE, int aYDISTANCE, color aColor)
{
  CreateLabel(aLabelName, aLabelText, CORNER_LEFT_UPPER, aXDISTANCE, aYDISTANCE, GUI_FontName, GUI_FontSize, aColor);
}

//---------------------------------------------------------------------------------------------
//  Создает Label
//---------------------------------------------------------------------------------------------
void CreateLabel(string aLabelName, string aLabelText, int aCorner, int aXDISTANCE, int aYDISTANCE, string aFontName, int aFontSize, color aColor)
{
   ObjectDelete(aLabelName);
   ObjectCreate(aLabelName, OBJ_LABEL, _GUI_WindowNumber, 0, 1.0);
   ObjectSet(aLabelName, OBJPROP_CORNER, aCorner);
   ObjectSet(aLabelName, OBJPROP_XDISTANCE, aXDISTANCE);
   ObjectSet(aLabelName, OBJPROP_YDISTANCE, aYDISTANCE);
   ObjectSetText(aLabelName, aLabelText, aFontSize, aFontName, aColor);
}

//---------------------------------------------------------------------------------------------
//  Вычисляет ширину и высоту окна в переменные GUI_Window_Width, GUI_Window_Height
//  Устанавливает флаг GUI_Window_FlagWidthChanged
//---------------------------------------------------------------------------------------------
void CalculateWindowRect()
{
  int _Window_rect[4];     // Массив координат окна
  int _aGUI_Window_Width;   // Ширина окна (локальная)

  // Вычисляем Rect окна и определяем ширину
  GetWindowRect(WindowHandle(Symbol(), Period()), _Window_rect);
  _aGUI_Window_Width = _Window_rect[2]-_Window_rect[0];

  // Если ширина изменилась и панель справа, то выставляем флаг изменения ширины окна
  // используется в OnChartEvent для перерисовки контролов
  if (_aGUI_Window_Width!=_GUI_Window_Width)
  {
    _GUI_Window_Width=_aGUI_Window_Width;
    _FlagWindowWidthChanged=true;
  }
    
  // Оперативный сдвиг по X
  if (GUI_Left)
  {
    _GUI_X = GUI_X;
  }
  else
  {
    _GUI_X = (_Window_rect[2]-_Window_rect[0]-48)-GUI_Right_Offset+GUI_X;
  }

  // Высота окна
  _GUI_Window_Height = _Window_rect[3]-_Window_rect[1];
  
  _GUI_Y=GUI_Y;
}
