Обмен данными между двумя советниками, работающими в разных терминалах - страница 3

 

Еще можно попробовать забить гвоздь лампочкой. У некоторых получается.

А в чём кривость такого подхода ?

Еще можно через установку системного времени.

Так синхронизация по системному времени идёт :-). Не через установку, но через чтение. Такой своеобразный обмен данными.

 

Всем доброго дня!

Одним из лучших способов надежной связи терминалов представляется использование сетевой 1С.
Две основные возможности:
1. основное приложение выполняется на 1С, терминалы и их MQL4 программы являются исполнителями,
2. основное приложение выполняется на одном из терминалов, 1С приложение используется как связующий протокол.

Преимущества:
1. возможность хранить и обрабатывать полные истории котировок одновременно разных серверов;
2. возможность вести полный бухгалтерский учет сделок с возможностью сверки отчетов брокеров.

С уважением,
Ais

 
Andres >>:

Так я уже библиотеку маленькую написал, уже и советники у меня инфой во всю меняются через реестр. По факту они меняются через оперативку, никаких чтений-записей на диск не наблюдаю.


Спасибо за предоставленную библиотеку! Буду разбираться и с этой реализацией обмена тоже.

Сразу имеется один очевидный вопрос. Как у Вас реализован контроль чтения/записи параметров? То есть каким образом другой советник узнаёт о том что какой-нибудь параметр ключа уже можно считывать?

Вы создаёте какой-то дополнительный ключ разрешения чтения/записи другим советником или же имеется какая-то другая опробированная Вами возможность? То есть другими словами как обеспечить унитарный доступ к какому-либо параметру, чтобы советники не работали одновременно с одним и тем же параметром ключа во избежание сбоев?

 

Я вроде сообразил как Вы обеспечиваете унитарный доступ к параметра ключа. Вы просто производите контроль ошибок через функцию string GetErrorString( int ErrorCode).

И в случае ошибки наверное производите повторную операцию. Правда я не понял из библиотеки где эта повторная операция выполняется. Наверное нужно будет дописать то что требуется уже самому. В любом случае спасибо за красивое решение!

 

Это простая обёртка над Win API, с выводом ошибок, позволяющая работать только со строковыми параметрами ключей.

GetErrorString( int ErrorCode ) носит скорее индикативный характер, для того чтобы при возникновении ошибок знать: что, где, почему и как исправлять. Конечно можно и даже нужно вынести обработку возникающих ошибок за пределы обёрточно-библиотечных функций, и реагировать на них по разному (типов ошибок то много) уже исходя из логики использования ключей различными экспертами. А пока SetStringValue() при любой неудачной попытке способна только сказать Вам о том, что попытка не удалась. А GetStringValue() в случае неудачи, не только скажет, но и вернёт пустую строку. Думаю, что в дополнительном ключе разрешения чтения/записи нету необходимости,  так как такие проверки делает ОС. Достаточно обработки ошибок и правильного реагирования на них. Мои советники для "горячего" теста просто рассинхронизированы во времени, видимо поэтому конфликтов при одновременном чтении/записи одного поля у них не возникало. Но разумеется это не решение. Нужно двигаться дальше. Всё-таки за одну ночь написал, не судите строго. Типа "бэтта" версии, для того чтобы пощупать метод :-).

 
Andres >>:

Так я уже библиотеку маленькую написал, уже и советники у меня инфой во всю меняются через реестр. По факту они меняются через оперативку, никаких чтений-записей на диск не наблюдаю. В MSDN написано что лучше не пихать в реестр данные больше пары сотен Кб.

Билиотека настроена так что все ключи и параметры создаются во временной области реестра и не записываются в постоянный реестр. После перезагрузки этих ключей уже нету.

Одно НО - библиотека работает только со строковыми параметрами, не более 255 символов длинной (ограничение в MQL). Но этого вполне хватает. Вообще параметры в реестре могут быть разных типов, а не только строки, но пока другие типы на мой взгляд не нужны. Сейчас через реестр у меня меняются два советника, но можно и больше :-). Плюс ёщё в том, что в Win API есть возможнть подключаться к сетевому реесту. Если кому нужен обмен инфой между советниками запущенными на разных машинах в одной сети, то можно посмотреть и в этом направлении. На мой взгляд - быстро, просто и надёжно, и без всяких длл и файлов. Строку загнал - строку получил.

Андрей, спасибо!

Немного подредактировал и разукрасил под себя.

Может Вам это в копилку положить? Весьма, достойное решение!

Файлы:
reglib.rar  11 kb
 

На днях Вашу библиотеку, Андрей, интегрирую со своей библиотекой для работы с графическими переменными. Получиться ещё один уровень объявления переменных.

1. Будет GlobalSuperVariable. Такая переменная будет видна на уровне ОС.

2. Сейчас существует GlobalVariable.

3. И ещё есть глобальные графические переменные GlobalChartVariable. Они видны программам только одного окна.

Вообщем, должна получиться библиотека для работы со своими структурами на уровне ОС в MQL4.

 
Zhunko >>:

1. Будет GlobalSuperVariable. Такая переменная будет видна на уровне ОС.

Буду премного благодарен (и наверное не я один) если выложите такую переменную в кодобазу.

Устал уже изгаляться кустарными методами.

 

Вопрос Андрею. Вот это реестр перенесёт?

string GetStringValue1 (int    hKey,      // Код ключа реестра.
                        int    lpSize,    // Длина считываемой строки.
                        string ValueName) // Имя параметра ключа.
 {
  int lpType[1];      // Возвращаемый тип параметра.
  int lpcbData[1];    // Размер буфера.
  int i;              // Переменная для подрезки последних пустых строк.
  int lres;           // Результат.
  string lpData = ""; // Буфер для возвращаемой строки.
  //----
  lpcbData[0] = lpSize; // Размер буфера.
  for (i = 0; i < lpSize; i++) lpData = lpData + "#";
  lres = RegQueryValueExA (hKey, ValueName, 0, lpType, lpData, lpcbData); // вызов API
  // Теперь в lpcbData[0] размер скопированных байт. Проверяем результат.
  if (lres != ERROR_SUCCESS)
   {
    Print ("Error in RegQueryValueExA(): ", GetErrorString (lres));
    return ("");
   }
  if (lpType[0] == REG_SZ || lpType[0] == REG_EXPAND_SZ) return (StringSubstr (lpData, 0, lpcbData[0] - 1));
  return ("");
 }
 
Я объясню. Дело в том, что если вы будете в качестве буфера использовать динамически наращиваемую строку, то будут наблюдаться некоторые ошибки. Я сам натыкался на такую раньше:
InitRegDefines();
hKey = CreateKey( HKEY_CURRENT_USER, "!MT4TestKey" );

// заносим
SetStringValue( hKey, "Param", "Test" );

// вытаскиваем при помощи Вашей функции:
Print( GetStringValue1( hKey, 20, "Param" ) );

После чего получается:

2009.05.19 01:22:16 2008.12.31 01:49 temp EURUSD,M1: ####
2009.05.19 01:22:16 2008.12.31 01:49 temp EURUSD,M1: RegCreateKeyExA(): Создан не существовавший раздел.
2009.05.19 01:22:16 temp started for testing

То есть содержимое буфера не меняется, хотя ошибок при вызове не происходит. И в реестре содержится именно строка "Test"

Из сообщений на форуме, я понял, что это происходит из-за необычной передачи строк из среды MQL в функции DLL. В среде MQL разработчики оперируют строками при помощи своего собственного менеджера (строкового пула), и видимо на этой границе происходит заполнение не того буфера, и поэтому мы не можем видеть результат возвращаемый API-функцией. Но если использовать строки, инициализированные во всю максимальную длину, то, на сколько мне ясно, проблем не возникает. Именно поэтому там строка на 255 символов "#". Символ "#" был выбран просто для того чтобы строка была заметна глазу. К самим Win API это не имеет никакого отношения, так как не важно чем буфер заполнен до вызова. В этом и ограничение на длину строки о котором я говорил раньше. Вот передавать в SetStringValue() можно строки бОльшие, чем 255 символов, но прочитать их не получится.

Конечно хорошо, когда ограничений нету, но особого неудобства не вижу. Возникает вопрос: зачем Вам чтение строки заданного размера ? Если дело в ограничении, то и его можно обойти, просто написав функцию, которая при записи в реестр разбивает исходную строку на N параметров длинной по 255 + "остаточный" параметр. А при чтении - собирает обратно. По другому вроде никак. Если затрудняетесь, то обращайтесь - сделаю. Просто потребности у всех разные, всего не предусмотришь, мне хватает только этого, а кто-то использует глобальные переменные, да ёщё и на нескольких уровнях.