Assistance turning a netting-only EA into a hedge-activated-broker-compatible EA.

 

Dear MQL5 community,

First of all I'd like to say I'm not the kind of guy to randomly post a question every time I stumble upon an issue. As a matter of fact this is my first post here ever even though I've been using MQL5 for years and coded multiple EAs of varying complexity, some of which running live for a long time. I've been spending days (if not weeks) researching this and trying many different things to make my netting-only EA work properly with hedge-activated-brokers. Something must be missing because I can't get a trade to close.

I must clarify first I guess: the purpose is not to hedge anything; just to be able to open a long or a short and then closing it, then repeating the process.

Most (if not all) of the information I found talks about using "close by" but just assumes there are already 2 opposite positions open. Now, I've tried using my current code which simply opens an opposite position to close, then adding a "close by" order after but I'm obviously missing something.

Would anyone please enlighten me (and another potential lost soul like me in a quest for the same information)?

Here are my "OpenLong" and "CloseLong" functions:

bool NewLong(string symbol)
  {
   MqlTick last_tick;
   SymbolInfoTick(symbol,last_tick);
   MqlTradeResult result;
   MqlTradeRequest request;

   ZeroMemory(result);
   ZeroMemory(request);

   request.symbol=symbol;
   request.magic=magic;
   request.deviation=Slip;
   request.action=TRADE_ACTION_DEAL;
   request.type_filling=ORDER_FILLING_FOK;
   request.volume=Vol;
   float testsl = last_tick.bid-Stop*Point();
   if(testsl <= 0){testsl = 0.05;}
   request.sl=testsl;
   request.tp=last_tick.ask+Tp*Point();
   request.price=last_tick.ask;
   request.type=ORDER_TYPE_BUY;
   bool success = OrderSend(request,result);
   if(!success){FailPrint(request,result);}
   return success;
  }

bool CloseLong(string symbol,ulong identify)
  {
   MqlTick last_tick;
   SymbolInfoTick(symbol,last_tick);
   MqlTradeResult result;
   MqlTradeRequest request;
   ZeroMemory(result);
   ZeroMemory(request);
   
   PositionSelect(symbol);

   request.symbol=symbol;
   request.magic=777;
   request.deviation=Slip;
   request.action=TRADE_ACTION_CLOSE_BY;
   request.type_filling=ORDER_FILLING_FOK;
   request.volume=Vol;
   request.sl=last_tick.ask+Stop*Point();
   request.tp=last_tick.bid-Tp*Point();;
   request.price=last_tick.bid;
   request.position=identify;
   request.type=ORDER_TYPE_SELL;
   ResetLastError();
   bool success = OrderSend(request,result);
   if(!success){FailPrint(request,result);}
   return success;
  }

Obviously just replacing "ORDER_TYPE_SELL" by "ORDER_TYPE_CLOSE_BY" would be too easy and of course it failed.

So I tried to get the identifier ID in the OnTrade event then feeding that into the Close functions, while removing the bits that seemed unnecessary in there (from the examples I've seen of "close by" code)

void OnTrade()
  {
   if(PositionSelect(_Symbol))
     {
      Ident = PositionGetInteger(POSITION_IDENTIFIER);
     }

I've also tried to get and use the ticket number instead (I seem to not understand the difference between these 2 and what to use one or the other for...)

void OnTrade()
  {
   int total=PositionsTotal(); // number of open positions  
   if(PositionSelect(_Symbol))
     {
      for(int i=total-1; i>=0; i--)
        {
         //--- parameters of the order
         ulong  position_ticket=PositionGetTicket(i);                                    // ticket of the position
         string position_symbol=PositionGetString(POSITION_SYMBOL);                      // symbol 
         if(position_symbol==_Symbol)
           {
            Ident = position_ticket;
           }
        }

I've tried inserting ready-made code for "close all trades" to no avail.

I've also tried to include "trade.mqh" and to use its functions as some people simply point to it as the magical answer to everything but it seems I wasn't even able to call the functions within it from my EA. Again I must be missing something (something about "objects" I guess, I've never needed that but I'd be more than willing to learn if someone has a comprehensive link about it!) but when looking at the code in trade.mqh I feel that the problem will be the same as with my own code... 

Now I think I understand that I must already have 2 opposite positions in order to use "close by".

So my questions are:

Is there an easy way to close a single position in hedge mode? If so, could you please point me in the right direction?

If there isn't, how do I go about opening another opposite position then closing both with the "close by"? My attempts at that failed... (see below, it's not neat but I was just trying to get a trade to close; planning to clean up after)

 bool CloseLong(string symbol,ulong identify)
  {
   MqlTick last_tick;
   SymbolInfoTick(symbol,last_tick);
   MqlTradeResult result;
   MqlTradeRequest request;
   ZeroMemory(result);
   ZeroMemory(request);
   
   PositionSelect(symbol);

   request.symbol=symbol;
   request.magic=777;
   request.deviation=Slip;
   request.action=TRADE_ACTION_CLOSE_BY;
   request.type_filling=ORDER_FILLING_FOK;
   request.volume=Vol;
   request.sl=last_tick.ask+Stop*Point();
   request.tp=last_tick.bid-Tp*Point();;
   request.price=last_tick.bid;
   request.position=identify;
   request.type=ORDER_TYPE_SELL;
   ResetLastError();
   bool success = OrderSend(request,result);
   if(!success){FailPrint(request,result);}
   bool success2 = KickIt(symbol);
   if(!success2){FailPrint(request,result);}
   return success2;
  }

Created "KickIt" from some ready-made code I found somewhere. Bit of a desperate attempt..

bool KickIt(string symbol)
  {
   MqlTradeRequest request2;
   MqlTradeResult  result2;
   int total=PositionsTotal(); // number of open positions   
   bool success = FALSE
//--- iterate over all open positions
   for(int i=total-1; i>=0; i--)
     {
      //--- parameters of the order
      ulong  position_ticket=PositionGetTicket(i);                                    // ticket of the position
      string position_symbol=PositionGetString(POSITION_SYMBOL);                      // symbol 
      int    digits=(int)SymbolInfoInteger(position_symbol,SYMBOL_DIGITS);            // ticket of the position
      ulong  magic=PositionGetInteger(POSITION_MAGIC);                                // MagicNumber of the position
      double volume=PositionGetDouble(POSITION_VOLUME);                               // volume of the position
      double sl=PositionGetDouble(POSITION_SL);                                       // Stop Loss of the position
      double tp=PositionGetDouble(POSITION_TP);                                       // Take Profit of the position
      ENUM_POSITION_TYPE type=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);  // type of the position
      //--- output information about the position
      PrintFormat("#%I64u %s  %s  %.2f  %s  sl: %s  tp: %s  [%I64d]",
                  position_ticket,
                  position_symbol,
                  EnumToString(type),
                  volume,
                  DoubleToString(PositionGetDouble(POSITION_PRICE_OPEN),digits),
                  DoubleToString(sl,digits),
                  DoubleToString(tp,digits),
                  magic);
      //--- if the symbol matches
      if(symbol==position_symbol)
        {
         for(int j=0; j<i; j++)
           {
            string symbol=PositionGetSymbol(j); // symbol of the opposite position
            //--- if the symbols of the opposite and initial positions match
            if(symbol==position_symbol && PositionGetInteger(POSITION_MAGIC)==777)
              {
               //--- set the type of the opposite position
               ENUM_POSITION_TYPE type_by=(ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
               //--- leave, if the types of the initial and opposite positions match
               if(type==type_by)
                  continue;
               //--- zeroing the request and result values
               ZeroMemory(request2);
               ZeroMemory(result2);
               //--- setting the operation parameters
               request2.action=TRADE_ACTION_CLOSE_BY;                         // type of trade operation
               request2.position=position_ticket;                             // ticket of the position
               request2.position_by=PositionGetInteger(POSITION_TICKET);      // ticket of the opposite position
               //request.symbol     =position_symbol;
               request2.magic=777;                                   // MagicNumber of the position
               //--- output information about the closure by opposite position
               PrintFormat("Close #%I64d %s %s by #%I64d",position_ticket,position_symbol,EnumToString(type),request2.position_by);
               //--- send the request
               success = OrderSend(request2,result2);
               if(!success)PrintFormat("OrderSend error %d",GetLastError()); // if unable to send the request, output the error code
 
               //--- information about the operation   
               PrintFormat("retcode=%u  deal=%I64u  order=%I64u",result2.retcode,result2.deal,result2.order);
              }
           }
        }
     }
   return success;
  }


Thank you so much already for taking the time to read this.

I'm ready to read up on whatever you can throw at me!

 

Is there an easy way to close a single position in hedge mode? If so, could you please point me in the right direction?

Yes, you need to add the ticket to close in your request.

Forum on trading, automated trading systems and testing trading strategies

Closing a position

Alain Verleyen, 2016.04.15 08:07

When modifying or closing a position in the hedging system, make sure to specify its ticket (MqlTradeRequest::ticket). You can specify a ticket in the netting system as well, however positions are identified by a symbol name.
bool CloseLong(string symbol,ulong ticket)
  {
   MqlTick last_tick;
   SymbolInfoTick(symbol,last_tick);               // What if false ?
   MqlTradeResult result;
   MqlTradeRequest request;
   ZeroMemory(result);
   ZeroMemory(request);
   
   PositionSelect(symbol);                         // What if false ?

   request.symbol=symbol;
   request.magic=777;
   request.deviation=Slip;
   request.action=TRADE_ACTION_DEAL;
   request.type_filling=ORDER_FILLING_FOK;
   request.volume=Vol;
   request.sl=last_tick.ask+Stop*Point();
   request.tp=last_tick.bid-Tp*Point();;
   request.price=last_tick.bid;
   request.position=ticket;
   request.type=ORDER_TYPE_SELL;
   ResetLastError();  //Useless
   bool success = OrderSend(request,result);
   if(!success){FailPrint(request,result);}        // even if success, doesn't mean the position is closed
   return success;
  }

 
Alain Verleyen:

Yes, you need to add the ticket to close in your request.

Wow, I really got dragged into this whole "close by" for the hedging mode... I feel so silly now...

I've used your simple and effective recommendation and it's working like a charm. Thank you so much!!! 


Thanks a lot also for sharing your concerns regarding the rest of the code.

  • My Open and Close functions are all called from within the OnTick event so SymbolInfoTick is always true in this EA (isn't it?). Because of this I'd never really thought about the whole "what if false" aspect of calling this function but I realize I should consider this eventuality it if I want to be able to call these from any event. Thanks!
  • PositionSelect(symbol) will also always be true because a CloseLong/CloseShort is only called after all the checks are made in terms of current positions. I doubt I would ever use these functions in an EA in which I don't check my status before calling a Close or an Open but it wouldn't hurt to be absolutely certain in the function itself. I'll add this to my todo list as well.
  • The "success" is more about being successful in sending the request; The EA keeps track of the positions it opens and closes and has a systematic inconsistency check allowing for it to retry failed orders through it's normal behavior.

I've been looking into putting in place a full and thorough system to track each step of each transaction within the "OnTrade" event to know exactly what is happening and to be able to take appropriate actions immediately whenever something is not right (instead of doing this in the OnTick event). Unfortunately, I have failed to find a comprehensive explanation of what is actually happening at each step of a transaction and where to grab the relevant info regarding each step.

I'm not sure what could go wrong by having the EA just compare what its expecting with the actual result as opposed to precisely tracking every step of every transaction. I've read a lot about all of this and most people seem to recommend (or share) the most basic of position status checking functions/code. If you have any recommended reads or any warnings, I'd be very grateful.

On another note, if anyone would like me to share the "position inconsistency" part of my code I'd be happy to share.

Thanks again!
 

Meyski:

...

  • PositionSelect(symbol) will also always be true because a CloseLong/CloseShort is only called after all the checks are made in terms of current positions. I doubt I would ever use these functions in an EA in which I don't check my status before calling a Close or an Open but it wouldn't hurt to be absolutely certain in the function itself. I'll add this to my todo list as well.

Why to call it at this stage at all ? Not needed actually.

  • The "success" is more about being successful in sending the request; The EA keeps track of the positions it opens and closes and has a systematic inconsistency check allowing for it to retry failed orders through it's normal behavior.

I've been looking into putting in place a full and thorough system to track each step of each transaction within the "OnTrade" event to know exactly what is happening and to be able to take appropriate actions immediately whenever something is not right (instead of doing this in the OnTick event). Unfortunately, I have failed to find a comprehensive explanation of what is actually happening at each step of a transaction and where to grab the relevant info regarding each step.

I'm not sure what could go wrong by having the EA just compare what its expecting with the actual result as opposed to precisely tracking every step of every transaction. I've read a lot about all of this and most people seem to recommend (or share) the most basic of position status checking functions/code. If you have any recommended reads or any warnings, I'd be very grateful.

On another note, if anyone would like me to share the "position inconsistency" part of my code I'd be happy to share.

Thanks again!

Use OnTradeTransaction() to keep track of what you need to know.

Reason: