Adwizard/Optimization/Optimizer.mqh

228 lines
16 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) {
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;
}
//+------------------------------------------------------------------+