Article-15026-MQL5-Trade-Hi.../Position.mqh

610 lines
68 KiB
MQL5

2026-03-23 12:53:11 +07:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Position.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 "Deal.mqh"
#include <Arrays\ArrayObj.mqh>
enum ENUM_POSITION_SORT_MODE
{
SORT_MODE_POSITION_TICKET = 0, // 568< A@02=5=8O/A>@B8@>2:8 ?> B8:5BC ?>78F88
SORT_MODE_POSITION_TIME, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 >B:@KB8O ?>78F88
SORT_MODE_POSITION_TIME_MSC, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 >B:@KB8O ?>78F88 2 <8;;8A5:C=40E
SORT_MODE_POSITION_TIME_UPDATE, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 87<5=5=8O ?>78F88
SORT_MODE_POSITION_TIME_UPDATE_MSC, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 87<5=5=8O ?>78F88 2 <8;;8A5:C=40E
SORT_MODE_POSITION_TYPE, // 568< A@02=5=8O/A>@B8@>2:8 ?> B8?C ?>78F88
SORT_MODE_POSITION_MAGIC, // 568< A@02=5=8O/A>@B8@>2:8 ?> Magic number ?>78F88
SORT_MODE_POSITION_IDENTIFIER, // 568< A@02=5=8O/A>@B8@>2:8 ?> 845=B8D8:0B>@C ?>78F88
SORT_MODE_POSITION_REASON, // 568< A@02=5=8O/A>@B8@>2:8 ?> ?@8G8=5 >B:@KB8O ?>78F88
SORT_MODE_POSITION_VOLUME, // 568< A@02=5=8O/A>@B8@>2:8 ?> >1J5<C ?>78F88
SORT_MODE_POSITION_PRICE_OPEN, // 568< A@02=5=8O/A>@B8@>2:8 ?> F5=5 ?>78F88
SORT_MODE_POSITION_SL, // 568< A@02=5=8O/A>@B8@>2:8 ?> C@>2=N Stop Loss 4;O >B:@KB>9 ?>78F88
SORT_MODE_POSITION_TP, // 568< A@02=5=8O/A>@B8@>2:8 ?> C@>2=N Take Profit 4;O >B:@KB>9 ?>78F88
SORT_MODE_POSITION_PRICE_CURRENT, // 568< A@02=5=8O/A>@B8@>2:8 ?> B5:CI59 F5=5 ?> A8<2>;C
SORT_MODE_POSITION_SWAP, // 568< A@02=5=8O/A>@B8@>2:8 ?> =0:>?;5==><C A2>?C
SORT_MODE_POSITION_PROFIT, // 568< A@02=5=8O/A>@B8@>2:8 ?> B5:CI59 ?@81K;8
SORT_MODE_POSITION_SYMBOL, // 568< A@02=5=8O/A>@B8@>2:8 ?> A8<2>;C, ?> :>B>@><C >B:@KB0 ?>78F8O
SORT_MODE_POSITION_COMMENT, // 568< A@02=5=8O/A>@B8@>2:8 ?> :><<5=B0@8N : ?>78F88
SORT_MODE_POSITION_EXTERNAL_ID, // 568< A@02=5=8O/A>@B8@>2:8 ?> 845=B8D8:0B>@C ?>78F88 2> 2=5H=59 A8AB5<5
SORT_MODE_POSITION_TIME_CLOSE, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 >B:@KB8O ?>78F88
SORT_MODE_POSITION_TIME_CLOSE_MSC, // 568< A@02=5=8O/A>@B8@>2:8 ?> 2@5<5=8 >B:@KB8O ?>78F88 2 <8;;8A5:C=40E
SORT_MODE_POSITION_PRICE_CLOSE, // 568< A@02=5=8O/A>@B8@>2:8 ?> F5=5 ?>78F88
};
//+------------------------------------------------------------------+
//| ;0AA ?>78F88 |
//+------------------------------------------------------------------+
class CPosition : public CObject
{
private:
protected:
CArrayObj m_list_deals; // !?8A>: A45;>: ?>78F88
CDeal m_temp_deal; // @5<5==K9 >1J5:B-A45;:0 4;O ?>8A:0 ?> A2>9AB2C 2 A?8A:5
//--- >72@0I05B 2@5<O A <8;;8A5:C=40<8
string TimeMscToString(const long time_msc,int flags=TIME_DATE|TIME_MINUTES|TIME_SECONDS) const;
//--- &5;>G8A;5==K5 A2>9AB20
long m_ticket; // "8:5B ?>78F88
datetime m_time; // @5<O >B:@KB8O ?>78F88
long m_time_msc; // @5<O >B:@KB8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
datetime m_time_update; // @5<O 87<5=5=8O ?>78F88
long m_time_update_msc; // @5<O 87<5=5=8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
ENUM_POSITION_TYPE m_type; // "8? ?>78F88
long m_magic; // Magic number 4;O ?>78F88 (A<>B@8 ORDER_MAGIC)
long m_identifier; // 45=B8D8:0B>@ ?>78F88
ENUM_POSITION_REASON m_reason; // @8G8=0 >B:@KB8O ?>78F88
//--- 5I5AB25==K5 A2>9AB20
double m_volume; // 1J5< ?>78F88
double m_price_open; // &5=0 ?>78F88
double m_sl; // #@>25=L Stop Loss 4;O >B:@KB>9 ?>78F88
double m_tp; // #@>25=L Take Profit 4;O >B:@KB>9 ?>78F88
double m_price_current; // "5:CI0O F5=0 ?> A8<2>;C
double m_swap; // 0:>?;5==K9 A2>?
double m_profit; // "5:CI0O ?@81K;L
//--- !B@>:>2K5 A2>9AB20
string m_symbol; // !8<2>;, ?> :>B>@><C >B:@KB0 ?>78F8O
string m_comment; // ><<5=B0@89 : ?>78F88
string m_external_id; // 45=B8D8:0B>@ ?>78F88 2> 2=5H=59 A8AB5<5 (=0 18@65)
//--- >?>;=8B5;L=K5 A2>9AB20
long m_chart_id; // 45=B8D8:0B>@ 3@0D8:0
int m_profit_pt; // @81K;L 2 ?C=:B0E
int m_digits; // Digits A8<2>;0
double m_point; // =0G5=85 >4=>3> ?C=:B0 A8<2>;0
double m_contract_size; // 07<5@ B>@3>2>3> :>=B@0:B0 A8<2>;0
string m_currency_profit; // 0;NB0 ?@81K;8 A8<2>;0
string m_account_currency; // 0;NB0 45?>78B0
string m_line_name; // <O 3@0D8G5A:>3> >1J5:B0-;8=88
color m_line_color; // &25B A>548=8B5;L=>9 ;8=88
//---!>740QB ;8=8N, A>548=ONICN A45;:8 >B:@KB8O-70:@KB8O
virtual bool CreateLine(void);
//--- >72@0I05B C:070B5;L =0 A45;:C (1) >B:@KB8O, (2) 70:@KB8O
CDeal *GetDealIn(void) const;
CDeal *GetDealOut(void) const;
//--- (1) !:@K205B, (2) >B>1@0605B 7=0G:8 A45;>: =0 3@0D8:5
void HideDeals(const bool chart_redraw=false);
void ShowDeals(const bool chart_redraw=false);
//--- (1) !:@K205B, (2) >B>1@0605B A>548=8B5;L=CN ;8=8N <564C 7=0G:0<8 A45;>:
void HideLine(const bool chart_redraw=false);
void ShowLine(const bool chart_redraw=false);
public:
//--- #AB0=>2:0 A2>9AB2
//--- &5;>G8A;5==K5 A2>9AB20
void SetTicket(const long ticket) { this.m_ticket=ticket; } // "8:5B ?>78F88
void SetTime(const datetime time) { this.m_time=time; } // @5<O >B:@KB8O ?>78F88
void SetTimeMsc(const long value) { this.m_time_msc=value; } // @5<O >B:@KB8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
void SetTimeUpdate(const datetime time) { this.m_time_update=time; } // @5<O 87<5=5=8O ?>78F88
void SetTimeUpdateMsc(const long value) { this.m_time_update_msc=value; } // @5<O 87<5=5=8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
void SetTypePosition(const ENUM_POSITION_TYPE type) { this.m_type=type; } // "8? ?>78F88
void SetMagic(const long magic) { this.m_magic=magic; } // Magic number 4;O ?>78F88 (A<>B@8 ORDER_MAGIC)
void SetID(const long id) { this.m_identifier=id; } // 45=B8D8:0B>@ ?>78F88
void SetReason(const ENUM_POSITION_REASON reason) { this.m_reason=reason; } // @8G8=0 >B:@KB8O ?>78F88
//--- 5I5AB25==K5 A2>9AB20
void SetVolume(const double volume) { this.m_volume=volume; } // 1J5< ?>78F88
void SetPriceOpen(const double price) { this.m_price_open=price; } // &5=0 ?>78F88
void SetSL(const double value) { this.m_sl=value; } // #@>25=L Stop Loss 4;O >B:@KB>9 ?>78F88
void SetTP(const double value) { this.m_tp=value; } // #@>25=L Take Profit 4;O >B:@KB>9 ?>78F88
void SetPriceCurrent(const double price) { this.m_price_current=price; } // "5:CI0O F5=0 ?> A8<2>;C
void SetSwap(const double value) { this.m_swap=value; } // 0:>?;5==K9 A2>?
void SetProfit(const double value) { this.m_profit=value; } // "5:CI0O ?@81K;L
//--- !B@>:>2K5 A2>9AB20
void SetSymbol(const string symbol) { this.m_symbol=symbol; } // !8<2>;, ?> :>B>@><C >B:@KB0 ?>78F8O
void SetComment(const string comment) { this.m_comment=comment; } // ><<5=B0@89 : ?>78F88
void SetExternalID(const string ext_id) { this.m_external_id=ext_id; } // 45=B8D8:0B>@ ?>78F88 2> 2=5H=59 A8AB5<5 (=0 18@65)
//--- >;CG5=85 A2>9AB2
//--- &5;>G8A;5==K5 A2>9AB20
long Ticket(void) const { return(this.m_ticket); } // "8:5B ?>78F88
datetime Time(void) const { return(this.m_time); } // @5<O >B:@KB8O ?>78F88
long TimeMsc(void) const { return(this.m_time_msc); } // @5<O >B:@KB8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
datetime TimeUpdate(void) const { return(this.m_time_update); } // @5<O 87<5=5=8O ?>78F88
long TimeUpdateMsc(void) const { return(this.m_time_update_msc);} // @5<O 87<5=5=8O ?>78F88 2 <8;;8A5:C=40E A 01.01.1970
ENUM_POSITION_TYPE TypePosition(void) const { return(this.m_type); } // "8? ?>78F88
long Magic(void) const { return(this.m_magic); } // Magic number 4;O ?>78F88 (A<>B@8 ORDER_MAGIC)
long ID(void) const { return(this.m_identifier); } // 45=B8D8:0B>@ ?>78F88
ENUM_POSITION_REASON Reason(void) const { return(this.m_reason); } // @8G8=0 >B:@KB8O ?>78F88
//--- 5I5AB25==K5 A2>9AB20
double Volume(void) const { return(this.m_volume); } // 1J5< ?>78F88
double PriceOpen(void) const { return(this.m_price_open); } // &5=0 ?>78F88
double SL(void) const { return(this.m_sl); } // #@>25=L Stop Loss 4;O >B:@KB>9 ?>78F88
double TP(void) const { return(this.m_tp); } // #@>25=L Take Profit 4;O >B:@KB>9 ?>78F88
double PriceCurrent(void) const { return(this.m_price_current); } // "5:CI0O F5=0 ?> A8<2>;C
double Swap(void) const { return(this.m_swap); } // 0:>?;5==K9 A2>?
double Profit(void) const { return(this.m_profit); } // "5:CI0O ?@81K;L
//--- !B@>:>2K5 A2>9AB20
string Symbol(void) const { return(this.m_symbol); } // !8<2>;, ?> :>B>@><C >B:@KB0 ?>78F8O
string Comment(void) const { return(this.m_comment); } // ><<5=B0@89 : ?>78F88
string ExternalID(void) const { return(this.m_external_id); } // 45=B8D8:0B>@ ?>78F88 2> 2=5H=59 A8AB5<5 (=0 18@65)
//--- >?>;=8B5;L=K5 A2>9AB20
ulong DealIn(void) const; // "8:5B A45;:8 >B:@KB8O
ulong DealOut(void) const; // "8:5B A45;:8 70:@KB8O
datetime TimeClose(void) const; // @5<O 70:@KB8O
long TimeCloseMsc(void) const; // @5<O 70:@KB8O 2 <8;;8A5:C=40E
int ProfitInPoints(void) const; // @81K;L 2 ?C=:B0E
double PriceClose(void) const; // &5=0 70:@KB8O
//--- >102;O5B A45;:C 2 A?8A>: A45;>:, 2>72@0I05B C:070B5;L
CDeal *DealAdd(const long ticket);
//--- #AB0=02;8205B F25B (1) A>548=8B5;L=>9 ;8=88, (2) A45;>: Buy 8 Sell
void SetLineColor(const color clr=C'225,68,29');
void SetDealsColor(const color clr_deal_buy=C'3,95,172', const color clr_deal_sell=C'225,68,29');
//--- >72@0I05B >?8A0=85 B8?0 ?>78F88
string TypeDescription(void) const;
//--- >72@0I05B >?8A0=85 2@5<5=8 8 F5=K >B:@KB8O ?>78F88
string TimePriceCloseDescription(void);
//--- >72@0I05B >?8A0=85 2@5<5=8 8 F5=K 70:@KB8O ?>78F88
string TimePriceOpenDescription(void);
//--- >72@0I05B :@0B:>5 >?8A0=85 ?>78F88
string Description(void);
//--- >72@0I05B B5:AB 2A?;K20NI53> A>>1I5=8O ?>78F88
virtual string Tooltip(void);
//--- 0A?5G0BK205B 2 6C@=0;5 A2>9AB20 ?>78F88 8 5Q A45;>:
void Print(void);
//--- (1) !:@K205B, (2) >B>1@0605B 3@0D8G5A:>5 ?@54AB02;5=85 ?>78F88 =0 3@0D8:5
void Hide(const bool chart_redraw=false);
void Show(const bool chart_redraw=false);
//--- !@02=8205B 420 >1J5:B0 <564C A>1>9 ?> C:070==><C 2 mode A2>9AB2C
virtual int Compare(const CObject *node, const int mode=0) const;
//--- >=AB@C:B>@/45AB@C:B>@
CPosition(const long position_id, const string symbol);
CPosition(void) { this.m_symbol=::Symbol(); }
~CPosition();
};
//+------------------------------------------------------------------+
//| >=AB@C:B>@ |
//+------------------------------------------------------------------+
CPosition::CPosition(const long position_id, const string symbol)
{
this.m_list_deals.Sort(SORT_MODE_DEAL_TIME_MSC);
this.m_identifier = position_id;
this.m_account_currency = ::AccountInfoString(ACCOUNT_CURRENCY);
this.m_symbol = (symbol==NULL ? ::Symbol() : symbol);
this.m_digits = (int)::SymbolInfoInteger(this.m_symbol,SYMBOL_DIGITS);
this.m_point = ::SymbolInfoDouble(this.m_symbol,SYMBOL_POINT);
this.m_contract_size = ::SymbolInfoDouble(this.m_symbol,SYMBOL_TRADE_CONTRACT_SIZE);
this.m_currency_profit = ::SymbolInfoString(this.m_symbol,SYMBOL_CURRENCY_PROFIT);
this.m_chart_id = ::ChartID();
this.m_line_name = "line#"+(string)this.m_identifier;
this.m_line_color = C'225,68,29';
}
//+------------------------------------------------------------------+
//| 5AB@C:B>@ |
//+------------------------------------------------------------------+
CPosition::~CPosition()
{
::ObjectsDeleteAll(this.m_chart_id, this.m_line_name);
this.m_list_deals.Clear();
}
//+------------------------------------------------------------------+
//| !@02=8205B 420 >1J5:B0 <564C A>1>9 ?> C:070==><C A2>9AB2C |
//+------------------------------------------------------------------+
int CPosition::Compare(const CObject *node,const int mode=0) const
{
const CPosition *obj=node;
switch(mode)
{
case SORT_MODE_POSITION_TICKET : return(this.Ticket() > obj.Ticket() ? 1 : this.Ticket() < obj.Ticket() ? -1 : 0);
case SORT_MODE_POSITION_TIME : return(this.Time() > obj.Time() ? 1 : this.Time() < obj.Time() ? -1 : 0);
case SORT_MODE_POSITION_TIME_MSC : return(this.TimeMsc() > obj.TimeMsc() ? 1 : this.TimeMsc() < obj.TimeMsc() ? -1 : 0);
case SORT_MODE_POSITION_TIME_UPDATE : return(this.TimeUpdate() > obj.TimeUpdate() ? 1 : this.TimeUpdate() < obj.TimeUpdate() ? -1 : 0);
case SORT_MODE_POSITION_TIME_UPDATE_MSC: return(this.TimeUpdateMsc() > obj.TimeUpdateMsc() ? 1 : this.TimeUpdateMsc() < obj.TimeUpdateMsc() ? -1 : 0);
case SORT_MODE_POSITION_TYPE : return(this.TypePosition() > obj.TypePosition() ? 1 : this.TypePosition() < obj.TypePosition() ? -1 : 0);
case SORT_MODE_POSITION_MAGIC : return(this.Magic() > obj.Magic() ? 1 : this.Magic() < obj.Magic() ? -1 : 0);
case SORT_MODE_POSITION_IDENTIFIER : return(this.ID() > obj.ID() ? 1 : this.ID() < obj.ID() ? -1 : 0);
case SORT_MODE_POSITION_REASON : return(this.Reason() > obj.Reason() ? 1 : this.Reason() < obj.Reason() ? -1 : 0);
case SORT_MODE_POSITION_VOLUME : return(this.Volume() > obj.Volume() ? 1 : this.Volume() < obj.Volume() ? -1 : 0);
case SORT_MODE_POSITION_PRICE_OPEN : return(this.PriceOpen() > obj.PriceOpen() ? 1 : this.PriceOpen() < obj.PriceOpen() ? -1 : 0);
case SORT_MODE_POSITION_SL : return(this.SL() > obj.SL() ? 1 : this.SL() < obj.SL() ? -1 : 0);
case SORT_MODE_POSITION_TP : return(this.TP() > obj.TP() ? 1 : this.TP() < obj.TP() ? -1 : 0);
case SORT_MODE_POSITION_PRICE_CURRENT : return(this.PriceCurrent() > obj.PriceCurrent() ? 1 : this.PriceCurrent() < obj.PriceCurrent() ? -1 : 0);
case SORT_MODE_POSITION_SWAP : return(this.Swap() > obj.Swap() ? 1 : this.Swap() < obj.Swap() ? -1 : 0);
case SORT_MODE_POSITION_PROFIT : return(this.Profit() > obj.Profit() ? 1 : this.Profit() < obj.Profit() ? -1 : 0);
case SORT_MODE_POSITION_SYMBOL : return(this.Symbol() > obj.Symbol() ? 1 : this.Symbol() < obj.Symbol() ? -1 : 0);
case SORT_MODE_POSITION_COMMENT : return(this.Comment() > obj.Comment() ? 1 : this.Comment() < obj.Comment() ? -1 : 0);
case SORT_MODE_POSITION_EXTERNAL_ID : return(this.ExternalID() > obj.ExternalID() ? 1 : this.ExternalID() < obj.ExternalID() ? -1 : 0);
case SORT_MODE_POSITION_TIME_CLOSE : return(this.TimeClose() > obj.TimeClose() ? 1 : this.TimeClose() < obj.TimeClose() ? -1 : 0);
case SORT_MODE_POSITION_TIME_CLOSE_MSC : return(this.TimeCloseMsc() > obj.TimeCloseMsc() ? 1 : this.TimeCloseMsc() < obj.TimeCloseMsc() ? -1 : 0);
case SORT_MODE_POSITION_PRICE_CLOSE : return(this.PriceClose() > obj.PriceClose() ? 1 : this.PriceClose() < obj.PriceClose() ? -1 : 0);
default : return -1;
}
}
//+------------------------------------------------------------------+
//| >72@0I05B 2@5<O A <8;;8A5:C=40<8 |
//+------------------------------------------------------------------+
string CPosition::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'));
}
//+------------------------------------------------------------------+
//| >72@0I05B C:070B5;L =0 A45;:C >B:@KB8O |
//+------------------------------------------------------------------+
CDeal *CPosition::GetDealIn(void) const
{
int total=this.m_list_deals.Total();
for(int i=0; i<total; i++)
{
CDeal *deal=this.m_list_deals.At(i);
if(deal==NULL)
continue;
if(deal.Entry()==DEAL_ENTRY_IN)
return deal;
}
return NULL;
}
//+------------------------------------------------------------------+
//| >72@0I05B C:070B5;L =0 A45;:C 70:@KB8O |
//+------------------------------------------------------------------+
CDeal *CPosition::GetDealOut(void) const
{
for(int i=this.m_list_deals.Total()-1; i>=0; i--)
{
CDeal *deal=this.m_list_deals.At(i);
if(deal==NULL)
continue;
if(deal.Entry()==DEAL_ENTRY_OUT || deal.Entry()==DEAL_ENTRY_OUT_BY)
return deal;
}
return NULL;
}
//+------------------------------------------------------------------+
//| >72@0I05B B8:5B A45;:8 >B:@KB8O |
//+------------------------------------------------------------------+
ulong CPosition::DealIn(void) const
{
CDeal *deal=this.GetDealIn();
return(deal!=NULL ? deal.Ticket() : 0);