Автоматическое магическое число - страница 2

 
jjc:

Я чего-то не понимаю. Если я открываю два графика, например, USDJPY H1, и добавляю экземпляр советника на каждый из них, то оба используют магическое число 9999033.

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

но тогда вы потеряете устойчивость при перезапуске и закрытии графика, и, следовательно, в результате могут или будут созданы ордера-сироты.

 
BarrowBoy:

Так является ли терминальное приложение MT "контейнером" - с одним hWnd для <всего>?

Да. Это довольно типичное MDI-приложение. Есть окно верхнего уровня, которое содержит такие вещи, как панели инструментов, панели и клиентскую область MDI. Последняя затем содержит каждый график, и каждый график фактически состоит из двух окон: контейнер с областью рисования внутри него. Каждое из этих окон имеет свой собственный хэндл hWnd. Функция WindowHandle() возвращает хэндл области рисования, и поэтому, используя вызов API GetParent() три раза, вы получите hWnd окна верхнего уровня MT4.

 

fwiw, я использую нижеприведенный вариант и никогда не имел дубликатов. Один и тот же советник на 10 графиках [любого типа].

У меня нет ответа на вопрос о том, что хэш-функции передается слишком много хлама. Я просто запихал туда все, включая кухонную раковину, т.е. я не математик..., просто долбил и долбил, пока не получил ни одного повторения - даже при запуске терминала с профилем из 10 графиков с одним и тем же советником...

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

У меня нет ответа на вопрос о том, что хэш-функции передается слишком много хлама. Я просто запихал туда все, включая кухонную раковину, т.е. я не математик..., просто долбил и долбил, пока не получил ни одного повторения - даже при запуске терминала с профилем из 10 графиков с одним и тем же советником...

Очевидно, я хотел бы иметь лучший и более описываемый/логичный метод... так что начинайте рвать его на куски :O)

Мне нравится. Особенно старый добрый хэш djb2.

 

Очень впечатляющий материал, ребята :)

Контейнеры MDI возвращают меня назад <вздох>.

Я по-прежнему считаю, что, ИМХО, магические числа слишком важны, чтобы применять их произвольно!

Я уверен, что CB подтвердит, что предсказуемое восстановление при перезагрузке является чрезвычайно важным элементом надежной системы...

FWIW

-BB-

 

С помощью этого кода советник может распознавать свои собственные ордера, если платформа выключается. Он использует глобальные переменные, поэтому если вы хотите сделать советника "невосприимчивым" к отключению ПК, его можно переписать, чтобы использовать файлы вместо глобальных переменных. Я также приложил пример, который открывает позицию в момент инициализации и закрывает ее на следующем баре, вы можете загрузить эксперта на 1M таймфрейме, выключить метатрейдер и затем открыть его снова, просто подождите следующего бара, чтобы увидеть, как советник закрывает свой ордер. Это не было доказано на нескольких графиках и не было обмануто несколькими ордерами, но что вы думаете об этом?

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);
   }
      
}
Файлы:
 
jjc wrote >>

Мне нравится. Особенно старый добрый хэш djb2.

Спасибо - но я действительно чувствую себя виноватым за такой неосведомленный бит кодирования в makeexpertid...

Пока еще рано, но, возможно, кто-то заметит недостаток(и)... если они есть.

 
BarrowBoy wrote >>

Очень впечатляющий материал, ребята :)

Контейнеры MDI возвращают меня назад <вздох>.

Я по-прежнему считаю, что, ИМХО, магические числа слишком важны, чтобы применять их произвольно!

Я уверен, что CB подтвердит, что предсказуемое восстановление при перезагрузке является чрезвычайно важным элементом надежной системы...


FWIW

-BB-

Я все еще говорю, что, ИМХО, магические числа слишком важны, чтобы применять их произвольно!

Конечно, ВВ, vip-данные. Я потратил слишком много времени, пытаясь найти уникальную точку отсчета, которую могли бы использовать несколько экземпляров советника. Эта точка отсчета должна была быть повторяемой, чтобы все открытые файлы могли быть отображены при восстановлении/перезапуске. Я хотел, чтобы любое количество экземпляров советника с одинаковыми ccy+первыми графиками могло "каким-то образом" открывать уникальное имя файла и при перезапуске волшебным образом открывать его заново...


Данные оконной ручки могут быть тем самым "фактором X"?

 
fbj:

конечно, BB, vip-датумы. Я потратил слишком много времени, пытаясь найти уникальную точку отсчета, которую могли бы использовать несколько экземпляров советника. Эта точка отсчета должна была быть повторяемой, чтобы все открытые файлы могли быть отображены при восстановлении/перезапуске. Я хотел, чтобы любое количество одинаковых экземпляров советника ccy+per chart могло "каким-то образом" открывать уникальное имя файла и при перезапуске волшебным образом открываться снова...

Я не могу понять, как это возможно без того, чтобы MT4 или пользователь назначили ID каждому советнику. Или, точнее говоря, я не вижу ничего, что не включало бы в себя что-то очень неприятное, например, генерацию уникального ID, а затем модификацию .chr файла советника, чтобы сохранить ID как часть внешних параметров советника.


И, для общего развлечения, следующий способ не продвигает обсуждение, но он заменяет входные данные для хэша djb2 значением, которое гарантированно уникально (ценой необходимости вызова DLL). Я не знаю, насколько хорошо djb2 работает с такими вещами, как GUID, но я только что попробовал сгенерировать 1,000,000 идентификаторов без каких-либо коллизий. Но это все равно не решает проблему перезагрузки.


#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 >>

Данные ручки окна могут быть тем самым "фактором X"?

Если бы вы не закрывали частично ордера, вы могли бы использовать комментарий к ордеру для хранения информации об исходной паре/таймфрейме...?

Таким образом, советник при перезапуске мог бы выяснить, были ли у него предыдущие ордера и какое магическое число он должен был использовать?

NB

Держите комментарии на уровне < 25 и проверяйте LEFT(OrderComments(), 24), иначе [sl] или [tp] могут повлиять на ситуацию.

Предполагается, что <вся история> остается доступной на вкладке "История счета"!

FWIW

-BB-

Причина обращения: