EA is sending orders in multiple charts

 
Hi,

I'm having a problem with my EA and I would like some help with it.


I developed an EA that places a limit buy order when the asset price reaches a determined price. For instance: if Asset A reaches 10.00, the EA will add a limit buy order at 9.50.

As I'm using this strategy on many assets ( stocks ), I created a simple script to open a new graph for each symbol and apply a template with the EA.

The script to open the charts is working fine and placing the EA on each chart.  The problem is when the price of one asset reaches the level and send the order.

The order is been sent for every open asset, each with its own price, even if the other assets haven't reached its own triggers ( the price levels ). Something like this:

The price reached the level on Asset A and sent the buy order at 9.50, but it also is sending orders ( at the same time ) for all other assets ( with its own settings ): Asset A - 9.50 | Asset B - 8.35 | Asset C - 6.48

Here is what I've tryed:

- random Magic Number ( based on this > https://www.mql5.com/en/forum/141280 )
- open the charts with the script, but place the EA manually
- open the charts manually and also place the EA manually
- create a global variable at the begining of the EA to get the chart symbol and compare it with Symbol() before sending the buy order
- reinitializing global variables on the OnInit() after reading this > https://www.mql5.com/en/forum/122969


This is the checking I'm doing to call the function to place the order:

//--- checking to send buy order
//--- checking symbol to try and avoid errors with EA on multiple charts at the same time
if(rates[0].open<=trigger_price && buy_order_sent==false && chart_symbol==Symbol()){
        //--- place buy order
        send_buy_order();
}

And this is how I'm sending the order:

//--- zeroing
ZeroMemory(trade_request);
ZeroMemory(trade_result);

//--- filling trade info
trade_request.magic        = EXPERT_MAGIC;
trade_request.action       = TRADE_ACTION_PENDING;
trade_request.symbol       = chart_symbol;
trade_request.volume       = volume;
trade_request.type         = ORDER_TYPE_BUY_LIMIT;
trade_request.type_filling = ORDER_FILLING_IOC;
trade_request.price        = entry_price;
trade_request.sl           = stop_loss;
trade_request.stoplimit    = stop_loss;
trade_request.tp           = take_profit;

//--- send request
if(!OrderSend(trade_request,trade_result)){
// if unable to send request, output error
PrintFormat("OrderSend error %d ... symbol=%s volume=%d", GetLastError(),trade_request.symbol,DoubleToString(trade_request.volume));

I don't know if makes a difference, but the functions are on an mqh file and referenced on the mq5 via #include


And the build of my MetaTrader 5 is 2450 ( May 2020 )


Thank you all for the help, and sorry for my english.

Dynamic Magic Number: Unique & Referenced even if the EA is compiled over the same pair, timeframe & period
Dynamic Magic Number: Unique & Referenced even if the EA is compiled over the same pair, timeframe & period
  • 2012.09.15
  • www.mql5.com
I have been searching the MT4 forums & database to find a way to automatically generate magic numbers but to be able to do it easily and still...
 
The problem is not your English, post all the relevant code or don't expect useful help.
 
Alain Verleyen:
The problem is not your English, post all the relevant code or don't expect useful help.

Thanks for the comment. I'll try to post more of the code and hope you guys find it usefull...

This is the function I'm using to send the order ( now I know that there are better ways to check the balance, and I'll fix it later )

/+------------------------------------------------------------------+
//| Places a buy order on the entry price                            |
//+------------------------------------------------------------------+
void send_buy_order()
{

   //--- declare and initialize the trade request and result of trade request
   MqlTradeRequest     trade_request;
   MqlTradeResult      trade_result;
   MqlTradeTransaction trade_transaction;

   //--- getting account balance
   double balance = AccountInfoDouble(ACCOUNT_BALANCE);
   
   //--- get proper volume based on the financial volume (from txt file)
   volume = floor_100(fin_volume/entry_price);

   if(volume==0.0){
      Print("---------------------------------------");
      Print("volume == 0.0");
      Print("min balance needed > ", DoubleToString(entry_price*100,2));
      Print("---------------------------------------");
      //--- switching
      buy_order_sent = true;
   }

   //--- checking volume and permission to send order (again)
   if(volume>0 && buy_order_sent==false){
      if(check_trading_balance(chart_symbol,volume)){
         //--- zeroing
         ZeroMemory(trade_request);
         ZeroMemory(trade_result);
         
         //--- filling trade info
         trade_request.magic        = EXPERT_MAGIC;
         trade_request.action       = TRADE_ACTION_PENDING;
         trade_request.symbol       = chart_symbol;
         trade_request.volume       = volume;
         trade_request.type         = ORDER_TYPE_BUY_LIMIT;
         trade_request.type_filling = ORDER_FILLING_IOC;
         trade_request.price        = entry_price;
         trade_request.sl           = stop_loss;
         trade_request.stoplimit    = stop_loss;
         trade_request.tp           = take_profit;
         
         //--- switching
         buy_order_sent = true;
         
         //--- send request
         if(!OrderSend(trade_request,trade_result)){
            // if unable to send request, output error
            PrintFormat("OrderSend error %d ... symbol=%s volume=%d", GetLastError(),trade_request.symbol,DoubleToString(trade_request.volume));
         }
      }
   }
}


I'm also using this event to save the data from orders in a csv file


//+------------------------------------------------------------------+
//| Handling the trade transaction event                             |
//+------------------------------------------------------------------+
void OnTradeTransaction(const MqlTradeTransaction &trans,
                        const MqlTradeRequest &request,
                        const MqlTradeResult &result)
{
//---

   //--- result of trade request execution
   ulong            lastOrderID   =trans.order;
   ENUM_ORDER_TYPE  lastOrderType =trans.order_type;
   ENUM_ORDER_STATE lastOrderState=trans.order_state;

   //--- the name of the symbol, for which a transaction was performed
   string trans_symbol=trans.symbol;

   //--- date and time variables
   MqlDateTime struct_date;
   TimeToStruct(TimeCurrent(),struct_date);
   string today_date   = IntegerToString(struct_date.year) + "-" +
                         IntegerToString(struct_date.mon) + "-" +
                         IntegerToString(struct_date.day);
   string current_time = IntegerToString(struct_date.hour) + ":" +
                         IntegerToString(struct_date.min)  + ":" +
                         IntegerToString(struct_date.sec);

   //--- type of transaction
   ENUM_TRADE_TRANSACTION_TYPE  trans_type=trans.type;

   switch(trans.type)
   {
      case  TRADE_TRANSACTION_POSITION:   // position modification
      {
         ulong pos_ID=trans.position;
         PrintFormat("MqlTradeTransaction: Position  #%d %s modified: SL=%.5f TP=%.5f",
                     pos_ID,trans_symbol,trans.price_sl,trans.price_tp);
      }
      break;
      
      case TRADE_TRANSACTION_REQUEST:     // sending a trade request
         PrintFormat("MqlTradeTransaction: TRADE_TRANSACTION_REQUEST");
         break;
         
      case TRADE_TRANSACTION_DEAL_ADD:    // adding a trade
      {
         ulong          lastDealID    =trans.deal;
         ENUM_DEAL_TYPE lastDealType  =trans.deal_type;
         double         lastDealVolume=trans.volume;
         
         //--- Trade ID in an external system - a ticket assigned by an exchange
         string Exchange_ticket="";
         if(HistoryDealSelect(lastDealID))
            Exchange_ticket=HistoryDealGetString(lastDealID,DEAL_EXTERNAL_ID);
         if(Exchange_ticket!="")
            Exchange_ticket=StringFormat("(Exchange deal=%s)",Exchange_ticket);
         
         PrintFormat("MqlTradeTransaction: %s deal #%d %s %s %.2f lot   %s",EnumToString(trans_type),
                     lastDealID,EnumToString(lastDealType),trans_symbol,lastDealVolume,Exchange_ticket);
      }
      break;

      case TRADE_TRANSACTION_HISTORY_ADD: // adding an order to the history
      {
         //--- order ID in an external system - a ticket assigned by an Exchange
         string Exchange_ticket="";
         if(lastOrderState==ORDER_STATE_FILLED)
         {
                  
            //--- setting the switch to keep track
            buy_order_filled=true;
            
            if(HistoryOrderSelect(lastOrderID))
               Exchange_ticket=HistoryOrderGetString(lastOrderID,ORDER_EXTERNAL_ID);
            if(Exchange_ticket!="")
               Exchange_ticket=StringFormat("(Exchange ticket=%s)",Exchange_ticket);
         }

         // magic,date,time,symbol,deal,order_state,price,stop_loss,take_profit,volume
         write_csv(IntegerToString(EXPERT_MAGIC),today_date,current_time,chart_symbol,EnumToString(lastOrderType),
                   EnumToString(lastOrderState),DoubleToString(entry_price),DoubleToString(0.0),DoubleToString(0.0),
                   DoubleToString(volume));
                   
         PrintFormat("MqlTradeTransaction: %s order #%d %s %s %s   %s",EnumToString(trans_type),
         lastOrderID,EnumToString(lastOrderType),trans_symbol,EnumToString(lastOrderState),Exchange_ticket);
      }
      break;
      
      default: // other transactions  
      {
         //--- order ID in an external system - a ticket assigned by Exchange
         string Exchange_ticket="";
         if(lastOrderState==ORDER_STATE_PLACED)
         {
            PrintFormat(">> csv order added - %s | %s <<",DoubleToString(entry_price),DoubleToString(volume));
            // magic,date,time,symbol,deal,order_state,price,stop_loss,take_profit,volume
            write_csv(IntegerToString(EXPERT_MAGIC),today_date,current_time,chart_symbol,EnumToString(lastOrderType),
                      EnumToString(lastOrderState),DoubleToString(entry_price),DoubleToString(0.0),DoubleToString(0.0),
                      DoubleToString(volume));

            if(OrderSelect(lastOrderID))
               Exchange_ticket=OrderGetString(ORDER_EXTERNAL_ID);
            if(Exchange_ticket!="")
               Exchange_ticket=StringFormat("Exchange ticket=%s",Exchange_ticket);
         }
         PrintFormat("MqlTradeTransaction: %s order #%d %s %s   %s",EnumToString(trans_type),
                     lastOrderID,EnumToString(lastOrderType),EnumToString(lastOrderState),Exchange_ticket);
      }
      break;
   }
   
   //--- order ticket    
   ulong orderID_result=result.order;
   string retcode_result=GetRetcodeID(result.retcode);
   
   if(orderID_result!=0)
      PrintFormat("MqlTradeResult: order #%d retcode=%s ",orderID_result,retcode_result);

//---
}


And this is the function I'm using to check if there's a new bar ( I'm using a 1 minute chart to check the price )

//+------------------------------------------------------------------+
//| Returns true if a new bar has appeared for a symbol/period pair  |
//+------------------------------------------------------------------+
bool isNewBar()
{
   //--- memorize the time of opening of the last bar in the static variable
   static datetime last_time=0;
   
   //--- current time
   //datetime lastbar_time=SeriesInfoInteger(Symbol(),Period(),SERIES_LASTBAR_DATE);
   datetime lastbar_time=(datetime)SeriesInfoInteger(chart_symbol,Period(),SERIES_LASTBAR_DATE);

   //--- if it is the first call of the function
   if(last_time==0)
   {
      //--- set the time and exit
      last_time=lastbar_time;
      return(true); // set to true to return the first bar
   }

   //--- if the time differs
   if(last_time!=lastbar_time)
   {
      //--- memorize the time and return true
      last_time=lastbar_time;
      return(true);
   }
   //--- if we passed to this line, then the bar is not new; return false
   return(false);
}


And this is my OnTick()

//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

   MqlRates    rates[];
   MqlRates    daily_rates[]; // to get the correct open price
   MqlDateTime bar_time;
   MqlDateTime today;

   TimeToStruct(TimeCurrent(), today); // getting today date

   //--- scanning every new 1min bar
   if(isNewBar()){
   
      //--- looking at the current candle
      int copied=CopyRates(chart_symbol,PERIOD_M1,0,1,rates);
      
      if(copied<=0)
         Print("Error copying price data ",GetLastError());
      else
      {
         // check if the new bar is the first bar of the day
         TimeToStruct(rates[0].time, bar_time); // getting today date
         
         if(bar_time.day_of_year==today.day_of_year){
            //--- open price of the day to estimate the entry price
            if(entry_price==0.0){

               //--- looking at the daily candle
               int copied_daily=CopyRates(chart_symbol,PERIOD_D1,0,1,daily_rates);
               
               if(copied_daily<=0)
                  Print("Error copying daily price data ",GetLastError());
               else
               {
                  get_entry_price(daily_rates[0].open); // open price of the day
                  
                  //--- lines for debuggin
                  ObjectsDeleteAll(0);
                  if(!HLineCreate(0,"trigger_line",0,trigger_price,clrGold,STYLE_DASH,1,false,true,true,0))
                     return;
                  if(!HLineCreate(0,"entry_line",0,entry_price,clrMediumBlue,STYLE_DASH,1,false,true,true,0))
                     return;
                  if(!HLineCreate(0,"cancel_line",0,cancel_price,clrLightSlateGray,STYLE_DASH,1,false,true,true,0))
                     return;
                  if(stop_loss!=0.0){
                     if(!HLineCreate(0,"stop_line",0,stop_loss,clrRed,STYLE_DASH,1,false,true,true,0))
                        return;
                  }
                  if(take_profit!=0.0){
                     if(!HLineCreate(0,"take_line",0,take_profit,clrSpringGreen,STYLE_DASH,1,false,true,true,0))
                        return;
                  }
               }
            }
            else{
               //--- checking to send buy order
               //--- checking symbol to try and avoid errors with EA on multiple charts at the same time
               if(rates[0].open<=trigger_price && buy_order_sent==false && chart_symbol==Symbol()){
                  //--- place buy order
                  send_buy_order();
               }
               //--- if the price comes back to the open price, cancel the order
               if(rates[0].open>=cancel_price && buy_order_sent==true && buy_order_filled==false && order_deleted==false && chart_symbol==Symbol()){
                  delete_orders();
               }
               
               //--- checking to send sell order
               if(TimeCurrent()==StringToTime("16:54:00"))
               {
                  //--- send sell order
                  if(buy_order_sent==true && buy_order_filled==true && chart_symbol==Symbol())
                     send_sell_order();
                  
                  //--- delete buy order
                  if(buy_order_sent==true && buy_order_filled==false && order_deleted==false && chart_symbol==Symbol())
                     delete_orders();
               }
            }
         }
      }
   }




Thanks again

 
filipe.lopes:

Thanks for the comment. I'll try to post more of the code and hope you guys find it usefull...

This is the function I'm using to send the order ( now I know that there are better ways to check the balance, and I'll fix it later )


I'm also using this event to save the data from orders in a csv file



And this is the function I'm using to check if there's a new bar ( I'm using a 1 minute chart to check the price )


And this is my OnTick()




Thanks again

if open price - trigger price = 0 will that work? if it works you can further improve from there
 
roshjardine:
if open price - trigger price = 0 will that work? if it works you can further improve from there

Hi roshjardine,

Thanks for the tip. I'll take a look at it.


But my main problem is that MetaTrader is sending orders for every symbol with the EA.

For instance:
- if I have the EA on charts(0), charts(1) and charts(2) 
- charts(0) sets the trigger to buy Asset A at 9.50
- EA is sending orders for charts(0), charts(1) and charts(2)

What I'm trying to do is send an order for Asset A only, because the price didn't reach the levels on charts(1) and charts(2).



 
filipe.lopes:

Hi roshjardine,

Thanks for the tip. I'll take a look at it.


But my main problem is that MetaTrader is sending orders for every symbol with the EA.

For instance:
- if I have the EA on charts(0), charts(1) and charts(2) 
- charts(0) sets the trigger to buy Asset A at 9.50
- EA is sending orders for charts(0), charts(1) and charts(2)

What I'm trying to do is send an order for Asset A only, because the price didn't reach the levels on charts(1) and charts(2).



you're explicitly allowing any value that is less than equal to trigger price..so any price below trigger price regardless the charts where the Ea runs will be impacted unless you specify each trigger price for each chart respectively and evaluate from there
 
roshjardine:
you're explicitly allowing any value that is less than equal to trigger price..so any price below trigger price regardless the charts where the Ea runs will be impacted unless you specify each trigger price for each chart respectively and evaluate from there
Thank you for your input...

On each chart I'm calculating the trigger and the order price with this function

//+------------------------------------------------------------------+
//| Calculates entry, trigger, stop loss and take profit             |
//+------------------------------------------------------------------+
void get_entry_price(double open_price)
{
   //--- calculating the price of the order
   entry_price = NormalizeDouble(open_price + (open_price*(percentage/100)),2);
   
   //--- calculating the price to trigger the send of the order
   trigger_price = entry_price + ((open_price-entry_price)/3);

   //--- price to cancel the order in case the price didnt reach the order
   cancel_price = open_price;

   //--- calculating the stop loss
   if(perc_stop==0.0){stop_loss = 0.0;}
   else{stop_loss = NormalizeDouble(entry_price + (entry_price*(perc_stop/100)),2);}

   //--- calculating the take profit
   if(perc_take==0.0){take_profit=0.0;}
   else{take_profit = NormalizeDouble(entry_price + (entry_price*(perc_take/100)),2);}

   //--- for reference
   Print("open price > ", DoubleToString(open_price));
   Print("entry price > ", DoubleToString(entry_price));
   Print("trigger_price > ", DoubleToString(trigger_price));
   Print("stop_loss > ", DoubleToString(stop_loss));
   Print("take_profit > ", DoubleToString(take_profit));
   Print("fin_volume > ", DoubleToString(fin_volume));
}


And I am also checking if the rates of the symbol of the chart are below the trigger before I send the buy order


//--- checking to send buy order
//--- checking symbol to try and avoid errors with EA on multiple charts at the same time
if(rates[0].open<=trigger_price && buy_order_sent==false && chart_symbol==Symbol()){
        //--- place buy order
        send_buy_order();
}


And the variable for the trigger ( and all global variables ) are been initialized outside the OnInit() and "reinitialized" on the OnInit()

int OnInit()
  {
//---

   //--- reinitializing global variables to try and fix errors when sending orders
   // https://www.mql5.com/en/forum/122969
   EXPERT_MAGIC = makeMagicNumber(Symbol() + IntegerToString(Period()));
   entry_price    = 0.0;   // price of the order
   percentage     = 0.0;   // percent the order must be from the opening price
   perc_stop      = 0.0;   // percent to calculate the stop_loss
   perc_take      = 0.0;   // percent to calculate the take_profit
   fin_volume     = 0.0;   // financial volume for the order
   cancel_price   = 0.0;   // price to cancel order in case didnt trigger the buy order
   stop_loss      = 0.0;   // price for the stop loss
   take_profit    = 0.0;   // price for the take profit
   trigger_price  = 0.0;   // price to trigger the order
   volume         = 0.0;   // order volume
   buy_order_sent    = false; // switch to control if the order has been sent or not
   buy_order_filled  = false; // switch to control if the order has been filled or not
   sell_order_sent   = false; // switch to control if the order has been sent or not
   sell_order_filled = false; // switch to control if the order has been filled or not
   order_deleted     = false; // switch to control if the order has been deleted
   chart_symbol = Symbol(); // trying to avoid multiple send orders
   

   if(!get_data_from_txt()){
      Print(chart_symbol + " not found in price_on_open.txt . Waiting to try again");
      Sleep(10000); // 10 sec
      if(!get_data_from_txt()){
         Print(chart_symbol + " not found in price_on_open.txt for the second time. Check the file");
      }
   }
   else{
      Print(chart_symbol + " percentage > " + DoubleToString(percentage));
   }
   
   PrintFormat("Symbol -> %s | EXPERT_MAGIC -> %s", chart_symbol,IntegerToString(EXPERT_MAGIC));

   
//---
   return(INIT_SUCCEEDED);
  }
 
filipe.lopes:

Hi roshjardine,

Thanks for the tip. I'll take a look at it.


But my main problem is that MetaTrader is sending orders for every symbol with the EA.

For instance:
- if I have the EA on charts(0), charts(1) and charts(2) 
- charts(0) sets the trigger to buy Asset A at 9.50
- EA is sending orders for charts(0), charts(1) and charts(2)

What I'm trying to do is send an order for Asset A only, because the price didn't reach the levels on charts(1) and charts(2).



It sounds like that your EA is not associated independently to each symbol, but that it evaluates all symbols together. I guess that your focus should be on that.
 
WindmillMQL:
It sounds like that your EA is not associated independently to each symbol, but that it evaluates all symbols together. I guess that your focus should be on that.

Hi WindmillMQ,


Thank you for your input and I think this might be the problem.


I'll make some tests today and hope to get back to you with some good news or more information.


Thanks a lot

WindmillMQL
WindmillMQL
  • www.mql5.com
Added topic Write logging data to text file? So I have created my EA and am running it now as paper trading. In order to understand how it behaves does it contain various Alert() statements in the code. This helps me to understand when it detects certain signal changes, when it takes trades Added topic How to use...
 
Hi everyone,

I think I've found the mistake I made on my EA.

As I'm using variables to track whether an order has been sent and filled, I was assuming that just changin the variables on the OnTradeTransaction() event would do the trick.

But this event is triggered in all charts because it is an event related to the account.

I commented this part of the code and everything seems to be working fine ( I still have to test on live account ).

To avoid that, I'll check the symbol before changing those variables. And I'll also cleanup the code.

Thanks a lot for the help and I hope my mistake might help others.
 
roshjardine: if open price - trigger price = 0 will that work? if it works you can further improve from there

Doubles are rarely equal. Understand the links in:
          The == operand. - MQL4 programming forum #2 2013.06.07