English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
채널 그리기 - 내부 및 외부 보기

채널 그리기 - 내부 및 외부 보기

MetaTrader 5지표 | 4 8월 2021, 16:44
121 0
Dmitriy Skub
Dmitriy Skub

소개

채널이 시장 분석과 이동 평균 이후 거래 결정을 위한 가장 인기있는 도구라고 말하면 과장이 아닐 것 같습니다. 채널에 관한 시리즈의 첫 번째 글에서는 클라이언트 터미널의 화면에 세 극값으로 설정된 채널을 그리는 표시기의 수학적 기초와 이론적 구현에 대해 논의할 것입니다.

첫눈에 채널을 그리는 것은 초등학교에서 가르치는 직선 방정식을 기반으로 하기 때문에 쉬운 작업인 것 같습니다. 그러나 클라이언트 터미널에서의 실제 구현에는 직접 대답 할 수 없는 많은 질문이 포함됩니다.

극한 설정을 구성하고 변경 사항을 가장 잘 추적하는 방법은 무엇입니까? 중간 부분이 누락된 바에 있는 경우 수행 할 작업과 채널을 그리는 방법은 무엇입니까? 채널의 왼쪽 극값이 금요일이고 오른쪽이 월요일이면 바가 없는 휴일이 그 사이에 있으면 어떨까요? 채널 경계의 현재 값을 어떻게 얻을 수 있습니까?

이러한 질문과 몇 가지 다른 질문은 채널에 대한 일련의 글 중 첫 번째 글에서 답변합니다. 여기에서 표준 클래스와 객체 지향 접근 방식을 사용하여 세 가지 지정된 극값으로 채널 그리기 구현을 찾을 수도 있습니다. 표시기 형태로 채널 드로어를 구현할 것입니다.


극한 설정

사실, 차트에서 채널의 포지션은 최소 3 개의 극값에 의해 결정됩니다. 극한값을 정의하면 이 값을 받아 들일 수 있습니다 : 주어진 범위에서 함수의 최대 또는 최소 값입니다. 극한에 도달하는 지점을 극한 지점이라고 합니다. 각각 최소값에 도달하면 극한 점을 최소점이라고 하고 최대 값이면 최대 점이라고 합니다.

수학적 분석은 로컬 극한 (각각 최소 및 최대)이라는 또 다른 용어를 정의합니다. 최대 (최소) 포인트에서 함수 값은 모든 인접 포인트의 값보다 크거나 작습니다. 정의는 Wikipedia (러시아어에서 번역됨)에서 가져 왔습니다.

채널을 그리기 위해 우리는 극값이 필요합니다. 수학 공식에 들어가지 않고 그래픽으로 보여 봅시다. 아래의 그림 1에는 빨간색 가격 수준으로 표시된 세 개의 로컬 극한값이 있습니다. 직사각형 점은 두 개의 최대 값과 하나의 최소값을 표시합니다.

그림 1. 로컬 극한의 예

그림 1. 로컬 극한의 예

차트에 기존 극값이 모두 표시되어 있는 것은 아니며 가장 중요한 부분만 표시됩니다. 촛대 또는 바 차트의 경우 극값을 정의하는 데 "프랙탈" 용어를 사용하는 것이 편리합니다. 왼쪽과 오른쪽에 인접한 여러 바가 엄격하게 내림차순 또는 오름차순 일 때 (그림 1 참조).

자동 채널 드로어를 만들 목적이 없으므로 그림과 같이 극한 포지션이 설정됩니다. 1 - 시간 및 가격 축의 포지션. 이러한 목적에 가장 적합한 것은 MetaTrader 5 클라이언트 터미널의 특수 그래픽 개체인 가격 라벨입니다. 가격 레이블에는 시간 및 가격 좌표 속성이있어 차트에서 극한 지점을 확실히 식별 할 수 있습니다.


극값을 저장하는 객체는 TExtremum 클래스입니다.

가장 먼저해야 할 일은 극한을 저장하기 위한 컨테이너 클래스와 극한 그룹을 조작하기 위한 클래스를 개발하는 것입니다. 가능한 한 터미널에 포함 된 표준 클래스를 사용할 것이므로 TExtremum 클래스는 CObject 표준 클래스에서 상속됩니다. 클래스에 대한 설명은 다음과 같습니다.

class TExtremum : public CObject
{
private:
  datetime  extr_datetime;              // data/time in an extremum point
  double    extr_price;                 // price in an extremum point
        
protected:
  virtual int  Compare(const CObject* _node, int _mode = 0) const;

public:
  void      TExtremum();               // constructor
  void      ~TExtremum();              // destructor
  void      SetExtremum(datetime _time, double _price);  // change date/time and price in an extremum point
  void      SetDateTime(datetime _time);                 // change date/time in an extremum point
  void      SetPrice(double _price);  // change price in an extremum point

public:
  datetime  GetDateTime() const;      // get date/time in an extremum point
  double    GetPrice() const;         // get price in an extremum point

public:
  virtual bool  SaveExtremum(string _dt_name, string _p_name);  // save extremum
  virtual bool  LoadExtremum(string _dt_name, string _p_name);  // load extremum
  virtual bool  DeleteExtremum(string _dt_name, string _p_name);// delete extremum
};

대부분의 방법은 사소하며 구현에 주의를 기울일 가치가 없습니다. 우리가 계속해야 할 것은 TExtremum::Compare 메소드입니다. 이 메소드는 CObject 클래스에서 선언되며 목록 내에서 정렬하는데 사용됩니다. 우리는 다음과 같은 방식으로 구현했습니다.

//---------------------------------------------------------------------
//  Comparing two extremums by time:
//---------------------------------------------------------------------
int TExtremum::Compare(const CObject* _node, int _mode = 0) const
{
  datetime  temp = ((TExtremum* )_node).GetDateTime();
  datetime  curr = GetDateTime();
  if(curr > temp)
  {
    return(_mode > 0 ? 1 : -1);
  }
  else if(curr < temp)
  {
    return(_mode > 0 ? -1 : 1);
  }

  return(0);
}

여기서 _mode 매개 변수는 정렬 방향을 설정하기 위한 것입니다. 0보다 크면 정렬은 직접 (오름차순), 그렇지 않으면 역 (내림)입니다.

그 외에도 극한값을 저장/로드하기 위한 두 가지 방법이 있습니다. 우리의 극한값을 전역 변수에 저장합시다. 그 방법은 다음과 같습니다.

//---------------------------------------------------------------------
//  Save extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::SaveExtremum(string _dt_name, string _p_name)
{
  datetime  dt_result = GlobalVariableSet(_dt_name, (double)extr_datetime);
  datetime  p_result = GlobalVariableSet(_p_name, (double) extr_price);
  if(dt_result != 0 && p_result != 0)
  {
    return(true);
  }

  return(false);
}

//---------------------------------------------------------------------
//  Load extremum (date/time):
//---------------------------------------------------------------------
bool TExtremum::LoadExtremum(string _dt_name, string _p_name)
{
  double  dt_temp, p_temp;
  bool    result = GlobalVariableGet(_dt_name, dt_temp);
  result &= GlobalVariableGet(_p_name, p_temp);
  if(result != false)
  {
    extr_datetime = (datetime)dt_temp;
    extr_price = p_temp;
    return(true);
  }

  return(false);
}

성공적 실행의 경우 전역 변수 TExtremum::LoadExtremumTExtremum::SaveExtremum에서 읽고 쓰는 두 가지 방법은 'true'를 반환합니다.


극한 목록 조작 - 클래스 TExtremumList

시간별로 극값을 저장하고 정렬해야 하므로 표준 클래스 CList에서 TExtremumList 클래스를 상속해야 합니다. 이 상속으로 우리는 극한의 수와 유형에 제한이 없는 보편적인 조작자를 얻습니다. 이를 통해 그려지는 채널 수를 추가로 확장할 수 있습니다. 예를 들어, 여러 극값에 의한 비선형 회귀인 경우 채널 그림을 추가할 수 있습니다.

이 클래스에 대한 설명은 다음과 같습니다.

class TExtremumList : public CList
{
private:
  string              channel_prefix;     // channel name (prefix)
  ENUM_TIMEFRAMES      chart_timeframe;    // current timeframe
  string              chart_symbol;       // work symbols of the chart

protected:
  string    MakeDTimeName(int _nmb);     // get name for saving/reading data/time of an extremum
  string    MakePriceName(int _nmb);     // get name for saving/reading price of an extremum

public:
  void      TExtremumList();             // конструктор
  void     ~TExtremumList();             // деструктор
  void     SetChannelParams(string _pref, string _symbol = NULL, ENUM_TIMEFRAMES _curr_tf = PERIOD_CURRENT);
  void     AddExtremum(datetime _time, double  _price);
  void     DeleteAllExtremum();
  void     SaveExtremumList();
  void     LoadExtremumList();
  int      FindExtremum(datetime _dt);  // search extremum by specified time

public:
  datetime GetDateTime(int _index);
  double   GetPrice(int _index);
};

클래스의 주요 메소드는 TExtremumList::AddExtremum입니다. 목록에 새 극값을 추가하기 위한 것입니다. 목록에 있는 극한값을 극한 시점별로 정렬하는 작업은 추가 후 수행됩니다. 이 메소드의 코드는 다음과 같습니다.

void TExtremumList::AddExtremum(datetime _time, double  _price)
{
//  Create extremum:
  TExtremum*    extr = new TExtremum();
  extr.SetExtremum(_time, _price);

//  Add it in the list:
  Add(extr);

//  Sort:
  Sort(1);
}

여기에는 기본 클래스의 다음 메소드가 사용됩니다. CList::Add - 목록에 새 요소를 추가하고 CList::Sort - 목록의 요소를 정렬합니다. TExtremum::Compare 메소드는 CList::Sort에서 사용됩니다.

TExtremumList::FindExtremum 목록에서 주어진 시간으로 극값을 검색하는 방법을 살펴보겠습니다. 메소드 코드는 다음과 같습니다.

int TExtremumList::FindExtremum(datetime _dt)
{
  int           k = 0;
  TExtremum*    extr = (TExtremum*)(GetFirstNode());
  while(extr != NULL)
  {
    if(extr.GetDateTime() == _dt)
    {
      return(k);
    }
    extr = (TExtremum*)(GetNextNode());
  }
  return(-1);                     // extremum not found
}

여기에서는 기본 클래스의 다음 메소드가 사용됩니다. CList::GetFirstNode - 목록의 첫 번째 요소를 가져옵니다 (목록이 비어 있으면 0 포인터를 반환합니다. ) 및 CList::GetNextNode - 목록의 다음 요소를 가져옵니다 (다음 요소가 없고 목록이 끝나면 제로 포인터가 반환 됨).

노트:

클래스 목록 CList의 내부 데이터에 현재 요소에 대한 포인터가 있습니다. 이 포인터는 목록에서 이동하는 메소드 (CList::GetFirstNode, CList::GetNextNode, CList::GetPrevNode, 등.)를 호출 할 때 변경됩니다. 이전에 이러한 메소드가 호출되지 않은 경우 현재 요소에 대한 핀터는 첫 번째 요소를 가리킵니다.

주어진 시간의 극한값이 성공적으로 발견되면 발견된 요소의 TExtremumList::FindExtremum 메소드 인덱스입니다. 그러한 요소가 없으면 -1을 반환합니다.

TExtremum::MakeDTimeNameTExtremum::MakePriceName 메소드는 보조입니다. 극값을 저장하고 읽을 때 사용되는 전역 변수의 이름을 가져오기 위한 것입니다. 이러한 메소드는 다음과 같이 구현됩니다.

string TExtremumList::MakeDTimeName(int _nmb)
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_DTime_Extr", _nmb);
  return(name);
}

string TExtremumList::MakePriceName( int _nmb )
{
  string    name;
  StringConcatenate(name, channel_prefix, "_", channel_symbol, "_", channel_timeframe, "_Price_DTime_Extr", _nmb);
  return(name);
}

얻은 이름의 : "MainChannel_EURUSD_5_DTime_Extr1 ". 이러한 이름은 채널 MainChannel (기존 이름)의 임시 극한 지점, EURUSD 기호, 타임 프레임 5M 및 극한 번호 1에 해당합니다. 극값에 대한 숫자는 1부터 시작하여 시간 오름차순으로 할당됩니다. 실제로 오름차순 정렬 목록에서 1로 이동한 인덱스입니다.

터미널에 저장된 세 극값의 예는 아래 그림과 같습니다.

그림 2. 전역 변수에 저장된 극한

그림 2. 전역 변수에 저장된 극한

위에 설명된 클래스는 ExtremumClasses.mqh 파일의 문서에 첨부됩니다.


극한을 수동으로 설정하기 위한 표시기 - ExtremumHandSet

글쎄, 우리는 수동 모드에서 극값의 포지션을 ​​설정하는 첫 번째 지표를 개발하는 데 필요한 모든 것을 갖추고 있습니다. 표시기의 코드는 ExtremumHandSet.MQ5 파일의 글에 첨부됩니다. 그림을 자세히 분석해 봅시다.

먼저 화면에서 보고 싶은 것을 시각적으로 상상해 봅시다.

그림 3. 극값 설정 표시기

그림 3. 극값 설정 표시기

왼쪽 가격 레이블을 사용하여 차트의 시간 및 가격 축에 극값 포지션을 설정합니다. 표시기는 차트에서 해당 레이블의 포지션을 ​​결정하고 화면에 임시 극한 점을 표시하고 위에서 설명한 형식으로 클라이언트 터미널의 전역 변수에 저장해야 합니다. 또한 지표는 차트에서 가격 레이블의 이동을 추적하고 로드된 임시 최고점을 수정해야 합니다.

차트의 가격 레이블 이동 추적은 1 초에 한 번 수행됩니다. 이렇게하면 시스템이 견적서 및 근무일/비 근무일에 독립적이 될 수 있습니다.

먼저 필요한 라이브러리를 연결해보겠습니다.

//---------------------------------------------------------------------
//  Included libraries:
//---------------------------------------------------------------------
#include  <TextDisplay.mqh>
#include  <ExtremumClasses.mqh>

첫 번째 라이브러리에는 화면에 텍스트 정보를 표시하는 구성을위한 클래스가 포함되어 있습니다 (다음을 봐주세요. "표준 라이브러리 클래스를 사용하여 나만의 Market Watch 만들기" 글). 이를 사용하여 임시 극한점 값을 표시합니다.

그런 다음 표시기의 입력 매개 변수를 추가합니다 (여기에서는 주요 매개 변수만 설명합니다).

input string  PrefixString = "MainChannel";
//---------------------------------------------------------------------
input color   ExtremumPointColor = Yellow;
//---------------------------------------------------------------------
input bool    ShowInfo = true;

첫 번째 매개 변수 PrefixString은 극값을 쓰거나 읽을 때 전역 변수의 이름을 구성하는 데 사용되는 접두사를 설정합니다. 또한 단일 차트에서 여러 지표를 사용할 수 있습니다. 할 일은 다른 접두사를 설정하는 것 뿐입니다.

ExtremumPointColor 매개 변수는 극값의 포지션을 ​​결정하는 왼쪽 가격 레이블의 색상을 설정합니다. 가격 레이블은 지정된 색상이어야 합니다. 이 일치는 표시기에서 확인됩니다. 매개 변수가 다른 레이블은 무시됩니다.

ShowInfo 매개 변수는 지정된 극한 지점에 대한 텍스트 정보를 화면에 표시하는 것을 제어합니다.

다음으로 정보를 표시하고 극값을 조작하기위한 개체를 만들어 보겠습니다.

TableDisplay    TitlesDisplay;    // displaying information on the screen
//---------------------------------------------------------------------
TExtremumList*  PrevExtr_List;    // list of previous extremums
TExtremumList*  CurrExtr_List;    // list of current extremums
TExtremumList*  NewExtr_List;     // list of new extremums

이러한 개체는 다음에서 초기화됩니다.

PrevExtr_List = new TExtremumList();
PrevExtr_List.SetChannelParams(PrefixString, Symbol(), Period());
PrevExtr_List.LoadExtremumList();

CurrExtr_List = PrevExtr_List;

NewExtr_List = new TExtremumList();
NewExtr_List.SetChannelParams(PrefixString, Symbol(), Period());

PrevExtr_List 목록에서 TExtremumList::LoadExtremumList 메소드를 사용하여 전역 변수에서 극값을 로드합니다. 이 목록은 새 항목과 비교하기 위한 극한값을 저장하며, 화면에서 가격 레이블을 드래그 할 때 차트에서 읽습니다.

CurrExtr_List 목록은 현재 목록으로 사용되며 현재 극값을 저장합니다. 처음에는 전역 변수에서 읽은 극값만 있으므로 실제 변수로 간주됩니다.

NewExtr_List 목록에서 차트에 있는 새로운 극값을 작성합니다.

표시기에서 사용되는 주요 기능을 살펴 보겠습니다. 첫 번째 함수 FindExtremumPoints는 극값의 포지션을 ​​결정하는 가격 레이블의 매개 변수를 읽고 확인하는 데 사용됩니다.

bool FindExtremumPoints(long _chart_id)
{
  string  name;

//  1. Search for the total number of objects with specified parameters and write them to the list:
  int total_objects = ObjectsTotal(_chart_id, -1, OBJ_ARROW_LEFT_PRICE);
  if(total_objects <= 0)
  {
    return(false);
  }

  NewExtr_List.Clear();
  for(int i = 0; i < total_objects; i++)
  {
    name = ObjectName(_chart_id, i, -1, OBJ_ARROW_LEFT_PRICE);

    if( IsGraphicObjectGood(_chart_id, name, OBJ_ARROW_LEFT_PRICE, ExtremumPointColor) == true)
    {
      NewExtr_List.AddExtremum(ObjectGetInteger( _chart_id, name, OBJPROP_TIME),
                               ObjectGetDouble(_chart_id, name, OBJPROP_PRICE));
    }
  }

//  2. If three extremums are found, we can try to draw a channel:
  if(NewExtr_List.Total() == 3)
  {

//  Save the list of new extremums:
    NewExtr_List.SaveExtremumList();
    return(true);
  }

  NewExtr_List.Clear();
  return(false);
}

먼저 TExtremumList::Clear 메소드를 호출하여 NewExtr_List 목록을 지운 다음 지정된 매개 변수를 가진 발견된 모든 극한 지점을 여기에 추가합니다. 발견 된 포인트의 수가 3 개이면 목록이 전역 변수에 저장되고 함수는 'true'를 반환합니다.

다른 함수 CheakExtremumMoving은 차트에서 극한 지점의 이동을 추적합니다. 차트의 시간축을 따라 적어도 on point를 이동하면이 함수는 'true'를 반환합니다.

코드는 다음과 같습니다.

//---------------------------------------------------------------------
//  Check whether extremums have been moved on the screen:
//---------------------------------------------------------------------
bool CheakExtremumMoving()
{
  if(FindExtremumLines(0) == true)
  {
    int  count = NewExtr_List.Total();
    int  index;
    for(int i = 0; i < count; i++)
    {
      index = CurrExtr_List.FindExtremum(NewExtr_List.GetDateTime(i));

//  If a new extremum is found:
      if(index == -1)
      {
        PrevExtr_List = CurrExtr_List;
        CurrExtr_List = NewExtr_List;
        return(true);
      }
    }
    CurrExtr_List = PrevExtr_List;
  }

  return(false);
}

수동 모드에서 극한 점을 설정하는 방법을 고려했습니다. 이 프로세스를 제어하고 전역 변수에 포인트를 쓸 수 있는 준비 표시기가 있습니다. 표시기의 전체 코드는 첨부 파일 ExtremumHandSet.mq5에 있습니다. 이제 우리는 채널을 그리는 주요 부분으로 이동할 수 있습니다.


채널 그리기 - 일부 이론

선형 채널은 극한 지점을 엄격하게 통과하는 두 개의 평행선으로 구성됩니다. 또한 한 선은 두 점을 통과해야 하고 다른 선은 첫 번째 선과 평행 한 상태로 남아있는 점을 통과해야 합니다. 간단한 그림으로 볼 수 있습니다.

세 개의 극한 점을 사용하여 채널 그리기

그림 4. 세 개의 극한 점을 사용하여 채널 그리기

기하학에서 알 수 있듯이 두 점을 통해 하나의 직선만 그릴 수 있습니다. 그림 4에서 이 선은 무화과에서 붉은 색입니다. (T1, P1) 및 (T2, P2) 좌표를 갖는 두 점이 생각됩니다. 포인트는 문자 A와 B로 표시됩니다.이 선의 방정식은 다음과 같습니다.

(1) P (t) = P1 + (t-T1) * (P2-P1) / (T2-T1); 여기서 P (t)는 't'시점에 계산 된 가격입니다.


점 C (세 번째 극값)를 통해 첫 번째 선과 평행 한 또 다른 직선을 그려야 합니다. 이 선은 그림 3에서 녹색입니다. T1과 T2 점이 두 선에 대해 동일하므로 P1 '및 P2'의 값을 찾아야 합니다. 그림 4).

앞으로 나아 가기 전에 중요한 발언을 해야 합니다. 터미널 차트에는 시간 "구멍"이 표시되지 않습니다. 예를 들어, 따옴표가 터미널에 오지 않는 휴일은 가격 할인으로 표시되어야 합니다. 그리고 그들이 그렇지 않다는 것은 나쁘다. 빈 차트를 볼 때의 요점은 무엇입니까? 그러나 위의 방정식에서 절대 시간을 사용하면 잘못된 채널을 얻게 됩니다.

다행히도 상황은 절망적이지 않습니다. 절대 시간을 바의 상대 수로 변경하면 바의 열거가 중단 될 수 없기 때문에 해당 좌표를 사용하여 채널을 그릴 수 있습니다 (실제로는 가격 배열의 인덱스).

더 나아가서 그림의 A 지점을 가정하면. 4는 항상 시간축의 0 좌표 (제로 바)에 위치하므로 방정식이 더욱 쉬워질 것입니다. 따라서 T1=0, T3=B3, T2=В2입니다. 여기서 В3과 В2는 점 Т1 (즉, 영점)에 상대적인 바의 숫자입니다. 이 가정이 선의 기울기로 이어지지 않음은 분명합니다. 그런 다음 점 A와 B를 통과하는 직선의 다음 방정식을 얻습니다.

(2) P (n) = P1 + n * (P2-P1) / B2. 여기서 P (n)은 숫자가 'n'인 바에 대해 계산 된 가격입니다.


따라서 우리는 P1, P2, P3 및 B2, B3 값을 알고 있습니다. 이제 P1 ' 및 P2' 값을 찾아야 합니다. 두 방정식을 결합하고 풀면 다음 공식을 얻습니다.이를 사용하여 알려지지 않은 값을 찾을 수 있습니다.

(3)   P1' = P3 - B3 * (P2 - P1) / B2

(4)   P2' = P2 - P1 + P1'


P1 '값을 찾아 (4) 공식으로 대체하면 P2' 값을 얻게 됩니다. 이제 우리는 채널을 그리는 이론적 기초를 가지고 있습니다. 구현을 시작합시다.


채널 테두리 그리기 - 클래스 TChannelBorderObject

이 클래스는 표준 클래스 CChartObjectTrend에서 파생됩니다. 그 목적은 채널의 경계와 연결된 모든 매개 변수를 저장하고 경계선을 그리기/삭제하고 이러한 선의 그래픽 매개 변수를 제어하는 ​​것입니다.

이 클래스에 대한 설명은 다음과 같습니다.

class TChannelBorderObject : public CChartObjectTrend
{
//  General properties of a border:
private:
  bool             is_created;       // whether the graphical object is created on the screen
  long             chart_id;         // identifier of the chart window
  int              window;           // identifier of the subwindow

//  Parameters of a border line:
private:
  string           border_name;      // name of the border line
  color            border_color;     // color of the border line
  int              border_width;     // thickness of the border line
  ENUM_LINE_STYLE   border_style;     // style of the border line

//  Coordinates of a border:
private:
  datetime         point_left;       // time of the left point (T1)
  datetime         point_right;      // time of the right point (T2)
  double           price_left;       // price of the left point (P1)
  double           price_right;      // price of the right point (P2)

public:
  void     TChannelBorderObject();  // constructor
  void    ~TChannelBorderObject();  // destructor
  bool     IsCreated();             // check whether the line is created

//  Creating/deleting a line:
public:
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right, color _color, int _width, ENUM_LINE_STYLE _style);
  bool     CreateBorder(long _chart_id, int _window, string _name, datetime _t_left, datetime _t_right, 
                           double _p_left, double _p_right);
  bool     CreateBorder(datetime _t_left, datetime _t_right, double _p_left, double _p_right);
  bool     RemoveBorder();          // delete line from the chart

//  Setting parameters of the line:
public:
  void     SetCommonParams(long _chart_id, int _window, string _name);
  bool     SetBorderParams(color _color, int _width, ENUM_LINE_STYLE _style);
  bool     SetBorderColor(color _color);
  bool     SetBorderWidth(int _width);
  bool     SetBorderStyle(ENUM_LINE_STYLE _style);

//  Getting values on the line:
  double   GetPrice(datetime _dt); // get price value in the specified position of the border line
};

이 클래스는 특별한 설명이 필요하지 않습니다.

지정된 지점에서 국경 가격을 얻는 방법에만 주의를 기울여야 합니다.

//---------------------------------------------------------------------
//  Get price value in the specified position of the border line:
//---------------------------------------------------------------------
double TChannelBorderObject::GetPrice(datetime _dt)
{
//  If the graphical object is created:
  if(is_created == true)
  {
    return(ObjectGetValueByTime( chart_id, border_name, _dt));
  }
  return(0.0);
}

터미널 ObjectGetValueByTime의 기능이 여기에 사용됩니다. 지정된 시간의 가격 값을 반환합니다. 수학 공식을 사용하여 값을 계산하는 대신 터미널 가능성을 사용하는 것이 편리합니다.


채널 그리기 - 클래스 TSlideChannelObject

이 클래스는 표준 클래스 CList에서 파생됩니다. 그 목적은 다음과 같습니다.

  • TChannelBorderObject 클래스의 객체를 저장하고 다른 작업을 수행합니다.
  • 채널을 구성하는 필수 라인을 그리기 위한 포인트를 계산하는 단계;
  • 채널의 매개 변수를 저장하고 수정하는 단계;
  • 그려진 채널을 설명하는 계산 된 값 (높이, 테두리의 가격 값 등) 얻기;

이 클래스를 설명하는 코드가 너무 커서 여기에 완전히 표시 할 수 없습니다. 원하는 사람들은 글에 첨부 된 SlideChannelClasses.mqh 파일에서 볼 수 있습니다. 그것의 주요 부분을 분석해 봅시다.

우선, 점 T2와 T3에서 각각 B2와 B3 값을 얻습니다 (그림 4 참조). 다음 코드가 사용됩니다.

//  Get relative shifts in bars relatively to the extremum points:
  total_bars = Bars(symbol, time_frame);     // total number of bars in history
  if(total_bars == 0)
  {
    return(false);                           // channel cannot be drawn
  }
  double  B2 = Bars(symbol, time_frame, point_left, point_right);
  double  B3 = Bars(symbol, time_frame, point_left, point_middle);

바가 없는 상황을 방지하기 위해 지정된 기호 및 기간 동안 내역에서 바의 수를 반환하는 터미널 함수 Bars를 사용합니다. 정보가 아직 형성되지 않은 경우 함수는 0 값을 반환합니다. 확인에 사용됩니다.

함수가 0이 아닌 값을 반환하면 В2 및 В3 값을 얻을 수 있습니다. 동일한 함수 Bars를 사용하여 수행되지만 다른 형식으로 호출합니다. 시간 제한을 설정하고 이 범위 내의 바의 수를 얻습니다. 왼쪽 테두리가 같기 때문에 Т2와 Т3에 대한 바의 이동을 얻습니다. 점 Т1의 이동은 항상 0입니다.

이제 채널 라인의 모든 지점을 계산할 수 있습니다. 채널은 (상단 및 하단 테두리에 추가하여) 중간 선과 테두리 및 중간 라인 주위에 백분율 영역의 선을 표시하므로 최대 9 개가 있을 수 있습니다.


계산의 주요 부분을 분석해봅시다. 전체 계산은 TSlideChannelObject::CalcChannel 메소드에 있습니다.

//  Coefficient of the line inclination:
  koeff_A = (price_right - price_left) / B2;

//  Price value on the AB line in the point T3:
  double  P3_AB = price_left + B3 * koeff_A;

// Determine the channel type - 2MAX_1MIN или 1MAX_2MIN:
  if(P3_AB > price_middle)              // 2MAX_1MIN
  {
    channel_type = CHANNEL_2MAX_1MIN;

    left_prices[BORDER_UP_INDEX] = price_left;
    right_prices[BORDER_UP_INDEX] = price_right;
        
    left_prices[BORDER_DN_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_DN_INDEX] = left_prices[BORDER_DN_INDEX] + (price_right - price_left);
  }
  else if(P3_AB < price_middle)         // 1MAX_2MIN
  {
    channel_type = CHANNEL_1MAX_2MIN;

    left_prices[BORDER_DN_INDEX] = price_left;
    right_prices[BORDER_DN_INDEX] = price_right;
        
    left_prices[BORDER_UP_INDEX] = price_middle - B3 * koeff_A;
    right_prices[BORDER_UP_INDEX] = left_prices[BORDER_UP_INDEX] + (price_right - price_left);
  }
  else
  {
    return( false );                      // channel cannot be drawn (all extremums are on the same line)
  }

left_pricesright_prices는 채널 9 개 라인의 가격 좌표를 저장하는 배열입니다. 채널의 모든 라인의 시간 좌표는 이미 알려져 있습니다.

먼저 라인 경사 계수 koeff_A를 결정합니다 (공식 (2) 참조). 그런 다음 T3 지점에서 AB 라인의 가격 값을 계산합니다 (그림 4 참조). 그리기에 지정된 채널 유형을 결정하기 위해 최대 2 개와 최소 1 개 또는 최소 2 개와 최대 1 개가 지정됩니다. 가격 축에서 어떤 지점이 더 높은지 확인합니다. 지점 C 또는 (P3 ', T3) 좌표가 있는 지점입니다. 위치에 따라 채널이 첫 번째 유형인지 두 번째 유형인지 결정합니다.

채널의 두 주요 라인 (상하)의 좌표가 결정되는 즉시 나머지 7 개 라인의 좌표를 계산하는 것은 어렵지 않습니다. 예를 들어 다음과 같은 방법으로 채널의 위쪽 및 아래쪽 테두리 좌표를 사용하여 중간 선의 좌표를 계산합니다.

  left_prices[BORDER_MD_INDEX] = (left_prices[BORDER_DN_INDEX] + left_prices[BORDER_UP_INDEX ]) / 2.0;
  right_prices[BORDER_MD_INDEX] = (right_prices[BORDER_DN_INDEX] + right_prices[BORDER_UP_INDEX]) / 2.0;

채널의 위쪽 및 아래쪽 테두리에서 평균 값을 가져옵니다.


지정된 극한으로 채널을 그리기위한 표시기 - SlideChannel

음, 우리는 이미 채널을 그리는 클래스가 있습니다. 이제 글로벌 변수에서 극값의 매개 변수를 읽고 차트에 채널을 그리는 표시기를 작성해보겠습니다. 다음과 같이 표시됩니다.

그림 5. 극값을 사용하여 그린 채널의 예

그림 5. 극값을 사용하여 그린 채널의 예

그려진 채널에 대한 정보도 여기에 표시됩니다-너비, 현재 가격에서 채널 경계 및 중간 선까지의 거리 (포인트).

필요한 라이브러리를 연결하겠습니다.

#include  <TextDisplay.mqh>
#include  <SlideChannelClasses.mqh>

첫 번째 라이브러리에는 화면에 텍스트 정보를 표시하는 구성을위한 클래스가 포함되어 있습니다 (다음을 봐주세요. "표준 라이브러리 클래스를 사용하여 나만의 Market Watch 만들기" 글). 이를 사용하여 임시 극한점 값을 표시합니다.

그런 다음 표시기의 입력 매개 변수를 추가합니다 (여기에서는 주요 매개 변수만 설명합니다).

input string          PrefixString = "MainChannel";
//---------------------------------------------------------------------
input ENUM_TIMEFRAMES  ExtremumTimeFrame = PERIOD_CURRENT;
//---------------------------------------------------------------------
input bool            ShowInfo = true;

ExtremumHandSet 표시기와 동일한 첫 번째 매개 변수 PrefixString은 극값을 읽을 때 전역 변수의 이름을 구성하는 데 사용되는 접두사를 설정합니다. 또한 단일 차트에서 여러 지표를 사용할 수 있습니다. 할 일은 다른 접두사를 설정하는 것 뿐입니다.

ExtremumTimeFrame 매개 변수는 전역 변수에서 극한 지점을 읽는데 사용되는 기간을 설정합니다. 매우 유용한 매개 변수입니다. 다른 시간대에 동기 채널을 그릴 수 있습니다. 예를 들어 H1에서 극한값을 설정하면 M5 시간대에 동일한 채널을 그릴 수 있습니다. 이를 위해 M5 차트에 채널 그리기에 대한 지표를 추가하기만 하면 됩니다. 모든 변경 사항을 동시에 표시합니다.

매개 변수 ShowInfo는 화면에 채널 매개 변수에 대한 텍스트 정보 표시를 제어합니다.

다음으로 정보를 표시하고 채널을 그리기 위한 개체를 만듭니다.

TableDisplay         ChannalDisplay;  // displaying of general information about a channel on the screen
TableDisplay         BordersDisplay;  // displaying information about the borders of a channel on the screen
//---------------------------------------------------------------------
TSlideChannelObject  Channel;         // drawing of a channel

채널을 그리기 위한 개체는 다음과 같은 방식으로 초기화됩니다.

  Channel.CreateChannel(PrefixString, 0, 0, Symbol(), period_current, curr_left_point, curr_middle_point, 
                        curr_right_point, curr_left_price, curr_middle_price, curr_right_price);
  Channel.SetBorderWidth(BorderWidth );
  Channel.SetmiddleWidth(middleLineWidth);
  Channel.SetUpBorderColor(UpBorderColor);
  Channel.SetDnBorderColor(DnBorderColor);
  Channel.SetmiddleColor(middleLineColor );
  Channel.ShowBorderZone(ShowBorderPercentageLines);
  Channel.BorderZonePercentage( PercentageZoneSize);
  Channel.Showmiddle(ShowmiddleLine);
  Channel.ShowmiddleZone( ShowmiddlePercentageLines);
  Channel.middleZonePercentage(PercentagemiddleZoneSize);

여기에서 먼저 TSlideChannelObject::CreateChannel 메소드를 호출하여 채널을 생성한 다음 채널 라인의 필수 매개 변수를 설정합니다. 설정 순서는 중요하지 않습니다. 반대로 설정할 수 있습니다. 매개 변수를 설정한 다음 채널을 만듭니다.

period_current 매개 변수는 전역 변수에서 극값을 읽을 때 사용되는 기간입니다. 현재 차트의 기간과 다를 수 있습니다.

표시기에서 사용되는 주요 기능을 살펴 보겠습니다. 첫 번째 함수 GetExtremums는 극한 포지션을 읽고 얻은 값에 따라 채널을 새로 고치는 데 사용됩니다.

void GetExtremums()
{
  double  temp;
  string  name;

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr2");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_middle_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_DTime_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_point = (datetime)temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr1");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_left_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol( ), "_", period_current, "_Price_Extr2");
  if( GlobalVariableGet(name, temp) != false )
  {
    curr_middle_price = temp;
  }

  StringConcatenate(name, PrefixString, "_", Symbol(), "_", period_current, "_Price_Extr3");
  if( GlobalVariableGet(name, temp) != false)
  {
    curr_right_price = temp;
  }

//  Update the position of channel:
  Channel.SetExtremums(curr_left_point, curr_middle_point, curr_right_point, 
                       curr_left_price, curr_middle_price, curr_right_price);
}

화면에서 채널을 새로 고치려면 TSlideChannelObject::SetExtremums 메소드를 사용합니다. 이 방법은 채널 라인의 좌표를 다시 계산하고 화면에 채널을 다시 그립니다.

다른 시간대에 채널을 그리는 예가 아래 비디오에 나와 있습니다.


시작 표시기의 순서는별로 중요하지 않지만 처음에 ExtremumHandSet 표시기를 시작한 다음 노란색 (색상 레이블 수는 표시기 매개 변수에 설정되고 노란색은 기본값으로 설정 됨), 지정된 극값으로 채널을 그리는 SlideChannel 표시기를 시작합니다.

채널이 첫 번째 차트의 극값과 동기식으로 그려지려면 SlideChannel 표시기의 ExtremumTimeFrame 매개 변수에서 차트 중 하나와 동일하게 기간을 설정해야 합니다. 극값이 설정된 곳.

이는 채널의 극한 점 설정 기능과 터미널 화면의 드로잉 기능을 분리한 결과입니다.


결론

우리는 화면에서 채널의 포지션을 ​​설정하는 것부터 그림까지의 전체주기를 고려했습니다. 특히 표준 클래스와 OOP를 사용할 때 모든 것이 그렇게 복잡하지 않은 것처럼 보였습니다.

그러나 문제가 있습니다. 시장에서 일하기 위해 채널을 어떻게 사용해야 합니까? 첫째, 금융 상품의 현재 상태에 대한 기술적 분석에 필요합니다. 둘째, 분석 후 결정을 내리는 데 필요합니다. 채널은 그것에 크게 도움이 될 수 있습니다.

포지션을 열거 나 닫을 때 채널의 경계를 분석하는 반자동 Expert Advisor를 개발할 수 있습니다. 경계를 뚫거나 경계에서 롤백하는 방식으로 작동할 수 있습니다. 이것은 다음 글인 채널 작업 방법 - 롤백 및 브레이크 스루의 주제입니다.

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

파일 첨부됨 |
extremumclasses.mqh (12.58 KB)
extremumhandset.mq5 (11.89 KB)
slidechannel.mq5 (13.7 KB)
textdisplay.mqh (15.21 KB)
Trading Model 기반 Multi-Expert Advisor 양성 Trading Model 기반 Multi-Expert Advisor 양성
MQL5에서 객체 지향 접근 방식을 사용하면 다중 통화/다중 시스템/다중 타임 프레임 Expert Advisors 생성이 크게 간소화됩니다. 하나의 EA가 수십 가지 거래 전략, 사용 가능한 모든 상품 및 모든 가능한 타임 프레임에서 거래한다고 상상해보십시오! 또한 EA는 테스터에서 쉽게 테스트되며 구성에 포함된 모든 전략에 대해 하나 또는 여러 개의 자금 관리 시스템이 있습니다.
MetaTrader 5의 병렬 계산 MetaTrader 5의 병렬 계산
시간은 인류 내역을 통틀어 큰 가치로 여겨져 왔으며, 불필요하게 낭비하지 않도록 노력하고 있습니다. 이 글에서는 컴퓨터에 멀티 코어 프로세서가 있는 경우 Expert Advisor의 작업을 가속화하는 방법에 대해 설명합니다. 또한 제안된 방법의 구현에는 MQL5 외에 다른 언어에 대한 지식이 필요하지 않습니다.
마이크로, 미들, 메인 추세의 지표 마이크로, 미들, 메인 추세의 지표
이 글의 목적은 James Hyerczyk의 "Pattern, Price & Time: Using Gann Theory in Trading Systems"라는 책의 몇 가지 아이디어를 기반으로 지표 및 Expert Advisor의 형태로 거래 자동화 및 분석의 가능성을 조사하는 것입니다. 완전하다고 주장하지 않고 여기서 우리는 Gann 이론의 첫 번째 부분인 모델만 조사합니다.
CChartObject 클래스 기반의 새로운 GUI 위젯 설계 및 구현 CChartObject 클래스 기반의 새로운 GUI 위젯 설계 및 구현
GUI 인터페이스가 있는 반자동 Expert Advisor에 대한 이전 글을 작성한 후 더 복잡한 지표와 Expert Advisors를 위한 몇 가지 새로운 기능으로 인터페이스를 향상시키는 것이 바람직하다는 것이 밝혀졌습니다. MQL5 표준 라이브러리 클래스에 익숙해 진 후 새로운 위젯을 구현했습니다. 이 글에서는 표시기 및 Expert Advisor에서 사용할 수 있는 새로운 MQL5 GUI 위젯을 설계하고 구현하는 프로세스를 설명합니다. 글에 제시된 위젯은 CChartObjectSpinner, CChartObjectProgressBar 및 CChartObjectEditTable입니다.