Это логично, если индикатор пережат, поэтому, если хай или лоу был достигнут на времени открытия бара - будет совпадение, остальные варианты будут мимо кассы.
CurAT = CurA*CurBar;
PreAT = PreA*CurBar;
CurChlTop2[i] = CurChlTop[i];
CurChlTop[i] = CurAT + CurBt;
CurChlBot[i] = CurAT + CurBb;
PreChlTop[i] = PreAT + PreBt;
PreChlBot[i] = PreAT + PreBb;
Соответственно, изменён эксперт
int start() {
CurChlTop = iCustom(NULL,0,"TwoChannels1",377,987,1,1);
CurChlBot = iCustom(NULL,0,"TwoChannels1",377,987,2,1);
PreChlTop = iCustom(NULL,0,"TwoChannels1",377,987,3,1);
PreChlBot = iCustom(NULL,0,"TwoChannels1",377,987,4,1);
CurChlTop2 = iCustom(NULL,0,"TwoChannels1",377,987,6,1);
cnt++;
// if (cnt%600 == 0) {
Print("Значения индикатора Дно1: ",CurChlBot," Верх1: ",CurChlTop," Дно2: ",PreChlBot," Верх2: ",PreChlTop);
Print("Буфер для Верх1 перед расчётом: ",CurChlTop2);
// }
return(0);
}
Вот фрагмент real time журнала
2006.02.06 23:22:33 TestChannels1 EURUSD,M1: Буфер для Верх1 перед расчётом: 2147483647 2006.02.06 23:22:33 TestChannels1 EURUSD,M1: Значения индикатора Дно1: 1.1944 Верх1: 1.2049 Дно2: 1.2 Верх2: 1.2138 2006.02.06 23:22:32 TestChannels1 EURUSD,M1: Буфер для Верх1 перед расчётом: 2147483647 2006.02.06 23:22:32 TestChannels1 EURUSD,M1: Значения индикатора Дно1: 1.1944 Верх1: 1.2049 Дно2: 1.2 Верх2: 1.2138 2006.02.06 23:21:43 TestChannels1 EURUSD,M1: Буфер для Верх1 перед расчётом: 2147483647 2006.02.06 23:21:43 TestChannels1 EURUSD,M1: Значения индикатора Дно1: 1.1944 Верх1: 1.205 Дно2: 1.2 Верх2: 1.2138 2006.02.06 23:20:57 TestChannels1 EURUSD,M1: Буфер для Верх1 перед расчётом: 2147483647 2006.02.06 23:20:57 TestChannels1 EURUSD,M1: Значения индикатора Дно1: 1.1944 Верх1: 1.205 Дно2: 1.2 Верх2: 1.2138
Если я правильно трактую, это означает, что предпоследнее значение исследуемого буфера считется 1 раз при открытии нового бара и потом не пересчитывается(как раз то, что нужно для экономии ресурсов). Правильно ли я трактую?
Следующая проверка. Возвращаемся к первоначальному коду индикатора и эксперта. Чтобы не включать в испытание весь код, берём типичную ситуацию, когда пересечения средних нет и коэффициенты вообще не пересчитываются. То есть меняется только величина CurBar и фактически работает только участок
CurAT = CurA*CurBar;
PreAT = PreA*CurBar;
CurChlTop[i] = CurAT + CurBt;
CurChlBot[i] = CurAT + CurBb;
PreChlTop[i] = PreAT + PreBt;
PreChlBot[i] = PreAT + PreBb;
Вот картинка индикатора в реальном времени (включение в 20:40 по времени графика)
А это тот же интервал из тестера
Значения индикатора совпадают (то есть он как будто одинаково работает на и на истории и в реальном времени и правильно обрабатывает момент включения). Тем не менее в 21:28 принт печатает
Дно1: 1.2003 Верх1: 1.2049 Дно2: 1.2 Верх2: 1.2015
, хотя картинка показывет
Дно1: 1.1944 Верх1: 1.2049 Дно2: 1.2 Верх2: 1.2138
Даже если бы значения индикатора пересчитывались, они не должны меняться, потому что CurBar = Bars-i, то есть отсчёт ведётся от начала графика и с появлением нового бара CurBar для конкретного бара не меняется.
Новая неприятность - на real-time графике видна звёздочка, показывающая экстремум там, где его нет. Но каналы при этом не переключаются и не пересчитываются - а по коду видно, что это происходит всегда при фиксации экстремума. Поэтому (да простят меня разработчики) пока я склонен видеть в этом глюк терминала. Момент появления уследить не удалось, но при прикреплении индикатора её не было. Возможно это связано с переключением масштабов и таймфреймов, однако утверждать не берусь. Да и с проблемами лучше разбираться по порядку.
counted_bars=0;
И после прогона тестера все принты с точностью совпали.
Это говорит о том, что в Вашем алгоритме эффективного расчёта есть ошибка. Вы можете самостоятельно это проверить.
Открыть график, кинуть на него индикатор и подождать несколько новых баров.
Потом открыть такой же график и опять кинуть на него индикатор.
Сравнить результаты на последних барах.
Теперь про экстремум там, где его не было.
Необходимо учитывать тот факт, что при открытии тестового графика на него подгружаются текущие исторические данные. Которые вполне могут не совпадать с данными, на которых Вы тестировались. Для исключения несоответствия нажимайте галку "Пересчёт".
counted_bars=0;
И после прогона тестера все принты с точностью совпали.
Это говорит о том, что в Вашем алгоритме эффективного расчёта есть ошибка. Вы можете самостоятельно это проверить.
Открыть график, кинуть на него индикатор и подождать несколько новых баров.
Потом открыть такой же график и опять кинуть на него индикатор.
Сравнить результаты на последних барах.
Необходимо учитывать тот факт, что при открытии тестового графика на него подгружаются текущие исторические данные. Которые вполне могут не совпадать с данными, на которых Вы тестировались. Для исключения несоответствия нажимайте галку "Пересчёт".
И еще - "Снова про индикаторы в Экспертах - вопрос к разработчикам"
И еще - "Снова про индикаторы в Экспертах - вопрос к разработчикам"
Открыть график, кинуть на него индикатор и подождать несколько новых баров.
Потом открыть такой же график и опять кинуть на него индикатор.
Сравнить результаты на последних барах.
Кстати, при написании mql4-аналогов некоторых наших встроенных индикаторов (например, Parabolic SAR) у нас возникала проблема "эффективного пересчёта". И решить её не очень просто - надо очень хорошо представлять алгоритм расчёта.
- Бесплатные приложения для трейдинга
- 8 000+ сигналов для копирования
- Экономические новости для анализа финансовых рынков
Вы принимаете политику сайта и условия использования
int cnt; double CurChlTop,CurChlBot; double PreChlTop,PreChlBot; //+------------------------------------------------------------------+ //| expert initialization function | //+------------------------------------------------------------------+ int init() { //---- cnt = 0; //---- return(0); } //+------------------------------------------------------------------+ //| expert deinitialization function | //+------------------------------------------------------------------+ int deinit() { //---- //---- return(0); } //+------------------------------------------------------------------+ //| expert start function | //+-----------------------------------------------------------------+ int start() { CurChlTop = iCustom(NULL,0,"TwoChannels",377,987,1,1); CurChlBot = iCustom(NULL,0,"TwoChannels",377,987,2,1); PreChlTop = iCustom(NULL,0,"TwoChannels",377,987,3,1); PreChlBot = iCustom(NULL,0,"TwoChannels",377,987,4,1); cnt++; if (cnt%600 == 0) { Print("Значения индикатора Дно1: ",CurChlBot," Верх1: ",CurChlTop," Дно2: ",PreChlBot," Верх2: ",PreChlTop); } return(0); } //+------------------------------------------------------------------+После тестера имею картинку
Из картинки следует, что в журнале должно печататься
На самом деле печатается
Общая закономерность - на графике и в принте всегда совпадают две пары значений, но иногда это дно, а иногда - верх. То есть одни и те же строчки кода в индикаторе иногда дают одинаковый результат в тестере и на графике, а иногда разный. Код индикатора прилагается
//+------------------------------------------------------------------+ //| TwoChannels.mq4 | //| Copyright © 2006, Candid | //| likh@yandex.ru | //+------------------------------------------------------------------+ #property copyright "Copyright © 2006, Candid" #property link "likh@yandex.ru" #property indicator_chart_window #property indicator_buffers 6 #property indicator_color1 DarkViolet #property indicator_color2 Crimson #property indicator_color3 Crimson #property indicator_color4 Indigo #property indicator_color5 Indigo #property indicator_color6 White extern int Period1 = 377; extern int Period2 = 987; //extern int TimeFrame = 0; //extern int ArrowGap = 3; //extern color ArrowColor = DarkOrchid; int TimeFrame = 0; int ArrowGap = 3; color ArrowColor = DarkOrchid; //---- buffers double Ext[]; double CurChlTop[]; double CurChlBot[]; double PreChlTop[]; double PreChlBot[]; double ChlsParams[]; double Gap; double Max, Min; int MaxPos, MinPos; int MaxBar, MinBar; int preMaxPos, preMinPos; int pre2MaxPos, pre2MinPos; int preMaxBar, preMinBar; int pre2MaxBar, pre2MinBar; bool FindMax = TRUE; bool FindMin = TRUE; double CurA = 0; double CurBt = 0; double CurBb = 0; double PreA = 0; double PreBt = 0; double PreBb = 0; int CurBar = 0; double CurAT = 0; double PreAT = 0; //+------------------------------------------------------------------+ //| Custom indicator initialization function | //+------------------------------------------------------------------+ int init() { //---- indicators IndicatorDigits(Digits); // SetIndexStyle(0,DRAW_NONE); SetIndexStyle(0,DRAW_ARROW,EMPTY,EMPTY,ArrowColor); SetIndexArrow(0,93); SetIndexBuffer(0,Ext); SetIndexStyle(1,DRAW_LINE,STYLE_SOLID,2); SetIndexBuffer(1,CurChlTop); SetIndexStyle(2,DRAW_LINE,STYLE_SOLID,2); SetIndexBuffer(2,CurChlBot); SetIndexStyle(3,DRAW_LINE,STYLE_SOLID,2); SetIndexBuffer(3,PreChlTop); SetIndexStyle(4,DRAW_LINE,STYLE_SOLID,2); SetIndexBuffer(4,PreChlBot); SetIndexStyle(5,DRAW_NONE); SetIndexBuffer(5,ChlsParams); Gap = ArrowGap*Point; MaxBar = 0; MinBar = 0; preMaxBar = 0; preMinBar = 0; Max = 0; Min = 0; //---- return(0); } //+------------------------------------------------------------------+ //| Custor indicator deinitialization function | //+------------------------------------------------------------------+ int deinit() { return(0); } //+------------------------------------------------------------------+ //| Custom indicator iteration function | //+------------------------------------------------------------------+ int start() { double fEMA, sEMA; int i,j,limit; int counted_bars=IndicatorCounted(); //---- check for possible errors if (counted_bars<0) return(-1); limit = Bars-counted_bars-1; //---- for(i=limit; i>0; i--) { CurBar = Bars-i; // Рассчитываем скользящие средние fEMA = iMA(NULL,0,377,0,MODE_EMA,PRICE_MEDIAN,i); sEMA = iMA(NULL,0,987,0,MODE_EMA,PRICE_MEDIAN,i); // fEMA = iMA(NULL,TimeFrame,Period1,0,MODE_EMA,PRICE_MEDIAN,i); // sEMA = iMA(NULL,TimeFrame,Period2,0,MODE_EMA,PRICE_MEDIAN,i); // Если разность скользящих средних положительна, ищем максимум if (fEMA >= sEMA) { if (FindMin) { // Пересечение средних. Фиксируем очередной минимум. FindMin = FALSE; FindMax = TRUE; pre2MinBar = preMinBar; preMinBar = MinBar; pre2MinPos = Bars-pre2MinBar; preMinPos = Bars-preMinBar; Ext[preMinPos] = Min - Gap; // Стартовые значения для следующего максимума Max = High[preMinPos]; MaxPos = preMinPos; for(j=preMinPos-1;j>i;j--) { if(High[j] >= Max) { Max = High[j]; MaxPos = j; } } MaxBar = Bars-MaxPos; // Текущий канал становится предыдущим PreA = CurA; PreBt = CurBt; PreBb = CurBb; // Рассчитываем новый канал по двум последним минимумам. y = Ax + B // A = (y2-y1)/(x2-x1) // B = (x2*y1-x1*y2)/(x2-x1) if ( Time[preMaxPos]-Time[pre2MaxPos] != 0) { // Рассчитываем А CurA = (Low[preMinPos]-Low[pre2MinPos])/(preMinBar-pre2MinBar); // Рассчитываем смещение дна канала Bb CurBb = (preMinBar*Low[pre2MinPos]-pre2MinBar*Low[preMinPos])/(preMinBar-pre2MinBar); // Рассчитываем смещение верха канала Bt = y3 - A*x3 CurBt = High[preMaxPos] - CurA*preMaxBar; } } if(High[i] >= Max) { Max = High[i]; MaxBar = CurBar; } } // Если разность скользящих средних отрицательна, ищем минимум if (fEMA < sEMA) { if (FindMax) { // Пересечение средних. Фиксируем очередной максимум. FindMax = FALSE; FindMin = TRUE; pre2MaxBar = preMaxBar; preMaxBar = MaxBar; pre2MaxPos = Bars-pre2MaxBar; preMaxPos = Bars-preMaxBar; Ext[preMaxPos] = Max + Gap; // Стартовые значения для следующего минимума Min = Low[preMaxPos]; MinPos = preMaxPos; for(j=preMaxPos-1;j>i;j--) { if(Low[j] <= Min) { Min = Low[j]; MinPos = j; } } MinBar = Bars-MinPos; // Текущий канал становится предыдущим PreA = CurA; PreBt = CurBt; PreBb = CurBb; // Рассчитываем новый канал по двум последним максимумам. y = Ax + B // A = (y2-y1)/(x2-x1) // B = (x2*y1-x1*y2)/(x2-x1) if ( preMaxBar-pre2MaxBar != 0) { // Рассчитываем А CurA = (High[preMaxPos]-High[pre2MaxPos])/(preMaxBar-pre2MaxBar); // Рассчитываем смещение верха канала Bt CurBt = (preMaxBar*High[pre2MaxPos]-pre2MaxBar*High[preMaxPos])/(preMaxBar-pre2MaxBar); // Рассчитываем смещение дна канала Bb = y3 - A*x3 CurBb = Low[preMinPos] - CurA*preMinBar; } } if(Low[i] <= Min) { Min = Low[i]; MinBar = CurBar; } } CurAT = CurA*CurBar; PreAT = PreA*CurBar; CurChlTop[i] = CurAT + CurBt; CurChlBot[i] = CurAT + CurBb; PreChlTop[i] = PreAT + PreBt; PreChlBot[i] = PreAT + PreBb; ChlsParams[1] = CurA; ChlsParams[2] = CurBt; ChlsParams[3] = CurBb; ChlsParams[4] = PreA; ChlsParams[5] = PreBt; ChlsParams[6] = PreBb; } return(0); } //+------------------------------------------------------------------+