Loop for predefined #of Limit Orders, each with more volume and higher prices

 

Hi, I am struggling with one loop. I hope you can help me.

The EA has a defined market entry. Once the market entry occurred, I want to have predefined #of Limit Orders cascading based on multiples defined.


// Initialisation

ulong LimitOrders(int type)

        {

          static double NextPrice;

          static double NextVolume;


//Select the sell-position Price and Volume                    

          PositionSelectByTicket(PositionGetTicket(PositionsTotal()-1));

          double positionOpenPrice=PositionGetDouble(POSITION_PRICE_OPEN);

          double positionVolume=PositionGetDouble(POSITION_VOLUME);

          ulong ticket=-1;

          

//define the new price and volume          

          NextPrice=(positionOpenPrice*PriceDev*StepScale);

          NextVolume=(positionVolume*VolumeScale);


//start the Limit Orders Loop          

          int i=OrdersTotal();

          do

          {

          bool result=trades.SellLimit(NextVolume,NextPrice,_Symbol,0,0,ORDER_TIME_GTC,0,"SO"+(i+1));         

//define the new price and volume for the next limit order 

          NextPrice=(positionOpenPrice*PriceDev*PriceDev*StepScale*StepScale);

          NextVolume=(positionVolume*VolumeScale*VolumeScale);

          i++;

          }

//Do the loop until the maximum amount of orders that are allowed are reached

          while(OrdersTotal() <= SOcount);

          

          ticket=trades.ResultOrder();

          return ticket;

         }

 

I don't understand your problem, maybe its easier for you to ask your question in the German forum: https://www.mql5.com/de/forum/general

Anyway you should use the (Extras=>) styler in the editor (Ctrl+,) and the code button for code (Alt+s or click on </>) and have to know this for pending orders:


Forum für Händler - MQL5 community: Allgemeine Diskussion
Forum für Händler - MQL5 community: Allgemeine Diskussion
  • www.mql5.com
Ankündigungen, Neuigkeiten und allgemeine Fragen, die zu keiner anderen Kategorie gehören
 
Johannes Vogel:

Hi, I am struggling with one loop. I hope you can help me.

The EA has a defined market entry. Once the market entry occurred, I want to have predefined #of Limit Orders cascading based on multiples defined.


// Initialisation

ulong LimitOrders(int type)

        {

          static double NextPrice;

          static double NextVolume;


//Select the sell-position Price and Volume                    

          PositionSelectByTicket(PositionGetTicket(PositionsTotal()-1));

          double positionOpenPrice=PositionGetDouble(POSITION_PRICE_OPEN);

          double positionVolume=PositionGetDouble(POSITION_VOLUME);

          ulong ticket=-1;

          

//define the new price and volume          

          NextPrice=(positionOpenPrice*PriceDev*StepScale);

          NextVolume=(positionVolume*VolumeScale);


//start the Limit Orders Loop          

          int i=OrdersTotal();

          do

          {

          bool result=trades.SellLimit(NextVolume,NextPrice,_Symbol,0,0,ORDER_TIME_GTC,0,"SO"+(i+1));         

//define the new price and volume for the next limit order 

          NextPrice=(positionOpenPrice*PriceDev*PriceDev*StepScale*StepScale);

          NextVolume=(positionVolume*VolumeScale*VolumeScale);

          i++;

          }

//Do the loop until the maximum amount of orders that are allowed are reached

          while(OrdersTotal() <= SOcount);

          

          ticket=trades.ResultOrder();

          return ticket;

         }

Hi ,You want to deploy limit orders around an existing open order ? am i understanding this right ? 

 
Carl Schreiber #:

I don't understand your problem, maybe its easier for you to ask your question in the German forum: https://www.mql5.com/de/forum/general

Anyway you should use the (Extras=>) styler in the editor (Ctrl+,) and the code button for code (Alt+s or click on </>) and have to know this for pending orders:


Why would it be easier to ask in the German forum ? im curious .

 
Lorentzos Roussos #: Why would it be easier to ask in the German forum ? im curious .
Because the OP is from Germany according to the profile, and may be easier for them to discuss the issue in their native language.
 
Fernando Carreiro #:
Because the OP is from Germany according to the profile, and may be easier for them to discuss the issue in their native language.

ow i see .

The latest post in the general section there is 2 days ago , so the one helping would probably be Carl ,who did not understand the question like us.

The OP seems to speak good english , Carl too , why narrow down his chances like this ?

 
Lorentzos Roussos #: ow i see . The latest post in the general section there is 2 days ago , so the one helping would probably be Carl ,who did not understand the question like us. The OP seems to speak good english , Carl too , why narrow down his chances like this ?
It did not narrow anything. He only made a suggestion and gave one more option.
 

Here you go , this is an example . 

I hope it helps 

(your issue may have been the stop level of the broker)

Cheers , happy holidays , schöne ferien :)

//+------------------------------------------------------------------+
//|                                         parachute_after_open.mq5 |
//|                                  Copyright 2022, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2022, MetaQuotes Ltd."
#property link      "https://www.mql5.com"
#property version   "1.00"
#include <Trade\Trade.mqh>
CTrade order;

int OnInit()
  {
//--- create timer
  // EventSetTimer(60);
  //test open a buy 
    
    bool testorder=order.Buy(0.01,_Symbol,(double)SymbolInfoDouble(_Symbol,SYMBOL_ASK),0.0,0.0,"ThisParachuteIsANapsack");
    if(testorder){
    if(PositionSelect(_Symbol)){
    ulong ticket=PositionGetTicket(0);
    parachute(ticket,0.01,false,300,5,parachute_below_opposite);
    }
    }else{
    Print("Cannot open test order");
    }
//---
   return(INIT_SUCCEEDED);
  }

void OnTick(){}
/*
parachute function
send a ticket 
send a volume step
send a price  step 
and it will deploy the pending orders
*/
/*
lets construct a quick enumeration for where and what type of orders you may deploy . 
So while a parachute is usually deployed above the skydiver in this case it may deploy 
above or below and be of any type so the enumeration will help guide the function on 
what to open .
*/
#define ENFORCE_LIMIT_MULTIPLE 1.5
enum parachute_method{
parachute_void=0,//nothing
parachute_above_same=1,//above the order and same direction
parachute_below_same=2,//below the order and same direction 
parachute_above_opposite=3,//above the order and opposite direction
parachute_below_opposite=4//below the order and opposite direction
};//self descriptive , moving on
bool parachute(ulong for_ticket,//the ticket of the position to deploy for
              double volume_step,//the step of the volume 
              bool volume_is_stacked,//if true the volume will begin from the positions volume
              double price_step_in_points,//the step of the price , absolute value will be used
              int amount,//how many to deploy
              parachute_method method){//and one of the methods above
//first we need to do a little preparation 
  int errors=0;//our error collector 
  ResetLastError();//reset the error container
  //now we need the lot limits (volume)
  double vol_max=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MAX);errors+=GetLastError();ResetLastError();
  double vol_min=(double)SymbolInfoDouble(_Symbol,SYMBOL_VOLUME_MIN);errors+=GetLastError();ResetLastError();
  //and we also need the stop level which is -as far as i know- the closer you can get to the market price 
  double stop_level=(double)SymbolInfoInteger(_Symbol,SYMBOL_TRADE_STOPS_LEVEL);errors+=GetLastError();ResetLastError();
  //turn the stop level to points 
    stop_level*=_Point;
  //and if we got no errors move on
  if(errors==0)
  {
  double price_step=MathAbs(price_step_in_points)*_Point;
  //now select the position 
    if(PositionSelectByTicket(for_ticket)){
    //we now have access to open price and direction and volume
      double open_price=PositionGetDouble(POSITION_PRICE_OPEN);
      double volume=PositionGetDouble(POSITION_VOLUME);
      ENUM_ORDER_TYPE type=(ENUM_ORDER_TYPE)PositionGetInteger(POSITION_TYPE);
      //and we can decide what types of pending orders we need based on the 
      //method the user (we) have chosen so : 
        //we will place our decision in these following variables 
          double starting_volume=volume_step;
          //if the directive is to stack the volume on top of the original order
          if(volume_is_stacked){starting_volume=volume+volume_step;}
          if(starting_volume<vol_min){starting_volume=vol_min;}
          else if(starting_volume>vol_max){starting_volume=vol_max;}
          ENUM_ORDER_TYPE pending_type=ORDER_TYPE_BUY_LIMIT;
          //so if the method is above + same direction
            if(method==parachute_above_same){
            //and the initial order is a buy 
              if(type==ORDER_TYPE_BUY){
              //that means we need buy stops :) simple eh?
                pending_type=ORDER_TYPE_BUY_STOP;
              }
            //if the initial order is a sell 
              else if(type==ORDER_TYPE_SELL){
              //it means we need sell limits 
                pending_type=ORDER_TYPE_SELL_LIMIT;
              }
            }
          //if the method is below and same direction
            else if(method==parachute_below_same){
              if(type==ORDER_TYPE_BUY){
                pending_type=ORDER_TYPE_BUY_LIMIT;
              }
              else if(type==ORDER_TYPE_SELL){
                pending_type=ORDER_TYPE_SELL_STOP;
              }            
            }
          //if the method is above and opposite direction
            else if(method==parachute_above_opposite){
              if(type==ORDER_TYPE_BUY){
                pending_type=ORDER_TYPE_SELL_LIMIT;
              }
              else if(type==ORDER_TYPE_SELL){
                pending_type=ORDER_TYPE_BUY_STOP;
              }              
            }
          //if the method is below and opposite direction
            else if(method==parachute_below_opposite){
              if(type==ORDER_TYPE_BUY){
                pending_type=ORDER_TYPE_SELL_STOP;
              }
              else if(type==ORDER_TYPE_SELL){
                pending_type=ORDER_TYPE_BUY_LIMIT;
              }              
            }   
          //and finally we need to prepare the starting price 
            double start_price=open_price;
            //if we are playing above the order 
              if(method==parachute_above_opposite||method==parachute_above_same){
              start_price+=price_step;
              }         
            //but if we are playing below the order 
              else if(method==parachute_below_opposite||method==parachute_below_same){
              start_price-=price_step;
              price_step*=-1.0;
              }
          //and since this is supposed to happen after the open of a position the live price must be close 
          //so we can run a quick check if we are violating any stop level limits so , if we got the stop levels correctly 
            if(stop_level>0.0){
            //then pull the Ask and Bid prices 
              double ask=(double)SymbolInfoDouble(_Symbol,SYMBOL_ASK);
              double bid=(double)SymbolInfoDouble(_Symbol,SYMBOL_BID);
            //if we are opening buys we want to check distance off of the ask
              if(pending_type==ORDER_TYPE_BUY_STOP||pending_type==ORDER_TYPE_BUY_LIMIT){
              double distance=MathAbs(ask-start_price);
              //if that distance is less than the stop level allows 
                if(distance<=stop_level){
                //then we need a new distance for the first order 
                  //and here is what that enforce multiplier does 
                    distance=NormalizeDouble(stop_level*ENFORCE_LIMIT_MULTIPLE,_Digits);
                  //reapply it based on whether or not we are above or below 
                    if(method==parachute_above_opposite||method==parachute_above_same){
                    start_price=ask+distance;
                    }else{
                    start_price=ask-distance;
                    }
                }
              }
            //if we are opening sells we want ot check distance off of the bid 
              else if(pending_type==ORDER_TYPE_SELL_STOP||pending_type==ORDER_TYPE_SELL_LIMIT){
              double distance=MathAbs(bid-start_price);
              //if that distance is less than the stop level allows 
                if(distance<=stop_level){
                //then we need a new distance for the first order 
                    distance=NormalizeDouble(stop_level*ENFORCE_LIMIT_MULTIPLE,_Digits);
                  //reapply it based on whether or not we are above or below 
                    if(method==parachute_above_opposite||method==parachute_above_same){
                    start_price=bid+distance;
                    }else{
                    start_price=bid-distance;
                    }
                }
              }             
            }
          //it appears we can start deploying so lets loop into the amount of orders we need 
            for(int i=0;i<amount;i++)
            {
            bool sent=false;
            int attempts=0;
            //so try to open an order 
              while(!sent&&attempts<10){
              //a bit sloppy here , sorry
              attempts++;
              if(pending_type==ORDER_TYPE_BUY_STOP){
                sent=order.BuyStop(starting_volume,start_price,_Symbol,0.0,0.0,ORDER_TIME_GTC,0,"Parachute");
              }
              else if(pending_type==ORDER_TYPE_BUY_LIMIT){
                sent=order.BuyLimit(starting_volume,start_price,_Symbol,0.0,0.0,ORDER_TIME_GTC,0,"Parachute");
              }
              else if(pending_type==ORDER_TYPE_SELL_STOP){
                sent=order.SellStop(starting_volume,start_price,_Symbol,0.0,0.0,ORDER_TIME_GTC,0,"Parachute");
              }
              else if(pending_type==ORDER_TYPE_SELL_LIMIT){
                sent=order.SellLimit(starting_volume,start_price,_Symbol,0.0,0.0,ORDER_TIME_GTC,0,"Parachute");
              }
              Sleep(333);
              }
            if(!sent){
            Print("PARACHUTE::Cannot open pending order");
            return(false);
            }  
            //increase step and volume 
              start_price+=price_step;
              starting_volume+=volume_step;
              if(starting_volume<vol_min){starting_volume=vol_min;}
              else if(starting_volume>vol_max){starting_volume=vol_max;}
            if(i==amount-1){return(true);}
            }
    }else{Print("PARACHUTE::Cannot select position "+IntegerToString(for_ticket));}
  }else{
  Print("PARACHUTE::Error in preparation");
  }
return(false);
}
 
Lorentzos Roussos #:

Hi ,You want to deploy limit orders around an existing open order ? am i understanding this right ? 

Yes, in the end the should be a cascading order structure.

Example (short selling): 1 open position and 3 limit orders. Volume multiple=2, Price multiple=0.9

Open position (volume=1, entry price=10)

Order #1 (volume=2, limit price=9)

Order #2 (volume=4, limit price=8.1) 

Order #3 (volume=8, limit price=7.29)


I cannot get the loop right...

 
Lorentzos Roussos #:

Here you go , this is an example . 

I hope it helps 

(your issue may have been the stop level of the broker)

Cheers , happy holidays , schöne ferien :)

Thanks. The broker is fine. I get one limit order, but not the rest.

In your example I can see that you have the increase step and volume after the loop...I'll try that.

 
Johannes Vogel #:

Thanks. The broker is fine. I get one limit order, but not the rest.

In your example I can see that you have the increase step and volume after the loop...I'll try that.

Does it work if you add instead of multiplying ? If yes then your issue is probably invalid price and you could try normalize double. (assuming based on that the first one passes the rest don't)

Also check the volume limits and the volume step (i'm not checking for volume step in the code) since you are multiplying

NormalizeDouble(new_price,_Digits);

Cheers

PS : 

If i recall how the volume step works , you can do this : 

double volume_you_want=...; //this is the result of the volume you want after the multiplication
double volume_step=...;//and let's assume this is the volume step
int steps=(int)(MathFloor(volume_you_want/volume_step));
volume_you_want=((double)steps)*volume_step;
//and check against vol max vol min
Reason: