Logo

    dmffx.com
      программирование для терминала MetaTrader4, MetaTrader5
 

Если больше ничего не помогает прочитайте инструкцию - Дж. Мерфи.

политика конфиденциальности

<<  вернуться  <<

Пересечение двух линий

Пересечение двух линий

Казалось бы что проще - пересечение двух линий, о чем здесь можно говорить? Есть о чем поговорить, все не так просто как кажется с начала, как бы странно не звучали эти слова. 

Положение и пересечение

В первую очередь нужно отметить большую разницу двух понятий: положения и пересечения. Положение - это когда одна линия находится выше или ниже второй линии. Положение существует всегда. Если есть две линии, то всегда одна линия выше или ниже другой (пока не трогая случая, когда когда обе лини совпадают). Если использовать, например, две скользящих средних (MA), или главную и сигнальную линию осциллятора Stochastic, практически всегда одна линия выше или ниже другой (рис. 1).


Рис. 1. Положения двух МА. Быстрая МА (красная) всегда расположена выше или ниже медленной МА (синей). 
Участки разного положения отмечены горизонтальными полосками в нижней части графика: розовая 
плоска - быстрая МА ниже медленной МА, зеленая полоска - быстрая МА выше медленной МА.

Пересечение же - это точка, момент. Сначала быстрая МА была с одной стороны медленной МА, затем, перешла на другую сторону медленной МА. Поскольку временная ось на графике не является непрерывной, а разделена побарно, то момент пересечения двух МА фиксируется не в момент времени, а течение одного бара. На одном баре быстрая МА выше/ниже медленной МА, а на следующем баре ниже/выше медленной МА, вот этот бар и является баром пересечения (рис. 2).


Рис. 2. Пересечение двух МА. Зеленой стрелкой отмечен бар пересечения вверх, розовой - бар пересечения вниз.

Для программной проверки положения двух линий, достаточно сравнить два значения на одном баре, значение быстрой линии и медленной:

double fast_ma=iMA(NULL,0,FastMAPeriod,0,FastMAMethod,FastMAPrice,1); // Значение быстрой МА
double slow_ma=iMA(NULL,0,SlowMAPeriod,0,SlowMAMethod,SlowMAPrice,1);
// Значение медленной МА

bool BuySignal=false;
bool SellSignal=false;

// Проверка положения двух МА:

   if(fast_ma>slow_ma){
     
// Быстрая МА выше медленной
      BuySignal=true;
   }
   if(fast_ma<slow_ma){
     
// Быстрая МА ниже медленной
      SellSignal=true;
}

При такой проверке всегда будет существовать сигнал к покупке или продаже. Будет ли эксперт открывать ордер, зависит только от наличия в нем проверки каких-то других условий, например, существования открытого ордера. Если выполняется дополнительная проверка на существования ордера, то как только ордер будет закрыт, будет открыт новый ордер. Практически подобная проверка скорее может использоваться не для определения сигнала к открытию позиции, а для определения подтверждающего сигнала в сочетании с другим сигналом.  К примеру, система на четырех МА, две более быстрых МА используются для определения момента входа (по пересечению), а две более медленных для подтверждения направления (в приложении индикатор i4MASys).

Для определения пересечения двух линий необходимо дополнительно проверять их положение еще на одном баре, на предыдущем. Очень часто в интернете на форумах предлагает код подобный следующему:

double f1=iMA(NULL,0,FastMAPeriod,0,FastMAMethod,FastMAPrice,1); // Значение быстрой МА
double s1=iMA(NULL,0,SlowMAPeriod,0,SlowMAMethod,SlowMAPrice,1);
// Значение медленной МА
double f2=iMA(NULL,0,FastMAPeriod,0,FastMAMethod,FastMAPrice,2);
// Значение быстрой МА на предыдущем баре
double s2=iMA(NULL,0,SlowMAPeriod,0,SlowMAMethod,SlowMAPrice,2);
// Значение медленной МА на предыдущем баре

bool BuySignal=false;
bool SellSignal=false;

// Неправильная проверка пересечения двух МА:

   if(f1>s1){
// Быстрая МА выше медленной
      if(f2<s2){
// На предыдущем баре быстрая МА ниже медленной
         BuySignal=true;
      } 
   }
   if(f1<s1){
// Быстрая МА ниже медленной
      if(f2>s2){
// На предыдущем баре быстрая МА выше медленной
         SellSignal=true;
      } 
   }

Казалось бы, что все нормально - на одном баре быстрая линия находится с одной стороны медленной линии, на соседнем - с другой стороны. 

Теперь рассмотрим тот редкий случай, когда значения быстрой и медленной линий равны, хоть и очень очень редко, но это случается. Рассмотрим что произойдет в этом случае при использовании вышеприведенного кода. 

Допустим, эксперт работает на двух МА, при пересечении вверх должна закрываться позиция sell и открываться позиция buy, при пересечении вниз - закрываться buy и открываться sell. Если текущие значения двух линий равны - все нормально, быстрая линия только коснулась медленной, но не пересекла ее, не надо предпринимать никаких действий. Если же на предыдущем баре значения равны, дело обстоит несколько иначе. На следующем баре быстрая линия может развернуться назад и снова оказаться в том же положение, что и была до касания (до равенства значений), но может и пересечь медленную линию. Фактически будет пересечение, но оно не будет выявлено. Пересечение не выявлено, противоположная позиция не закрыта, а после пересечение цена может уйти очень далеко... В результате будем иметь пропущенный торговый сигнал, незакрытую позицию против показаний нашей торговой  системы и соответственно убыток (рис. 3).


Рис. 3. Равенство двух МА(обведено коричневой окружность) и пересечение. В этой ситуации пересечение вниз не будет выявлено.

Чтобы не было таких ситуаций, проверку пересечения двух линий нужно немного изменить, на предыдущем баре выполнят проверку не на больше/меньше, а на больше или равно, и на меньше или равно:

double f1=iMA(NULL,0,FastMAPeriod,0,FastMAMethod,FastMAPrice,1); // Значение быстрой МА
double s1=iMA(NULL,0,SlowMAPeriod,0,SlowMAMethod,SlowMAPrice,1);
// Значение медленной МА
double f2=iMA(NULL,0,FastMAPeriod,0,FastMAMethod,FastMAPrice,2);
// Значение быстрой МА на предыдущем баре
double s2=iMA(NULL,0,SlowMAPeriod,0,SlowMAMethod,SlowMAPrice,2);
// Значение медленной МА на предыдущем баре

bool BuySignal=false;
bool SellSignal=false;

// Правильная проверка пересечения двух МА:

   if(f1>s1){
// Быстрая МА выше медленной
      if(f2
<=s2){ // На предыдущем баре быстрая МА ниже медленной
         BuySignal=true;
      } 
   }
   if(f1<s1){
// Быстрая МА ниже медленной
      if(f2
>=s2){ // На предыдущем баре быстрая МА выше медленной
         SellSignal=true;
      } 
   }

Такой вариант, тоже не самый совершенный, но все же позволяет избежать грубой ошибки в торговле. При использовании такой проверки будет определяться торговый сигнал после касания и возврата в туже сторону (рис. 4). 


Рис 4. Равенство двух МА и возврат быстрой МА в туже сторону. 

Рассмотрим подробно ситуацию изображенную рис. 4. По сигналу buy-1 открывается позиция, при появлении сигнала buy-2 у нас уже есть позиция buy, поэтому сигнал buy-2 будет проигнорирован. Если же эксперт был запущен позже появления сигнала buy-1, то по сигналу buy-2 будет открыта позиция buy, а при обратном пересечении двух МА, что в общем-то соответствует правилам торговой системы, по крайней мере ситуация не столь опасна, как пропуск сигнала при действительном пересечении двух МА, показанный на рис 3.

К статье прилагается скрипт a2MAEqCheck для определения количества равенств значений двух МА, эксперименты со этим скриптом показывают, что явление очень редкое -  на несколько десятков графиков можно обнаружить всего лишь один случай, но все же оно есть. 

Учитывая редкость случаев равенства двух линий такой проверкой можно пользоваться практически.

Частые случаи равенства значений 

Если используется две МА или главная с сигнальной линией осциллятора Stochastic и т.п., случаи равенства значений очень редки, однако существуют индикаторы у которых такое явление очень частое, например индикатор Ichimoku, линии Tenkan и Kijun (рис. 5).


Рис. 5. Индикатор Ichimoku. Линии Tenkan и Kijun часто совпадают (коричневые овалы).

При проверке положения, если две линии совпадают, можно считать, что направление не определено (третье состояние индикатора). Если необходимо всегда иметь показания направления вверх или вниз, то в случае равенства значений двух линий, необходимо найти последний бар на котором значения не равны:

bool BuySignal=false;
bool SellSignal=false;

   for(int i=
1;i<Bars;i++){ // Цикл по всем барам с первого
      double Tenkan=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_TENKANSEN,i);
      double Kijun=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_KIJUNSEN,i);
         if(Tenkan>Kijun){
// Есть бар на котором Тенкан выше Киджун
            BuySignal=true;
// Направление вверх
            break;
// Завершение цикла
         }
         else if(Tenkan<Kijun){
// Есть бар на котором Тенкан ниже Киджун
            SellSignal=true;
// Направление вниз
            break;
// Завершение цикла
         } 
   }

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

bool BuySignal=false;
bool SellSignal=false;

double Tenkan=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_TENKANSEN,
1);
double Kijun=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_KIJUNSEN,
1);

   if(Tenkan>Kijun){
// Положение вверх
      for(int i=
2;i<Bars;i++){ // Цикл по всем барам с предшествующего бара
         Tenkan=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_TENKANSEN,1);
         Kijun=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_KIJUNSEN,1); 
            if(Tenkan>Kijun){
// Ближайший предшествующий бар с положением вверх
            break;
// Завершение цикла, нет сигнала
      }
      else if(Tenkan<Kijun){
// Ближайший предшествующий бар с положением вниз
         BuySignal=true;
// Есть сигнал
         break;
// Завершение цикла
      } 
   }
}
else if(Tenkan<Kijun){
// Положение вниз
   for(i=
2;i<Bars;i++){ // Цикл по всем барам с предшествующего бара
      Tenkan=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_TENKANSEN,1);
      Kijun=iIchimoku(NULL,0,TenkanPeriod,KijunPeriod,SenkouPeriod,MODE_KIJUNSEN,1); 
         if(Tenkan<Kijun){
// Ближайший предшествующий бар с положением вниз
            break;
// Завершение цикла, нет сигнала
         }
         else if(Tenkan<Kijun){
// Ближайший предшествующий бар с положением вверх
            SellSignal=true;
// Значит есть пересечение
            break;
// Завершение цикла
         } 
   } 
}

При определении положения у таких индикаторов всего можно выделить четыре типа положения: положение вверх, положение вниз, равенство после положения вверх и равенство после положения вниз. На рис. 5 в левом овале можно увидеть равенство после положения вверх, в правом - равенство после положения вниз.

При определении пересечения можно выделить четыре типа сигналов: пересечение вверх, пересечение вниз, расхождение вверх после соединения, расхождение вниз после соединения. На рис. 5 в левом овале можно увидеть пересечение вниз, в правом - расхождение вниз после соединения.

Такие проверки с циклами подойдут для выполнения их в экспертах, при написании индикаторов можно поступить несколько другим способом - без цикла с использовать дополнительного индикаторного буфера. Рассмотрим на примере прилагаемого к статье индикатора i2IchSys. Система подобна ранее рассмотренной системе на четырех МА, но здесь используется два индикатора Ichimoku (так же четыре линии). Смысл использования буферов в том, что последнее известное положение двух линий ищется не при помощи цикла, а протягивается от бара к бару в буфере:  

int start(){
   int limit=Bars-IndicatorCounted()-1;
      for(int i=limit;i>=0;i--){
         FastDir[i]=FastDir[i+1];
// При прохождении цикла тянем за собой последнее известное положение быстрых линий
         SlowDir[i]=SlowDir[i+1];
// При прохождении цикла тянем за собой последнее известное положение медленных линий

         double ft=iIchimoku(NULL,0,Fast_TenkanPeriod,Fast_KijunPeriod,Fast_SenkouPeriod,MODE_TENKANSEN,i);
         double fk=iIchimoku(NULL,0,Fast_TenkanPeriod,Fast_KijunPeriod,Fast_SenkouPeriod,MODE_KIJUNSEN,i);
         double st=iIchimoku(NULL,0,Slow_TenkanPeriod,Slow_KijunPeriod,Slow_SenkouPeriod,MODE_TENKANSEN,i);
         double sk=iIchimoku(NULL,0,Slow_TenkanPeriod,Slow_KijunPeriod,Slow_SenkouPeriod,MODE_KIJUNSEN,i); 

            if(ft>fk){
// Быстрая Тенкан выше быстрой Киджун
               FastDir[i]=1;
// Фиксируем последнее известное положение быстрых линий, теперь его будем тянуть за собой
            }
            else if(ft<fk){
// Быстрая Тенкан ниже быстрой Киджун
               FastDir[i]=-1;
// Фиксируем последнее известное положение быстрых линий, теперь его будем тянуть за собой 
            }

            if(st>sk){
// Медленна Тенкан выше медленной Киджун
               SlowDir[i]=1;
// Фиксируем последнее известное положение медленных линий, теперь его будем тянуть за собой
            }
            else if(st<sk){
// Медленна Тенкан ниже медленной Киджун
               SlowDir[i]=-1;
// Фиксируем последнее известное положение медленных линий, теперь его будем тянуть за собой 
            } 

         ExtMapBuffer5[i]=0;
// Обнуляем буферы торговых сигналов на случай исчезновения сигнала на нулевом баре
         ExtMapBuffer6[i]=0; 

            if(SlowDir[i]==1){
// Основное направление вверх
               if(FastDir[i]==1){
// Бар смены направления вверх у быстрых линий
                  if(FastDir[i+1]==-1){
                     ExtMapBuffer5[i]=Low[i]-Point*5;
                  }
               }
            }
            else if(SlowDir[i]==-1){
// Основное направление вниз
               if(FastDir[i]==-1){
// Бар смены направления вниз у быстрых линий
                  if(FastDir[i+1]==1){
                     ExtMapBuffer6[i]=High[i]+Point*5;
                  }
               } 
            }
         ExtMapBuffer1[i]=ft;
         ExtMapBuffer2[i]=fk;
         ExtMapBuffer3[i]=st;
         ExtMapBuffer4[i]=sk; 
      }
   return(0);
}

Индикатор не сложный, код прокомментирован, надеюсь все должно быть понятно.

Пересечение линией горизонтальных уровней

Если горизонтальный уровень постоянен, (например пересечение индикатором CCI уровня 0 или 100), нет никаких сложностей, все также как и про определении пересечения двух линий, только вместо значения второй лини используется значение уровня:

double cci1=iCCI(NULL,0,CCIPeriod,CCIPrice,1);
double cci2=iCCI(NULL,0,CCIPeriod,CCIPrice,2);

bool BuySignal=false; 
bool SellSignal=false;

   if(cci1>0){
// CCI сейчас выше уровня
      if(cci2<=0){
// На предыдущем баре выше или равно уровню
        BuySignal=true; 
      }
   }
   if(cci1<0){
// CCI сейчас ниже уровня
      if(cci2>=0){
         SellSignal=true;
// На предыдущем баре ниже или равно уровню
      }
   } 

Бывают индикаторы у которых значение уровня не постоянно, например уровень последнего фрактала и пересечение МА. Уровень как бы горизонтален, лишь изредка меняется. В этом случае, при определении пересечения, новички часто делают ошибку - проверяют положение МА относительно уровня на одном баре, и проверяют значение МА на предыдущем баре, но опять же сравнивают его со значением уровня на текущем баре (думая, что уровень ведь горизонтальный), при такой проверке будут упущены моменты, когда положение МА относительно уровня меняется скорее за изменения уровня, а не за счет изменения значения МА (рис. 6). 


Рис. 6. Нижний уровень (красная линия) пересек МА снизу вверх, но индикатор не отметил это пересечение стрелкой.

С такими индикаторами может быть несколько вариантов: проверять положение МА относительно уровня на текущем баре и проверять положение МА на предыдущем баре со значением уровня тоже на предыдущем баре, или же, проверять, действительно ли уровень горизонтален. В приложении находится индикатор iFrLevMA с различными вариантами проверки.

Приложение

Скачать

<<  вернуться  <<

London
New York
Tokyo
Sygney
 
Рейтинг@Mail.ru