467 lines
No EOL
39 KiB
MQL5
467 lines
No EOL
39 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| 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"
|
|
//+------------------------------------------------------------------+
|
|
//| Класс активной позиции, для классических стратегий |
|
|
//+------------------------------------------------------------------+
|
|
class CPosition : public CObject
|
|
{
|
|
private:
|
|
ulong m_id; // Уникальный идентификатор позиции
|
|
uint m_magic; // Уникальный идентификатор эксперта, к которому принадлежит данная позиция.
|
|
ENUM_POSITION_TYPE m_direction; // Направление позиции
|
|
double m_entry_price; // Цена входа в позицию
|
|
string m_symbol; // Инструмент, по которому открыта позиция
|
|
datetime m_time_open; // Время открытия
|
|
string m_entry_comment; // Входящий комментарий
|
|
bool m_is_closed; // Истина, если позиция была закрыта
|
|
CLog* Log; // Логирование
|
|
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
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает истину, если текущая позиция активна. Возвращает ложь |
|
|
//| в противном случае. |
|
|
//+------------------------------------------------------------------+
|
|
bool CPosition::IsActive(void)
|
|
{
|
|
return m_time_open > 0 && !m_is_closed;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает направление позиции. |
|
|
//+------------------------------------------------------------------+
|
|
ENUM_POSITION_TYPE CPosition::Direction(void)
|
|
{
|
|
return m_direction;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает уникальный идентификатор эксперта, которому |
|
|
//| принадлежит текущая позиция. |
|
|
//+------------------------------------------------------------------+
|
|
uint CPosition::ExpertMagic(void)
|
|
{
|
|
return m_magic;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает уникальный идентификатор позиции. |
|
|
//+------------------------------------------------------------------+
|
|
ulong CPosition::ID(void)
|
|
{
|
|
return m_id;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает цену входа в позицию. |
|
|
//+------------------------------------------------------------------+
|
|
double CPosition::EntryPrice(void)
|
|
{
|
|
return m_entry_price;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает входящий комментарий активной позиции. |
|
|
//+------------------------------------------------------------------+
|
|
string CPosition::EntryComment(void)
|
|
{
|
|
return m_entry_comment;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает название инструмента, по которому открыта текущая |
|
|
//| позиция. |
|
|
//+------------------------------------------------------------------+
|
|
string CPosition::Symbol(void)
|
|
{
|
|
return m_symbol;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает время открытия позиции. |
|
|
//+------------------------------------------------------------------+
|
|
datetime CPosition::TimeOpen(void)
|
|
{
|
|
return m_time_open;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает истину, если текущая позиция является частью |
|
|
//| составной, рыночно-нейтральной комплексной позиции. Возвращает |
|
|
//| ложь в противном случае. |
|
|
//+------------------------------------------------------------------+
|
|
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;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает абсолютный уровень стоп-лосса для текущей позиции. |
|
|
//| Если уровень стоп-лосса не установлен возвращает 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;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает абсолютный уровень стоп-лосса |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает абсолютный уровень тейк-профита для текущей позиции. |
|
|
//| Если уровень тейк-профита не установлен возвращает 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;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает абсолютный уровень тейк-профита |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает стоп-лосс в процентах от текущей цены. |
|
|
//| ПАРАМЕТРЫ: |
|
|
//| sl_percent - Уровень в процентах от цены входа в позицию, |
|
|
//| например sl_percent=3.2 = 3,2% от цены входа. |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Устанавливает тейк-профит в процентах от текущей цены. |
|
|
//| ПАРАМЕТРЫ: |
|
|
//| tp_percent - Уровень в процентах от цены входа в позицию, |
|
|
//| например tp_percent=3.2 = 3,2% от цены входа. |
|
|
//+------------------------------------------------------------------+
|
|
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);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Закрывает текущую позицию по рынку, устанавливая закрывающий |
|
|
//| комментарий равный comment |
|
|
//+------------------------------------------------------------------+
|
|
bool CPosition::CloseAtMarket(string comment = "")
|
|
{
|
|
return CloseAtMarket(Volume(), 0, comment, false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Закрывает текущую позицию по рынку, устанавливая закрывающий |
|
|
//| комментарий, объем и предельное отклонение цены. |
|
|
//+------------------------------------------------------------------+
|
|
bool CPosition::CloseAtMarket(double volume, ulong deviation, string comment="")
|
|
{
|
|
return CloseAtMarket(Volume(), 0, comment, false);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Закрывает текущую позицию по рынку. |
|
|
//| Параметры: |
|
|
//| volume - объем который требуется закрыть. Может быть равен или |
|
|
//| меньше текущего объема позиции. |
|
|
//| deviation - предельное отклонение цены в прайсстепах. |
|
|
//| comment - Закрывающий комментарий. |
|
|
//| Возвращаемое значение: Истина, если закрытие позиции прошло |
|
|
//| успешно и ложь в противном случае. |
|
|
//+------------------------------------------------------------------+
|
|
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;
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текущий объем позиции. |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текущую прибыль позиции в валюте депозита. |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| Возвращает текущую прибыль в пунктах инструмента. |
|
|
//+------------------------------------------------------------------+
|
|
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
|
|
}
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| Проверяет корректность переданного уровня stoplevel. Возвращает |
|
|
//| истину, если уровень SL является корректным и ложь в противном |
|
|
//| случае. |
|
|
//+------------------------------------------------------------------+
|
|
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;
|
|
} |