//+------------------------------------------------------------------+ //| 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;iy1 && y_cursorpanel.CoordX()+panel.Width() || y_cursorpanel.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.CoordX()+panel.Width() || y_cursorpanel.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_cursorpanel.CoordX()+panel.Width() || y_cursorpanel.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()2) x=2; if(x+table.Width()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_cursorpanel.CoordX()+panel.Width() || y_cursorpanel.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_cursorpanel.CoordX()+panel.Width() || y_cursorpanel.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;ipanel.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;ipanel.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;ipanel.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;ipanel.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;ipanel.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;i0 ? 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; } //+------------------------------------------------------------------+