//+------------------------------------------------------------------+ //| 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.03" #include "OptimizerTask.mqh" //+------------------------------------------------------------------+ //| Класс для менеджера автоматической оптимизации проектов | //+------------------------------------------------------------------+ class COptimizer { string m_fileName; // Текущая задача оптимизации COptimizerTask *m_task; // Получение количества задач в очереди int TotalTasks(); // Получение идентификатора следующей задачи оптимизации из очереди ulong GetNextTaskId(); public: COptimizer(string p_fileName, string p_pythonPath = NULL); // Конструктор ~COptimizer(); void Process(); // Основной метод обработки }; //+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ COptimizer::COptimizer(string p_fileName, string p_pythonPath = NULL) : m_fileName(p_fileName) { // Передаём путь к интерпретатору объекту задачи оптимизации m_task = new COptimizerTask(p_fileName, p_pythonPath); } //+------------------------------------------------------------------+ //| Конструктор | //+------------------------------------------------------------------+ COptimizer::~COptimizer() { // Передаём путь к интерпретатору объекту задачи оптимизации if (!!m_task) delete m_task; Comment(""); } //+------------------------------------------------------------------+ //| Получение количества задач с заданным статусом | //+------------------------------------------------------------------+ 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() { PrintFormat(__FUNCTION__" | Current Task ID = %d", m_task.Id()); // Если советник остановлен, то удаляем таймер и самого советника с графика if (IsStopped()) { EventKillTimer(); ExpertRemove(); return; } // Если текущая задача завершена, то if (m_task.IsDone()) { // Если текущая задача не пустая, то if(m_task.Id()) { // Звершаем текущую задачу m_task.Finish(); } // Получаем количество задач в очереди int totalTasks = TotalTasks(); // Если задачи есть, то if(totalTasks) { // Получаем идентификатор очередной текущей задачи ulong taskId = GetNextTaskId(); // Загружаем параметры задачи оптимизации из базы данных m_task.Load(taskId); // Запускаем текущую задачу m_task.Start(); // Выводим на график количество оставшихся задач и текущую задачу Comment(StringFormat( "Total tasks in queue: %d\n" "Current Task ID: %d", totalTasks, m_task.Id())); } else { // Если задач нет, то удаляем советник с графика PrintFormat(__FUNCTION__" | Finish.", 0); ExpertRemove(); } } } //+------------------------------------------------------------------+