Дробное(частичное) закрытие позиции

 

 Есть ли у кого-н. подобная функция? Нужно чтоб закрывалось по достижению определённого уровня по мере удаления от цены открытия .. либо фикс. значениями лота, либо процентом от лота. На форуме подобного не нашёл, поэтому и спрашиваю.

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

 

Покажите как это было реализовано - найдут и ошибку.

А если просто "нипонЯла я" - то в джоб -> https://www.mql5.com/ru/job

 
hoz:

 Есть ли у кого-н. подобная функция? Нужно чтоб закрывалось по достижению определённого уровня по мере удаления от цены открытия .. либо фикс. значениями лота, либо процентом от лота. На форуме подобного не нашёл, поэтому и спрашиваю.

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

Если для конкретного уровня, то ставьте на нем противоположную позу, которая частично перекрывает текущую с таким же мейджиком. А потом закрывайте по встречной.
 
 
ktest0:

Покажите как это было реализовано - найдут и ошибку.

А если просто "нипонЯла я" - то в джоб -> https://www.mql5.com/ru/job

 


 Да не вопрос! Вот смотри:

 Глобальные переменные для этих функций:

extern int i_takeProfit1 = 10;                           // Величина 1-ого тейк-профита
extern int i_takeProfit2 = 20;                           // Величина 2-го тейк-профита
extern int i_takeProfit3 = 0;                            // Величина 3-го тейк-профита
extern int i_tp1Percent = 50;                            // Процент от основного лота для закрытия 1-го тейк- профита
extern int i_tp2Percent = 30;                            // Процент от основного лота для закрытия 2-го тейк-профита
extern int i_tp3Percent = 0;                             // Процент от основного лота для закрытия 3-го тейк-профита
extern int i_slippage = 2;

  В int init помещаем это:

int init()
  {
    minLot = MarketInfo(Symbol(), MODE_MINLOT);
    maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
    lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);

 Дальше вот фукнкции:

//+-------------------------------------------------------------------------------------+
//| TakeProfitLots                                                                      |
//+-------------------------------------------------------------------------------------+
double TakeProfitLots(double lotPrimary, int approach)
{
  double lotDealToClose;                                       // лот для закрытия на данном уровне тейк-профита
  if (approach == 1) lotDealToClose = lotPrimary * i_tp1Percent / 100.0;
      return (LotRound(lotDealToClose));
  if (approach == 2) lotDealToClose = lotPrimary * i_tp2Percent / 100.0;
      return (LotRound(lotDealToClose));
  if (approach == 3) lotDealToClose = lotPrimary * i_tp3Percent / 100.0;
      return (LotRound(lotDealToClose));
}
//+-------------------------------------------------------------------------------------+
//| Проверка объема на корректность и округление                                        |
//+-------------------------------------------------------------------------------------+
double LotRound(double L)
{
  return(MathRound(MathMin(MathMax(L, minLot), maxLot)/lotStep)*lotStep);
}
//+-------------------------------------------------------------------------------------+
//| Определяем количество закрытий ордеров                                              |
//+-------------------------------------------------------------------------------------+
int OrderCloseCount(double ordOpPrice, datetime ordOpTime)
{
  int count = 0;
  
  for (int i = 0; i < OrdersHistoryTotal(); i ++)
  {
    if (OrderSelect(i, SELECT_BY_POS, MODE_HISTORY))
    {
      if (OrderSymbol() != Symbol()) continue;
          if (OrderOpenPrice() == ordOpPrice && OrderOpenTime() == ordOpTime)
              count++;
    }
  }
  
   return (count);
}
//+-------------------------------------------------------------------------------------+
//| Определяем тейк-профиты                                                             |
//+-------------------------------------------------------------------------------------+
void TakeProfits()
{
  int type;
  double OOP;
  datetime OOT;
  double lotik;
  int ticket;
  int counterOfCloses;
  
  for (int i = OrdersTotal() - 1; i >= 0; i --)
  {  
    if (OrderSelect(i, SELECT_BY_POS, MODE_TRADES))
    {
      if (OrderSymbol() != Symbol()) continue;
      type = OrderType();
      OOP = OrderOpenPrice();
      OOT = OrderOpenTime();
      lotik = OrderLots();
      ticket = OrderTicket();
      counterOfCloses = OrderCloseCount(OOP, OOT);
      RefreshRates();
      if (type == OP_SELL)
      {
        if (i_takeProfit1 > 0)
           if (Ask <= OOP - i_takeProfit1 * pt && counterOfCloses < 1)
               OrderClose(ticket, TakeProfitLots(lotik, 1), Ask, i_slippage, Black);
        if (i_takeProfit2 > 0)
           if (Ask <= OOP - i_takeProfit2 * pt && counterOfCloses < 2)
               OrderClose(ticket, TakeProfitLots(lotik, 2), Ask, i_slippage, Black);
        if (i_takeProfit3 > 0)
           if (Ask <= OOP - i_takeProfit3 * pt && counterOfCloses < 3)
               OrderClose(ticket, TakeProfitLots(lotik, 3), Ask, i_slippage, Black);
      }
      if (type == OP_BUY)
      {
        if (i_takeProfit1 > 0)
           if (Bid >= OOP + i_takeProfit1 * pt && counterOfCloses < 1)
               OrderClose(ticket, TakeProfitLots(lotik, 1), Bid, i_slippage, Black);
        if (i_takeProfit2 > 0)
           if (Bid >= OOP + i_takeProfit2 * pt && counterOfCloses < 2)
               OrderClose(ticket, TakeProfitLots(lotik, 2), Bid, i_slippage, Black);
        if (i_takeProfit3 > 0)
           if (Bid >= OOP + i_takeProfit3 * pt && counterOfCloses < 3)
               OrderClose(ticket, TakeProfitLots(lotik, 3), Bid, i_slippage, Black);
      }
    }
  }
}

 Тут странно как-то. Вся позиция (3 части) закрывается пачкой сразу..

Вот скрин:

Закрывает сразу всё 


 
 Вопрос решён, косяк найден...
 

 Хотя нет, как оказалось, что-то не все ордера подхватываются.

Что-то странно работает. Некоторые ордера как-будто пропускает и они висят мёртвым грузом. Что тут не так?

Вот что имеется касательно частичного закрытия лота:

Это в init:

minLot = MarketInfo(Symbol(), MODE_MINLOT);
maxLot = MarketInfo(Symbol(), MODE_MAXLOT);
lotStep = MarketInfo(Symbol(), MODE_LOTSTEP);

 Касательно переменных объявленных на глобальном уровне, которых тут не видно вот что нужно:

extern int i_takeProfit1 = 10;                           // Величина 1-ого тейк-профита
extern int i_takeProfit2 = 20;                           // Величина 2-го тейк-профита
extern int i_takeProfit3 = 25;                           // Величина 3-го тейк-профита
extern int i_tp1Percent = 50;                            // Процент от основного лота для закрытия 1-го тейк- профита
extern int i_tp2Percent = 30;                            // Процент от основного лота для закрытия 2-го тейк-профита
extern int i_tp3Percent = 20;                            // Процент от основного лота для закрытия 3-го тейк-профита
extern int i_slippage = 2;
extern double i_lot = 0.1;
#define SIGNAL_BUY                        0                          // Сигнал на покупку
#define SIGNAL_SELL                       1                          // Сигнал на продажу
#define SIGNAL_NO                        -1                          // Сигнала нет  

 А вот сами функции:

//+-------------------------------------------------------------------------------------+
//|TakeProfitLots                                                                       |
//+-------------------------------------------------------------------------------------+
double TakeProfitLots(double lotPrimary, int approach)
{
  double lotDealToClose;                                       // лот для закрытия на данном уровне тейк-профита
  if (approach == 1)
      lotDealToClose = lotPrimary * i_tp1Percent / 100;
        return (LotRound(lotDealToClose));
  if (approach == 2)
      lotDealToClose = lotPrimary * i_tp2Percent / 100;
        return (LotRound(lotDealToClose));
  if (approach == 3)
      lotDealToClose = lotPrimary * i_tp3Percent / 100;
        return (LotRound(lotDealToClose));
}
//+-------------------------------------------------------------------------------------+
//| Проверка объема на корректность и округление                                        |
//+-------------------------------------------------------------------------------------+
double LotRound(double L)
{
  return(MathRound(MathMin(MathMax(L, minLot), maxLot)/lotStep)*lotStep);
}
//+-------------------------------------------------------------------------------------+
//| Определяем количество закрытий ордеров                                              |
//+-------------------------------------------------------------------------------------+
int OrderCloseCount(double ordOpPrice, datetime ordOpTime)
{
  int count = 0;
  
  for (int i = OrdersHistoryTotal() - 1; i >= 0 ; i--)
  {
    if (!OrderSelect(i, SELECT_BY_POS, MODE_HISTORY)) continue;
      if (OrderSymbol() != Symbol()) continue;
          if (OrderOpenPrice() == ordOpPrice && OrderOpenTime() == ordOpTime)
              count++;
  }
  
   return (count);
}
//+-------------------------------------------------------------------------------------+
//| Определяем тейк-профиты                                                             |
//+-------------------------------------------------------------------------------------+
void TakeProfits()
{
  int type;
  double OOP;
  datetime OOT;
  int ticket;
  int counterOfCloses;
  
  for (int i = OrdersTotal() - 1; i >= 0; i--)
  {  
    if (!OrderSelect(i, SELECT_BY_POS, MODE_TRADES)) continue;
      if (OrderSymbol() != Symbol()) continue;
          type = OrderType();
          OOP = OrderOpenPrice();
          OOT = OrderOpenTime();
          i_lot = OrderLots();
          ticket = OrderTicket();
          counterOfCloses = OrderCloseCount(OOP, OOT);
          
          RefreshRates();
          
          if (type == OP_SELL)
          {
           if (i_takeProfit1 > 0)
               if (Ask <= OOP - i_takeProfit1 * pt && counterOfCloses == 0)
                   OrderClose(ticket, TakeProfitLots(i_lot, 1), Ask, i_slippage, Black);
           if (i_takeProfit2 > 0)
               if (Ask <= OOP - i_takeProfit2 * pt && counterOfCloses == 1)
                   OrderClose(ticket, TakeProfitLots(i_lot, 2), Ask, i_slippage, Black);
           if (i_takeProfit3 > 0)
               if (Ask <= OOP - i_takeProfit3 * pt && counterOfCloses == 2)
                  OrderClose(ticket, TakeProfitLots(i_lot, 3), Ask, i_slippage, Black);
          }
          
          if (type == OP_BUY)
          {
           if (i_takeProfit1 > 0)
               if (Bid >= OOP + i_takeProfit1 * pt && counterOfCloses == 0)
                   OrderClose(ticket, TakeProfitLots(i_lot, 1), Bid, i_slippage, Black);
           if (i_takeProfit2 > 0)
               if (Bid >= OOP + i_takeProfit2 * pt && counterOfCloses == 1)
                   OrderClose(ticket, TakeProfitLots(i_lot, 2), Bid, i_slippage, Black);
           if (i_takeProfit3 > 0)
               if (Bid >= OOP + i_takeProfit3 * pt && counterOfCloses == 2)
                   OrderClose(ticket, TakeProfitLots(i_lot, 3), Bid, i_slippage, Black);
          }
  }
}  

Вот скрины, на которых видны недочёты: 

 

 
hoz:

Виктор,, есть надёжный и проверенный способ. Представляете одну позицию в виде группы позиций. И на каждого "члена" этой группы устанавливаете свой ТР и SL. Этот способ тем более удобен, если вы применяете отложенные ордера

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


 Т.е. в минус или в плюс идем - неважно, все равно закрываем ордер?

И что делает функция OrderCloseCount(), опишите подробнее.

 

Алгоритм прост как бублик.

При частичном закрытии не меняется Magic. Тикет меняется, а магик - нет.

Есть открытая поза, есть уровни, на которых эта поза должна частями закрываться.

Допустим Level1, Level2 и Level3.

Если поза Buy в профите и Bid >= Level1 && Bid< Level2 ---> закрываем первую часть позиции (лотом, меньшим, чем лот этой позиции, при условии, что оставшийся лот не будет меньше минимального лота), далее:

Если Bid >= Level2 && Bid< Level3 ---> закрываем вторую часть позиции (лотом, меньшим, чем лот этой позиции, при условии, что оставшийся лот не будет меньше минимального лота), далее:

Если Bid >= Level3 ---> закрываем третью часть позиции (лотом, меньшим, чем лот этой позиции, при условии, что оставшийся лот не будет меньше минимального лота), далее:

1. Если при третьем частичном закрытии на уровне Bid>=Level3 лот стал меньше минимального ---> закрываем всю позицию

2. Если после третьего закрытия на уровне Bid>=Level3 ещё осталась позиция, либо сопровождаем оставшуюся позу тралом, либо закрываем её всю.

Это всё.

Для Sell смотрим по Ask: Ask<=Level1 && Ask>Level2 ... и т.д. ...

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

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

И ещё: после частичного закрытия не забывайте подтягивать защитный стоп. После закрытия на уровне1 - стоп в безубыток, после закрытия на уровне2 - стоп на уровень1, после закрытия на уровне 3 - стоп на уровень2...

Причина обращения: