Adwizard/Optimization/Optimizer.mqh
2025-09-25 09:26:09 +03:00

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;
}
//+------------------------------------------------------------------+