Лучше работать через DLL. Посмотри статью 'Автоматизированный выбор ДЦ для эффективной работы экспертов', там есть исходники и внешней программы и dll, в которых есть примеры
передачи данных.
Либо вот еще примерчик :
описание на с++ в dll __declspec(dllexport) bool __stdcall GetAction(char *isInstrument, double bid, double ask, int *action, double *lots, int *magik)
описание в mql4 bool GetAction(string isInstrument, double bid, double ask, int &action[], double &lots[], int &magik[]);
Что касается твоей dll, то возможно неправильное объявление функции в DLL.
Идея с файлом - семафором тоже вполне рабочая. Только для решения проблемы в файл надо что-то писать и программе и эксперту, выработать протокол обмена данными. Например, программа пишет в файл-семафор 1 и закрывает хэндл. Эксперт ждет 1 в семафоре, потом считывает данные из файла, записывает 0 в семафор и закрывает хэндл.
Либо вот еще примерчик :
описание на с++ в dll __declspec(dllexport) bool __stdcall GetAction(char *isInstrument, double bid, double ask, int *action, double *lots, int *magik)
описание в mql4 bool GetAction(string isInstrument, double bid, double ask, int &action[], double &lots[], int &magik[]);
Что касается твоей dll, то возможно неправильное объявление функции в DLL.
Идея с файлом - семафором тоже вполне рабочая. Только для решения проблемы в файл надо что-то писать и программе и эксперту, выработать протокол обмена данными. Например, программа пишет в файл-семафор 1 и закрывает хэндл. Эксперт ждет 1 в семафоре, потом считывает данные из файла, записывает 0 в семафор и закрывает хэндл.
polecat:
Пока единственное, что приходит в голову, это то, что программа после заполнения файла данных и его закрытия должна создать файл семафора для эксперта, а эксперт соответственно после запуска программы должен в цикле ждать появления файла семафора, и при появлении читать данные и удалять семафор. Как следствие непонятно как сказать эксперту «ждать появления файла семафора».
Пока единственное, что приходит в голову, это то, что программа после заполнения файла данных и его закрытия должна создать файл семафора для эксперта, а эксперт соответственно после запуска программы должен в цикле ждать появления файла семафора, и при появлении читать данные и удалять семафор. Как следствие непонятно как сказать эксперту «ждать появления файла семафора».
int start() { while( SemaforIsBusy() && !IsStopped() ) Sleep(100); // работа с файлом while( !SemaforOFF() && !IsStopped() ) Sleep(100); return(0); } bool SemaforIsBusy() { //---- Проверяем состояние семафора, и, если он свободен, занимаем его. //---- Открываем файл int file_handle = FileOpen( "semafor.csv", FILE_READ | FILE_WRITE | FILE_CSV ), _GetLastError; //---- Если произошла ошибка, if ( file_handle < 0 ) { //---- Выводим сообщение и выходим _GetLastError = GetLastError(); Print( "SemaforIsBusy: FileOpen error #", _GetLastError ); return(true); } //---- Если размер файла больше 10 байт, значит семафор занят if ( FileSize( file_handle ) > 10 ) { FileClose( file_handle ); return(true); } //---- Записываем в файл фразу "семафор занят!" //---- Если возникла ошибка, if ( FileWrite( file_handle, "семафор занят!" ) < 0 ) { //---- Выводим сообщение, закрываем файл и выходим _GetLastError = GetLastError(); Print( "SemaforIsBusy: FileWrite error #", _GetLastError ); FileClose( file_handle ); return(true); } //---- Закрываем файл FileClose( file_handle ); return(false); } bool SemaforOFF() { //---- Обнуляем файл-семафор готовности //---- Открываем файл только для записи (содержимое файла теряется) int file_handle = FileOpen( "semafor.csv", FILE_WRITE | FILE_CSV ), _GetLastError; //---- Если произошла ошибка, if ( file_handle < 0 ) { //---- Выводим сообщение и выходим _GetLastError = GetLastError(); Print( "SemaforOFF: FileOpen error #", _GetLastError ); return(false); } //---- Закрываем файл FileClose( file_handle ); return(true); }
polecat:
и непонятно как заставить эксперта подождать не только появления файла данных, но и его корректного заполнения.
и непонятно как заставить эксперта подождать не только появления файла данных, но и его корректного заполнения.
Я делаю это в два прохода, сохраняя коллекцию имён найденных файлов и их размеров в байтах. Если файл найден первый раз, он запоминается в коллекции со своим размером. Если найден, и он уже есть в коллекции, то это его второй (третий, 4-й, ..) мониторинг. Если размер в байтах совпадает, то запись в файл завершена, и он готов к обработке, иначе ждать неизменного размера (можно и дату LastUpdated мониторить).
Спасибо большое за советы, буду разбираться!
polecat:
и непонятно как заставить эксперта подождать не только появления файла данных, но и его корректного заполнения.
пишите в первой строке файла метку начала, а в последней строке
метку конца файла. Читая метки, делаете вывод о корректной заполненности
файла.
и непонятно как заставить эксперта подождать не только появления файла данных, но и его корректного заполнения.
У меня были друлие проблермы с dll: в dll использовался managed code, и
dllне освобождала память после вызова в МТ. Следовательно, после
некоторого времени работы сьедалась вся память в компютере.
Я решил проблему таким образом, что я написал простенькую, НЕ managed, dll, которая:
По пункту 1:
а) Для создания файла я использовал функцию GetTempFileName, так как песочница МТ не очень удобна в связи с изменяющимися путями в модусе тестирования и работы
б) Явное обьявление locale в dll и внешней программе, у меня были проблемы при читании double в managed и unmanaged: setlocale( LC_NUMERIC, "en_US" );
По пункту 3:
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
Замечания:
а) не забудьте стереть temp-файл после использования
б) можете использовать RAM-диск для повышения быстродействия. Значение системной переменной %TEMP% должно тогда показывать на RAM-диск.
Удачи!
- пишет данные в файл
- формирует коммандную строку
- запускает внешнюю программу и ждет ее завершения
По пункту 1:
а) Для создания файла я использовал функцию GetTempFileName, так как песочница МТ не очень удобна в связи с изменяющимися путями в модусе тестирования и работы
б) Явное обьявление locale в dll и внешней программе, у меня были проблемы при читании double в managed и unmanaged: setlocale( LC_NUMERIC, "en_US" );
По пункту 3:
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
Замечания:
а) не забудьте стереть temp-файл после использования
б) можете использовать RAM-диск для повышения быстродействия. Значение системной переменной %TEMP% должно тогда показывать на RAM-диск.
Удачи!
Огромное спасибо всем за советы. С DLL конечно более красивый
подход, но за неимением времени на разбирательства сделал таким
образом: Эксперт запускает программу, и ждёт появления файла
семафора. Программа сначала пишет данные в файл, затем когда
закрывает его, создаёт файл семафора. Эксперт, дождавшись семафора,
удалят его, и спокойно читает данные.
Это дело реализовал так:
Где функции FileExists и DataReady имеют следующую реализацию:
Это дело реализовал так:
//Удаляем файл семафора, если он есть if (FileExists(SemaFile)) {FileDelete(SemaFile);} //Запускаем программу WinExec(PredProg, 0); //Ждём появления семафора while (!DataReady()) { Sleep(WaitLimit); } //Получаем данные из программы ReadDataFile();
Где функции FileExists и DataReady имеют следующую реализацию:
//Проверяет существование файла FileName bool FileExists(string FileName) { handle = FileOpen(FileName, FILE_CSV|FILE_READ, FileDelimiter); if (handle >= 1) { FileClose(handle); return(true); } else { return(false); } } //Проверяем выставлен ли семафор о том, что можно принять данные bool DataReady() { if (FileExists(SemaFile)) { FileDelete(SemaFile); return(true); } else { return(false); } }
olexij:
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
Сначала хотел сделать именно так, без использования семафоров,
но угробив день на разбирательства так и не понял как это можно
сделать в MQL. :( Примеров действительно много... буду разбираться.
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
polecat:
В MQL вы делаете только вызов вашей dll. В дистрибуции МТ есть пример,
как это сделать. Остальное - создание файлов, вызов программы
и т.д. делается вашей dll средствами среды программирования. Вот
вам кусочек кода, как я сам делаю, VC++:olexij:
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
Сначала хотел сделать именно так, без использования семафоров,
но угробив день на разбирательства так и не понял как это можно
сделать в MQL. :( Примеров действительно много... буду разбираться.
Дла запуска и ожидания завершения используйте CreateProcess и WaitForSingleObject. В интернете полно информации и примеров как ими пользоваться.
MT4_EXPFUNC int __stdcall Recommendation(const RateInfo rates[], const int numberRates /*, ваши параметри */) { int recommendation = RECOMMENDED_NOACTION; STARTUPINFO si; memset(&si, 0, sizeof(si)); si.cb=sizeof(si); // Do not show the window si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = SW_HIDE; // open pipe SECURITY_ATTRIBUTES sa; sa.nLength=sizeof(SECURITY_ATTRIBUTES); sa.bInheritHandle=TRUE; sa.lpSecurityDescriptor=NULL; HANDLE readPipe, writePipe; char szCommandLine[BUFSIZE]; // set US locale char *locale = setlocale( LC_NUMERIC, "en_US" ); // ваш код создания командной строки и записи файла .... if(!CreatePipe(&readPipe, &writePipe, &sa, 0)) { MessageBox(NULL, "Unable to create input/output pipes", "Your program name", NULL); } else { si.dwFlags|=STARTF_USESTDHANDLES; si.hStdOutput=writePipe; si.hStdInput=readPipe; si.hStdError=writePipe; PROCESS_INFORMATION pi; // start prozess if(!CreateProcess(0, szCommandLine, 0, 0, TRUE, 0, 0, 0, &si, &pi )) { MessageBox(NULL, "Unable to start child process", "Your program name", NULL); } else { if (WaitForSingleObject(pi.hProcess, WAITING_TIMEOUT) != WAIT_FAILED) { DWORD exitCode; GetExitCodeProcess(pi.hProcess, &exitCode); DWORD NumberOfBytesRead; char buffer[BUFSIZE]; std::string output; while(ReadFile(readPipe, buffer, BUFSIZE, &NumberOfBytesRead, 0)) { buffer[NumberOfBytesRead]=0; output+=buffer; if(NumberOfBytesRead!=BUFSIZE) break; } if(exitCode == 0) { // parse output on success recommendation = atol(buffer); } else { // processing error, ignore output } CloseHandle (pi.hThread); CloseHandle (pi.hProcess); } } CloseHandle(writePipe); CloseHandle(readPipe); } return recommendation; }Моя внешняя программа пишет рекомендацию как целоe число на stdout, вариаций может быть много. Если будете делать в VS, не забудьте отключить поддержку managed code.
Что еще можна усовершенствовать? Например передачу данных через stdin программы. Или еще лучше - работать с веб-сервисом...
Вы упускаете торговые возможности:
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Регистрация
Вход
Вы принимаете политику сайта и условия использования
Если у вас нет учетной записи, зарегистрируйтесь
С DLL решил завязать т. к. моя программа вызывает ещё 3 другие DLL, работает с внешними файлами и вообще неизвестно как там с путями всё сделать. Решил попробовать такой подход:
- Эксперт запускает exe-программу (с помощью WinExec).
- Программа выполняется и создаёт файл с передаваемыми данными.
- Эксперт читает файл с данными.
Проблема в том, что программа выполняется несколько секунд, и непонятно как заставить эксперта подождать не только появления файла данных, но и его корректного заполнения. Пока единственное, что приходит в голову, это то, что программа после заполнения файла данных и его закрытия должна создать файл семафора для эксперта, а эксперт соответственно после запуска программы должен в цикле ждать появления файла семафора, и при появлении читать данные и удалять семафор. Как следствие непонятно как сказать эксперту «ждать появления файла семафора».Я новичок в MQL, посоветуйте, пожалуйста, правильно ли я иду или же есть более грамотные решения для передачи нескольких переменных из своей программы эксперту?
P. S. С DLL указатель на массив пытался получить так: