How to index the Open Trades symbols (in a Buffer)

Hi coders, I’m learning coding now. I got a set of codes from MQL5 (to get the symbols that with open orders)

#include <arrays/arraystring.mqh>

void OnStart()
{
   CArrayString symbols;
   for (int i=0; OrderSelect(i, SELECT_BY_POS); i++)
      if (symbols.SearchLinear(OrderSymbol()) < 0)
         symbols.Add(OrderSymbol());
   for (int i=0; i<symbols.Total(); i++)
      Print(symbols[i]);
}
for (int i=0; i<symbols.Total(); i++)
Print(symbols[i]);

From my understanding, the “symbols” is a buffer to store all the open trades symbols. Let’s say there are 5 symbols that with open orders, is there a way to index the open trades symbols, sort the 5 symbols and to avoid using the [i] so that if I want to get the iHigh price for all the open trades symbols, such as :-

Print(DoubleToStr(iHigh(symbols,1440,1),5));
// expected output would be the High price of the 5 symbols

I also intend to run a loop to get the shift for the 5 symbols too :-

   int obStoF5Sf=0; for(int i=0; i<=100; i++) {
   double cSto0=iStochastic(symbols,60,5,3,3,0,0,MODE_MAIN,i), cSto1=iStochastic(symbols,60,5,3,3,0,0,MODE_MAIN,i+1),
   cSto2=iStochastic(symbols,60,5,3,3,0,0,MODE_MAIN,i+2), cSto3=iStochastic(symbols,60,5,3,3,0,0,MODE_MAIN,i+3),
   cSto4=iStochastic(symbols,60,5,3,3,0,0,MODE_MAIN,i+4);
   if(cSto0<cSto1 && cSto1>=cSto2 && cSto2>cSto3 && cSto3>cSto4 && cSto1>80) {
      obStoF5Sf=i;
      break;
      }
   } // to get Overbought Shift

   Print(oSym+" OB Sto Sf : "+IntegerToString(obStoF5Sf));

How to “convert” the symbols[i] into oSym and sort the 5 oSym according to MODE_ASCEND ? What are the coding steps to do so ? Thanks

FYI, I tried to firstly to “convert” as follows :-

   string oSym="";
   for(int i=0; i<symbols.Total(); i++) oSym=symbols[i];

   Print(oSym+" High "+DoubleToStr(iHigh(oSym,1440,1),5));

but the output only has 1 symbol (the first symbol), the other 4 symbols are not shown, why ?

It looks like you’re diving into the interesting world of coding with MQL5, specifically focusing on handling trade symbols in MetaTrader. Your primary goal is to process symbols with open orders, index them, sort them, and perform operations like fetching the high prices and stochastic values. Let’s tackle your questions step by step.

Understanding Your Current Code

Your current code correctly collects all unique symbols with open orders into a CArrayString object. The issue arises when you try to process these symbols outside the scope where they’re valid, and in the way you attempt to “convert” the symbols into oSym.

Fixing the Output for Multiple Symbols

Your attempt only assigns the last symbol in the array to oSym, which is why you’re seeing only one symbol’s output. This happens because each iteration of your loop overwrites oSym with the current symbol, and after the loop concludes, oSym retains only the last symbol’s value.

Solutions and Steps

Indexing and Sorting Symbols

To sort the symbols, you would ideally want to use a sorting algorithm or function that MQL5 supports. However, CArrayString doesn’t directly support sorting. You’d have to implement a sorting algorithm yourself or convert the CArrayString to a different structure that supports sorting.

For simplicity, let’s focus on improving your current process to get the desired output for all symbols. Sorting can be more complex and might require a custom implementation.

Improved Code for Handling Multiple Symbols

  1. Correctly Fetching High Prices for All Symbols:

    You want to iterate through all symbols and fetch the high price for each. Your current approach tries to assign multiple symbols to a single string variable (oSym), which won’t work as intended. Instead, you should use the loop to process each symbol individually:

    #include <arrays/arraystring.mqh>
    
    void OnStart() {
       CArrayString symbols;
       for (int i = 0; OrderSelect(i, SELECT_BY_POS); i++) {
          if (symbols.SearchLinear(OrderSymbol()) < 0)
             symbols.Add(OrderSymbol());
       }
    
       // Sorting symbols if needed here before the loop below
    
       for (int i = 0; i < symbols.Total(); i++) {
          string symbol = symbols[i];
          Print(symbol + " High: " + DoubleToStr(iHigh(symbol, PERIOD_D1, 1), 5));
       }
    }
    

    This will print the high price for each symbol collected.

  2. Loop to Get the Shift for the 5 Symbols:

    When you’re trying to work with stochastic values for each symbol, you should encapsulate the logic inside a function or within the loop that iterates over each symbol. Your current code snippet seems to try to use symbols directly in iStochastic, which isn’t correct because iStochastic expects a single symbol as a string, not an array or collection of symbols.

  3. Sorting and Indexing:

    To sort the symbols and work with them in a sorted order, consider implementing a sorting algorithm or using an auxiliary array or list structure that supports sorting. MQL5 does not provide a direct way to sort a CArrayString, but you can implement a basic sorting algorithm (like bubble sort) or use a different data structure for your purposes.

  4. Final Notes:

    • Ensure your logic for working with market symbols respects the scope where variables are declared and used.
    • When iterating over symbols to perform operations like fetching high prices or calculating stochastics, make sure you’re doing it within the context of each symbol being processed individually.
    • For sorting, you might need to implement a custom sorting function or adjust your data structure.

This approach will help you manage and process multiple symbols effectively, capturing the high prices for each and potentially sorting them as needed for further analysis or operation.


Let me know if this helped? :slight_smile:

Hi Sherman, thank you for your detailed advice.

FYI, I’m not a programmer, but I’m learning coding now.

  1. From the way you explained, the “oSym” must be “inside” the loop but cannot be “outside”. My original thought was “outside” the loop so that all the calculation can use the “oSym”. Anyway, I accept it.

  2. Since you touched on the sorting issue, yes, I tried to use the ArraySort to sort the symbols, but unfortunately, I realised that ArraySort can only work on values but not string. From the way you explained, sorting job seems a complicated coding. Do you have a fast and short-cut way to sort the symbols ?

  3. I have another issue in my EA test :-

   string arTrSym[8]={"AUDCAD","AUDCHF","AUDJPY","AUDNZD","AUDUSD","CADCHF","CADJPY","CHFJPY"};

   double bLLNPL[], sLLNPL[];
   ArrayResize(bLLNPL,ArraySize(arTrSym));
   ArrayResize(sLLNPL,ArraySize(arTrSym));

   for(int i=0; i<ArraySize(arTrSym); i++) {
   double bSum=0, sSum=0;
      for(int j=OrdersTotal()-1; j>=0; j--) {
      if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==arTrSym[i] && (OrderMagicNumber()==mnBUY || OrderMagicNumber()==mnSEL)) {
      if(OrderType()==OP_BUY)    bSum+=OrderProfit()+OrderCommission()+OrderSwap();
      if(OrderType()==OP_SELL)   sSum+=OrderProfit()+OrderCommission()+OrderSwap();}}
   bLLNPL[i]=bSum; sLLNPL[i]=sSum;}

   ArraySort(bLLNPL,WHOLE_ARRAY,0,MODE_ASCEND); // -50.00,-23.02 ... 30.50
   ArraySort(sLLNPL,WHOLE_ARRAY,0,MODE_ASCEND); // -50.00,-23.02 ... 30.50

   Print("bLLNPL "+DoubleToStr(bLLNPL[0],2)+" / "+DoubleToStr(bLLNPL[1],2)+" / "+DoubleToStr(bLLNPL[2],2)+" / "+DoubleToStr(bLLNPL[3],2)+" ++ sLLNPL "+
   DoubleToStr(sLLNPL[0],2)+" / "+DoubleToStr(sLLNPL[1],2)+" / "+DoubleToStr(sLLNPL[2],2)+" / "+DoubleToStr(sLLNPL[3],2));

I notice that if the NPL values of ArraySorted symbols (MODE_ASCEND) are positive values (in net profit position), the output will be “0.00”, my question : the OrderProfit()+OrderCommission()+OrderSwap() should give both positive and negative values, and should not convert the positive values to “0.00”, am I right ?

If I change to MODE_DESCEND, all the negative values (in net loss position) will turn into zero.

Why the MQL4 ArraySort cannot keep both positive and negative values together in the buffers ? Is there any way to resolve and to avoid auto-ZERO setting issue ?

FYI, you cannot test the NPL codes in a script but you must test it in a live EA with existing multiple symbols’ open orders.

Thanks

Your questions cover a few different areas of MQL programming, so I’ll address them separately to provide clarity and solutions.

Sorting Symbols Issue

It seems there was a misunderstanding about the ArraySort function in MQL. ArraySort can sort arrays of strings (symbols in your case). However, when you sort the arrays bLLNPL and sLLNPL, which contain the net profit/loss (NPL) values for each symbol, you lose the association between the symbols and their corresponding NPL values because sorting the NPL arrays reorders them independently of the symbols.


To maintain the association between symbols and their NPL values and sort them based on NPL, you would typically create a structure that holds both the symbol and its NPL value, then sort an array of these structures. Unfortunately, MQL does not directly support sorting arrays of custom structures. However, you can work around this limitation by using a “proxy” array to sort the indices indirectly.

Here’s an example approach:

  1. Create a “proxy” array to hold indices.
  2. Sort the proxy array based on the NPL values, maintaining the association with symbols.

Example Solution for Sorting

Since MQL4 doesn’t support sorting an array of structures directly, I’ll illustrate how you can sort the symbols based on their NPL values using a proxy array for indices:

// Assuming 'arTrSym' and 'bLLNPL' are already filled as in your example
int indices[ArraySize(arTrSym)];
for(int i = 0; i < ArraySize(indices); i++) {
    indices[i] = i; // Initialize indices
}

// Custom function to sort 'indices' based on 'bLLNPL' values
void SortSymbolsByNPL(double &npl[], int &indices[]) {
    for(int i = 0; i < ArraySize(npl) - 1; i++) {
        for(int j = 0; j < ArraySize(npl) - i - 1; j++) {
            if(npl[indices[j]] > npl[indices[j + 1]]) {
                // Swap indices
                int temp = indices[j];
                indices[j] = indices[j + 1];
                indices[j + 1] = temp;
            }
        }
    }
}

// Call the sort function
SortSymbolsByNPL(bLLNPL, indices);

// Now 'indices' is sorted based on 'bLLNPL' values, and you can access the sorted symbols and NPLs like this:
for(int i = 0; i < ArraySize(arTrSym); i++) {
    Print(arTrSym[indices[i]] + ": " + DoubleToString(bLLNPL[indices[i]], 2));
}

Issue with Positive and Negative Values Turning into “0.00”

Regarding the NPL values turning into “0.00” after sorting, it seems there might be a misunderstanding or a specific issue with how the sorting or data assignment is done. The ArraySort function itself does not alter the values (other than ordering them), nor does it turn positive or negative values into “0.00”. The problem might lie elsewhere in the code logic or in how the values are being printed or interpreted.


Ensure you’re accurately printing and interpreting the sorted values. Debug by printing values before and after sorting to confirm the behavior.


If negative values turn into zero when changing to MODE_DESCEND, double-check that the arrays are correctly associated and that there’s no logic elsewhere resetting or modifying these values based on the sort order or any other condition.


In summary, to resolve the sorting issue, use the proxy sorting method described above. For the issue with values turning into “0.00”, ensure there’s no accidental modification of the arrays post-sorting and carefully debug the value assignments and print statements.


I myself am not an MQL expert and am more inclined towards Py and Js libraries, the best help would be completing an actual MQL tutorial and get a basic function to work.


Try not to delve too deep into specific tasks, just yet, until you can - 1. Create a simple indicator [e.g: a moving average], and 2. Create a simple EA based on that. Once you’ve mastered the basics, you can move on from there. Hope this helps…

Hi Sherman, thank you. Let’s come back to the same question.

   CArrayString opSym; // Symbols with Open Trades
   for(int i=0; OrderSelect(i,SELECT_BY_POS,MODE_TRADES); i++)
   if(opSym.SearchLinear(OrderSymbol())<0 && (OrderMagicNumber()==mnBUY || OrderMagicNumber()==mnSEL)) opSym.Add(OrderSymbol());
   //for(int i=0; i<opSym.Total(); i++) Print(opSym[i]);

The above opSym[i] is to store the total symbols that with open orders (BUY and/or SELL open orders). I tried to figure out for the past 2 days that to get :-

  1. string bSym; // to store all the symbols with only BUY open orders
  2. string sSym; // to store all the symbols with only SELL open orders
  3. double bSymSumNPL; // to store the sum of net P/L (+=OrderProfit()+OrderCommission()+OrderSwap()) for each symbol with only BUY Orders
  4. double sSymSumNPL; // to store the sum of net P/L (+=OrderProfit()+OrderCommission()+OrderSwap()) for each symbol with only SELL Orders

After tried, but I failed.

FYI, if I use for(int j=OrdersTotal()-1; j>=0; j–) to get the above 4 missions, I don’t know how to remove the duplicated symbols, for example, if GBPJPY has 3 BUY open orders, I only need to store the GBPJPY only once into the bSym but not to store 3 times of GBPJPY.

   string bSymArTem[], sSymArTem[]; // to Store Sym with OpOrd
   ArrayResize(bSymArTem,opSym.Total()); ArrayResize(sSymArTem,opSym.Total()); 

   int bSymNum=0; // Total Number of Sym with BUY open trades
   for(int i=0; i<opSym.Total(); i++) {
   int bSum=0; string bSymb="";
      for(int j=OrdersTotal()-1; j>=0; j--) {
      if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==opSym[i] && OrderMagicNumber()==mnBUY) {
      if(OrderType()==OP_BUY) {bSum++; bSymb=opSym[i];}}}
   if(bSum>0) {bSymNum++; bSymArTem[i]=bSymb;}}

   int sSymNum=0; // Total Number of Sym with SEL open trades
   for(int i=0; i<opSym.Total(); i++) {
   int sSum=0; string sSymb="";
      for(int j=OrdersTotal()-1; j>=0; j--) {
      if(OrderSelect(j,SELECT_BY_POS,MODE_TRADES) && OrderSymbol()==opSym[i] && OrderMagicNumber()==mnSEL) {
      if(OrderType()==OP_SELL) {sSum++; sSymb=opSym[i];}}}
   if(sSum>0) {sSymNum++; sSymArTem[i]=sSymb;}}

   string bSymAr[]; ArrayResize(bSymAr,0);
   for(int i=0; i<ArraySize(bSymArTem); i++) {
   if(bSymArTem[i]!=NULL && OrderMagicNumber()==mnBUY)   {ArrayResize(bSymAr,ArraySize(bSymAr)+1);
                                                          bSymAr[ArraySize(bSymAr)-1]=bSymArTem[i];}}
   string sSymAr[]; ArrayResize(sSymAr,0); 
   for(int i=0; i<ArraySize(sSymArTem); i++) {
   if(sSymArTem[i]!=NULL && OrderMagicNumber()==mnSEL)   {ArrayResize(sSymAr,ArraySize(sSymAr)+1);
                                                          sSymAr[ArraySize(sSymAr)-1]=sSymArTem[i];}}

   {Print(sym+" : BUY Sym# "+IntegerToString(bSymNum)+" / "+IntegerToString(ArraySize(bSymAr))+
   " : SEL Sym# "+IntegerToString(sSymNum)+" / "+IntegerToString(ArraySize(sSymAr))); Sleep(500);}

In my case, there is only 1 SELL symbol, i.e. EURSGD, why sSymNum shows 1 but ArraySize(sSymAr) shows 0 (the EURSGD is not stored into the sSymAr ) ? Why ?

Could you please help to provide me the looping codes ? Have a nice weekend, thanks