创造一个神奇的数字

 
/**
* 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变体的那个(与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());
谢谢你发布的代码(和哈希文章!)。

问题 - 我正在研究一种方法,用于在同一图表上打开和关闭多个订单,同一算法,等等。

我分两步来做 -

1)生成一个基数MN(上述代码似乎就是这样做的)作为一个整数。每个图表/符号/时间框架的基数将总是相同的。
2) 为每个特定的订单生成一个以小数点表示的特定后缀,一旦一个后缀未被使用,就可以再次使用。

因此,MN将是XXXXX.YY,其中X是基数,Y是特定后缀。后缀将从0.001开始,每一次新的发送都将增加0.001。在每个订单结束时,它将分配给当前未使用的最低后缀。这样一来,我就可以通过重新生成基本的MN和循环使用后缀来重新获得MN。

似乎有点太复杂了。有什么更好的方法可以做到这一点吗?

当我完成后,我会把我的东西贴出来。
 
作为一个NuB,我不知道为什么你会想要或需要一个 "加密 "的MagicNumber?
我只是用前5个数字表示EA的版本#,后4个数字表示交易的分钟数。
 
FourX:
作为一个NuB,我不知道你为什么想要或需要一个 "加密的 "MagicNumber?
我只是用前5个数字表示EA#的版本,后4个数字表示交易的分钟数。

在你的例子中,符号()如何成为MN的一部分?你有一个EA号码和一个时间框架号码,但符号呢?

我只通过MN来识别我的订单,我在订单列表上的循环只比较OrderMagicNumber(),你的订单也必须检查符号名称。我有一些其他独立的脚本对订单列表进行处理,例如绘制EA的股权图或将交易复制到另一个平台,它们都只需要神奇的数字来识别特定EA在特定对和特定时间框架的交易。

我根本不为我的不同EA使用序列号,我为我的所有EA使用4或5个字母的短名称。例如,一个名为snowball.mq4的EA将被命名为 "snow"。这在代码中是硬性规定的,从未改变。我也使用这个简短的名字作为订单注释

所以我有3样东西:短名称、符号和时间框架。将其转换为MN的最方便方式是哈希值。我可以为我的EA提供数字,而不是名称,但仍然没有简单的方法将符号名称转换成数字。哈希值简单地一次性解决了所有这些问题。

 
FourX:
作为一个NuB,我不知道为什么你会想要或需要一个 "加密 "的MagicNumber ?
我只是用前5个数字表示EA#的版本,后4个数字表示交易的分钟数。

你还应该看到这个->https://www.mql5.com/en/forum/120034


我对这整个方法的问题是,我有时在同一个账户中运行相同的专家/符号/时间框架。所以最终我还是不得不手动改变一些东西,这就是为什么我更喜欢手动设置魔法本身。

 
gordon:
我对这一方法的问题是,我有时在同一个账户中运行相同的专家/符号/时间框架。所以最终我还是不得不手动改变一些东西,这就是为什么我更喜欢手动设置魔法本身。

那么使用秒呢?TimeCurrent()返回的数字将永远是唯一的--好吧,至少在那一秒的跨度之外。

- 为你的专家指定一个GlobalVariable ID号码。用WindowExpertName()返回它。

- 将该ID与一个增量计数器(如果你附加了同一个专家)和TimeCurrent()连接起来。

- 如果TimeCurrent()返回的数字超过允许的大小。那么就舍弃年和月的数量,直到我们有了天、小时、分钟和秒的模数。

 
cameofx:

那么使用秒呢?TimeCurrent()返回的数字将永远是唯一的--好吧,至少在那一秒的跨度之外。

- 为你的专家分配一个ID号。用WindowExpertName()返回它。

- 将这个ID与一个增量计数器和TimeCurrent()串联起来。

- 如果TimeCurrent()返回的数字超过允许的大小。那么就放弃年和月的数量,直到我们得到天、小时、分钟和秒的模数。

因为这样你就必须为这个魔法保持一个持久的水平。如果你的终端机重新启动会怎样?魔法将是不同的...

 
gordon:

因为这样你就必须为这个魔法保持一个持久的水平。如果你的终端机重新启动会怎样?魔法将是不同的...

天啊,你打败了我的编辑速度:))。我编辑了它。忘了说它是一个GlobalVariable。