Правильный расчет цены безубытка, для серии ордеров. Алгоритм. - страница 2

 

Написал класс для расчета безубытка для mql5

#include <Trade/PositionInfo.mqh>
#include <Trade/OrderInfo.mqh>
//+------------------------------------------------------------------+
//|                 BREAKEVEN CLASS                                  |
//+------------------------------------------------------------------+
class CBreakEven
  {
private:
   double            lotDiff;
   CPositionInfo     pos;
   COrderInfo        ord;
   double            GetBreakEven(double& lot, string symbol=NULL, long magic=-1, int type=-1, bool pend=false);
   double            GetPointValue(string symbol);
   double            GetBreakEven(
      double&  lot,
      bool&    buy,
      string   symbol=NULL,
      long     magic=-1,
      int      type=-1,
      bool     pend=false)
     {

      double ret=GetBreakEven(buy, symbol, magic, type, pend);
      lot=lotDiff;
      return(ret);
     };

public:
   void              CBreakEven() {lotDiff=0;};
   double            GetBreakEven(bool &buy, string symbol=NULL, long magic=-1, int type=-1, bool pend=false);
   double            GetBreakEvenPoints(double points, string symbol=NULL, long magic=-1, int type=-1, bool pend=false);
   double            GetBreakEvenMoney(double money, string symbol=NULL, long magic=-1, int type=-1, bool pend=false);
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CBreakEven::GetBreakEven(double &lot, string symbol=NULL, long magic=-1, int type=-1, bool pend=false)
  {
   lot=0;
   double total=0;
   double fees=0;
   if(symbol==NULL)
      symbol=Symbol();
   bool custom=false;
   if(!SymbolExist(symbol,custom))
      return(0);
   for(int i=0; i<PositionsTotal(); i++)
     {
      if(!pos.SelectByIndex(i))
         continue;
      if(pos.Symbol()!=symbol)
         continue;
      if(pos.PositionType()!=type && type!=-1)
         continue;
      if(pos.Magic()!=magic && magic!=-1)
         continue;
      double l=pos.Volume();
      double p=pos.PriceOpen();
      total+=l*p;
      lot+=l;
      fees+=pos.Commission()+pos.Swap();
     }
   if(pend)
     {
      int op1=type==-1 ? -1:
              type==POSITION_TYPE_BUY ? ORDER_TYPE_BUY_STOP:ORDER_TYPE_SELL_STOP;
      int op2=type==-1 ? -1:
              type==POSITION_TYPE_BUY ? ORDER_TYPE_BUY_LIMIT:ORDER_TYPE_SELL_LIMIT;

      for(int i=0; i<OrdersTotal(); i++)
        {
         if(!ord.SelectByIndex(i))
            continue;
         if(ord.Symbol()!=symbol)
            continue;
         if(ord.Magic()!=magic && magic!=-1)
            continue;
         bool cond1=type==-1 || ord.OrderType()==op1;
         bool cond2=type==-1 || ord.OrderType()==op2;
         if(!cond1 && !cond2)
            continue;

         double l=ord.VolumeCurrent();
         double p=ord.PriceOpen();
         total+=l*p;
         lot+=l;
        }
     }
   if(lot>0)
     {
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      double corr=point*(fees/(lot*GetPointValue(symbol)));
      double coef=type==POSITION_TYPE_BUY ? -1.0:1.0;
      double ret=(total+coef*corr*lot)/lot;
      return(ret);
     }
   return(0);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CBreakEven::GetPointValue(string symbol)
  {
   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
   double tickValue=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_VALUE);
   double tickSize=SymbolInfoDouble(symbol,SYMBOL_TRADE_TICK_SIZE);
   double pointValue=tickValue*(point/tickSize);
   return (pointValue);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CBreakEven::GetBreakEven(
   bool     &buy,
   string   symbol= NULL,
   long     magic = -1,
   int      type=-1,
   bool     pend=false)
  {

   if(type !=-1)
     {
      buy = type==POSITION_TYPE_BUY ? true : false;
      return(GetBreakEven(lotDiff,symbol,magic,type,pend));
     }

   double buylot=0, selllot=0;
   double levbuy=GetBreakEven(buylot,symbol,magic,POSITION_TYPE_BUY,pend);
   double levsell=GetBreakEven(selllot,symbol,magic,POSITION_TYPE_SELL,pend);
   lotDiff=MathAbs(buylot-selllot);

   double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
   double pointval=GetPointValue(symbol);
   double spread=(double)SymbolInfoInteger(symbol,SYMBOL_SPREAD)*point;
   if(buylot>selllot)
     {
      buy=true;
      if(selllot==0)
         return(levbuy);
      double diff=buylot-selllot;
      if(levbuy>=levsell)
        {
         double dist=(levbuy-levsell+spread*(selllot/buylot))/point;
         double loss=selllot*dist*pointval;
         double lev=levbuy+point*(loss/(diff*pointval));
         return(lev);
        }
      else
        {
         double dist=(levsell-levbuy-spread*(selllot/buylot))/point;
         double prof=selllot*dist*pointval;
         double lev=levbuy-point*(prof/(diff*pointval));
         return(lev);
        }
     }
   else
      if(buylot<selllot)
        {
         buy=false;
         if(buylot==0)
            return(levsell);
         double diff=selllot-buylot;
         if(levbuy>=levsell)
           {
            double dist=(levbuy-levsell+spread*(buylot/selllot))/point;
            double loss=buylot*dist*pointval;
            double lev=levsell-point*(loss/(diff*pointval));
            return(lev);
           }
         else
           {
            double dist=(levsell-levbuy-spread*(buylot/selllot))/point;
            double prof=buylot*dist*pointval;
            double lev=levsell+point*(prof/(diff*pointval));
            return(lev);
           }
        }
   return(0);
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CBreakEven::GetBreakEvenPoints(
   double points,
   string symbol=NULL,
   long magic=-1,
   int type=-1,
   bool pend=false)
  {

   double ret=0;
   string sym=symbol==NULL ? Symbol() : symbol;
   bool custom=false;
   if(!SymbolExist(sym,custom))
      return(0);
   if(sym != "")
     {
      bool buy=true;
      double be=GetBreakEven(buy,sym,magic,type,pend);
      if(be>0)
        {
         double coef = buy ? 1.0 : -1.0;
         double point=SymbolInfoDouble(sym,SYMBOL_POINT);
         int dig=(int)SymbolInfoInteger(sym,SYMBOL_DIGITS);
         ret = NormalizeDouble(be + coef*points*point, dig);
        }
     }
   return(ret);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
double CBreakEven::GetBreakEvenMoney(
   double money,
   string symbol=NULL,
   long magic=-1,
   int type=-1,
   bool pend=false)
  {

   string sym=symbol==NULL ? Symbol() : symbol;
   bool custom=false;
   if(!SymbolExist(sym,custom))
      return(0);

   double ret=0;
   bool buy=true;
   double lots=0;
   double be=GetBreakEven(lots,buy,symbol,magic,type,pend);
   if(be>0)
     {

      double pointVal=GetPointValue(symbol);
      double coef = buy ? 1.0 : -1.0;
      double point=SymbolInfoDouble(symbol,SYMBOL_POINT);
      double dist=money/(lots*pointVal)*point;
      int dig=(int)SymbolInfoInteger(symbol,SYMBOL_DIGITS);
      ret = NormalizeDouble(be + coef*dist, dig);
     }
   return(ret);
  }
 
Неужели все единодушны во мнении, что нужно такое лютое усложнение на ровном месте?
 
Ihor Herasko:

Цена БУ для серии ордеров одного направления:


    Благодарю.

    На самом деле у меня такая же формула, только я не разделяю своп+комиссию от прибылии.


    НЕ двигать СЛ и ТП, если изменение меньше спреда - хорошая идея. А если спред = 0, брать минималку в 1-2 пункта (например)

     
    pribludilsa:
    Неужели все единодушны во мнении, что нужно такое лютое усложнение на ровном месте?

    Ну а в чем усложнение то? Ордеров много, если сетка. Поэтому и кажется, что сложно. Это минимально необходимые действия, если нужен универсализм, например, для кроссов.

     
    Ihor Herasko:

    Ну а в чем усложнение то? Ордеров много, если сетка. Поэтому и кажется, что сложно. Это минимально необходимые действия, если нужен универсализм, например, для кроссов.

    Что такое кроссы? Я не понимаю зачем это всё, считаю прибыль. Результат то один, а насколько проще.

     
    pribludilsa:

    Что такое кроссы? 

    Кроссы - это когда и базовая, и котируемая валюта символа не являются валютой депозита. Например, GBPJPY при валюте депозита USD является кроссом, т. к. прибыль по ней рассчитывается на основании цены символа GBPUSD. В таких случаях необходимо учитывать стоимость одного изменения цены, которая постоянно меняется из-за изменения цены GBPUSD.

    Я не понимаю зачем это всё, считаю прибыль. Результат то один, а насколько проще.

    Интересно, как же Вы считаете? Ну вот даже для простого случая приведите пример. Есть Buy 0.15 лот по цене 1.25678 и Buy 0.35 лот по цене 1.26532. Как Вы определяете цену безубытка, исходя только из величины прибыли?
     
    Ihor Herasko:

    Кроссы - это когда и базовая, и котируемая валюта символа не являются валютой депозита. Например, GBPJPY при валюте депозита USD является кроссом, т. к. прибыль по ней рассчитывается на основании цены символа GBPUSD. В таких случаях необходимо учитывать стоимость одного изменения цены, которая постоянно меняется из-за изменения цены GBPUSD.


    Спасибо. Подумаю над этим. Нужно на этих инструментах поторговать, может чего то не знаю. Но мне показалось вполне изящным решением запрашивать прибыль и ее складывать, ведь то, о чем Вы говорите, должно отражаться в прибыли. У меня только упускается половина комиссии, она берется в момент закрытия потому что, пока этим пренебрёг. Может, когда это начну решать, приду к вашему способу.

     
    Интересно, как же Вы считаете? Ну вот даже для простого случая приведите пример. Есть Buy 0.15 лот по цене 1.25678 и Buy 0.35 лот по цене 1.26532. Как Вы определяете цену безубытка, исходя только из величины прибыли?

    Запрашиваю прибыль позиции и всё. Я тейки не ставлю, точно, наверно по этому весь вопрос возник. У меня закрытие онлайн происходит. Ну как бы виртуальный тейк, кажется называется.

     
    pribludilsa:

    Спасибо. Подумаю над этим. Нужно на этих инструментах поторговать, может чего то не знаю. Но мне показалось вполне изящным решением запрашивать прибыль и ее складывать, ведь то, о чем Вы говорите, должно отражаться в прибыли. У меня только упускается половина комиссии, она берется в момент закрытия потому что, пока этим пренебрёг. Может, когда это начну решать, приду к вашему способу.

    Возможно, Вы просто сравниваете совокупную прибыль с целевой? Да, так тоже можно делать. Но проблема в том, что при большом количестве рыночных ордеров (позиций) придется закрывать все торговыми приказами (по рынку). На это уйдет достаточно много времени, а цена будет изменяться. 

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

     
    pribludilsa:

    Запрашиваю прибыль позиции и всё. Я тейки не ставлю, точно, наверно по этому весь вопрос возник. У меня закрытие онлайн происходит. Ну как бы виртуальный тейк, кажется называется.

    В таком случае нужно постоянно быть онлайн, а это на 100% невозможно. Чтобы обезопасить позиции, приходится ставить стопы/профиты.

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