forked from antekov/Adwizard
		
	
		
			
				
	
	
		
			235 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
			
		
		
	
	
			235 lines
		
	
	
	
		
			9.8 KiB
		
	
	
	
		
			MQL5
		
	
	
	
	
	
//+------------------------------------------------------------------+
 | 
						|
//|                                                    Optimizer.mqh |
 | 
						|
//|                                      Copyright 2024, Yuriy Bykov |
 | 
						|
//|                            https://www.mql5.com/ru/users/antekov |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
#property copyright "Copyright 2024, Yuriy Bykov"
 | 
						|
#property link      "https://www.mql5.com/ru/users/antekov"
 | 
						|
#property version   "1.04"
 | 
						|
 | 
						|
#include "OptimizerTask.mqh"
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Класс для менеджера автоматической оптимизации проектов          |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
class COptimizer {
 | 
						|
   string            m_fileName;
 | 
						|
   // Текущая задача оптимизации
 | 
						|
   COptimizerTask    *m_task;
 | 
						|
   int               m_totalTasks;
 | 
						|
 | 
						|
   // Получение количества задач в очереди
 | 
						|
   int               TotalTasks();
 | 
						|
 | 
						|
   // Получение идентификатора следующей задачи оптимизации из очереди
 | 
						|
   ulong             GetNextTaskId();
 | 
						|
 | 
						|
public:
 | 
						|
   COptimizer(string p_fileName, string p_pythonPath = NULL);   // Конструктор
 | 
						|
   ~COptimizer();
 | 
						|
   void              Process();  // Основной метод обработки
 | 
						|
   string            Text();     // Информация от текущем состоянии оптимизации
 | 
						|
};
 | 
						|
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Конструктор                                                      |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
COptimizer::COptimizer(string p_fileName, string p_pythonPath = NULL) :
 | 
						|
   m_fileName(p_fileName),
 | 
						|
   m_totalTasks(0) {
 | 
						|
// Передаём путь к интерпретатору объекту задачи оптимизации
 | 
						|
   m_task = new COptimizerTask(p_fileName, p_pythonPath);
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Деструктор                                                      |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
COptimizer::~COptimizer() {
 | 
						|
// Если есть задача оптимизации, то останавливаем и удаляем её
 | 
						|
   if (!!m_task) {
 | 
						|
      if(m_task.Id()) m_task.Stop();
 | 
						|
      delete m_task;
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Получение количества задач с заданным статусом                   |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
int COptimizer::TotalTasks() {
 | 
						|
// Результат
 | 
						|
   int res = 0;
 | 
						|
 | 
						|
// Запрос на получение количества задач с заданным статусом
 | 
						|
   string query = "SELECT COUNT(*)"
 | 
						|
                  "  FROM tasks t"
 | 
						|
                  "       JOIN"
 | 
						|
                  "       jobs j ON t.id_job = j.id_job"
 | 
						|
                  "       JOIN"
 | 
						|
                  "       stages s ON j.id_stage = s.id_stage"
 | 
						|
                  " WHERE t.status IN ('Queued', 'Process') "
 | 
						|
                  " ORDER BY s.id_stage, j.id_job, t.status LIMIT 1;";
 | 
						|
 | 
						|
// Открываем базу данных
 | 
						|
   if(DB::Connect(m_fileName)) {
 | 
						|
      // Выполняем запрос
 | 
						|
      int request = DatabasePrepare(DB::Id(), query);
 | 
						|
 | 
						|
      // Если нет ошибки
 | 
						|
      if(request != INVALID_HANDLE) {
 | 
						|
         // Структура данных для чтения одной строки результата запроса
 | 
						|
         struct Row {
 | 
						|
            int      count;
 | 
						|
         } row;
 | 
						|
 | 
						|
         // Читаем данные из первой строки результата
 | 
						|
         if(DatabaseReadBind(request, row)) {
 | 
						|
            res = row.count;
 | 
						|
         } else {
 | 
						|
            // Сообщаем об ошибке при необходимости
 | 
						|
            PrintFormat(__FUNCTION__" | ERROR: Reading row for request \n%s\nfailed with code %d",
 | 
						|
                        query, GetLastError());
 | 
						|
         }
 | 
						|
      } else {
 | 
						|
         // Сообщаем об ошибке при необходимости
 | 
						|
         PrintFormat(__FUNCTION__" | ERROR: Request \n%s\nfailed with code %d", query, GetLastError());
 | 
						|
      }
 | 
						|
 | 
						|
      // Закрываем базу данных
 | 
						|
      DB::Close();
 | 
						|
   }
 | 
						|
 | 
						|
   return res;
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Получение идентификатора следующей задачи оптимизации из очереди |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
ulong COptimizer::GetNextTaskId() {
 | 
						|
// Результат
 | 
						|
   ulong res = 0;
 | 
						|
 | 
						|
// Запрос на получение очередной задачи оптимизации из очереди
 | 
						|
   string query = "SELECT t.id_task"
 | 
						|
                  "  FROM tasks t "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       jobs j ON j.id_job = t.id_job "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       stages s ON s.id_stage = j.id_stage "
 | 
						|
                  "       LEFT JOIN "
 | 
						|
                  "       stages ps ON ps.id_stage = s.id_parent_stage "
 | 
						|
                  "       JOIN "
 | 
						|
                  "       projects p ON p.id_project = s.id_project "
 | 
						|
                  " WHERE t.id_task > 0 AND "
 | 
						|
                  "       t.status IN ('Queued', 'Process') AND "
 | 
						|
                  "       (ps.id_stage IS NULL OR "
 | 
						|
                  "        ps.status = 'Done') "
 | 
						|
                  " ORDER BY j.id_stage, "
 | 
						|
                  "          j.id_job, "
 | 
						|
                  "          t.status, "
 | 
						|
                  "          t.id_task"
 | 
						|
                  " LIMIT 1;";
 | 
						|
 | 
						|
// Открываем базу данных
 | 
						|
   if(DB::Connect(m_fileName)) {
 | 
						|
      // Выполняем запрос
 | 
						|
      int request = DatabasePrepare(DB::Id(), query);
 | 
						|
 | 
						|
      // Если нет ошибки
 | 
						|
      if(request != INVALID_HANDLE) {
 | 
						|
         // Структура данных для чтения одной строки результата запроса
 | 
						|
         struct Row {
 | 
						|
            ulong    id_task;
 | 
						|
         } row;
 | 
						|
 | 
						|
         // Читаем данные из первой строки результата
 | 
						|
         if(DatabaseReadBind(request, row)) {
 | 
						|
            res = row.id_task;
 | 
						|
         } else {
 | 
						|
            // Сообщаем об ошибке при необходимости
 | 
						|
            PrintFormat(__FUNCTION__" | ERROR: Reading row for request \n%s\nfailed with code %d",
 | 
						|
                        query, GetLastError());
 | 
						|
         }
 | 
						|
      } else {
 | 
						|
         // Сообщаем об ошибке при необходимости
 | 
						|
         PrintFormat(__FUNCTION__" | ERROR: request \n%s\nfailed with code %d", query, GetLastError());
 | 
						|
      }
 | 
						|
 | 
						|
      // Закрываем базу данных
 | 
						|
      DB::Close();
 | 
						|
   }
 | 
						|
 | 
						|
   return res;
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Основной метод обработки                                         |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
void COptimizer::Process() {
 | 
						|
   if(m_task.Id()) {
 | 
						|
      PrintFormat(__FUNCTION__" | Current Task ID = %d", m_task.Id());
 | 
						|
   }
 | 
						|
 | 
						|
   // Если текущая задача завершена, то
 | 
						|
   if (m_task.IsDone()) {
 | 
						|
      // Если текущая задача не пустая, то
 | 
						|
      if(m_task.Id()) {
 | 
						|
         // Звершаем текущую задачу
 | 
						|
         m_task.Finish();
 | 
						|
      }
 | 
						|
 | 
						|
      // Получаем количество задач в очереди
 | 
						|
      m_totalTasks = TotalTasks();
 | 
						|
 | 
						|
      // Если задачи есть, то
 | 
						|
      if(m_totalTasks) {
 | 
						|
         // Получаем идентификатор очередной текущей задачи
 | 
						|
         ulong taskId = GetNextTaskId();
 | 
						|
 | 
						|
         // Загружаем параметры задачи оптимизации из базы данных
 | 
						|
         m_task.Load(taskId);
 | 
						|
 | 
						|
         // Запускаем текущую задачу
 | 
						|
         m_task.Start();
 | 
						|
      }
 | 
						|
   }
 | 
						|
}
 | 
						|
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
//| Информация от текущем состоянии оптимизации                      |
 | 
						|
//+------------------------------------------------------------------+
 | 
						|
string COptimizer::Text(void) {
 | 
						|
   string text = "";
 | 
						|
 | 
						|
   // Получим количество проектов с разными статусами
 | 
						|
   DB::Connect(m_fileName);
 | 
						|
   int process_projects_count = (int) DB::GetValue("SELECT count(status) FROM projects WHERE status = 'Process'");
 | 
						|
   int queued_projects_count = (int) DB::GetValue("SELECT count(status) FROM projects WHERE status = 'Queued'");
 | 
						|
   int done_projects_count = (int) DB::GetValue("SELECT count(status) FROM projects WHERE status = 'Done'");
 | 
						|
   int total_projects_count = process_projects_count + queued_projects_count + done_projects_count;
 | 
						|
   DB::Close();
 | 
						|
 | 
						|
   // Добавим это в текст сообщения
 | 
						|
   text += StringFormat("DB: %s | %d Projects (Process: %d, Queued: %d, Done: %d)\n",
 | 
						|
                        m_fileName,
 | 
						|
                        total_projects_count,
 | 
						|
                        process_projects_count,
 | 
						|
                        queued_projects_count,
 | 
						|
                        done_projects_count
 | 
						|
                       );
 | 
						|
 | 
						|
   // Если есть активный проект 
 | 
						|
   if(process_projects_count > 0) {
 | 
						|
      // Добавим в текст сообщения информацию о текущей задачи
 | 
						|
      text += m_task.Text();
 | 
						|
 | 
						|
      // И общее количество задач в очереди
 | 
						|
      if(m_totalTasks)
 | 
						|
         text += StringFormat(
 | 
						|
                    "Total tasks in queue: %d\n",
 | 
						|
                    m_totalTasks);
 | 
						|
   }
 | 
						|
 | 
						|
   return text;
 | 
						|
}
 | 
						|
//+------------------------------------------------------------------+
 |