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