//+------------------------------------------------------------------+ //| 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) { 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() { 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(); } // Получаем количество задач в очереди m_totalTasks = TotalTasks(); // Если задачи есть, то if(m_totalTasks) { // Получаем идентификатор очередной текущей задачи ulong taskId = GetNextTaskId(); // Загружаем параметры задачи оптимизации из базы данных m_task.Load(taskId); // Запускаем текущую задачу m_task.Start(); } else { // Если задач нет, то удаляем советник с графика PrintFormat(__FUNCTION__" | Finish.", 0); //EventKillTimer(); //ExpertRemove(); } } } //+------------------------------------------------------------------+ //| | //+------------------------------------------------------------------+ string COptimizer::Text(void) { string text = ""; text += StringFormat("DB: %s | %d Projects (Process: %d, Queued: %d, Done: %d)\n", m_fileName, 19, 1, 5, 14); text += StringFormat("===============================================================\n" "PROJECT: %s %s\n%s\n\n", "SimpleCandles", "1.00", "2023.09.01 - 2024.01.01"); text += StringFormat( "Total tasks in queue: %d\n" "Current Task: %s", m_totalTasks, m_task.Text()); return text; } //+------------------------------------------------------------------+