Automatic Magic Number - page 2

 
jjc:

I'm missing something here. If I open two charts for e.g. USDJPY H1, and add an instance of the EA to each of them, then both use the the magic number 9999033.

Yes, that option was not built into it because I never had any use for it. Only possibility to distinguish between two indentical charts (that I can see) would be to hash in the window handle...

but then you'd loose the persistance over restartsand chart close, and therefore orphaned orders may or will be created as a result.

 
BarrowBoy:

So is the MT terminal app a 'container' - with a single hWnd for <the whole thing>?

Yes. It's a fairly typical MDI application. There's a top-level window which contains things like toolbars, panes, and the MDI client area. The latter then contains each chart, and each chart actually consists of two windows: a container with the drawing area inside it. Each of these things has its own hWnd handle. The WindowHandle() function returns the handle of the drawing area, and therefore using the GetParent() API call three times gives you the hWnd of the top-level MT4 window.

 

fwiw, I use below and have never had duplicates. Same EA on up to 10 [any type] charts.

I have no answer to the massively overkill junk actuals handed to hash function. I just shoved in everything including the kitchen sink. ie, I'm no maths person..., just hammer 'n chisled away until never got repeats - even on terminal startup with 10 chart profile all same EA...

Obviously, I would be keen to have a better and more describable/logical method... so start tearing it to pieces :O)

#define EMPTYSTRING     ""
#define EAIDMIN         1
#define EAIDMAX         21473


  //+------------------------------------------------------------------+
//
int iMakeHash (string s1, string s2=EMPTYSTRING, string s3=EMPTYSTRING, string s4=EMPTYSTRING, string s5=EMPTYSTRING
              ,string s6=EMPTYSTRING, string s7=EMPTYSTRING, string s8=EMPTYSTRING, string s9=EMPTYSTRING, string s10=EMPTYSTRING)
{
  /*
  Produce 32bit string hash code from  a string composed of up to TEN concatenated input strings.
  WebRef: http://www.cse.yorku.ca/~oz/hash.html
  KeyWrd: "djb2"
  FirstParaOnPage:
  "  Hash Functions
    A comprehensive collection of hash functions, a hash visualiser and some test results [see Mckenzie
    et al. Selecting a Hashing Algorithm, SP&E 20(2):209-224, Feb 1990] will be available someday. If
    you just want to have a good hash function, and cannot wait, djb2 is one of the best string hash
    functions i know. it has excellent distribution and speed on many different sets of keys and table
    sizes. you are not likely to do better with one of the "well known" functions such as PJW, K&R[1],
    etc. Also see tpop pp. 126 for graphing hash functions.
  "

  NOTES:
  0. WARNING - mql4 strings maxlen=255 so... unless code changed to deal with up to 10 string parameters
     the total length of contactenated string must be <=255
  1. C source uses "unsigned [char|long]", not in MQL4 syntax
  //
  Downside?
    original code uses UNSIGNED - MQL4 not support this, presume could use type double and then cast back to type int.
  */
  string s = StringConcatenate(s1,s2,s3,s4,s5,s6,s7,s8,s9,s10);
  int iHash = 5381;
  int iLast = StringLen(s)-1;
  int iPos=0;

  while( iPos <= iLast )    //while (c = *str++)  [ consume str bytes until EOS hit {isn't C concise!} ]
  {
    //original C code: hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
    iHash = ((iHash << 5) + iHash) + StringGetChar(s,iPos);    //StringGetChar() returns int
    iPos++;
  }
  return(MathAbs(iHash));
  
}//iMakeHash()




  //+------------------------------------------------------------------+
//
int iMakeExpertId ()
{
  int i1a,i2a,i1b,i2b;
  int iExpertId = EAIDMAX+1;
  while(iExpertId<EAIDMIN || iExpertId>EAIDMAX)
  {
    i1a=TimeLocal(); i2a=GetTickCount();
    Sleep(500);
    i1b=TimeLocal(); i2b=GetTickCount();
    MathSrand(iMakeHash(Symbol()
                        ,DoubleToStr(Period(),Digits)
                        ,DoubleToStr(i2a*WindowBarsPerChart()/Period(),Digits-1)
                        ,DoubleToStr(WindowTimeOnDropped()/i2b,Digits+1)
                        ,StringConcatenate(i2a/Period()
                                          ,Symbol()
                                          ,Period()
                                          ,i1a
                                          ,i2b*WindowBarsPerChart()/Period()
                                          ,i1b/WindowBarsPerChart()
                                          ,WindowTimeOnDropped()
                                          )
                        )
              );

    iExpertId = MathRand();  //here, on 2nd rand call, is even btr (tests seem to say this...)
  }

  return(iExpertId);

}//iMakeExpertId()

daaaaamn... these results are when had diff EAIDMAX! Anyway, just can't get the staff these days 0 lol
  /*test extract:
12:06:22 "EXPERT ID = "19736
12:06:21 "EXPERT ID = "16236
12:06:20 "EXPERT ID = "4633
12:06:19 "EXPERT ID = "26753
12:06:18 "EXPERT ID = "28286
12:06:16 "EXPERT ID = "23335
12:06:15 "EXPERT ID = "4036
12:06:14 "EXPERT ID = "12879
12:06:13 "EXPERT ID = "8095

12:06:08 "EXPERT ID = "7940
12:06:07 "EXPERT ID = "10700
12:06:06 "EXPERT ID = "24889
12:06:05 "EXPERT ID = "16055
12:06:04 "EXPERT ID = "12774
12:06:03 "EXPERT ID = "10058
12:06:02 "EXPERT ID = "29346
12:06:01 "EXPERT ID = "14624
12:06:00 "EXPERT ID = "18432
*/
 
fbj:

fwiw, I use below and have never had duplicates. Same EA on up to 10 [any type] charts.

I have no answer to the massively overkill junk actuals handed to hash function. I just shoved in everything including the kitchen sink. ie, I'm no maths person..., just hammer 'n chisled away until never got repeats - even on terminal startup with 10 chart profile all same EA...

Obviously, I would be keen to have a better and more describable/logical method... so start tearing it to pieces :O)

I like it. Particularly the good ol' djb2 hash.

 

Very impressive stuff chaps :)

MDI containers takes me back <sigh>

I still say that, IMHO, Magic Numbers are too important to apply randomly!

I'm sure CB would confirm that predictable recovery on restart is an extremely important element in a robust system..

FWIW

-BB-

 

With this code an EA is able to recognize its own orders if the platform shutdowns. It uses Global Variables so if you want to make the EA "inmune" to PC shutdown it could be rewritten to use files instead of Global Variables. I have attached too an example that opens a position just at the init time and closes it in the next bar, you can load the expert in 1M timeframe, shutdown metatrader and then open it again, just wait for the next bar to see how the EA closes its order. It hasn't been proved with multiple graphs neither tricked with multiple orders, but what do you think about it?

int MagicNumber;
 
int init()
{
   // Unique sting id.    
   string id = WindowExpertName() + Symbol() + Period();
    
    
   // If there isn't already a Global Variable with the id in wich search for the MagicNumber create it  
   if(!GlobalVariableCheck(id))
   {
      MagicNumber = WindowHandle(Symbol(),0);   
      GlobalVariableSet(id,MagicNumber);
   }
   else // Just get the MagicNumber for the unique id
   {
      MagicNumber = GlobalVariableGet(id);
   }
      
}
Files:
 
jjc wrote >>

I like it. Particularly the good ol' djb2 hash.

thanks - but I really do feel sheepish about such an uninformed bit of coding in makeexpertid...

Is early yet but maybe someone will spot the flaw(s)... should they be present

 
BarrowBoy wrote >>

Very impressive stuff chaps :)

MDI containers takes me back <sigh>

I still say that, IMHO, Magic Numbers are too important to apply randomly!

I'm sure CB would confirm that predictable recovery on restart is an extremely important element in a robust system..


FWIW

-BB-

I still say that, IMHO, Magic Numbers are too important to apply randomly!

for sure BB, vip datums. I spent way too much time attempting to discover a unique datum which multiple instances of an EA could use. This datum had to be repeatable such that all files opened would be mapable on recovery/restart. I wanted to allow possibility of any number of same ccy+per chart EA instances to 'some how' open a unique filename and on restart magically reopen...


Window handle data could be that 'factor X' ?

 
fbj:

for sure BB, vip datums. I spent way too much time attempting to discover a unique datum which multiple instances of an EA could use. This datum had to be repeatable such that all files opened would be mapable on recovery/restart. I wanted to allow possibility of any number of same ccy+per chart EA instances to 'some how' open a unique filename and on restart magically reopen...

I can't see how this is possible without either MT4 or the user assigning an ID to each EA. Or, more accurately, I can't see anything which doesn't involve something very nasty such as generating a unique ID and then modifying the EA's .chr file to store the ID as part of the EA's extern parameters.


And, for general entertainment, the following doesn't really advance the discussion in any way, but it replaces the input to the djb2 hash with a value which is guaranteed to be unique (at the cost of requiring DLL calls). I don't know how good djb2 is meant to be on things like GUIDs, but I've just tried generating 1,000,000 IDs without any collisions. But still doesn't solve the restart issue.


#import "ole32.dll"
   int CoCreateGuid(int & Bytes[]);
#import

int GenerateMagicNumber()
{
   // Generate a 16-byte GUID
   int Bytes[4];
   CoCreateGuid(Bytes);
   
   // Hash the GUID using djb2
   int iHash = 5381;
   for (int i = 0; i < 4; i++) {
      //original C code: hash = ((hash << 5) + hash) + c; /* hash * 33 + c */
      iHash = ((iHash << 5) + iHash) + Bytes[i];
   }
   return (MathAbs(iHash));
}
 
fbj wrote >>

Window handle data could be that 'factor X' ?

If you weren't partially closing any orders, you could use the order comment to store the originating pair/timeframe info..?

Thus the EA, on restart, could work out if it had any prior orders and what magic number it was therefore supposed to be using?

NB

Keep the comments to < 25 and check on the LEFT(OrderComments(), 24) else the [sl] or [tp] stuff could affect things

Does assume that <all history> is left available in the Account History tab!

FWIW

-BB-