How can I know if a stoploss has been moved?

 

Hi all!

I'm trying to do an EA that can recalculate target values when its re-initialized when the VPS restarts or when I reload the EA for any reason.

The thing is that I am setting my stoploss at 1.5 * ATR value and want to take half of the profit at 1*ATR and also start trailing from this point, but when the EA reinitializes, the takeProfit target level is lost and I it needs to be recalculated.

If anyone of you have an idea that can "store" in a less painful way this value, would be greatly appreciated.

So far, this is how I'm doing it: If there is a position open, I look back how many candles it is and get the ATR value of the moment the trade took place. Then I set the value of takeProfit to that the open price +(-) 1*ATR. The thing is that the value that it gives me back

is different from the original value. Also, I need to tell if the stoploss have been moved from the original position, because if it is the case it means that half of the trade has been cashed out and the "firstCall" value should be set to false.

I'm posting the code of how I'm doing this!


This part is what recalculates the target value:

bool firstCall=true;
double takeProfit;

int OnInit()
  {
//---
   


   atrMain=iATR(NULL,timeFrame,14);


   
   ArraySetAsSeries(atrTrades,true);
   
   if(PositionSelect(Symbol()))
     {
      datetime openTime,totalTime;
      int barsBack=0,type;
      double priceOpen=0.0,iniStopLoss,posStopLoss;

      for(int i=PositionsTotal()-1;i>=0;i--)
        {
         if(mposition.SelectByIndex(i))
           {
            if(mposition.Symbol()==Symbol() && mposition.Magic()==123456)
              {
               openTime=mposition.Time();
               priceOpen=mposition.PriceOpen();
               totalTime= openTime-86400;
               type=(mposition.PositionType()==POSITION_TYPE_BUY)?1:0;
               posStopLoss=mposition.StopLoss();
               barsBack=Bars(NULL,timeFrame,iTime(NULL,timeFrame,0),openTime);
              }
           }
        }

      CopyBuffer(atrMain,0,0,barsBack+1,atrTrades);

      iniStopLoss=(type==1)?priceOpen-atrStopLoss*atrTrades[barsBack]:priceOpen+atrStopLoss*atrTrades[barsBack];
      
      if(type==1)
        {
         if(iniStopLoss<posStopLoss)
           {
            firstCall=false;
           }
         else
           {
            firstCall=true;
           }

         takeProfit=NormalizeDouble(priceOpen+atrProfit*atrTrades[barsBack],Digits());
        }

      if(type==0)
        {
         if(iniStopLoss>posStopLoss)
           {
            firstCall=false;
           }
         else
           {
            firstCall=true;
           }
         takeProfit=NormalizeDouble(priceOpen-atrProfit*atrTrades[barsBack],Digits());
        }
      Print("Previous order opened detected on ",Symbol(),". Takeprofit level adjusted at: ",DoubleToString(takeProfit,Digits()),". Using ",atrTrail," ATR value to trail.");
     }


//---
   return(INIT_SUCCEEDED);
  }

And this part is what place the trades and calculates the initial target level:

void openTrade(int typeOfTrade)
  {
   ZeroMemory(lastTick);
   ZeroMemory(mrequest);
   ZeroMemory(mresult);
   ZeroMemory(mcheck);
   SymbolInfoTick(Symbol(),lastTick);


   CopyBuffer(atrMain,0,0,1,atrTrades);

   double PipValue=(((SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_VALUE))*Point())/(SymbolInfoDouble(Symbol(),SYMBOL_TRADE_TICK_SIZE)));
   double stopLossPips=(atrStopLoss*atrTrades[0])/Point();
   double totalLots=risk*AccountInfoDouble(ACCOUNT_EQUITY)/(PipValue*stopLossPips);
   totalLots=floor(totalLots*100)/100;

   mrequest.volume=NormalizeDouble(totalLots,_Digits);
   mrequest.sl=(typeOfTrade==1)? NormalizeDouble(lastTick.ask-stopLossPips*Point(),_Digits):NormalizeDouble(lastTick.bid+stopLossPips*Point(),_Digits);
   mrequest.magic=Magic;
   mrequest.deviation=Slippage;
   mrequest.action=TRADE_ACTION_DEAL;
   mrequest.price=(typeOfTrade==1)?NormalizeDouble(lastTick.ask,_Digits):NormalizeDouble(lastTick.bid,_Digits);
   mrequest.symbol=Symbol();
   mrequest.type=(typeOfTrade==1)?ORDER_TYPE_BUY:ORDER_TYPE_SELL;
   mrequest.type_filling=ORDER_FILLING_FOK;


   if(OrderSend(mrequest,mresult))
     {
      takeProfit=(typeOfTrade==1)? NormalizeDouble(lastTick.bid+atrProfit*atrTrades[0],_Digits):NormalizeDouble(lastTick.ask-atrProfit*atrTrades[0],_Digits);
      Print("New trade on ",Symbol()," placed correctly. Target profit level is: ",DoubleToString(takeProfit,Digits()));
     }

  }


Thank you in advance,

PS

 

Pedro Severin:

The thing is that I am setting my stoploss at 1.5 * ATR value and want to take half of the profit at 1*ATR and also start trailing from this point, but when the EA reinitializes, the takeProfit target level is lost and I it needs to be recalculated.

If anyone of you have an idea that can "store" in a less painful way this value, would be greatly appreciated.

Check if the SL is above break even. If not, and market is at 1 ATR, move the SL to BE and do a partial close. If is, just trail. No need to remember the original.

 
William Roeder:

Check if the SL is above break even. If not, and market is at 1 ATR, move the SL to BE and do a partial close. If is, just trail. No need to remember the original.

Hi William!

Thank you for your reply. Should I always go to BE? I am in doubt with that. I mean, isn't better give the market the room and space it needs?

And how can I know if the market is at 1 ATR if I restart the EA? Lets say that it has been like a 5 days trend, then the actual ATR value would be different with the ATR value when the trade was placed.

I think that I'm not recovering the original ATR value when the trade took place.

Or I'm getting something wrong?

 

Pedro Severin: Thank you for your reply. Should I always go to BE?

If anyone of you have an idea that can "store" in a less painful way this value, would be greatly appreciated.

  1. You can't just use OrderLots()/2 because that is not a multiple of LotStep, and you can't close or have remaining less than MinLot. See my code
  2. You also must check if you have already done it, to avoid repeated closing. Alternatives:
    • Move SL to Break Even+1 before the partial close. That way you know that you already did it.
    • Set a flag in persistent storage (files, global variables w/flush) that you already did it.
    • Remember the original SL and see if you already did it.
    • Open two orders initially, and close one (manually or by TP.) No need to do it.
Choose a method.
 
William Roeder:
  1. You can't just use OrderLots()/2 because that is not a multiple of LotStep, and you can't close or have remaining less than MinLot. See my code
  2. You also must check if you have already done it, to avoid repeated closing. Alternatives:
    • Move SL to Break Even+1 before the partial close. That way you know that you already did it.
    • Set a flag in persistent storage (files, global variables w/flush) that you already did it.
    • Remember the original SL and see if you already did it.
    • Open two orders initially, and close one (manually or by TP.) No need to do it.
Choose a method.

Hi William,

1. I guess that applies for MQL5 too. This code is ment to MT5 and, as far as I know, there is no OrderLots() in MQL5.

2. Those global variables looks really nice, will look at them. Correct me if I'm wrong, but that method works only while the PC/terminal is open, right? If for some reason, the PC restarts the variable are lost? Open two orders is also a nice way to do it, but I would like to learn "the coded" way :) .


I will take a look at those methods and see which one is my best approach! Thank you! :D

Reason: