Adwizard/Optimization/Optimizer.mqh
2025-04-11 13:28:40 +03:00

207 lines
15 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.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();
}
}
}
//+------------------------------------------------------------------+