228 lines
16 KiB
MQL5
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|