FIFO close, processing error

 

Hi there community,

There's a problem on closing several positions from the pool by FIFO rule with this code.

It seems to be working ok on EAs through the strategy tester, even throwing better results than LIFO close, but for some reason it's not working fine on live trading.

Made the code as simple as possible, these are the lines:

   for(int i=0;i<PositionsTotal();i++){
      ulong Ticket=PositionGetTicket(i);
      if(!trade.PositionClose(Ticket,ULONG_MAX)){
         Print("PositionClose error ",trade.ResultRetcode());
         return;
         }
      else{i--;}
      }

What it does

- Loop forward from the first position index.

- If done, count back again to the new first position index.

What's the flaw/problem: at some point the algorithm can't count back to the new first position index and it just stops leaving open positions once a target is reached.

----

Would be glad if someone can shred some light on this matter.

 

The correct direction of bypassing positions is necessary:

  for(int i=PositionsTotal()-1; i>=0; i--) // returns the number of current positions

after that, create a list that will be sorted by time and then close positions by ticket (you will take the ticket from your sorted list)

 
Vladimir Karputov #:

The correct direction of bypassing positions is necessary:

after that, create a list that will be sorted by time and then close positions by ticket (you will take the ticket from your sorted list)

Thank for your reply.

 

Tested this method into one advisor and compared with LIFO close, these are the results:

- FIFO: profit 71,12%, drawdown 8,65%, PF 2,94, RF 7,38, SR 18,66, trades 141.

- LIFO: profit 48,34%, drawdown 13,23%, PF 2,13, RF 3,28, SR 14,89, trades 131.

Quite strange, mostly about drawdown if there was a mistake on risk control.

 
David Diez #:

Tested this method into one advisor and compared with LIFO close, these are the results:

- FIFO: profit 71,12%, drawdown 8,65%, PF 2,94, RF 7,38, SR 18,66, trades 141.

- LIFO: profit 48,34%, drawdown 13,23%, PF 2,13, RF 3,28, SR 14,89, trades 131.

Quite strange, mostly about drawdown if there was a mistake on risk control.

It depends on the strategy. Some strategies are not affected at all whether it is FIFO, LIFO or anything else. But other strategies can be heavily affected and some cannot work at all with FIFO.

That is why it is best to redesign a strategy to carry out trades in a mathematically equivalent "netting" method.

Strategies like Grids, same symbol Hedging, Stacking, Scaling-in, Scaling-out, should all be studied mathematically to create a "netting" equivalent which will be compatible to FIFO.

Obviously when you reduce Grids and same symbol Hedging to a "netting" equivalent, one discovers that it is the same as not trading at all except for the trade costs, but zero profit.

 
Fernando Carreiro #:

It depends on the strategy. Some strategies are not affected at all whether it is FIFO, LIFO or anything else. But other strategies can be heavily affected and some cannot work at all with FIFO.

That is why it is best to redesign a strategy to carry out trades in a mathematically equivalent "netting" method.

Strategies like Grids, same symbol Hedging, Stacking, Scaling-in, Scaling-out, should all be studied mathematically to create a "netting" equivalent which will be compatible to FIFO.

Obviously when you reduce Grids and same symbol Hedging to a "netting" equivalent, one discovers that it is the same as not trading at all except for the trade costs, but zero profit.

Thank you for your reply, the advisor works only one trade per pair.

Now trying to apply a new way to set global risk by PositionsTotal and compare results back again but I got stucked, will post new results further.

 

This is my code to close all positions (FIFO-compliant)

#include <Arrays\ArrayLong.mqh>
#include <Trade\PositionInfo.mqh>
#include <Trade\Trade.mqh>
//---
CArrayLong     arr_tickets; // array tickets
CPositionInfo  position;    // position info object
CTrade         trade;       // trading object
//+------------------------------------------------------------------+
//| Close market positions                                           |
//+------------------------------------------------------------------+
void ClosePositions()
  {
//--- initialize common information
   trade.SetDeviationInPoints(INT_MAX);
   trade.SetAsyncMode(true);
   trade.SetMarginMode();
   trade.LogLevel(LOG_LEVEL_ERRORS);
//---
   for(uint retry=0; retry<5 && !IsStopped(); retry++)
     {
      bool result = true;
      //--- Collect and Close Method (FIFO-Compliant, for US brokers)
      //--- Tickets are processed starting with the oldest one.
      arr_tickets.Shutdown();
      for(int i=0; i<PositionsTotal() && !IsStopped(); i++)
        {
         ResetLastError();
         if(!position.SelectByIndex(i))
           {
            PrintFormat("> Error: selecting position with index #%d failed. Error Code: %d",i,GetLastError());
            result = false;
            continue;
           }
         //--- build array of position tickets to be processed
         if(!arr_tickets.Add(position.Ticket()))
           {
            PrintFormat("> Error: adding position ticket #%I64u failed.",position.Ticket());
            result = false;
           }
        }

      //--- now process the list of tickets stored in the array
      for(int i=0; i<arr_tickets.Total() && !IsStopped(); i++)
        {
         ResetLastError();
         ulong m_curr_ticket = arr_tickets.At(i);
         if(!position.SelectByTicket(m_curr_ticket))
           {
            PrintFormat("> Error: selecting position ticket #%I64u failed. Error Code: %d",m_curr_ticket,GetLastError());
            result = false;
            continue;
           }
         //--- check freeze level
         int freeze_level = (int)SymbolInfoInteger(position.Symbol(),SYMBOL_TRADE_FREEZE_LEVEL);
         double point = SymbolInfoDouble(position.Symbol(),SYMBOL_POINT);
         bool TP_check = (MathAbs(position.PriceCurrent() - position.TakeProfit()) > freeze_level * point);
         bool SL_check = (MathAbs(position.PriceCurrent() - position.StopLoss()) > freeze_level * point);
         if(!TP_check || !SL_check)
           {
            PrintFormat("> Error: closing position ticket #%I64u on %s is prohibited. Position TP or SL is too close to activation price.",position.Ticket(),position.Symbol());
            result = false;
            continue;
           }
         //--- trading object
         trade.SetExpertMagicNumber(position.Magic());
         trade.SetTypeFillingBySymbol(position.Symbol());
         //--- close positions
         if(trade.PositionClose(position.Ticket()) && (trade.ResultRetcode()==TRADE_RETCODE_DONE || trade.ResultRetcode()==TRADE_RETCODE_PLACED))
           {
            PrintFormat("Position ticket #%I64u on %s to be closed.",position.Ticket(),position.Symbol());
            PlaySound("expert.wav");
           }
         else
           {
            PrintFormat("> Error: closing position ticket #%I64u on %s failed. Retcode=%u (%s)",position.Ticket(),position.Symbol(),trade.ResultRetcode(),trade.ResultComment());
            result = false;
           }
        }

      if(result)
         break;
      Sleep(1000);
      PlaySound("timeout.wav");
     }
  }
//+------------------------------------------------------------------+

You might take a look at the full implementation of my 'close_all' script on codebase.

https://www.mql5.com/en/code/25650

Close-All
Close-All
  • www.mql5.com
A script to close all market positions and/or pending orders.
 
amrali #:

This is my code to close all positions (FIFO-compliant)

You might take a look at the full implementation of my 'close_all' script on codebase.

https://www.mql5.com/en/code/25650

Thanks, I will take a look in detail.

Reason: