Article-15346-MQL5-Trade-Mo.../Deal.mqh
2026-03-23 13:19:06 +07:00

377 lines
51 KiB
MQL5

//+------------------------------------------------------------------+
//| Deal.mqh |
//| Copyright 2024, MetaQuotes Ltd. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2024, MetaQuotes Ltd."
#property link "https://www.mql5.com"
#property version "1.00"
#include <Object.mqh>
//--- Перечисление целочисленных свойств сделки
enum ENUM_DEAL_PROPERTY_INT
{
DEAL_PROP_TICKET = 0, // Тикет сделки
DEAL_PROP_ORDER, // Ордер, на основание которого выполнена сделка
DEAL_PROP_TIME, // Время совершения сделки
DEAL_PROP_TIME_MSC, // Время совершения сделки в миллисекундах
DEAL_PROP_TYPE, // Тип сделки
DEAL_PROP_ENTRY, // Направление сделки
DEAL_PROP_MAGIC, // Magic number сделки
DEAL_PROP_REASON, // Причина или источник проведения сделки
DEAL_PROP_POSITION_ID, // Идентификатор позиции
DEAL_PROP_SPREAD, // Spread при совершении сделки
};
//--- Перечисление вещественных свойств сделки
enum ENUM_DEAL_PROPERTY_DBL
{
DEAL_PROP_VOLUME = DEAL_PROP_SPREAD+1,// Объем сделки
DEAL_PROP_PRICE, // Цена сделки
DEAL_PROP_COMMISSION, // Комиссия
DEAL_PROP_SWAP, // Накопленный своп при закрытии
DEAL_PROP_PROFIT, // Финансовый результат сделки
DEAL_PROP_FEE, // Оплата за проведение сделки
DEAL_PROP_SL, // Уровень Stop Loss
DEAL_PROP_TP, // Уровень Take Profit
};
//--- Перечисление строковых свойств сделки
enum ENUM_DEAL_PROPERTY_STR
{
DEAL_PROP_SYMBOL = DEAL_PROP_TP+1, // Символ, по которому произведена сделка
DEAL_PROP_COMMENT, // Комментарий к сделке
DEAL_PROP_EXTERNAL_ID, // Идентификатор сделки во внешней торговой системе
};
//+------------------------------------------------------------------+
//| Класс сделки |
//+------------------------------------------------------------------+
class CDeal : public CObject
{
private:
MqlTick m_tick; // Структура тика сделки
long m_lprop[DEAL_PROP_SPREAD+1]; // Массив для хранения целочисленных свойств
double m_dprop[DEAL_PROP_TP-DEAL_PROP_SPREAD]; // Массив для хранения вещественных свойств
string m_sprop[DEAL_PROP_EXTERNAL_ID-DEAL_PROP_TP]; // Массив для хранения строковых свойств
//--- Возвращает индекс массива, по которому фактически расположено (1) double-свойство и (2) string-свойство сделки
int IndexProp(ENUM_DEAL_PROPERTY_DBL property) const { return(int)property-DEAL_PROP_SPREAD-1; }
int IndexProp(ENUM_DEAL_PROPERTY_STR property) const { return(int)property-DEAL_PROP_TP-1; }
//--- Получает (1) тик сделки, (2) спред минутного бара сделки
bool GetDealTick(const int amount=20);
int GetSpreadM1(void);
//--- Возвращает время с миллисекундами
string TimeMscToString(const long time_msc,int flags=TIME_DATE|TIME_MINUTES|TIME_SECONDS) const;
protected:
//--- Дополнительные свойства
int m_digits; // Digits символа
double m_point; // Point символа
double m_bid; // Bid при совершении сделки
double m_ask; // Ask при совершении сделки
public:
//--- Установка свойств
//--- Устанавливает (1) целочисленное, (2) вещественное и (3) строковое свойство сделки
void SetProperty(ENUM_DEAL_PROPERTY_INT property,long value){ this.m_lprop[property]=value; }
void SetProperty(ENUM_DEAL_PROPERTY_DBL property,double value){ this.m_dprop[this.IndexProp(property)]=value; }
void SetProperty(ENUM_DEAL_PROPERTY_STR property,string value){ this.m_sprop[this.IndexProp(property)]=value; }
//--- Целочисленные свойства
void SetTicket(const long ticket) { this.SetProperty(DEAL_PROP_TICKET, ticket); } // Тикет
void SetOrder(const long order) { this.SetProperty(DEAL_PROP_ORDER, order); } // Ордер
void SetTime(const datetime time) { this.SetProperty(DEAL_PROP_TIME, time); } // Время
void SetTimeMsc(const long value) { this.SetProperty(DEAL_PROP_TIME_MSC, value); } // Время в миллисекундах
void SetTypeDeal(const ENUM_DEAL_TYPE type) { this.SetProperty(DEAL_PROP_TYPE, type); } // Тип
void SetEntry(const ENUM_DEAL_ENTRY entry) { this.SetProperty(DEAL_PROP_ENTRY, entry); } // Направление
void SetMagic(const long magic) { this.SetProperty(DEAL_PROP_MAGIC, magic); } // Magic number
void SetReason(const ENUM_DEAL_REASON reason) { this.SetProperty(DEAL_PROP_REASON, reason); } // Причина или источник проведения сделки
void SetPositionID(const long id) { this.SetProperty(DEAL_PROP_POSITION_ID, id); } // Идентификатор позиции
//--- Вещественные свойства
void SetVolume(const double volume) { this.SetProperty(DEAL_PROP_VOLUME, volume); } // Объем
void SetPrice(const double price) { this.SetProperty(DEAL_PROP_PRICE, price); } // Цена
void SetCommission(const double value) { this.SetProperty(DEAL_PROP_COMMISSION, value); } // Комиссия
void SetSwap(const double value) { this.SetProperty(DEAL_PROP_SWAP, value); } // Накопленный своп при закрытии
void SetProfit(const double value) { this.SetProperty(DEAL_PROP_PROFIT, value); } // Финансовый результат
void SetFee(const double value) { this.SetProperty(DEAL_PROP_FEE, value); } // Оплата за проведение сделки
void SetSL(const double value) { this.SetProperty(DEAL_PROP_SL, value); } // Уровень Stop Loss
void SetTP(const double value) { this.SetProperty(DEAL_PROP_TP, value); } // Уровень Take Profit
//--- Строковые свойства
void SetSymbol(const string symbol) { this.SetProperty(DEAL_PROP_SYMBOL,symbol); } // Имя символа
void SetComment(const string comment) { this.SetProperty(DEAL_PROP_COMMENT,comment); } // Комментарий
void SetExternalID(const string ext_id) { this.SetProperty(DEAL_PROP_EXTERNAL_ID,ext_id); } // Идентификатор сделки во внешней торговой системе
//--- Получение свойств
//--- Возвращает из массива свойств (1) целочисленное, (2) вещественное и (3) строковое свойство сделки
long GetProperty(ENUM_DEAL_PROPERTY_INT property) const { return this.m_lprop[property]; }
double GetProperty(ENUM_DEAL_PROPERTY_DBL property) const { return this.m_dprop[this.IndexProp(property)]; }
string GetProperty(ENUM_DEAL_PROPERTY_STR property) const { return this.m_sprop[this.IndexProp(property)]; }
//--- Целочисленные свойства
long Ticket(void) const { return this.GetProperty(DEAL_PROP_TICKET); } // Тикет
long Order(void) const { return this.GetProperty(DEAL_PROP_ORDER); } // Ордер
datetime Time(void) const { return (datetime)this.GetProperty(DEAL_PROP_TIME); } // Время
long TimeMsc(void) const { return this.GetProperty(DEAL_PROP_TIME_MSC); } // Время в миллисекундах
ENUM_DEAL_TYPE TypeDeal(void) const { return (ENUM_DEAL_TYPE)this.GetProperty(DEAL_PROP_TYPE); } // Тип
ENUM_DEAL_ENTRY Entry(void) const { return (ENUM_DEAL_ENTRY)this.GetProperty(DEAL_PROP_ENTRY); } // Направление
long Magic(void) const { return this.GetProperty(DEAL_PROP_MAGIC); } // Magic number
ENUM_DEAL_REASON Reason(void) const { return (ENUM_DEAL_REASON)this.GetProperty(DEAL_PROP_REASON); } // Причина или источник проведения сделки
long PositionID(void) const { return this.GetProperty(DEAL_PROP_POSITION_ID); } // Идентификатор позиции
//--- Вещественные свойства
double Volume(void) const { return this.GetProperty(DEAL_PROP_VOLUME); } // Объем
double Price(void) const { return this.GetProperty(DEAL_PROP_PRICE); } // Цена
double Commission(void) const { return this.GetProperty(DEAL_PROP_COMMISSION); } // Комиссия
double Swap(void) const { return this.GetProperty(DEAL_PROP_SWAP); } // Накопленный своп при закрытии
double Profit(void) const { return this.GetProperty(DEAL_PROP_PROFIT); } // Финансовый результат
double Fee(void) const { return this.GetProperty(DEAL_PROP_FEE); } // Оплата за проведение сделки
double SL(void) const { return this.GetProperty(DEAL_PROP_SL); } // Уровень Stop Loss
double TP(void) const { return this.GetProperty(DEAL_PROP_TP); } // Уровень Take Profit
//--- Строковые свойства
string Symbol(void) const { return this.GetProperty(DEAL_PROP_SYMBOL); } // Имя символа
string Comment(void) const { return this.GetProperty(DEAL_PROP_COMMENT); } // Комментарий
string ExternalID(void) const { return this.GetProperty(DEAL_PROP_EXTERNAL_ID); } // Идентификатор сделки во внешней торговой системе
//--- Дополнительные свойства
double Bid(void) const { return this.m_bid; } // Bid при совершении сделки
double Ask(void) const { return this.m_ask; } // Ask при совершении сделки
int Spread(void) const { return (int)this.GetProperty(DEAL_PROP_SPREAD); } // Spread при совершении сделки
//--- Возвращает описание (1) типа сделки, (2) способа изменения позиции, (3) причины проведения сделки
string TypeDescription(void) const;
string EntryDescription(void) const;
string ReasonDescription(void) const;
//--- Возвращает описание сделки
string Description(void);
//--- Распечатывает в журнал свойства сделки
void Print(void);
//--- Сравнивает два объекта между собой по указанному в mode свойству
virtual int Compare(const CObject *node, const int mode=0) const;
//--- Конструкторы/деструктор
CDeal(void){}
CDeal(const ulong ticket);
~CDeal();
};
//+------------------------------------------------------------------+
//| Конструктор |
//+------------------------------------------------------------------+
CDeal::CDeal(const ulong ticket)
{
//--- Сохранение свойств
//--- Целочисленные свойства
this.SetTicket((long)ticket); // Тикет сделки
this.SetOrder(::HistoryDealGetInteger(ticket, DEAL_ORDER)); // Ордер
this.SetTime((datetime)::HistoryDealGetInteger(ticket, DEAL_TIME)); // Время совершения сделки
this.SetTimeMsc(::HistoryDealGetInteger(ticket, DEAL_TIME_MSC)); // Время совершения сделки в миллисекундах
this.SetTypeDeal((ENUM_DEAL_TYPE)::HistoryDealGetInteger(ticket, DEAL_TYPE)); // Тип
this.SetEntry((ENUM_DEAL_ENTRY)::HistoryDealGetInteger(ticket, DEAL_ENTRY)); // Направление
this.SetMagic(::HistoryDealGetInteger(ticket, DEAL_MAGIC)); // Magic number
this.SetReason((ENUM_DEAL_REASON)::HistoryDealGetInteger(ticket, DEAL_REASON)); // Причина или источник проведения сделки
this.SetPositionID(::HistoryDealGetInteger(ticket, DEAL_POSITION_ID)); // Идентификатор позиции
//--- Вещественные свойства
this.SetVolume(::HistoryDealGetDouble(ticket, DEAL_VOLUME)); // Объем
this.SetPrice(::HistoryDealGetDouble(ticket, DEAL_PRICE)); // Цена
this.SetCommission(::HistoryDealGetDouble(ticket, DEAL_COMMISSION)); // Комиссия
this.SetSwap(::HistoryDealGetDouble(ticket, DEAL_SWAP)); // Накопленный своп при закрытии
this.SetProfit(::HistoryDealGetDouble(ticket, DEAL_PROFIT)); // Финансовый результат
this.SetFee(::HistoryDealGetDouble(ticket, DEAL_FEE)); // Оплата за проведение сделки
this.SetSL(::HistoryDealGetDouble(ticket, DEAL_SL)); // Уровень Stop Loss
this.SetTP(::HistoryDealGetDouble(ticket, DEAL_TP)); // Уровень Take Profit
//--- Строковые свойства
this.SetSymbol(::HistoryDealGetString(ticket, DEAL_SYMBOL)); // Имя символа
this.SetComment(::HistoryDealGetString(ticket, DEAL_COMMENT)); // Комментарий
this.SetExternalID(::HistoryDealGetString(ticket, DEAL_EXTERNAL_ID)); // Идентификатор сделки во внешней торговой системе
//--- Дополнительные параметры
this.m_digits = (int)::SymbolInfoInteger(this.Symbol(), SYMBOL_DIGITS);
this.m_point = ::SymbolInfoDouble(this.Symbol(), SYMBOL_POINT);
//--- Параметры для расчёта спреда
this.m_bid = 0;
this.m_ask = 0;
this.SetProperty(DEAL_PROP_SPREAD, 0);
//--- Если исторический тик и значение Point символа удалось получить
if(this.GetDealTick() && this.m_point!=0)
{
//--- запишем значения цен Bid и Ask и рассчитаем и сохраним значение спреда
this.m_bid=this.m_tick.bid;
this.m_ask=this.m_tick.ask;
int spread=(int)::fabs((this.m_ask-this.m_bid)/this.m_point);
this.SetProperty(DEAL_PROP_SPREAD, spread);
}
//--- Если исторический тик получить не удалось, возьмём значение спреда минутного бара, на котором была сделка
else
this.SetProperty(DEAL_PROP_SPREAD, this.GetSpreadM1());
}
//+------------------------------------------------------------------+
//| Деструктор |
//+------------------------------------------------------------------+
CDeal::~CDeal()
{
}
//+------------------------------------------------------------------+
//| Сравнивает два объекта между собой по указанному свойству |
//+------------------------------------------------------------------+
int CDeal::Compare(const CObject *node,const int mode=0) const
{
const CDeal * obj = node;
switch(mode)
{
case DEAL_PROP_TICKET : return(this.Ticket() > obj.Ticket() ? 1 : this.Ticket() < obj.Ticket() ? -1 : 0);
case DEAL_PROP_ORDER : return(this.Order() > obj.Order() ? 1 : this.Order() < obj.Order() ? -1 : 0);
case DEAL_PROP_TIME : return(this.Time() > obj.Time() ? 1 : this.Time() < obj.Time() ? -1 : 0);
case DEAL_PROP_TIME_MSC : return(this.TimeMsc() > obj.TimeMsc() ? 1 : this.TimeMsc() < obj.TimeMsc() ? -1 : 0);
case DEAL_PROP_TYPE : return(this.TypeDeal() > obj.TypeDeal() ? 1 : this.TypeDeal() < obj.TypeDeal() ? -1 : 0);
case DEAL_PROP_ENTRY : return(this.Entry() > obj.Entry() ? 1 : this.Entry() < obj.Entry() ? -1 : 0);
case DEAL_PROP_MAGIC : return(this.Magic() > obj.Magic() ? 1 : this.Magic() < obj.Magic() ? -1 : 0);
case DEAL_PROP_REASON : return(this.Reason() > obj.Reason() ? 1 : this.Reason() < obj.Reason() ? -1 : 0);
case DEAL_PROP_POSITION_ID : return(this.PositionID() > obj.PositionID() ? 1 : this.PositionID() < obj.PositionID() ? -1 : 0);
case DEAL_PROP_SPREAD : return(this.Spread() > obj.Spread() ? 1 : this.Spread() < obj.Spread() ? -1 : 0);
case DEAL_PROP_VOLUME : return(this.Volume() > obj.Volume() ? 1 : this.Volume() < obj.Volume() ? -1 : 0);
case DEAL_PROP_PRICE : return(this.Price() > obj.Price() ? 1 : this.Price() < obj.Price() ? -1 : 0);
case DEAL_PROP_COMMISSION : return(this.Commission() > obj.Commission() ? 1 : this.Commission() < obj.Commission() ? -1 : 0);
case DEAL_PROP_SWAP : return(this.Swap() > obj.Swap() ? 1 : this.Swap() < obj.Swap() ? -1 : 0);
case DEAL_PROP_PROFIT : return(this.Profit() > obj.Profit() ? 1 : this.Profit() < obj.Profit() ? -1 : 0);
case DEAL_PROP_FEE : return(this.Fee() > obj.Fee() ? 1 : this.Fee() < obj.Fee() ? -1 : 0);
case DEAL_PROP_SL : return(this.SL() > obj.SL() ? 1 : this.SL() < obj.SL() ? -1 : 0);
case DEAL_PROP_TP : return(this.TP() > obj.TP() ? 1 : this.TP() < obj.TP() ? -1 : 0);
case DEAL_PROP_SYMBOL : return(this.Symbol() > obj.Symbol() ? 1 : this.Symbol() < obj.Symbol() ? -1 : 0);
case DEAL_PROP_COMMENT : return(this.Comment() > obj.Comment() ? 1 : this.Comment() < obj.Comment() ? -1 : 0);
case DEAL_PROP_EXTERNAL_ID : return(this.ExternalID() > obj.ExternalID() ? 1 : this.ExternalID() < obj.ExternalID() ? -1 : 0);
default : return(-1);
}
}
//+------------------------------------------------------------------+
//| Возвращает описание типа сделки |
//+------------------------------------------------------------------+
string CDeal::TypeDescription(void) const
{
switch(this.TypeDeal())
{
case DEAL_TYPE_BUY : return "Buy";
case DEAL_TYPE_SELL : return "Sell";
case DEAL_TYPE_BALANCE : return "Balance";
case DEAL_TYPE_CREDIT : return "Credit";
case DEAL_TYPE_CHARGE : return "Additional charge";
case DEAL_TYPE_CORRECTION : return "Correction";
case DEAL_TYPE_BONUS : return "Bonus";
case DEAL_TYPE_COMMISSION : return "Additional commission";
case DEAL_TYPE_COMMISSION_DAILY : return "Daily commission";
case DEAL_TYPE_COMMISSION_MONTHLY : return "Monthly commission";
case DEAL_TYPE_COMMISSION_AGENT_DAILY : return "Daily agent commission";
case DEAL_TYPE_COMMISSION_AGENT_MONTHLY: return "Monthly agent commission";
case DEAL_TYPE_INTEREST : return "Interest rate";
case DEAL_TYPE_BUY_CANCELED : return "Canceled buy deal";
case DEAL_TYPE_SELL_CANCELED : return "Canceled sell deal";
case DEAL_DIVIDEND : return "Dividend operations";
case DEAL_DIVIDEND_FRANKED : return "Franked (non-taxable) dividend operations";
case DEAL_TAX : return "Tax charges";
default : return "Unknown: "+(string)this.TypeDeal();
}
}
//+------------------------------------------------------------------+
//| Возвращает описание способа изменения позиции |
//+------------------------------------------------------------------+
string CDeal::EntryDescription(void) const
{
switch(this.Entry())
{
case DEAL_ENTRY_IN : return "Entry In";
case DEAL_ENTRY_OUT : return "Entry Out";
case DEAL_ENTRY_INOUT : return "Reverse";
case DEAL_ENTRY_OUT_BY : return "Close a position by an opposite one";
default : return "Unknown: "+(string)this.Entry();
}
}
//+------------------------------------------------------------------+
//| Возвращает описание причины проведения сделки |
//+------------------------------------------------------------------+
string CDeal::ReasonDescription(void) const
{
switch(this.Reason())
{
case DEAL_REASON_CLIENT : return "Terminal";
case DEAL_REASON_MOBILE : return "Mobile";
case DEAL_REASON_WEB : return "Web";
case DEAL_REASON_EXPERT : return "EA";
case DEAL_REASON_SL : return "SL";
case DEAL_REASON_TP : return "TP";
case DEAL_REASON_SO : return "SO";
case DEAL_REASON_ROLLOVER : return "Rollover";
case DEAL_REASON_VMARGIN : return "Var. Margin";
case DEAL_REASON_SPLIT : return "Split";
case DEAL_REASON_CORPORATE_ACTION: return "Corp. Action";
default : return "Unknown reason "+(string)this.Reason();
}
}
//+------------------------------------------------------------------+
//| Возвращает описание сделки |
//+------------------------------------------------------------------+
string CDeal::Description(void)
{
return(::StringFormat("Deal: %-9s %.2f %-4s #%I64d at %s", this.EntryDescription(), this.Volume(), this.TypeDescription(), this.Ticket(), this.TimeMscToString(this.TimeMsc())));
}
//+------------------------------------------------------------------+
//| Распечатывает в журнал свойства сделки |
//+------------------------------------------------------------------+
void CDeal::Print(void)
{
::Print(this.Description());
}
//+------------------------------------------------------------------+
//| Возвращает время с миллисекундами |
//+------------------------------------------------------------------+
string CDeal::TimeMscToString(const long time_msc, int flags=TIME_DATE|TIME_MINUTES|TIME_SECONDS) const
{
return(::TimeToString(time_msc/1000, flags) + "." + ::IntegerToString(time_msc %1000, 3, '0'));
}
//+------------------------------------------------------------------+
//| Получает тик сделки |
//| https://www.mql5.com/ru/forum/42122/page47#comment_37205238 |
//+------------------------------------------------------------------+
bool CDeal::GetDealTick(const int amount=20)
{
MqlTick ticks[]; // Сюда будем получать тики
int attempts = amount; // Количество попыток получения тиков
int offset = 500; // Начальное смещение времени для попытки
int copied = 0; // Количество скопированных тиков
//--- До тех пор, пока не скопирован тик и не закончилось количество попыток копирования
//--- пытаемся получить тик, на каждой итерации увеличивая вдвое начальное смещение времени (расширяем диапазон времени "from_msc")
while(!::IsStopped() && (copied<=0) && (attempts--)!=0)
copied = ::CopyTicksRange(this.Symbol(), ticks, COPY_TICKS_INFO, this.TimeMsc()-(offset <<=1), this.TimeMsc());
//--- Если тик скопировать удалось (он последний в массиве тиков) - записываем его в переменную m_tick
if(copied>0)
this.m_tick=ticks[copied-1];
//--- Возвращаем флаг того, что тик скопирован
return(copied>0);
}
//+------------------------------------------------------------------+
//| Получает спред минутного бара сделки |
//+------------------------------------------------------------------+
int CDeal::GetSpreadM1(void)
{
int array[1]={};
int bar=::iBarShift(this.Symbol(), PERIOD_M1, this.Time());
if(bar==WRONG_VALUE)
return 0;
return(::CopySpread(this.Symbol(), PERIOD_M1, bar, 1, array)==1 ? array[0] : 0);
}
//+------------------------------------------------------------------+