English 中文 Español Deutsch 日本語
preview
Торговый инструментарий MQL5 (Часть 8): Внедрение и использование EX5-библиотеки для управления историей в коде

Торговый инструментарий MQL5 (Часть 8): Внедрение и использование EX5-библиотеки для управления историей в коде

MetaTrader 5Трейдинг |
557 3
Wanateki Solutions LTD
Kelvin Muturi Muigua

Введение

В предыдущих статьях я подробно рассказал о разработке надежной и всеобъемлющей EX5-библиотеки для управления историей сделок, предназначенной для оптимизации взаимодействия с историей сделок в MetaTrader 5. Эта мощная библиотека позволяет без труда сканировать, извлекать, сортировать, классифицировать и фильтровать все типы истории сделок — будь то закрытые позиции, отложенные ордера или история сделок — непосредственно из вашего аккаунта MetaTrader 5. Опираясь на этот опыт, данная статья делает заключительный шаг, показывая, как эффективно интегрировать библиотеку History Manager в ваши проекты MQL5.

Я подробно расскажу о функциях, доступных в EX5-библиотеке, с четкими пояснениями и практическими примерами. Эти примеры из реальной жизни не только помогут вам понять, как работает каждая функция, но и продемонстрируют, как применять их в ваших торговых стратегиях или аналитических инструментах. Независимо от того, являетесь ли вы новичком, стремящимся улучшить свои навыки программирования, или опытным разработчиком, желающим оптимизировать свой рабочий процесс, это руководство предоставит вам знания и инструменты для использования всего потенциала библиотеки History Manager. К концу этой статьи вы сможете уверенно внедрить эту универсальную библиотеку и начать использовать ее возможности для более эффективного управления историей сделок, чем когда-либо прежде.

Преимущества использования History Manager в MQL5

Ниже перечислены основные преимущества интеграции History Manager в проекты MQL5:

  • Простой поиск данных: Библиотека предоставляет интуитивно понятные функции для получения данных об истории сделок, таких как сделки, ордера, позиции и отложенные ордера, с минимальным объемом кода. Это устраняет необходимость в сложном и повторяющемся коде.
  • Единый интерфейс: Все данные об истории торговых операций доступны через единый, согласованный интерфейс, что упрощает управление и анализ различных видов торговой деятельности.
  • Экономия времени: Благодаря вызовам функций в одну строку, вы можете быстро получить доступ к важным торговым данным, сократив время разработки и позволив себе сосредоточиться на реализации стратегии.
  • Автоматизированная обработка данных: Библиотека автоматизирует поиск, сортировку и фильтрацию истории сделок, оптимизируя рабочие процессы и повышая общую эффективность.
  • Безошибочная обработка данных: Библиотека обеспечивает точное извлечение данных об истории сделок, сводя к минимуму риск ошибок, которые могут возникнуть при ручном кодировании.
  • Полный охват данных: Библиотека предоставляет доступ ко всем типам истории сделок, от закрытых позиций до ожидающих исполнения ордеров, гарантируя, что ни никакие данные не будут упущены.
  • Подробная информация: Функции, подобные GetLastClosedPositionData(), GetLastFilledPendingOrderData() и GetLastClosedProfitablePositionData() среди прочего предоставляют подробную информацию о сделках, что позволяет проводить более глубокий анализ и принимать более обоснованные решения.
  • Настраиваемые фильтры: Вы можете сортировать историю сделок по символу, магическому числу или временному диапазону, что позволяет проводить целенаправленный анализ, адаптированный к вашим конкретным потребностям.
  • Простая реализация: Библиотека разработана для бесшовной интеграции в существующие проекты MQL5, требуя минимальной настройки и конфигурации.
  • Масштабируемость: Независимо от того, работаете ли вы над небольшим скриптом или крупномасштабной торговой системой, History Manager легко масштабируется в соответствии с вашими требованиями.
  • Адаптация под ваши потребности: Модульная конструкция библиотеки позволяет использовать только необходимые функции, что делает ее легко адаптируемой к различным торговым стилям и стратегиям.
  • Расширяемая функциональность: Разработчики могут использовать существующие функции библиотеки для создания индивидуальных решений, отвечающих уникальным требованиям к торговле.
  • Готовые решения: Используя встроенные функции библиотеки, вы можете значительно сократить время и затраты, связанные с разработкой собственных инструментов управления историей сделок.
  • Подходит для пользователей любого уровня подготовки: Независимо от того, являетесь ли вы начинающим или опытным разработчиком, простая структура библиотеки делает ее доступной для пользователей любого уровня подготовки.
  • Принятие решений на основе данных: Доступ к полной истории сделок позволяет принимать обоснованные решения при разработке или совершенствовании торговых стратегий.
  • Тестирование на истории: Используйте библиотеку для получения исторических данных о сделках для тестирования стратегий на исторических данных, чтобы убедиться в их надежности и устойчивости.
  • Чистый и читаемый код: Функции библиотеки разработаны для создания чистого, читаемого кода, что упрощает поддержку и обновление проектов.



Импорт и настройка библиотеки History Manager EX5.

Прежде чем начать использовать возможности библиотеки History Manager EX5, необходимо правильно импортировать и настроить библиотеку в вашем проекте MQL5. В этом разделе вы шаг за шагом пройдете весь процесс, что обеспечит плавную и беспроблемную настройку.

Для использования файла библиотеки HistoryManager.ex5 в ваших проектах MQL5, его необходимо загрузить и поместить в соответствующую директорию внутри папки установки MetaTrader 5. Запустите MetaEditor из терминала MetaTrader 5: "Сервис" > "Редактор MetaQuotes Language" или нажмите F4 и выполните следующие шаги:

  • Шаг 1. Создайте необходимые каталоги:

Внутри папки Libraries, расположенной в корневом каталоге MQL5, создайте следующие подкаталоги, если они еще не существуют: "\Wanateki\Toolkit\HistoryManager".
Полный путь к папке установки MQL5 должен выглядеть следующим образом: "MQL5\Libraries\Wanateki\Toolkit\HistoryManager".

  • Шаг 2. Скачайте исполняемый бинарный файл HistoryManager.ex5:

Прокрутите страницу до конца статьи, найдите прикрепленный файл HistoryManager.ex5 и загрузите его. Поместите файл в папку HistoryManager, которую вы создали в Step 1.
Структура директории библиотеки Libraries теперь должна выглядеть примерно так, как на изображении ниже:

Каталог для сохранения исполняемого файла библиотеки HistoryManager.ex5.

  • Шаг 3.  Создайте файл заголовка библиотеки:

1. В MetaEditor IDE запустите Мастер MQL, нажав кнопку меню "Создать".

Новый файл в Мастере MQL5


2. Выберите Include (*.mqh) и нажмите "Далее".

Настройка нового включаемого файла в Мастере MQL5

3. В окне общих свойств включаемого файла найдите параметр "Имя:". Удалите весь текст и введите следующий путь, чтобы указать каталог и имя для включаемого файла: Include\Wanateki\Toolkit\HistoryManager\HistoryManager.mqh

Настройка директории нового включаемого файла в Мастере MQL5

4. Нажмите "Готово", чтобы сгенерировать заголовочный файл библиотеки.



Введение заголовочного файла библиотеки управления историей (HistoryManager.mqh)

Теперь, когда мы успешно создали пустой файл include для HistoryManager.mqh, следующий шаг — заполнить заголовок библиотеки необходимыми компонентами, которые будут определять её функциональность. Это включает в себя добавление структур данных для эффективного управления и хранения информации, использование макродиректив для упрощения повторяющихся задач и повышения читаемости кода, а также импорт и объявление библиотечных функций, которые будут служить основными интерфейсами для взаимодействия с функционалом HistoryManager.ex5.

Вслед за #property link, мы начнем с объявления структур данных DealData, OrderData, PositionData и PendingOrderData в глобальном масштабе. Эти структуры будут отвечать за хранение различных свойств истории сделок и будут доступны из любой части нашего кода.

struct DealData
  {
  // Add all the DealData members here
  }
  
struct OrderData
  {
  // Add all the OrderData members here
  } 
  
struct PositionData
  {
  // Add all the PositionData members here
  }
  
struct PendingOrderData
  {
  // Add all the PendingOrderData members here
  }

Далее мы определим несколько констант или макросов для представления ключевых временных периодов в секундах. К ним относятся NOW, ONE_DAY (сейчас, один день), ONE_WEEK (одна неделя), ONE_MONTH (один месяц), ONE_YEAR (один год), EPOCH, TODAY, THIS_WEEK, THIS_MONTH (эпоха, сегодня, эта неделя, этот месяц) и THIS_YEAR (этот год), что упростит вычисления, связанные со временем, и улучшит читаемость кода.

#define NOW datetime(TimeCurrent())
#define ONE_DAY datetime(TimeCurrent() - PeriodSeconds(PERIOD_D1))
#define ONE_WEEK datetime(TimeCurrent() - PeriodSeconds(PERIOD_W1))
#define ONE_MONTH datetime(TimeCurrent() - PeriodSeconds(PERIOD_MN1))
#define ONE_YEAR datetime(TimeCurrent() - (PeriodSeconds(PERIOD_MN1) * 12))
#define EPOCH 0 // 1st Jan 1970
//--
#define TODAY 12
#define THIS_WEEK 13
#define THIS_MONTH 14
#define THIS_YEAR 15

Мы также создадим строковый макрос ALL_SYMBOLS для хранения пустой строки. Это послужит сигналом, указывающим на то, что мы хотим обработать указанную историю для всех символов. Кроме того, мы определим макросы целых чисел ALL_POSITIONS (все позиции), ALL_ORDERS (все ордера) и ALL_DEALS (все сделки). Это позволит нам определить типы ордеров, сделок и историю позиций, которые мы хотим обработать.

#define ALL_SYMBOLS ""
#define ALL_POSITIONS 1110
#define ALL_ORDERS 1111
#define ALL_DEALS 1112

Теперь, когда мы создали все необходимые структуры данных и определили директивы препроцессора или макросов, пора импортировать библиотеку HistoryManager.ex5. Для этого мы воспользуемся директивой #import, за которой следует путь к папке, где находится EX5-библиотека.

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"

После директивы #import мы добавим объявления функций библиотеки и завершим, вставив закрывающую директиву #import в качестве заключительной строки заголовочного файла HistoryManager.mqh.

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"
//--
void PrintDealsHistory(datetime fromDateTime, datetime toDateTime);
void PrintOrdersHistory(datetime fromDateTime, datetime toDateTime);
void PrintPositionsHistory(datetime fromDateTime, datetime toDateTime);
void PrintPendingOrdersHistory(datetime fromDateTime, datetime toDateTime);

//--
bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
//--

// Add all the other function declarations here...

#import

Ниже представлены основные фрагменты кода, составляющие включаемый файл HistoryManager.mqh. Этот заголовочный файл содержит все необходимые ресурсы для импорта и интеграции EX5-библиотеки History Manager5 в свои проекты MQL5. Включив его в начало исходного файла, вы получите доступ ко всем структурам данных и библиотечным функциям, что сделает их готовыми к немедленному использованию. Полный исходный файл HistoryManager.mqh прикреплен в конце статьи.

struct DealData
  {
   ulong             ticket;
   ulong             magic;
   ENUM_DEAL_ENTRY   entry;
   ENUM_DEAL_TYPE    type;
   ENUM_DEAL_REASON  reason;
   ulong             positionId;
   ulong             order;
   string            symbol;
   string            comment;
   double            volume;
   double            price;
   datetime          time;
   double            tpPrice;
   double            slPrice;
   double            commission;
   double            swap;
   double            profit;
  };  
//--
struct OrderData
  {
   datetime                timeSetup;
   datetime                timeDone;
   datetime                expirationTime;
   ulong                   ticket;
   ulong                   magic;
   ENUM_ORDER_REASON       reason;
   ENUM_ORDER_TYPE         type;
   ENUM_ORDER_TYPE_FILLING typeFilling;
   ENUM_ORDER_STATE        state;
   ENUM_ORDER_TYPE_TIME    typeTime;
   ulong                   positionId;
   ulong                   positionById;
   string                  symbol;
   string                  comment;
   double                  volumeInitial;
   double                  priceOpen;
   double                  priceStopLimit;
   double                  tpPrice;
   double                  slPrice;
  };
//--
struct PositionData
  {
   ENUM_POSITION_TYPE type;
   ulong              ticket;
   ENUM_ORDER_TYPE    initiatingOrderType;
   ulong              positionId;
   bool               initiatedByPendingOrder;
   ulong              openingOrderTicket;
   ulong              openingDealTicket;
   ulong              closingDealTicket;
   string             symbol;
   double             volume;
   double             openPrice;
   double             closePrice;
   datetime           openTime;
   datetime           closeTime;
   long               duration;
   double             commission;
   double             swap;
   double             profit;
   double             tpPrice;
   double             slPrice;
   int                tpPips;
   int                slPips;
   int                pipProfit;
   double             netProfit;
   ulong              magic;
   string             comment;
  };
//--
struct PendingOrderData
  {
   string                  symbol;
   ENUM_ORDER_TYPE         type;
   ENUM_ORDER_STATE        state;
   double                  priceOpen;
   double                  tpPrice;
   double                  slPrice;
   int                     tpPips;
   int                     slPips;
   ulong                   positionId;
   ulong                   ticket;
   datetime                timeSetup;
   datetime                expirationTime;
   datetime                timeDone;
   ENUM_ORDER_TYPE_TIME    typeTime;
   ulong                   magic;
   ENUM_ORDER_REASON       reason;
   ENUM_ORDER_TYPE_FILLING typeFilling;
   string                  comment;
   double                  volumeInitial;
   double                  priceStopLimit;
  };
//--
#define NOW datetime(TimeCurrent())
#define ONE_DAY datetime(TimeCurrent() - PeriodSeconds(PERIOD_D1))
#define ONE_WEEK datetime(TimeCurrent() - PeriodSeconds(PERIOD_W1))
#define ONE_MONTH datetime(TimeCurrent() - PeriodSeconds(PERIOD_MN1))
#define ONE_YEAR datetime(TimeCurrent() - (PeriodSeconds(PERIOD_MN1) * 12))
#define EPOCH 0 // 1st Jan 1970
//--
#define TODAY 12
#define THIS_WEEK 13
#define THIS_MONTH 14
#define THIS_YEAR 15
//--
#define ALL_SYMBOLS ""
#define ALL_POSITIONS 1110
#define ALL_ORDERS 1111
#define ALL_DEALS 1112
//--

#import "Wanateki/Toolkit/HistoryManager/HistoryManager.ex5"
//--
void PrintDealsHistory(datetime fromDateTime, datetime toDateTime);
void PrintOrdersHistory(datetime fromDateTime, datetime toDateTime);
void PrintPositionsHistory(datetime fromDateTime, datetime toDateTime);
void PrintPendingOrdersHistory(datetime fromDateTime, datetime toDateTime);

//--
bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime, string symbol, ulong magic);
//--

bool GetDealsData(DealData &dealsData[], datetime fromDateTime, datetime toDateTime);
bool GetOrdersData(OrderData &ordersData[], datetime fromDateTime, datetime toDateTime);
bool GetPositionsData(PositionData &positionsData[], datetime fromDateTime, datetime toDateTime);
bool GetPendingOrdersData(PendingOrderData &pendingOrdersData[], datetime fromDateTime, datetime toDateTime);

//--
bool GetAllDealsData(DealData &dealsData[]);
bool GetAllOrdersData(OrderData &ordersData[]);
bool GetAllPositionsData(PositionData &positionsData[]);
bool GetAllPendingOrdersData(PendingOrderData &pendingOrdersData[]);
//--
bool GetAllDealsData(DealData &dealsData[], string symbol, ulong magic);
bool GetAllOrdersData(OrderData &ordersData[], string symbol, ulong magic);
bool GetAllPositionsData(PositionData &positionsData[], string symbol, ulong magic);
bool GetAllPendingOrdersData(PendingOrderData &pendingOrdersData[], string symbol, ulong magic);

//--
bool GetLastClosedPositionData(PositionData &lastClosedPositionInfo);
bool LastClosedPositionType(ENUM_POSITION_TYPE &lastClosedPositionType);
bool LastClosedPositionVolume(double &lastClosedPositionVolume);
bool LastClosedPositionSymbol(string &lastClosedPositionSymbol);
bool LastClosedPositionTicket(ulong &lastClosedPositionTicket);
bool LastClosedPositionProfit(double &lastClosedPositionProfit);
bool LastClosedPositionNetProfit(double &lastClosedPositionNetProfit);
bool LastClosedPositionPipProfit(int &lastClosedPositionPipProfit);
bool LastClosedPositionClosePrice(double &lastClosedPositionClosePrice);
bool LastClosedPositionOpenPrice(double &lastClosedPositionOpenPrice);
bool LastClosedPositionSlPrice(double &lastClosedPositionSlPrice);
bool LastClosedPositionTpPrice(double &lastClosedPositionTpPrice);
bool LastClosedPositionSlPips(int &lastClosedPositionSlPips);
bool LastClosedPositionTpPips(int &lastClosedPositionTpPips);
bool LastClosedPositionOpenTime(datetime &lastClosedPositionOpenTime);
bool LastClosedPositionCloseTime(datetime &lastClosedPositionCloseTime);
bool LastClosedPositionSwap(double &lastClosedPositionSwap);
bool LastClosedPositionCommission(double &lastClosedPositionCommission);
bool LastClosedPositionInitiatedByPendingOrder(bool &lastClosedPositionInitiatedByPendingOrder);
bool LastClosedPositionInitiatingOrderType(ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType);
bool LastClosedPositionId(ulong &lastClosedPositionId);
bool LastClosedPositionOpeningOrderTicket(ulong &lastClosedPositionOpeningOrderTicket);
bool LastClosedPositionOpeningDealTicket(ulong &lastClosedPositionOpeningDealTicket);
bool LastClosedPositionClosingDealTicket(ulong &lastClosedPositionClosingDealTicket);
bool LastClosedPositionMagic(ulong &lastClosedPositionMagic);
bool LastClosedPositionComment(string &lastClosedPositionComment);
bool LastClosedPositionDuration(long &lastClosedPositionDuration);

//--
bool GetLastClosedProfitablePositionData(PositionData &lastClosedProfitablePositionInfo);
bool GetLastClosedLossPositionData(PositionData &lastClosedLossPositionData);

//--
bool GetLastFilledPendingOrderData(PendingOrderData &getLastFilledPendingOrderData);
bool LastFilledPendingOrderType(ENUM_ORDER_TYPE &lastFilledPendingOrderType);
bool LastFilledPendingOrderSymbol(string &lastFilledPendingOrderSymbol);
bool LastFilledPendingOrderTicket(ulong &lastFilledPendingOrderTicket);
bool LastFilledPendingOrderPriceOpen(double &lastFilledPendingOrderPriceOpen);
bool LastFilledPendingOrderSlPrice(double &lastFilledPendingOrderSlPrice);
bool LastFilledPendingOrderTpPrice(double &lastFilledPendingOrderTpPrice);
bool LastFilledPendingOrderSlPips(int &lastFilledPendingOrderSlPips);
bool LastFilledPendingOrderTpPips(int &lastFilledPendingOrderTpPips);
bool LastFilledPendingOrderTimeSetup(datetime &lastFilledPendingOrderTimeSetup);
bool LastFilledPendingOrderTimeDone(datetime &lastFilledPendingOrderTimeDone);
bool LastFilledPendingOrderExpirationTime(datetime &lastFilledPendingOrderExpirationTime);
bool LastFilledPendingOrderPositionId(ulong &lastFilledPendingOrderPositionId);
bool LastFilledPendingOrderMagic(ulong &lastFilledPendingOrderMagic);
bool LastFilledPendingOrderReason(ENUM_ORDER_REASON &lastFilledPendingOrderReason);
bool LastFilledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling);
bool LastFilledPendingOrderTypeTime(datetime &lastFilledPendingOrderTypeTime);
bool LastFilledPendingOrderComment(string &lastFilledPendingOrderComment);

//--
bool GetLastCanceledPendingOrderData(PendingOrderData &getLastCanceledPendingOrderData);
bool LastCanceledPendingOrderType(ENUM_ORDER_TYPE &lastCanceledPendingOrderType);
bool LastCanceledPendingOrderSymbol(string &lastCanceledPendingOrderSymbol);
bool LastCanceledPendingOrderTicket(ulong &lastCanceledPendingOrderTicket);
bool LastCanceledPendingOrderPriceOpen(double &lastCanceledPendingOrderPriceOpen);
bool LastCanceledPendingOrderSlPrice(double &lastCanceledPendingOrderSlPrice);
bool LastCanceledPendingOrderTpPrice(double &lastCanceledPendingOrderTpPrice);
bool LastCanceledPendingOrderSlPips(int &lastCanceledPendingOrderSlPips);
bool LastCanceledPendingOrderTpPips(int &lastCanceledPendingOrderTpPips);
bool LastCanceledPendingOrderTimeSetup(datetime &lastCanceledPendingOrderTimeSetup);
bool LastCanceledPendingOrderTimeDone(datetime &lastCanceledPendingOrderTimeDone);
bool LastCanceledPendingOrderExpirationTime(datetime &lastCanceledPendingOrderExpirationTime);
bool LastCanceledPendingOrderPositionId(ulong &lastCanceledPendingOrderPositionId);
bool LastCanceledPendingOrderMagic(ulong &lastCanceledPendingOrderMagic);
bool LastCanceledPendingOrderReason(ENUM_ORDER_REASON &lastCanceledPendingOrderReason);
bool LastCanceledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling);
bool LastCanceledPendingOrderTypeTime(datetime &lastCanceledPendingOrderTypeTime);
bool LastCanceledPendingOrderComment(string &lastCanceledPendingOrderComment);

//*
//--
bool GetLastClosedPositionData(PositionData &lastClosedPositionInfo, string symbol, ulong magic);
bool LastClosedPositionType(ENUM_POSITION_TYPE &lastClosedPositionType, string symbol, ulong magic);
bool LastClosedPositionVolume(double &lastClosedPositionVolume, string symbol, ulong magic);
bool LastClosedPositionSymbol(string &lastClosedPositionSymbol, string symbol, ulong magic);
bool LastClosedPositionTicket(ulong &lastClosedPositionTicket, string symbol, ulong magic);
bool LastClosedPositionProfit(double &lastClosedPositionProfit, string symbol, ulong magic);
bool LastClosedPositionNetProfit(double &lastClosedPositionNetProfit, string symbol, ulong magic);
bool LastClosedPositionPipProfit(int &lastClosedPositionPipProfit, string symbol, ulong magic);
bool LastClosedPositionClosePrice(double &lastClosedPositionClosePrice, string symbol, ulong magic);
bool LastClosedPositionOpenPrice(double &lastClosedPositionOpenPrice, string symbol, ulong magic);
bool LastClosedPositionSlPrice(double &lastClosedPositionSlPrice, string symbol, ulong magic);
bool LastClosedPositionTpPrice(double &lastClosedPositionTpPrice, string symbol, ulong magic);
bool LastClosedPositionSlPips(int &lastClosedPositionSlPips, string symbol, ulong magic);
bool LastClosedPositionTpPips(int &lastClosedPositionTpPips, string symbol, ulong magic);
bool LastClosedPositionOpenTime(datetime &lastClosedPositionOpenTime, string symbol, ulong magic);
bool LastClosedPositionCloseTime(datetime &lastClosedPositionCloseTime, string symbol, ulong magic);
bool LastClosedPositionSwap(double &lastClosedPositionSwap, string symbol, ulong magic);
bool LastClosedPositionCommission(double &lastClosedPositionCommission, string symbol, ulong magic);
bool LastClosedPositionInitiatingOrderType(ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType, string symbol, ulong magic);
bool LastClosedPositionId(ulong &lastClosedPositionId, string symbol, ulong magic);
bool LastClosedPositionInitiatedByPendingOrder(bool &lastClosedPositionInitiatedByPendingOrder, string symbol, ulong magic);
bool LastClosedPositionOpeningOrderTicket(ulong &lastClosedPositionOpeningOrderTicket, string symbol, ulong magic);
bool LastClosedPositionOpeningDealTicket(ulong &lastClosedPositionOpeningDealTicket, string symbol, ulong magic);
bool LastClosedPositionClosingDealTicket(ulong &lastClosedPositionClosingDealTicket, string symbol, ulong magic);
bool LastClosedPositionMagic(ulong &lastClosedPositionMagic, string symbol, ulong magic);
bool LastClosedPositionComment(string &lastClosedPositionComment, string symbol, ulong magic);
bool LastClosedPositionDuration(long &lastClosedPositionDuration, string symbol, ulong magic);

//--
bool GetLastClosedProfitablePositionData(PositionData &lastClosedProfitablePositionInfo, string symbol, ulong magic);
bool GetLastClosedLossPositionData(PositionData &lastClosedLossPositionData, string symbol, ulong magic);

//--
bool GetLastFilledPendingOrderData(PendingOrderData &lastFilledPendingOrderData, string symbol, ulong magic);
bool LastFilledPendingOrderType(ENUM_ORDER_TYPE &lastFilledPendingOrderType, string symbol, ulong magic);
bool LastFilledPendingOrderSymbol(string &lastFilledPendingOrderSymbol, string symbol, ulong magic);
bool LastFilledPendingOrderTicket(ulong &lastFilledPendingOrderTicket, string symbol, ulong magic);
bool LastFilledPendingOrderPriceOpen(double &lastFilledPendingOrderPriceOpen, string symbol, ulong magic);
bool LastFilledPendingOrderSlPrice(double &lastFilledPendingOrderSlPrice, string symbol, ulong magic);
bool LastFilledPendingOrderTpPrice(double &lastFilledPendingOrderTpPrice, string symbol, ulong magic);
bool LastFilledPendingOrderSlPips(int &lastFilledPendingOrderSlPips, string symbol, ulong magic);
bool LastFilledPendingOrderTpPips(int &lastFilledPendingOrderTpPips, string symbol, ulong magic);
bool LastFilledPendingOrderTimeSetup(datetime &lastFilledPendingOrderTimeSetup, string symbol, ulong magic);
bool LastFilledPendingOrderTimeDone(datetime &lastFilledPendingOrderTimeDone, string symbol, ulong magic);
bool LastFilledPendingOrderExpirationTime(datetime &lastFilledPendingOrderExpirationTime, string symbol, ulong magic);
bool LastFilledPendingOrderPositionId(ulong &lastFilledPendingOrderPositionId, string symbol, ulong magic);
bool LastFilledPendingOrderMagic(ulong &lastFilledPendingOrderMagic, string symbol, ulong magic);
bool LastFilledPendingOrderReason(ENUM_ORDER_REASON &lastFilledPendingOrderReason, string symbol, ulong magic);
bool LastFilledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling, string symbol, ulong magic);
bool LastFilledPendingOrderTypeTime(datetime &lastFilledPendingOrderTypeTime, string symbol, ulong magic);
bool LastFilledPendingOrderComment(string &lastFilledPendingOrderComment, string symbol, ulong magic);

//--
bool GetLastCanceledPendingOrderData(PendingOrderData &lastCanceledPendingOrderData, string symbol, ulong magic);
bool LastCanceledPendingOrderType(ENUM_ORDER_TYPE &lastCanceledPendingOrderType, string symbol, ulong magic);
bool LastCanceledPendingOrderSymbol(string &lastCanceledPendingOrderSymbol, string symbol, ulong magic);
bool LastCanceledPendingOrderTicket(ulong &lastCanceledPendingOrderTicket, string symbol, ulong magic);
bool LastCanceledPendingOrderPriceOpen(double &lastCanceledPendingOrderPriceOpen, string symbol, ulong magic);
bool LastCanceledPendingOrderSlPrice(double &lastCanceledPendingOrderSlPrice, string symbol, ulong magic);
bool LastCanceledPendingOrderTpPrice(double &lastCanceledPendingOrderTpPrice, string symbol, ulong magic);
bool LastCanceledPendingOrderSlPips(int &lastCanceledPendingOrderSlPips, string symbol, ulong magic);
bool LastCanceledPendingOrderTpPips(int &lastCanceledPendingOrderTpPips, string symbol, ulong magic);
bool LastCanceledPendingOrderTimeSetup(datetime &lastCanceledPendingOrderTimeSetup, string symbol, ulong magic);
bool LastCanceledPendingOrderTimeDone(datetime &lastCanceledPendingOrderTimeDone, string symbol, ulong magic);
bool LastCanceledPendingOrderExpirationTime(datetime &lastCanceledPendingOrderExpirationTime, string symbol, ulong magic);
bool LastCanceledPendingOrderPositionId(ulong &lastCanceledPendingOrderPositionId, string symbol, ulong magic);
bool LastCanceledPendingOrderMagic(ulong &lastCanceledPendingOrderMagic, string symbol, ulong magic);
bool LastCanceledPendingOrderReason(ENUM_ORDER_REASON &lastCanceledPendingOrderReason, string symbol, ulong magic);
bool LastCanceledPendingOrderTypeFilling(ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling, string symbol, ulong magic);
bool LastCanceledPendingOrderTypeTime(datetime &lastCanceledPendingOrderTypeTime, string symbol, ulong magic);
bool LastCanceledPendingOrderComment(string &lastCanceledPendingOrderComment, string symbol, ulong magic);

//--
string BoolToString(bool boolVariable);
datetime GetPeriodStart(int periodType);

#import
//+------------------------------------------------------------------+



Практическая реализация и обзор EX5-библиотеки History Manager

Теперь мы рассмотрим функции библиотеки, сгруппировав их по соответствующим категориям для большей ясности и удобства использования. Попутно мы опишем их роли и приведем простые примеры использования, чтобы продемонстрировать, как их можно применять для выполнения различных задач.

1. Отображение истории сделок за определенный период времени

Эти функции позволяют выводить историю сделок непосредственно в журнал терминала MetaTrader 5, что удобно для быстрого доступа и отладки. Они относятся к типу void, то есть не возвращают никаких значений и принимают два параметра типа datetime, используемых для указания временного диапазона обрабатываемой истории:

Определение прототипа функции Описание Пример использования
void PrintDealsHistory(
   datetime fromDateTime,
   datetime toDateTime
);


Выводит информацию обо всех сделках за указанный период времени.
// Print the deals history for the last 24 hours (1 day)
PrintDealsHistory(ONE_DAY, NOW);
void PrintOrdersHistory(
   datetime fromDateTime,
   datetime toDateTime
);

Выводит информацию обо всех ордерах за указанный период времени.
// Print the orders history for the last 24 hours (1 day)
PrintOrdersHistory(ONE_DAY, NOW);


void PrintPositionsHistory(
   datetime fromDateTime,
   datetime toDateTime
);


Выводит информацию обо всех закрытых позициях за указанный период времени.
// Print the positions history for the last 24 hours (1 day)
PrintPositionsHistory(ONE_DAY, NOW);
void PrintPendingOrdersHistory(
   datetime fromDateTime,
   datetime toDateTime
);

Выводит информацию обо всех ожидающих обработки ордерах за указанный период времени.
// Print the pending orders history for the last 24 hours (1 day)
PrintPendingOrdersHistory(ONE_DAY, NOW);


2. Получение данных об истории сделок за указанный временной диапазон.

Эти функции позволяют программно получать данные истории сделок, отсортированные по символу и магическому числу за определенный период. Полученные данные сохраняются в массивах структур данных, что позволяет проводить дальнейший анализ или обработку:

Определение прототипа функции Описание Пример использования
bool GetDealsData(
   DealData &dealsData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


Эта функция выполняет поиск и извлечение данных о сделках в указанном временном диапазоне. Кроме того, она предоставляет возможность сортировки полученных данных по символу и магическому числу, что позволяет проводить более целенаправленную обработку.
// Print the total account net profit for the last 7 days
DealData dealsData[];
if(
   GetDealsData(
      dealsData,
      ONE_WEEK, NOW,
      ALL_SYMBOLS, 0
   ) &&
   ArraySize(dealsData) > 0
)
  {
   double totalGrossProfit = 0.0,
          totalSwap = 0.0,
          totalCommission = 0.0;
   int totalDeals = ArraySize(dealsData);
   for(int k = 0; k < totalDeals; k++)
     {
      if(dealsData[k].entry == DEAL_ENTRY_OUT)
        {
         totalGrossProfit += dealsData[k].profit;
         totalSwap += dealsData[k].swap;
         totalCommission += dealsData[k].commission;
        }
     }
   double totalExpenses = totalSwap + totalCommission;
   double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

   Print("-------------------------------------------------");
   Print(
      "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
      " [ 7 DAYS NET PROFIT ]"
   );
   Print(
      "Total Gross Profit: ",
      DoubleToString(totalGrossProfit, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Swap: ", DoubleToString(totalSwap, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Commission: ", DoubleToString(totalCommission, 2),
      " ", AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print(
      "Total Net Profit: ",
      DoubleToString(totalNetProfit, 2), " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
  }
bool GetOrdersData(
   OrderData &ordersData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция запрашивает и извлекает данные об ордерах в указанном временном диапазоне. Кроме того, предоставляется возможность сортировки полученных данных по символу и магическому числу.
// Print the total BUY Orders filled in the last 7 days
OrderData ordersData[];
if(
   GetOrdersData(ordersData, ONE_WEEK, NOW) &&
   ArraySize(ordersData) > 0
)
  {
   int totalBuyOrdersFilled = 0,
       totalOrders = ArraySize(ordersData);
   for(int w = 0; w < totalOrders; w++)
     {
      if(ordersData[w].type == ORDER_TYPE_BUY)
         ++totalBuyOrdersFilled;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print(totalBuyOrdersFilled, " BUY Orders Filled in the last 7 days!");
  }


bool GetPositionsData(
   PositionData &positionsData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


Функция выполняет поиск и извлечение данных об истории закрытых позиций в заданном временном диапазоне. Вы можете сортировать полученные данные по символу и магическому числу.
// Print total pips earned in last 24hrs for specified symbol and magic
string symbol = _Symbol;
long magic = 0;
PositionData positionsData[];
if(
   GetPositionsData(positionsData, ONE_DAY, NOW, symbol, magic) &&
   ArraySize(positionsData) > 0
)
  {
   int totalPipsEarned = 0,
       totalPositions = ArraySize(positionsData);
   for(int k = 0; k < totalPositions; k++)
     {
      totalPipsEarned += positionsData[k].pipProfit;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print(
      totalPipsEarned, " pips earned in the last 24hrs for ", symbol,
      " with magic no. ", magic
   );
  }

 
bool GetPendingOrdersData(
   PendingOrderData &pendingOrdersData[], // [out]
   datetime fromDateTime,
   datetime toDateTime,
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция получает данные по отложенным ордерам за указанный период времени. Также предоставляется возможность сортировки данных истории отложенных ордеров по символу и магическому числу.
// Print total number of buy and sell stops filled for symbol and magic
// in the last 7 days
string symbol = _Symbol;
long magic = 0;
PendingOrderData pendingOrdersData[];
if(
   GetPendingOrdersData(pendingOrdersData, ONE_WEEK, NOW, symbol, magic) &&
   ArraySize(pendingOrdersData) > 0
)
  {
   int totalBuyStopsFilled = 0, totalSellStopsFilled = 0,
       totalPendingOrders = ArraySize(pendingOrdersData);
   for(int k = 0; k < totalPendingOrders; k++)
     {
      if(pendingOrdersData[k].type == ORDER_TYPE_BUY_STOP)
         ++totalBuyStopsFilled;
      if(pendingOrdersData[k].type == ORDER_TYPE_SELL_STOP)
         ++totalSellStopsFilled;
     }
   Print("");
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN), ", Magic No = ", magic);
   Print(
      symbol, " --> Total Filled - (Buy Stops = ", totalBuyStopsFilled,
      ") (Sell Stops = ", totalSellStopsFilled, ") in the last 7 days."
   );
  }


3. Получение всех сделок на истории

Эти функции предоставляют комплексный способ получения всех доступных данных об истории сделок на счете, с возможностью добавления фильтров для символа и магического числа без необходимости ввода конкретного временного диапазона:

Определение прототипа функции
Описание
Пример использования
bool GetAllDealsData(
   DealData &dealsData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция извлекает все данные о сделках с возможностью сортировки истории сделок по символу и магическому числу.
// Find and list total deposited funds in the account
DealData dealsData[];
if(GetAllDealsData(dealsData) && ArraySize(dealsData) > 0)
  {
   double totalDeposits = 0.0;
   int totalDeals = ArraySize(dealsData);
   Print("");
   for(int k = 0; k < totalDeals; k++)
     {
      if(dealsData[k].type == DEAL_TYPE_BALANCE)
        {
         totalDeposits += dealsData[k].profit;
         Print(
            dealsData[k].profit, " ", AccountInfoString(ACCOUNT_CURRENCY),
            " --> Cash deposit on: ", dealsData[k].time
         );
        }
     }
   Print("-------------------------------------------------");
   Print(
      "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
      " Total Cash Deposits: ", totalDeposits, " ", 
      AccountInfoString(ACCOUNT_CURRENCY)
   );
  }

bool GetAllOrdersData(
   OrderData &ordersData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция извлекает все данные об ордерах, предоставляя при этом возможность сортировки истории ордеров по символу и магическому числу.
// Find if the account has ever gotten a Stop Out/Margin Call
OrderData ordersData[];
if(GetAllOrdersData(ordersData) && ArraySize(ordersData) > 0)
  {
   int totalStopOuts = 0;
   int totalOrders = ArraySize(ordersData);
   Print("");
   for(int k = 0; k < totalOrders; k++)
     {
      if(ordersData[k].reason == ORDER_REASON_SO)
        {
         ++totalStopOuts;
         Print(
            EnumToString(ordersData[k].type),
            " --> on: ", ordersData[k].timeDone
         );
        }
     }
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Total STOP OUT events: ", totalStopOuts);
  }

bool GetAllPositionsData(
   PositionData &positionsData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция получает все данные по истории позиций с возможностью сортировки данных о закрытых позициях по символу и магическому числу.
// Find the average trade duration in seconds
PositionData positionsData[];
if(GetAllPositionsData(positionsData) && ArraySize(positionsData) > 0)
  {
   long totalTradesDuration = 0; 
   int totalPositions = ArraySize(positionsData);
   Print("");
   for(int k = 0; k < totalPositions; k++)
     {
      totalTradesDuration += positionsData[k].duration;
     }
   long averageTradesDuration = totalTradesDuration / totalPositions;
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Average trade duration: ", averageTradesDuration, " seconds.");
  }

bool GetAllPendingOrdersData(
   PendingOrderData &pendingOrdersData[], // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция извлекает все данные по отложенным ордерам с возможностью сортировки истории отложенных ордеров по символу и магическому числу.
// Find the total expired pending orders in the account
PendingOrderData pendingOrdersData[];
if(GetAllPendingOrdersData(pendingOrdersData) && ArraySize(pendingOrdersData) > 0)
  {
   int totalExpiredPendingOrders = 0;
   int totalPendingOrders = ArraySize(pendingOrdersData);
   Print("");
   Print("-- EXPIRED PENDING ORDERS --");
   for(int k = 0; k < totalPendingOrders; k++)
     {
      if(pendingOrdersData[k].state == ORDER_STATE_EXPIRED)
        {
         ++totalExpiredPendingOrders;
         Print("Symbol = ", pendingOrdersData[k].symbol);
         Print("Time Setup = ", pendingOrdersData[k].timeSetup);
         Print("Ticket = ", pendingOrdersData[k].ticket);
         Print("Price Open = ", pendingOrdersData[k].priceOpen);
         Print(
            "SL Price = ", pendingOrdersData[k].slPrice,
            ", TP Price = ", pendingOrdersData[k].tpPrice
         );
         Print("Expiration Time = ", pendingOrdersData[k].expirationTime);
         Print("");
        }
     }
   Print("-------------------------------------------------");
   Print("Account No: ", AccountInfoInteger(ACCOUNT_LOGIN));
   Print("Total Expired Pending Orders: ", totalExpiredPendingOrders);
  }


4. Анализ последних закрытых позиций

Эти функции предназначены для получения исчерпывающей информации о недавно закрытых позициях, предоставляя данные о ключевых аспектах, таких как прибыль или убыток, торговый объем и время закрытия каждой позиции. Каждая функция играет уникальную роль, обеспечивая доступ ко всем важным аспектам вашей последней сделки. Функции также позволяют отсортировать данные по истории позиции по символу и магическому числу:

Определение прототипа функции
Описание
Пример использования
bool GetLastClosedPositionData(
   PositionData &lastClosedPositionInfo, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция получает полный снимок окончательной закрытой позиции, включая все соответствующие детали. Результаты можно сортировать по символу и магическому числу.
// Get the last closed position in the account
PositionData lastClosedPositionInfo;
if(
   GetLastClosedPositionData(lastClosedPositionInfo) &&
   lastClosedPositionInfo.ticket > 0
)
  {
   // Process the last closed position data
   Print("---LAST CLOSED POSITION--");
   Print("Symbol: ", lastClosedPositionInfo.symbol);
   Print("Type: ", EnumToString(lastClosedPositionInfo.type));
   Print("Open Time: ", lastClosedPositionInfo.openTime);
   Print("Close Time: ", lastClosedPositionInfo.closeTime);
   Print("Profit: ", lastClosedPositionInfo.profit);
   // Place more position properties analysis code....
  }
//-
// Get the last closed position for GBPUSD and magic 0
PositionData lastClosedPositionInfo;
string symbol = "GBPUSD";
if(
   GetLastClosedPositionData(lastClosedPositionInfo, symbol, 0) &&
   lastClosedPositionInfo.ticket > 0
)
  {
   // Process the last closed position data
   Print("---LAST CLOSED POSITION FOR ", symbol, " --");
   Print("Symbol: ", lastClosedPositionInfo.symbol);
   Print("Type: ", EnumToString(lastClosedPositionInfo.type));
   Print("Open Time: ", lastClosedPositionInfo.openTime);
   Print("Close Time: ", lastClosedPositionInfo.closeTime);
   Print("Profit: ", lastClosedPositionInfo.profit);
   // Place more position properties analysis code....
  }


bool LastClosedPositionType(
   ENUM_POSITION_TYPE &lastClosedPositionType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Эта функция показывает, была ли последняя позиция покупкой или продажей. Результаты можно сортировать по символу и магическому числу.
// Get the last closed position type in the account
ENUM_POSITION_TYPE lastClosedPositionType;
LastClosedPositionType(lastClosedPositionType);
Print(
   "Account's last closed position type: ",
   EnumToString(lastClosedPositionType)
);
//--
// Get the last closed position type for EURUSD and magic 0
ENUM_POSITION_TYPE lastClosedPositionType;
LastClosedPositionType(lastClosedPositionType, "EURUSD", 0);
Print(
   "EURUSD: last closed position type: ",
   EnumToString(lastClosedPositionType)
);

bool LastClosedPositionVolume(
   double &lastClosedPositionVolume, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция отображает торговый объем последней закрытой позиции. Функция также позволяет сортировать данные по символу и магическому числу.
// Get the last closed position volume in the account
double lastClosedPositionVolume;
LastClosedPositionVolume(lastClosedPositionVolume);
Print(
   "Account's last closed position volume: ",
   lastClosedPositionVolume
);
//--
// Get the last closed position volume for GBPUSD and magic 0
double lastClosedPositionVolume;
LastClosedPositionVolume(lastClosedPositionVolume, "GBPUSD", 0);
Print(
   "GBPUSD: last closed position volume: ",
   lastClosedPositionVolume
);

bool LastClosedPositionSymbol(
   string &lastClosedPositionSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция получает символ последней закрытой позиции. Результаты можно сортировать по символу и магическому числу.
// Get the last closed position's symbol in the account
string lastClosedPositionSymbol;
LastClosedPositionSymbol(lastClosedPositionSymbol);
Print(
   lastClosedPositionSymbol, " is the last closed position symbol ", 
   "in the account"
);
//--
// Get the last closed position's symbol for magic 0
string lastClosedPositionSymbol;
LastClosedPositionSymbol(lastClosedPositionSymbol, ALL_SYMBOLS, 0);
Print(
   lastClosedPositionSymbol, " is the last closed position symbol ",
   "for magic no: 0."
);

bool LastClosedPositionTicket(
   ulong &lastClosedPositionTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция извлекает номер тикета последней закрытой позиции. Результаты можно сортировать по символу и магическому числу.
// Get the last closed position's ticket in the account
long lastClosedPositionTicket;
LastClosedPositionTicket(lastClosedPositionTicket);
Print(
   "Account's last closed position's ticket: ",
   lastClosedPositionTicket
);
//--
// Get the last closed position's ticket for EURUSD and magic 0
long lastClosedPositionTicket;
LastClosedPositionTicket(lastClosedPositionTicket, "EURUSD", 0);
Print(
   "EURUSD: last closed position's ticket: ",
   lastClosedPositionTicket
);

bool LastClosedPositionProfit(
   double &lastClosedPositionProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция отображает валовую прибыль, полученную от последней сделки. Результаты можно сортировать по символу и магическому числу.
// Get the last closed position's profit in the account
double lastClosedPositionProfit;
LastClosedPositionProfit(lastClosedPositionProfit);
Print(
   "Account's last closed position's profit: ",
   lastClosedPositionProfit, " ", AccountInfoString(ACCOUNT_CURRENCY)
);
//--
// Get the last closed position's profit for EURUSD and magic 0
//double lastClosedPositionProfit;
LastClosedPositionProfit(lastClosedPositionProfit, "EURUSD", 0);
Print(
   "EURUSD: last closed position's profit: ",
   lastClosedPositionProfit, " ", AccountInfoString(ACCOUNT_CURRENCY)
);

Ниже перечислены оставшиеся функции библиотеки, отвечающие за получение свойств последней закрытой позиции. Для получения подробной информации о реализации обратитесь к приведенным выше примерам кода, включая такие функции, как LastClosedPositionVolume(), LastClosedPositionType() и другие, поскольку все они придерживаются схожего подхода.

Определение прототипа функции
Описание
bool LastClosedPositionNetProfit(
   double &lastClosedPositionNetProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Рассчитывает чистую прибыль от последней сделки с учетом свопов и комиссий. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionPipProfit(
   int &lastClosedPositionPipProfit, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает прибыль в пипсах для окончательной закрытой позиции. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionClosePrice(
   double &lastClosedPositionClosePrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает цену, по которой была закрыта позиция. Функция предоставляет возможность сортировки результатов по символу и магическому числу.
bool LastClosedPositionOpenPrice(
   double &lastClosedPositionOpenPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Показывает цену, по которой позиция была первоначально открыта. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionSlPrice(
   double &lastClosedPositionSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает цену стоп-лосса, установленную для последней закрытой позиции. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionTpPrice(
   double &lastClosedPositionTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Указывает цену тейк-профита, установленную для последней закрытой сделки. Также предусмотрена возможность сортировки данных по символу и магическому числу.
bool LastClosedPositionSlPips(
   int &lastClosedPositionSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Указывает расстояние стоп-лосса в пунктах для последней закрытой позиции. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionTpPips(
   int &lastClosedPositionTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Отображает расстояние фиксации прибыли в пипсах для последней закрытой сделки. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionOpenTime(
   datetime &lastClosedPositionOpenTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


Получает метку времени открытия последней закрытой позиции. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionCloseTime(
   datetime &lastClosedPositionCloseTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Указывает точное время закрытия последней закрытой позиции. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionSwap(
   double &lastClosedPositionSwap, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Отображает сумму свопа, связанную с последней закрытой позицией. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionCommission(
   double &lastClosedPositionCommission, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает комиссию, взимавшуюся за последнюю завершенную сделку. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionInitiatingOrderType(
   ENUM_ORDER_TYPE &lastClosedPositionInitiatingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Определяет тип ордера, который инициировал последнюю закрытую позицию. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionId(
   ulong &lastClosedPositionId, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает уникальный идентификатор последней закрытой позиции. Параметры символа и магического числа необязательны и требуются только в том случае, если необходимо отсортировать результаты.
bool LastClosedPositionInitiatedByPendingOrder(
   bool &lastClosedPositionInitiatedByPendingOrder, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);


Проверяет, была ли последняя закрытая позиция активирована или инициирована отложенным ордером. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionOpeningOrderTicket(
   ulong &lastClosedPositionOpeningOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Предоставляет номер тикета, по которому была открыта позиция. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionOpeningDealTicket(
   ulong &lastClosedPositionOpeningDealTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает номер тикета сделки, инициировавшей позицию. Результаты можно сортировать по символу и магическому числу.
bool LastClosedPositionClosingDealTicket(
   ulong &lastClosedPositionClosingDealTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает номер тикета сделки, в результате которой была закрыта позиция. Данные можно сортировать по символу и магическому числу.
bool LastClosedPositionMagic(
   ulong &lastClosedPositionMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Отображает магическое число, связанное с последней закрытой позицией. Результаты можно сортировать по символу и магическому числу.
 
bool LastClosedPositionComment(
   string &lastClosedPositionComment, // [Out]
   string symbol,  // Optional parameter
   ulong magic // Optional parameter
);

Извлекает все комментарии к последней закрытой сделке. Данные можно сортировать по символу и магическому числу.
 
bool LastClosedPositionDuration(
   long &lastClosedPositionDuration, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Вычисляет общую продолжительность (в секундах), в течение которой позиция оставалась открытой. Результаты можно сортировать по символу и магическому числу.


5. Анализ последних закрытых прибыльных и убыточных позиций.

Когда вам необходимо получить свойства последней закрытой прибыльной или убыточной позиции, библиотека History Manager предоставляет две специальные функции для этой задачи. Эти функции позволяют быстро получить доступ ко всей необходимой информации одним вызовом, что дает возможность проанализировать последнюю закрытую позицию с точки зрения ее прибыльности. Предоставляя важные данные, они помогают оценивать эффективность торговых операций и совершенствовать стратегии. Кроме того, предоставляется возможность сортировки полученных данных по конкретному символу и магическому числу, позволяя сосредоточиться на конкретных сделках и более эффективно оценивать эффективность отдельных стратегий или активов.

Определение прототипа функции Описание Пример использования
bool GetLastClosedProfitablePositionData(
   PositionData &lastClosedProfitablePositionInfo, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает подробную информацию и свойства последней закрытой позиции, которая была закрыта с прибылью. Функция также позволяет сортировать результаты по символу и магическому числу.
// Get the symbol, ticket, and net and pip profit of
// the last closed profitable position
PositionData lastClosedProfitablePosition;
if(
   GetLastClosedProfitablePositionData(lastClosedProfitablePosition) &&
   lastClosedProfitablePosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print(
      lastClosedProfitablePosition.symbol,
      " --> LAST CLOSED PROFITABLE POSITION"
   );
   Print("Ticket = ", lastClosedProfitablePosition.ticket);
   Print(
      "Net Profit = ", lastClosedProfitablePosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedProfitablePosition.pipProfit);
  }
//--
// Get the ticket, and net and pip profit of
// the last closed profitable position for EURUSD and magic 0
PositionData lastClosedProfitablePosition;
if(
   GetLastClosedProfitablePositionData(
      lastClosedProfitablePosition, "EURUSD", 0
   ) &&
   lastClosedProfitablePosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print("EURUSD --> LAST CLOSED PROFITABLE POSITION");
   Print("Ticket = ", lastClosedProfitablePosition.ticket);
   Print(
      "Net Profit = ", lastClosedProfitablePosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedProfitablePosition.pipProfit);
  }

bool GetLastClosedLossPositionData(
   PositionData &lastClosedLossPositionData,  // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает подробную информацию и свойства последней закрытой позиции, которая была закрыта или привела к убытку. Результаты можно сортировать по символу и магическому числу.
// Get the symbol, ticket, and net and pip profit of
// the last closed loss position
PositionData lastClosedLossPosition;
if(
   GetLastClosedLossPositionData(lastClosedLossPosition) &&
   lastClosedLossPosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print(
      lastClosedLossPosition.symbol,
      " --> LAST CLOSED LOSS POSITION"
   );
   Print("Ticket = ", lastClosedLossPosition.ticket);
   Print(
      "Net Profit = ", lastClosedLossPosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedLossPosition.pipProfit);
  }
//--
// Get the ticket, and net and pip profit of
// the last closed loss position for GBPUSD and magic 0
PositionData lastClosedLossPosition;
if(
   GetLastClosedLossPositionData(
      lastClosedLossPosition, "GBPUSD", 0
   ) &&
   lastClosedLossPosition.ticket > 0
)
  {
   Print("-------------------------------------------------");
   Print("GBPUSD --> LAST CLOSED LOSS POSITION");
   Print("Ticket = ", lastClosedLossPosition.ticket);
   Print(
      "Net Profit = ", lastClosedLossPosition.netProfit, " ",
      AccountInfoString(ACCOUNT_CURRENCY)
   );
   Print("Pip Profit = ", lastClosedLossPosition.pipProfit);
  }


6. Анализ последних выполненных и отмененных отложенных ордеров.

Библиотека предоставляет специализированные функции для получения подробной информации о последнем выполненном или отмененном отложенном ордере. Эти функции позволяют получить все необходимые сведения об ордере одним вызовом функции, что упрощает анализ исполнения или отмены отложенных ордеров. Предоставляя ключевые данные, они помогают оценивать эффективность обработки ордеров и исполнение сделок, а также корректировать торговые стратегии. Кроме того, эти функции предоставляют возможность сортировать результаты по определенному символу и магическому числу, позволяя сосредоточиться на конкретных ордерах и уточнить свой подход на основе точных исторических данных.

Поскольку функции последнего выполненного и отмененного отложенного ордера импортируются и реализуются с использованием того же подхода, что и функции, обрабатывающие исторические данные по последней закрытой позиции, я приведу только прототипы функций и их краткие описания. Если вам нужен пример реализации этих функций, обратитесь к разделу "Анализ последних закрытых позиций" выше.

Для получения полной информации о последнем исполненном отложенном ордере функция GetLastFilledPendingOrderData() извлекает все необходимые свойства, предоставляя полный обзор исполнения ордера. Если вам нужны только определенные атрибуты, следующие специализированные функции позволят вам извлечь отдельные сведения или свойства:

Определение прототипа функции Описание
bool GetLastFilledPendingOrderData(
   PendingOrderData &lastFilledPendingOrderData, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функция извлекает все соответствующие данные о последнем исполненном отложенном ордере, предоставляя полную картину того, как был исполнен ордер.
bool LastFilledPendingOrderType(
   ENUM_ORDER_TYPE &lastFilledPendingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает тип ордера, помогая определить, был ли это buy stop, sell limit или другой вариант отложенного ордера.
bool LastFilledPendingOrderSymbol(
   string &lastFilledPendingOrderSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Определяет торговый инструмент, позволяя сосредоточиться на ордерах, связанных с конкретным активом.
bool LastFilledPendingOrderTicket(
   ulong &lastFilledPendingOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Предоставляет уникальный тикет ордера, необходимый для ссылки или отслеживания конкретного выполненного ордера.
bool LastFilledPendingOrderPriceOpen(
   double &lastFilledPendingOrderPriceOpen, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает цену, по которой был исполнен ордер, что крайне важно для анализа условий входа.
bool LastFilledPendingOrderSlPrice(
   double &lastFilledPendingOrderSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTpPrice(
   double &lastFilledPendingOrderTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функции возвращают уровни стоп-лосса и тейк-профита соответственно, что позволяет оценить настройки управления рисками.
bool LastFilledPendingOrderSlPips(
   int &lastFilledPendingOrderSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTpPips(
   int &lastFilledPendingOrderTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Функции выражают расстояния стоп-лосса и тейк-профита в пунктах, что позволяет более наглядно оценить соотношение риска и прибыли по сделке.
bool LastFilledPendingOrderTimeSetup(
   datetime &lastFilledPendingOrderTimeSetup, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTimeDone(
   datetime &lastFilledPendingOrderTimeDone, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastFilledPendingOrderTimeSetup() указывает время размещения ордера, в то время как LastFilledPendingOrderTimeDone() указывает время исполнения. Это помогает анализировать промежуток времени между моментом создания отложенного ордера и моментом его срабатывания или исполнения.
bool LastFilledPendingOrderExpirationTime(
   datetime &lastFilledPendingOrderExpirationTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Проверяет и предоставляет время истечения срока действия, что полезно для торговых стратегий, чувствительных ко времени.
bool LastFilledPendingOrderPositionId(
   ulong &lastFilledPendingOrderPositionId, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает идентификатор позиции, который имеет решающее значение для привязки ордера к соответствующей позиции, обеспечивая точное отслеживание.
bool LastFilledPendingOrderMagic(
   ulong &lastFilledPendingOrderMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает магическое число, позволяющее сортировать ордера на основе автоматизированных стратегий или торговых ботов.
bool LastFilledPendingOrderReason(
   ENUM_ORDER_REASON &lastFilledPendingOrderReason, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Фиксирует причину исполнения, предоставляя информацию о процессе обработки ордеров, инициированном системой или выполненном вручную.
bool LastFilledPendingOrderTypeFilling(
   ENUM_ORDER_TYPE_FILLING &lastFilledPendingOrderTypeFilling, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastFilledPendingOrderTypeTime(
   datetime &lastFilledPendingOrderTypeTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastFilledPendingOrderTypeFilling() and LastFilledPendingOrderTypeTime() define the order filling method and time model, respectively, aiding in execution analysis.
bool LastFilledPendingOrderComment(
   string &lastFilledPendingOrderComment, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает все связанные комментарии к последнему исполненному отложенному ордеру, что может быть полезно для маркировки и классификации сделок.

Аналогично, если вам нужно проверить последний отмененный отложенный ордер, функция GetLastCanceledPendingOrderData() извлекает все данные за один вызов. В качестве альтернативы, вы можете извлечь отдельные свойства, используя следующие специализированные функции:

Определение прототипа функции Описание
bool GetLastCanceledPendingOrderData(
   PendingOrderData &lastCanceledPendingOrderData, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Эта функция предоставляет исчерпывающую информацию о последнем отмененном отложенном ордере, включая все его свойства и атрибуты.
bool LastCanceledPendingOrderType(
   ENUM_ORDER_TYPE &lastCanceledPendingOrderType, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает и указывает тип последнего отмененного отложенного ордера.
bool LastCanceledPendingOrderSymbol(
   string &lastCanceledPendingOrderSymbol, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает и идентифицирует торговый символ последнего отмененного отложенного ордера, что позволяет проводить целенаправленный анализ.
bool LastCanceledPendingOrderTicket(
   ulong &lastCanceledPendingOrderTicket, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Предоставляет уникальный номер тикета последнего отмененного отложенного ордера.
bool LastCanceledPendingOrderPriceOpen(
   double &lastCanceledPendingOrderPriceOpen, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает и сохраняет первоначальную предполагаемую цену входа последнего отмененного отложенного ордера.
bool LastCanceledPendingOrderSlPrice(
   double &lastCanceledPendingOrderSlPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTpPrice(
   double &lastCanceledPendingOrderTpPrice, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderSlPrice() and LastCanceledPendingOrderTpPrice() retrieve the mostly recently canceled pending order’s stop-loss and take-profit price levels.
bool LastCanceledPendingOrderSlPips(
   int &lastCanceledPendingOrderSlPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTpPips(
   int &lastCanceledPendingOrderTpPips, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderSlPips() and LastCanceledPendingOrderTpPips() express the last canceled pending order's stop-loss and take-profit distances in pips.
bool LastCanceledPendingOrderTimeSetup(
   datetime &lastCanceledPendingOrderTimeSetup, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTimeDone(
   datetime &lastCanceledPendingOrderTimeDone, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderTimeSetup() указывает время размещения последнего отмененного отложенного ордера, в то время как LastCanceledPendingOrderTimeDone() регистрирует время отмены.
bool LastCanceledPendingOrderExpirationTime(
   datetime &lastCanceledPendingOrderExpirationTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает и сохраняет время истечения отмененного отложенного ордера.
bool LastCanceledPendingOrderMagic(
   ulong &lastCanceledPendingOrderMagic, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает и сохраняет магическое число, связанное с последним отмененным отложенным ордером, что позволяет сортировать данные на основе автоматических идентификаторов стратегии.
bool LastCanceledPendingOrderReason(
   ENUM_ORDER_REASON &lastCanceledPendingOrderReason, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Получает причину отмены последнего отложенного ордера и позволяет определить, на какой платформе ордер был инициирован.
bool LastCanceledPendingOrderTypeFilling(
   ENUM_ORDER_TYPE_FILLING &lastCanceledPendingOrderTypeFilling, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);
bool LastCanceledPendingOrderTypeTime(
   datetime &lastCanceledPendingOrderTypeTime, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

LastCanceledPendingOrderTypeFilling() и LastCanceledPendingOrderTypeTime() получают и сохраняют настройки типа заполнения и времени для последнего отмененного отложенного ордера.
bool LastCanceledPendingOrderComment(
   string &lastCanceledPendingOrderComment, // [Out]
   string symbol, // Optional parameter
   ulong magic // Optional parameter
);

Извлекает все заданные пользователем комментарии, сохраненные при открытии последнего отмененного отложенного ордера, для отслеживания.


7. Вспомогательные функции
Определение прототипа функции Описание
string BoolToString(bool boolVariable);

Функция конвертирует логическое значение в строку (TRUE или FALSE) для более удобного чтения и журналирования.
 
datetime GetPeriodStart(int periodType);

Функция возвращает значение datetime для начала года, месяца, недели (начиная с воскресенья) или дня в зависимости от типа входных данных. Он принимает предопределенные макросы из заголовочного файла в качестве входных данных, а именно TODAY, THIS_WEEK, THIS_MONTH и THIS_YEAR. Функция упрощает получение даты и времени для этих периодов, позволяя сделать это с помощью одной строки кода.

В следующем разделе мы рассмотрим практические примеры, демонстрирующие, как библиотека History Management может быть использована для получения ценной торговой аналитики. Кроме того, мы разработаем советник, который будет использовать библиотеку истории для определения оптимального объема или лота и направления позиции при совершении новых сделок. Это позволит наглядно продемонстрировать, как исторические данные могут быть эффективно интегрированы в автоматизированные торговые системы, улучшая как выполнение стратегий, так и принятие решений.


Как рассчитать коэффициент прибыли, валовую прибыль/убыток и среднюю валовую прибыль и убыток по одной сделке для советника или торгового символа?

При оценке эффективности советника или торговой стратегии в MetaTrader 5 одним из наиболее важных показателей является коэффициент прибыли (Profit Factor). Это показатель, измеряющий валовую прибыль по отношению к валовому убытку за определенный период. Это позволяет наглядно оценить прибыльность торговой стратегии, сравнивая общую прибыль с общими убытками.

Высокий коэффициент прибыли указывает на то, что стратегия приносит больше прибыли по отношению к убыткам, что является желательным свойством для любой торговой системы. И наоборот, низкий коэффициент прибыли указывает на то, что стратегия может быть не столь эффективной и нуждаться в дальнейшей оптимизации.

Коэффициент прибыли рассчитывается по следующей формуле:
Profit Factor = Gross Profit / Gross Loss

где:

  • Gross Profit (валовая прибыль) - общая сумма, заработанная на всех прибыльных сделках.
  • Gross Loss (валовой убыток) - общая сумма денег, потерянных в результате всех убыточных сделок.

Коэффициент прибыли, превышающий 1, указывает на то, что стратегия является прибыльной, поскольку валовая прибыль превышает валовой убыток. Коэффициент прибыли, равный 1, означает, что валовая прибыль и валовой убыток равны, что указывает на безубыточность. Коэффициент прибыли меньше 1 указывает на то, что стратегия приносит убытки, поскольку валовой убыток превышает валовую прибыль.

Понимание и расчет коэффициента прибыли имеют решающее значение для трейдеров и разработчиков, позволяя им принимать обоснованные решения о жизнеспособности и эффективности своих торговых стратегий.

В этом примере я воспользуюсь библиотекой HistoryManager.ex5, чтобы показать, насколько легко реализовать этот расчет в вашем MQL5-коде.

Для начала создадим новый советник и назовем его GetProfitFactor.mq5. Сохраним его по следующему пути: Experts\Wanateki\HistoryManager\GetProfitFactor.mq5. Обратите внимание, что каталог, в котором вы сохраняете советника, имеет важное значение, поскольку он повлияет на путь, используемый для включения заголовочного файла, содержащего определения прототипов функций библиотеки.

Советник GetProfitFactor.mq5 поможет вам проанализировать эффективность ваших торговых стратегий, рассчитав ключевые показатели, такие как валовая прибыль, валовой убыток и коэффициент прибыли.

Во-первых, нам нужно включить библиотеку HistoryManager.ex5 и определить перечисление, которое мы будем использовать для ввода строкового значения символа в нашем советнике. Перечисление symbolName позволит нам указать, хотим ли мы анализировать текущий символ на графике или все символы на счете. Это перечисление вместе с параметром магического числа позволит нам отсортировать результаты в соответствии с целевыми символами и советниками.

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
//--
enum symbolName
  {
   CURRENT_CHART_SYMBOL,
   ALL_ACCOUNT_SYMBOLS,
  };

Далее мы определяем входные параметры для сортировки выходных данных.

//--- input parameters
input ulong  magicNo = 0;          //Magic Number (0 to disable)
input symbolName getSymbolName = ALL_ACCOUNT_SYMBOLS;

Мы инициализируем переменные, которые будут использоваться для хранения наших вычислений и отображения результатов.

string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
double totalGrossProfit = 0.0, totalGrossLoss = 0.0,
       averageGrossProfit = 0.0, averageGrossLoss = 0.0,
       averageProfitOrLossPerTrade = 0.0,
       profitFactor = 0.0;
int totalTrades = 0,
    totalLossPositions = 0, totalProfitPositions = 0;
string symbol, printedSymbol, profitFactorSummery,
       commentString;

В функции OnInit() мы будем использовать оператор switch для определения анализируемого символа. Как только символ определен, мы вызываем функцию CalcProfitFactor(), отвечающую за расчет коэффициента прибыли. В качестве первой задачи после загрузки советника мы отобразим все результаты на графике, используя функцию Comment().

int OnInit()
  {
//---
   switch(getSymbolName)
     {
      case CURRENT_CHART_SYMBOL:
         symbol = _Symbol;
         break;
      case ALL_ACCOUNT_SYMBOLS:
         symbol = ALL_SYMBOLS;
         break;
      default:
         symbol = ALL_SYMBOLS;
     }
   printedSymbol = symbol;
   if(symbol == "")
      printedSymbol = "ALL_SYMBOLS";
//--
   CalcProfitFactor();
   Comment(commentString);
//---
   return(INIT_SUCCEEDED);
  }

Прежде чем продолжить, введем функцию CalcProfitFactor(), поскольку она содержит большую часть кода, который управляет советником GetProfitFactor

Мы начнем реализацию функции CalcProfitFactor(), введя ее сигнатуру, а затем - вернув всем переменным их исходные значения. Это гарантирует, что любые предыдущие расчеты не будут мешать текущему анализу.

   totalGrossProfit = 0.0;
   totalGrossLoss = 0.0;
   averageProfitOrLossPerTrade = 0.0;
   averageGrossProfit = 0.0;
   averageGrossLoss = 0.0;
   profitFactor = 0.0;
   totalTrades = 0;
   totalLossPositions = 0;
   totalProfitPositions = 0;

Далее мы используем функцию GetAllPositionsData() для получения исторических данных о торговых операциях. Функция заполняет массив positionsData всеми торговыми позициями на основе указанных символаи магического числа. Аналогичным образом мы проверяем, возвращает ли функция true. Если размер массива превышает ноль, это гарантирует наличие корректных данных для обработки. Этот шаг необходим для получения требуемой торговой информации, которая потребуется для проведения расчетов.

if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      //--
     }

Затем мы проходим циклом по каждой сделке в массиве positionsData для расчета общей валовой прибыли и убытка. Для каждой сделки мы проверяем, превышает ли прибыль ноль, чтобы определить, является ли она прибыльной. Если это так, увеличиваем счетчик totalProfitPositions и добавляем прибыль к totalGrossProfit. Если прибыль меньше или равна нулю, мы увеличиваем счетчик totalLossPositions и добавляем абсолютное значение прибыли к totalGrossLoss. Этот цикл помогает нам суммировать прибыль и убытки от всех сделок.

      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalGrossProfit += positionsData[r].profit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalGrossLoss += MathAbs(positionsData[r].profit);
           }
        }
      // Calculate the profit factor and other data
      if(totalGrossProfit > 0 || totalGrossLoss > 0)
         averageProfitOrLossPerTrade = NormalizeDouble(
                                          (totalGrossProfit + totalGrossLoss) / totalTrades, 2
                                       );
      if(totalGrossProfit > 0)
         averageGrossProfit = NormalizeDouble(
                                 (totalGrossProfit / totalProfitPositions), 2
                              );
      if(totalGrossLoss > 0)
         averageGrossLoss = NormalizeDouble(
                               (totalGrossLoss / totalLossPositions), 2
                            );
      //--
      if(totalGrossLoss == 0.0)
         profitFactor = 0.0; // Avoid division by zero, indicating no losses
      profitFactor = totalGrossProfit / totalGrossLoss;
     }

После накопления общей валовой прибыли и убытка мы приступаем к расчету различных параметров. Сначала мы вычисляем среднюю прибыль или убыток по каждой сделке, разделив сумму общей валовой прибыли и убытка на общее количество сделок. Кроме того, затем мы рассчитываем среднюю валовую прибыль, деля общую валовую прибыль на количество прибыльных сделок. Аналогичным образом мы рассчитываем средний валовой убыток, деля общий валовой убыток на количество убыточных сделок. Наконец, мы рассчитываем коэффициент прибыльности, деля общую валовую прибыль на общий валовой убыток. Эти показатели дают всестороннее представление об эффективности торговой стратегии.

   profitFactorSummery = "Profit Factor = " + DoubleToString(profitFactor, 2);
   if(profitFactor > 2.0)
     {
      profitFactorSummery = profitFactorSummery +
                            "\nThe trading strategy is HIGHLY PROFITABLE and efficient.";
     }
   else
      if(profitFactor > 1.5)
        {
         profitFactorSummery = profitFactorSummery +
                               "\nThe trading strategy is profitable and well-balanced.";
        }
      else
         if(profitFactor > 1.0)
           {
            profitFactorSummery = profitFactorSummery +
                                  "\nThe trading strategy is slightly profitable but may need improvement.";
           }
         else
            if(profitFactor == 1.0)
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe strategy is break-even with no net gain or loss.";
              }
            else
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe trading strategy is unprofitable and needs optimization.";
              }

Мы анализируем фактор прибыльности, чтобы сгенерировать сводную строку, описывающую эффективность торговой стратегии. Вот как мы интерпретируем коэффициент прибыли:

  • Коэффициент прибыли > 2.0 - стратегия высокодоходна и эффективна.
  • Коэффициент прибыли 1.0 между 1.5 - стратегия приносит небольшую прибыль, но, возможно, нуждается в улучшении.
  • Коэффициент прибыли = 1.0 - стратегия обеспечивает безубыточность, то есть без чистой прибыли или убытка.
  • Коэффициент прибыли < 1.0 - стратегия убыточна и требует оптимизации.

Анализ коэффициентов прибыли позволяет быстро оценить общую эффективность торговой стратегии.

Наконец, мы вводим подробную строку comment (комментарий), содержащую все рассчитанные показатели и сводку коэффициентов прибыли. Строка отформатирована для отображения анализируемого символа, магического числа, общего количества сделок, количества прибыльных и убыточных сделок, общей валовой прибыли и убытка, средней прибыли или убытка на сделку, средней валовой прибыли и убытка, а также сводки коэффициентов прибыли.

Ниже представлена функция CalcProfitFactor() полностью со всеми сегментами кода на своих местах.

void CalcProfitFactor()
  {
   totalGrossProfit = 0.0;
   totalGrossLoss = 0.0;
   averageProfitOrLossPerTrade = 0.0;
   averageGrossProfit = 0.0;
   averageGrossLoss = 0.0;
   profitFactor = 0.0;
   totalTrades = 0;
   totalLossPositions = 0;
   totalProfitPositions = 0;
//--
   PositionData positionsData[];
   if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalGrossProfit += positionsData[r].profit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalGrossLoss += MathAbs(positionsData[r].profit);
           }
        }
      // Calculate the profit factor and other data
      if(totalGrossProfit > 0 || totalGrossLoss > 0)
         averageProfitOrLossPerTrade = NormalizeDouble(
                                          (totalGrossProfit + totalGrossLoss) / totalTrades, 2
                                       );
      if(totalGrossProfit > 0)
         averageGrossProfit = NormalizeDouble(
                                 (totalGrossProfit / totalProfitPositions), 2
                              );
      if(totalGrossLoss > 0)
         averageGrossLoss = NormalizeDouble(
                               (totalGrossLoss / totalLossPositions), 2
                            );
      //--
      if(totalGrossLoss == 0.0)
         profitFactor = 0.0; // Avoid division by zero, indicating no losses
      profitFactor = totalGrossProfit / totalGrossLoss;
     }

// Analyze the Profit Factor result
   profitFactorSummery = "Profit Factor = " + DoubleToString(profitFactor, 2);
   if(profitFactor > 2.0)
     {
      profitFactorSummery = profitFactorSummery +
                            "\nThe trading strategy is HIGHLY PROFITABLE and efficient.";
     }
   else
      if(profitFactor > 1.5)
        {
         profitFactorSummery = profitFactorSummery +
                               "\nThe trading strategy is profitable and well-balanced.";
        }
      else
         if(profitFactor > 1.0)
           {
            profitFactorSummery = profitFactorSummery +
                                  "\nThe trading strategy is slightly profitable but may need improvement.";
           }
         else
            if(profitFactor == 1.0)
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe strategy is break-even with no net gain or loss.";
              }
            else
              {
               profitFactorSummery = profitFactorSummery +
                                     "\nThe trading strategy is unprofitable and needs optimization.";
              }

   commentString =
      "\n\n-----------------------------------------------------------------------------------------------------" +
      "\n  HistoryManager.ex5 --- PROFIT FACTOR ANALYTICS ---" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n   -> Symbol   = " + printedSymbol +
      "\n   -> Magic No = " + IntegerToString(magicNo) +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n" + profitFactorSummery +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------" +
      "\n   -> Total Trades Analysed   = " + IntegerToString(totalTrades) +
      "\n   -> Total Profitable Trades = " + IntegerToString(totalProfitPositions) +
      "\n   -> Total Loss Trades       = " + IntegerToString(totalLossPositions) +
      "\n   --------------------------------------------------------" +
      "\n   -> Total Gross Profit = " + DoubleToString(totalGrossProfit, 2) + currency +
      "\n   -> Total Gross Loss   = -" + DoubleToString(totalGrossLoss, 2) + currency +
      "\n   ----------------------------------" +
      "\n   -> Total Gross (Profit - Loss) = " + DoubleToString(totalGrossProfit - totalGrossLoss, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n   -> Average Profit or Loss Per Trade = (-/+)" + DoubleToString(averageProfitOrLossPerTrade, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n   -> Average Gross Profit = " + DoubleToString(averageGrossProfit, 2) + currency +
      "\n   -> Average Gross Loss   = -" + DoubleToString(averageGrossLoss, 2) + currency +
      "\n   --------------------------------------------------------" +
      "\n-----------------------------------------------------------------------------------------------------";
//--
  }

Мы также помещаем эту функцию внутри стандартной функции OnTrade() для исполнения и перерасчета коэффициента прибыли после каждой торговой операции.

void OnTrade()
  {
//---
   CalcProfitFactor();
  }

Чтобы убедиться, что на графике отображаются актуальные данные, мы будем использовать функцию Comment() для вывода commentString. Здесь содержатся все данные о текущем обновленном коэффициенте прибыли. Коэффициент выводится после каждого нового тика в стандартной функции OnTick().

void OnTick()
  {
//---
   Comment(commentString);
  }

Вот результат работы советника GetProfitFactor в окне графика MetaTrader 5.

Советник GetProfitFactor на основе HistoryManager.ex5

Исходный файл GetProfitFactor.mq5 приложен в конце статьи.



Как рассчитать валовую и чистую прибыль за текущую неделю для конкретного советника или символа?

В этом примере мы создадим скрипт MQL5, который предоставит исчерпывающий обзор финансовых результатов за текущую неделю, включая валовую прибыль, свопы, комиссионные и чистую прибыль. Это поможет продемонстрировать, как можно использовать библиотеку History Manager для быстрой оценки еженедельной доходности всего счета, конкретного символа или магического числа советника непосредственно в терминале MetaTrader 5.

Начнем с создания нового скрипта под названием GetNetProfitThisWeek.mq5 и сохраним его в папке Scripts\Wanateki\HistoryManager\GetNetProfitThisWeek.mq5. В новом файле скрипта начнем с добавления библиотеки HistoryManager.mqh, которая предоставит доступ ко всем библиотечным функциям.

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>

Далее мы поместим весь наш код внутрь функции OnStart() для простоты понимания. Первая часть скрипта будет посвящена инициализации строковой переменной для хранения валюты счета. Это необходимо для форматирования выходных данных финансовых показателей.

string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);

Прежде чем приступать к каким-либо вычислениям, нам необходимо сначала рассчитать время начала текущей недели. Расчет упрощен, так как библиотека HistoryManager.ex5 содержит вспомогательную функцию GetPeriodStart(), которую мы будем использовать для получения значения datetime начала текущей недели. Чтобы получить это значение, нам достаточно вызвать функцию GetPeriodStart() с выходным параметром THIS_WEEK. Это поможет нам сортировать сделки, заключенные в течение текущей недели.

datetime thisWeekStartTime = GetPeriodStart(THIS_WEEK);

Мы объявляем массив для хранения данных о сделке и используем функцию GetDealsData() для ее заполнения сделками, заключенных в период с начала текущей недели до текущего времени (NOW). Аналогичным образом мы сортируем сделки по всем символам с магическим числом 0.

if(
      GetDealsData(
         dealsData,
         thisWeekStartTime, NOW,
         ALL_SYMBOLS, 0
      ) &&
      ArraySize(dealsData) > 0
   )

Мы инициализируем переменные для хранения итоговой валовой прибыли, суммарного свопа и комиссии. Эти переменные будут использоваться для накопления соответствующих значений из данных по сделке.

double totalGrossProfit = 0.0,
             totalSwap = 0.0,
             totalCommission = 0.0;

Мы проходим по каждой сделке в массиве dealsData. Для каждой сделки мы проверяем, является ли она закрывающей (DEAL_ENTRY_OUT). Если да, добавляем прибыль, своп и комиссию к их соответствующим суммарным переменным.

int totalDeals = ArraySize(dealsData);
for(int k = 0; k < totalDeals; k++)
  {
   if(dealsData[k].entry == DEAL_ENTRY_OUT)
     {
      totalGrossProfit += dealsData[k].profit;
      totalSwap += dealsData[k].swap;
      totalCommission += dealsData[k].commission;
     }
  }

рассчитываем общие расходы, суммируя их итоговые своп и комиссию. Затем мы вычисляем суммарную чистую прибыль путем вычитания общих расходов из суммарной валовой прибыли.

double totalExpenses = totalSwap + totalCommission;
double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

Используем функцию Print() для вывода результатов в журнал MetaTrader 5. Это включает в себя общую валовую прибыль, общую сумму свопов и комиссионных, а также общую чистую прибыль за текущую неделю. Кроме того, мы также используем функцию Comment() для отображения результатов непосредственно в окне графика. Они включают в себя подробную сводку финансовых показателей за текущую неделю.

HistoryManager.ex5 - Узнаем общую чистую прибыль за эту неделю

Ниже представлена полная функция OnStart() со всеми сегментами кода в правильной последовательности и в полном объеме.

void OnStart()
  {
//---
   string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
   datetime thisWeekStartTime = GetPeriodStart(THIS_WEEK);
   DealData dealsData[];
   if(
      GetDealsData(
         dealsData,
         thisWeekStartTime, NOW,
         ALL_SYMBOLS, 0
      ) &&
      ArraySize(dealsData) > 0
   )
     {
      double totalGrossProfit = 0.0,
             totalSwap = 0.0,
             totalCommission = 0.0;
      int totalDeals = ArraySize(dealsData);
      for(int k = 0; k < totalDeals; k++)
        {
         if(dealsData[k].entry == DEAL_ENTRY_OUT)
           {
            totalGrossProfit += dealsData[k].profit;
            totalSwap += dealsData[k].swap;
            totalCommission += dealsData[k].commission;
           }
        }
      double totalExpenses = totalSwap + totalCommission;
      double totalNetProfit = totalGrossProfit - MathAbs(totalExpenses);

      Print("-------------------------------------------------");
      Print(
         "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
         " [ THIS WEEK'S NET PROFIT ]"
      );
      Print(
         "Total Gross Profit This Week: ",
         DoubleToString(totalGrossProfit, 2),
         " ", currency
      );
      Print(
         "Total Swaps This Week: ", DoubleToString(totalSwap, 2),
         " ", currency
      );
      Print(
         "Total Commission This Week: ", DoubleToString(totalCommission, 2),
         " ", currency
      );
      Print(
         "Total Net Profit This Week: ",
         DoubleToString(totalNetProfit, 2), " ",
         currency
      );
      
     //--
     Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "-------------------------------------------------------------------" +
         "\n  HistoryManager.ex5 --- TOTAL NET PROFIT THIS WEEK ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n DATE = ( From: " + TimeToString(thisWeekStartTime) + ", to: " + TimeToString(NOW) + " )" +
         "\n Account No  = " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) +
         "\n------------------------------------------------------" +
         "\n   -> Total Gross Profit =  " + DoubleToString(totalGrossProfit, 2) +
         currency +
         "\n   -> Total Swaps        =  " + DoubleToString(totalSwap, 2) +
         currency +
         "\n   -> Total Commission   =  " + DoubleToString(totalCommission, 2) +
         currency +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n   -> TOTAL NET PROFIT   =  " + DoubleToString(totalNetProfit, 2) +
         currency +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +         
         "\n-----------------------------------------------------------------------------------------------------" +
         "-------------------------------------------------------------------"
      );
     }
  }

Чтобы получить полный исходный код скрипта, скачайте исходный файл GetNetProfitThisWeek.mq5, приложенный к статье.


Как рассчитать коэффициент прибыли/убытка в пипсах для конкретного символа или советника?

В этом примере мы рассмотрим, как рассчитать соотношение прибыли и убытков в пунктах для конкретного торгового символа или всего советника с помощью MQL5. Этот расчет является важнейшим инструментом для оценки эффективности торговой стратегии, поскольку он предоставляет четкий и поддающийся количественной оценке показатель, позволяющий определить, является ли стратегия прибыльной, безубыточной или убыточной в зависимости от полученных или потерянных пипсов. Предложенный код предназначен для анализа исторических данных о торговле, вычисления коэффициента и представления результатов в удобном и легко интерпретируемом формате.

Советник будет называться GetSymbolPipsProfitToLossRatio.mq5. Сохраним его в соответствующей папке и начнем с включения библиотеки HistoryManager.mqh - это первая и самая важная строка в нашем исходном файле. Далее создадим перечисление для хранения имени символа и определим входные параметры (символ и магическое число). Эти параметры позволят пользователю сортировать результаты анализа данных в соответствии со своими предпочтениями: хочет ли он анализировать все закрытые позиции для конкретного символа, закрытые позиции для конкретного символа, включающие определенное магическое число, или все позиции с определенным магическим числом, независимо от символа.

В функции OnInit() извлечем валюту счета и определим символ(ы) для анализа на основе данных, введенных пользователем. Если пользователь выбирает CURRENT_CHART_SYMBOL, наш советник сфокусируется на символе текущего графика. При выборе ALL_ACCOUNT_SYMBOLS, будут анализироваться все символы, торгуемые на счете.

Используем функцию GetAllPositionsData() для получения исторических данных о сделках для указанного символа (символов) и магического числа. Эти данные будут храниться в массиве структур PositionData. Аналогичным образом, мы затем пройдемся по массиву, чтобы классифицировать сделки как прибыльные или убыточные. В ходе этого процесса мы рассчитаем общее количество пипсов, полученных от прибыльных сделок (totalPipsProfit) и общее количество пипсов, потерянных из-за убыточных сделок (totalPipsLoss).

Для расчета коэффициент прибыли/убытка по пипсам, мы разделим общую сумму полученных пипсов на общую сумму потерянных пипсов. Кроме того, мы будем использовать абсолютное значение, чтобы гарантировать, что коэффициент всегда будет положительным. Если убыточных сделок нет (totalPipsLoss == 0), коэффициент не определен (undefined) и советник выдаст сообщение о том, что стратегия не имеет убыточных сделок. Советник интерпретирует коэффициент следующим образом:

  • Коэффициент > 1.0 - стратегия прибыльна, поскольку приносит больше пипсов, чем теряет.
  • Коэффициент == 1.0 - стратегия выходит в безубыток по пипсам.
  • Коэффициент < 1.0 - стратегия убыточна, так как теряет больше пипсов, чем зарабатывает.

Функция Comment() используется для отображения результатов анализа непосредственно на графике. В выходные данные будут включены: анализируемые символы, использованное магическое число (если есть), общее количество проанализированных сделок, количество прибыльных и убыточных сделок, а также общее количество полученных и потерянных пипсов, расчетное соотношение прибыли и убытков в пипсах и его интерпретация.

HistoryManager.ex5 Советник коэффициента прибыли/убытков в пипсах

С помощью функции OnDeinit() мы удалим комментарии к графику при удалении или деинициализации советника, обеспечивая чистоту рабочего пространства. Мы оставим функцию OnTick() пустой, поскольку анализ выполняется только один раз во время инициализации. Однако при необходимости эту функцию можно расширить для выполнения вычислений или обновлений в реальном времени.

Вот все представленные фрагменты кода в правильной последовательности:

//--
#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
//--
enum symbolName
  {
   CURRENT_CHART_SYMBOL,
   ALL_ACCOUNT_SYMBOLS,
  };
//--- input parameters
input ulong  magicNo = 0;          //Magic Number (0 to disable)
input symbolName getSymbolName = CURRENT_CHART_SYMBOL;
int OnInit()
  {
//---
   string currency = " " + AccountInfoString(ACCOUNT_CURRENCY);
   string symbol, printedSymbol;

   switch(getSymbolName)
     {
      case CURRENT_CHART_SYMBOL:
         symbol = _Symbol;
         break;
      case ALL_ACCOUNT_SYMBOLS:
         symbol = ALL_SYMBOLS;
         break;
      default:
         symbol = ALL_SYMBOLS;
     }
   printedSymbol = symbol;
   if(symbol == "")
      printedSymbol = "ALL_SYMBOLS";
//--
   int totalTrades = 0;
   int totalLossPositions = 0;
   int totalProfitPositions = 0;
   double totalPipsProfit = 0;
   double totalPipsLoss = 0;
   string interpretation;
   double pipsProfitToLossRatio = 0;
//--
   PositionData positionsData[];
   if(GetAllPositionsData(positionsData, symbol, magicNo) && ArraySize(positionsData) > 0)
     {
      totalTrades = ArraySize(positionsData);
      for(int r = 0; r < totalTrades; r++)
        {
         if(positionsData[r].profit > 0) // profitable trade
           {
            ++totalProfitPositions;
            totalPipsProfit += positionsData[r].pipProfit;
           }
         else  // loss trade
           {
            ++totalLossPositions;
            totalPipsLoss += positionsData[r].pipProfit;
           }
        }
      // Calculate the pip profit loss ratioInterpretation
      if(totalPipsLoss == 0)
        {
         interpretation = "Pips Profit-to-Loss Ratio: Undefined (Total pips loss is zero)." +
                          "The strategy has no losing trades.";
        }
      else
        {
         pipsProfitToLossRatio = fabs(totalPipsProfit / totalPipsLoss);

         switch(pipsProfitToLossRatio > 1.0 ? 1 : pipsProfitToLossRatio == 1.0 ? 0 : -1)
           {
            case 1:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy is profitable as it gains more pips than it loses.";
               break;
            case 0:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy breaks even in terms of pips.";
               break;
            case -1:
               interpretation = "Pips Profit-to-Loss Ratio: " + DoubleToString(pipsProfitToLossRatio, 2) +
                                ". The strategy is unprofitable as it loses more pips than it gains.";
               break;
           }
        }

      Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n  HistoryManager.ex5 --- PIPS PROFIT TO LOSS RATIO ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n   -> Symbol   = " + printedSymbol +
         "\n   -> Magic No = " + IntegerToString(magicNo) +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n" + interpretation +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------" +
         "\n   -> Total Trades Analysed     = " + IntegerToString(totalTrades) +
         "\n   -> Total Profitable Trades   = " + IntegerToString(totalProfitPositions) +
         " ( " + DoubleToString(totalPipsProfit, 0) + " Pips )" +
         "\n   -> Total Loss Trades         = " + IntegerToString(totalLossPositions) +
         " ( " + DoubleToString(totalPipsLoss, 0) + " Pips )" +
         "\n   --------------------------------------------------------------------------" +
         "\n   -> PIPS PROFIT TO LOSS RATIO = " + DoubleToString(pipsProfitToLossRatio, 2) +
         "\n   --------------------------------------------------------------------------" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------"
      );
     }

//---
   return(INIT_SUCCEEDED);
  }

Полная версия исходного файла GetSymbolPipsProfitToLossRatio.mq5 приложена к статье.


Как рассчитать общую сумму денежных средств на счете?

Мы создадим простой скрипт GetTotalDeposits.mq5, который использует функцию GetAllDealsData() из нашей библиотеки для получения и анализа данных о сделках, чтобы получить четкое представление об истории пополнения счета. Это ценный инструмент, который пригодится вам, если вы хотите алгоритмически отслеживать общий объем средств, внесенных на ваш торговый счет, проверять историю пополнения счета для целей учета или налогообложения, или просто проверять транзакции пополнения.

Мы будем использовать функцию GetAllDealsData() для получения всех исторических данных о сделках для данного аккаунта. Эти данные будут храниться в массиве структур DealData. Далее мы инициализируем переменную для хранения значения суммарного пополнения (total deposit) и проходимся по данным сделки. Чтобы определить транзакции пополнения убедимся, что тип сделки - DEAL_TYPE_BALANCE. Суммируем значения прибыли по этим сделкам, чтобы рассчитать общую сумму пополнений.

После того, как мы рассчитаем и сохраним все целевые данные, мы выведем общую сумму пополнений и отобразим ее на графике с помощью функции Comment(). Это обеспечивает удобный для пользователя обзор истории пополнения счета.

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
void OnStart()
  {
//---
// Find and list total deposited funds in the account
   DealData dealsData[];
   if(GetAllDealsData(dealsData) && ArraySize(dealsData) > 0)
     {
      double totalDeposits = 0.0;
      int totalDeals = ArraySize(dealsData);
      Print("");
      for(int k = 0; k < totalDeals; k++)
        {
         if(dealsData[k].type == DEAL_TYPE_BALANCE)
           {
            totalDeposits += dealsData[k].profit;
            Print(
               dealsData[k].profit, " ", AccountInfoString(ACCOUNT_CURRENCY),
               " --> Cash deposit on: ", dealsData[k].time
            );
           }
        }
      Print("-------------------------------------------------");
      Print(
         "Account No: ", AccountInfoInteger(ACCOUNT_LOGIN),
         " Total Cash Deposits: ", totalDeposits, " ",
         AccountInfoString(ACCOUNT_CURRENCY)
      );

      Comment(
         "\n\n-----------------------------------------------------------------------------------------------------" +
         "---------------------------------------------------------" +
         "\n  HistoryManager.ex5 --- TOTAL ACCOUNT DEPOSITS ---" +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------" +
         "\n   -> Account No  = " + IntegerToString(AccountInfoInteger(ACCOUNT_LOGIN)) +
         "\n   -> Total Cash Deposits =  " + DoubleToString(totalDeposits, 2) +
         AccountInfoString(ACCOUNT_CURRENCY) +
         "\n-----------------------------------------------------------------------------------------------------" +
         "------------------------------------------------------"
      );
     }
  }

Полная версия исходного файла GetTotalDeposits.mq5 приложена к статье.


Как создать советник, основанный на данных о ценах, использовав библиотеку History Manager EX5?

В качестве последнего примера в этой статье мы создадим простой, но мощный советник, основанный на данных о ценах, под названием PriceTrader_EA, работающий на базе библиотек PositionsManager.ex5 и HistoryManager.ex5. Советник обладает значительным потенциалом для получения прибыли, особенно при использовании на крупных счетах и после тщательного тестирования и оптимизации. Вы увидите, что исходный код PriceTrader_EA лаконичен и эффективен благодаря нашим предварительно разработанным библиотекам PositionsManager.ex5 и HistoryManager.ex5. Библиотеки позволяют минимизировать код, сохраняя при этом надежность и согласованность.

PriceTrader_EA предназначен для принятия торговых решений на основе данных о ценах и исторических данных о результатах сделок. Он включает в себя следующие ключевые особенности:

  • Динамическое определение размера лота: Советник корректирует размеры лотов на основе результатов предыдущих сделок, удваивая размер лота после убыточной сделки для компенсации потерь (в пределах заранее установленных лимитов ).
  • Направление сделки на основе динамики цен:PriceTrader_EA открывает сделки в направлении преобладающего тренда, определяемого движением цены на таймфрейме H1.
  • Управление рисками: Уровни стоп-лосса (SL) и тейк-профита (TP) рассчитываются динамически на основе текущего спреда, обеспечивая адаптивность к меняющимся рыночным условиям.

Начнем с включения заголовочных файлов библиотеки HistoryManager.mqh и PositionsManager.mqh в разделе заголовков нашего исходного файла.

#include <Wanateki/Toolkit/HistoryManager/HistoryManager.mqh>
#include <Wanateki/Toolkit/PositionsManager/PositionsManager.mqh>

Далее определим входные параметры для PriceTrader_EA. Эти параметры позволяют нам настроить магическое число, множители спреда для TP и SL, а также увеличение размера максимального лота.

input ulong magicNo = 101010;
input int tpSpreadMulti = 70;
input int slSpreadMulti = 90;
input int maxLotIncrease = 1000;

Мы инициализируем ключевые переменные для хранения такой информации, как спред, размер лота и количество открытых позиций. Эти переменные будут использоваться во всей логике советника.

bool eaJustLoaded = true;
double spread;
int spreadPips;
long minSLTP = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_STOPS_LEVEL);
long freezeLevel = SymbolInfoInteger(Symbol(), SYMBOL_TRADE_FREEZE_LEVEL);
double lotSize;
int sl, tp;
int totalOpenPositions, totalBuyPositionsOpen, totalSellPositionsOpen;
//--
PositionData lastClosedPositionInfo;

В функции OnInit() рассчитаем текущий спред и инициализируем уровни TP и SL на основе множителей спреда. При успешной загрузке PriceTrader_EA проигрывается звук.

int OnInit()
  {
//---
   spread = SymbolInfoDouble(_Symbol, SYMBOL_ASK) - SymbolInfoDouble(_Symbol, SYMBOL_BID);
   spread = NormalizeDouble(spread, _Digits);
   spreadPips = int(spread / _Point);
   tp = spreadPips * tpSpreadMulti;
   sl = spreadPips * slSpreadMulti;
//--
   PlaySound("connect.wav");
//---
   return(INIT_SUCCEEDED);
  }

В функции OnDeinit() очищаем комментарии к графику, проигрываем звук, чтобы указать на успешное удаление PriceTrader_EA с графика.

void OnDeinit(const int reason)
  {
//---
   Comment("");
   PlaySound("disconnect.wav");
  }

Функция OnTick() содержит основную логику PriceTrader_EA. Вот что мы будем делать в этой функции:

  • Получим текущий размер лота и количество открытых позиций.
  • Проверим, был ли PriceTrader_EA загружен только что, и откроем первоначальную сделку на основе динамики цен на H1.
  • Скорректируйте размер лота и направление сделки в зависимости от результата последней закрытой сделки.
  • Открывайте сделки подряд, чтобы извлечь выгоду из прибыльных трендов или восстановиться после убытков.

void OnTick()
  {
//---
   lotSize = SymbolInfoDouble(_Symbol, SYMBOL_VOLUME_MIN);
//--
   totalOpenPositions = SymbolPositionsTotal(_Symbol, magicNo);
   totalBuyPositionsOpen = SymbolBuyPositionsTotal(_Symbol, magicNo);
   totalSellPositionsOpen = SymbolSellPositionsTotal(_Symbol, magicNo);

   if(eaJustLoaded && totalOpenPositions == 0)
     {
      //--
      GetLastClosedPositionData(lastClosedPositionInfo, _Symbol, magicNo);
      if(lastClosedPositionInfo.ticket > 0 && lastClosedPositionInfo.profit < 0)
        {
         if(lastClosedPositionInfo.volume * 2 < lotSize * maxLotIncrease)
            lotSize = lastClosedPositionInfo.volume * 2; // double lot size
        }
      //--
      if(iOpen(_Symbol, PERIOD_H1, 0) < iClose(_Symbol, PERIOD_H1, 0))
        {
         OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Initial_Position");
        }
      else
        {
         OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Initial_Position");
        }
      if(totalOpenPositions > 0)
         eaJustLoaded = false;
     }
   else
     {
      eaJustLoaded = false;
     }

   if(totalOpenPositions == 0 && !eaJustLoaded)
     {
      if(GetLastClosedPositionData(lastClosedPositionInfo, _Symbol, magicNo))
        {
         if(lastClosedPositionInfo.profit > 0) // PROFITABLE TRADE
           {
            if(lastClosedPositionInfo.type == POSITION_TYPE_BUY)
              {
               OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Consecutive Profit");
              }
            else  // SELL POSITION
              {
               OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Consecutive Profit");
              }
           }
         else   // LOSS TRADE
           {
            if(lastClosedPositionInfo.volume * 2 < lotSize * maxLotIncrease)
               lotSize = lastClosedPositionInfo.volume * 2; // double lot size
            //--
            if(lastClosedPositionInfo.type == POSITION_TYPE_BUY)
              {
               // Reverse trade direction
               OpenSellPosition(magicNo, _Symbol, lotSize, sl, tp, "Loss Recovery");
              }
            else  // SELL POSITION
              {
               OpenBuyPosition(magicNo, _Symbol, lotSize, sl, tp, "Loss Recovery");
              }
           }
        }
     }

PriceTrader_EA подойдет вам, если вы предпочитаете или нуждаетесь в простой, но эффективной автоматизированной стратегии следования за трендом с динамическим управлением рисками. Советник разработан для быстрого восстановления потерь за счет адаптивного размера лота, что гарантирует устойчивость вашей торговой стратегии даже в неблагоприятных рыночных условиях. Кроме того, вы заметите, что PriceTrader_EA спроектирована так, чтобы тестирование MetaTrader 5 на истории было максимально простым и эффективным. Пользовательские значения размера лота, стоп-лосса и тейк-профита автоматически корректируются в зависимости от символа, устраняя необходимость в ручной настройке и обеспечивая оптимальную производительность различных инструментов.

Полный исходный файл PriceTrader_EA.mq5 приложен к статье вместе с библиотекой PositionsManager.ex5.


Тестирование на исторических данных советника Price Trader

Давайте проведем тестирование этой простой торговой стратегии в MetaTrader 5, чтобы посмотреть, как она показала себя за последние четырнадцать месяцев.
Примененные настройки:

  • Брокер: Deriv

  • Сервер: Deriv-Demo

  • Символ: Volatility 50 (1s) Index

  • Таймфрейм: Daily (дневной)

  • Период тестирования (дата): 1 год 2 месяца (январь 2024 - февраль 2025)

  • Моделирование: Каждый тик на основе реальных тиков

  • Депозит: USD 5000

  • Кредитное плечо: 1:1000

Настройки тестирования на истории Wanateki PriceTrader_EA

Входные параметры:

Входные параметры для тестирования Wanateki PriceTrader_EA на истории

Вот результаты тестирования PriceTrader_EA на истории:

Отчет о тестировании советника Wanateki PriceTrader_EA на истории

Отчет о тестировании советника Wanateki PriceTrader_EA на истории


Отчет о тестировании советника Wanateki PriceTrader_EA на истории

Отчет о тестировании советника Wanateki PriceTrader_EA на истории

Отчет о тестировании советника Wanateki PriceTrader_EA на истории

Отчет о тестировании советника Wanateki PriceTrader_EA на истории

Согласно результатам тестирования PriceTrader_EA показал впечатляющую прибыль в размере более 129% при сохранении низкой просадки капитала всего в 29%. Эта простая, но эффективная стратегия демонстрирует значительный потенциал и может быть дополнительно усовершенствована и оптимизирована для достижения еще лучших результатов. Поскольку PriceTrader_EA динамически корректирует свои входные данные, такие как размер лота, стоп-лосс и тейк-профит, на основе торгуемого символа или инструмента. Вы можете легко протестировать его на демо-счете. Просто загрузите его на график и понаблюдайте за его динамикой в течение дня или более, чтобы увидеть, приносит ли он прибыль, сопоставимую с той, что наблюдалась в тестере. Благодаря своей гибкости, советник является превосходным инструментом как для тестирования, так и для реальной торговли.


Заключение

Как показано в этой заключительной статье серии, библиотека HistoryManager.ex5 - мощный и эффективный инструмент, упрощающий обработку истории сделок в MetaTrader 5. Благодаря широкому набору функций библиотека позволяет легко получать доступ к данным, связанным со сделками, ордерами, позициями и отложенными ордерами, и управлять ими с помощью простых вызовов функций в одну строку. Такой упрощенный подход экономит время и усилия, позволяя вам сосредоточиться на разработке и оптимизации ваших торговых стратегий.

В этой статье я привел практические примеры кода, которые помогут вам в полной мере использовать потенциал библиотеки HistoryManager.ex5. Эти примеры в сочетании со знаниями, представленными в этой серии, обеспечивают инструменты и ресурсы, необходимые для алгоритмической обработки любых типов исторических данных, полученных в результате вашей торговой деятельности в MetaTrader 5 с использованием MQL5. В качестве прощального подарка всем читателям, которые следили за моими публикациями, я создал PriceTrader_EA - простой, но эффективный советник, демонстрирующий практическое применение некоторых из этих концепций.

Спасибо, что присоединились ко мне в этом путешествии! Как всегда, желаю вам всего наилучшего в вашем стремлении разгадать загадки рынков и добиться успеха в разработке программного обеспечения на языке MQL5. Успешного программирования, и пусть ваши стратегии всегда приносят успех!


Ресурсы и исходные файлы

Весь код, упомянутый в этой статье, приведен ниже. В приведенной здесь таблице перечислены сопутствующие библиотеки EX5 и файлы исходного кода, что упрощает доступ, внедрение и изучение рассматриваемых примеров.

Имя файла Описание
HistoryManager.ex5 Библиотека EX5 предназначена для обработки и управления историей торговых операций.
PositionsManager.ex5 Библиотека EX5 для управления и обработки позиций и ордеров.
HistoryManager.mqh Заголовочный файл для импорта структур данных и функций прототипа из библиотеки HistoryManager.ex5 в исходные файлы.
PositionsManager.mqh Заголовочный файл для импорта функций прототипа из библиотеки PositionsManager.ex5 в исходные файлы.
GetProfitFactor.mq5 Советник, анализирующий эффективность торговых стратегий путем расчета ключевых показателей, таких как валовая прибыль, валовой убыток и коэффициент прибыли.
GetNetProfitThisWeek.mq5 Скрипт, рассчитывающий чистую прибыль за текущую неделю.
GetSymbolPipsProfitToLossRatio.mq5 Советник, рассчитывающий соотношение прибыли и убытков в пунктах для конкретного торгового символа или для всего советника целиком.
GetTotalDeposits.mq5 Скрипт, который извлекает и анализирует данные о сделках, чтобы предоставить наглядный обзор истории пополнения или внесения денежных средств на счет
PriceTrader_EA.mq5 Советник, основанный на данных о ценах, который использует историю сделок для определения направления движения цены и восстановления после потерь. Работает на основе библиотек PositionsManager.ex5 и HistoryManager.ex5.



Перевод с английского произведен MetaQuotes Ltd.
Оригинальная статья: https://www.mql5.com/en/articles/17015

Последние комментарии | Перейти к обсуждению на форуме трейдеров (3)
hini
hini | 5 июл. 2025 в 15:31
Здравствуйте, автор, спасибо за ваш код. Вы тестировали его производительность? Насколько быстро он работает при большом количестве заказов?
Wanateki Solutions LTD
Kelvin Muturi Muigua | 6 июл. 2025 в 23:03
Здравствуйте, Хини, спасибо за интерес к статье. Она быстрая, так как возвращает результаты запросов за миллисекунды даже при работе с большим количеством исторических ордеров, но это зависит от скорости вашего компьютера.
hini
hini | 7 июл. 2025 в 00:18
Kelvin Muturi Muigua #:
Здравствуйте, Хини, спасибо за интерес к статье. Она быстрая, так как возвращает результаты запросов за миллисекунды даже при работе с большим количеством исторических ордеров, но это зависит от скорости вашего компьютера.
Спасибо!
Выборочные методы марковских цепей Монте-Карло. Алгоритм HMC Выборочные методы марковских цепей Монте-Карло. Алгоритм HMC
В статье исследуется гамильтонов алгоритм Монте-Карло (HMC) — золотой стандарт сэмплирования из сложных многомерных распределений. Представлена полноценная реализация HMC на языке MQL5, которая включает адаптивную настройку матрицы масс, поиск моды апостериорного распределения (MAP) с помощью метода оптимизации L-BFGS и комплексной диагностикой.
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (MDC-модуль) Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (MDC-модуль)
Представляем реализацию ключевых компонентов фреймворка EEMFlow средствами MQL5. Статья демонстрирует, как многомасштабная обработка событий, спайковые модули FAM и адаптивное объединение признаков в MDC формируют структурированное и адаптированное к плотности рынка представление. Это позволяет стратегии эффективно выявлять значимые сигналы, сочетать микроимпульсы с глобальными тенденциями и повышать точность прогнозов, обеспечивая трейдеру надежный инструмент для анализа и принятия решений.
Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (ADM-модуль) Нейросети в трейдинге: Сеточная аппроксимация событийного потока как инструмент анализа ценовых паттернов (ADM-модуль)
В статье представлена реализация Adaptive Density Module (ADM), ключевого компонента фреймворка EEMFlow, средствами MQL5. Рассмотрены этапы построения и объединения субмодулей MDC и MDS, а также интеграция ADM в существующую торговую модель BAT. Результаты тестирования на исторических данных EURUSD показывают устойчивый рост депозита, контролируемые просадки и высокую стабильность кривой эквити.
Объединяем LLM, CatBoost и квантовые вычисления в единую торговую систему Объединяем LLM, CatBoost и квантовые вычисления в единую торговую систему
В статье предлагается синтез новых технологий для преодоления ограничений классических индикаторов в аналитике рыночных данных. Показано, как языковые модели и квантовое кодирование могут выявлять скрытые рыночные паттерны, которые традиционные методики упускают. Эксперимент подтверждает ценность новых технологий и предлагает обновлённую методологию анализа, соответствующую современному уровню вычислительных инноваций.