Форум » Консультации по программированию » Я в шоке! Подскажите. » Ответить

Я в шоке! Подскажите.

Sergey: Всем привет! Я в шоке! Выпал из рынка на 3,5 месяца, а тут такие перемены. Игорь подскажи, где можно ознакомиться с изменениями в MQL4? Хотел перенести все данные на новый комп, но некоторые индикаторы после компиляции перестают работать. Вот один из них. http://gfile.ru/a8cCP Хотя не перекомпилированные файлы работают. Компиляция ошибок в коде не выявляет. Но при отладке выдается ошибка формирования массива стр.67. Но в чем ошибка не пойму. Буду благодарен, если найдешь время исправить.

Ответов - 204, стр: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 All

Sergey: Игорь, Привет! Я решил попробовать MQL5. Начал с простого. Попробовал раскрасить OsMA используя вызов стандартного индикатора. Привожу код полностью #property copyright "Copyright 2018, MetaQuotes Software Corp." #property link "https://www.mql5.com" #property version "1.00" #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 2 #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrGreen #property indicator_width1 2 #property indicator_type2 DRAW_HISTOGRAM #property indicator_color2 clrRed #property indicator_width2 2 #property indicator_level1 0 input int ShowBars = 300; input int FastEMA = 34; input int SlowEMA = 72; input int SignalSMA = 9; input ENUM_APPLIED_PRICE applied_price = PRICE_CLOSE; //--- indicator buffers double Up_OsMA_Buffer[]; double Dn_OsMA_Buffer[]; double OsMA_Buffer[]; //--- OsMA handles int OsMA_Handle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,Up_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(1,Dn_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(2,OsMA_Buffer,INDICATOR_CALCULATIONS); IndicatorSetInteger(INDICATOR_DIGITS,_Digits+3); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); IndicatorSetString(INDICATOR_SHORTNAME,"FW-OsMA("+string(FastEMA)+","+string(SlowEMA)+","+string(SignalSMA)+")"); PlotIndexSetString(0,PLOT_LABEL,"UpOsMA"); PlotIndexSetString(1,PLOT_LABEL,"DnOsMA"); OsMA_Handle = iOsMA(NULL,PERIOD_CURRENT ,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int calculated=BarsCalculated(OsMA_Handle); if(calculated<rates_total) { Alert("Not all data of OsMA_Handle is calculated (",calculated,"bars ). Error",GetLastError()); return(0); } //--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total; else { to_copy=rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(IsStopped()) return(0); //Checking for stop flag if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); } //--- int k,limit; if(prev_calculated==0) limit=0; else limit=prev_calculated-1; //--- the main loop of calculations for(k=limit;k<rates_total;k++) { //Dn_OsMA_Buffer[k]=0.0; Up_OsMA_Buffer[k]=0.0; //--- calculate OsMA //if(OsMA_Buffer[k]>OsMA_Buffer[k+1]) //Up_OsMA_Buffer[k]=OsMA_Buffer[k]; //else Dn_OsMA_Buffer[k]=OsMA_Buffer[k]; Если вместо выше выделенного текста подставить нижнюю строку и (#property indicator_plots 1), то все работает, но в одном цвете. А так, нет. Отображается абра-кадабра какая-то. Up_OsMA_Buffer[k]=OsMA_Buffer[k]; } //--- return value of prev_calculated for next call return(rates_total); } //==================================================================== Что не правильно в выделенном тексте? А если задать ArraySetAsSeries(OsMA_Buffer,true); , то и этот вариант не работает.

Scriptong: Sergey пишет: Что не правильно в выделенном тексте? А если задать ArraySetAsSeries(OsMA_Buffer,true); , то и этот вариант не работает. Дело в том, что без ArraySetAsSeries нумерация баров в таймсериях ведется слева направо по графику. То есть бар с индексом 0 - где-то глубоко в истории, а текущий бар - это rates_total - 1. Поэтому для такой нумерации нужно: Начинать перебор баров не с бара 0, а с бара 1, т. к. нам нужно взять высоты гистограммы предыдущего бара, которого для бара 0 нет. То есть limit ставится не на 0, а на 1. Понять, что предыдущий бар, это не k + 1, а k - 1. Получаем такой вот работающий код: #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 2 #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrGreen #property indicator_width1 2 #property indicator_type2 DRAW_HISTOGRAM #property indicator_color2 clrRed #property indicator_width2 2 #property indicator_level1 0 input int ShowBars= 300; input int FastEMA = 34; input int SlowEMA = 72; input int SignalSMA=9; input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; //--- indicator buffers double Up_OsMA_Buffer[]; double Dn_OsMA_Buffer[]; double OsMA_Buffer[]; //--- OsMA handles int OsMA_Handle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,Up_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(1,Dn_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(2,OsMA_Buffer,INDICATOR_CALCULATIONS); IndicatorSetInteger(INDICATOR_DIGITS,_Digits+3); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); IndicatorSetString(INDICATOR_SHORTNAME,"FW-OsMA("+string(FastEMA)+","+string(SlowEMA)+","+string(SignalSMA)+")"); PlotIndexSetString(0,PLOT_LABEL,"UpOsMA"); PlotIndexSetString(1,PLOT_LABEL,"DnOsMA"); OsMA_Handle=iOsMA(NULL,PERIOD_CURRENT,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int calculated=BarsCalculated(OsMA_Handle); if(calculated<rates_total) { Alert("Not all data of OsMA_Handle is calculated (",calculated,"bars ). Error",GetLastError()); return(0); } //--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy=rates_total; else { to_copy=rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(IsStopped()) return(0); //Checking for stop flag if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); } //--- int k,limit; if(prev_calculated==0) limit=1; else limit=prev_calculated-1; //--- the main loop of calculations for(k=limit;k<rates_total;k++) { Dn_OsMA_Buffer[k]=0.0; Up_OsMA_Buffer[k]=0.0; //-- calculate OsMA if(OsMA_Buffer[k]>OsMA_Buffer[k-1]) Up_OsMA_Buffer[k]=OsMA_Buffer[k]; else Dn_OsMA_Buffer[k]=OsMA_Buffer[k]; } //--- return value of prev_calculated for next call return(rates_total); }

Sergey: Спасибо! Но хотелось бы разобраться до конца. Как изменить код с использованием ArraySetAsSeries(OsMA_Buffer,true); Поскольку именно этот вариант в дальнейшем будет использован в советниках и рекомендован во всех статьях, а у меня не вышел.


Scriptong: Тогда нужно всю индексацию развернуть, а не просто использовать ArraySetAsSeries. Т. к. цикл расчета данных для каждого бара в "правильном" индикаторе должен следовать слева направо по графику, то нужно идти от rates_total (limit поддерживать) до 0 с декрементом.

Sergey: Scriptong пишет: Тогда нужно всю индексацию развернуть, а не просто использовать ArraySetAsSeries. Т. к. цикл расчета данных для каждого бара в "правильном" индикаторе должен следовать слева направо по графику, то нужно идти от rates_total (limit поддерживать) до 0 с декрементом. На словах я это понимаю, с практикой туго. Устанавливаем порядок индексации массива как в таймсерии if(CopyBuffer(OsMA_Handle,0,0,to_copy,OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error",GetLastError()); return(0); } ArraySetAsSeries(OsMA_Buffer,true); Отобразим первые 200 баров for(int k=200;k>=0;k--) { Dn_OsMA_Buffer[k]=0.0; Up_OsMA_Buffer[k]=0.0; //-- calculate OsMA if(OsMA_Buffer[k]>OsMA_Buffer[k+1]) Up_OsMA_Buffer[k]=OsMA_Buffer[k]; else Dn_OsMA_Buffer[k]=OsMA_Buffer[k]; } Как не пересчитываю слева-направо или наоборот, получается фигня. В чем не прав не знаю. Я это смогу понять, лишь проанализировав правильный код. Не зачти за лишний труд. Плиз!

Scriptong: Sergey пишет: Как не пересчитываю слева-направо или наоборот, получается фигня. В чем не прав не знаю. Я это смогу понять, лишь проанализировав правильный код. Не зачти за лишний труд. Плиз! Установка признака таймсерии делается один раз, а не на каждом тике. И не для одного буфера, а для всех. Поэтому и проблема: #property indicator_separate_window #property indicator_buffers 3 #property indicator_plots 2 #property indicator_type1 DRAW_HISTOGRAM #property indicator_color1 clrGreen #property indicator_width1 2 #property indicator_type2 DRAW_HISTOGRAM #property indicator_color2 clrRed #property indicator_width2 2 #property indicator_level1 0 input int ShowBars= 300; input int FastEMA = 34; input int SlowEMA = 72; input int SignalSMA=9; input ENUM_APPLIED_PRICE applied_price=PRICE_CLOSE; //--- indicator buffers double Up_OsMA_Buffer[]; double Dn_OsMA_Buffer[]; double OsMA_Buffer[]; //--- OsMA handles int OsMA_Handle; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- indicator buffers mapping SetIndexBuffer(0,Up_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(1,Dn_OsMA_Buffer,INDICATOR_DATA); SetIndexBuffer(2,OsMA_Buffer,INDICATOR_CALCULATIONS); ArraySetAsSeries(Up_OsMA_Buffer, true); ArraySetAsSeries(Dn_OsMA_Buffer, true); ArraySetAsSeries(OsMA_Buffer, true); IndicatorSetInteger(INDICATOR_DIGITS,_Digits+3); PlotIndexSetInteger(0,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); PlotIndexSetInteger(1,PLOT_DRAW_BEGIN,SlowEMA+SignalSMA-2); IndicatorSetString(INDICATOR_SHORTNAME,"FW-OsMA("+string(FastEMA)+","+string(SlowEMA)+","+string(SignalSMA)+")"); PlotIndexSetString(0,PLOT_LABEL,"UpOsMA"); PlotIndexSetString(1,PLOT_LABEL,"DnOsMA"); OsMA_Handle=iOsMA(NULL,PERIOD_CURRENT,FastEMA,SlowEMA,SignalSMA,applied_price); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Функция деинициализации | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { IndicatorRelease(OsMA_Handle); // удаляет хэндл индикатора и освобождает память занимаемую им ArrayFree(Up_OsMA_Buffer); // освобождаем динамический массив от данных ArrayFree(Dn_OsMA_Buffer); ArrayFree(OsMA_Buffer); } //==================================================================== //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int OnCalculate(const int rates_total, const int prev_calculated, const datetime &time[], const double &open[], const double &high[], const double &low[], const double &close[], const long &tick_volume[], const long &volume[], const int &spread[]) { int calculated = BarsCalculated(OsMA_Handle); if(calculated < rates_total) { Alert("Not all data of OsMA_Handle is calculated (", calculated, "bars ). Error", GetLastError()); return(0); } //--- we can copy not all data int to_copy; if(prev_calculated>rates_total || prev_calculated<0) to_copy = rates_total; else { to_copy = rates_total-prev_calculated; to_copy++; } //--- get OsMA_Buffer buffer if(CopyBuffer(OsMA_Handle, 0, 0, to_copy, OsMA_Buffer)<=0) { Print("Getting OsMA_Buffer is failed! Error", GetLastError()); return(0); } //--- int k,limit; if(prev_calculated == 0) limit = rates_total - 2; else limit = fmin(rates_total - prev_calculated, rates_total - 2); //--- the main loop of calculations for(k = limit; k >= 0; --k) { Dn_OsMA_Buffer[k] = 0.0; Up_OsMA_Buffer[k] = 0.0; //-- calculate OsMA if (OsMA_Buffer[k] > OsMA_Buffer[k + 1]) Up_OsMA_Buffer[k] = OsMA_Buffer[k]; else Dn_OsMA_Buffer[k] = OsMA_Buffer[k]; } //--- return value of prev_calculated for next call return(rates_total); }

Sergey: Scriptong пишет: Установка признака таймсерии делается один раз, а не на каждом тике. И не для одного буфера, а для всех. Поэтому и проблема: Все точно! В этом проблема. А что с советниками? Вот пример на сайте mql5.com /---- indicator buffers double MA[]; // массив для индикатора iMA //---- handles for indicators int MA_handle; // указатель на индикатор iMA //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- создание указателя на объект - индикатор iMA MA_handle=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE); return(0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- заполнение массива MA[] текущими значениями индикатора iMA //--- в массив будет записано 100 элементов CopyBuffer(MA_handle,0,0,100,MA); //--- задаём порядок индексации массива MA[] как в MQL4 ArraySetAsSeries(MA,true); //--- а дальше делайте с этими данными всё что угодно, например: if(MA[0]>MA[1]) { //--- выполнение каких-то операций } } 1. Почему в советниках порядок индексации делается на каждом тике? 2. Есть ли возможность в советниках обновлять последние бары как в индикаторах, если для анализа нужно большое их количество. 3. И стоит ли использовать динамический массив, если для анализа брать 2 последних бара. Можно ли написать так: double MA[2]; // массив для индикатора iMA //---- handles for indicators int MA_handle; // указатель на индикатор iMA //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- создание указателя на объект - индикатор iMA MA_handle=iMA(NULL,0,21,0,MODE_EMA,PRICE_CLOSE); //--- задаём порядок индексации массива MA[] как в MQL4 ArraySetAsSeries(MA,true); return(0); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- заполнение массива MA[] текущими значениями индикатора iMA //--- в массив будет записано 2 элементов CopyBuffer(MA_handle,0,0,2,MA); //--- а дальше делайте с этими данными всё что угодно, например: if(MA[0]>MA[1]) { //--- выполнение каких-то операций } }

Scriptong: Sergey пишет: Можно ли написать так: Статический массив нельзя сделать таймсерией. Но ничего страшного в динамических массивах нет. Ведь функция CopyBuffer сама перераспределит память под массив при первом вызове. При последующих вызовах на это не будет уходить время. Поэтому вполне можно сделать так, проверяя попутно формирование нового бара: double MA[]; int MA_handle; void OnInit() { MA_handle = iMA(NULL, 0, 21, 0, MODE_EMA, PRICE_CLOSE); ArraySetAsSeries(MA, true); } void OnTick() { if (!IsNewBar()) return; if (CopyBuffer(MA_handle, 0, 0, 2, MA) != 2) { Print("Receiving MA values error N", GetLastError()); return; } if (MA[0] > MA[1]) { Print("MA[0] (", MA[0], ") greater than MA[1] (", MA[1], ")"); } else Print("MA[0] (", MA[0], ") less than MA[1] (", MA[1], ")"); } bool IsNewBar() { static datetime dtLastTime = 0; datetime arrdtTime[1]; if (CopyTime(Symbol(), PERIOD_CURRENT, 0, 1, arrdtTime) != 1) { Print("Receiving Time value error N", GetLastError()); return false; } bool bResult = (arrdtTime[0] != dtLastTime); dtLastTime = arrdtTime[0]; return bResult; }

Sergey: Игорь, огромное спасибо! Ситуацию по обращению к индикаторам прояснил.

Sergey: Столкнулся с не пониманием обращения к функции... в mql4. //+------------------------------------------------------------------+ //| Проверяет объем ордера на корректность | //+------------------------------------------------------------------+ bool CheckVolumeValueStart(double volume,string &description) { //--- минимально допустимый объем для торговых операций double min_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MIN); if(volume<min_volume) { description=StringFormat("Объем меньше минимально допустимого SYMBOL_VOLUME_MIN=%.2f",min_volume); return(false); } //--- максимально допустимый объем для торговых операций double max_volume=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_MAX); if(volume>max_volume) { description=StringFormat("Объем больше максимально допустимого SYMBOL_VOLUME_MAX=%.2f",max_volume); return(false); } //--- получим минимальную градацию объема double volume_step=SymbolInfoDouble(Symbol(),SYMBOL_VOLUME_STEP); int ratio=(int)MathRound(volume/volume_step); if(MathAbs(ratio*volume_step-volume)>0.0000001) { description=StringFormat("Объем не является кратным минимальной градации SYMBOL_VOLUME_STEP=%.2f, ближайший корректный объем %.2f", volume_step,ratio*volume_step); return(false); } description="Корректное значение объема"; return(true); } //============================================================================= Что делать с &description? if (!CheckVolumeValueStart(Lot,................)) return; Конечно, можно его убрать из функции, а в тексте заменить на Print. Но хотелось бы разобраться, что это значит и как правильно применить. Спасибо!

Admin: Sergey пишет: Что делать с &description? if (!CheckVolumeValueStart(Lot,................)) return; Конечно, можно его убрать из функции, а в тексте заменить на Print. Но хотелось бы разобраться, что это значит и как правильно применить. Этот аргумент функции нужно рассматривать как сообщение об ошибке. Пользоваться так: string description = ""; if (!CheckVolumeValueStart(Lot, description)) { Print(description); return; } Могу согласиться с тем, что в качестве примера такой прием вызывает недоумение. Скорее всего взято из какого-то готового проекта и вставлено как есть.

Sergey: Admin пишет: string description = ""; А вот это я и пропустил. Забыл объявить. Спасибо Игорь! Admin пишет: Могу согласиться с тем, что в качестве примера такой прием вызывает недоумение. Скорее всего взято из какого-то готового проекта и вставлено как есть. В маркете на mql5.com при валидации (автоматической проверки на наличие ошибок) это выдано в качестве примера. Авто контроль проверяет каждую из позиций: минимальный и максимальный лот, кратность шагу и достаточность свободных средств для стартового лота в советнике. Причем ошибка обязательно должна быть выведена в журнал (Print) иначе проверку сова на проходит. Пришлось сделать отдельную объединенную функцию на будущее. Замучился, пока понял, что ошибка неправильные объемы относятся к стартовому лоту.

Sergey: Сейчас другая проблема:"Необходимо добавить возможность проверки торговых функций программы на наличие ошибок в Тестере стратегий." В советнике заложен вывод (Alert), если ордер не установлен, при условии, что все параметры заданы правильно. Что еще нужно не пойму. Ведь Alert в журнал тоже выводится. Может кто подскажет, что означает выше указанная ошибка..... И вот это: TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); double Lot = CalculatedProfit/TickValue/TakeProfit; TickValue почему-то именно для золота равно 0. Валютные пары тестирование проходят. Бред какой-то. Как обойти не знаю. В тестере ошибок нет.

Scriptong: Sergey пишет: Сейчас другая проблема:"Необходимо добавить возможность проверки торговых функций программы на наличие ошибок в Тестере стратегий." В советнике заложен вывод (Alert), если ордер не установлен, при условии, что все параметры заданы правильно. Что еще нужно не пойму. Ведь Alert в журнал тоже выводится. Может кто подскажет, что означает выше указанная ошибка..... Alert при тестировании выводится в журнал тестера по аналогии с функцией Print. Само окно и звуковой сигнал, конечно же, не отображается ни в одном из режимов тестирования. Sergey пишет: И вот это: TickValue = MarketInfo(Symbol(), MODE_TICKVALUE); double Lot = CalculatedProfit/TickValue/TakeProfit; TickValue почему-то именно для золота равно 0. Валютные пары тестирование проходят. Бред какой-то. Как обойти не знаю. В тестере ошибок нет. Проверил для золота на Альпари. Есть значение. А в онлайн что показывает? Еще можно попробовать заменить на более современную форму: SymbolInfoDouble(Symbol(), SYMBOL_TRADE_TICK_VALUE);

Sergey: Scriptong пишет: ще можно попробовать заменить на более современную форму: За эту подсказку спасибо. Что современнее , то и надо применять. Scriptong пишет: А в онлайн что показывает? Значения есть. Мне видится дело не в этом, а в настойках стартового лота. Проблему решил так: Установил в стартовых настройках вместо расчетного постоянный лот. Таким образом строка в авто проверку не попала. Теперь жду замечания от модератора.....



полная версия страницы