создание магического числа

 
/**
* 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:
[ ... хэш-функция ... ]

Для справки, fbj однажды сделал нечто подобное, используя известную хэш-функцию djb2: https://www.mql5.com/en/forum/120034/page2

 
Изначально меня вдохновил этот http://www.cs.hmc.edu/~geoff/classes/hmc.cs070.200101/homework10/hashfuncs.html, особенно тот, что помечен как CRC variant (который очень похож на djb2). Этот хэш, хотя я и не смог легко получить коллизии, не дал мне достаточно уверенности, иногда только очень немногие биты отличались между хэшами двух похожих строк. Поэтому я создал три его варианта с разным поворотом h и сложил все три подхэша вместе. Если один из них столкнется, то останутся еще два, вычисленные совершенно другим способом. Теперь каждый измененный бит во входной строке изменяет более половины всех битов в хэше, и все биты выглядят совершенно случайными.


djb2, упомянутый в вашей ссылке выше, может быть написан без всех этих сотен строк вокруг него просто как:
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:
djb2, упомянутый в вашей ссылке выше, может быть написан без всех этих сотен строк вокруг него просто как: [...]

Я не специалист по хэш-алгоритмам, не говоря уже о djb2 в частности, но я, кажется, помню, что инициализация хэш-значения (переменная h в вашей версии) в 5381 считается значимой, хотя никто точно не знает, почему.

 
*    magic = makeMagicNumber(name+ Symbol() + Period());
Не хочу придираться, но вы должны иметь возможность использовать и это:
*    magic = makeMagicNumber(WindowExpertName() + Symbol() + Period());
Спасибо, что опубликовали код (и хэш-статью!).

Вопрос - Я работаю над методом открытия и закрытия нескольких ордеров на одном и том же графике, по одному и тому же алгоритму и т.д.

Я подхожу к этому в 2 этапа.

1) генерирование базового MN (это то, что делает вышеприведенный код) в виде целого числа. База всегда будет одинаковой для каждого графика/символа/таймфрейма
2) генерирование определенного суффикса, выраженного в виде десятичной точки для каждого конкретного ордера, после того, как суффикс становится неиспользуемым, он снова становится доступным.

Таким образом, MN будет XXXXXX.YYY, где X - база, а Y - специфический суффикс. Суффиксы начинаются с .001 и увеличиваются на .001 для каждого нового отправления. При каждом отправлении он будет присваивать самый низкий неиспользуемый в данный момент суффикс. Таким образом, я могу получить MN позже, регенерируя базовый MN и перебирая суффиксы.

Это кажется немного слишком сложным. Есть ли лучший способ сделать это?

Я опубликую то, что у меня получилось, когда все будет готово.
 
Как NuB, я не понимаю, зачем вам нужен "зашифрованный" MagicNumber?
Я просто использую первые 5 цифр для версии советника # и последние 4 для количества минут, на которых он торгуется.
 
FourX:
Я не совсем понимаю, зачем вам нужен "зашифрованный" MagicNumber?
Я просто использую первые 5 цифр для версии советника # и последние 4 для количества минут, на которых он торгуется.

Как в вашем примере Symbol() станет частью MN? У вас есть номер эксперта и номер таймфрейма, но как насчет символа?

Я идентифицирую свои ордера только по MN, мои циклы по списку ордеров сравнивают только OrderMagicNumber(), ваш должен был бы проверять и имя символа. У меня есть еще несколько независимых скриптов, которые делают что-то со списком ордеров, например, строят графики эквити советников или копируют сделки на другую платформу, им всем нужен только магический номер для идентификации сделок конкретного советника на конкретной паре и конкретном таймфрейме.

Я вообще не использую серийные номера для своих советников, я использую короткие имена из 4-5 букв для всех своих советников. Например, советник с именем snowball.mq4 получит имя "snow". Это жестко заложено в коде и никогда не меняется. Я использую это короткое имя и для комментариев к ордерам.

Итак, у меня есть 3 вещи: короткое имя, символ и таймфрейм. Самый удобный способ преобразовать это в MN - хэш. Я мог бы давать своим советникам номера вместо имен, но все равно не было бы простого способа преобразовать имя символа в число. Хэш просто решает все эти проблемы сразу.

 
FourX:
Как NuB, я не понимаю, зачем вам нужен "зашифрованный" MagicNumber?
Я просто использую первые 5 цифр для версии советника # и последние 4 для количества минут, на которых он торгуется.

Вы также должны увидеть это -> https://www.mql5.com/en/forum/120034


Проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что у меня иногда есть идентичные эксперты/символы/таймфреймы, работающие на одном счете. В итоге мне все равно придется что-то менять вручную, поэтому я предпочитаю просто установить магию вручную.

 
gordon:
Проблема, с которой я сталкиваюсь при таком подходе, заключается в том, что у меня иногда есть идентичные эксперты/символы/таймфреймы, работающие на одном счете. В итоге мне все равно придется что-то менять вручную, поэтому я предпочитаю просто установить магию вручную.

Как насчет использования секунд? TimeCurrent() возвращает число, которое всегда будет уникальным - ну, по крайней мере, за пределами этого промежутка секунд...

- Назначьте идентификационный номер GlobalVariable для вашего эксперта. Верните его с помощью функции WindowExpertName().

- Объедините этот ID со счетчиком инкремента (если вы прикрепляете одного и того же эксперта) и TimeCurrent()

- Если число, возвращаемое TimeCurrent(), превышает допустимый размер. Тогда отбрасываем количество лет и месяцев, пока не получим модуль дней, часов, минут и секунд.

 
cameofx:

Как насчет использования секунд? TimeCurrent() возвращает число, которое всегда будет уникальным - ну, по крайней мере, за пределами этого промежутка секунд...

- Присвойте ID номер для вашего эксперта. Верните его с помощью WindowExpertName().

- Объедините этот ID со счетчиком инкремента и TimeCurrent().

- Если число, возвращенное функцией TimeCurrent(), превышает допустимый размер. Тогда отбросьте количество лет и месяцев, пока у нас не будет модуля дней, часов, минут и секунд.

Потому что тогда вам придется поддерживать уровень постоянства для этой магии. Что произойдет, если ваш терминал перезагрузится? Магия будет другой...

 
gordon:

Потому что тогда вам придется поддерживать уровень постоянства для этой магии. Что произойдет, если ваш терминал перезагрузится? Магия будет другой...

Боже, вы превзошли мою скорость редактирования :)). Я отредактировал. Забыл упомянуть, что это GlobalVariable.
Причина обращения: