
Expert Advisor에 지표를 포함시키기 위한 기성 템플릿(1부): 오실레이터
콘텐츠
- 소개
- 평균 실제 범위
- 베어스 파워
- 불스 파워
- 차이킨 오실레이터
- 상품 채널 인덱스
- 디마커
- 포스 인덱스
- MACD
- 모멘텀
- 오실레이터 이동 평균
- 상대 강도 지수
- 상대 활력 지수
- 스토캐스틱 오실레이터
- 삼중 지수 평균
- 윌리엄스의 퍼센트 범위
- 결론
소개
EA에 지표를 포함하고 EA에서 지표 버퍼의 데이터를 사용하는 것은 매우 간단한 작업입니다. 그러나 참조 내용들을 계속 탐색해야 합니다. 우리는 지표 생성 함수에 전달된 모든 매개 변수를 기억해야 하고 그 중 일부를 EA 입력으로 공식화하고 유효성 검사 등을 도입해야 하며 데이터를 얻기 위해서는 원하는 바에서 필요한 데이터를 반환하는 함수를 작성해야합니다. 이 모든 작업을 하기 위해서는 우리는 도움말에 액세스하고, EA에 필요한 변수를 입력하고, 신호를 확인하기 위해 데이터를 수신하고 모니터링하는 함수를 작성하는 등의 작업을 해야 합니다.
이 문서의 목적은 EA에 지표를 포함하기 위한 용도의 템플릿을 만드는 것입니다. 이제 오실레이터 카테고리의 지표와 입력 변수, 지표 핸들을 만들고 필요한 데이터를 가져오는 방법을 살펴보겠습니다. 각 지표는 다음과 같은 기능을 제공합니다:
- 샘플 입력,
- 입력을 초기화하고 핸들을 생성,
- 초기화 해제
- 지정된 시계열 인덱스에 따라 지정된 지표 라인의 데이터를 수신,
- 수신된 데이터의 값을 모든 레벨과 비교하여 선 상태 측면에서 모니터링.
선 상태란 선의 모양과 형태를 의미합니다:
- 위쪽 방향(값 2는 값 1보다 작거나 같고, 값 1은 값 0보다 작음),
- 아래쪽 방향(값 2는 값 1보다 크거나 같고, 값 1은 값 0보다 큼),
- 상향 반전(값 2가 값 1보다 크고, 값 1이 값 0보다 작음),
- 하향 반전(값 2가 값 1보다 작고 값 1이 값 0보다 큰 경우),
- 상향 정지(값 2는 값 1보다 작거나 같고, 값 1은 값 0과 같음),
- 하향 정지(값 2는 값 1보다 크거나 같고, 값 1은 값 0과 같음),
- 정의되지 않은 상태(의도된 상태가 아님)
여기서 말하는 선 상태는 모든 레벨에 대한 상대적인 상태를 의미합니다:
- 값 위(선 값이 레벨 값보다 큼)
- 값 미만(선 값이 레벨 값보다 작음)
- 값을 위쪽으로 교차(값 1이 바 1의 레벨 값보다 작거나 같고 값 0이 바 0의 레벨 값보다 큼)
- 값을 아래쪽으로 교차(값 1은 바 1의 레벨 값보다 크거나 같고 값 0은 바 0의 레벨 값보다 작음)
- 아래쪽에서 값을 터치합니다(값 1은 바 1의 레벨 값보다 작고 값 0은 바 0의 레벨 값과 같음).
- 위쪽에서 값을 터치합니다(값 1은 바 1의 레벨 값보다 크고, 값 0은 바 0의 레벨 값과 같음).
- 값과 같음(바 1과 0의 선 값은 바 1과 0의 레벨 값과 같음)
이러한 조건은 선 상태(두 번째, 첫 번째 및 제로 바 사이의 두 세그먼트의 모양 또는 그림)를 결정하고 다른 표시선과의 교차점 또는 수평 수준을 결정하는 데 매우 충분합니다.
이러한 상태를 제어하기 위해 우리는 모든 지표에 공통으로 적용되는 범용 함수를 구현할 것입니다. 지표 버퍼에서 데이터를 가져오는 함수와 마찬가지로 모든 지표에 공통적으로 적용됩니다.
이 문서에서 제공하는 모든 예제와 코드는 완전한 코드 블록입니다. 사용자 지정 프로그램에서 '있는 그대로' 사용할 수 있습니다.
평균 실제 범위
평균 실제 범위 지표(ATR)는 시장 변동성을 보여주는 지표로 웰즈 와일더가 그의 저서 "기술적 트레이딩 시스템의 새로운 개념"에서 소개한 개념입니다. 이 지표는 이후 수많은 다른 지표와 트레이딩 시스템의 구성 요소로 사용되었습니다.
평균 실제 범위는 패닉 매도로 인해 가격이 급락한 후 시장의 바닥에서 높은 값에 도달하는 경우가 많습니다. 지표의 낮은 값은 시장의 고점 및 통합 중에 발생하는 장기간의 횡보 기간 중에 일반적이며 다른 변동성 지표와 동일한 규칙에 따라 해석할 수 있습니다. 이 지표를 기반으로 한 예측의 원리는 다음과 같이 표현될 수 있습니다; 지표의 값이 높을수록 추세 변화의 확률이 높고 지표의 값이 낮을수록 추세의 움직임이 약하다는 뜻입니다.
실제 범위는 다음 세 가지 값 중 가장 큰 값입니다:
- 현재 최대값과 최소값(최고와 최저)의 차이입니다;
- 이전 종가와 현재 최고가 사이의 차이입니다;
- 이전 종가와 현재 최저가의 차이입니다.
ATR은 실제 범위 값의 이동 평균입니다.
매개변수
지표에는 조정 가능한 매개변수가 이동 평균 평활화 기간 하나만 있습니다. 기본값은 14입니다.
모든 지표 입력이 사용자 지정 가능한 EA 매개 변수로 지정된다는 데 동의합시다.
빈 EA 템플릿을 만듭니다:
이름과 입력 매개변수를 입력합니다:
핸들러에서 타이머와 이벤트 핸들러를 선택합니다:
클릭하고 마침을 클릭합니다. 그러면 빈 EA 템플릿이 나옵니다:
//+------------------------------------------------------------------+ //| TestOscillatorATR.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- input parameters input uint InpPeriod=14; //+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); } //+------------------------------------------------------------------+ //| Expert tick function | //+------------------------------------------------------------------+ void OnTick() { //--- } //+------------------------------------------------------------------+ //| Timer function | //+------------------------------------------------------------------+ void OnTimer() { //--- } //+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- } //+------------------------------------------------------------------+
변수와 함수 등 글로벌 수준에서만 코드를 입력합니다. OnInit() 및 OnDeinit()) 핸들러에서 지표 매개변수의 초기화 및 제어, 지표 핸들의 생성 및 삭제를 설정합니다. 테스트 EA는 지표에서 수신한 데이터를 지표 라인의 상태에 대한 설명과 함께 표시하는 대시보드를 사용합니다. OnChartEvent() EA 핸들러는 패널 작업에 대한 이벤트만 처리하도록 설정합니다. 즉 EA에서 지표를 완벽하게 처리하려면 생성된 변수, 초기화, 지표 핸들 생성 및 삭제, 지표 버퍼에서 데이터를 수신하는 일반 함수의 예제만 사용하면 됩니다. 예제의 다른 모든 내용은 패널로 작업한 것입니다.
글로벌 변수 그리고 입력 속성에 설명을 추가합니다. 그리고 작업합니다:
//--- input parameters input uint InpPeriod = 14; /* ATR Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ATR calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
이전 글에서 지표와 EA에 사용할 대시보드를 만들었습니다. 이제 클래스가 약간 수정되어 다양한 데이터를 표시하는 판을 원하는 수만큼 만들 수 있습니다. 여기서는 변경 사항에 대해 설명하지 않고 잠시 후에 다시 설명하겠습니다. 다음 글에서는 변경 사항과 개선 사항에 대해 간략하게 설명하겠습니다. 이 문서에서 EA를 테스트하려면 패널 클래스 파일이 \MQL5\Include\Dashboard\Dashboard.mqh에 있어야 합니다. 패널 클래스의 소스 코드가 포함된 파일은 테스트 EA 파일과 함께 문서에 첨부되어 있습니다.
대시보드 파일을 EA 코드에 포함시키고 대시보드 작업을 위한 전역 변수를 설정합니다:
#property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- input parameters input uint InpPeriod = 14; /* ATR Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ATR calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
위에서 우리는 지표 라인의 상태를 분류하는 가능한 옵션을 살펴봤습니다. 가장 편리한 방법은 가능한 모든 옵션으로 열거형을 만들고 이 열거형의 유형으로 변수에서 지표 라인의 상태를 결정하는 함수로부터 결과를 수신하는 것이라고 생각합니다. 글로벌 영역에서 이러한 열거형을 생성하고 그 결과로 다음과 같은 헤더를 얻도록 하겠습니다:
#property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* ATR Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // ATR calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
다음으로 입력 값을 확인하고 필요한 경우 조정해야 합니다.
초기화
모든 지표에서 기간 값으로 0을 입력하면 기본값이 설정됩니다. 평활화 기간 값을 0으로 설정하면 EA는 기간 값이 0으로 설정된 표준 지표와 동일한 지표를 생성해야 하며 이 경우 두 지표의 기본값이 됩니다. 또한 일부 지표는 기간 값에 지표를 입력할 때 계산되지 않습니다. 기간의 최소 기간은 2입니다. 지표마다 소수점 이하 자릿수가 다릅니다. 우리는 이 점도 고려해야 합니다. 이 문서에 있는 모든 템플릿에서는 모든 뉘앙스가 고려됩니다. 모든 점검이 이미 완료되었으며 올바르게 처리되었습니다. 이 글에 있는 코드를 여러분의 EA 코드에 복사하여 사용하기만 하면 됩니다.
지표 변수 값을 설정하고 지표 핸들을 생성하는 OnInit() EA 핸들러를 사용합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ATR(%lu)",period); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iATR(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); } //+------------------------------------------------------------------+
EA에서 대시보드를 사용하려면 OnInit() 핸들러에 코드 블록을 추가하세요. 결과적으로 전체 핸들러 코드는 다음과 같이 됩니다(지표 생성 및 패널 생성):
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("ATR(%lu)",period); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iATR(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
강조 표시 된 코드만 있으면 지표를 만들 수 있습니다. 여기와 이 글의 이후의 테스트 EA에서 패널은 지표에서 수신할 데이터를 시각적으로 표시하기 위해 만들어집니다.
초기화 해제
OnDeinit() EA 핸들러에서 우리는 생성된 지표의 핸들을 해제해야 합니다.
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
패널을 사용하는 경우 생성된 패널 객체를 삭제해야 합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 버퍼에서 데이터를 가져오려면 CopyBuffer() 함수를 사용해야 합니다. 이 함수는 지정된 지표 버퍼의 데이터를 지정된 수량만큼 '버퍼' 배열로 받습니다.
데이터를 얻는 방법에는 세 가지가 있습니다:
초기 위치 및 필요한 요소 수에 따라 액세스합니다:
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index int start_pos, // starting point int count, // amount to copy double buffer[] // array the data to be copied to );
시작 날짜 및 필수 요소 수에 따라 액세스합니다:
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index datetime start_time, // starting date int count, // amount to copy double buffer[] // array the data to be copied to );
필요한 시간 간격의 초기 및 최종 날짜로 액세스합니다:
int CopyBuffer( int indicator_handle, // indicator handle int buffer_num, // indicator buffer index datetime start_time, // starting date datetime stop_time, // end time double buffer[] // array the data to be copied to );
데이터를 얻기 위해 첫 번째 옵션인 바 인덱스별 옵션을 사용하겠습니다.
이 함수는 필요한 지표 핸들, 바 인덱스, 지표 버퍼 인덱스를 받아 지정된 바 인덱스의 지정된 지표 라인에서 얻은 값을 반환하거나 데이터 검색에 실패할 경우에는 EMPTY_VALUE를 반환합니다:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; }
CopyBuffer() 함수를 사용하면 한 번에 하나의 바에서 하나의 값 뿐만 아니라 지정된 범위의 지표 라인 값도 가져올 수 있다는 점에 주목할 필요가 있습니다. 이 기능은 여기서는 사용하지 않을 것입니다. 그러므로 결과 값 범위를 메모리에 저장한 다음 지정된 인덱스의 이동에 따라 필요한 값을 계산하여 지표 라인의 상태를 모니터링하는 것은 복잡하지 않습니다. 이제 더 간단합니다: 지정된 인덱스에서 값을 가져와서 첫 번째 값과 비교할 다른 값을 가져옵니다. 함수의 다양성 측면에서 더 간단하고 편리합니다.
표시줄의 상태를 반환하는 함수입니다:
//+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; }
여기서는 현재 바와 이전 바 두 개, 총 세 개의 바에서 지표 선의 값을 가져옵니다. 이 정도면 간단한 선 모양 구성을 얻기에 충분합니다. 3개 중 가장 오른쪽 바의 인덱스가 함수에 전달됩니다(예: 인덱스 15). 이 경우 바 17, 16, 15는 선의 상태를 계산하는 데 사용됩니다. 여기서 우리는 실수로 작업하므로 두 값의 정규화된 차이를 사용하고 이를 0과 비교하여 각 바의 값을 비교합니다.
지정된 레벨을 기준으로 지표 선의 상태를 반환하는 함수입니다:
//+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; }
이 함수는 매개변수에 전달된 레벨을 사용하여 인접한 두 바에서 지표 선의 두 값 사이의 관계를 확인합니다. 매개변수는 두 지표 선 값에서 가져온 두 선 바 중 오른쪽 바의 인덱스와 두 선 바의 값을 비교하여 관계를 식별하는 데 필요한 레벨 값을 나타내며
만약 우리가 수평 레벨과의 관계를 가져와야 하는 경우 level0 매개 변수에 전달해야 합니다. 두 번째 level1 매개변수의 기본값은 EMPTY_VALUE로 인접한 두 바의 지표 선 데이터 값이 모두 level0으로 전달된 하나의 값과 비교됩니다(index+1의 표시줄 바는 level0 값과 비교되고 index의 바는 level0과 비교됨).
level1이 EMPTY_VALUE 이외의 값을 받으면 두 지표 선 바 각각이 level1 및 level0의 두 해당 값과 비교됩니다(index+1의 선 바는 level1의 값과 비교되고 인덱스의 바는 level0과 비교됩니다). 따라서 지표 선을 동일하거나 다른 지표의 다른 선과 비교하여 관계, 특히 교차점을 식별할 수 있습니다.
식별된 상태 및 표시줄의 관계에 대한 설명을 표시하려면 지표선 상태에 대한 설명을 반환하는 함수를 작성합니다:
//+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
위에서 설명한 세 가지 기능을 EA에서 '있는 그대로' 사용하여 모든 지표의 데이터를 수신하고 지표의 상태와 상대적 위치를 제어할 수 있습니다.
다음은 지표에서 데이터를 수신하고 데이터 설명을 표시하는 방법의 예입니다. 지표에서 얻은 데이터를 대시보드에 표시하는 EA 함수를 만들어 보겠습니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
이전 글의 예제에서 대시보드를 만들 때 이미 비슷한 함수를 사용했습니다. 여기서 커서가 위치한 바 데이터는 첫 번째 패널 패널에 표시되고 지표 데이터와 해당 라인의 상태는 두 번째 패널 패널에 표시됩니다.
패널이 작동하도록 하려면 OnChartEvent() 이벤트 핸들러에 코드를 추가해야 합니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
이전 글에서 우리는 이미 핸들러 로직에 대해 살펴봤습니다. 여기서는 '있는 그대로' 사용합니다.
이제 EA를 컴파일하고 기본 매개 변수로 차트에서 실행하면(이전에 기본 매개 변수가 있는 차트에 ATR 지표도 추가했음) 커서가 차트에서 이동함에 따라 데이터가 변경되는 대시보드가 표시됩니다:
여러분은 이 글에 첨부된 파일에서 TestOscillatorATR.mq5 테스트 EA를 확인할 수 있습니다.
베어스 파워
매일의 거래는 가격을 올리는 매수자("강세")와 가격을 내리는 매도자("약세")의 전투입니다. 어느쪽이 점수를 깎는지에 따라 전날보다 높거나 낮은 가격으로 하루가 종료됩니다. 중간 결과, 우선은 최고 및 최저 가격을 통해 하루 동안 전투가 어떻게 진행되고 있는지 판단 할 수 있습니다.
베어스 파워 균형을 추정할 수 있다는 것은 매우 중요합니다. 왜냐하면 이 균형의 변화는 추세 반전 가능성에 대한 신호이기 때문입니다. 이 작업은 알렉산더 엘더가 개발한 베어스 파워 오실레이터를 사용하여 해결할 수 있으며 그의 저서 <생계를 위한 트레이딩>에 설명되어 있습니다. 엘더는 이 오실레이터를 추론할 때 다음과 같은 전제를 기반으로 합니다:
- 이동 평균은 매수자와 매도자 간의 일정 기간 동안의 가격 계약입니다,
- 최저가는 당일 최대 매도자의 파워를 표시합니다.
이러한 전제하에 엘더는 베어스 파워를 최저가와 13기간 이동평균 (LOW - ЕМА)의 차이로 개발했습니다.
이 지표는 추세 지표(주로 이동 평균)와 함께 사용하는 것이 좋습니다:
- 추세 지표가 상승 방향이고 베어스 파워 지수가 0보다 낮지만 상승 중이면 매수 신호입니다;
- 이 경우 지표 차트에서 다이버전스의 기초가 형성되는 것이 바람직합니다.
매개변수
지표에는 구성 가능한 매개 변수인 계산 기간이 하나 있습니다. 기본값은 13입니다.
지표를 위한 매개변수와 변수를 코드에 추가해 보겠습니다:
//+------------------------------------------------------------------+ //| TestOscillatorBears.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Bears Power Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bears Power calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
패널을 사용할 때 대시보드 클래스 파일을 포함하고 작업할 변수를 추가합니다:
//+------------------------------------------------------------------+ //| TestOscillatorBears.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Bears Power Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bears Power calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit() 핸들러에서 지표 입력을 초기화 및 조정하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bears(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBearsPower(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
EA가 대시보드를 사용하는 경우 여기에서 생성하세요:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bears(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBearsPower(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
EA에 패널이 포함된 경우 생성된 패널 클래스 객체를 제거합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
우리는 이미 모든 지표에서 데이터를 검색할 수 있는 공통 함수를 구현했습니다:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
여기에 있는 모든 예제는 변경 없이 그대로 사용되었습니다.
EA가 대시보드를 사용하는 경우 우리는 지표에서 수신한 데이터를 대시보드에 표시하는 함수를 구현할 것입니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the value of the line above/below zero color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
지표의 신호는 0을 기준으로 할때 선의 위치에 따라 달라지므로 우리는 대시보드에서 지표의 양수 및 음수 값을 강조 표시할 것입니다.
OnChartEvent() 이벤트 핸들러에서 패널 이벤트를 처리하고 커서가 위치한 바의 인덱스를 나타내는 코드를 작성합니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 기본값을 사용하여 차트에서 실행하고 차트에 동일한 매개 변수가 있는 지표를 추가했는지 확인합니다:
"TestOscillatorBears.mq5" EA 파일은 아래에 첨부되어 있습니다.
불스 파워
매일의 거래는 가격을 올리는 매수자("강세")와 가격을 내리는 매도자("약세")의 전투입니다. 어느쪽이 우세했는지에 따라 전날보다 높거나 낮은 가격으로 당일이 마감됩니다. 중간 결과, 우선은 최고 및 최저 가격을 통해 하루 동안 전투가 어떻게 진행되고 있는지 판단 할 수 있습니다.
이 균형의 변화는 추세 반전 가능성에 대한 신호이므로 불스 파워 균형을 추정할 수 있는 것은 매우 중요합니다. 이 작업은 알렉산더 엘더가 개발한 파워 오실레이터를 사용하여 해결할 수 있으며 그의 저서 <Trading for a Living>에 설명되어 있습니다. 엘더는 이 오실레이터를 추론할 때 다음과 같은 전제를 기반으로 합니다:
- 이동 평균은 매수자와 매도자 간의 일정 기간 동안의 가격 계약입니다,
- 가장 높은 가격은 당일 최대 매수자의 힘을 표시합니다.
이러한 전제에서 Elder는 최고가와 13기간 이동평균 (HIGH - ЕМА)의 차이로 불스 파워를 개발했습니다.
이 지표는 추세 지표(주로 이동 평균)와 함께 사용하는 것이 좋습니다:
- 추세 지표가 하락 방향이고 불스 파워 지수가 0보다 높지만 하락하는 경우 매도 신호입니다;
- 이 경우 지표 차트에서 피크의 다이버전스가 형성되는 것이 바람직합니다.
매개변수
지표에서 조정 가능한 매개 변수 하나가 평활화 기간입니다. 기본값은 13입니다.
EA에서 사용할 입력 및 전역 변수 목록입니다:
//+------------------------------------------------------------------+ //| TestOscillatorBulls.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Bulls Power Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bulls Power calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorBulls.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Bulls Power Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Bulls Power calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bulls(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBullsPower(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Bulls(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iBullsPower(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the value of the line above/below zero color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorBulls.mq5" EA 파일은 아래에 첨부되어 있습니다.
차이킨 오실레이터
오실레이터(CHO)는 누적/분배의 이동 평균의 차이입니다.
"이 오실레이터의 개념은 세 가지 주요 논제를 기반으로 합니다. 첫째, 주식 또는 지수가 장중보다 장마감 시점에 더 높으면(평균값은 [최대+최소]/2로 계산할 수 있음) 누적된 날이라는 뜻입니다. 주식 또는 지수의 종가가 최대치에 가까울수록 누적이 더 활발하게 이루어집니다. 반대로 주식의 종가가 당일 평균 수준보다 낮으면 분배가 이루어졌다는 의미입니다. 점유율이 최소값에 가까울수록 더 활발한 분배가 이루어집니다.
둘째, 안정적인 가격 상승은 볼륨 증가와 볼륨의 강력한 누적을 동반합니다. 볼륨은 시장 성장을 이끄는 연료와 같기 때문에 가격 상승이 일어나면서 볼륨이 뒤처진다는 것은 상승세를 이어갈 연료가 충분하지 않다는 것을 의미합니다.
반대로 가격 급락은 일반적으로 낮은 양을 동반하며 기관 투자자의 패닉과 같은 포지션 청산으로 이어집니다. 따라서 우선 볼륨이 증가한 다음 볼륨 감소와 함께 가격이 하락하고 마지막으로 시장이 안정에 가까워지면 약간의 축적이 발생합니다.
셋째, 차이킨 오실레이터를 사용하면 시장에 들어오고 나가는 자금의 양을 추적할 수 있습니다. 볼륨과 가격의 역학을 비교하면 단기 및 중기적으로 시장의 정점과 바닥을 파악할 수 있습니다.
오류가 없는 기술적 분석 방법은 없으므로 여러분은 이 오실레이터를 다른 보조지표와 함께 사용하는 것이 좋습니다. 예를 들어 21일 이동평균과 과매수/과매도 오실레이터를 기반으로 한 Envelopes를 차이킨 오실레이터와 함께 사용하면 단기 및 중기 거래 신호의 신뢰도가 높아집니다.
가장 중요한 신호는 가격이 최대 또는 최소 수준(특히 과매수/과매도 수준)에 도달했을 때 차이킨 오실레이터가 이전 극값을 극복하지 못해 돌아서는 경우 발생합니다.
- 중기 추세의 방향으로 움직이는 신호는 추세에 역행하는 신호보다 더 신뢰할 수 있습니다.
- 오실레이터가 새로운 최고가 또는 최저가를 확인했다고 해서 가격이 그 방향으로 움직인다는 의미는 아닙니다. 이 이벤트는 중요하지 않은 것으로 간주됩니다.
차이킨 오실레이터를 사용하는 또 다른 방법은 다음과 같습니다: 방향의 변화는 매수 또는 매도 신호이지만 이는 가격 추세 방향과 일치하는 경우에만 해당합니다. 예를 들어 주가가 상승 중이고 주가가 90일 이동평균보다 높은 경우 음의 값 영역에서 오실레이터 곡선이 상승 전환하면 매수 신호로 간주할 수 있습니다(단, 주가가 90일 이동평균보다 높아야 합니다)
오실레이터 곡선이 양수(0 이상) 영역에서 하락하면 매도 신호로 간주할 수 있지만 주가가 종가의 90일 이동평균보다는 낮아야 합니다."
매개변수
지표에는 네 가지 매개 변수가 있습니다:
- 볼륨, 기본값으로 - 틱
- 빠른 MA 계산 기간, 기본값 - 3,
- 느린 MA 계산 기간, 기본값 - 10,
- 계산 방법, 기본값 - EMA.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorCHO.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 3; /* CHO Fast MA Period */ input uint InpPeriodSlow = 10; /* CHO Slow MA Period */ input ENUM_MA_METHOD InpMethod = MODE_EMA; /* Method */ input ENUM_APPLIED_VOLUME InpAppliedVol = VOLUME_TICK; /* Applied Volume */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast moving average calculation period int period_slow=0; // Slow moving average calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorCHO.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 3; /* CHO Fast MA Period */ input uint InpPeriodSlow = 10; /* CHO Slow MA Period */ input ENUM_MA_METHOD InpMethod = MODE_EMA; /* Method */ input ENUM_APPLIED_VOLUME InpAppliedVol = VOLUME_TICK; /* Applied Volume */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast moving average calculation period int period_slow=0; // Slow moving average calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 3 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 10 : InpPeriodSlow); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("CHO(%lu,%lu)",period_slow,period_fast); ind_digits=0; //--- Create indicator handle ResetLastError(); handle=iChaikin(Symbol(),PERIOD_CURRENT,period_fast,period_slow,InpMethod,InpAppliedVol); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 3 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 10 : InpPeriodSlow); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("CHO(%lu,%lu)",period_slow,period_fast); ind_digits=0; //--- Create indicator handle ResetLastError(); handle=iChaikin(Symbol(),PERIOD_CURRENT,period_fast,period_slow,InpMethod,InpAppliedVol); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); // The label color changes depending on the value of the line above/below zero panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
0보다 높거나 낮은 지표 선의 값은 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorCHO.mq5" EA 파일은 아래에 첨부되어 있습니다.
상품 채널 인덱스
상품 채널 지수(CCI)는 상품 가격이 상품의 평균 통계 가격에서 벗어난 편차를 측정합니다. 지수가 높으면 평균 가격과 비교했을 때 가격이 비정상적으로 높다는 의미이고 낮으면 가격이 너무 낮다는 의미입니다. 이름과 달리 상품 채널 지수는 상품뿐만 아니라 모든 금융 상품에 적용할 수 있습니다.
상품 채널 인덱스를 사용하는 두 가지 기본 기술이 있습니다:
- 다이버전스를 찾으려면
다이버전스는 가격이 새로운 최고점에 도달하고 상품 채널 지수가 이전 최고점 이상으로 상승할 수 없을 때 나타납니다. 이러한 고전적인 다이버전스 뒤에는 보통 가격 조정이 뒤따릅니다. - 과매수/과매도 지표의 기능
상품 채널 지수는 일반적으로 ±100 범위에서 변동합니다. 100 이상의 값은 과매수 상태(및 하락 조정 확률)를, 100 미만의 값은 과매도 상태(및 상승 조정 확률)를 나타냅니다.
매개변수
지표에는 두 가지 입력 매개변수가 있습니다:
- 계산 기간, 기본값 - 14
- 계산 가격, 기본값 - Typical Price(HLC/3)
표준 지표 입력 외에도 과매수 및 과매도 레벨을 사용하여 신호를 검색할 수 있으며 이때는 EA 입력창에 지정되어 있어야 합니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorCCI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* CCI Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_TYPICAL; /* Applied Price */ input double InpOverbough= 100.0; /* Overbough level*/ input double InpOversold = -100.0; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // CCI calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorCCI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* CCI Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_TYPICAL; /* Applied Price */ input double InpOverbough= 100.0; /* Overbough level*/ input double InpOversold = -100.0; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // CCI calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("CCI(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iCCI(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("CCI(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iCCI(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state relative to the overbought level string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); //--- The label color changes depending on the value of the line relative to the level color clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Display a description of the indicator line state relative to the oversold level panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- The label color changes depending on the value of the line relative to the level clr=(state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the location of the line in the overbought/oversold areas clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
과매수 및 과매도 영역의 지표 선 위치와 해당 영역의 신호는 패널에 색상으로 표시되어 있습니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorCCI.mq5" EA 파일은 아래에 첨부되어 있습니다.
디마커
디마커 기술 지표(DeM)는 현재 기간 최대치와 이전 기간 최대치의 비교를 기반으로 합니다. 현재 기간(바) 최대값이 더 높으면 둘 사이의 차액이 각각 등록됩니다. 현재 최대값이 이전 기간의 최대값보다 낮거나 같으면 0 값이 등록됩니다. 그런 다음 N 기간 동안의 차이를 합산합니다. 수신된 값은 디마커의 분자로 사용되며 이전 기간과 현재 기간의 가격 최소값(바)의 차이의 합을 더한 값으로 나뉘어집니다. 현재 가격 최소값이 이전 바의 가격보다 크면 값0이 등록됩니다.
지표가 30 아래로 떨어지면 강세로의 가격 반전을 예상해야 합니다. 지표가 70 이상으로 상승하면 약세로의 가격 반전을 예상해야 합니다.
지표를 계산할 때 더 긴 기간을 사용하면 장기적인 시장 추세를 파악할 수 있습니다. 단기에 기반한 지표를 사용하면 위험이 가장 적은 시점에 시장에 진입하고 주요 추세에 부합하도록 거래 시점을 계획할 수 있습니다.
매개변수
지표에는 구성 가능한 매개 변수는 계산 기간 하나가 있습니다. 기본값은 14입니다.
과매수/과매도 영역은 지표 신호를 검색하는 데 사용되므로 이 영역은 EA의 입력 매개변수에도 포함되어야 합니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorDeM.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpOverbough= 0.7; /* Overbough level*/ input double InpOversold = 0.3; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // DeMarker calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorDeM.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpOverbough= 0.7; /* Overbough level*/ input double InpOversold = 0.3; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // DeMarker calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("DeM(%lu)",period); ind_digits=3; //--- Create indicator handle ResetLastError(); handle=iDeMarker(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("DeM(%lu)",period); ind_digits=3; //--- Create indicator handle ResetLastError(); handle=iDeMarker(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state relative to the overbought level string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); //--- The label color changes depending on the value of the line relative to the level color clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,100); //--- Display a description of the indicator line state relative to the oversold level panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- The label color changes depending on the value of the line relative to the level clr=(state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the location of the line in the overbought/oversold areas clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
과매수 및 과매도 영역의 지표 선의 위치는 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorDeM.mq5" EA 파일은 아래에 첨부되어 있습니다.
포스 인덱스
강도 지수(Force Index(FRC)) 기술 지표는 알렉산더 엘더가 개발했습니다. 이 지수는 지수가 상승할 때마다 상승세를, 하락할 때마다 하락세를 측정하며 시장 정보의 기본 요소인 가격 추세, 하락폭, 볼륨을 연결합니다. 이 지수는 그대로 사용할 수 있지만 이동 평균을 사용하여 근사치를 구하는 것이 좋습니다. 짧은 이동평균(저자는 2구간 사용을 제안함)을 이용한 근사치는 포지션에 진입하고 청산할 수 있는 최적의 기회를 찾는 데 도움이 됩니다. 긴 이동 평균(기간 13)을 사용하여 근사치를 수행하면 지수는 추세 변화를 표시합니다.
- 지표가 증가하는 경향의 기간에 강도가 마이너스가 될 때 (0 이하로 떨어질 때) 매수하는 것이 좋습니다;
- 강도 지수가 새로운 정점을 높일 경우 증가 추세가 지속되고 있음을 나타냅니다;
- 매도 신호는 하락 추세에서 지수가 플러스가 될 때 발생합니다;
- 강도 지수는 매도세와 지수가 새로운 저점으로 떨어질 때 감소하는 경향의 지속을 나타냅니다;
- 가격 변동이 볼륨 변동과 상관관계가 없는 경우 강도 지표는 어느 수준에 머물게 되고 이는 추세가 곧 바뀔 것임을 알려줍니다.

매개변수
지표에는 세 가지 입력 매개변수가 있습니다:
- 계산 기간, 기본값 - 2,
- 계산 방법, 기본값 - SMA,
- 기본적으로 사용되는 볼륨 - 체크.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorForce.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Period */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input ENUM_APPLIED_VOLUME InpAppliedVol = VOLUME_TICK; /* Applied Volume */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Force Index calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorForce.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 13; /* Period */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input ENUM_APPLIED_VOLUME InpAppliedVol = VOLUME_TICK; /* Applied Volume */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Force Index calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Force(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iForce(Symbol(),PERIOD_CURRENT,period,InpMethod,InpAppliedVol); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 13 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Force(%lu)",period); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iForce(Symbol(),PERIOD_CURRENT,period,InpMethod,InpAppliedVol); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); // The label color changes depending on the value of the line above/below zero panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
0보다 높거나 낮은 지표 선의 값은 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorForce.mq5" EA 파일은 아래에 첨부되어 있습니다.
MACD
이동 평균 수렴/발산(MACD)은 추세를 따르는 동적 지표이며 두 가격 이동 평균간의 상관관계를 나타냅니다.
MACD는 26주와 12주 지수 이동 평균(EMA)의 차이입니다. 매수/매도 기회를 명확하게 보여주기 위해 신호선(지표의 9주 이동평균)이란 것을 MACD 차트에 표시합니다.
MACD는 변동폭이 큰 트레이딩 시장에서 가장 효과적입니다. 이동평균 수렴/발산은 크로스오버, 과매수/과매도 조건, 발산 등 세 가지 방법으로 많이 사용됩니다.
교차
MACD 트레이딩의 기본 규칙은 MACD가 신호선 아래로 떨어지면 매도하는 것입니다. 마찬가지로 이동평균 수렴/발산이 신호선 위로 상승하면 매수 신호가 발생합니다. MACD가 0보다 높거나 낮을 때 매수/매도하는 것도 인기입니다.
과매수/과매도 조건
MACD는 과매수/과매도 지표로도 유용합니다. 짧은 이동평균이 긴 이동평균에서 급격히 멀어지면(즉, MACD가 상승하면) 심볼 가격이 과도하게 확장되고 있으며 이는 곧 더 현실적인 수준으로 돌아올 가능성이 높다는 것입니다.
다이버전스
현재 추세의 끝이 가까워졌다는 신호는 MACD가 심볼에서 벗어날 때 발생합니다. 강세 다이버전스는 이동평균 수렴/발산 지표가 새로운 저점을 기록하는 반면 가격이 이를 달성하지 못할 때 발생합니다. 약세 다이버전스는 MACD가 새로운 최고치를 기록하는 동안 가격이 최고치에 도달하지 못할 때 발생합니다. 이 두 가지 차이는 상대적으로 과매수/과매도 수준에서 발생할 때 가장 두드러집니다.
매개변수
지표에는 네 가지 매개 변수가 있습니다:
- 빠른 EMA 계산 기간, 기본값 - 12
- 느린 EMA 계산 기간, 기본값 - 26,
- 신호 SMA 계산 기간, 기본값 - 9,
- 계산 가격, 기본값 - 종가.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorMACD.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 12; /* Fast MA Period */ input uint InpPeriodSlow = 26; /* Slow MA Period */ input uint InpPeriodSignal= 9; /* MACD SMA */ input ENUM_APPLIED_PRICE InpAppliedPrice= PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int period_signal=0; // Signal line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorMACD.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 12; /* Fast MA Period */ input uint InpPeriodSlow = 26; /* Slow MA Period */ input uint InpPeriodSignal= 9; /* MACD SMA */ input ENUM_APPLIED_PRICE InpAppliedPrice= PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int period_signal=0; // Signal line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 12 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 26 : InpPeriodSlow==period_fast ? period_fast+1 : InpPeriodSlow); period_signal=int(InpPeriodSignal<1 ? 9 : InpPeriodSignal); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("MACD(%lu,%lu,%lu)",period_fast,period_slow,period_signal); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iMACD(Symbol(),PERIOD_CURRENT,period_fast,period_slow,period_signal,InpAppliedPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 12 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 26 : InpPeriodSlow==period_fast ? period_fast+1 : InpPeriodSlow); period_signal=int(InpPeriodSignal<1 ? 9 : InpPeriodSignal); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("MACD(%lu,%lu,%lu)",period_fast,period_slow,period_signal); ind_digits=Digits()+1; //--- Create indicator handle ResetLastError(); handle=iMACD(Symbol(),PERIOD_CURRENT,period_fast,period_slow,period_signal,InpAppliedPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,261); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,5,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display the indicator signal line data from the specified bar on the panel in table 1 panel.DrawText("Signal", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double signal=IndicatorValue(handle,index,1); string signal_str=(signal!=EMPTY_VALUE ? DoubleToString(signal,ind_digits) : ""); panel.DrawText(signal_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Display a description of the indicator line state relative to zero panel.DrawText("MACD vs Zero", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_zero=LineStateRelative(handle,index,0,0); string state_zero_str= ( state_zero==LINE_STATE_ABOVE ? "MACD > 0" : state_zero==LINE_STATE_UNDER ? "MACD < 0" : state_zero==LINE_STATE_TOUCH_ABOVE || state_zero==LINE_STATE_TOUCH_BELOW ? "Touch" : LineStateDescription(state_zero) ); //--- The label color changes depending on the value of the line relative to the level color clr=(state_zero==LINE_STATE_CROSS_UP ? clrBlue : state_zero==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_zero_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Display a description of the indicator line state relative to the signal line panel.DrawText("MACD vs Signal", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_signal=LineStateRelative(handle,index,0,signal,IndicatorValue(handle,index+1,1)); string state_signal_str=(state_signal==LINE_STATE_ABOVE ? "MACD > Signal" : state_signal==LINE_STATE_UNDER ? "MACD < Signal" : LineStateDescription(state_signal)); //--- The label color changes depending on the value of the line relative to the level clr=(state_signal==LINE_STATE_CROSS_UP ? clrBlue : state_signal==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_signal_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
신호선과 0을 기준으로 한 히스토그램의 비율은 패널에서 색상으로 강조되어 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표의 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorMACD.mq5" EA 파일은 아래에 첨부되어 있습니다.
모멘텀
모멘텀 보조지표는 주어진 기간 동안 금융상품의 가격 변동을 측정합니다. 모멘텀 지표를 사용하는 방법은 기본적으로 두 가지입니다:
- 이동 평균 수렴/발산(MACD)과 유사한 추세 추종 지표입니다. 이 경우 모멘텀 지표가 저점을 형성하고 상승하기 시작하면 매수 신호가 발생하고 정점에 도달하고 하락세로 전환하면 매도 신호가 발생합니다. 지표의 단기 이동 평균을 그려서 지표의 바닥 또는 정점의 시점을 확인할 수 있습니다.
모멘텀의 값이 매우 높거나 낮으면 현재 추세가 지속되고 있음을 의미합니다. 따라서 지표가 매우 높은 값에 도달했다가 하락하면 추가 가격 상승을 예상해야 합니다. 어떤 경우든 지표에서 생성된 신호를 가격이 확인한 후에만 포지션에 진입하거나 청산해야 합니다. - 선행 지표로서. 이 방법은 상승 추세의 마지막 단계에는 일반적으로 급격한 가격 상승(모두가 가격이 더 오를 것으로 기대하는 시기)이 동반되고 하락장의 끝에는 급격한 가격 하락(모두가 빠져나오려고 하는 시기)이 특징이라고 가정합니다. 이는 종종 발생하지만 이는 광범위한 일반화이기도 합니다.
시장이 정점에 가까워지면 모멘텀 지표가 급격히 상승합니다. 그 이후에는 가격이 계속 상승하거나 수평으로 움직이면서 하락하기 시작합니다. 이와 유사하게 시장 바닥에서는 모멘텀이 급격히 하락했다가 가격이 상승하기 훨씬 전에 상승세로 돌아섭니다. 이 두 가지 상황 모두 지표와 가격 사이에 차이가 발생합니다.
매개변수
지표에는 두 가지 입력 매개변수가 있습니다:
- 계산 기간, 기본값 - 14,
- 계산 가격, 기본값 - 종가.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorMomentum.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Momentum calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorMomentum.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // Momentum calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Momentum(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iMomentum(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Momentum(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iMomentum(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
아래에 "TestOscillatorMomentum.mq5" EA 파일이 첨부되어 있습니다.
오실레이터 이동 평균
오실레이터 이동 평균(OsMA)은 오실레이터와 오실레이터 평활화의 차이입니다. 이 경우 이동평균 수렴/발산 기준선이 오실레이터로 사용되고 신호선이 평활화로 사용됩니다.
매개변수
지표에는 네 가지 매개 변수가 있습니다:
- 빠른 EMA MACD 계산 기간, 기본값 - 12,
- 느린 EMA MACD 계산 기간, 기본값 - 26,
- 신호 SMA MACD 계산 기간, 기본값 - 9,
- MACD 계산 가격, 기본값 - 종가.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorOsMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 12; /* Fast MA Period */ input uint InpPeriodSlow = 26; /* Slow MA Period */ input uint InpPeriodSignal= 9; /* MACD SMA */ input ENUM_APPLIED_PRICE InpAppliedPrice= PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int period_signal=0; // Signal line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorOsMA.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodFast = 12; /* Fast MA Period */ input uint InpPeriodSlow = 26; /* Slow MA Period */ input uint InpPeriodSignal= 9; /* MACD SMA */ input ENUM_APPLIED_PRICE InpAppliedPrice= PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_fast=0; // Fast EMA calculation period int period_slow=0; // Slow EMA calculation period int period_signal=0; // Signal line calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 12 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 26 : InpPeriodSlow==period_fast ? period_fast+1 : InpPeriodSlow); period_signal=int(InpPeriodSignal<1 ? 9 : InpPeriodSignal); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("OsMA(%lu,%lu,%lu)",period_fast,period_slow,period_signal); ind_digits=Digits()+2; //--- Create indicator handle ResetLastError(); handle=iOsMA(Symbol(),PERIOD_CURRENT,period_fast,period_slow,period_signal,InpAppliedPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_fast=int(InpPeriodFast<1 ? 12 : InpPeriodFast); period_slow=int(InpPeriodSlow<1 ? 26 : InpPeriodSlow==period_fast ? period_fast+1 : InpPeriodSlow); period_signal=int(InpPeriodSignal<1 ? 9 : InpPeriodSignal); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("OsMA(%lu,%lu,%lu)",period_fast,period_slow,period_signal); ind_digits=Digits()+2; //--- Create indicator handle ResetLastError(); handle=iOsMA(Symbol(),PERIOD_CURRENT,period_fast,period_slow,period_signal,InpAppliedPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the value of the line above/below zero color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Display a description of the indicator line state relative to zero panel.DrawText("OsMA vs Zero", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_zero=LineStateRelative(handle,index,0,0); string state_zero_str= ( state_zero==LINE_STATE_ABOVE ? "OsMA > 0" : state_zero==LINE_STATE_UNDER ? "OsMA < 0" : state_zero==LINE_STATE_TOUCH_ABOVE || state_zero==LINE_STATE_TOUCH_BELOW ? "Touch" : LineStateDescription(state_zero) ); //--- The label color changes depending on the value of the line relative to the level clr=(state_zero==LINE_STATE_CROSS_UP ? clrBlue : state_zero==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_zero_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
지표의 상태와 0을 기준으로 한 위치는 대시보드에서 색상으로 강조 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorOsMA.mq5" EA 파일은 아래에 첨부되어 있습니다.
상대 강도 지수
상대 강도 지수(RSI)는 0에서 100 사이의 가격 추종형 오실레이터입니다. 상대 강도 지수 설명, J. W. 와일더는 14 기간인 버전을 사용할 것을 권장했습니다. 이후 9주 및 25주 상대강도지수 지표도 인기를 얻고 있습니다. RSI를 분석하는 인기 있는 방법은 상품이 새로운 최고치를 기록했지만 RSI가 이전 최고치를 넘어서지 못하는 다이버전스를 찾는 것입니다. 이러한 차이는 곧 반전이 임박했음을 나타냅니다. 이후 지표가 하락세로 돌아서 가장 최근 저점 아래로 떨어지면 "실패 스윙"이 일어난 것으로 간주합니다. 이 실패 스윙은 반전이 임박했음을 확인하는 것으로 간주됩니다.
차트 분석에 사용되는 상대 강도 지수의 신호는 다음과 같습니다:
- 상단 및 하단
상대 강도 지수는 일반적으로 70 이상, 30 미만이 최고치이며 일반적으로 기본 가격 차트보다 먼저 이러한 고점과 저점을 형성합니다. - 차트 포메이션
RSI는 종종 가격 차트에 표시되거나 표시되지 않을 수 있는 헤드 앤 숄더 또는 삼각수렴과 같은 차트 패턴을 형성합니다. - 실패한 스윙(지지 또는 저항 돌파)
상대 강도 지수가 이전 최고치(고점)를 넘어서거나 최근 최저치(저점) 아래로 떨어지는 지점입니다. - 지지 및 저항 수준
상대강도 지수는 가격 자체보다 더 명확하게 지지와 저항 수준을 보여줍니다. - 다이버전스
위에서 설명한 것처럼 다이버전스는 상대강도지수에서 새로운 고점(또는 저점)이 확인되지 않은 상태에서 가격이 새로운 고점(또는 저점)을 기록할 때 발생합니다. 가격은 일반적으로 RSI의 방향을 따라 조정되고 움직입니다.
매개변수
지표에는 두 가지 입력 매개변수가 있습니다:
- 계산 기간, 기본값 - 14,
- 계산 가격, 기본값 - 종가.
과매수/과매도 영역은 지표 신호 검색에 적용되므로 해당 값을 EA의 입력값으로도 사용할 것입니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorRSI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ input double InpOverbough= 70; /* Overbough level*/ input double InpOversold = 30; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // RSI calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorRSI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */ input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ input double InpOverbough= 70; /* Overbough level*/ input double InpOversold = 30; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // RSI calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("RSI(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iRSI(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("RSI(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iRSI(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display a description of the indicator line state relative to the overbought level string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); //--- The label color changes depending on the value of the line relative to the level color clr=(state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,100); //--- Display a description of the indicator line state relative to the oversold level panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- The label color changes depending on the value of the line relative to the level clr=(state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,100); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the location of the line in the overbought/oversold areas clr=(state_ovb==LINE_STATE_ABOVE || state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : state_ovs==LINE_STATE_UNDER || state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
과매수/과매도 영역에서 선의 위치와 레벨 대비 선의 상태는 패널에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorRSI.mq5" EA 파일은 아래에 첨부되어 있습니다.
상대 활력 지수
상대 활력 지수(Relative Vigor Index; RVI) 의 요점은 강세장에서는 종가가 일반적으로 시초가보다 높다는 것입니다. 약세장에서는 그 반대입니다. 따라서 상대 활력 지수의 개념은 종가 기준으로 움직임의 활력 또는 에너지가 어디에서 끝나는지에 따라 결정된다는 것입니다. 일일 거래 범위로 지수를 정규화 하려면 가격 변동폭을 당일 최대 가격 범위로 나눕니다. 보다 원활한 계산을 위해 단순 이동 평균을 사용합니다. 보통 10이 가장 좋은 기간으로 간주됩니다. 모호성을 피하려면 상대적 활력 지수 값의 4주기 대칭 가중 이동 평균인 신호선을 구성해야 합니다. 라인의 일치 여부는 매수 또는 매도 신호로 사용됩니다.
매개변수
지표에는 구성 가능한 매개 변수는 계산 기간 하나가 있습니다. 기본값은 10입니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorRVI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 10; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // RVI calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorRVI.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 10; /* Period */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // RVI calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 10 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("RVI(%lu)",period); ind_digits=3; //--- Create indicator handle ResetLastError(); handle=iRVI(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 10 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("RVI(%lu)",period); ind_digits=3; //--- Create indicator handle ResetLastError(); handle=iRVI(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display the indicator signal line data from the specified bar on the panel in table 1 panel.DrawText("Signal", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double signal=IndicatorValue(handle,index,1); string signal_str=(signal!=EMPTY_VALUE ? DoubleToString(signal,ind_digits) : ""); panel.DrawText(signal_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,90); //--- Display a description of the indicator line state relative to the signal line panel.DrawText("RVI vs Signal", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_signal=LineStateRelative(handle,index,0,signal,IndicatorValue(handle,index+1,1)); string state_signal_str=(state_signal==LINE_STATE_ABOVE ? "RVI > Signal" : state_signal==LINE_STATE_UNDER ? "RVI < Signal" : LineStateDescription(state_signal)); //--- The label color changes depending on the value of the line relative to the level color clr=(state_signal==LINE_STATE_CROSS_UP ? clrBlue : state_signal==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_signal_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
지표 신호(지표 선과 신호선의 교차점)는 대시보드에서 색상으로 강조 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorRVI.mq5" EA 파일은 아래에 첨부되어 있습니다.
스토캐스틱 오실레이터
스토캐스틱 오실레이터는 특정 기간 동안의 가격 범위와 비교하여 유가증권의 종가를 비교합니다. 스토캐스틱 오실레이터는 두 줄로 표시됩니다. 메인 라인은 %K라고 합니다. 두 번째 선인 %D는 %K 선의 이동 평균입니다. K 라인은 일반적으로 실선으로 표시되고 %D 라인은 일반적으로 점선으로 표시됩니다. 스토캐스틱 오실레이터를 해석하는 방법에는 여러 가지가 있습니다. 널리 사용되는 세 가지 방법은 다음과 같습니다:
- 오실레이터(%K 또는 %D)가 특정 수준(예: 20) 아래로 떨어졌다가 해당 수준 이상으로 상승할 때 매수합니다. 오실레이터가 특정 레벨(예: 80) 이상으로 상승했다가 해당 레벨 아래로 떨어지면 매도하세요.
- K 라인이 %D 위로 상승하면 매수합니다. K가 %D 아래로 떨어지면 판매합니다.
- 차이점을 찾아보세요. 예를 들어, 가격이 연이어 최고치를 경신하고 있는데 스토캐스틱 오실레이터가 이전 최고치를 넘어서지 못하는 경우입니다.
매개변수
지표에는 5개의 입력 매개변수가 있습니다:
- K 선 계산 기간, 기본값 - 5,
- D 선 계산 기간, 기본값 - 3,
- 슬로우 기간, 기본값 - 3,
- 확률적 계산 가격, 기본값 - 저가/고가,
- 계산 방법, 기본값 - SMA.
이러한 값 외에도 EA 입력에 과매수 및 과매도 수준을 지정해야 합니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorStoch.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodK = 5; /* Period %K */ input uint InpPeriodD = 3; /* Period %D */ input uint InpSlowing = 3; /* Slowing */ input ENUM_STO_PRICE InpPrice = STO_LOWHIGH; /* Price */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input double InpOverbough= 80; /* Overbough level*/ input double InpOversold = 20; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_k=0; // %K period int period_d=0; // %D period int slowing=0; // Slowing period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorStoch.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriodK = 5; /* Period %K */ input uint InpPeriodD = 3; /* Period %D */ input uint InpSlowing = 3; /* Slowing */ input ENUM_STO_PRICE InpPrice = STO_LOWHIGH; /* Price */ input ENUM_MA_METHOD InpMethod = MODE_SMA; /* Method */ input double InpOverbough= 80; /* Overbough level*/ input double InpOversold = 20; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period_k=0; // %K period int period_d=0; // %D period int slowing=0; // Slowing period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_k=int(InpPeriodK<1 ? 5 : InpPeriodK); period_d=int(InpPeriodD<1 ? 3 : InpPeriodD); slowing =int(InpSlowing<1 ? 3 : InpSlowing); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Stoch(%lu,%lu,%lu)",period_k,period_d,slowing); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iStochastic(Symbol(),PERIOD_CURRENT,period_k,period_d,slowing,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period_k=int(InpPeriodK<1 ? 5 : InpPeriodK); period_d=int(InpPeriodD<1 ? 3 : InpPeriodD); slowing =int(InpSlowing<1 ? 3 : InpSlowing); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("Stoch(%lu,%lu,%lu)",period_k,period_d,slowing); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iStochastic(Symbol(),PERIOD_CURRENT,period_k,period_d,slowing,InpMethod,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,261); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,5,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,100); //--- Display the indicator signal line data from the specified bar on the panel in table 1 panel.DrawText("Signal", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); double signal=IndicatorValue(handle,index,1); string signal_str=(signal!=EMPTY_VALUE ? DoubleToString(signal,ind_digits) : ""); panel.DrawText(signal_str,panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clrNONE,100); //--- Display a description of the indicator line state relative to the signal line panel.DrawText("Stoch vs Signal", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_signal=LineStateRelative(handle,index,0,signal,IndicatorValue(handle,index+1,1)); string state_signal_str=(state_signal==LINE_STATE_ABOVE ? "Stoch > Signal" : state_signal==LINE_STATE_UNDER ? "Stoch < Signal" : LineStateDescription(state_signal)); //--- The label color changes depending on the value of the line relative to the level color clr=(state_signal==LINE_STATE_CROSS_UP ? clrBlue : state_signal==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_signal_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,100); //--- Display a description of the indicator line state relative to the overbought level string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); panel.DrawText(ovb, panel.CellX(1,3,0)+66, panel.CellY(1,3,0)+2); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); //--- The label color changes depending on the value of the line relative to the level clr=(state_ovb==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,100); //--- Display a description of the indicator line state relative to the oversold level panel.DrawText("Oversold", panel.CellX(1,4,0)+2, panel.CellY(1,4,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,4,0)+68, panel.CellY(1,4,0)+2); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- The label color changes depending on the value of the line relative to the level clr=(state_ovs==LINE_STATE_CROSS_UP ? clrBlue : clrNONE); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,4,1)+2,panel.CellY(1,4,1)+2,clr,100); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
스토캐스틱 라인의 상태, 과매수/과매도 영역 및 지표 신호는 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
아래에 "TestOscillatorStoch.mq5" EA 파일이 첨부되어 있습니다.
삼중 지수 평균
트리플 지수 평균(Triple Exponential Average; TRIX)은 잭 허슨이 과매수/과매도 시장 상태의 오실레이터로 개발한 것으로 모멘텀 지표로도 사용할 수 있습니다. 트리플 스무딩은 TRIX보다 기간이 짧은 가격 변동에서 주기적인 요소를 제거하는 데 사용됩니다.
이 영역은 과매수 또는 과매도 상태(각각 양수 및 음수)를 나타내는 지표로 사용됩니다. 매수 신호는 지표가 아래에서 0선을 넘거나 '상승' 다이버전스이고, 매도 신호는 지표가 위에서 0선을 넘거나 가격과의 '하락' 다이버전스입니다. 이 지표의 특징은 가격 노이즈를 완벽하게 걸러내고 대부분의 이동평균에서 흔히 볼 수 있는 지연이 없다는 것입니다.
매개변수
지표에는 두 가지 입력 매개변수가 있습니다:
- 계산 기간, 기본값 - 14,
- 계산 가격, 기본값 - 종가.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorTRIX.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */// input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // TRIX calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorTRIX.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod= 14; /* Period */// input ENUM_APPLIED_PRICE InpPrice = PRICE_CLOSE; /* Applied Price */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // TRIX calculation period int ind_digits=0; // Number of decimal places in the indicator values string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("TRIX(%lu)",period); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iTriX(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period if necessary period=int(InpPeriod<1 ? 14 : InpPeriod<2 ? 2 : InpPeriod); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("TRIX(%lu)",period); ind_digits=Digits(); //--- Create indicator handle ResetLastError(); handle=iTriX(Symbol(),PERIOD_CURRENT,period,InpPrice); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,199,225); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,97); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,3,2,18,97); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); ENUM_LINE_STATE state=LineState(handle,index,0); //--- The label color changes depending on the value of the line above/below zero color clr=(value<0 ? clrRed : value>0 ? clrBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Display a description of the indicator line state relative to zero panel.DrawText("TRIX vs Zero", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); ENUM_LINE_STATE state_zero=LineStateRelative(handle,index,0,0); string state_zero_str= ( state_zero==LINE_STATE_ABOVE ? "TRIX > 0" : state_zero==LINE_STATE_UNDER ? "TRIX < 0" : state_zero==LINE_STATE_TOUCH_ABOVE || state_zero==LINE_STATE_TOUCH_BELOW ? "Touch" : LineStateDescription(state_zero) ); //--- The label color changes depending on the value of the line relative to the level clr=(state_zero==LINE_STATE_CROSS_UP ? clrBlue : state_zero==LINE_STATE_CROSS_DOWN ? clrRed : clrNONE); panel.DrawText(state_zero_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
선의 상태와 0과의 관계는 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorTRIX.mq5" EA 파일은 아래에 첨부되어 있습니다.
윌리엄스의 퍼센트 범위
윌리엄스 퍼센트 범위(%R)는 시장의 과매수/과매도 여부를 판단하는 동적 기술 지표입니다. 윌리엄스의 퍼센트 범위는 스토캐스틱 오실레이터와 매우 유사합니다. 유일한 차이점은 %R의 스케일이 거꾸로 되어 있고 스토캐스틱 오실레이터는 내부 평활화가 있다는 점입니다.
지표 값이 -80%에서 -100% 사이이면 시장이 과매도 상태임을 나타냅니다. 지표 값이 -0%에서 -20% 사이이면 시장이 과매수 상태임을 나타냅니다. 이렇게 거꾸로 표시하려면 윌리엄스 퍼센트 범위 값 앞에 마이너스 기호를 배치합니다(예: -30%). 분석을 수행할 때는 마이너스 기호를 무시해야 합니다.
모든 과매수/과매도 지표와 마찬가지로, 거래하기 전에 심볼 가격의 방향이 바뀔 때까지 기다리는 것이 가장 좋습니다. 예를 들어 과매수/과매도 지표가 과매수 상태를 나타내는 경우 주식을 매도하기 전에 가격이 하락할 때까지 기다리는 것이 현명합니다.
윌리엄스 퍼센트 범위 지표의 흥미로운 현상은 기본 주식 가격의 반전을 예측할 수 있는 기이한 능력입니다. 지표는 거의 항상 주식 가격이 정점을 찍고 하락하기 며칠 전에 정점을 형성하고 하락합니다. 마찬가지로 윌리엄스 퍼센트 범위는 일반적으로 저점을 형성하고 주식 가격이 상승하기 며칠 전에 상승합니다.
매개변수
지표에는 구성 가능한 매개 변수는 계산 기간 하나가 있습니다. 기본값은 14입니다.
지표 신호를 결정하기 위해서는 과매수/과매도 영역에서 선의 위치를 고려해야 합니다. 이를 위해 레벨의 값을 EA 입력에 추가해야 합니다.
EA에서 지표를 사용하기 위한 입력 및 전역 변수입니다:
//+------------------------------------------------------------------+ //| TestOscillatorWPR.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpOverbough= -20.0; /* Overbough level*/ input double InpOversold = -80.0; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // TRIX calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description
대시보드를 사용할 때 패널 클래스 파일이 포함되고 작업할 수 있는 변수가 추가됩니다:
//+------------------------------------------------------------------+ //| TestOscillatorWPR.mq5 | //| Copyright 2023, MetaQuotes Ltd. | //| https://www.mql5.com | //+------------------------------------------------------------------+ #property copyright "Copyright 2023, MetaQuotes Ltd." #property link "https://www.mql5.com" #property version "1.00" //--- includes #include <Dashboard\Dashboard.mqh> //--- enums enum ENUM_LINE_STATE { LINE_STATE_NONE, // Undefined state LINE_STATE_UP, // Upward LINE_STATE_DOWN, // Downward LINE_STATE_TURN_UP, // Upward reversal LINE_STATE_TURN_DOWN, // Downward reversal LINE_STATE_STOP_UP, // Upward stop LINE_STATE_STOP_DOWN, // Downward stop LINE_STATE_ABOVE, // Above value LINE_STATE_UNDER, // Below value LINE_STATE_CROSS_UP, // Crossing value upwards LINE_STATE_CROSS_DOWN, // Crossing value downwards LINE_STATE_TOUCH_BELOW, // Touching value from below LINE_STATE_TOUCH_ABOVE, // Touch value from above LINE_STATE_EQUALS, // Equal to value }; //--- input parameters input uint InpPeriod = 14; /* Period */ input double InpOverbough= -20.0; /* Overbough level*/ input double InpOversold = -80.0; /* Oversold level */ //--- global variables int handle=INVALID_HANDLE; // Indicator handle int period=0; // TRIX calculation period int ind_digits=0; // Number of decimal places in the indicator values double overbough=0; // Overbought level double oversold=0; // Oversold level string ind_title; // Indicator description //--- variables for the panel int mouse_bar_index; // Index of the bar the data is taken from CDashboard *panel=NULL; // Pointer to the panel object
초기화
OnInit( ) 핸들러는 지표 매개변수를 초기화하고 해당 핸들을 생성합니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("%%R(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iWPR(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Successful initialization return(INIT_SUCCEEDED); }
패널은 대시보드를 사용할 때 만들어집니다:
//+------------------------------------------------------------------+ //| Expert initialization function | //+------------------------------------------------------------------+ int OnInit() { //--- create timer EventSetTimer(60); //--- Indicator //--- Set and adjust the calculation period and levels if necessary period=int(InpPeriod<1 ? 14 : InpPeriod); overbough=InpOverbough; oversold=(InpOversold>=overbough ? overbough-0.01 : InpOversold); //--- Set the indicator name and the number of decimal places ind_title=StringFormat("%%R(%lu)",period); ind_digits=2; //--- Create indicator handle ResetLastError(); handle=iWPR(Symbol(),PERIOD_CURRENT,period); if(handle==INVALID_HANDLE) { PrintFormat("%s: Failed to create indicator handle %s. Error %ld",__FUNCTION__,ind_title,GetLastError()); return INIT_FAILED; } //--- Dashboard //--- Create the panel panel=new CDashboard(1,20,20,229,243); if(panel==NULL) { Print("Error. Failed to create panel object"); return INIT_FAILED; } //--- Set font parameters panel.SetFontParams("Calibri",9); //--- Display the panel with the "Symbol, Timeframe description" header text panel.View(Symbol()+", "+StringSubstr(EnumToString(Period()),7)); //--- Create a table with ID 0 to display bar data in it panel.CreateNewTable(0); //--- Draw a table with ID 0 on the panel background panel.DrawGrid(0,2,20,6,2,18,112); //--- Create a table with ID 1 to display indicator data in it panel.CreateNewTable(1); //--- Get the Y2 table coordinate with ID 0 and //--- set the Y1 coordinate for the table with ID 1 int y1=panel.TableY2(0)+22; //--- Draw a table with ID 1 on the panel background panel.DrawGrid(1,2,y1,4,2,18,112); //--- Display tabular data in the journal panel.GridPrint(0,2); panel.GridPrint(1,2); //--- Initialize the variable with the index of the mouse cursor bar mouse_bar_index=0; //--- Display the data of the current bar on the panel DrawData(mouse_bar_index,TimeCurrent()); //--- Successful initialization return(INIT_SUCCEEDED); }
초기화 해제
EA OnDeinit() 핸들러 에서 지표 핸들을 해제합니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); }
대시보드를 사용할 때 생성된 대시보드 객체가 제거됩니다:
//+------------------------------------------------------------------+ //| Expert deinitialization function | //+------------------------------------------------------------------+ void OnDeinit(const int reason) { //--- destroy timer EventKillTimer(); //--- Release handle of the indicator ResetLastError(); if(!IndicatorRelease(handle)) PrintFormat("%s: IndicatorRelease failed. Error %ld",__FUNCTION__,GetLastError()); //--- Clear all comments on the chart Comment(""); //--- If the panel object exists, delete it if(panel!=NULL) delete panel; }
데이터 검색
지표 핸들로 데이터를 얻기 위한 일반 함수:
//+------------------------------------------------------------------+ //| Return the indicator data on the specified bar | //+------------------------------------------------------------------+ double IndicatorValue(const int ind_handle,const int index,const int buffer_num) { double array[1]={0}; ResetLastError(); if(CopyBuffer(ind_handle,buffer_num,index,1,array)!=1) { PrintFormat("%s: CopyBuffer failed. Error %ld",__FUNCTION__,GetLastError()); return EMPTY_VALUE; } return array[0]; } //+------------------------------------------------------------------+ //| Return the state of the indicator line | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineState(const int ind_handle,const int index,const int buffer_num) { //--- Get the values of the indicator line with the shift (0,1,2) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); const double value2=IndicatorValue(ind_handle,index+2,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE || value2==EMPTY_VALUE) return LINE_STATE_NONE; //--- Line upward reversal (value2>value1 && value0>value1) if(NormalizeDouble(value2-value1,ind_digits)>0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_TURN_UP; //--- Line upward direction (value2<=value1 && value0>value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)>0) return LINE_STATE_UP; //--- Line upward stop (value2<=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)<=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_UP; //--- Line downward reversal (value2<value1 && value0<value1) if(NormalizeDouble(value2-value1,ind_digits)<0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_TURN_DOWN; //--- Line downward direction (value2>=value1 && value0<value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)<0) return LINE_STATE_DOWN; //--- Line downward stop (value2>=value1 && value0==value1) else if(NormalizeDouble(value2-value1,ind_digits)>=0 && NormalizeDouble(value0-value1,ind_digits)==0) return LINE_STATE_STOP_DOWN; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the state of the line relative to the specified level | //+------------------------------------------------------------------+ ENUM_LINE_STATE LineStateRelative(const int ind_handle,const int index,const int buffer_num,const double level0,const double level1=EMPTY_VALUE) { //--- Get the values of the indicator line with the shift (0,1) relative to the passed index const double value0=IndicatorValue(ind_handle,index, buffer_num); const double value1=IndicatorValue(ind_handle,index+1,buffer_num); //--- If at least one of the values could not be obtained, return an undefined value if(value0==EMPTY_VALUE || value1==EMPTY_VALUE) return LINE_STATE_NONE; //--- Define the second level to compare double level=(level1==EMPTY_VALUE ? level0 : level1); //--- The line is below the level (value1<level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_UNDER; //--- The line is above the level (value1>level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_ABOVE; //--- The line crossed the level upwards (value1<=level && value0>level0) if(NormalizeDouble(value1-level,ind_digits)<=0 && NormalizeDouble(value0-level0,ind_digits)>0) return LINE_STATE_CROSS_UP; //--- The line crossed the level downwards (value1>=level && value0<level0) if(NormalizeDouble(value1-level,ind_digits)>=0 && NormalizeDouble(value0-level0,ind_digits)<0) return LINE_STATE_CROSS_DOWN; //--- The line touched the level from below (value1<level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)<0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- The line touched the level from above (value1>level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)>0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_TOUCH_BELOW; //--- Line is equal to the level value (value1==level0 && value0==level0) if(NormalizeDouble(value1-level,ind_digits)==0 && NormalizeDouble(value0-level0,ind_digits)==0) return LINE_STATE_EQUALS; //--- Undefined state return LINE_STATE_NONE; } //+------------------------------------------------------------------+ //| Return the indicator line state description | //+------------------------------------------------------------------+ string LineStateDescription(const ENUM_LINE_STATE state) { switch(state) { case LINE_STATE_UP : return "Up"; case LINE_STATE_STOP_UP : return "Stop Up"; case LINE_STATE_TURN_UP : return "Turn Up"; case LINE_STATE_DOWN : return "Down"; case LINE_STATE_STOP_DOWN : return "Stop Down"; case LINE_STATE_TURN_DOWN : return "Turn Down"; case LINE_STATE_ABOVE : return "Above level"; case LINE_STATE_UNDER : return "Under level"; case LINE_STATE_CROSS_UP : return "Crossing Up"; case LINE_STATE_CROSS_DOWN : return "Crossing Down"; case LINE_STATE_TOUCH_BELOW: return "Touch from Below"; case LINE_STATE_TOUCH_ABOVE: return "Touch from Above"; case LINE_STATE_EQUALS : return "Equals"; default : return "Unknown"; } }
대시보드를 사용할 때 함수를 사용하여 패널에 데이터가 표시됩니다:
//+------------------------------------------------------------------+ //| Display data from the specified timeseries index to the panel | //+------------------------------------------------------------------+ void DrawData(const int index,const datetime time) { //--- Declare the variables to receive data in them MqlTick tick={0}; MqlRates rates[1]; //--- Exit if unable to get the current prices if(!SymbolInfoTick(Symbol(),tick)) return; //--- Exit if unable to get the bar data by the specified index if(CopyRates(Symbol(),PERIOD_CURRENT,index,1,rates)!=1) return; //--- Set font parameters for bar and indicator data headers int size=0; uint flags=0; uint angle=0; string name=panel.FontParams(size,flags,angle); panel.SetFontParams(name,9,FW_BOLD); panel.DrawText("Bar data ["+(string)index+"]",3,panel.TableY1(0)-16,clrMaroon,panel.Width()-6); panel.DrawText("Indicator data ["+(string)index+"]",3,panel.TableY1(1)-16,clrGreen,panel.Width()-6); //--- Set font parameters for bar and indicator data panel.SetFontParams(name,9); //--- Display the data of the specified bar in table 0 on the panel panel.DrawText("Date", panel.CellX(0,0,0)+2, panel.CellY(0,0,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_DATE), panel.CellX(0,0,1)+2, panel.CellY(0,0,1)+2,clrNONE,90); panel.DrawText("Time", panel.CellX(0,1,0)+2, panel.CellY(0,1,0)+2); panel.DrawText(TimeToString( rates[0].time,TIME_MINUTES), panel.CellX(0,1,1)+2, panel.CellY(0,1,1)+2,clrNONE,90); panel.DrawText("Open", panel.CellX(0,2,0)+2, panel.CellY(0,2,0)+2); panel.DrawText(DoubleToString(rates[0].open,Digits()), panel.CellX(0,2,1)+2, panel.CellY(0,2,1)+2,clrNONE,90); panel.DrawText("High", panel.CellX(0,3,0)+2, panel.CellY(0,3,0)+2); panel.DrawText(DoubleToString(rates[0].high,Digits()), panel.CellX(0,3,1)+2, panel.CellY(0,3,1)+2,clrNONE,90); panel.DrawText("Low", panel.CellX(0,4,0)+2, panel.CellY(0,4,0)+2); panel.DrawText(DoubleToString(rates[0].low,Digits()), panel.CellX(0,4,1)+2, panel.CellY(0,4,1)+2,clrNONE,90); panel.DrawText("Close", panel.CellX(0,5,0)+2, panel.CellY(0,5,0)+2); panel.DrawText(DoubleToString(rates[0].close,Digits()), panel.CellX(0,5,1)+2, panel.CellY(0,5,1)+2,clrNONE,90); //--- Display the indicator data from the specified bar on the panel in table 1 panel.DrawText(ind_title, panel.CellX(1,0,0)+2, panel.CellY(1,0,0)+2); double value=IndicatorValue(handle,index,0); string value_str=(value!=EMPTY_VALUE ? DoubleToString(value,ind_digits) : ""); panel.DrawText(value_str,panel.CellX(1,0,1)+2,panel.CellY(1,0,1)+2,clrNONE,90); //--- Get the state of the line and the states relative to the levels ENUM_LINE_STATE state=LineState(handle,index,0); ENUM_LINE_STATE state_ovb=LineStateRelative(handle,index,0,overbough); ENUM_LINE_STATE state_ovs=LineStateRelative(handle,index,0,oversold); //--- Display a description of the indicator line state relative to the overbought level string ovb=StringFormat("%+.2f",overbough); panel.DrawText("Overbough", panel.CellX(1,2,0)+2, panel.CellY(1,2,0)+2); panel.DrawText(ovb, panel.CellX(1,2,0)+66, panel.CellY(1,2,0)+2); color clr=clrNONE; //--- The label color changes depending on the value of the line relative to the level clr= ( state_ovb==LINE_STATE_CROSS_DOWN || (state_ovb==LINE_STATE_ABOVE && state==LINE_STATE_TURN_DOWN) ? clrRed : clrNONE ); string ovb_str=(state_ovb==LINE_STATE_ABOVE ? "Inside the area" : LineStateDescription(state_ovb)); panel.DrawText(ovb_str,panel.CellX(1,2,1)+2,panel.CellY(1,2,1)+2,clr,90); //--- Display a description of the indicator line state relative to the oversold level panel.DrawText("Oversold", panel.CellX(1,3,0)+2, panel.CellY(1,3,0)+2); string ovs=StringFormat("%+.2f",oversold); panel.DrawText(ovs, panel.CellX(1,3,0)+68, panel.CellY(1,3,0)+2); //--- The label color changes depending on the value of the line relative to the level clr= ( state_ovs==LINE_STATE_CROSS_UP || (state_ovs==LINE_STATE_UNDER && state==LINE_STATE_TURN_UP) ? clrBlue : clrNONE ); string ovs_str=(state_ovs==LINE_STATE_UNDER ? "Inside the area" : LineStateDescription(state_ovs)); panel.DrawText(ovs_str,panel.CellX(1,3,1)+2,panel.CellY(1,3,1)+2,clr,90); //--- Display a description of the indicator line state panel.DrawText("Line state", panel.CellX(1,1,0)+2, panel.CellY(1,1,0)+2); //--- The label color changes depending on the location of the line in the overbought/oversold areas clr=(state_ovb==LINE_STATE_ABOVE ? clrOrangeRed : state_ovs==LINE_STATE_UNDER ? clrDodgerBlue : clrNONE); panel.DrawText(LineStateDescription(state),panel.CellX(1,1,1)+2,panel.CellY(1,1,1)+2,clr,90); //--- Redraw the chart to immediately display all changes on the panel ChartRedraw(ChartID()); }
과매수 및 과매도 영역의 지표 라인 위치, 지표 신호 및 라인 상태는 대시보드에 색상으로 표시됩니다.
또한 패널 이벤트 핸들러는 OnChartEvent() EA 이벤트 핸들러에서 호출되며 커서 아래의 바 인덱스를 수신하는 이벤트도 처리됩니다:
//+------------------------------------------------------------------+ //| ChartEvent function | //+------------------------------------------------------------------+ void OnChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam) { //--- Handling the panel //--- Call the panel event handler panel.OnChartEvent(id,lparam,dparam,sparam); //--- If the cursor moves or a click is made on the chart if(id==CHARTEVENT_MOUSE_MOVE || id==CHARTEVENT_CLICK) { //--- Declare the variables to record time and price coordinates in them datetime time=0; double price=0; int wnd=0; //--- If the cursor coordinates are converted to date and time if(ChartXYToTimePrice(ChartID(),(int)lparam,(int)dparam,wnd,time,price)) { //--- write the bar index where the cursor is located to a global variable mouse_bar_index=iBarShift(Symbol(),PERIOD_CURRENT,time); //--- Display the bar data under the cursor on the panel DrawData(mouse_bar_index,time); } } //--- If we received a custom event, display the appropriate message in the journal if(id>CHARTEVENT_CUSTOM) { //--- Here we can implement handling a click on the close button on the panel PrintFormat("%s: Event id=%ld, object id (lparam): %lu, event message (sparam): %s",__FUNCTION__,id,lparam,sparam); } }
EA를 컴파일하고 차트에서 실행하면 패널에서 지표 선의 상태를 모니터링할 수 있습니다:
"TestOscillatorWPR.mq5" EA 파일은 아래에 첨부되어 있습니다.
결론
이 글에서는 우리는 오실레이터를 EA에 연결하는 방법에 대해 알아보았습니다. 대시보드를 사용하면 일반적인 범용 함수를 통해 얻은 지표의 값과 신호를 모니터링할 수 있습니다. 여기에서 제안된 모든 코드는 EA 코드로 쉽게 쓸수 있습니다. 복사-붙여넣기를 사용하여 "있는 그대로" 사용하거나 아래 첨부된 파일에서 다운로드하여 미세한 조정을 할 수 있습니다.
다음으로 표준 터미널에서 찾을 수 있는 나머지 지표도 같은 맥락에서 살펴보겠습니다.
MetaQuotes 소프트웨어 사를 통해 러시아어가 번역됨.
원본 기고글: https://www.mql5.com/ru/articles/13244




InpPeriod - 입력 변수 입력. 여기에 마이너스를 넣을 수 없습니다. 거기에 0을 넣을 수 있습니다. 이러한 검사 (1 미만의 경우)는 숫자를 0과 직접 비교하지 않는 습관입니다. 갑자기 다른 유사한 구조에 이중 유형의 입력 변수가 있으면 두 개의 이중 숫자를 직접 비교하지 않도록 할 수 있습니다. 예, 이것은 "완벽한"것입니다. 우선 나 자신부터 코드를 다른 곳으로 포팅할 때 실수를 줄이려고 합니다.
음, 네, uint))))))입니다. 마이너스를 넣을 수 없습니다))))
그래, 겨울))))))) 마이너스를 붙일 수 없어))))
그리고 0은요?
0은요?
0도 가능합니다. 그러나 이 경우 표시기는 기본값으로 설정됩니다.
그러나 질문의 요점은 다른 것입니다. 이미 0에 대해 알고 있습니다.
그러나 나는 추측하지 않을 것입니다.
0도 가능합니다. 그러나 이 경우 표시기는 기본값으로 설정됩니다.
그러나 질문의 요점은 다른 것이었습니다. 이미 0에 대해 알고 있습니다.
그러나 나는 추측하지 않을 것입니다.
맞습니다. 추측할 필요가 없습니다. 그냥 발레리에게 물어본 질문이었어요. 마이너스를 넣으면 안 되고 0을 넣으면 되나요?
0은요?
그래서 0은 현재입니다)))) 완벽한 디자인으로 괜찮습니다))))))
그리고 키보드에 마스크를 씌워 숫자 만 누르고 다른 키는 누르지 않도록 할 수 있습니다)))))) 90 년대 군인을 위해)))))) 그리고 다른 키를 누르면 큰 글씨로 경고가 나타났습니다)))