Call variable with string concatenate or similar just impossible?

 

Need advice in order to be able to solve an issue that is preventing me from using 10 times smaller code because I can't call a variable with String Concatenate. If you think my ideas are not the best please let me know what you would do instead, you think this is the best at all to use same ea on many timeframes (without opening 50 charts just for 5 instruments with 10 timeframes each)? 

I named a variable Macd0, where I will store the current Macd of PERIOD_CURRENT, therefore the 0 at the end of Macd0. In the same way I created a list of 10 variables for every time frame, Macd1 (equivalent of Macd PERIOD_M1), Macd5 to store the Macd for PERIOD_M5, this same way for all the Macds all the way to monthly.

So

Macd0 is assigned the macd for macd current

Macd1 is assigned the macd for 1m

Macd5 is assigned the macd for 5m

Macd15 is assigned the macd for 15m 

I then created a TimeFrames[] array in order to store the different timeframes, so as to have the ability to use StringConcatenate in order to juxtapose the variable name with the appropriate timeframe. 

   TimeFrames[0]=PERIOD_CURRENT; // (note PERIOD_CURRENT is just a 0 in the Macd function call)
   TimeFrames[1]=PERIOD_M1; // (PERIOD_M1 is just a 1 in function call)
   TimeFrames[2]=PERIOD_M5; // (PERIOD_M5 is just a 5)
   TimeFrames[3]=PERIOD_M15;
   TimeFrames[4]=PERIOD_M30;
   TimeFrames[5]=PERIOD_H1;
   TimeFrames[6]=PERIOD_H4;
   TimeFrames[7]=PERIOD_D1;
   TimeFrames[8]=PERIOD_W1;
   TimeFrames[9]=PERIOD_MN1;

So for example I use 

StringConcatenate("Macd",TimeFrames[0])

in order to call the variable named "Macd0" where we stored the Macd for the current timeframe. Calling all the macds:

Macd0

Macd1

Macd5 

by just appending the TimeFrame[x] with a string concatenate would allow me to just put the TimeFrames[0] at the end of Macd in order to call Macd0, as I attempted above.

Unfortunately this does not work, as 

StringConcatenate("Macd",TimeFrames[0])

just prints the actual string, not calls the variable itself that is named the same way as this string.

In other words , I am trying to make an EA work on multiple timeframes intead of copy pasting everything ten times for every time frame. I thought I could just call a variable with StringConcatenate, and use this within a for loop to rapidly make an ea work with every time frame, but I cannot.

The following code

Print(StringConcatenate("Macd",TimeFrames[0]));

does not print the same result as

Print(Macd0);

when Macd0 has been assigned the value of current Macd for example.


So is there any way to call a variable with the string concatenate function or anything similar in order to not have to copy paste the same code 10 different times for every time frames? I know maybe its a little weird, feel free to ask away if you dont get it, as its even a little difficult to express the question. Looks like its maybe one of those things they left out of MT4, so Im just making this thread about it. Hope theres a way, thank you !!


You think this is a bad idea and its just more straighforward and better programming practice to just copy paste the whole thing many times instead or any better way Id really really appreciate your insight. Its not gonna break my pc however seems so illogical instead a simple for loop and the ea is ten times smaller. Fear the simple EA might break somewhere along the process as there are various more loops in there, im not that experienced in programming. Looks like unfortunately I will be forced to just copy pasting the whole thing 10 x eventually if I cant find a smarter way.

 
//+------------------------------------------------------------------+
//|                                                        Debug.mq4 |
//|                                    Copyright 2019, Chad Magruder |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Chad Magruder"
#property version   "1.00"
#property strict
int TimeFrames[10];
double MACD[10];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   
   TimeFrames[0]=PERIOD_CURRENT; // (note PERIOD_CURRENT is just a 0 in the Macd function call)
   TimeFrames[1]=PERIOD_M1; // (PERIOD_M1 is just a 1 in function call)
   TimeFrames[2]=PERIOD_M5; // (PERIOD_M5 is just a 5)
   TimeFrames[3]=PERIOD_M15;
   TimeFrames[4]=PERIOD_M30;
   TimeFrames[5]=PERIOD_H1;
   TimeFrames[6]=PERIOD_H4;
   TimeFrames[7]=PERIOD_D1;
   TimeFrames[8]=PERIOD_W1;
   TimeFrames[9]=PERIOD_MN1;

   for(int a=0;a<10;a++){
      MACD[a]=iMACD(Symbol(),TimeFrames[a],12,26,9,PRICE_CLOSE,MODE_MAIN,1);
      Print(MACD[a]);
      //OR
      Print(iMACD(Symbol(),TimeFrames[a],12,26,9,PRICE_CLOSE,MODE_MAIN,1));
   }
  }
//+------------------------------------------------------------------+
 

In programming you'd never use dynamic variable creation. You need a collection to add your indicators to. MQL already provides everything you need in the std lib with CIndicators...

 
Chad Magruder:

THX!!! This looks to be very close to the solution!! You made my week This is the type of post thats really really worth it, so happy I asked this question at the right place at the right time.   Can take someone an extremely long time to figure all of these quasi-genius programming insights (to a new programmer) on their own.

Nice thinking, normal maybe in programming, however whoever figure this type of thing out for the first time is a genius. Seen somewhat similar things done with associative arrays. These types of perfectly thought out ways around seeming limitations are priceless. 

Now I also have 10 x less variables as its all just simple arrays for every time frame version of every variable im really really happy about that
 
nicholi shen:

In programming you'd never use dynamic variable creation. You need a collection to add your indicators to. MQL already provides everything you need in the std lib with CIndicators...

Considering this Ill just use the [0] as the "dynamic variable part of the name" as suggested.

Also you mention I need a collection to add indicators to. What for? How you think this seeming to be more complicated approach more efficient/better and in what ways instead of just using a (to my understanding) "fake/virtual dynamic array" as suggested?

I greatly appreaciate your post, and I do not want to sound rude however I need to express the fact that I just needed an efficient, lines-of-code-reducing nice insight (maybe what you say, I cant figure it out though) of how to cut down on copy pasting the whole ea millions of times so that it did the same thing for every time frame; I wonder how your approach would be better, looks like there's something to it, Ill see what I can find about it. Seems you suggest having all of these MACD's already isolated in a library which I just call out from the EA. This the idea? Faster like this or something? This would definitely "shorten" the EA code but would it exactly directly result in a faster/more efficient EA? To be serious Id now have to test this concept perfectly out for live however ive never even gone live yet so its a little too much for me at the moment unfortunately
 

OK now a second thing about all of this:

I now have a set of all of these for-use-in-different-timeframes versions of the same variable. For example ProfitTargetOfSellTrade[4] holds:

ProfitTargetOfSellTrade[0]; // Profit Target for TF PERIOD_CURRENT
ProfitTargetOfSellTrade[1]; // Profit Target for TF PERIOD_M1
ProfitTargetOfSellTrade[2]; // Profit Target for TF PERIOD_M5

in the form of these smart "virtually dynamic variables" in the form of (can "change name" with just the [x] component) arrays:

double ProfitTargetOfSellTrade[4];
double ProfitTargetOfBuyTrade[4];
double StopLossTargetOfSellTrade[4];
double StopLossTargetOfBuyTrade[4];


So the Macd[4] decalred array holds:

Macd[0] // current timeframe version of the macd of at shift 0
Macd[1] // timeframe minute one version of the macd at shift 0
Macd[2] // timeframe minute five version of the macd at shift 0
Macd[3] // timeframe minute fifteen version of the macd at shift 0

However in the actual code I already had "real" arrays in there; which means that i just cant "universalize" them like the variables at all. (Or can I? The only way I can think of would be to assign a certain range of the array for every different timeframe which is not going to work for my situation.)

To better explain, for example, lets look at the declaration part on top of EA where I've got:


double Macd[4]; // described above; is a "universal one" because I have mixed timeframes in the same array for macd[4]
double ProfitTargetOfSellTrade[4]; // universal as well as there is one array entry for every timeframe to be traded, just like the above macd[4] which also holds data from different timeframes as explained above. 
double ProfitTargetOfBuyTrade[4];  // universal (mixed timeframes' data)
double StopLossTargetOfSellTrade[4]; // universal
double StopLossTargetOfBuyTrade[4]; // universal
double MacdAverageCurrentTimeframe[10]; // NON UNIVERSAL!! ( only current timeframe data here) The array that holds data of Macd's BUT JUST FOR THE PERDIOD_CURRENT TIMEFRAME, unlike previous above macd[4] array that is "universal". 
double MacdAverageM1Timeframe[10]; // NON UNIVERSAL The array that holds average of Macd's for M1 only 
double MacdAverageM5Timeframe[10]; // NON UNIVERSAL The array that holds average of Macd's for M5 only
double MacdAverageM15Timeframe[10]; // NON UNIVERSAL The array that holds average of Macd's for M15 only:

What Ive been trying to get to is:

Do I need to keep this "Non Universal/Univesral Arrays" approach? Seems like a better way as well probably exists. 

The Macd[4] array holds data from mixed timeframes, however I will do individual calculations for every time frame which require the averages of each time frame individually allocated to a separate array then. This effectively divides my decalared things into the "universal" and "non universal" types. You think this is going the best way like this or you know a better way about all of this?

Judging by how much help the previous answer gave me, Ive decided to post this in hope that there is a revelation of the better way about all of this(im assuming there is one); however it does look like Ill have to keep the "Non Universal Arrays" and " Universal Arrays" approach like that. Anyway its a huge upgrade from where I was. 

Will greatly appreciate any of your insights about this situation or any insight into the best way to make an EA work on every timeframe in the most efficient way possible.Dont know if this is really even going to work might jarble everything up Ill post about progress/results later.

 
//+------------------------------------------------------------------+
//|                                                        debug.mq4 |
//|                                    Copyright 2019, Chad Magruder |
//+------------------------------------------------------------------+
#property copyright "Copyright 2019, Chad Magruder"
#property version   "1.00"
#property strict
int TimeFrames[10];
double MACD[10][10];
//+------------------------------------------------------------------+
//| Script program start function                                    |
//+------------------------------------------------------------------+
void OnStart()
  {
//---
   TimeFrames[0]=PERIOD_CURRENT; // (note PERIOD_CURRENT is just a 0 in the Macd function call)
   TimeFrames[1]=PERIOD_M1; // (PERIOD_M1 is just a 1 in function call)
   TimeFrames[2]=PERIOD_M5; // (PERIOD_M5 is just a 5)
   TimeFrames[3]=PERIOD_M15;
   TimeFrames[4]=PERIOD_M30;
   TimeFrames[5]=PERIOD_H1;
   TimeFrames[6]=PERIOD_H4;
   TimeFrames[7]=PERIOD_D1;
   TimeFrames[8]=PERIOD_W1;
   TimeFrames[9]=PERIOD_MN1;


for(int a=0;a<10;a++){
   for(int b=0;b<10;b++){
      MACD[a][b]=iMACD(Symbol(),TimeFrames[a],12,26,9,PRICE_CLOSE,MODE_MAIN,b);//Calculate your lows here to assign into the two dimensional array
   }
}
  
for(int a=0;a<10;a++){
   for(int b=0;b<10;b++){
      Print("PERIOD("+TimeFrames[a]+") - BAR("+b+") MACD: "+MACD[a][b]);
   }
}
}//OnStart()

 
//+------------------------------------------------------------------+

Look into two dimensional arrays. Same can be done with your Stops and Targets

double Sat[10][4];

//Sat[X][0]=X Timeframe Buy Target
//Sat[X][1]=X Timeframe Sell Target
//Sat[X][2]=X Timeframe Buy SL
//Sat[X][3]=X Timeframe Sell SL
 
Chad Magruder:

Look into two dimensional arrays. Same can be done with your Stops and Targets

I dont know why I was under the incorrect impression that MT4 did not feature multi dimensional arrays at all.

Thanks for pointing this out!! Problem solved.

 

You should learn how to use dynamic objects with pointer collections because multidimensional arrays are not really an appropriate data type to manage collections of indicators. As soon as you need to expand the functionality of your program it's going to wreck you with bugs and impossibilities. That's when hackish code begets more hackish code until your project spins out of control and nobody can figure out what was going on. Here is an example of a better way to manage your indicators. 

#property strict
#include <indicators/indicators.mqh>

struct MacdSettings {
   ENUM_TIMEFRAMES tf;
   int fast_ma;
   int slow_ma;
   int signal;
};

class MyMACDs : public CIndicators {
public: 
   CiMACD* operator[](int i) { 
      return this.At(i); 
   }
   bool create(MacdSettings &settings[]) {
      for (int i=0; i<ArraySize(settings); i++) {
         CiMACD *macd = new CiMACD();
         bool create = macd.Create(
            _Symbol, 
            settings[i].tf,
            settings[i].fast_ma,
            settings[i].slow_ma,
            settings[i].signal,
            PRICE_CLOSE
         );
         if (!create || !this.Add(macd))
            return false;
      }
      return true; 
   }
};

MyMACDs g_macds;
//+------------------------------------------------------------------+
int OnInit()
{
   MacdSettings settings[] = {
      {PERIOD_M1,  12, 26, 9}, 
      {PERIOD_M5,  12, 26, 9},
      {PERIOD_M15, 12, 26, 9},
      {PERIOD_M30, 12, 26, 9},
      {PERIOD_H1,  12, 26, 9},
      {PERIOD_H4,  12, 26, 9}
   };
   g_macds.Clear();
   if (!g_macds.create(settings))
      return INIT_FAILED;
   return(INIT_SUCCEEDED);
}
//+------------------------------------------------------------------+
void OnTick()
{
   for (int i=0; i<g_macds.Total(); i++) {
      CiMACD *macd = g_macds[i];
      printf("PERIOD(%s) - MACD(%s)",
         EnumToString((ENUM_TIMEFRAMES)macd.Period()),
         DoubleToString(macd.Main(0), _Digits)
      );
   }
}

From this code you can access [all] indicator data -- from any buffer, any bar, and all defined timeframes - dynamically. That's not possible with arrays. 

 
nicholi shen:

You should learn how to use dynamic objects with pointer collections because multidimensional arrays are not really an appropriate data type to manage collections of indicators. As soon as you need to expand the functionality of your program it's going to wreck you with bugs and impossibilities. That's when hackish code begets more hackish code until your project spins out of control and nobody can figure out what was going on. Here is an example of a better way to manage your indicators. 

From this code you can access [all] indicator data -- from any buffer, any bar, and all defined timeframes - dynamically. That's not possible with arrays. 

THANKS!!! 

Reason: