English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
지그재그 지표: 신선한 접근 방식과 새로운 솔루션

지그재그 지표: 신선한 접근 방식과 새로운 솔루션

MetaTrader 5트레이딩 시스템 | 2 9월 2021, 17:08
1 609 0
Sergey Pavlov
Sergey Pavlov

소개

모든 거래자는 주어진 또는 더 큰 진폭의 가격 변동 분석을 위한 ZigZag 지표를 확실히 알고 있습니다. 지그재그 선은 가격 차트의 고점과 저점에 노드가 있는 파선입니다.

이 지표에는 많은 변형이 있습니다. 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16. 하지만 많은 MQL5 프로그램 개발자들은 자신만의 '이상적인' 지그재그를 만들고 싶어 합니다. ZigZag 지표의 주요 단점은 지연, 의심스러운 노드(외부 바)의 잘못된 표시 및 불만족스러운 성능입니다.

제 생각에 가장 우아한 ZigZag 구현은 Yuri Kulikov(Yurich)가 제안했습니다. 그 외에도 "Layman's Notes: ZigZag..." 및 "Show Must Go On, or Once Again about ZigZag"와 같은 아주 좋은 MQL4 글이 있습니다. 많은 수의 출판물을 이용할 수 있어 주제가 상당히 탐구된 것 같습니다. 그러나 그것에 대해 자화하는 것이 있습니다. 이제, 특히 고급 ZigZag 지표를 만들 가능성에 관심을 갖게 되었습니다.

이 문서에서는 Envelopes 지표를 사용하여 고급 ZigZag를 만드는 방법을 설명합니다. 대부분의 ZigZag 노드가 Envelopes 밴드의 범위 내에 있는 일련의 Envelopes에 대한 입력 매개변수의 특정 조합을 찾을 수 있다고 가정합니다.

 

고급 지그재그 지표 생성 방법

우리는 목표를 설정할 것입니다: 현재와 예측된 노드의 두 노드의 좌표를 찾는 것입니다(그림 1). 현재 노드는 아직 좌표를 검색하거나 조정 중인 완료되지 않은 노드입니다. 또한 항상 현재(영) 바에 있습니다. 미래에 있는 동안 예측 노드는 다음 지그재그 노드의 예상 수준을 보여야 합니다.

새로운 ZigZag 노드 예측

그림 1. 새로운 지그재그 노드 예측: 현재 노드와 다음 노드.

그래서 목표가 설정되었고 고급 지표를 구축하기 위한 기초로 Moving Average Envelopes를 사용하는 방법에 대한 아이디어가 있습니다(그림 2). ZigZag 노드와의 편차가 최소인 envelope를 검색합니다. ZigZag 피크와 트로프에 대한 엔벨로프를 별도로 검색해야 하는 것은 매우 논리적으로 보입니다.

지그재그 지표 및 이동 평균 envelope

그림 2. 지그재그 지표 및 이동 평균 envelope.

예측의 통계적 중요성을 높이려면 하나 또는 10개의 Envelopes 지표만 사용하는 대신 입력 데이터가 다른 100개 이상의 지표 풀을 사용해야 합니다. 주요 지표 라인의 평균 기간과 사용된 가격이 다릅니다(고점은 고점, 저점은 저가). 다음 표기법과 공식을 소개하겠습니다.

  • ZZ - 지그재그 지표.
  • ENV - envelope 지표의 메인 라인(iMA 지표와 일치).
  • Envelopes(i) - i번째 바에 있는 Envelopes 지표의 메인 라인 값.
  • ZZ(높음) - 지그재그 피크 값;
  • ZZ(낮음) - 지그재그 저점 값;
  • ENV(High) - 지그재그 피크에 해당하는 엔벨로프 지표의 메인 라인 값.
  • ENV(Low) - 지그재그 저점에 해당하는 Envelopes 지표의 기본 라인 값.
  • n_high - 지그재그 피크의 수.
  • n_low - 지그재그 골 수.

두 개의 지표 풀이 있습니다. 하나는 최고점용이고 다른 하나는 저점용입니다(각각 약 100개의 지표). 우리는 풀의 각 지표에 대한 Envelopes 지표의 메인 라인에서 ZigZag 노드의 편차를 계산하고 위의 공식을 사용하여 각 풀 지표에 대한 편차의 산술 평균을 찾습니다. 다음 그림은 하나의 지표에 대한 메인 라인 ENV에서 식별된 노드 ZZ에 대한 편차 다이어그램을 보여줍니다.

ENV에서 ZZ 노드의 편차 다이어그램

그림 3. ENV에서 ZZ 노드의 편차 다이어그램.

편차의 산술 평균은 엔벨로프 밴드를 표시하기 위해 엔벨로프 지표의 메인 라인을 이동해야 하는 수준을 결정하는 데 사용됩니다. 따라서 상단선을 그리려면 지그재그 피크에서 편차의 산술 평균이 필요하고 Envelopes 지표의 하단선을 그리려면 골에서 편차의 산술 평균이 필요합니다.

특징점을 찾고 ZigZag 노드를 예측하는 데 사용할 envelope의 상단 및 하단 라인입니다. 다시 한 번, Envelopes 지표 세트로 구성된 Envelopes 풀에 관심이 있습니다. 주어진 엔벨로프의 메인 라인에서 지그재그 노드의 편차의 산술 평균은 각 지표에 대해 계산됩니다. 차트에서 풀의 결과 선(상단 및 하단 선)을 그린 후 다음을 볼 수 있습니다.

비행기의 envelope 선

그림 4. 비행기의 envelope 선입니다.

각 라인이 별도의 평면에 있고 모두 함께 표면을 생성한다고 가정하면 위의 그림은 가격 차트 평면에서 각 지표의 투영만을 보여줍니다. 이 선의 3D 이미지는 대략 다음과 같습니다.

3D의 envelope 선

그림 5. 3D의 envelope 라인.

이제 기하학에 대한 간단한 수업을 합시다. Envelopes 지표의 라인 풀이 3D 표면이라고 상상해 보십시오. 가격 차트에 수직인 평면을 가져 와서 현재(0) 바에서 표면을 자릅니다.

결과적으로 우리는 곡선을 나타내는 표면의 단면을 얻습니다(위 그림은 곡선이 직선인 특수한 경우를 보여줍니다). 예측을 수행하려면 계산에 추가로 사용될 곡선의 각 점 좌표를 갖는 것으로 충분합니다.

다음과 같은 단면 특성이 필요합니다. 최대 및 최소 점, 단면의 무게 중심(모든 점 값의 산술 평균). 획득한 특성 포인트는 현재(0) 바에 투영되고 관련 데이터는 이력에 저장됩니다. 이러한 특징점은 현재 및 다음 지그재그 노드의 기반이 됩니다.

엔벨로프 밴드에 대한 검색은 피크와 골에 대해 별도로 수행되므로 결과적으로 두 개의 횡단면을 얻어야 합니다. 하나는 피크에 대한 것이고 다른 하나는 골에 대한 것입니다.

예측을 얻기 위해 가장 가까운 특성점을 사용합니다. 예를 들어 지그재그 피크를 검색할 때 Envelopes 지표의 상단선 표면과 절단면을 말합니다. 반대로, 물마루를 찾기 위해 Envelopes 지표의 하부 선 표면과 절단면의 교차로 인한 단면의 특징점을 취합니다.

 

새로운 지표 테스트

이제 메소드를 정의했으므로 지표를 생성해 보겠습니다. 먼저 ZigZag 지표의 마지막 노드를 찾아 차트에 그립니다. 이를 위해 당면한 작업에 대해 작성된 AdvancedZigZag 클래스를 사용합니다.

//+------------------------------------------------------------------+
//|                                               AdvancedZigZag.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//+------------------------------------------------------------------+
//|                                                 GetExtremums.mqh |
//+------------------------------------------------------------------+
#include <GetExtremums.mqh>   // author of the code Yurich
#property copyright "Copyright 2012, Yurich"
#property link      "https://www.mql5.com/ru/users/Yurich"
//+------------------------------------------------------------------+
//| ZigZag node structure                                            |
//+------------------------------------------------------------------+
struct MqlZigZag
  {
   double            price;   // Node coordinate
   datetime          t;       // Time
  };
//+------------------------------------------------------------------+
//| The AdvancedZigZag class                                         |
//+------------------------------------------------------------------+
class AdvancedZigZag
  {
private:
   MqlRates          rt[];
   dextremum         zz[];
   int               history;
   double            amplitude;
public:
   dextremum         zHL[];
   MqlZigZag         zzH[],zzL[];
   int               Count(const double range);
   int               Read(const int nodes);
                     AdvancedZigZag(const int bars);
                    ~AdvancedZigZag();
  };
//+------------------------------------------------------------------+
//| Class constructor                                                |
//+------------------------------------------------------------------+
AdvancedZigZag::AdvancedZigZag(const int bars)
  {
   history=bars;
   amplitude=0;
  }
//+------------------------------------------------------------------+
//| The Read method of the class                                     |
//+------------------------------------------------------------------+
int AdvancedZigZag::Read(const int nodes)
  {
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zHL,nodes);
   return(cnt);
  }
//+------------------------------------------------------------------+
//| The Count method of the class                                    |
//+------------------------------------------------------------------+
int AdvancedZigZag::Count(const double range)
  {
   amplitude=range;
   CopyRates(NULL,0,TimeCurrent(),history,rt);
   int cnt=GetExtremums(amplitude,rt,zz);
   ArrayResize(zzH,cnt);
   ArrayResize(zzL,cnt);
   int h=0;
   int l=0;
   for(int i=0; i<cnt; i++)
     {
      if(zz[i].type>0)
        {
         zzH[h]=(MqlZigZag)zz[i];
         h++;
        }
      else
        {
         zzL[l]=(MqlZigZag)zz[i];
         l++;
        }
     }
   ArrayResize(zzH,h);
   ArrayResize(zzL,l);
   return(cnt);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
AdvancedZigZag::~AdvancedZigZag()
  {
  }

총 두 가지 방법이 있습니다.

  • Count 방법은 주어진 시간(바 수) 동안 모든 ZigZag 노드를 찾아 정점과 최저점을 분리하여 다양한 배열에 저장합니다. 이렇게 하면 엔벨로프의 분석과 계산을 더 쉽게 수행할 수 있습니다.
  • 읽기 방법은 마지막 노드를 찾아 단일 배열에 저장합니다. ZigZag 지표 시각화를 위해 이 방법이 필요합니다.

GetExtremums 라이브러리(Yury Kulikov)도 노드 검색에 필요합니다.

Expert Advisor에서 지표를 고려하도록 합시다. 지표가 아닌 Expert Advisor가 필요한 이유는 무엇입니까? 물론 취향의 문제지만 저는 그게 더 효율적인 것 같습니다. Expert Advisor의 그래픽 기능은 의심할 여지 없이 약하지만 동일한 기호 지표가 단일 스트림에서 작동하는 반면 모든 EA는 자체 별도 스트림에서 작동하므로 성능이 향상됩니다. 코드를 살펴보겠습니다.

//+------------------------------------------------------------------+
//|                                                   two_Comets.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#include <AdvancedZigZag.mqh>
//--- Depth of history for the indicator calculation
input int      depth_stories=5000;  // Depth stories for calculating the indicator [bars]
//--- Minimum ZigZag amplitude value
input int      amplitude=100;        // The minimum value of the amplitude of the indicator [points]
//--- Declaring the class
AdvancedZigZag Azz(depth_stories);
//---
#define NUMBER_MA   227
#define START_MA    5
//--- macros
#define SIZE(i)                     (double)i*0.3<1?1:(int)(i*0.25)
#define ObjF1                       ObjectSetString(0,name,OBJPROP_FONT,"Wingdings")
#define ObjF2                       ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER)
#define ObjF3(T)                    ObjectSetInteger(0,name,OBJPROP_TIME,T)
#define ObjF4(P)                    ObjectSetDouble(0,name,OBJPROP_PRICE,P)
#define ObjF5(size)                 ObjectSetInteger(0,name,OBJPROP_FONTSIZE,size)
#define ObjF6(code)                 ObjectSetString(0,name,OBJPROP_TEXT,CharToString(code))
#define ObjF7(clr)                  ObjectSetInteger(0,name,OBJPROP_COLOR,clr)
#define ObjF8                       ObjectSetInteger(0,name,OBJPROP_COLOR,clrMagenta)
#define ObjF9                       ObjectSetInteger(0,name,OBJPROP_WIDTH,3)
#define ObjF10                      ObjectSetInteger(0,name,OBJPROP_BACK,true) 
#define ObjFont                     ObjF1;ObjF2;
#define ObjCoordinates(T,P)         ObjF3(T);ObjF4(P);
#define ObjProperty(size,code,clr)  ObjF5(size);ObjF6(code);ObjF7(clr);
#define ObjZZ                       ObjF8;ObjF9;ObjF10;
//---
double      MA[1],sumHi[NUMBER_MA],sumLo[NUMBER_MA];
int         handle_MA_H[NUMBER_MA],handle_MA_L[NUMBER_MA];
datetime    t[1];
int         H,L;
int         t_min,t_max;
int         err=-1;
double      sumH[2],maxH[2],minH[2];
double      sumL[2],maxL[2],minL[2];
string      name;
int         count;
int         shift;
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   shift=PeriodSeconds()/30;
//--- calculation of ZigZag nodes using historical data
   Azz.Count(amplitude*Point());
   H=ArraySize(Azz.zzH);
   L=ArraySize(Azz.zzL);
   if(H<30 || L<30)
     {
      Print("Not enough data to calculate ZigZag nodes: "+
            "increase the depth of history; "+
            "or decrease the amplitude value.");
      return(-1);
     }
//---
   for(int i=0; i<NUMBER_MA; i++)
     {
      handle_MA_H[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_HIGH);
      handle_MA_L[i]=iMA(NULL,0,i+START_MA,0,MODE_SMA,PRICE_LOW);
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
   ObjectsDeleteAll(0,-1,-1);
   for(int i=0; i<NUMBER_MA; i++)
     {
      IndicatorRelease(handle_MA_H[i]);
      IndicatorRelease(handle_MA_L[i]);
     }
//---
  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+

void OnTick()
  {
//--- get the current bar's opening time value
   CopyTime(NULL,0,0,1,t);
//--- ZigZag: last 7 nodes
   count=Azz.Read(7);
   for(int i=1; i<count; i++)
     {
      name="ZZ"+(string)i;
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,clrRed);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,10);
      ObjectSetInteger(0,name,OBJPROP_BACK,true);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[i-1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[i-1].time);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,Azz.zHL[i].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,Azz.zHL[i].time);
     }
//--- check for integrity of preliminary calculations
   if(err<0)
     {
      //--- calculate the sums of deviations of the nodes from MA for ZigZag peaks
      ArrayInitialize(sumHi,0.0);
      for(int j=H-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_H[i],0,Azz.zzH[j].t,1,MA);
            if(err<0) return;
            sumHi[i]+=Azz.zzH[j].price-MA[0];
           }
        }
      //--- calculate the sums of deviations of the nodes from MA for ZigZag troughs
      ArrayInitialize(sumLo,0.0);
      for(int j=L-1; j>=0; j--)
        {
         for(int i=0; i<NUMBER_MA; i++)
           {
            err=CopyBuffer(handle_MA_L[i],0,Azz.zzL[j].t,1,MA);
            if(err<0) return;
            sumLo[i]+=MA[0]-Azz.zzL[j].price;
           }
        }
     }
  }
//+------------------------------------------------------------------+

여기서 몇 가지를 명확히 해야 합니다.

  • iEnvelopes 지표는 iMA 지표로 대체됩니다. 거기에는 거짓이나 오해의 소지가 없습니다. 문제는 iEnvelopes의 메인 라인이 iMA와 일치한다는 것입니다! 따라서 이동 평균 지표를 사용하는 것이 더 편리합니다.
  • 우리는 각각 227개의 라인으로 구성된 2개의 이동 평균 풀을 사용하여 총 454개의 iMA 지표를 만듭니다! 많거나 적습니까? 기본적으로 큰 숫자입니다. 그러나 우선 필요한 경우 지표 수를 변경할 수 있으며 두 번째로 통계가 필요합니다. 12개의 노드에 대한 envelope 검색의 요점은 무엇입니까? 우리는 적어도 100명이 필요합니다.
  • 지표 값은 OnInit() 대신 OnTick() 블록에 로드됩니다. 데이터 로드 블록이 OnInit()에 배치된 경우 일부 데이터 로드가 늦어질 수 있으며 결과적으로 지표가 정확하고 완전히 계산되지 않을 가능성이 높습니다. 계산을 위한 모든 데이터를 얻은 후 err 변수 값은 양수이고 이 블록은 작업에서 제외됩니다.

따라서 결과 지표는 마지막 7개의 ZigZag 노드를 표시하고 주어진 이력에 대한 다른 모든 노드의 좌표를 계산합니다(그림 6). 계산은 한 번만 수행되며 계산된 데이터를 추가로 사용합니다. 물론 데이터를 정기적으로 업데이트할 수 있는 방식으로 구현할 수 있지만 이 문서에서는 단일 패스로 유지합니다.

지그재그 지표(7노드)

그림 6. 지그재그 지표(7개 노드).

또한 Envelopes 지표의 표면 단면을 플롯해 보겠습니다. 이를 위해 OnTick() 메소드에 다음을 추가합니다.

//--- PEAKS
   sumH[0]=0.0;
   maxH[0]=0.0;
   minH[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_H[i],0,t[0],1,MA);
      double envelope=MA[0]+sumHi[i]/H;
      if(i==0 || envelope<minH[0])
        {
         minH[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxH[0])
        {
         maxH[0]=envelope;
         t_max=SIZE(i);
        }
      sumH[0]+=envelope;
      name="H"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]-(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrBlue)
     }
//--- TROUGHS
   sumL[0]=0.0;
   maxL[0]=0.0;
   minL[0]=0.0;
   for(int i=0; i<NUMBER_MA; i++)
     {
      CopyBuffer(handle_MA_L[i],0,t[0],1,MA);
      double envelope=MA[0]-sumLo[i]/L;
      if(i==0 || envelope<minL[0])
        {
         minL[0]=envelope;
         t_min=SIZE(i);
        }
      if(envelope>maxL[0])
        {
         maxL[0]=envelope;
         t_max=SIZE(i);
        }
      sumL[0]+=envelope;
      name="L"+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjFont
      ObjCoordinates(t[0]+(NUMBER_MA-i*2)*shift,envelope)
      ObjProperty(SIZE(i),158,clrGold)
     }
초보 프로그래머를 위한 참고 사항: Peaks 및 Troughs 블록 끝에 있는 연산자에는 ';'가 없습니다. 문자열의 끝에서. 실수나 오타가 아닙니다. 그것들은 매크로입니다(선언된 데이터 섹션 참조) - 매우 유용합니다! 프로그램에서 사용하는 것이 좋습니다.

엔벨로프 라인에 의해 형성된 표면의 횡단면 포인트를 식별하기 위해 포인트의 크기가 다양합니다. 엔벨로프 지표의 메인 라인의 평균 주기가 클수록 포인트가 커집니다(그림 7). 또한 단면은 현재(0) 바를 통과하는 수직 축을 중심으로 서로 다른 방향으로 회전합니다. 피크는 오른쪽으로 90도이고 골은 왼쪽으로 90도입니다.

이제 가격 차트 평면에서 볼 수 있습니다. 처음에는 절단면(그림 5)에 놓여 있어 관찰할 수 없었습니다. 우리는 그것들의 모양에 대해 전혀 알지 못하고 우리 자신으로만 상상할 수 있었습니다. 단면 라인이 매우 독특한 모양으로 밝혀졌습니다. 이것은 또한 그래픽 분석의 편의를 위해 수행됩니다. 시각적으로 횡단면은 두 개의 날아다니는 혜성과 비슷합니다.

envelope 지표 풀의 단면

그림 7. Envelopes 지표 풀의 단면입니다.

단면 특성 계산을 진행해 보겠습니다. 최대값과 최소값, 무게 중심(산술 평균)입니다. 결과 값은 현재 바에 포인트로 표시되며 포인트 크기는 관련 특성의 크기에 해당합니다. 또한 추가 분석을 위해 기록을 저장합니다. 따라서 기존 코드에 다음을 추가합니다.

//--- PEAKS

...

//--- midi
   string str=(string)t[0];
   name="Hmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumH[0]/NUMBER_MA)
   ObjProperty(10,119,clrBlue)
//--- max
   name="Hmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxH[0])
   ObjProperty(t_max,158,clrBlue)
//--- min
   name="Hmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minH[0])
   ObjProperty(t_min,158,clrBlue)

...

//--- TROUGHS

...

//--- midi
   name="Lmidi"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],sumL[0]/NUMBER_MA)
   ObjProperty(10,119,clrGold)
//--- max
   name="Lmax"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],maxL[0])
   ObjProperty(t_max,158,clrGold)
//--- min
   name="Lmin"+str;
   ObjectCreate(0,name,OBJ_TEXT,0,0,0);
   ObjFont
   ObjCoordinates(t[0],minL[0])
   ObjProperty(t_min,158,clrGold)

이제 그래픽으로 나타낼 때 어떻게 보이는지 봅시다.

단면 특성

그림 8. 단면 특성: 최대값과 최소값, 피크와 골에 대해 별도로 표시된 무게 중심.

고급 ZigZag 노드를 찾고 플로팅하여 마지막 마무리 작업을 추가하기만 하면 됩니다. 다음을 추가하여 코드를 개선합니다.

//--- ZigZag: advanced nodes
   if(Azz.zHL[0].type>0) // peak
     {
      ObjectDelete(0,"MIN");
      ObjectDelete(0,"MINfuture");
      name="MAX";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=minH[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value>minH[0])
        {
         price=sumH[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value>sumH[0]/NUMBER_MA)
        {
         price=maxH[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MAXfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxL[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price<maxL[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumL[0]/NUMBER_MA);
      if(price<sumL[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,minL[0]);
     }
   if(Azz.zHL[0].type<0) // trough
     {
      ObjectDelete(0,"MAX");
      ObjectDelete(0,"MAXfuture");
      name="MIN";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,Azz.zHL[1].value);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,Azz.zHL[1].time);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]);
      double price=maxL[0];
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
      if(Azz.zHL[0].value<maxL[0])
        {
         price=sumL[0]/NUMBER_MA;
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      if(Azz.zHL[0].value<sumL[0]/NUMBER_MA)
        {
         price=minL[0];
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,price);
        }
      //--- into the future
      name="MINfuture";
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjZZ
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,price);
      ObjectSetInteger(0,name,OBJPROP_TIME,0,t[0]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,minH[0]);
      ObjectSetInteger(0,name,OBJPROP_TIME,1,t[0]+NUMBER_MA*shift);
      if(price>minH[0])
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,sumH[0]/NUMBER_MA);
      if(price>sumH[0]/NUMBER_MA)
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,maxH[0]);
     }

따라서 새로운 노드의 위치를 ​​예측하는 새로운 고급 ZigZag 지표가 있습니다(그림 9). 노드 자체는 최대, 최소 및 무게 중심과 같은 특징적인 단면 지점에 있습니다. 지표의 작업 제목은 "두 개의 혜성"입니다.

미래에 있는 다음 노드의 완료 시간은 아직 알 수 없음에 유의해야 합니다. 기본적으로 우리는 하나의 노드 좌표, 즉 가격만 예측할 수 있습니다.

예측된 지그재그 노드

그림 9. 고급 ZigZag 지표는 현재 및 다음 노드를 예측합니다.

 

결과 분석 및 개발자 권장 사항

지표 관찰은 다음을 보여줍니다.

  1. 예측 노드에서 지그재그 노드 좌표의 편차는 허용 범위 내에 있습니다. 수많은 노드가 해당 단면의 그림자에 있습니다. 이것은 확실히 질적 평가일 뿐입니다. 더 정확한 결과는 다음 글에서 따를 것입니다.
  2. envelope 라인의 횡단면은 시장 행동과 예상되는 가격 모멘텀을 보여줍니다! 평균 주기가 가장 작은(크기가 가장 작은) 점으로 구성된 혜성 꼬리에 주목하세요. 가격 방향으로 진행됩니다. 혜성의 꼬리는 가장 복잡한 방식으로 구부러지고 반대 방향으로 많이 돌수록 추세 변화를 볼 기회가 커집니다. 진폭이 다른 여러 시간 프레임에서 지표의 동작을 관찰하기만 하면 됩니다. 이건 아주 흥미롭습니다!
  3. 단면의 특징적인 점은 가격 움직임에 강한 저항을 나타낼 수 있는 선을 형성합니다. 따라서 그들은 지지선과 저항선으로 간주될 수 있습니다.
  4. 단면의 무게 중심점이 앞서면(그림 9의 피크), 이는 상승 추세의 존재를 나타냅니다.

결과적으로 우리가 얻은 것은 거래 전략에서 시도할 수 있는 매우 흥미로운 지표입니다!

 

결론

  • 글에서 검토한 ZigZag 지표 노드를 예측하는 방법을 통해 "Two Comets"라는 새로운 지표를 만들 수 있었습니다.
  • 고급 ZigZag는 예측일 뿐이지만 새 노드의 가능한 좌표를 보여줍니다.
  • 글에서 고려한 알고리즘은 유사한 고급 지표를 표시하는 데 사용할 수 있으며 반드시 지그재그 지표일 필요는 없습니다 (예: 프랙탈 또는 세마포어 지표).
  • 초보자 MQL5 프로그래머는 반복되는 코드의 양을 줄이기 위해 프로그램에서 매크로를 만드는 방법을 보는 것이 흥미로울 수 있습니다.

MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/646

파일 첨부됨 |
advancedzigzag.mqh (3.54 KB)
getextremums.mqh (5.24 KB)
two_comets.mq5 (10.16 KB)
MQL5 Cookbook: 트리플 스크린 전략에 기반한 거래 시스템을 위한 프레임워크 개발 MQL5 Cookbook: 트리플 스크린 전략에 기반한 거래 시스템을 위한 프레임워크 개발
이 글에서는 MQL5의 Triple Screen 전략을 기반으로 하는 거래 시스템의 프레임워크를 개발할 것입니다. Expert Advisor는 처음부터 개발되지 않습니다. 대신에 이미 우리의 목적에 실질적으로 부합하는 이전 글 "MQL5 Cookbook: 지표를 사용하여 Expert Advisors에서 거래 조건 설정"에서 프로그램을 수정하기만 하면 됩니다. 따라서 이 글에서는 기성 프로그램의 패턴을 쉽게 수정할 수 있는 방법도 보여줍니다.
MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정 MQL5 Cookbook: 지표를 사용하여 Expert Advisor의 거래 조건 설정
이 글에서는 MQL5 Cookbook 시리즈의 이전 글에서 작업한 Expert Advisor를 계속 수정할 것입니다. 이번에는 Expert Advisor가 포지션 개방 조건을 확인하는 데 사용할 값의 지표로 향상됩니다. 재미를 더하기 위해 외부 매개변수에 드롭다운 목록을 만들어 세 가지 거래 지표 중 하나를 선택할 수 있습니다.
MQL5 Cookbook: 다중 통화 Expert Advisor - 간단하고 깔끔하며 빠른 접근 MQL5 Cookbook: 다중 통화 Expert Advisor - 간단하고 깔끔하며 빠른 접근
이 글에서는 다중 통화 Expert Advisor에 적합한 간단한 접근 방식의 구현에 대해 설명합니다. 이는 동일한 조건에서 각 기호에 대해 다른 매개변수를 사용하여 테스트/거래를 위해 Expert Advisor를 설정할 수 있음을 의미합니다. 예를 들어, 필요한 경우 코드를 약간 변경하여 추가 기호를 추가할 수 있는 방식으로 두 개의 기호에 대한 패턴을 만들 것입니다.
MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리 MQL5 Cookbook: 거래의 역사 및 직위 속성 가져오기를 위한 기능 라이브러리
포지션 속성에 대한 이전 글에서 제공한 정보를 간략하게 요약할 시간입니다. 이 글에서는 거래 내역에 액세스한 후에만 얻을 수 있는 속성을 가져오는 몇 가지 추가 함수를 만듭니다. 또한 보다 편리한 방법으로 포지션 및 기호 속성에 액세스할 수 있는 데이터 구조에 익숙해질 것입니다.