Взаимодействие между MetaTrader 4 и Matlab посредством CSV-файлов
Введение
Известно, что вычислительные способности инженерной системы 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.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
Встроил Вашу программу в эксперт в отдельную подпрограмму МТ4.
Файл создаётся.. данные пишутся ( как пишет программа советника) но найти этот файл визуально на диске мне не удаётся.
Подскажите где искать этот сохранённый файл.
Я ищу в папке experts/files но папка пуста.
Может быть файлы скрыты для просмотра?
Или он в другой папке:
Искал так же в других папка х.
Матлаб 2012а, вин7. ГУЙ рисует график но не создается файл в матлабе, соотв. не рисует в МТ. В матлабе выскакивает это:
Error while evaluating TimerFcn for timer 'timer-1'Too many output arguments.
ЧТО ДЕЛАТЬ?
Матлаб 2012а, вин7. ГУЙ рисует график но не создается файл в матлабе, соотв. не рисует в МТ. В матлабе выскакивает это:
Error while evaluating TimerFcn for timer 'timer-1'
Too many output arguments.
ЧТО ДЕЛАТЬ?
Попробовать сначала без таймера.
Т.е. проверить, - работает ли до пункта 4.5 включительно, и создаётся ли файл при нажатии на "Start".
А потом уже разбираться с функцией "timer()" по матлабовскому хелпу.
Я помню, что там некоторая сложность была, связанная с тем, что в функцию, вызываемую таймером передавались лишние аргументы. Т.е. я пишу - только handles-структуру передавать, а в вызываемую функцию передаются ещё какие-то. И пока я в вызываемой функции "checktime()" - не приписал эти входные аргументы (хоть и не использовал их) - функция вызывалась с ошибкой. Вот ваше сообщение об ошибке - похоже на что-то такое.
Файл создаётся.. данные пишутся ( как пишет программа советника) но найти этот файл визуально на диске мне не удаётся.
Подскажите где искать этот сохранённый файл.
Куда пишет и может писать MT4 - лучше посмотреть в документации на MT4, функции FileWrite() и FileOpen(). У меня записывал туда, где Вы искали.
Может попробовать имя файла задавать полное принудительно вместе с расположением. Ну там C:\...
Только надо посмотреть в хелпе на MT4 - можно ли.
Попробовать сначала без таймера.
Т.е. проверить, - работает ли до пункта 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)