Too many positions

 

Hi everyone,

i have a problem on my EA, which works with a grid system.

The system should open a new buy position when bid price is 180 points lower than last opened position price. This level is called "nexyBuy".

The problem occurs only on certain moments, for example backtesting with usdcad on 10 August 2020, it opens many many positions also if price is higher than the " nexyBuy" target price of the grid system:


#include <trade/Trade.mqh>
#include <Trade\SymbolInfo.mqh>   

input group "=== General Settings ==="
   input double Lot=0.01;
   input double multiplierLot =1.27;
   input ENUM_TIMEFRAMES RsiTimeframe = PERIOD_H1;
   input ENUM_TIMEFRAMES Timeframe = PERIOD_CURRENT;   
   input int RsiPeriods = 14;
   input ENUM_APPLIED_PRICE RsiAppPrice = PRICE_CLOSE;
   
   input double RsiSellTrigger = 70;
   input double RsiBuyTrigger = 30;
   input int InpMagic = 454545;                     //EA identification no
   input int InpMagicB = 111111;                     //EA identification no
   input int InpMagicS = 222222;                     //EA identification no
   input int TpPoints=220;    
   input int SLinProfit=40;    
   input int ProfitforSl=111;           
            
input group "=== Grid Settings ==="

   input int MaxOrders=10;
   input int MinDistance=180;  
   



int buyN=0;int sellN=0;int pointsB =0;int pointsS =0;double LotsB=Lot;double LotsS=Lot;
double sellVol=0;double buyVol=0;double nextBuy;double nextSell;

int handleRsi;
double rsi[2];

CTrade trade;
CPositionInfo pos;
COrderInfo ord;
CSymbolInfo symb;

int OnInit(){   
   trade.SetExpertMagicNumber(InpMagic);
   ChartSetInteger(0,CHART_SHOW_GRID,false);
   handleRsi= iRSI(_Symbol,RsiTimeframe,RsiPeriods,RsiAppPrice);
   return(INIT_SUCCEEDED);
}

void OnDeinit(const int reason){
}

void OnTick(){
   double sl=0; double tp=0; buyN=0; sellN=0; double volPBuy=0; double volPSell=0; int points=0;
   pointsB=0; pointsS=0; buyVol=0; sellVol=0; nextBuy=999999999; nextSell=0;
   for(int i = 0;i<=PositionsTotal()-1;i++){
      ulong ticket =PositionGetTicket(i);
      ulong magic =PositionGetInteger(POSITION_MAGIC);
      if(PositionSelectByTicket(ticket) && (magic==InpMagic || magic==InpMagicB || magic==InpMagicS) && PositionGetString(POSITION_SYMBOL)==_Symbol){
         ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         if(posType==POSITION_TYPE_BUY){
            buyN+=1;
            pointsB += (int)((pos.PriceCurrent()-pos.PriceOpen())/symb.Point()*pos.Volume()/Lot);
            volPBuy+= pos.PriceOpen()*pos.Volume();
            buyVol+=pos.Volume();
         }else if(posType==POSITION_TYPE_SELL) {
            sellN+=1;
            pointsS += (int)((pos.PriceOpen()-pos.PriceCurrent())/symb.Point()*pos.Volume()/Lot);
            volPSell+= pos.PriceOpen()*pos.Volume();
            sellVol+=pos.Volume();
         }
      }
   }
   for(int i = 0;i<=PositionsTotal()-1;i++){
      ulong ticket =PositionGetTicket(i);
      ulong magic =PositionGetInteger(POSITION_MAGIC);
      if(PositionSelectByTicket(ticket) && (magic==InpMagic || magic==InpMagicB || magic==InpMagicS) && PositionGetString(POSITION_SYMBOL)==_Symbol){
         ENUM_POSITION_TYPE posType = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
         double posSl = PositionGetDouble(POSITION_SL);
         double posTp = PositionGetDouble(POSITION_TP);
         if(posType==POSITION_TYPE_BUY){
            points = (int)((pos.PriceCurrent() - pos.PriceOpen())/symb.Point());
            sl = NormalizeDouble(pos.PriceOpen()+SLinProfit*symb.Point(),symb.Digits());
            tp = NormalizeDouble(TpPoints*symb.Point()+volPBuy/buyVol,symb.Digits());
            nextBuy= NormalizeDouble(pos.PriceOpen()-MinDistance*symb.Point(),symb.Digits());
            if(posTp!=tp){
               trade.PositionModify(ticket,posSl,tp);
            }
            if(points>=ProfitforSl && posSl!=sl){
               trade.PositionModify(ticket,sl,posTp);
            }
         }else if(posType==POSITION_TYPE_SELL) {
            points = (int)((pos.PriceOpen() - pos.PriceCurrent()) / symb.Point());
            sl =  NormalizeDouble(pos.PriceOpen()-SLinProfit*symb.Point(),symb.Digits());
            tp = NormalizeDouble(-TpPoints*symb.Point()+volPSell/sellVol,symb.Digits());
            nextSell= NormalizeDouble(pos.PriceOpen() + MinDistance* symb.Point(),symb.Digits());
            if(posTp!=tp){
               trade.PositionModify(ticket,posSl,tp);
            }
            if(points>=ProfitforSl && posSl!=sl){
               trade.PositionModify(ticket,sl,posTp);
            }
         }
      }
   }
    double bid = SymbolInfoDouble(_Symbol,SYMBOL_BID);
    double ask = SymbolInfoDouble(_Symbol,SYMBOL_ASK);
      CopyBuffer(handleRsi,MAIN_LINE,1,2,rsi);  
      if(sellN==0 && buyN<MaxOrders && bid<=nextBuy ){//&& rsi[1]<RsiBuyTrigger && rsi[0]>RsiBuyTrigger
            //buy signal
         trade.SetExpertMagicNumber(InpMagicB);
         LotsB=Lot*(int)MathPow(multiplierLot,buyN);
           trade.Buy(LotsB);

      }
}
 
Your topic has been moved to the section: Expert Advisors and Automated Trading
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 
Framode:

Hi everyone,

i have a problem on my EA, which works with a grid system.

The system should open a new buy position when bid price is 180 points lower than last opened position price. This level is called "nexyBuy".

The problem occurs only on certain moments, for example backtesting with usdcad on 10 August 2020, it opens many many positions also if price is higher than the " nexyBuy" target price of the grid system:


All I see is that there are a lot of variables that are simultaneously declared and defined on the local scope. As a matter of best practice, I declare as many variables as possible up top on the global scope, define them in OnInit(), and then update their values in OnTick() or in custom functions. I would try rearranging those variables and then re-Debugging.

 

i solved the problem putting orders with BuyLimit and SellLimit. So the EA puts just one order at time, and not many orders simultaneously. 

if(buyCount>=1 && buyCount<MaxOrders && count_buy_limits==0){
      //buy signal
      LotsB=Lot*(int)MathPow(MultiplierLot,buyCount);
      if(ask>nextBuy){
         m_trade.BuyLimit(LotsB,nextBuy);
      }else if(ask<=nextBuy){
         m_trade.BuyLimit(LotsB,ask);
      }
   }else if(sellCount>=1 && sellCount<MaxOrders && count_sell_stops==0){
      //sell signal
      LotsS=Lot*(int)MathPow(MultiplierLot,sellCount);
      if(bid<nextSell){
         m_trade.SellLimit(LotsS,nextSell);
      }else if(bid>=nextSell){
         m_trade.SellLimit(LotsS,bid);
      }
   }


But if i declare  variables  in Oninit section many errors occurs: "undeclared identifier", so i have to declare them before, just after input section.

All works now but i didn't understand what was the problem putting orders just with trade. command

 
Framode #:

... so i have to declare them before, just after input section.

That is what is called the "global scope" or "global environment" -- the section that ryan advised you of.

 
Michael Charles Schefe #:

That is what is called the "global scope" or "global environment" -- the section that ryan advised you of.

I found before that using global variables to track the number of opened buy positions or sell positions (or orders) doesn't work efficiently. It's better to reset those variables to 0 on every new tick and then loop through open buy and sell positions to count how many are now open. It will update accurately that way.

 
Conor Mcnamara #:
I found before that using global variables to track the number of opened buy positions or sell positions (or orders) doesn't work efficiently. It's better to reset those variables to 0 on every new tick...

To be clear, variables declared on the global scope can be defined or redefined anywhere and at any time in the program--hence the name of their scope, "global." Declaring, or redeclaring, variables throughout OnTick() is not programmatically more efficient.

 
Ryan L Johnson #:

To be clear, variables declared on the global scope can be defined or redefined anywhere and at any time in the program--hence the name of their scope, "global." Declaring, or redeclaring, variables throughout OnTick() is not programmatically more efficient.

For me, I only declare variables in the global scope for holding persistent data. If I need variables to constantly update, I like to reset the definition of the variable along with the value locally, because memory may sometimes not be free'd properly especially as MQL5 is c++ based architecture.  Local variables get allocated and deallocated with each new tick, avoiding memory leaks.

 
Conor Mcnamara #:

For me, I only declare variables in the global scope for holding persistent data. If I need variables to constantly update, I like to reset the definition of the variable along with the value locally, because memory may sometimes not be free'd properly especially as MQL5 is c++ based architecture.  Local variables get allocated and deallocated with each new tick, avoiding memory leaks.

Thanks for that. If I ever decide to embark on high frequency trading, I'll keep that in mind.

 
Conor Mcnamara #:

I found before that using global variables to track the number of opened buy positions or sell positions (or orders) doesn't work efficiently. It's better to reset those variables to 0 on every new tick and then loop through open buy and sell positions to count how many are now open. It will update accurately that way.

agreed. however that means that you need to send instruction to broker on every tick.

suggestion for a more efficient method to save buy and sell counts, is via a fixed or dynamic array. It is just as efficient when used either globally or local.

 
Michael Charles Schefe #:

agreed. however that means that you need to send instruction to broker on every tick.

suggestion for a more efficient method to save buy and sell counts, is via a fixed or dynamic array. It is just as efficient when used either globally or local.

Thanks.

I use a global int with somewhat convoluted global ENUM's but it's fast enough for swing trading:

void GetPositions()
  {
   if(PositionsTotal() >= 1)
    {
     for(int i = PositionsTotal() - 1; i >= 0; i--) // count all currency pair positions
      {
       // get the ticket number
       PositionTicket = PositionGetTicket(i);
       ENUM_POSITION_TYPE positiontype = (ENUM_POSITION_TYPE)PositionGetInteger(POSITION_TYPE);
       openprice = (ENUM_POSITION_PROPERTY_DOUBLE)PositionGetDouble(POSITION_PRICE_OPEN);
       opentime = (ENUM_POSITION_PROPERTY_INTEGER)PositionGetInteger(POSITION_TIME);
     
       if(positiontype == POSITION_TYPE_BUY)
                  {
         positionType = 1; // buy position
         positionTime = POSITION_TIME;
        }
     
       if(positiontype == POSITION_TYPE_SELL)
        {
         positionType = 2; // sell position
         positionTime = POSITION_TIME;
        }
       
       if(PositionsTotal() == 0)
        {
         positionType = 0; // flat
        } 
      }     
    }  
  }