Article-16233-MQL5-SQLite-T.../Article-16233-MQL5-SQLite-Trade-Statistics-Panel.mq5

1864 lines
96 KiB
MQL5

//+------------------------------------------------------------------+
//| Article-16233-MQL5-SQLite-Trade-Statistics-Panel.mq5 |
//| Copyright 2026, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property indicator_buffers 0
#property indicator_plots 0
#include "Dashboard\Dashboard.mqh"
#include "SQLiteFunc.mqh"
#define PROGRAM_NAME (MQLInfoString(MQL_PROGRAM_NAME)) // Имя программы
#define DB_NAME (PROGRAM_NAME+"_DB.sqlite") // Имя базы данных
#define DATE_FROM 0 // Дата начала истории сделок
#define DATE_TO (TimeCurrent()) // Дата окончания истории сделок
//--- Ширина ячеек таблиц
#define CELL_W_TRADES 94 // Ширина ячеек таблицы истории торговли
#define CELL_W_SYMBOLS 62 // Ширина ячеек таблицы символов, используемых в торговле
#define CELL_W_MAGICS 62 // Ширина ячеек таблицы магиков, используемых в торговле
#define CELL_H 16 // Высота ячейки таблицы
//--- Размеры итоговой таблицы статистики
#define TABLE_STAT_ROWS 9 // Количество строк итоговой таблицы статистики
#define TABLE_STAT_COLS 4 // Количество столбцов итоговой таблицы статистики
//--- Таблицы
#define TABLE_TRADES 1 // Идентификатор таблицы истории торговли
#define TABLE_SYMBOLS 2 // Идентификатор таблицы символов, используемых в торговле
#define TABLE_MAGICS 3 // Идентификатор таблицы магиков, используемых в торговле
#define TABLE_ACCOUNT 4 // Идентификатор таблицы статистики счёта
#define TABLE_STATS 5 // Идентификатор итоговой таблицы статистики выбранного символа или магика
//--- Заголовки таблиц (полный/сокращённый)
#define H_TRADES "Trades"
#define H_TRADES_S "Trades"
#define H_LONG "Long"
#define H_LONG_S "Long"
#define H_SHORT "Short"
#define H_SHORT_S "Short"
#define H_GROSS_PROFIT "Gross Profit"
#define H_GROSS_PROFIT_S "Gross Profit"
#define H_GROSS_LOSS "Gross Loss"
#define H_GROSS_LOSS_S "Gross Loss"
#define H_COMMISSIONS "Commission total"
#define H_COMMISSIONS_S "Fees"
#define H_SWAPS "Swap total"
#define H_SWAPS_S "Swaps"
#define H_PROFITS "Profit Loss"
#define H_PROFITS_S "P/L"
#define H_NET_PROFIT "Net Profit"
#define H_NET_PROFIT_S "Net Profit"
#define H_WINS "Win trades"
#define H_WINS_S "Win"
#define H_LOST "Loss trades"
#define H_LOST_S "Lost"
#define H_EXP_PAYOFF "Expected Payoff"
#define H_EXP_PAYOFF_S "Avg $"
#define H_WIN_PRC "Win percent"
#define H_WIN_PRC_S "Win %"
#define H_LOSS_PRC "Loss percent"
#define H_LOSS_PRC_S "Loss %"
#define H_AVG_PROFIT "Average Profit"
#define H_AVG_PROFIT_S "Avg Profit"
#define H_AVG_LOSS "Average Loss"
#define H_AVG_LOSS_S "Avg Loss"
#define H_PRF_FACTOR "Profit factor"
#define H_PRF_FACTOR_S "PF"
//--- Массив расположения столбцов таблиц статистики слева-направо
string ArrayDataName[18]=
{
"HEADER",
H_NET_PROFIT_S,
H_TRADES_S,
H_GROSS_PROFIT_S,
H_GROSS_LOSS_S,
H_COMMISSIONS_S,
H_SWAPS_S,
H_PROFITS_S,
H_LONG_S,
H_SHORT_S,
H_WINS_S,
H_LOST_S,
H_EXP_PAYOFF_S,
H_WIN_PRC_S,
H_LOSS_PRC_S,
H_AVG_PROFIT_S,
H_AVG_LOSS_S,
H_PRF_FACTOR_S,
};
//--- input parameters
input int InpPanelX = 20; /* Dashboard X */ // Координата X панели
input int InpPanelY = 20; /* Dashboard Y */ // Координата Y панели
input int InpUniqID = 0; /* Unique ID */ // Уникальный идентификатор для объекта-панели
//--- global variables
int DBHandle; // Хэндл базы данных
int LPanelTable; // Активная панель в левом поле
int RPanelTable; // Активная панель в правом поле
long ArrayMagics[]; // Массив магиков
string ArraySymbols[]; // Массив символов
STrade ArrayTrades[]; // Массив трейдов
SSymbolStats ArraySymbolStats[]; // Массив статистики по символам
SMagicStats ArrayMagicStats[]; // Массив статистики по магикам
SAccountStats ArrayAccountStats[]; // Массив статистики по счёту
CDashboard *dashboard=NULL; // Указатель на экземпляр панели
//+------------------------------------------------------------------+
//| Custom indicator initialization function |
//+------------------------------------------------------------------+
int OnInit()
{
//--- Проверим, что на счете используется хеджинг для учета открытых позиций
if((ENUM_ACCOUNT_MARGIN_MODE)AccountInfoInteger(ACCOUNT_MARGIN_MODE)!=ACCOUNT_MARGIN_MODE_RETAIL_HEDGING)
{
//--- Если счёт неттинговый, то мы не можем преобразовать сделки в трейды простым способом через транзакции, поэтому завершаем работу
Print("For a Netting account, there is no way to convert deals into trades in a simple way.");
return INIT_FAILED;
}
//--- Указываем путь расположения и создаём БД (\MQL5\Files\StatisticsBy\Database\)
string path=PROGRAM_NAME+"\\Database\\";
DBHandle=DatabaseOpen(path+DB_NAME,DATABASE_OPEN_CREATE);
if(DBHandle==INVALID_HANDLE)
{
Print("DatabaseOpen() failed. Error ", GetLastError());
return(INIT_FAILED);
}
PrintFormat("Database \"%s\" successfully created at MQL5\\Files\\%s", DB_NAME, path);
//--- Создаём панель-окно программы
dashboard = new CDashboard(InpUniqID, InpPanelX, InpPanelY, 601, 300);
if(dashboard==NULL)
{
Print("Error. Failed to create dashboard object");
return INIT_FAILED;
}
//--- Отображаем панель с текстом названия программы в заголовке окна
dashboard.SetFontParams("Calibri",8);
dashboard.SetName("Main");
dashboard.View(PROGRAM_NAME);
//--- Рисуем рабочее пространство
//--- Кнопка для выбора символов
CDashboard *panel1=dashboard.InsertNewPanel(dashboard.ID()+1, 3, 20, 49, 21);
if(panel1!=NULL)
{
panel1.SetName("SymbolButton");
panel1.SetButtonCloseOff();
panel1.SetButtonMinimizeOff();
panel1.SetButtonPinOff();
panel1.View("");
panel1.Collapse();
panel1.SetHeaderNewParams("Symbol",clrLightGray,clrBlack,USHORT_MAX,5,-1);
}
//--- Кнопка для выбора магиков
CDashboard *panel2=dashboard.InsertNewPanel(dashboard.ID()+2, 54, 20, 48, 21);
if(panel2!=NULL)
{
panel2.SetName("MagicButton");
panel2.SetButtonCloseOff();
panel2.SetButtonMinimizeOff();
panel2.SetButtonPinOff();
panel2.View("");
panel2.Collapse();
panel2.SetHeaderNewParams("Magic",clrLightGray,clrBlack,USHORT_MAX,8,-1);
}
//--- Кнопка для создания списка трейдов
CDashboard *panel3=dashboard.InsertNewPanel(dashboard.ID()+3, 105, 20, 106, 21);
if(panel3!=NULL)
{
panel3.SetName("TradesButton");
panel3.SetButtonCloseOff();
panel3.SetButtonMinimizeOff();
panel3.SetButtonPinOff();
panel3.View("");
panel3.Collapse();
panel3.SetHeaderNewParams("Get trade history",clrLightGray,clrBlack,USHORT_MAX,10,-1);
}
//--- Панель слева для вывода таблицы символов/магиков
CDashboard *panel4=dashboard.InsertNewPanel(dashboard.ID()+4, 2, 38, 101, dashboard.Height()-38-2);
if(panel4!=NULL)
{
panel4.SetName("FieldL");
panel4.SetButtonCloseOff();
panel4.SetButtonMinimizeOff();
panel4.SetButtonPinOff();
panel4.View("");
panel4.SetPanelHeaderOff(true);
panel4.SetFontParams("Calibri",8);
}
//--- Панель справа для вывода заголовков статистики по списку трейдов и выбранному символу/магику
CDashboard *panel5=dashboard.InsertNewPanel(dashboard.ID()+5, 104, 38, dashboard.Width()-104-2, 20);
if(panel5!=NULL)
{
panel5.SetName("FieldH");
panel5.SetButtonCloseOff();
panel5.SetButtonMinimizeOff();
panel5.SetButtonPinOff();
panel5.View("");
panel5.SetPanelHeaderOff(true);
panel5.SetFontParams("Calibri",8,FW_EXTRABOLD);
}
//--- Панель справа для вывода статистики по списку трейдов и выбранному символу/магику
CDashboard *panel6=dashboard.InsertNewPanel(dashboard.ID()+6, 104, 38+20, dashboard.Width()-104-2, dashboard.Height()-38-20-2);
if(panel5!=NULL)
{
panel6.SetName("FieldR");
panel6.SetButtonCloseOff();
panel6.SetButtonMinimizeOff();
panel6.SetButtonPinOff();
panel6.View("");
panel6.SetPanelHeaderOff(true);
panel6.SetFontParams("Calibri",8);
}
//--- Все таблицы на левой и правой панелях изначально не активны
LPanelTable=WRONG_VALUE;
RPanelTable=WRONG_VALUE;
//--- Всё успешно
return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
//| Custom indicator deinitialization function |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
{
//--- Закрываем базу данных
DatabaseClose(DBHandle);
if(GetLastError()==ERR_DATABASE_INVALID_HANDLE)
Print("Error. An invalid database handle was passed to the DatabaseClose() function");
//--- Если объект панели существует - удаляем
if(dashboard!=NULL)
{
delete dashboard;
ChartRedraw();
}
}
//+------------------------------------------------------------------+
//| 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[])
{
//---
//--- return value of prev_calculated for next call
return(rates_total);
}
//+------------------------------------------------------------------+
//| ChartEvent function |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,
const long &lparam,
const double &dparam,
const string &sparam)
{
//--- Идентификатор активной панели
int table_id=WRONG_VALUE;
//--- Вызываем обработчик событий панели, которая в свою очередь отправляет сюда свои события
dashboard.OnChartEvent(id,lparam,dparam,sparam);
//--- Если получили пользовательское событие от панели-окна программы
if(id>CHARTEVENT_CUSTOM)
{
//--- Нажата кнопка закрытия на панели
if(id==1001)
{
//--- Здесь может быть обработка щелчка по кнопке закрытия
}
//--- Нажатия кнопок работы с БД - идентификатор всегда 1002, а уточнение - по значению в lparam
if(id==1002)
{
//--- получение истории сделок с сервера и трейдов из БД (нажата кнопка Get trade history)
if(lparam==3)
{
//--- Если история сделок не получена - уходим
if(!GetHistoryDeals(DATE_FROM, DATE_TO))
return;
//--- Если в истории нет сделок - сообщаем об этом и уходим
int deals_total=HistoryDealsTotal();
if(deals_total==0)
{
Print("No deals in history");
return;
}
//--- создадим таблицу сделок (DEALS) в базе данных
if(!CreateTableDeals(DBHandle))
return;
//--- внесем в созданную таблицу сделки
if(!InsertDeals(DBHandle))
return;
//--- Создадим таблицу трейдов (TRADES) на основе таблицы DEALS
if(!CreateTableTrades(DBHandle))
return;
//--- Заполним через SQL-запрос таблицу TRADES на основе данных из таблицы DEALS
if(!FillTRADEStableBasedOnDEALStable(DBHandle))
return;
//--- Запросим из БД список всех трейдов
if(!FillsListTradesFromDB(DBHandle, DB_NAME, ArrayTrades))
return;
//--- Выведем на панель количество сделок и количество трейдов в истории
dashboard.DrawText(" ",2,2,clrNONE,0,0); // стираем ранее написанное
dashboard.DrawText("Total deals in history: "+(string)deals_total+", trades: "+(string)ArrayTrades.Size(),216,3);
//--- Получаем указатель на панель заголовков
CDashboard *panel_h=dashboard.GetPanel("FieldH");
if(panel_h==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода заголовка таблицы трейдов
CTableData *table_h=NULL;
if(!panel_h.TableIsExist(TABLE_TRADES) && !panel_h.CreateNewTable(TABLE_TRADES))
return;
//--- Получаем указатель на объект-таблицу заголовков трейдов
table_h=panel_h.GetTable(TABLE_TRADES);
if(table_h==NULL)
return;
//--- Очищаем панель заголовка таблицы и выводим на неё таблицу заголовков
panel_h.Clear();
panel_h.DrawGrid(TABLE_TRADES,2,2,1,11,CELL_H,CELL_W_TRADES,C'200,200,200',false);
//--- Заполняем таблицу заголовков трейдов
FillsHeaderTradeTable(panel_h,table_h);
//--- Получаем указатель на правую панель
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода трейдов
if(!panel_r.TableIsExist(TABLE_TRADES) && !panel_r.CreateNewTable(TABLE_TRADES))
return;
//--- Получаем указатель на объект-таблицу трейдов
CTableData *table_r=panel_r.GetTable(TABLE_TRADES);
if(table_r==NULL)
return;
//--- Очищаем панель и выводим на неё таблицу трейдов
panel_r.Clear();
panel_r.DrawGrid(TABLE_TRADES,2,2,ArrayTrades.Size(),11,CELL_H,CELL_W_TRADES,C'220,220,220');
//--- Заполняем таблицу данными трейдов и указываем, что справа активна таблица TABLE_TRADES
FillsTradeTable(panel_r,table_r);
RPanelTable=TABLE_TRADES;
}
//--- Если нажата кнопка отображения символов
if(lparam==1)
{
//--- запросим из БД список всех символов, на которых осуществлялась торговля, и заполним массив символов
if(!FillsListSymbolsFromDB(DBHandle, DB_NAME, ArraySymbols))
return;
//--- Увеличим массив символов на 1 для записи в него пункта "Все символы" (ALL)
int size=(int)ArraySymbols.Size();
if(ArrayResize(ArraySymbols, size+1)==size+1)
ArraySymbols[size]="ALL";
//--- Получаем указатель на левую панель
CDashboard *panel=dashboard.GetPanel("FieldL");
if(panel==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода списка символов
CTableData *table=NULL;
if(!panel.TableIsExist(TABLE_SYMBOLS) && !panel.CreateNewTable(TABLE_SYMBOLS))
return;
//--- Получаем указатель на объект-таблицу
table=panel.GetTable(TABLE_SYMBOLS);
if(table==NULL)
return;
//--- Очищаем панель и рисуем на ней таблицу символов
panel.Clear();
panel.DrawGrid(TABLE_SYMBOLS,2,2,ArraySymbols.Size(),1,CELL_H,panel.Width()-5,C'220,220,220');
//--- Заполняем таблицу наименованиями символов и указываем, что на левой панели активна таблица TABLE_SYMBOLS
FillsSymbolTable(panel,table);
LPanelTable=TABLE_SYMBOLS;
//--- получим торговую статистику в разрезе символов
if(!GetTradingStatsBySymbols(DBHandle, DB_NAME, ArraySymbolStats))
return;
//--- Выведем на панель количество символов, использованных в торговле
dashboard.DrawText(" ",2,2,clrNONE,0,0); // Стираем всё содержимое панели
dashboard.DrawText("Total number of symbols used in trade: "+(string)ArraySymbols.Size(),216,3);
//--- Получаем указатель на панель заголовков
CDashboard *panel_h=dashboard.GetPanel("FieldH");
if(panel_h==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода заголовка таблицы статистики символов
CTableData *table_h=NULL;
if(!panel_h.TableIsExist(TABLE_SYMBOLS) && !panel_h.CreateNewTable(TABLE_SYMBOLS))
return;
//--- Получаем указатель на объект-таблицу заголовков статистики символов
table_h=panel_h.GetTable(TABLE_SYMBOLS);
if(table_h==NULL)
return;
//--- Очищаем панель заголовка таблицы и выводим на неё таблицу
RPanelTable=TABLE_SYMBOLS;
panel_h.Clear();
panel_h.DrawGrid(TABLE_SYMBOLS,2,2,1,ArrayDataName.Size(),CELL_H,CELL_W_SYMBOLS,C'200,200,200',false);
//--- Заполняем таблицу заголовка статистики символов
FillsHeaderTradingStatsTable(panel_h,table_h);
//--- Получаем указатель на правую панель
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода статистики символов
if(!panel_r.TableIsExist(TABLE_SYMBOLS) && !panel_r.CreateNewTable(TABLE_SYMBOLS))
return;
//--- Получаем указатель на объект-таблицу статистики символов
CTableData *table_r=panel_r.GetTable(TABLE_SYMBOLS);
if(table_r==NULL)
return;
//--- Очищаем панель и выводим на неё таблицу статистики символов
panel_r.Clear();
panel_r.DrawGrid(TABLE_SYMBOLS,2,2,ArraySymbolStats.Size(),ArrayDataName.Size(),CELL_H,CELL_W_SYMBOLS,C'220,220,220');
//--- Заполняем таблицу данными статистики символов и указываем, что справа активна таблица TABLE_SYMBOLS
FillsTradingStatsBySymbolsTable(panel_r,table_r);
RPanelTable=TABLE_SYMBOLS;
}
//--- Если нажата кнопка отображения магиков
if(lparam==2)
{
//--- Запросим из БД список всех магиков, на которых осуществлялась торговля, и заполним массив магиков
if(!FillsListMagicsFromDB(DBHandle, DB_NAME, ArrayMagics))
return;
//--- Увеличим массив магиков на 1 для записи в него пункта "Все магики" (значение LONG_MAX указывает на это)
int size=(int)ArrayMagics.Size();
if(ArrayResize(ArrayMagics, size+1)==size+1)
ArrayMagics[size]=LONG_MAX;
//--- Получаем указатель на левую панель
CDashboard *panel=dashboard.GetPanel("FieldL");
if(panel==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода магиков
CTableData *table=NULL;
if(!panel.TableIsExist(TABLE_MAGICS) && !panel.CreateNewTable(TABLE_MAGICS))
return;
//--- Получаем указатель на объект-таблицу
table=panel.GetTable(TABLE_MAGICS);
if(table==NULL)
return;
//--- Очищаем панель и рисуем на ней таблицу магиков
panel.Clear();
panel.DrawGrid(TABLE_MAGICS,2,2,ArrayMagics.Size(),1,CELL_H,panel.Width()-5,C'220,220,220');
//--- Заполняем таблицу значениями магиков и указываем, что на левой панели активна таблица TABLE_MAGICS
FillsMagicTable(panel,table);
LPanelTable=TABLE_MAGICS;
//--- Получаем торговую статистику в разрезе магиков
if(!GetTradingStatsByMagics(DBHandle, DB_NAME, ArrayMagicStats))
return;
//--- Выводим на панель количество магиков, использованных в торговле
dashboard.DrawText(" ",2,2,clrNONE,0,0);
dashboard.DrawText("Total number of magics used in trade: "+(string)ArrayMagics.Size(),216,3);
//--- Получаем указатель на панель заголовков
CDashboard *panel_h=dashboard.GetPanel("FieldH");
if(panel_h==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода заголовка таблицы статистики магиков
CTableData *table_h=NULL;
if(!panel_h.TableIsExist(TABLE_MAGICS) && !panel_h.CreateNewTable(TABLE_MAGICS))
return;
//--- Получаем указатель на объект-таблицу заголовков статистики магиков
table_h=panel_h.GetTable(TABLE_MAGICS);
if(table_h==NULL)
return;
//--- Очищаем панель заголовка таблицы и выводим на неё таблицу
panel_h.Clear();
panel_h.DrawGrid(TABLE_MAGICS,2,2,1,ArrayDataName.Size(),CELL_H,CELL_W_MAGICS,C'200,200,200',false);
//--- Заполняем таблицу заголовка статистики символов
FillsHeaderTradingStatsTable(panel_h,table_h);
//--- Получаем указатель на правую панель
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r==NULL)
return;
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода статистики магиков
if(!panel_r.TableIsExist(TABLE_MAGICS) && !panel_r.CreateNewTable(TABLE_MAGICS))
return;
//--- Получаем указатель на объект-таблицу статистики магиков
CTableData *table_r=panel_r.GetTable(TABLE_MAGICS);
if(table_r==NULL)
return;
//--- Очищаем панель и выводим на неё таблицу статистики магиков
panel_r.Clear();
panel_r.DrawGrid(TABLE_MAGICS,2,2,ArrayMagicStats.Size(),ArrayDataName.Size(),CELL_H,CELL_W_MAGICS,C'220,220,220');
//--- Заполняем таблицу данными статистики магиков и указываем, что активна таблица TABLE_MAGICS
FillsTradingStatsByMagicsTable(panel_r,table_r);
RPanelTable=TABLE_MAGICS;
}
}
}
//--- Если получили событие прокрутки колёсика мышки
if(id==CHARTEVENT_MOUSE_WHEEL)
{
static int index_l_p=WRONG_VALUE; // Прошлый индекс строки под курсором в таблице на левой панели
static int index_r_p=WRONG_VALUE; // Прошлый индекс строки под курсором в таблице на правой панели
//--- разберем состояние кнопок и колесика мышки для этого события
int flg_keys = (int)(lparam>>32); // флаг состояний клавиш Ctrl, Shift и кнопок мышки
int x_cursor = (int)(short)lparam; // X-координата, в которой произошло событие колесика мышки
int y_cursor = (int)(short)(lparam>>16); // Y-координата, в которой произошло событие колесика мышки
int delta = (int)dparam; // суммарное значение прокрутки колесика, срабатывает при достижении +120 или -120
//--- Получаем указатель на левую панель и вызываем для неё обработчик прокрутки колёсика мышки
int index_l=WRONG_VALUE;
CDashboard *panel_l=dashboard.GetPanel("FieldL");
if(panel_l!=NULL)
index_l=TableMouseWhellHandlerL(x_cursor,y_cursor,((flg_keys&0x0004)!=0),delta,panel_l,LPanelTable);
//--- Получаем указатель на правую панель и вызываем для неё обработчик прокрутки колёсика мышки
int index_r=WRONG_VALUE;
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r!=NULL)
index_r=TableMouseWhellHandlerR(x_cursor,y_cursor,((flg_keys&0x0004)!=0),delta,panel_r,RPanelTable);
//--- При необходимости можно обработать строку таблицы, над которой находится курсор.
//--- Номер строки записан в index_l для левой панели и в index_r - для правой
//--- Обновляем график после всех изменений, произошедших в обработчиках прокрутки колёсика мышки
if(index_l_p!=index_l)
{
index_l_p=index_l;
ChartRedraw();
}
if(index_r_p!=index_r)
{
index_r_p=index_r;
ChartRedraw();
}
}
//--- Если получили событие перемещения мышки
if(id==CHARTEVENT_MOUSE_MOVE)
{
static int index_l_p=WRONG_VALUE; // Прошлый индекс строки под курсором в таблице на левой панели
static int index_r_p=WRONG_VALUE; // Прошлый индекс строки под курсором в таблице на правой панели
int x_cursor = (int)lparam; // X-координата курсора мышки
int y_cursor = (int)dparam; // Y-координата курсора мышки
//--- Получаем указатель на левую панель и вызываем для неё обработчик перемещения мышки
int index_l=WRONG_VALUE;
CDashboard *panel_l=dashboard.GetPanel("FieldL");
if(panel_l!=NULL)
index_l=TableMouseMoveHandlerL(x_cursor,y_cursor,panel_l,LPanelTable);
//--- Получаем указатель на правую панель и вызываем для неё обработчик перемещения мышки
int index_r=WRONG_VALUE;
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r!=NULL)
index_r=TableMouseMoveHandlerR(x_cursor,y_cursor,panel_r,RPanelTable);
//--- При необходимости можно обработать строку таблицы, над которой находится курсор.
//--- Номер строки записан в index_l для левой панели и в index_r - для правой
//--- Обновляем график после всех изменений, произошедших в обработчиках перемещения мышки
if(index_l_p!=index_l)
{
index_l_p=index_l;
ChartRedraw();
}
if(index_r_p!=index_r)
{
index_r_p=index_r;
ChartRedraw();
}
}
//--- Если получили событие щелчка мышки
if(id==CHARTEVENT_CLICK)
{
int x_cursor = (int)lparam; // X-координата курсора мышки
int y_cursor = (int)dparam; // Y-координата курсора мышки
//--- Получаем указатель на левую панель и вызываем обработчик щелчка мышки
int index_l=WRONG_VALUE;
CDashboard *panel_l=dashboard.GetPanel("FieldL");
if(panel_l!=NULL)
index_l=TableMouseClickHandler(x_cursor,y_cursor,panel_l,LPanelTable);
//--- Получаем указатель на правую панель и вызываем обработчик щелчка мышки
int index_r=WRONG_VALUE;
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_r!=NULL)
index_r=TableMouseClickHandler(x_cursor,y_cursor,panel_r,RPanelTable);
//--- Обработаем строку таблицы, по которой был щелчок
//--- Если в левой панели был щелчок по символу из списка
if(LPanelTable==TABLE_SYMBOLS && index_l>WRONG_VALUE)
{
//--- Получим таблицу символов с левой панели
CTableData *table=panel_l.GetTable(TABLE_SYMBOLS);
if(table==NULL)
return;
//--- Получим единственную ячейку таблицы с номером строки index_l
CTableCell *cell=table.GetCell(index_l,0);
if(cell==NULL)
return;
//--- Если щелчок по последнему пункту (ALL)
if(index_l==ArraySymbols.Size()-1)
{
//--- получим и отобразим торговую статистику аккаунта, и укажем, что справа активна панель TABLE_STATS
if(!GetTradingStatsByAccount(DBHandle, DB_NAME, ArrayAccountStats))
return;
if(ViewStatistic(TABLE_ACCOUNT,(string)AccountInfoInteger(ACCOUNT_LOGIN)))
RPanelTable=TABLE_STATS;
}
//--- Щелчок по наименованию символа - отобразим статистику по символу и укажем, что справа активна панель TABLE_STATS
else
{
if(ViewStatistic(TABLE_SYMBOLS,cell.Text()))
RPanelTable=TABLE_STATS;
}
}
//--- Если в левой панели был щелчок по магику из списка
if(LPanelTable==TABLE_MAGICS && index_l>WRONG_VALUE)
{
//--- Получим таблицу магиков с левой панели
CTableData *table=panel_l.GetTable(TABLE_MAGICS);
if(table==NULL)
return;
//--- Получим единственную ячейку таблицы с номером строки index_l
CTableCell *cell=table.GetCell(index_l,0);
if(cell==NULL)
return;
//--- Если щелчок по последнему пункту (ALL)
if(index_l==ArrayMagics.Size()-1)
{
//--- получим и отобразим торговую статистику аккаунта, и укажем, что справа активна панель TABLE_STATS
if(!GetTradingStatsByAccount(DBHandle, DB_NAME, ArrayAccountStats))
return;
if(ViewStatistic(TABLE_ACCOUNT,(string)AccountInfoInteger(ACCOUNT_LOGIN)))
RPanelTable=TABLE_STATS;
}
//--- Щелчок по значению магика - отобразим статистику по магику и укажем, что справа активна панель TABLE_STATS
else
{
if(ViewStatistic(TABLE_MAGICS,cell.Text()))
RPanelTable=TABLE_STATS;
}
}
//--- Если в правой панели был щелчок по символу из списка
if(RPanelTable==TABLE_SYMBOLS && index_r>WRONG_VALUE)
{
//--- Получим таблицу статистики символов с правой панели
CTableData *table=panel_r.GetTable(TABLE_SYMBOLS);
if(table==NULL)
return;
//--- Получим нулевую ячейку таблицы с номером строки index_r
CTableCell *cell=table.GetCell(index_r,0);
if(cell==NULL)
return;
//--- Отобразим итоговую статистику по символу и укажем, что справа активна панель TABLE_STATS
if(ViewStatistic(TABLE_SYMBOLS,cell.Text()))
RPanelTable=TABLE_STATS;
}
//--- Если в правой панели был щелчок по магику из списка
if(RPanelTable==TABLE_MAGICS && index_r>WRONG_VALUE)
{
//--- Получим таблицу статистики магиков с правой панели
CTableData *table=panel_r.GetTable(TABLE_MAGICS);
if(table==NULL)
return;
//--- Получим нулевую ячейку таблицы с номером строки index_r
CTableCell *cell=table.GetCell(index_r,0);
if(cell==NULL)
return;
//--- Отобразим итоговую статистику по магику и укажем, что справа активна панель TABLE_STATS
if(ViewStatistic(TABLE_MAGICS,cell.Text()))
RPanelTable=TABLE_STATS;
}
}
}
//+------------------------------------------------------------------+
//| Возвращает индекс строки таблицы по координатам курсора |
//+------------------------------------------------------------------+
int TableSelectRowByMouse(const int x_cursor, const int y_cursor, const int cell_h, CDashboard *panel, CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return WRONG_VALUE;
int index=WRONG_VALUE; // Индекс строки таблицы, расположенной под курсором
//--- В цикле по строкам таблицы
int total=table.RowsTotal();
for(int i=0;i<total;i++)
{
//--- получаем очередную нулевую ячейку таблицы в строке с индексом цикла
CTableCell *cell=table.GetCell(i,0);
if(cell==NULL)
continue;
//--- Рассчитываем верхнюю и нижнюю координаты расположения строки таблицы по координате Y ячейки
int y1=panel.CoordY()+cell.Y()+1;
int y2=y1+cell_h;
//--- Если курсор по вертикали находится внутри рассчитанных координат строки таблицы
if(y_cursor>y1 && y_cursor<y2)
{
//--- Записываем индекс строки, рисуем прямоугольную область на всю ширину таблицы (выделение строки под курсором) и возвращаем индекс строки
index=cell.Row();
panel.DrawRectangleFill(2,cell.Y()+1,panel.Width()-4,y2-y1-1,C'220,220,220',240);
return index;
}
}
//--- Ничего не нашли
return WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| Обработчик прокрутки колёсика мышки внутри таблицы левой панели |
//+------------------------------------------------------------------+
int TableMouseWhellHandlerL(const int x_cursor,const int y_cursor,const bool shift_flag,const int delta,CDashboard *panel,const int table_id)
{
//--- Проверяем указатель на левую панель
if(panel==NULL)
return WRONG_VALUE;
//--- Проверяем расположение курсора внутри панели
if(x_cursor<panel.CoordX()+2 || x_cursor>panel.CoordX()+panel.Width() ||
y_cursor<panel.CoordY()+4 || y_cursor>panel.CoordY()+panel.Height())
return WRONG_VALUE;
//--- Проверяем наличие таблицы на панели
if(!panel.TableIsExist(table_id))
return WRONG_VALUE;
//--- Получаем указатель на активную таблицу на панели
CTableData *table=panel.GetTable(table_id);
if(table==NULL)
return WRONG_VALUE;
//--- Рассчитываем смещение таблицы на половину высоты строки таблицы
int shift=CELL_H/2*(delta<0 ? -1 : 1);
//--- Рассчитываем координаты, в пределах которых смещается таблица
int y=table.Y1()+shift;
if(y>2)
y=2;
if(y+table.Height()<panel.Height()-2)
y=panel.Height()-2-table.Height();
if(table.Height()<panel.Height())
return WRONG_VALUE;
//--- Очищаем панель и выводим на неё активную таблицу
int total=int(table_id==TABLE_SYMBOLS ? ArraySymbols.Size() : ArrayMagics.Size());
panel.Clear();
panel.DrawGrid(table_id,2,y,total,1,CELL_H,panel.Width()-5,C'220,220,220');
//--- Заполняем таблицу значениями
if(table_id==TABLE_SYMBOLS)
FillsSymbolTable(panel,table);
else
FillsMagicTable(panel,table);
//--- Получаем номер строки таблицы, над которой расположен курсор
int index=TableSelectRowByMouse(x_cursor,y_cursor,CELL_H,panel,table);
return index;
}
//+------------------------------------------------------------------+
//| Обработчик смещения курсора мышки внутри таблицы левой панели |
//+------------------------------------------------------------------+
int TableMouseMoveHandlerL(const int x_cursor,const int y_cursor,CDashboard *panel,const int table_id)
{
//--- Проверяем указатель на левую панель
if(panel==NULL)
return WRONG_VALUE;
//--- Проверяем наличие таблицы на панели
if(!panel.TableIsExist(table_id))
return WRONG_VALUE;
//--- Получаем указатель на активную таблицу на панели
CTableData *table=panel.GetTable(table_id);
if(table==NULL)
return WRONG_VALUE;
//--- Проверяем расположение курсора внутри панели
//--- Если курсор за пределами панели - рисуем активную таблицу и возвращаем -1 (чтобы убрать выделение строки, над которой был курсор)
int total=int(table_id==TABLE_SYMBOLS ? ArraySymbols.Size() : ArrayMagics.Size());
if(x_cursor<panel.CoordX()+2 || x_cursor>panel.CoordX()+panel.Width() ||
y_cursor<panel.CoordY()+4 || y_cursor>panel.CoordY()+panel.Height())
{
panel.Clear();
panel.DrawGrid(table_id,2,table.Y1(),total,1,CELL_H,panel.Width()-5,C'220,220,220');
return WRONG_VALUE;
}
//--- Очищаем панель и выводим на неё активную таблицу
panel.Clear();
panel.DrawGrid(table_id,2,table.Y1(),total,1,CELL_H,panel.Width()-5,C'220,220,220');
//--- Заполняем таблицу значениями
if(table_id==TABLE_SYMBOLS)
FillsSymbolTable(panel,table);
else
FillsMagicTable(panel,table);
//--- Получаем и возвращаем номер строки таблицы, над которой расположен курсор
int index=TableSelectRowByMouse(x_cursor,y_cursor,CELL_H,panel,table);
return index;
}
//+------------------------------------------------------------------+
//| Обработчик прокрутки колёсика мышки внутри таблицы правой панели |
//+------------------------------------------------------------------+
int TableMouseWhellHandlerR(const int x_cursor,const int y_cursor,const bool shift_flag,const int delta,CDashboard *panel,const int table_id)
{
//--- Проверяем указатель на правую панель
if(panel==NULL)
return WRONG_VALUE;
//--- Проверяем расположение курсора внутри панели
if(x_cursor<panel.CoordX()+2 || x_cursor>panel.CoordX()+panel.Width() ||
y_cursor<panel.CoordY()+4 || y_cursor>panel.CoordY()+panel.Height())
return WRONG_VALUE;
//--- Проверяем наличие таблицы на панели
if(!panel.TableIsExist(table_id))
return WRONG_VALUE;
//--- Получаем указатель на активную таблицу на панели
CTableData *table=panel.GetTable(table_id);
if(table==NULL)
return WRONG_VALUE;
//--- Рассчитываем вертикальное смещение таблицы на половину высоты строки таблицы
int shift_y=CELL_H/2*(delta<0 ? -1 : 1);
//--- Рассчитываем горизонтальное смещение таблицы на размер высоты строки таблицы
int shift_x=(shift_flag ? CELL_H*(delta<0 ? -1 : 1) : 0);
//--- Рассчитываем координаты, в пределах которых смещается таблица по Y
int y=table.Y1()+shift_y;
if(y>2)
y=2;
if(y+table.Height()<panel.Height()-2)
y=panel.Height()-2-table.Height();
//--- Рассчитываем координаты, в пределах которых смещается таблица по X
int x=0;
if(shift_flag)
{
x=table.X1()+shift_x;
if(x>2)
x=2;
if(x+table.Width()<panel.Width()-2)
x=panel.Width()-2-table.Width();
}
//--- Если вся таблица умещается в размеры панели - ничего прокручивать не нужно, возвращаем -1
if(table.Height()<panel.Height() && table.Width()<panel.Width())
return WRONG_VALUE;
//--- Определяем размеры таблицы
int total=0; // количество строк
int columns=0; // количество столбцов
int cell_w=0; // ширина ячейки таблицы (столбца)
int cell_h=CELL_H; // высота ячейки таблицы (строки)
switch(table_id)
{
case TABLE_TRADES :
total=(int)ArrayTrades.Size();
columns=11;
cell_w=CELL_W_TRADES;
break;
case TABLE_SYMBOLS:
total=(int)ArraySymbolStats.Size();
columns=(int)ArrayDataName.Size();
cell_w=CELL_W_SYMBOLS;
break;
case TABLE_MAGICS :
total=(int)ArrayMagicStats.Size();
columns=(int)ArrayDataName.Size();
cell_w=CELL_W_MAGICS;
break;
case TABLE_STATS :
total=TABLE_STAT_ROWS;
columns=TABLE_STAT_COLS;
cell_w=(panel.Width()-4)/TABLE_STAT_COLS;
cell_h=(panel.Height()-4)/total;
break;
default :
break;
}
//--- Очищаем панель и выводим на неё активную таблицу
panel.Clear();
panel.DrawGrid(table_id,
(shift_flag ? x : table.X1()),
(!shift_flag && table.Height()>panel.Height() ? y : table.Y1()),
total,columns,cell_h,cell_w,
(table_id!=TABLE_STATS ? C'220,220,220' : C'230,230,230'),
(table_id!=TABLE_STATS));
//--- Заполняем таблицу значениями
switch(table_id)
{
case TABLE_TRADES : FillsTradeTable(panel,table); break;
case TABLE_SYMBOLS: FillsTradingStatsBySymbolsTable(panel,table); break;
case TABLE_MAGICS : FillsTradingStatsByMagicsTable(panel,table); break;
default : break;
}
//--- Получаем указатель на панель заголовка
CDashboard *panel_h=dashboard.GetPanel("FieldH");
if(panel_h==NULL)
return WRONG_VALUE;
//--- Получаем указатель на таблицу заголовка
CTableData *table_h=panel_h.GetTable(table_id);
if(table_h==NULL)
return WRONG_VALUE;
//--- Очищаем панель заголовка таблицы и выводим на неё таблицу
panel_h.Clear();
panel_h.DrawGrid(table_id,(shift_flag ? x : table_h.X1()),2,1,columns,cell_h,cell_w,C'200,200,200',false);
//--- Заполняем таблицу заголовков
switch(table_id)
{
case TABLE_TRADES : FillsHeaderTradeTable(panel_h,table_h); break;
case TABLE_SYMBOLS:
case TABLE_MAGICS : FillsHeaderTradingStatsTable(panel_h,table_h); break;
default : break;
}
//--- Для таблицы итоговой статистики номер строки под курсором искать не нужно
if(table.ID()==TABLE_STATS)
return WRONG_VALUE;
//--- Получаем номер строки таблицы, над которой расположен курсор
int index=TableSelectRowByMouse(x_cursor,y_cursor,cell_h,panel,table);
return index;
}
//+------------------------------------------------------------------+
//| Обработчик смещения курсора мышки внутри таблицы правой панели |
//+------------------------------------------------------------------+
int TableMouseMoveHandlerR(const int x_cursor,const int y_cursor,CDashboard *panel,const int table_id)
{
//--- Проверяем указатель на левую панель
if(panel==NULL)
return WRONG_VALUE;
//--- Проверяем наличие таблицы на панели
if(!panel.TableIsExist(table_id))
return WRONG_VALUE;
//--- Получаем указатель на активную таблицу на панели
CTableData *table=panel.GetTable(table_id);
if(table==NULL)
return WRONG_VALUE;
//--- Определяем размеры таблицы
int total=0; // количество строк
int columns=0; // количество столбцов
int cell_w=0; // ширина ячейки таблицы (столбца)
int cell_h=CELL_H; // высота ячейки таблицы (строки)
switch(table_id)
{
case TABLE_TRADES :
total=(int)ArrayTrades.Size();
columns=11;
cell_w=CELL_W_TRADES;
break;
case TABLE_SYMBOLS:
total=(int)ArraySymbolStats.Size();
columns=(int)ArrayDataName.Size();
cell_w=CELL_W_SYMBOLS;
break;
case TABLE_MAGICS :
total=(int)ArrayMagicStats.Size();
columns=(int)ArrayDataName.Size();
cell_w=CELL_W_MAGICS;
break;
case TABLE_STATS :
total=TABLE_STAT_ROWS;
columns=TABLE_STAT_COLS;
cell_w=(panel.Width()-4)/TABLE_STAT_COLS;
cell_h=(panel.Height()-4)/total;
break;
default :
break;
}
//--- Проверяем расположение курсора внутри панели
//--- Если курсор за пределами панели - рисуем активную таблицу и возвращаем -1 (чтобы убрать выделение строки, над которой был курсор)
if(x_cursor<panel.CoordX()+2 || x_cursor>panel.CoordX()+panel.Width() ||
y_cursor<panel.CoordY()+4 || y_cursor>panel.CoordY()+panel.Height())
{
panel.Clear();
panel.DrawGrid(table_id,table.X1(),table.Y1(),total,columns,cell_h,cell_w,(table_id!=TABLE_STATS ? C'220,220,220' : C'230,230,230'),(table_id!=TABLE_STATS));
return WRONG_VALUE;
}
//--- Очищаем панель и выводим на неё активную таблицу
panel.Clear();
panel.DrawGrid(table_id,table.X1(),table.Y1(),total,columns,cell_h,cell_w,(table_id!=TABLE_STATS ? C'220,220,220' : C'230,230,230'),(table_id!=TABLE_STATS));
//--- Заполняем таблицу значениями
switch(table_id)
{
case TABLE_TRADES : FillsTradeTable(panel,table); break;
case TABLE_SYMBOLS: FillsTradingStatsBySymbolsTable(panel,table); break;
case TABLE_MAGICS : FillsTradingStatsByMagicsTable(panel,table); break;
default : break;
}
//--- Для таблицы итоговой статистики номер строки под курсором искать не нужно
if(table.ID()==TABLE_STATS)
return WRONG_VALUE;
//--- Получаем номер строки таблицы, над которой расположен курсор
int index=TableSelectRowByMouse(x_cursor,y_cursor,cell_h,panel,table);
return index;
}
//+------------------------------------------------------------------+
//| Обработчик щелчка мышки внутри таблицы на панели |
//+------------------------------------------------------------------+
int TableMouseClickHandler(const int x_cursor,const int y_cursor,CDashboard *panel,const int table_id)
{
//--- Проверяем указатель на левую панель
if(panel==NULL)
return WRONG_VALUE;
//--- Проверяем расположение курсора внутри панели
if(x_cursor<panel.CoordX()+2 || x_cursor>panel.CoordX()+panel.Width() ||
y_cursor<panel.CoordY()+4 || y_cursor>panel.CoordY()+panel.Height())
return WRONG_VALUE;
//--- Проверяем наличие таблицы на панели
if(!panel.TableIsExist(table_id))
return WRONG_VALUE;
//--- Получаем указатель на активную таблицу на панели
CTableData *table=panel.GetTable(table_id);
if(table==NULL)
return WRONG_VALUE;
//--- Для таблицы итоговой статистики номер строки под курсором искать не нужно
if(table.ID()==TABLE_STATS)
return WRONG_VALUE;
//--- Получаем номер строки таблицы, на которой был щелчок
int index=TableSelectRowByMouse(x_cursor,y_cursor,CELL_H,panel,table);
return index;
}
//+------------------------------------------------------------------+
//| Заполняет таблицу наименованиями символов |
//+------------------------------------------------------------------+
void FillsSymbolTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Рассчитаем индекс строки, с которой необходимо начать заполнение таблицы
CTableCell *cell=table.GetCell(0,0);
if(cell==NULL)
return;
int y=panel.CoordY()+cell.Y()-2;
int diff=panel.CoordY()-y;
int index=diff/CELL_H;
//--- Заполняем таблицу значениями из массива, начиная со строки index
for(int i=index;i<(int)ArraySymbols.Size();i++)
{
CTableCell *cell=table.GetCell(i,0);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- выводим данные из массива в ячейки таблицы
cell.SetText(ArraySymbols[i]);
panel.DrawText(cell.Text(),cell.X()+2,cell.Y()+1);
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу значениями магиков |
//+------------------------------------------------------------------+
void FillsMagicTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Рассчитаем индекс строки, с которой необходимо начать заполнение таблицы
CTableCell *cell=table.GetCell(0,0);
if(cell==NULL)
return;
int y=panel.CoordY()+cell.Y()-2;
int diff=panel.CoordY()-y;
int index=diff/CELL_H;
//--- Заполняем таблицу значениями из массива, начиная со строки index
for(int i=index;i<(int)ArrayMagics.Size();i++)
{
CTableCell *cell=table.GetCell(i,0);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- выводим данные из массива в ячейки таблицы
string text=(i<(int)ArrayMagics.Size()-1 ? (string)ArrayMagics[i] : "ALL");
cell.SetText(text);
panel.DrawText(cell.Text(),cell.X()+2,cell.Y()+1);
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу заголовков трейдов |
//+------------------------------------------------------------------+
void FillsHeaderTradeTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Заполняем таблицу значениями
int total=11; // 11 столбцов таблицы
CTableCell *cell=NULL;
for(int i=0;i<total;i++)
{
//--- Получаем ячейку i таблицы из нулевой (и единственной) строки таблицы
cell=table.GetCell(0,i);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- Записываем наименования заголовков в зависимости от индекса цикла
string cell_text="";
switch(i)
{
case 0 : cell_text="Time Entry In"; break; // время входа
case 1 : cell_text="Position ID"; break; // ID позиции
case 2 : cell_text="Position Type"; break; // покупка или продажа
case 3 : cell_text="Volume"; break; // объем
case 4 : cell_text="Symbol"; break; // символ
case 5 : cell_text="Price Entry In"; break; // цена входа
case 6 : cell_text="Time Entry Out"; break; // время выхода
case 7 : cell_text="Price Entry Out"; break; // цена выхода
case 8 : cell_text="Commission"; break; // комиссия за вход и выход
case 9 : cell_text="Swap"; break; // своп
case 10 : cell_text="Profit"; break; // прибыль или убыток
default : break;
}
//--- выводим записи в ячейки таблицы
cell.SetText(cell_text);
panel.DrawText(cell.Text(),cell.X()+6,cell.Y()+2);
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу трейдов |
//+------------------------------------------------------------------+
void FillsTradeTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Заполняем таблицу значениями из массива
CTableCell *cell=NULL;
int total=(int)ArrayTrades.Size();
if(total==0)
{
PrintFormat("%s: Error: Trades array is empty",__FUNCTION__);
return;
}
//--- Рассчитаем индекс строки, с которой необходимо начать заполнение таблицы
cell=table.GetCell(0,0);
if(cell==NULL)
return;
int y=panel.CoordY()+cell.Y()-2;
int diff=panel.CoordY()-y;
int index=diff/CELL_H;
//--- В цикле по количеству строк (размер массива трейдов), начиная со строки index
for(int i=index;i<total;i++)
{
//--- в цикле по количеству столбцов (11 для данной таблицы)
for(int j=0;j<11;j++)
{
//--- получаем очередную ячейку таблицы
cell=table.GetCell(i,j);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- Получаем данные таблицы из массива трейдов
string cell_text="";
int digits=(int)SymbolInfoInteger(ArrayTrades[i].symbol,SYMBOL_DIGITS);
switch(j)
{
case 0 : cell_text=TimeToString(ArrayTrades[i].time_in); break; // время входа
case 1 : cell_text=IntegerToString(ArrayTrades[i].ticket); break; // ID позиции
case 2 : cell_text=(ArrayTrades[i].type==0 ? "Buy" : "Sell"); break; // покупка или продажа
case 3 : cell_text=DoubleToString(ArrayTrades[i].volume,2); break; // объем
case 4 : cell_text=ArrayTrades[i].symbol; break; // символ
case 5 : cell_text=DoubleToString(ArrayTrades[i].price_in,digits); break; // цена входа
case 6 : cell_text=TimeToString(ArrayTrades[i].time_out); break; // время выхода
case 7 : cell_text=DoubleToString(ArrayTrades[i].price_out,digits); break; // цена выхода
case 8 : cell_text=DoubleToString(ArrayTrades[i].commission,2); break; // комиссия за вход и выход
case 9 : cell_text=DoubleToString(ArrayTrades[i].swap,2); break; // своп
case 10 : cell_text=DoubleToString(ArrayTrades[i].profit,2); break; // прибыль или убыток
default : break;
}
//--- выводим записи в ячейки таблицы
cell.SetText(cell_text);
panel.DrawText(cell.Text(),cell.X()+6,cell.Y()+1);
}
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу заголовков статистики торговли |
//+------------------------------------------------------------------+
void FillsHeaderTradingStatsTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Заполняем таблицу значениями в цикле по количеству столбцов (по размеру данных в ArrayDataName)
int total=(int)ArrayDataName.Size();
CTableCell *cell=NULL;
for(int i=0;i<total;i++)
{
//--- получаем очередную ячейку таблицы
cell=table.GetCell(0,i);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- Записываем наименования заголовков в зависимости от индекса цикла
string cell_text=(i>0 ? ArrayDataName[i] : table.ID()==TABLE_SYMBOLS ? "Symbol" : "Magic");
//--- выводим записи в ячейки таблицы
cell.SetText(cell_text);
panel.DrawText(cell.Text(),cell.X()+6,cell.Y()+2);
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу статистики торговли по символам |
//+------------------------------------------------------------------+
void FillsTradingStatsBySymbolsTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Заполняем таблицу значениями из массива
CTableCell *cell=NULL;
int total=(int)ArraySymbolStats.Size();
if(total==0)
{
PrintFormat("%s: Error: The array of trading statistics by symbols is empty",__FUNCTION__);
return;
}
//--- Рассчитаем индекс строки, с которой необходимо начать заполнение таблицы
cell=table.GetCell(0,0);
if(cell==NULL)
return;
int y=panel.CoordY()+cell.Y()-2;
int diff=panel.CoordY()-y;
int index=diff/CELL_H;
//--- В цикле по количеству строк (размер массива статистики символов), начиная со строки index
for(int i=index;i<total;i++)
{
//--- в цикле по количеству столбцов статистики (массив расположения столбцов таблиц статистики слева-направо)
for(int j=0;j<(int)ArrayDataName.Size();j++)
{
//--- получаем очередную ячейку таблицы
cell=table.GetCell(i,j);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- Получаем данные таблицы из массива структур
string cell_text="";
cell_text=GetDataStatsStr(TABLE_SYMBOLS, ArrayDataName[j],i);
//--- выводим записи в ячейки таблицы
cell.SetText(cell_text);
panel.DrawText(cell.Text(),cell.X()+6,cell.Y()+1);
}
}
}
//+------------------------------------------------------------------+
//| Заполняет таблицу статистики торговли по магикам |
//+------------------------------------------------------------------+
void FillsTradingStatsByMagicsTable(CDashboard *panel,CTableData *table)
{
//--- Проверяем указатели на панель и таблицу
if(panel==NULL || table==NULL)
return;
//--- Заполняем таблицу значениями из массива
CTableCell *cell=NULL;
int total=(int)ArrayMagicStats.Size();
if(total==0)
{
PrintFormat("%s: Error: The array of trading statistics by magics is empty",__FUNCTION__);
return;
}
//--- Рассчитаем индекс строки, с которой необходимо начать заполнение таблицы
cell=table.GetCell(0,0);
if(cell==NULL)
return;
int y=panel.CoordY()+cell.Y()-2;
int diff=panel.CoordY()-y;
int index=diff/CELL_H;
//--- В цикле по количеству строк (размер массива статистики магиков), начиная со строки index
for(int i=index;i<total;i++)
{
//--- в цикле по количеству столбцов статистики (массив расположения столбцов таблиц статистики слева-направо)
for(int j=0;j<(int)ArrayDataName.Size();j++)
{
//--- получаем очередную ячейку таблицы
cell=table.GetCell(i,j);
if(cell==NULL)
continue;
//--- невидимые области таблицы не рисуем
if(cell.X()>panel.CoordX()+panel.Width())
continue;
if(cell.Y()>panel.CoordY()+panel.Height())
break;
//--- Получаем данные таблицы из массива структур
string cell_text=GetDataStatsStr(TABLE_MAGICS, ArrayDataName[j],i);
//--- выводим записи в ячейки таблицы
cell.SetText(cell_text);
panel.DrawText(cell.Text(),cell.X()+6,cell.Y()+1);
}
}
}
//+------------------------------------------------------------------+
//| Возвращает данные из структуры по типу заголовка |
//+------------------------------------------------------------------+
double GetDataStats(const int table_type, const string data_type, const int index)
{
//--- В зависимости от типа данных в таблице возвращаем данные из полей структуры data_type, по индексу массива index
switch(table_type)
{
case TABLE_SYMBOLS :
return
(
data_type==H_TRADES_S ? ArraySymbolStats[index].trades :
data_type==H_GROSS_PROFIT_S ? ArraySymbolStats[index].gross_profit :
data_type==H_GROSS_LOSS_S ? ArraySymbolStats[index].gross_loss :
data_type==H_COMMISSIONS_S ? ArraySymbolStats[index].total_commission :
data_type==H_SWAPS_S ? ArraySymbolStats[index].total_swap :
data_type==H_PROFITS_S ? ArraySymbolStats[index].total_profit :
data_type==H_NET_PROFIT_S ? ArraySymbolStats[index].net_profit :
data_type==H_WINS_S ? ArraySymbolStats[index].win_trades :
data_type==H_LOST_S ? ArraySymbolStats[index].loss_trades :
data_type==H_LONG_S ? ArraySymbolStats[index].long_trades :
data_type==H_SHORT_S ? ArraySymbolStats[index].short_trades :
data_type==H_EXP_PAYOFF_S ? ArraySymbolStats[index].expected_payoff :
data_type==H_WIN_PRC_S ? ArraySymbolStats[index].win_percent :
data_type==H_LOSS_PRC_S ? ArraySymbolStats[index].loss_percent :
data_type==H_AVG_PROFIT_S ? ArraySymbolStats[index].average_profit :
data_type==H_AVG_LOSS_S ? ArraySymbolStats[index].average_loss :
data_type==H_PRF_FACTOR_S ? ArraySymbolStats[index].profit_factor :
0
);
case TABLE_MAGICS :
return
(
data_type==H_TRADES_S ? ArrayMagicStats[index].trades :
data_type==H_GROSS_PROFIT_S ? ArrayMagicStats[index].gross_profit :
data_type==H_GROSS_LOSS_S ? ArrayMagicStats[index].gross_loss :
data_type==H_COMMISSIONS_S ? ArrayMagicStats[index].total_commission :
data_type==H_SWAPS_S ? ArrayMagicStats[index].total_swap :
data_type==H_PROFITS_S ? ArrayMagicStats[index].total_profit :
data_type==H_NET_PROFIT_S ? ArrayMagicStats[index].net_profit :
data_type==H_WINS_S ? ArrayMagicStats[index].win_trades :
data_type==H_LOST_S ? ArrayMagicStats[index].loss_trades :
data_type==H_LONG_S ? ArrayMagicStats[index].long_trades :
data_type==H_SHORT_S ? ArrayMagicStats[index].short_trades :
data_type==H_EXP_PAYOFF_S ? ArrayMagicStats[index].expected_payoff :
data_type==H_WIN_PRC_S ? ArrayMagicStats[index].win_percent :
data_type==H_LOSS_PRC_S ? ArrayMagicStats[index].loss_percent :
data_type==H_AVG_PROFIT_S ? ArrayMagicStats[index].average_profit :
data_type==H_AVG_LOSS_S ? ArrayMagicStats[index].average_loss :
data_type==H_PRF_FACTOR_S ? ArrayMagicStats[index].profit_factor :
0
);
case TABLE_ACCOUNT :
return
(
data_type==H_TRADES_S ? ArrayAccountStats[index].trades :
data_type==H_GROSS_PROFIT_S ? ArrayAccountStats[index].gross_profit :
data_type==H_GROSS_LOSS_S ? ArrayAccountStats[index].gross_loss :
data_type==H_COMMISSIONS_S ? ArrayAccountStats[index].total_commission :
data_type==H_SWAPS_S ? ArrayAccountStats[index].total_swap :
data_type==H_PROFITS_S ? ArrayAccountStats[index].total_profit :
data_type==H_NET_PROFIT_S ? ArrayAccountStats[index].net_profit :
data_type==H_WINS_S ? ArrayAccountStats[index].win_trades :
data_type==H_LOST_S ? ArrayAccountStats[index].loss_trades :
data_type==H_LONG_S ? ArrayAccountStats[index].long_trades :
data_type==H_SHORT_S ? ArrayAccountStats[index].short_trades :
data_type==H_EXP_PAYOFF_S ? ArrayAccountStats[index].expected_payoff :
data_type==H_WIN_PRC_S ? ArrayAccountStats[index].win_percent :
data_type==H_LOSS_PRC_S ? ArrayAccountStats[index].loss_percent :
data_type==H_AVG_PROFIT_S ? ArrayAccountStats[index].average_profit :
data_type==H_AVG_LOSS_S ? ArrayAccountStats[index].average_loss :
data_type==H_PRF_FACTOR_S ? ArrayAccountStats[index].profit_factor :
0
);
default : return 0;
}
}
//+------------------------------------------------------------------+
//| Возвращает данные из структуры по типу заголовка в виде строки |
//+------------------------------------------------------------------+
string GetDataStatsStr(const int table_type, const string data_type, const int index)
{
//--- В зависимости от типа данных, определяем количество знаков после запятой
//--- (2 - для вещественного свойства и 0 - для целочисленного)
int digits=(data_type==H_TRADES_S ||
data_type==H_WINS_S ||
data_type==H_LOST_S ||
data_type==H_LONG_S ||
data_type==H_SHORT_S ? 0 : 2);
//--- Если тип данных "Заголовок"
if(data_type=="HEADER")
{
//--- возвращаем наименование в зависимости от типа таблицы (символ, магик, аккаунт)
switch(table_type)
{
case TABLE_SYMBOLS : return ArraySymbolStats[index].name;
case TABLE_MAGICS : return (string)ArrayMagicStats[index].magic;
case TABLE_ACCOUNT : return (string)ArrayAccountStats[index].account;
default : return "Unknown:"+(string)table_type;
}
}
//--- Для всех остальных типов данных возвращаем их строковое значение с ранее определённым количеством десятичных знаков
return(DoubleToString(GetDataStats(table_type, data_type, index),digits));
}
//+------------------------------------------------------------------+
//| Возвращает индекс символа в массиве статистики по символам |
//+------------------------------------------------------------------+
int GetIndexSymbol(const string symbol)
{
int total=(int)ArraySymbolStats.Size();
for(int i=0;i<total;i++)
{
if(ArraySymbolStats[i].name==symbol)
return i;
}
return WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| Возвращает индекс магика в массиве статистики по магикам |
//+------------------------------------------------------------------+
int GetIndexMagic(const long magic)
{
int total=(int)ArrayMagicStats.Size();
for(int i=0;i<total;i++)
{
if(ArrayMagicStats[i].magic==magic)
return i;
}
return WRONG_VALUE;
}
//+------------------------------------------------------------------+
//| Отображает статистику по выбранному символу, магику или счёту |
//+------------------------------------------------------------------+
bool ViewStatistic(const int table_type,const string cell_text)
{
//--- Получаем указатели на панель заголовков и правую панель для вывода статистики
CDashboard *panel_h=dashboard.GetPanel("FieldH");
CDashboard *panel_r=dashboard.GetPanel("FieldR");
if(panel_h==NULL || panel_r==NULL)
return false;
//--- Определяем источник статистических данных (символ/магик/аккаунт)
string source=(table_type==TABLE_SYMBOLS ? "symbol" : table_type==TABLE_MAGICS ? "magic" : "account");
int index=WRONG_VALUE;
//--- В зависимости от текста в выбранной ячейке таблицы (cell_text), переданному в функцию,
//--- получаем индекс, по которому содержатся данные в соответствующем массиве статистики
switch(table_type)
{
case TABLE_SYMBOLS: index=GetIndexSymbol(cell_text); break;
case TABLE_MAGICS : index=GetIndexMagic(StringToInteger(cell_text)); break;
case TABLE_ACCOUNT: index=(ArrayAccountStats.Size()==1 ? 0 : -1); break;
default : break;
}
//--- Если индекс получить не удалось, считаем, что соответствующий массив статистики пуст
if(index==WRONG_VALUE)
{
PrintFormat("%s: Error. Empty array of %s statistics",__FUNCTION__,source);
return false;
}
//--- Получим и сохраним установленные для панели заголовков свойства шрифта
int f_size;
uint f_flags,f_angle;
string f_name=panel_h.FontParams(f_size,f_flags,f_angle);
//--- Очищаем панель заголовков и выводим на неё описание выбранных данных шрифтом Tahoma размером 8
panel_h.Clear();
panel_h.SetFontParams("Tahoma",8,f_flags,f_angle);
panel_h.DrawText(StringFormat("Trade statistics by %s %s",source,cell_text),8,3,C'150,150,150');
//--- Возвращаем шрифту панели заголовков прежние сохранённые свойства
panel_h.SetFontParams(f_name,f_size,f_flags,f_angle);
//--- Проверяем наличие и получаем или создаём объект-таблицу для вывода статистики на правой панели
if(!panel_r.TableIsExist(TABLE_STATS) && !panel_r.CreateNewTable(TABLE_STATS))
return false;
//--- Получаем указатель на созданную таблицу
CTableData *table_r=panel_r.GetTable(TABLE_STATS);
if(table_r==NULL)
return false;
//--- Очищаем правую панель и рисуем на ней таблицу
panel_r.Clear();
panel_r.DrawGrid(TABLE_STATS,2,2,TABLE_STAT_ROWS,TABLE_STAT_COLS,(panel_r.Height()-4)/TABLE_STAT_ROWS,(panel_r.Width()-4)/TABLE_STAT_COLS,C'230,230,230',false);
//--- Объявляем структуру для хранения данных статистики
//--- (символ/магик/аккаунт) по ранее полученному индексу данных.
//--- Все поля структур SSymbolStats, SMagicStats и SAccountStats одинаковы,
//--- кроме первого поля с наименованием символа, значением магика или номером счёта.
//--- Т.к. первое поле здесь не нужно, поэтому здесь достаточно любого типа структуры из трёх.
//--- Заполняем объявленную структуру данными в зависимости от выбранного источника
SSymbolStats stats={};
switch(table_type)
{
case TABLE_SYMBOLS:
stats.trades = ArraySymbolStats[index].trades;
stats.gross_profit = ArraySymbolStats[index].gross_profit;
stats.gross_loss = ArraySymbolStats[index].gross_loss;
stats.total_commission= ArraySymbolStats[index].total_commission;
stats.total_swap = ArraySymbolStats[index].total_swap;
stats.total_profit = ArraySymbolStats[index].total_profit;
stats.net_profit = ArraySymbolStats[index].net_profit;
stats.win_trades = ArraySymbolStats[index].win_trades;
stats.loss_trades = ArraySymbolStats[index].loss_trades;
stats.long_trades = ArraySymbolStats[index].long_trades;
stats.short_trades = ArraySymbolStats[index].short_trades;
stats.expected_payoff = ArraySymbolStats[index].expected_payoff;
stats.win_percent = ArraySymbolStats[index].win_percent;
stats.loss_percent = ArraySymbolStats[index].loss_percent;
stats.average_profit = ArraySymbolStats[index].average_profit;
stats.average_loss = ArraySymbolStats[index].average_loss;
stats.profit_factor = ArraySymbolStats[index].profit_factor;
break;
case TABLE_MAGICS :
stats.trades = ArrayMagicStats[index].trades;
stats.gross_profit = ArrayMagicStats[index].gross_profit;
stats.gross_loss = ArrayMagicStats[index].gross_loss;
stats.total_commission= ArrayMagicStats[index].total_commission;
stats.total_swap = ArrayMagicStats[index].total_swap;
stats.total_profit = ArrayMagicStats[index].total_profit;
stats.net_profit = ArrayMagicStats[index].net_profit;
stats.win_trades = ArrayMagicStats[index].win_trades;
stats.loss_trades = ArrayMagicStats[index].loss_trades;
stats.long_trades = ArrayMagicStats[index].long_trades;
stats.short_trades = ArrayMagicStats[index].short_trades;
stats.expected_payoff = ArrayMagicStats[index].expected_payoff;
stats.win_percent = ArrayMagicStats[index].win_percent;
stats.loss_percent = ArrayMagicStats[index].loss_percent;
stats.average_profit = ArrayMagicStats[index].average_profit;
stats.average_loss = ArrayMagicStats[index].average_loss;
stats.profit_factor = ArrayMagicStats[index].profit_factor;
break;
case TABLE_ACCOUNT:
stats.trades = ArrayAccountStats[index].trades;
stats.gross_profit = ArrayAccountStats[index].gross_profit;
stats.gross_loss = ArrayAccountStats[index].gross_loss;
stats.total_commission= ArrayAccountStats[index].total_commission;
stats.total_swap = ArrayAccountStats[index].total_swap;
stats.total_profit = ArrayAccountStats[index].total_profit;
stats.net_profit = ArrayAccountStats[index].net_profit;
stats.win_trades = ArrayAccountStats[index].win_trades;
stats.loss_trades = ArrayAccountStats[index].loss_trades;
stats.long_trades = ArrayAccountStats[index].long_trades;
stats.short_trades = ArrayAccountStats[index].short_trades;
stats.expected_payoff = ArrayAccountStats[index].expected_payoff;
stats.win_percent = ArrayAccountStats[index].win_percent;
stats.loss_percent = ArrayAccountStats[index].loss_percent;
stats.average_profit = ArrayAccountStats[index].average_profit;
stats.average_loss = ArrayAccountStats[index].average_loss;
stats.profit_factor = ArrayAccountStats[index].profit_factor;
break;
default:
break;
}
//--- Получим и сохраним установленные для правой панели свойства шрифта
f_name=panel_r.FontParams(f_size,f_flags,f_angle);
//--- Устанавливаем для правой панели новый шрифт Tahoma размером 8
panel_r.SetFontParams("Tahoma",8,FW_BLACK,f_angle);
//--- Переменные для расчёта места расположения текста в ячейке таблицы
CTableCell *cellH=NULL, *cellV=NULL;
int cols=table_r.ColumnsInRow(0); // количество столбцов таблицы статистики
int cw=table_r.Width()/cols; // ширина одного столбца таблицы
int y_shift=6; // смещение текста по высоте
int x_shift=21; // смещение текста по ширине
int tw=0; // ширина текста
string text="";
double value=0;
//--- Левый столбец (данные -- значение)
//--- Получаем ячейки 0,0 и 0,1 таблицы и выводим в их координаты Trades и его значение
cellH=table_r.GetCell(0,0);
cellV=table_r.GetCell(0,1);
if(cellH==NULL || cellV==NULL)
return false;
text=(string)stats.trades;
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_TRADES+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 1,0 и 1,1 таблицы и выводим в их координаты Long и его значение
cellH=table_r.GetCell(1,0);
cellV=table_r.GetCell(1,1);
if(cellH==NULL || cellV==NULL)
return false;
text=(string)stats.long_trades;
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_LONG+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 2,0 и 2,1 таблицы и выводим в их координаты Short и его значение
cellH=table_r.GetCell(2,0);
cellV=table_r.GetCell(2,1);
if(cellH==NULL || cellV==NULL)
return false;
text=(string)stats.short_trades;
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_SHORT+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 3,0 и 3,1 таблицы и выводим в их координаты Net Profit и его значение
cellH=table_r.GetCell(3,0);
cellV=table_r.GetCell(3,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.net_profit;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_NET_PROFIT+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value>0 ? C'86,119,204' : value<0 ? C'234,50,50' : C'150,150,150'));
//--- Получаем ячейки 4,0 и 4,1 таблицы и выводим в их координаты Profit Loss и его значение
cellH=table_r.GetCell(4,0);
cellV=table_r.GetCell(4,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.total_profit;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_PROFITS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value>0 ? C'86,119,204' : value<0 ? C'234,50,50' : C'150,150,150'));
//--- Получаем ячейки 5,0 и 5,1 таблицы и выводим в их координаты Gross Profit и его значение
cellH=table_r.GetCell(5,0);
cellV=table_r.GetCell(5,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.gross_profit;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_GROSS_PROFIT+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value>0 ? C'86,119,204' : C'150,150,150'));
//--- Получаем ячейки 6,0 и 6,1 таблицы и выводим в их координаты Gross Loss и его значение
cellH=table_r.GetCell(6,0);
cellV=table_r.GetCell(6,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.gross_loss;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_GROSS_LOSS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value<0 ? C'234,50,50' : C'150,150,150'));
//--- Получаем ячейки 7,0 и 7,1 таблицы и выводим в их координаты Commission total и его значение
cellH=table_r.GetCell(7,0);
cellV=table_r.GetCell(7,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.total_commission;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_COMMISSIONS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value<0 ? C'234,50,50' : C'150,150,150'));
//--- Получаем ячейки 8,0 и 8,1 таблицы и выводим в их координаты Swap total и его значение
cellH=table_r.GetCell(8,0);
cellV=table_r.GetCell(8,1);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.total_swap;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_SWAPS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value<0 ? C'234,50,50' : C'150,150,150'));
//--- Правый столбец (данные -- значение)
//--- Получаем ячейки 0,2 и 0,3 таблицы и выводим в их координаты Win trades и его значение
cellH=table_r.GetCell(0,2);
cellV=table_r.GetCell(0,3);
if(cellH==NULL || cellV==NULL)
return false;
text=(string)stats.win_trades;
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_WINS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 1,2 и 1,3 таблицы и выводим в их координаты Loss trades и его значение
cellH=table_r.GetCell(1,2);
cellV=table_r.GetCell(1,3);
if(cellH==NULL || cellV==NULL)
return false;
text=(string)stats.loss_trades;
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_LOST+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 2,2 и 2,3 таблицы и выводим в их координаты Expected Payoff и его значение
cellH=table_r.GetCell(2,2);
cellV=table_r.GetCell(2,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.expected_payoff;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_EXP_PAYOFF+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Получаем ячейки 3,2 и 3,3 таблицы и выводим в их координаты Win percent и его значение
cellH=table_r.GetCell(3,2);
cellV=table_r.GetCell(3,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.win_percent;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_WIN_PRC+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'86,119,204');
//--- Получаем ячейки 4,2 и 4,3 таблицы и выводим в их координаты Loss percent и его значение
cellH=table_r.GetCell(4,2);
cellV=table_r.GetCell(4,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.loss_percent;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_LOSS_PRC+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'234,50,50');
//--- Получаем ячейки 5,2 и 5,3 таблицы и выводим в их координаты Average Profit и его значение
cellH=table_r.GetCell(5,2);
cellV=table_r.GetCell(5,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.average_profit;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_AVG_PROFIT+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value>0 ? C'86,119,204' : C'150,150,150'));
//--- Получаем ячейки 6,2 и 6,3 таблицы и выводим в их координаты Average Loss и его значение
cellH=table_r.GetCell(6,2);
cellV=table_r.GetCell(6,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.average_loss;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_AVG_LOSS+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,(value<0 ? C'234,50,50' : C'150,150,150'));
//--- Получаем ячейки 7,2 и 7,3 таблицы и выводим в их координаты Profit factor и его значение
cellH=table_r.GetCell(7,2);
cellV=table_r.GetCell(7,3);
if(cellH==NULL || cellV==NULL)
return false;
value=stats.profit_factor;
text=DoubleToString(value,2);
tw=panel_r.TextWidth(text);
panel_r.DrawText(H_PRF_FACTOR+":",cellH.X()+x_shift,cellH.Y()+y_shift,C'150,150,150');
panel_r.DrawText(text,cellV.X()+cw-tw-x_shift,cellV.Y()+y_shift,C'150,150,150');
//--- Возвращаем шрифту правой панели прежние сохранённые свойства
panel_r.SetFontParams(f_name,f_size,f_flags,f_angle);
return true;
}
//+------------------------------------------------------------------+