Обсуждение статьи "Графические интерфейсы X: Элемент "Стандартный график" (build 4)" - страница 2

 
Artyom Trishkin:

Анатолий, подскажи в чём причина ошибки

2016.10.19 03:09:04.993 TestTable (EURUSD,H1)   invalid pointer access in 'Scrolls.mqh' (698,10)

До этого обновления всё работало прекрасно. Сейчас при построении таблицы CTable выскакивает эта ошибка.

Подскажи пожалуйста где не так стало - уже каждую строчку принтовал - интерфейс строится, но после где-то спотыкается, и ... ошибка.

Файл с примером в архиве.

Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.

В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже: 

//+------------------------------------------------------------------+
//| Создаёт вертикальную полосу прокрутки                            |
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- Сохранить указатель формы
   m_scrollv.WindowPointer(m_wnd);
//--- Координаты
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- Установим размеры
   m_scrollv.Id(CElement::Id());
   m_scrollv.IsDropdown(CElement::IsDropdown());
   m_scrollv.XSize(m_scrollv.ScrollWidth());
   m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
   m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- Скрыть, если сейчас не нужна
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| Создаёт горизонтальную полосу прокрутки                          |
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- Сохранить указатель формы
   m_scrollh.WindowPointer(m_wnd);
//--- Координаты
   int x=CElement::X();
   int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Установим размеры
   m_scrollh.Id(CElement::Id());
   m_scrollh.IsDropdown(CElement::IsDropdown());
   m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
   m_scrollh.YSize(m_scrollh.ScrollWidth());
   m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- Скрыть, если сейчас не нужна
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.

 
Anatoli Kazharski:

Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.

В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже:

...
//---

Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.

О! Благодарствуем!
 
Anatoli Kazharski:

Забыл внести исправление, как это было сделано ранее в классе CCanvasTable.

В классе CTable нужно заменить текущие версии методов CreateScrollV() и CreateScrollH() на представленные в листинге ниже: 

//+------------------------------------------------------------------+
//| Создаёт вертикальную полосу прокрутки                            |
//+------------------------------------------------------------------+
bool CTable::CreateScrollV(void)
  {
//--- Сохранить указатель формы
   m_scrollv.WindowPointer(m_wnd);
//--- Координаты
   int x=(m_anchor_right_window_side)? m_x-m_x_size+m_scrollv.ScrollWidth() : CElement::X2()-m_scrollv.ScrollWidth();
   int y=CElement::Y();
//--- Установим размеры
   m_scrollv.Id(CElement::Id());
   m_scrollv.IsDropdown(CElement::IsDropdown());
   m_scrollv.XSize(m_scrollv.ScrollWidth());
   m_scrollv.YSize((m_columns_total>m_visible_columns_total)? m_y_size-m_scrollv.ScrollWidth()+1 : m_y_size);
   m_scrollv.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollv.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
   if(!m_scrollv.CreateScroll(m_chart_id,m_subwin,x,y,m_rows_total,m_visible_rows_total))
      return(false);
//--- Скрыть, если сейчас не нужна
   if(m_rows_total<=m_visible_rows_total)
      m_scrollv.Hide();
//---
   return(true);
  }
//+------------------------------------------------------------------+
//| Создаёт горизонтальную полосу прокрутки                          |
//+------------------------------------------------------------------+
bool CTable::CreateScrollH(void)
  {
//--- Сохранить указатель формы
   m_scrollh.WindowPointer(m_wnd);
//--- Координаты
   int x=CElement::X();
   int y=(m_anchor_bottom_window_side)? m_y-m_area.Y_Size()+m_scrollh.ScrollWidth() : CElement::Y2()-m_scrollh.ScrollWidth();
//--- Установим размеры
   m_scrollh.Id(CElement::Id());
   m_scrollh.IsDropdown(CElement::IsDropdown());
   m_scrollh.XSize((m_rows_total>m_visible_rows_total)? m_area.XSize()-m_scrollh.ScrollWidth()+1 : m_area.XSize());
   m_scrollh.YSize(m_scrollh.ScrollWidth());
   m_scrollh.AnchorRightWindowSide(m_anchor_right_window_side);
   m_scrollh.AnchorBottomWindowSide(m_anchor_bottom_window_side);
//--- Создание полосы прокрутки
   if(!m_scrollh.CreateScroll(m_chart_id,m_subwin,x,y,m_columns_total,m_visible_columns_total))
      return(false);
//--- Скрыть, если сейчас не нужна
   if(m_columns_total<=m_visible_columns_total)
      m_scrollh.Hide();
//---
   return(true);
  }


//---

Аналогичные изменения нужно внести в классе CLabelsTable. Исправления будут в следующем обновлении.

Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:

//+------------------------------------------------------------------+
//| Создаёт таблицу                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- Сохраним указатель на форму
   m_table.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Количество видимых столбцов и рядов
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Установим свойства перед созданием
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Создадим элемент управления
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Заполним таблицу:
//    Первая ячейка пустая
   m_table.SetValue(0,0,"-");
//--- Заголовки для столбцов
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- Заголовки для рядов, способ выравнивания текста - справа
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,ALIGN_RIGHT);
        }
     }
//--- Данные и форматирование таблицы (цвет фона и цвет ячеек)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- Обновить таблицу для отображения изменений
   m_table.UpdateTable();
//--- Добавим объект в общий массив групп объектов
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

Что делать, и как быть?

 
Artyom Trishkin:

Анатолий, изменения внесены. Берём пример из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, правим таблицу в Program.mqh так, чтобы количество строк совпадало с видимым количеством строк, или количество столбцов совпадало с видимым количеством столбцов, или и то, и другое чтобы совпадало. Например, так:

... 

Компилируем, запускаем пример, щёлкаем по самой нижней строке таблицы (всё нормально), а потом ещё раз щёлкаем по ней же. На втором щелчке выскакивает ошибка:

2016.10.24 03:37:16.407 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1091,86)

Что делать, и как быть?

В классах CScrollH и CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:

//+------------------------------------------------------------------+
//| Управление скроллом                                              |
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Выйти, если нет указателя на форму
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- Выйти, если форма заблокирована другим элементом
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Выйти, если элемент скрыт
   if(!CElement::IsVisible())
     return(false);

//--- Проверка фокуса над ползунком
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
   CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет полосы прокрутки списка
   CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
   if(CScroll::ScrollState())
     {
      //--- Перемещение ползунка
      OnDragThumb(x);
      //--- Изменяет номер позиции ползунка
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }

//---

Исправление будет доступно в следующем обновлении библиотеки. 

 
Anatoli Kazharski:

В классах CScrollH и CScrollV в методах ScrollBarControl() нужно добавить дополнительную проверку на видимость элемента так, как это показано в листинге ниже:

...

Исправление будет доступно в следующем обновлении библиотеки. 

Спасибо. Внёс такие изменения: в файле Scrolls.mqh в классах CScrollH и CScrollV добавил строки:

//+------------------------------------------------------------------+
//| Управление ползунком                                             |
//+------------------------------------------------------------------+
bool CScrollV::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Выйти, если нет указателя на форму
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
//--- Если форма не заблокирована и идентификаторы совпадают
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Выйти, если элемент скрыт
   if(!CElement::IsVisible())
     return(false);

//--- Проверка фокуса над ползуком
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
   CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет ползунка
   CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
   if(CScroll::ScrollState())
     {
      //--- Перемещение ползунка
      OnDragThumb(y);
      //--- Изменяет номер позиции ползунка
      CalculateThumbPos();
      return(true);
     }
//---
   return(false);
  }
//+------------------------------------------------------------------+


//+------------------------------------------------------------------+
//| Управление скроллом                                              |
//+------------------------------------------------------------------+
bool CScrollH::ScrollBarControl(const int x,const int y,const bool mouse_state)
  {
//--- Выйти, если нет указателя на форму
   if(::CheckPointer(m_wnd)==POINTER_INVALID)
      return(false);
   if(m_wnd.IsLocked() && m_wnd.IdActivatedElement()!=CElement::Id())
      return(false);
//--- Выйти, если элемент скрыт
   if(!CElement::IsVisible())
     return(false);

//--- Проверка фокуса над ползуком
   m_thumb.MouseFocus(x>m_thumb.X() && x<m_thumb.X2() &&
                      y>m_thumb.Y() && y<m_thumb.Y2());
//--- Проверим и запомним состояние кнопки мыши
   CScroll::CheckMouseButtonState(mouse_state);
//--- Изменим цвет полосы прокрутки списка
   CScroll::ChangeObjectsColor();
//--- Если управление передано полосе прокрутки, определим положение ползунка
   if(CScroll::ScrollState())
     {
      //--- Перемещение ползунка
      OnDragThumb(x);
      //--- Изменяет номер позиции ползунка
      CalculateThumbPos();
      return(true);
     }
   return(false);
  }
//+------------------------------------------------------------------+

Компилирую и запускаю тот же проверочный файл из \MQL5\Indicators\Article07\ChartWindow02\ChartWindow02.mq5, в который внесены изменения в функцию построения таблицы в Program.mqh так, чтобы количество всех столбцов и строк совпадало с количеством видимых столбцов и строк:

//+------------------------------------------------------------------+
//| Создаёт таблицу                                                  |
//+------------------------------------------------------------------+
bool CProgram::CreateTable(void)
  {
#define COLUMNS1_TOTAL (6)
#define ROWS1_TOTAL    (15)
//--- Сохраним указатель на форму
   m_table.WindowPointer(m_window1);
//--- Координаты
   int x=m_window1.X()+TABLE1_GAP_X;
   int y=m_window1.Y()+TABLE1_GAP_Y;
//--- Количество видимых столбцов и рядов
   int visible_columns_total =6;
   int visible_rows_total    =15;
//--- Установим свойства перед созданием
   m_table.XSize(600);
   m_table.RowYSize(20);
   m_table.FixFirstRow(true);
   m_table.FixFirstColumn(true);
   m_table.LightsHover(true);
   m_table.SelectableRow(true);
   m_table.TextAlign(ALIGN_CENTER);
   m_table.HeadersColor(C'255,244,213');
   m_table.HeadersTextColor(clrBlack);
   m_table.CellColorHover(clrGold);
   m_table.TableSize(COLUMNS1_TOTAL,ROWS1_TOTAL);
   m_table.VisibleTableSize(visible_columns_total,visible_rows_total);
//--- Создадим элемент управления
   if(!m_table.CreateTable(m_chart_id,m_subwin,x,y))
      return(false);
//--- Заполним таблицу:
//    Первая ячейка пустая
   m_table.SetValue(0,0,"-");
//--- Заголовки для столбцов
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=0; r<1; r++)
         m_table.SetValue(c,r,"SYMBOL "+string(c));
     }
//--- Заголовки для рядов, способ выравнивания текста - справа
   for(int c=0; c<1; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,"PARAMETER "+string(r));
         m_table.TextAlign(c,r,ALIGN_RIGHT);
        }
     }
//--- Данные и форматирование таблицы (цвет фона и цвет ячеек)
   for(int c=1; c<COLUMNS1_TOTAL; c++)
     {
      for(int r=1; r<ROWS1_TOTAL; r++)
        {
         m_table.SetValue(c,r,string(c)+":"+string(r));
         m_table.TextColor(c,r,(c%2==0)? clrRed : clrRoyalBlue);
         m_table.CellColor(c,r,(r%2==0)? clrWhiteSmoke : clrWhite);
        }
     }
//--- Обновить таблицу для отображения изменений
   m_table.UpdateTable();
//--- Добавим объект в общий массив групп объектов
   CWndContainer::AddToElementsArray(0,m_table);
   return(true);
  }
//+------------------------------------------------------------------+

Компилирую и запускаю ChartWindow02.ex5

 Несколько раз щёлкаем по самой нижней строке таблицы и получаем вылет за пределы массива:

2016.10.25 01:39:22.899 ChartWindow02 (USDCHF,H1)       array out of range in 'Table.mqh' (1096,86)
Получается, что ничего не изменилось?
 
Artyom Trishkin:

...

Получается, что ничего не изменилось?

А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.

На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:

//+------------------------------------------------------------------+
//| Показывает пункт меню                                            |
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- Выйдем, если количество элементов списка не больше количества видимой части списка
   if(m_items_total<=m_visible_items_total)
      return;
//---
   m_area.Timeframes(OBJ_ALL_PERIODS);
   m_bg.Timeframes(OBJ_ALL_PERIODS);
   m_inc.Timeframes(OBJ_ALL_PERIODS);
   m_dec.Timeframes(OBJ_ALL_PERIODS);
   m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Обновить положение объектов
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Состояние видимости
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Скрывает пункт меню                                              |
//+------------------------------------------------------------------+
void CScroll::Hide(void)
  {
   m_area.Timeframes(OBJ_NO_PERIODS);
   m_bg.Timeframes(OBJ_NO_PERIODS);
   m_inc.Timeframes(OBJ_NO_PERIODS);
   m_dec.Timeframes(OBJ_NO_PERIODS);
   m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Состояние видимости
   CElement::IsVisible(false);
  }


 //--- 

Если не поможет, то придётся подождать следующего обновления. 

 
Anatoli Kazharski:

А у меня после внесённых изменений больше не воспроизводится. Возможно, я какие-то ещё изменения вносил, но уже не помню. Не отмечаю у себя историю мелких правок.

На всякий случай, попробуй ещё методы CScroll::Show() и CScroll::Hide() заменить вот этими версиями, если отличаются:

//+------------------------------------------------------------------+
//| Показывает пункт меню                                            |
//+------------------------------------------------------------------+
void CScroll::Show(void)
  {
//--- Выйдем, если количество элементов списка не больше количества видимой части списка
   if(m_items_total<=m_visible_items_total)
      return;
//---
   m_area.Timeframes(OBJ_ALL_PERIODS);
   m_bg.Timeframes(OBJ_ALL_PERIODS);
   m_inc.Timeframes(OBJ_ALL_PERIODS);
   m_dec.Timeframes(OBJ_ALL_PERIODS);
   m_thumb.Timeframes(OBJ_ALL_PERIODS);
//--- Обновить положение объектов
   Moving(m_wnd.X(),m_wnd.Y(),true);
//--- Состояние видимости
   CElement::IsVisible(true);
  }
//+------------------------------------------------------------------+
//| Скрывает пункт меню                                              |
//+------------------------------------------------------------------+
void CScroll::Hide(void)
  {
   m_area.Timeframes(OBJ_NO_PERIODS);
   m_bg.Timeframes(OBJ_NO_PERIODS);
   m_inc.Timeframes(OBJ_NO_PERIODS);
   m_dec.Timeframes(OBJ_NO_PERIODS);
   m_thumb.Timeframes(OBJ_NO_PERIODS);
//--- Состояние видимости
   CElement::IsVisible(false);
  }


 //--- 

Если не поможет, то придётся подождать следующего обновления. 

Благодарю, вродь помогло. Отсутствовали строки о состоянии видимости в Show():

//--- Состояние видимости
   CElement::IsVisible(true);

и в Hide():

//--- Состояние видимости
   CElement::IsVisible(false);
 
Artyom Trishkin:

Благодарю, вродь помогло. Отсутствовали строки о состоянии видимости в Show():

//--- Состояние видимости
   CElement::IsVisible(true);

и в Hide():

//--- Состояние видимости
   CElement::IsVisible(false);

Ещё одна поправка нужна. Видимость нужно устанавливать перед обновлением положения элемента. Вот так:

...
//--- Состояние видимости
   CElement::IsVisible(true);
//--- Обновить положение объектов
   Moving(m_wnd.X(),m_wnd.Y(),true);
...


 

 

Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.

Для управления состояниями элементов управления вообще не нужен таймер.

1. Записывайте текущие координаты всех элементов в массиве (карте). Вносите коррективы в координаты местоположения всех объектов формы при перемещении окна.

2. Сделайте функцию нахождения элементов по координатам (локализатор). Функция будет делать цикл по записанным текущим координатам элементов и находить тот элемент, который сейчас находится под курсором.

3. Вызывайте локализатор из события "CHARTEVENT_MOUSE_MOVE" (на событие движения курсора).

4. Возвращаемое от локализатора имя объекта передавайте в функцию интерактивности, в которой к объекту будет применятся функция ObjectSetInteger(), которая будет заставлять менять его цвет.


Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.

 
Реter Konow:

Интерактивность элементов интерфейса реализованная через таймер странное решение. - Почему она должна реализовываться через (или с помощью) таймера? - Конечно, это будет потреблять много ресурсов.

...

Как видите, в этой схеме нет таймера, а значит нет и лишнего потребления ресурсов.

Вы ошибаетесь. Достаточно подробно уже ответил в комментариях выше, зачем это было сделано именно так. 

Сейчас это не потребляет много ресурсов (теперь и в Windows 10 тоже). Вы статью читали (и комментарии тоже) ?

//--- 

P.S. Кстати, потребление ресурсов процессора в разных терминалах (MT4/MT5) и версиях ОС (Windows) сильно отличается при равных условиях. В Windows 7 терминал MetaTrader 4 показывал себя существенно лучше, чем MetaTrader 5. К сожалению не смогу сейчас привести цифры, так как уже полностью перешёл на Windows 10

Что касается оптимизации, то я ещё не все варианты исчерпал. Ещё есть что оптимизировать и есть понимание как.