creare un numero magico

 
/**
* create a positive integer for the use as a magic number.
*
* The function takes a string as argument and calculates
* an 31 bit hash value from it. The hash does certainly not 
* have the strength of a real cryptographic hash function 
* but it should be more than sufficient for generating a
* unique ID from a string and collissions should not occur.
*
* use it in your init() function like this: 
*    magic = makeMagicNumber(WindowExpertName() + Symbol() + Period());
*
* where name would be the name of your EA. Your EA will then
* get a unique magic number for each instrument and timeframe
* and this number will always be the same, whenever you put
* the same EA onto the same chart.
*
* Numbers generated during testing mode will differ from those
* numbers generated on a live chart.
*/
int makeMagicNumber(string key){
   int i, k;
   int h = 0;
   
   if (IsTesting()){
      key = "_" + key;
   }
   
   for (i=0; i<StringLen(key); i++){
      k = StringGetChar(key, i);
      h = h + k;
      h = bitRotate(h, 5); // rotate 5 bits
   }
   
   for (i=0; i<StringLen(key); i++){
      k = StringGetChar(key, i);
      h = h + k;
      // rotate depending on character value
      h = bitRotate(h, k & 0x0000000F);
   }
   
   // now we go backwards in our string
   for (i=StringLen(key); i>0; i--){   
      k = StringGetChar(key, i - 1);
      h = h + k;
      // rotate depending on the last 4 bits of h
      h = bitRotate(h, h & 0x0000000F); 
   }
   
   return(h & 0x7fffffff);
}

/**
* Rotate a 32 bit integer value bit-wise 
* the specified number of bits to the right.
* This function is needed for calculations
* in the hash function makeMacicNumber()
*/
int bitRotate(int value, int count){
   int i, tmp, mask;
   mask = (0x00000001 << count) - 1;
   tmp = value & mask;
   value = value >> count;
   value = value | (tmp << (32 - count));
   return(value);
}
 
7bit:
[ ... funzione hash ... ]

Per la cronaca, fbj una volta ha fatto qualcosa di simile usando la nota funzione hash djb2: https://www.mql5.com/en/forum/120034/page2

 
Inizialmente sono stato ispirato da questo http://www.cs.hmc.edu/~geoff/classes/hmc.cs070.200101/homework10/hashfuncs.html, specialmente quello etichettato come variante CRC (che è molto simile a djb2). Questo hash da solo, anche se non ero in grado di produrre facilmente collisioni, non mi dava abbastanza fiducia, a volte solo pochi bit differivano tra gli hash di due stringhe simili. Così ho creato tre varianti di esso con rotazione variabile di h e ho aggiunto tutti e 3 i sub-hash insieme. Se uno di essi dovesse collidere, ce ne sono ancora altri due calcolati in modo completamente diverso. Ora ogni bit cambiato nella stringa di input cambia più della metà di tutti i bit nell'hash e tutti i bit sembrano completamente casuali.


il djb2 menzionato nel tuo link sopra potrebbe essere scritto senza tutte le centinaia di linee intorno semplicemente come:
int djb2(string key){
   int i, h, k;
   for (i=0; i<StringLen(key); i++){
      k = StringGetChar(key, i);
      h = (h << 5) + h + k;
   }
   return(h);
}
 
7bit:
il djb2 menzionato nel tuo link sopra potrebbe essere scritto senza tutte le centinaia di linee intorno ad esso semplicemente come: [...]

Non sono un esperto di algoritmi di hash, tanto meno di djb2 in particolare, ma mi sembra di ricordare che l'inizializzazione del valore di hash (la variabile h nella vostra versione) a 5381 è considerata significativa, anche se nessuno è esattamente sicuro del perché.

 
*    magic = makeMagicNumber(name+ Symbol() + Period());
Non voglio fare il pignolo, ma dovresti essere in grado di usare anche questo:
*    magic = makeMagicNumber(WindowExpertName() + Symbol() + Period());
Grazie per aver postato il codice (e l'articolo sull'hashish!).

Domanda - Sto lavorando ad un metodo per aprire e chiudere più ordini sullo stesso grafico, stesso algoritmo, ecc.

Mi sto avvicinando in 2 passi -

1) generando una base MN (che è quello che il codice sopra sembra fare) come un intero. La base sarebbe sempre la stessa per ogni grafico/simbolo/timeframe
2) generando un suffisso specifico espresso come un punto decimale per ogni specifico ordine, una volta che un suffisso diventa inutilizzato, rendendolo nuovamente disponibile

Quindi il MN sarebbe XXXXXX.YYY dove X è la base e Y è il suffisso specifico. I suffissi inizierebbero a .001 e aumenterebbero di .001 per ogni nuovo invio. Ad ogni invio, verrebbe assegnato il suffisso più basso attualmente non utilizzato. In questo modo, posso recuperare l'MN più tardi rigenerando l'MN di base e scorrendo i suffissi

Sembra un po' troppo complicato. C'è un modo migliore per farlo?

Sto postando quello che ho quando è finito.
 
Come NuB non sono sicuro del perché tu voglia o abbia bisogno di un MagicNumber "criptato"?
Io uso solo i primi 5 numeri per la versione dell'EA # e gli ultimi 4 per il numero di minuti in cui viene scambiato.
 
FourX:
Come NuB non sono sicuro del perché tu voglia o abbia bisogno di un MagicNumber "criptato"?
Io uso solo i primi 5 numeri per la versione dell'EA # e gli ultimi 4 per il numero di minuti in cui viene scambiato.

Come potrebbe nel tuo esempio il Symbol() diventare parte del MN? Hai un numero di EA e un numero di Timeframe, ma il simbolo?

Identifico i miei ordini solo per MN, i miei cicli sulla lista degli ordini confrontano solo OrderMagicNumber(), il tuo dovrebbe controllare anche il nome del simbolo. Ho alcuni altri script indipendenti che fanno cose con la lista degli ordini, per esempio tracciare i plot azionari degli EA o copiare i trade su un'altra piattaforma, tutti hanno bisogno solo del numero magico per identificare i trade di uno specifico EA su una specifica coppia e uno specifico timeframe.

Io non uso affatto numeri di serie per i miei diversi EA, uso nomi brevi di 4 o 5 lettere per tutti i miei EA. Un EA chiamato snowball.mq4 per esempio avrà il nome "snow". Questo è cablato nel codice e non viene mai cambiato. Uso questo nome breve anche per i commenti agli ordini.

Quindi ho 3 cose: nome breve, Symbol e timeframe. Il modo più conveniente per convertire questo in un MN è un hash. Potrei dare dei numeri ai miei EA al posto dei nomi, ma non ci sarebbe comunque un modo semplice per convertire il nome del simbolo in un numero. Un Hash risolve semplicemente tutti questi problemi in una volta sola.

 
FourX:
Come NuB non sono sicuro del perché tu voglia o abbia bisogno di un MagicNumber 'criptato'?
Io uso solo i primi 5 numeri per la versione dell'EA # e gli ultimi 4 per il numero di minuti in cui viene scambiato.

Dovreste anche vedere questo -> https://www.mql5.com/en/forum/120034


Il problema che ho con questo approccio è che a volte ho esperti/simbolo/timeframe identici che girano sullo stesso conto. Quindi alla fine dovrei comunque cambiare qualcosa manualmente, ed è per questo che preferisco impostare manualmente la magia stessa.

 
gordon:
Il problema che ho con questo approccio è che a volte ho un esperto/simbolo/timeframe identico che gira nello stesso conto. Quindi alla fine dovrei ancora cambiare qualcosa manualmente, ed è per questo che preferisco impostare manualmente la magia stessa.

E se usassimo i secondi? TimeCurrent() restituisce un numero che sarà sempre unico - beh, almeno al di fuori di quell'arco di secondi.

- Assegnate un numero ID di GlobalVariable al vostro esperto. Restituitelo con WindowExpertName().

- Concatenare quell'ID con un contatore di incremento (se si attacca lo stesso esperto) e TimeCurrent ()

- Se il numero restituito da TimeCurrent() supera la dimensione consentita. Allora scarta la quantità di anni e mesi fino ad avere il modulo di giorni, ore, minuti e secondi.

 
cameofx:

Che ne dite di usare i secondi? TimeCurrent() restituisce un numero che sarà sempre unico - beh, almeno al di fuori di quell'arco di secondi.

- Assegnate un numero ID al vostro esperto. Restituirlo con WindowExpertName().

- Concatenare quell'ID con un contatore di incremento e TimeCurrent ()

- Se il numero restituito da TimeCurrent() supera la dimensione consentita. Allora scarta la quantità di anni e mesi fino ad avere il modulo di giorni, ore, minuti e secondi.

Perché allora devi mantenere un livello di persistenza per questa magia. Cosa succede se il tuo terminale si riavvia? La magia sarebbe diversa...

 
gordon:

Perché allora devi mantenere un livello di persistenza per questa magia. Cosa succede se il tuo terminale si riavvia? La magia sarebbe diversa...

Santo cielo, hai battuto la mia velocità di editing :)). L'ho modificato. Ho dimenticato di dire che è una GlobalVariable.