UTE/Strategy/Position.mqh

467 lines
39 KiB
MQL5
Raw Permalink Normal View History

2025-05-30 16:34:43 +02:00
<EFBFBD><EFBFBD>//+------------------------------------------------------------------+
//| Position.mqh |
//| Copyright 2015, Vasiliy Sokolov. |
//| http://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2015, Vasiliy Sokolov."
#property link "http://www.mql5.com"
#include <Object.mqh>
#include "Message.mqh"
#include "Logs.mqh"
#include "Trailings\Trailing.mqh"
//+------------------------------------------------------------------+
//| ;0AA 0:B82=>9 ?>78F88, 4;O :;0AA8G5A:8E AB@0B5389 |
//+------------------------------------------------------------------+
class CPosition : public CObject
{
private:
ulong m_id; // #=8:0;L=K9 845=B8D8:0B>@ ?>78F88
uint m_magic; // #=8:0;L=K9 845=B8D8:0B>@ M:A?5@B0, : :>B>@><C ?@8=04;568B 40==0O ?>78F8O.
ENUM_POSITION_TYPE m_direction; // 0?@02;5=85 ?>78F88
double m_entry_price; // &5=0 2E>40 2 ?>78F8N
string m_symbol; // =AB@C<5=B, ?> :>B>@><C >B:@KB0 ?>78F8O
datetime m_time_open; // @5<O >B:@KB8O
string m_entry_comment; // E>4OI89 :><<5=B0@89
bool m_is_closed; // AB8=0, 5A;8 ?>78F8O 1K;0 70:@KB0
CLog* Log; // >38@>20=85
public:
CPosition(void);
bool IsActive();
uint ExpertMagic(void);
ulong ID(void);
ENUM_POSITION_TYPE Direction(void);
double EntryPrice(void);
string EntryComment(void);
double Profit(void);
double ProfitInPips(void);
double Volume(void);
string Symbol(void);
datetime TimeOpen(void);
bool CloseAtMarket(string comment="");
bool CloseAtMarket(double volume, ulong deviation, string comment);
bool CloseAtMarket(double volume, ulong deviation, string comment, bool asynch = false);
double StopLossValue(void);
bool StopLossValue(double sl);
double StopLossPercent(void);
bool StopLossPercent(double sl);
double TakeProfitValue(void);
bool TakeProfitValue(double tp);
double TakeProfitPercent(void);
bool TakeProfitPercent(double tp);
bool IsComplex(void);
bool CheckStopLevel(double stoplevel);
CTrailing* Trailing;
CObject* ExpertData;
};
CPosition::CPosition(void) : m_id(0),
m_entry_price(0.0),
m_symbol(""),
m_time_open(0)
{
Log = CLog::GetLog();
#ifdef __MQL5__
#ifdef __HT__
m_id = HedgePositionGetInteger(HEDGE_POSITION_ID);
m_magic = (uint)HedgePositionGetInteger(HEDGE_POSITION_MAGIC);
ENUM_DIRECTION_TYPE type = (ENUM_DIRECTION_TYPE)HedgePositionGetInteger(HEDGE_POSITION_DIRECTION);
m_direction = type == DIRECTION_LONG ? POSITION_TYPE_BUY : POSITION_TYPE_SELL;
m_entry_price = HedgePositionGetDouble(HEDGE_POSITION_PRICE_OPEN);
m_symbol = HedgePositionGetString(HEDGE_POSITION_SYMBOL);
m_time_open = (datetime)HedgePositionGetInteger(HEDGE_POSITION_ENTRY_TIME_EXECUTED_MSC)/1000;
m_entry_comment = HedgePositionGetString(HEDGE_POSITION_ENTRY_COMMENT);
#else
m_id = PositionGetInteger(POSITION_IDENTIFIER);
m_maigic = (uint)PositionGetInteger(POSITION_MAGIC);
m_direction = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
m_entry_price = PositionGetDouble(POSITION_PRICE_OPEN);
m_symbol = PositionGetString(POSITION_SYMBOL);
m_time_open = (datetime)PositionGetInteger(POSITION_TIME);
m_entry_comment = PositionGetString(POSITION_COMMENT);
#endif
#else
#ifdef __MQL4__
m_id = OrderTicket();
m_magic = OrderMagic();
if(OrderType() == ORDER_TYPE_BUY)
m_direction = POSITION_TYPE_BUY;
else
m_direction = POSITION_TYPE_SELL;
m_entry_price = OrderOpenPrice();
m_profit = OrderProfit();
m_volume = OrderLots();
m_symbol = OrderSymbol();
m_time_open = OrderOpenTime();
m_sl = OrderStopLoss();
m_tp = OrderTakeProfit();
m_entry_comment = OrderComment();
#endif
#endif
}
//+------------------------------------------------------------------+
//| >72@0I05B 8AB8=C, 5A;8 B5:CI0O ?>78F8O 0:B82=0. >72@0I05B ;>6L |
//| 2 ?@>B82=>< A;CG05. |
//+------------------------------------------------------------------+
bool CPosition::IsActive(void)
{
return m_time_open > 0 && !m_is_closed;
}
//+------------------------------------------------------------------+
//| >72@0I05B =0?@02;5=85 ?>78F88. |
//+------------------------------------------------------------------+
ENUM_POSITION_TYPE CPosition::Direction(void)
{
return m_direction;
}
//+------------------------------------------------------------------+
//| >72@0I05B C=8:0;L=K9 845=B8D8:0B>@ M:A?5@B0, :>B>@><C |
//| ?@8=04;568B B5:CI0O ?>78F8O. |
//+------------------------------------------------------------------+
uint CPosition::ExpertMagic(void)
{
return m_magic;
}
//+------------------------------------------------------------------+
//| >72@0I05B C=8:0;L=K9 845=B8D8:0B>@ ?>78F88. |
//+------------------------------------------------------------------+
ulong CPosition::ID(void)
{
return m_id;
}
//+------------------------------------------------------------------+
//| >72@0I05B F5=C 2E>40 2 ?>78F8N. |
//+------------------------------------------------------------------+
double CPosition::EntryPrice(void)
{
return m_entry_price;
}
//+------------------------------------------------------------------+
//| >72@0I05B 2E>4OI89 :><<5=B0@89 0:B82=>9 ?>78F88. |
//+------------------------------------------------------------------+
string CPosition::EntryComment(void)
{
return m_entry_comment;
}
//+------------------------------------------------------------------+
//| >72@0I05B =0720=85 8=AB@C<5=B0, ?> :>B>@><C >B:@KB0 B5:CI0O |
//| ?>78F8O. |
//+------------------------------------------------------------------+
string CPosition::Symbol(void)
{
return m_symbol;
}
//+------------------------------------------------------------------+
//| >72@0I05B 2@5<O >B:@KB8O ?>78F88. |
//+------------------------------------------------------------------+
datetime CPosition::TimeOpen(void)
{
return m_time_open;
}
//+------------------------------------------------------------------+
//| >72@0I05B 8AB8=C, 5A;8 B5:CI0O ?>78F8O O2;O5BAO G0ABLN |
//| A>AB02=>9, @K=>G=>-=59B@0;L=>9 :><?;5:A=>9 ?>78F88. >72@0I05B |
//| ;>6L 2 ?@>B82=>< A;CG05. |
//+------------------------------------------------------------------+
bool CPosition::IsComplex(void)
{
string comm = EntryComment();
string cp = StringSubstr(comm, 0, 3);
if(cp != "CP[")return false;
cp = StringSubstr(comm, StringLen(comm)-1, 1);
if(cp != "]")return false;
return true;
}
//+------------------------------------------------------------------+
//| >72@0I05B 01A>;NB=K9 C@>25=L AB>?-;>AA0 4;O B5:CI59 ?>78F88. |
//| A;8 C@>25=L AB>?-;>AA0 =5 CAB0=>2;5= 2>72@0I05B 0.0 |
//+------------------------------------------------------------------+
double CPosition::StopLossValue(void)
{
double value = 0.0;
ulong id = ID();
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID() + " not find. Get StopLoss failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
}
value = HedgePositionGetDouble(HEDGE_POSITION_SL);
#endif
return value;
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B 01A>;NB=K9 C@>25=L AB>?-;>AA0 |
//+------------------------------------------------------------------+
bool CPosition::StopLossValue(double sl)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID() + " not find. Set StopLoss failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return false;
}
double tp = HedgePositionGetDouble(HEDGE_POSITION_TP);
HedgeTradeRequest request;
request.action = REQUEST_MODIFY_SLTP;
request.sl = sl;
request.tp = tp;
bool res = SendTradeRequest(request);
if(res)
{
string text = "Position #" + (string)ID() + ": Set new S/L successfully at " + DoubleToString(sl);
CMessage* msg_info = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
Log.AddMessage(msg_info);
}
else
{
string err = EnumToString(GetHedgeError());
string text = "Position #" + (string)ID() + ": Set new S/L failed. Reason: " + err;
CMessage* msg_err = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
Log.AddMessage(msg_err);
}
return res;
#endif
}
//+------------------------------------------------------------------+
//| >72@0I05B 01A>;NB=K9 C@>25=L B59:-?@>D8B0 4;O B5:CI59 ?>78F88. |
//| A;8 C@>25=L B59:-?@>D8B0 =5 CAB0=>2;5= 2>72@0I05B 0.0 |
//+------------------------------------------------------------------+
double CPosition::TakeProfitValue(void)
{
double value = 0.0;
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID() + " not find. Get TakeProfit failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
}
value = HedgePositionGetDouble(HEDGE_POSITION_TP);
#endif
return value;
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B 01A>;NB=K9 C@>25=L B59:-?@>D8B0 |
//+------------------------------------------------------------------+
bool CPosition::TakeProfitValue(double tp)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID() + " not find. Set TakeProfit failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return false;
}
double sl = HedgePositionGetDouble(HEDGE_POSITION_SL);
HedgeTradeRequest request;
request.action = REQUEST_MODIFY_SLTP;
request.sl = sl;
request.tp = tp;
bool res = SendTradeRequest(request);
if(res)
{
string text = "Position #" + (string)ID() + ": Set new T/P successfully at " + DoubleToString(tp);
CMessage* msg_info = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
Log.AddMessage(msg_info);
}
else
{
string err = EnumToString(GetHedgeError());
string text = "Position #" + (string)ID() + ": Set new T/P failed. Reason: " + err;
CMessage* msg_err = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
Log.AddMessage(msg_err);
}
return res;
#endif
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B AB>?-;>AA 2 ?@>F5=B0E >B B5:CI59 F5=K. |
//|  " +: |
//| sl_percent - #@>25=L 2 ?@>F5=B0E >B F5=K 2E>40 2 ?>78F8N, |
//| =0?@8<5@ sl_percent=3.2 = 3,2% >B F5=K 2E>40. |
//+------------------------------------------------------------------+
bool CPosition::StopLossPercent(double sl_percent)
{
if(sl_percent < 0.0 || sl_percent > 100.0)
{
string text = "Position #" + (string)ID() + ": Set S/L must be greater than 0.0 and less than 100 %";
CMessage* msg = new CMessage(MESSAGE_WARNING, __FUNCTION__, text);
Log.AddMessage(msg);
return false;
}
double delta = EntryPrice()*sl_percent/100.0;
double sl = 0.0;
if(Direction() == POSITION_TYPE_BUY)
sl = EntryPrice() - delta;
else
sl = EntryPrice() + delta;
return StopLossValue(sl);
}
//+------------------------------------------------------------------+
//| #AB0=02;8205B B59:-?@>D8B 2 ?@>F5=B0E >B B5:CI59 F5=K. |
//|  " +: |
//| tp_percent - #@>25=L 2 ?@>F5=B0E >B F5=K 2E>40 2 ?>78F8N, |
//| =0?@8<5@ tp_percent=3.2 = 3,2% >B F5=K 2E>40. |
//+------------------------------------------------------------------+
bool CPosition::TakeProfitPercent(double tp_percent)
{
if(tp_percent < 0.0 || tp_percent > 100.0)
{
string text = "Position #" + (string)ID() + ": Set T/P must be greater than 0.0 and less than 100 %";
CMessage* msg = new CMessage(MESSAGE_WARNING, __FUNCTION__, text);
Log.AddMessage(msg);
return false;
}
double delta = EntryPrice()*tp_percent/100.0;
double tp = 0.0;
if(Direction() == POSITION_TYPE_BUY)
tp = EntryPrice() + delta;
else
tp = EntryPrice() - delta;
return TakeProfitValue(tp);
}
//+------------------------------------------------------------------+
//| 0:@K205B B5:CICN ?>78F8N ?> @K=:C, CAB0=02;820O 70:@K20NI89 |
//| :><<5=B0@89 @02=K9 comment |
//+------------------------------------------------------------------+
bool CPosition::CloseAtMarket(string comment = "")
{
return CloseAtMarket(Volume(), 0, comment, false);
}
//+------------------------------------------------------------------+
//| 0:@K205B B5:CICN ?>78F8N ?> @K=:C, CAB0=02;820O 70:@K20NI89 |
//| :><<5=B0@89, >1J5< 8 ?@545;L=>5 >B:;>=5=85 F5=K. |
//+------------------------------------------------------------------+
bool CPosition::CloseAtMarket(double volume, ulong deviation, string comment="")
{
return CloseAtMarket(Volume(), 0, comment, false);
}
//+------------------------------------------------------------------+
//| 0:@K205B B5:CICN ?>78F8N ?> @K=:C. |
//| 0@0<5B@K: |
//| volume - >1J5< :>B>@K9 B@51C5BAO 70:@KBL. >65B 1KBL @025= 8;8 |
//| <5=LH5 B5:CI53> >1J5<0 ?>78F88. |
//| deviation - ?@545;L=>5 >B:;>=5=85 F5=K 2 ?@09AAB5?0E. |
//| comment - 0:@K20NI89 :><<5=B0@89. |
//| >72@0I05<>5 7=0G5=85: AB8=0, 5A;8 70:@KB85 ?>78F88 ?@>H;> |
//| CA?5H=> 8 ;>6L 2 ?@>B82=>< A;CG05. |
//+------------------------------------------------------------------+
bool CPosition::CloseAtMarket(double volume, ulong deviation, string comment="", bool asynch=false)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") not find. Close at market failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return false;
}
HedgeTradeRequest request;
request.action = REQUEST_CLOSE_POSITION;
request.volume = volume;
request.exit_comment = comment;
request.deviation = deviation;
request.asynch_mode = asynch;
bool res = SendTradeRequest(request);
if(res)
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") was successfully closed";
CMessage* msg = new CMessage(MESSAGE_INFO, __FUNCTION__, text);
Log.AddMessage(msg);
}
else
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") closed failed. Reason: " + EnumToString(GetHedgeError());
CMessage* msg = new CMessage(MESSAGE_WARNING, __FUNCTION__, text);
Log.AddMessage(msg);
}
m_is_closed = res;
return res;
#endif
return false;
}
//+------------------------------------------------------------------+
//| >72@0I05B B5:CI89 >1J5< ?>78F88. |
//+------------------------------------------------------------------+
double CPosition::Volume(void)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") not find. Get volume failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return 0.0;
}
double vol = HedgePositionGetDouble(HEDGE_POSITION_VOLUME);
return vol;
#endif
}
//+------------------------------------------------------------------+
//| >72@0I05B B5:CICN ?@81K;L ?>78F88 2 20;NB5 45?>78B0. |
//+------------------------------------------------------------------+
double CPosition::Profit(void)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") not find. Get profit in currency failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return 0.0;
}
double profit = HedgePositionGetDouble(HEDGE_POSITION_PROFIT_CURRENCY);
return profit;
#endif
}
//+------------------------------------------------------------------+
//| >72@0I05B B5:CICN ?@81K;L 2 ?C=:B0E 8=AB@C<5=B0. |
//+------------------------------------------------------------------+
double CPosition::ProfitInPips(void)
{
#ifdef __HT__
if(!TransactionSelect(ID(), SELECT_BY_TICKET, MODE_TRADES))
{
string text = "Position #" + (string)ID()+ "(ExpertMagic = "+ (string)ExpertMagic() + ") not find. Get profit in pips failed.";
CMessage* msg_err = new CMessage(MESSAGE_ERROR, __FUNCTION__, text);
Log.AddMessage(msg_err);
return 0.0;
}
double profit = HedgePositionGetDouble(HEDGE_POSITION_PROFIT_POINTS);
return profit;
#endif
}
//+------------------------------------------------------------------+
//| @>25@O5B :>@@5:B=>ABL ?5@540==>3> C@>2=O stoplevel. >72@0I05B |
//| 8AB8=C, 5A;8 C@>25=L SL O2;O5BAO :>@@5:B=K< 8 ;>6L 2 ?@>B82=>< |
//| A;CG05. |
//+------------------------------------------------------------------+
bool CPosition::CheckStopLevel(double stoplevel)
{
double last = 0.0;
double max = SymbolInfoDouble(m_symbol, SYMBOL_SESSION_PRICE_LIMIT_MAX);
double min = SymbolInfoDouble(m_symbol, SYMBOL_SESSION_PRICE_LIMIT_MIN);
if(stoplevel >= max && max != 0.0)
return false;
if(stoplevel <= min)
return false;
if(m_direction == POSITION_TYPE_BUY)
{
if(stoplevel >= SymbolInfoDouble(m_symbol, SYMBOL_BID))
return false;
return true;
}
else
{
if(stoplevel <= SymbolInfoDouble(m_symbol, SYMBOL_ASK))
return false;
}
return true;
}