Closing Multiple Trades at once - page 2

 
nicholishen:

I know that my example looks to be over complicated on the surface, however, I designed it that way so that it could close all open orders/positions in the following way for maximum risk mitigation.

Operation Summary:

  1. Net positions are calculated per symbol (sum of all open trades).
  2. Symbols are prioritized to manage net-positions from larger (more risk) to smaller.
  3. Hedge orders are sent in the order of priority to close all exposure at once regardless of the number of trades.
  4. Once all open-exposure is hedged the program then prioritizes pending orders
  5. Pending orders are deleted in order of highest risk of being executed
  6. Remaining hedged positions (closed by hedge) are then reconciled on the broker server using CloseBy()

Now I see that my code has the same risks as yours. I did not see pending orders in your code. Probably, you did not show the full version.

 
fxsaber:

Now I see that my code has the same risks as yours. I did not see pending orders in your code. Probably, you did not show the full version.


Oh wow... good catch! I posted the completely wrong file! haha. ...sorry

Files:
 
nicholishen:

Oh wow... good catch! I posted the completely wrong file! haha. ...sorry

I'm reading now. Without "virtual" I could not immediately understand why such a function.

   int Compare(const CObject *node,const int mode=0)const override
   {
      OpenTradeSymbol* other = (OpenTradeSymbol*)node;
      if(fabs(this.Size())>fabs(other.Size()))return -1;
      if(fabs(this.Size())<fabs(other.Size()))return 1;
      return 0;
   }

"override" prompted, but still I would like to see "virtual", too.


Changed some code

class PendingOrder : public CObject
{
protected:
   const int m_ticket;
public:
   PendingOrder(int ticket):m_ticket(ticket){}
   int Ticket(){return m_ticket;}
   int Points()const
   {
      if(!OrderSelect(m_ticket,SELECT_BY_TICKET))
         return 0;
//      double _point = SymbolInfoDouble(OrderSymbol(),SYMBOL_POINT);
//      double bid = SymbolInfoDouble(OrderSymbol(),SYMBOL_BID);
      return int(fabs(OrderOpenPrice()-OrderClosePrice()));
   }
 
fxsaber:

I'm reading now. Without "virtual" I could not immediately understand why such a function.

"override" prompted, but still I would like to see "virtual", too.

Fair enough.
 
fxsaber:

I'm reading now. Without "virtual" I could not immediately understand why such a function.

"override" prompted, but still I would like to see "virtual", too.


Changed some code

Do you use git? 
 
nicholishen:
Do you use git? 

No, I use only ME.

 
nicholishen:

I fully understood your code. There are some pitfalls that I can not explain due to poor English( I use GoogleTranslate).


OpenTradeSymbol::Size() - this is a poor risk function. Risk(1 lot EURUSD) != Risk (1 lot EURNOK).


Similarly with this function - PendingOrder::Points(). Risk(1 point to openprice pending order EURUSD) != Risk(1 point to openprice pending order EURNOK).

Also, the TP and SL levels are not taken into account when calculating the risk.


But this is all nit-picking, of course, on my part. The logic of your code is easy to read, you're done, thank you.

 
fxsaber:

I fully understood your code. There are some pitfalls that I can not explain due to poor English( I use GoogleTranslate).


OpenTradeSymbol::Size() - this is a poor risk function. Risk(1 lot EURUSD) != Risk (1 lot EURNOK).


Similarly with this function - PendingOrder::Points(). Risk(1 point to openprice pending order EURUSD) != Risk(1 point to openprice pending order EURNOK).

Also, the TP and SL levels are not taken into account when calculating the risk.


But this is all nit-picking, of course, on my part. The logic of your code is easy to read, you're done, thank you.


Thank you very much for taking the time to review my code! I appreciate the feedback. What do you think of the following changes?


"OpenTradeSymbol::Size() - this is a poor risk function. Risk(1 lot EURUSD) != Risk (1 lot EURNOK)."

I agree. I think the best method would be to compute the lots * tick_value

   double Risk() const
   {
      return fabs(Size())*SymbolInfoDouble(m_symbol,SYMBOL_TRADE_TICK_VALUE);
   }
   
   virtual int Compare(const CObject *node,const int mode=0)const override
   {
      const LiveOrder* other = node;
      if(this.Risk()>other.Risk())
         return -1;
      if(this.Risk()<other.Risk())
         return 1;
      return 0;
   }


"Similarly with this function - PendingOrder::Points(). Risk(1 point to openprice pending order EURUSD) != Risk(1 point to openprice pending order EURNOK). Also, the TP and SL levels are not taken into account when calculating the risk."

This is the best feedback. I totally forgot to handle remaining stop levels as pending orders! The pending orders class now handles stop levels as pending orders.

   int NumTicks()const
   {
      if(!OrderSelect(m_ticket,SELECT_BY_TICKET))
         return 0;
      double tick_size=SymbolInfoDouble(OrderSymbol(),SYMBOL_TRADE_TICK_SIZE);
      if(OrderType()>=2)
         return int(fabs(OrderOpenPrice()-OrderClosePrice())/tick_size);
      double sl = OrderStopLoss() > 0.0 ? OrderStopLoss() : DBL_MAX;
      double tp = OrderTakeProfit() > 0.0 ? OrderTakeProfit() : DBL_MAX;
      return (int)fmin(fabs(OrderOpenPrice()-sl)/tick_size,fabs(OrderOpenPrice()-tp)/tick_size);
   }
   virtual int Compare(const CObject *node,const int mode=0)const override
   {
      const PendingOrder* other = node;
      if(this.NumTicks()>other.NumTicks())
         return 1;
      if(this.NumTicks()<other.NumTicks())
         return -1;
      return 0;
   }


   void ClosePending()
   {
      m_pending_list.Clear();
      int attempts = 0;
      while(!IsStopped()&&!AllPendingClosed()&&attempts<3)
      {
         for(int i=OrdersTotal();i>=0;i--)
         {
            if(OrderSelect(i,SELECT_BY_POS) && (OrderType()>=2 || OrderStopLoss() != 0.0 || OrderTakeProfit() != 0.0))
               m_pending_list.Add(new PendingOrder(OrderTicket()));
         }
         m_pending_list.Sort();
         for(int i=0;i<m_pending_list.Total();i++)
         {
            if(!m_pending_list[i].DeletePending())
               Print("OrderDeleteError: ",ErrorDescription(GetLastError()));   
         }
         attempts++;
      }
   }
 

I caught a bug in the pending order loop. The list should clear on every iteration. 

   void ClosePending()
   {
      //m_pending_list.Clear();
      int attempts = 0;
      while(!IsStopped()&&!AllPendingClosed()&&attempts<3)
      {
         m_pending_list.Clear();
         for(int i=OrdersTotal()-1;i>=0;i--)
         {
            if(OrderSelect(i,SELECT_BY_POS) && (OrderType()>=2 || OrderStopLoss() != 0.0 || OrderTakeProfit() != 0.0))
               m_pending_list.Add(new PendingOrder(OrderTicket()));
         }
         m_pending_list.Sort();
         for(int i=0;i<m_pending_list.Total();i++)
         {
            if(!m_pending_list[i].DeletePending())
               Print("OrderDeleteError: ",ErrorDescription(GetLastError()));   
         }
         attempts++;
      }
   }

 I also caught a major redundancy and changed the following:

   void ClosePending()
   {
      int attempts = 0;
      while(!IsStopped()&&!AllPendingClosed()&&attempts<3)
      {
         for(int i=0;i<m_pending_list.Total();i++)
         {
            if(!m_pending_list[i].DeletePending())
               Print("OrderDeleteError: ",ErrorDescription(GetLastError()));   
         }
         attempts++;
      }
   }
protected:
  
   bool  AllPendingClosed()
   {
      m_pending_list.Clear();
      for(int i=OrdersTotal()-1;i>=0;i--)
      {
         if(OrderSelect(i,SELECT_BY_POS) && (OrderType()>=2 || OrderStopLoss() != 0.0 || OrderTakeProfit() != 0.0))
            m_pending_list.Add(new PendingOrder(OrderTicket()));
      }
      m_pending_list.Sort();
      return m_pending_list.Total() == 0;
   }
Files:
 
return int ( fabs ( OrderOpenPrice ()- OrderClosePrice ())/tick_size);
template <typename T>
T MyPrint( const T Value, const string Str )
{
  static const bool IsDebug = MQLInfoInteger(MQL_DEBUG);

//  if (IsDebug)
  {
//    DebugBreak(); // если хочется посмотреть средствами дебага

    Print(Str + " = " + (string)Value);
  }
  
  return(Value);
}

#define _P(A) MyPrint(A, __FUNCSIG__ ", Line = " + (string)__LINE__ + ": " + #A)

int PriceToInteger( const double Price, const double point )
{
  return((int)(Price / point + 0.1));
}

void OnStart()
{
  double Price1 = 1.23456;
  double Price2 = 1.23457;
  double point = 1e-5;
  
  _P(Price1);
  _P(Price2);
  
  _P((int)fabs((Price1 - Price2) / point));
  _P(fabs(PriceToInteger(Price1, point) - PriceToInteger(Price2, point)));
}


Result

void OnStart(), Line = 28: Price1 = 1.23456
void OnStart(), Line = 29: Price2 = 1.23457
void OnStart(), Line = 31: (int)fabs((Price1-Price2)/point) = 0
void OnStart(), Line = 32: fabs(PriceToInteger(Price1,point)-PriceToInteger(Price2,point)) = 1
Reason: