MathSrand, version 5 build 5260 and generating random EA magics.

 

Hello All,

I have just received version 5 build 5260.

I have for the past three years and continue to generate my EA magic numbers auto magically with the following code:

/* make_long_random()
 *
 * Make a big 64 bit random number
 * Typical uses? create a random EA magic number.
 *
 * Parameters: None
 *
 * Returns: big random number as ulong 
 */
ulong make_long_random()
{
   ulong num;

   /* Seed random number generator */
   MathSrand(GetTickCount());  /* Preferred mechanism according to MQL5 docs */
   
   num = (MathRand() << 32) | (MathRand() & 0xFFFF);

   /* Enforce limits of value between 100000000 and 999999999 */
   return( (num % (999999999L - 100000000L)) + 100000000L);
}

It's been producing reliable as-far-as-possible random EA's for the past three years and looks OK to me, can you see anything odd? Is there a library problem?

It seems to produce the exciting magic 01 - always.

Thanks for looking,

With my best regards, ESB.

 
Your topic has been moved to the section: Expert Advisors and Automated Trading
Please consider which section is most appropriate — https://www.mql5.com/en/forum/172166/page6#comment_49114893
 

You shift by 32 bits, which is beyond "int" size. So, typecast it first.

num = ( (ulong) MathRand() << 32 ) | ( MathRand() & 0xFFFF );
Probably, in previous builds, it was typecasting implicitly, but cannot confirm.
 
Fernando Carreiro #:

You shift by 32 bits, which is beyond "int" size. So, typecast it first.

Probably, in previous builds, it was typecasting implicitly, but cannot confirm.

Thank you Fernando, well spotted and will look.

WMBR, ESB.

 
By the way, why are you making it a "ulong" when the last line then limits it to 9 digits, which perfectly fits within an "int" anyway?
 

Also MathRand(), returns a value between 0 to 32767 (15 bits), which fits in a "short" (16 bits). Would it not be better to shift by 15 or 16 and not 32, if you are only generating a 9 digit number?

EDIT: And this masking part is useless (because it is already within 16 bits) ...

( MathRand() & 0xFFFF )

EDIT2: This would be better, to generate 30 bits (since you are only using 9 digits anyway) ...

num = ( MathRand() << 15 ) | MathRand();
 

Proposed code ("int", not "long", as you only use 9 digits):

int make_int_random() {
   MathSrand( GetTickCount() );
   return ( ( MathRand() << 15 ) | MathRand() ) % 899999999L + 100000000L;
};
 
Fernando Carreiro #:

Proposed code ("int", not "long", as you only use 9 digits):

To be honest, I wrote the code so long ago I can't remember. I would have honoured what is expected as a magic - I use CTrade as a parent class, so would have given CTrade::SetExpertMagicNumber() the ulong it expects as an arg.

SetExpertMagicNumber Sets the expert ID. void SetExpertMagicNumber( ulong magic // ID ) Parameters magic [in] New ID of the expert. Return Value None. RequestMagic Gets the magic number of the Expert Advisor. ulong RequestMagic() const Return Value The magic number (ID) of the Expert Advisor, used in the last request.

So whether it fits in an int or not, I would have returned a ulong.

I will try your suggestion -  at the moment I think there is a problem as I still get a magic of 01 with your revised code.

I will come back.

I am not being argumentative and I am grateful for your input - I accept your greater knowledge of the platform than mine and that I am very likely to have done something wrong; I am prepared to accept that. However, the old code did work, has worked for three years and has stopped working. No code suggested as yet as changed that.

When this code is called, you should get an (almost random) ulong back, different every time it is called.

I'll bang a painfully simple script together with a for loop, and we should see 'n' different almost random magics back. If not, we have a problem Captain.

WMBR, ESB.

 
Earthy Stag beetle #: ... at the moment I think there is a problem as I still get a magic of 01 with your revised code.

Yes, that may be because the seeding process was included within the function (as per your example), but I prefer seeding the random generator only once, at the start somewhere else ...

void OnStart() {
   MathSrand( GetTickCount() );  // Seed the generator
   for( int i=0; i < 20; i++ )
      Print( "MagicRandom: ", make_int_random() );
};

int make_int_random() {
   return ( ( MathRand() << 15 ) | MathRand() ) % 899999999L + 100000000L;
};
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 704141107
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 451984877
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 254752992
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 760146101
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 608929916
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 207962986
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 461637305
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 953298276
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 652324299
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 164382863
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 300634395
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 508311741
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 332032827
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 355350080
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 879775519
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 237967802
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 743569802
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 398481707
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 282203846
2025.09.07 20:52:03.025 TestRandom (EURUSD,M1)  MagicRandom: 732572243
 

Yes - a very good point! 😂 As I only call it once, I have got away with that 😅.

The penny has dropped - it looks like I have wasted your time, Fernando - sorry.

The code does indeed work - a little dig shows me that CTrade::SetExpertMagicNumber() does what one would expect - saves the magic to: ulong  m_magic;                // expert magic number

CTrade::RequestMagicNumber() retrieves the magic in CTrade's internal MqlTradeRequest structure - which is not yet set.

All I had to do was a) RTFM and; b) have a quick look inside CTrade.

Again, really sorry, thanks for looking and I owe you a pint.

//+------------------------------------------------------------------+
//| Tests CTrade magic # initialiation                                  |
//+------------------------------------------------------------------+
#property script_show_inputs

#include <Trade\Trade.mqh>  

CTrade trade;

int make_int_random() {
   return ( ( MathRand() << 15 ) | MathRand() ) % 899999999L + 100000000L;
};

ulong make_ulong_random() {
   return ( ( MathRand() << 15 ) | MathRand() ) % 899999999L + 100000000L;
};

void OnStart()
{
   MathSrand( GetTickCount() );  // Seed the generator
   
   trade.SetExpertMagicNumber(make_int_random());
   printf("%s[%d], %s: %s int Magic=%d", __FILE__, __LINE__, __FUNCTION__, _Symbol, trade.RequestMagic());
   trade.SetExpertMagicNumber(make_ulong_random());
   printf("%s[%d], %s: %s ulong Magic=%lu", __FILE__, __LINE__, __FUNCTION__, _Symbol, trade.RequestMagic());
   
   printf("%s[%d], %s: %s int Magic=%d", __FILE__, __LINE__, __FUNCTION__, _Symbol, make_int_random());
   printf("%s[%d], %s: %s ulong Magic=%lu", __FILE__, __LINE__, __FUNCTION__, _Symbol, make_ulong_random());

}
//+------------------------------------------------------------------+