English 中文 Español Deutsch 日本語 Português
Взаимодействие между MetaTrader 4 и Matlab посредством CSV-файлов

Взаимодействие между MetaTrader 4 и Matlab посредством CSV-файлов

MetaTrader 4Примеры | 6 июля 2007, 08:19
4 211 19
Dmitriy
Dmitriy

Введение

Известно, что вычислительные способности инженерной системы Matlab существенно превосходят возможности любого языка программирования, в том числе и MQL. Богатство математических функций, предоставляемых Matlab, позволяет выполнять сложнейшие вычисления, нисколько не заботясь о теоретической базе выполняемых операций.

Однако взаимодействие между торговым терминалом и Matlab в реальном времени представляет собой нетривиальную задачу. В этой статье я предлагаю вариант организации обмена данными между MetaTrader 4 и Matlab посредством CSV-файлов.


1. Организация взаимодействия

Предположим, что с приходом каждого нового бара MetaTrader 4 должен отправить данные о последних 100 барах в Matlab и принять в ответ результат их обработки.

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

MetaTrader 4 должен формировать свой файл с данными с приходом каждого нового бара. Чтение результата нужно пытаться осуществлять на каждом тике. Чтобы не прочитать результат раньше, чем его обновит Matlab, удалим файл с результатом ещё до того, как сформировали свой выходной файл. В этом случае попытка чтения удастся, только когда Matlab закончит свои вычисления и сформирует новый файл.

Matlab раз в секунду должен анализировать атрибуты файла, созданного MetaTrader 4, и при изменении времени его создания запускать процесс обработки. По окончании обработки пересоздаётся файл, удалённый MetaTrader 4 до начала записи данных. MetaTrader 4 его благополучно удаляет, выкладывает новые данные и ждёт ответа.


2. Формирование файла выходных данных

Сохранению данных в файл посвящено немало статей, поэтому не будем подробно останавливаться на этом. Скажем только, что данные будем записывать в 7 столбцов: “DATE”, “TIME”, “HI”, “LOW”, “CLOSE”, “OPEN”, “VOLUME”. Разделяющий символ -- “;”. Очерёдность баров -- от раннего к позднему, т.е. последней должна быть записана строка с характеристиками нулевого бара. Файл снабдим заголовком, содержащим наименования столбцов. Имя файла сформируем из имени инструмента и таймфрейма.

#property indicator_chart_window
extern int length = 100;   // Количество баров, отправляемых на обработку
double ExtMap[];           // Буфер графика
string nameData;
int init()
{
   nameData = Symbol()+".txt";         // имя отправляемого файла данных
   return(0);
}
int start()
{
   static int old_bars = 0;   // запомним число известных баров   
   if (old_bars != Bars)      // если получен новый бар 
   {
      write_data();                             // записать файл данных                              
   }      
   old_bars = Bars;              // запомним, сколько баров известно
   return(0);
}
//+------------------------------------------------------------------+
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Не удалось создать "+nameData+". Ошибка #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // заголовок
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // заголовок
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("Файл "+nameData+" создан. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

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


3. Создание пользовательского интерфейса (GUI)

Итак, файл создан. Теперь запускаем Matlab.

Мы должны будем разработать приложение, читающее текстовые данные из файла, совершающее обработку и записывающее результаты в другой файл. Нам потребуется создать пользовательский интерфейс для указания имени файла, просмотра графиков и запуска обработки. Приступим.

Для создания пользовательского интерфейса запустим мастер “GUIDE Quick Start”, набрав команду “guide” в консоли или нажав кнопку на главной панели Matlab. В открывшемся диалоге выберем “Create New GUI” --> “Blank GUI (Default)”. Перед нами интерфейс создания GUI с пустым бланком. Разместим на пустом бланке следующие объекты: “Edit Text”, “Push Button”, “Static Text”, “Axes”, "Push Button". В результате должно получиться примерно как у меня.

Теперь мы должны вызвать редактор свойств каждого объекта двойным щелчком по объекту и установить свойства объектов следующим образом:

Static Text : HorizontalAlignment – left, Tag – textInfo, String - Info.
Edit Text: HorizontalAlignment – left, Tag – editPath, String – Path select .
Push Button: Tag – pushBrowse, String – Browse.
Axes: Box – on, FontName – MS Sans Serif, FontSize – 8, Tag - axesChart.
Push Button: Tag – pushSrart, String – Start.

Изменением свойства Tag мы выбираем уникальное имя для каждого объекта. Изменением других – меняем внешний вид.

Когда всё готово, запустим интерфейс нажатием кнопки “Run”, утвердительно ответим на вопрос о сохранении файла интерфейса и M-файла, зададим имя (к примеру “FromTo”) и нажмём “Сохранить”. После этого GUI будет запущен и приобретёт тот вид, который будет иметь при работе. При этом Matlab генерирует M-файл, являющийся основой нашей будущей программы, и открывает его во встроенном текстовом редакторе.

Если внешний вид Вас не устраивает, закройте работающий GUI и скорректируйте положения объектов с помощью редактора. Мой дистрибутив, к примеру, некорректно отображал шрифт MS Sans Serif. Пришлось изменять на просто “Sans Serif”.


4. Программирование пользовательского интерфейса

Поведение интерфейса программируется в M-file Editor на языке Matlab. Сгенерированная Matlabом заготовка представляет собой список функций, вызываемых при работе пользователя с объектами интерфейса. Функции пустые, поэтому GUI пока ничего не делает. Наша задача - наполнить функции требуемым содержимым.


4.1 Программирование кнопки Browse

В первую очередь нам требуется получить доступ к файлу, сгенерированному MetaTrader 4, поэтому начнём с функции, вызываемой при нажатии кнопки “Browse”.

Имя функции, вызываемой при нажатии кнопки, состоит из имени кнопки (задается свойством “Tag”)и постфикса "_Callback". Найдём функцию “pushBrowse_Callback” в тексте файла или нажмём кнопку “Show Functions” на панели инструментов и выберем “pushBrowse_Callback” из списка.

Синтаксис языка программирования Matlab отличается от привычных правил написания на языке С и им подобных. В частности, не требуется обозначать тело функции фигурными скобками и указывать тип передаваемых в функцию данных, нумерация элементов массива (вектора) начинается с единицы, а символ комментирования – “%”. Так что, весь этот зелёный текст – не программа, а комментарий, оставленный разработчиками Matlab, чтобы нам было проще разобраться в ситуации.

Нам потребуется создать диалог для указания полного имени файла. Воспользуемся функцией “uigetfile” для этого:

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
[fileName, filePath] = uigetfile('*.txt'); % получить имя и путь от юзера
if fileName==0          % если нажата отмена
    fileName='';        % создать пустое имя
    filePath='';        % создать пстой путь
end
fullname = [filePath fileName] % сформировать полное имя
set(handles.editPath,'String', fullname); % вписать в editPath

“handles” здесь – структура, хранящая дескрипторы всех объектов нашего GUI, в том числе и формы, на которой мы их разместили. Эта структура передаётся из функции в функцию и позволяет осуществлять доступ к объектам;
“hObject” – дескриптор объекта, вызвавшего функцию;
“set” – устанавливает свойство объекта в некоторое значение и имеет синтаксис: set(дескриптор_объекта, имя_свойства_объекта, значение_свойства).

Узнать значение свойств объекта можно, используя функцию: значение_свойства = get(дескриптор_объекта, имя_свойства_объекта).
Только не забывайте, что имя – значение типа string, поэтому заключается в одинарные кавычки.

И последнее об объектах и свойствах. Форма, на которой мы разместили элементы GUI, сама является объектом, размещённым в объекте “root” (является его потомком). Она также имеет набор свойств, доступных к изменению. Просмотреть свойства можно с помощью инструмента “Object Editor”, вызываемого с главной панели редактора интерфейса. Объект “root”, как следует из названия, является корнем иерархии графических объектов и предков не имеет.

Теперь проверим, что у нас получилось. Запустим наш GUI, нажав кнопку Run на главной панели М-file Editor, попробуем кликнуть на Browse и выбрать наш файл. Получилось? Тогда закроем работающий GUI и двинемся дальше.


4.2 Программирование кнопки Start, отрисовка графика


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

Сначала создадим саму функцию. В качестве входных данных нам понадобится структура дескрипторов объектов handles. Имея доступ к объектам, мы сможем читать и устанавливать их свойства.

% чтение данных, построение графиков, обработка, сохранение
function process(handles)
fullname = get(handles.editPath, 'String'); % прочитать имя из editPath
data = dlmread(fullname, ';', 2, 2);    % прочитать матрицу из файла
info = ['Last update: ' datestr(now)];  % сформировать информационное сообщение
set(handles.textInfo, 'String',info);   % вписать info в информационную строку
 
high = data(:,1);   % в high теперь первый столбец матрицы data
low = data(:,2);    % d low -- второй
close = data(:,3);  % --/--
open = data(:,4);   %
len = length(open); % количество элементов в open
 
axes(handles.axesChart); % сделать оси текущими
hold off; % очищать оси перед добалением нового графика
candle(high, low, close, open); % нарисовать "свечной" график (в текущих осях)
set(handles.axesChart,'XLim',[1 len]); % установить пределы отображения на графике

В качестве пояснения:

“dlmread” - читает данные из текстового файла с разделителями и имеет синтаксис: dlmread(полное_имя_файла, разделитель, пропустить_строк, пропустить_столбцов);
“length(qqq)” – наибольший размер матрицы qqq.
”now” –текущие время и дата
“datestr(now)” – преобразует время и дату в текстовый вид.
А вообще, в Matlab просто огромный help с теорией и примерами.

Разместим нашу функцию в самом конце программы (там её будет легче найти), а в “pushStart_Callback” добавим её вызов:

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
process(handles);

Запускаем кнопкой “Run”, выбираем файл, нажимаем "Start" и любуемся результатом.


4.3 Сохранение пути к файлу

Всё бы хорошо, только щёлкать мышкой, выбирая файл после нажатия “Browse”, надоело. Попробуем сохранить однажды выбранный путь в файл.
Начнём с чтения. Имя файла, хранящего путь, будет состоять из имени GUI и постфикса “_saveparam” и иметь расширение “.mat”.
Функция “FromTo_OpeningFcn” выполняется непосредственно после создания формы с GUI. Добавим в неё попытку чтения пути из файла. Если попытка не удастся, используем значениe “по умолчанию”.

% --- Executes just before FromTo is made visible.
function FromTo_OpeningFcn(hObject, eventdata, handles, varargin)
guiName = get(handles.figure1, 'Name'); % получить имя нашего GUI
name = [guiName '_saveparam.mat']       % определить имя файла
h=fopen(name);                          % попытаться открыть файл
if h==-1                                % если файл не открывается
    path='D:\';                         % значение по умолчанию
else
    load(name);                         % прочитать файл    
    fclose(h);                          % закрыть файл
end
set(handles.editPath,'String', path);   % вписать имя в объект "editPath"

Остальные строки функции “FromTo_OpeningFcn” оставим без изменений.


Функцию “pushBrowse_Callback” изменим следующим образом:

% --- Executes on button press in pushBrowse.
function pushBrowse_Callback(hObject, eventdata, handles)
path = get(handles.editPath,'String'); % прочитать путь из объекта editPath 
[partPath, partName, partExt] = fileparts(path);    % разбить путь на части
template = [partPath '\*.txt'];                     % создать шаблон из частей
[userName, userPath] = uigetfile(template);         % получить имя и путь от юзера
if userName~=0                                      % если не нажали отмена        
    path = [userPath userName];                     % собрать путь
end
set(handles.editPath,'String', path);               % вписать путь в объект "editPath"
guiName = get(handles.figure1, 'Name');             % узнать имя нашего GUI
save([guiName '_saveparam.mat'], 'path');           % сохранить путь

4.4 Обработка данных

В качестве примера обработки выполним интерполяцию столбца “OPEN” полиномиальной функцией 4-ого порядка.
Добавим в конец нашей функции “process” следующий код:

fitPoly2 = fit((1:len)',open,'poly4'); % получить формулу полинома
fresult = fitPoly2(1:len); % вычислить значения Y для X=(от 1 до len)
hold on; % новый график добавится к старому
stairs(fresult,'r'); % plot ступеньками цветом - 'r'- red


Попробуем запустить и нажать “Start”.


Если вы получили примерно то же, что и я, то самое время переходить к сохранению данных в файл.


4.5 Сохранение данных в файл

Сохранение данных выполняется не сложнее, чем чтение. Единственная тонкость в том, что отсчёты вектора “fresult” нужно записать в обратном порядке. Т.е. от последнего к первому. Это делается для того, чтобы было проще прочитать файл из MetaTrader 4 – начиная с нулевого бара и пока не кончится файл.

Дополним функцию “process” следующим кодом:

[pathstr,name,ext,versn] = fileparts(fullname); % разобрать полное имя
                                                % файла на части
newName = [pathstr '\' name '_result' ext];     % собрать новое имя файла
fresult = flipud(fresult);  % перевернуть вектор fresult
dlmwrite(newName, fresult);    % записать в файл

Теперь убедитесь, что файл с результатом создан, располагается там же, где исходный и имеет то же имя, но дополненное постфиксом “_result”.


4.6 Управление таймером

Это самая сложная часть работы. Нам потребуется создать таймер, который раз в секунду проверял бы время создания файла, сформированного MT4. Если время изменилось, должна быть запущена функция “process”. Пуск-останов таймера будем осуществлять кнопкой “Start”. При открытии GUI все ранее созданные таймеры удалим.

Создадим таймер, разместив внутри функции “FromTo_OpeningFcn” следующий код:

timers = timerfind; % найти таймеры
if ~isempty(timers) % если есть таймеры
    delete(timers); % удалить все  таймеры
end
handles.t = timer('TimerFcn',{@checktime, handles},'ExecutionMode','fixedRate','Period',1.0,'UserData', 'NONE');

Код нужно разместить сразу за нашей предыдущей вставкой в эту функцию. Т.е. перед строками “handles.output = hObject;” и “guidata(hObject, handles);”

Выполняя этот код, Matlab сразу после создания GUI проверит наличие таймеров, удалит существующие и создаст новый таймер. Каждую секунду таймер будет вызывать функцию “checktime” и передавать ей список дескрипторов “handles”. Кроме “handles” таймер передаст в функцию свой дескриптор и структуру, которая содержит время и причину вызова. На это мы повлиять не можем, но должны учесть, при написании вызываемой таймером функции.

Саму функцию разместите, где Вам заблагорассудится. Пусть она пока пишет в информационную строку Matlaba время своего вызова:

% функция, вызаваемая таймером
function checktime(obj, event, handles)
set(handles.textInfo,'String',datestr(now));

При создании таймер находится в остановленном состоянии и теперь его нужно запустить. Найдём функцию “pushStart_Callback” . Закомментируем размещённый в ней вызов 'process(handles)” и впишем управление таймером:

% --- Executes on button press in pushStart.
function pushStart_Callback(hObject, eventdata, handles)
% process(handles);
statusT = get(handles.t, 'Running'); % Узнать состояние таймера
if strcmp(statusT,'on')     % Если включен - 
    stop(handles.t);        % выключить
    set(hObject,'ForegroundColor','b'); % изменить цвет надписи на pushStart
    set(hObject,'String',['Start' datestr(now)]); % изменить надпись на кнопке
end     
if strcmp(statusT,'off')    % Если выключен - 
    start(handles.t);       % включить
    set(hObject,'ForegroundColor','r');% изменить цвет надписи на pushStart
    set(hObject,'String',['Stop' datestr(now)]); % изменить надпись на кнопке
end 

Теперь проверим, как всё работает. Кнопкой “Start” попробуем запустить и выключить таймер. При включенном таймере часы над полем ввода пути должны идти.

Вообще-то, правильнее будет удалять таймер при закрытии GUI кнопкой “Х”. Если вы хотите так сделать, добавьте

stop(handles.t) ; % остановить таймер
delete(handles.t); % удалить таймер

в начало функции “figure1_CloseRequestFcn”. Эта функция будет вызвана при закрытии GUI. Доступ к ней можно получить из редактора GUI:

Но учтите, теперь, если вы нажмёте кнопку “Run” редактора, не закрыв работающий GUI, старый таймер не будет удалён, но новый будет создан. Следующий раз – ещё один. Бороться с неупокоенными таймерами можно командой “delete(timerfind)” с консоли Matlab.


Теперь, если всё работает, пишем функцию проверки времени последнего изменения файла от MetaTrader 4:

% функция, вызываемая таймером
function checktime(obj, event, handles)
filename = get(handles.editPath, 'String'); % узнать имя файла 
fileInfo = dir(filename);        % получить информацию о файле
oldTime = get(obj, 'UserData');  % вспомнить время
if ~strcmp(fileInfo.date, oldTime) % если время изменилось
    process(handles);
end
set(obj,'UserData',fileInfo.date); % запомнить время
set(handles.pushStart,'String',['Stop ' datestr(now)]); % переписать время

Функция "dir(полное_имя_файла)" возвращает структуру, содержащую информацию о файле (name, date, bytes, isdir). Информацию о прошлом времени создания файла будем хранить в свойстве "Userdata" объекта таймер. Его дескриптор передаётся в функцию "checktime" под именем obj.

Теперь при изменении файла, созданного MetaTrader 4, наша программа будет переписывать результат. Проверить это можно, изменяя файл вручную (например, удаляя последние строки) и отслеживая изменения на графике или в файле результата. Кнопка "Start" при этом, естественно, должна быть нажата.

Если при работе программы создаётся ещё одно окно с копией графика, впишите в самое начало функции "process" следующую строку:

set(handles.figure1,'HandleVisibility','on');


5. Отрисовка результата в MetaTrader 4

Вернёмся к MetaTrader 4. Нам необходимо дополнить наш индикатор функцией чтения результата из файла и отображения его на графике. Поведение программы опишем следующим образом:

1. Если получен новый бар: Удалить старый файл результата, Стереть график, Записать файл данных.
2. Если файл результата читается: Прочитать файл, Нарисовать график, Удалить файл результата.

Я не буду описывать работу нижеприведённого кода, поскольку о чтении данных из файла и рисовании индикаторов можно прочесть в других статьях. Предупрежу только, что файл результата здесь удаляется сразу после того, как он был перенесён на график. Поэтому не пугайтесь, если увидите сообщение о множестве провалившихся попыток чтения.

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

#property indicator_chart_window
#property indicator_buffers 1
#property indicator_width1 2
#property indicator_color1 Tomato
extern int length = 100;   // Количество баров, отправляемых на обработку
double ExtMap[];           // Буфер графика
string nameData;
string nameResult;

int init()
{
   nameData = Symbol()+".txt";         // имя отправляемого файла данных
   nameResult = Symbol()+"_result.txt";// имя принимаемого файла  с результатом
   SetIndexStyle(0, DRAW_LINE);
   SetIndexBuffer(0, ExtMap);
   return(0);
}
int deinit()
  {
   Comment("");
   return(0);
  }
int start()
{
   static int attempt = 0;    // число попыток чтения результата
   static int old_bars = 0;   // запомним число известных баров
   
   if (old_bars != Bars)      // если получен новый бар 
   {
      FileDelete(nameResult);                   // удалить файл результата
      ArrayInitialize( ExtMap, EMPTY_VALUE);    // очистить график
      write_data();                             // записать файл данных
      
      old_bars = Bars; return(0);               // больше ничего в этот раз не делать                           
   }
   //
   int handle_read = FileOpen(nameResult,
                              FILE_CSV|FILE_READ,
                              ';'); // попытаться открыть файл с результатом
   attempt++;                       // посчитать попытку открытия
   
   if(handle_read >= 0)             // если файл окрылся для чтения
   { 
      Comment(nameResult+". Открылся с попытки #"+ attempt); // отчёт об открытии
      read_n_draw(handle_read);  // прочитать результат и нарисовать график
      FileClose(handle_read);    // закрыть файл
      FileDelete(nameResult);    // удалить файл результата
      attempt=0;                 // обнулить количество попыток чтения
   }
   else                          // если не можем открыть файл результата
   {
      Comment( "Не удалось прочитать "+nameResult+
               ". Попыток: "+attempt+
               ". Ошибка #"+GetLastError()); //Отчёт о невозможности прочитать
   }
   old_bars = Bars;              // запомним, сколько баров известно
   return(0);
}
//+------------------------------------------------------------------+
void read_n_draw(int handle_read)
{
   int i=0;
   while ( !FileIsEnding(handle_read)) 
   {
      ExtMap[i] = FileReadNumber(handle_read);
      i++;     
   }
   ExtMap[i-1] = EMPTY_VALUE;
}

 
void write_data()
{
  int handle;
  handle = FileOpen(nameData, FILE_CSV|FILE_WRITE,';');
  if(handle < 1)
  {
    Comment("Не удалось создать "+nameData+". Ошибка #", GetLastError());
    return(0);
  }
  FileWrite(handle, ServerAddress(), Symbol(), Period());                  // заголовок
  FileWrite(handle, "DATE","TIME","HIGH","LOW","CLOSE","OPEN","VOLUME");   // заголовок
  int i;
  for (i=length-1; i>=0; i--)
  {
    FileWrite(handle, TimeToStr(Time[i], TIME_DATE), TimeToStr(Time[i], TIME_SECONDS),
                      High[i], Low[i], Close[i], Open[i], Volume[i]);
  }
  FileClose(handle);
  Comment("Файл "+nameData+" создан. "+TimeToStr(TimeCurrent(), TIME_SECONDS) );
  return(0);
}

У меня финальный результат выглядит так. Надеюсь, я нигде не ошибся и Вы сможете его воспроизвести.





Заключение

Мы рассмотрели способ организации взаимодействия между MetaTrader 4 и Matlab посредством CSV-файлов. Этот способ не является ни единственным, ни оптимальным. Ценность такого подхода лишь в том, что он позволяет обмениваться массивами данных, не требуя навыков владения программными инструментами, отличными от МТ4 и Matlab.

Прикрепленные файлы |
work.zip (9.98 KB)
Последние комментарии | Перейти к обсуждению на форуме трейдеров (19)
Андрей Шелихов
Андрей Шелихов | 15 окт. 2012 в 12:00

Встроил Вашу программу в эксперт в отдельную подпрограмму МТ4.

Файл создаётся.. данные пишутся ( как пишет программа советника) но найти этот файл визуально на диске мне не удаётся.

Подскажите где искать этот сохранённый файл.

Я ищу в папке experts/files но папка пуста.

Может быть файлы скрыты для просмотра?

Или он в другой папке:

Искал так же в других папка х.

digger3d
digger3d | 13 янв. 2013 в 21:15

Матлаб 2012а, вин7. ГУЙ рисует график но не создается файл в матлабе, соотв. не рисует в МТ. В матлабе выскакивает это:

Error while evaluating TimerFcn for timer 'timer-1' 

Too many output arguments.

 

ЧТО ДЕЛАТЬ? 


Dmitriy
Dmitriy | 10 мар. 2013 в 21:12
digger3d:

Матлаб 2012а, вин7. ГУЙ рисует график но не создается файл в матлабе, соотв. не рисует в МТ. В матлабе выскакивает это:
Error while evaluating TimerFcn for timer 'timer-1'
Too many output arguments.
ЧТО ДЕЛАТЬ?

Попробовать сначала без таймера.
Т.е.  проверить, - работает ли до пункта 4.5 включительно, и создаётся ли файл при нажатии на "Start".
А потом уже разбираться с функцией "timer()" по матлабовскому хелпу.

Я помню, что там некоторая сложность была, связанная с тем, что в функцию, вызываемую таймером передавались лишние аргументы. Т.е. я пишу - только handles-структуру передавать, а в вызываемую функцию передаются ещё какие-то. И пока я в вызываемой функции "checktime()" - не приписал эти входные аргументы (хоть и не использовал их) - функция вызывалась с ошибкой. Вот ваше сообщение об ошибке - похоже на что-то такое.

Dmitriy
Dmitriy | 10 мар. 2013 в 21:32
shelandr:

Файл создаётся.. данные пишутся ( как пишет программа советника) но найти этот файл визуально на диске мне не удаётся.
Подскажите где искать этот сохранённый файл.

Матлаб в этом примере - пишет выходной файл туда же, откуда взял входной. Т.е. просто кладёт рядом. Только добавляет "_result" после имени (перед расширением).
Куда пишет и может писать MT4 - лучше посмотреть в документации на MT4, функции FileWrite() и FileOpen(). У меня записывал туда, где Вы искали.
Может попробовать имя файла задавать полное принудительно вместе с расположением. Ну там C:\...
Только надо посмотреть в хелпе на MT4 - можно ли.
awkozlov
awkozlov | 11 мая 2017 в 20:15
Dmitriy:

Попробовать сначала без таймера.
Т.е.  проверить, - работает ли до пункта 4.5 включительно, и создаётся ли файл при нажатии на "Start".
А потом уже разбираться с функцией "timer()" по матлабовскому хелпу.

Я помню, что там некоторая сложность была, связанная с тем, что в функцию, вызываемую таймером передавались лишние аргументы. Т.е. я пишу - только handles-структуру передавать, а в вызываемую функцию передаются ещё какие-то. И пока я в вызываемой функции "checktime()" - не приписал эти входные аргументы (хоть и не использовал их) - функция вызывалась с ошибкой. Вот ваше сообщение об ошибке - похоже на что-то такое.


Дмитрий, у меня та же проблема. 

Error while evaluating TimerFcn for timer 'timer-1' 

Too many output arguments.

Могли бы Вы прикрепить работающий код или, сказать что исправить при вызове функции checktime ?

Я нашел в коде по ней 2 строчки и меня как-то не могу понять сам синтаксис передачи аргументов. Что именно надо поравить?

1. handles.t = timer('TimerFcn',{@checktime, handles},'ExecutionMode','fixedRate','Period',1.0,'UserData', 'NONE');

2. function checktime(obj, event, handles)

Технический Анализ: невозможное - возможно! Технический Анализ: невозможное - возможно!
Ответ на вопрос: почему невозможное может быть возможным, когда многое говорит об обратном? Рассуждения о техническом анализе.
Принцип замены времени в интрадей-торговле Принцип замены времени в интрадей-торговле
В статье изложена концепция операционного времени, позволяющая получать более однородный поток цен. Представлен код измененного скользящего среднего, учитывающий это преобразование времени.
Визуализация тестирования. Графики состояния счета. Визуализация тестирования. Графики состояния счета.
Погрузитесь в процесс тестирования с графиками, отображающими состояние счета - теперь вся необходимая информация всегда на виду!
Как упростить обнаружение и устранение ошибок в коде эксперта Как упростить обнаружение и устранение ошибок в коде эксперта
В разработке торговых экспертов не последнее место занимают вопросы диагностики и исправления ошибок в их коде. Специфика такова, что порой не обнаруженная вовремя ошибка может погубить стоящую идею торговой системы еще на этапе ее первых испытаний. Поэтому любой здравомыслящий разработчик МТС будет изначально заботиться о таких проблемах. Данная статья рассматривает некоторые подходы, помогающие в этом нелегком деле.