English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
지표 배출 (Indicator Emissions)의 적분 특성 계산

지표 배출 (Indicator Emissions)의 적분 특성 계산

MetaTrader 5 | 2 9월 2021, 16:49
200 0
Sergey Pavlov
Sergey Pavlov

소개

지표 배출은 시계열 연구에서 새롭고 매우 유망한 방향을 나타냅니다. 분석이 지표 자체에 초점을 맞추는 것이 아니라 실제로 시장 환경을 예측할 수 있는 미래 또는 과거로의 배출량에 초점을 맞춘다는 사실이 특징입니다.

  • 미래의 지지 및 저항 수준;
  • 추세 방향(가격 움직임);
  • 과거에 축적된 움직임의 힘.

"MQL5의 도면 지표의 배출"이라는 이전 글에서 배출 도면 알고리즘을 다루고 주요 기능을 지정했습니다. 다시 한 번 알려드리죠:

배출은 고려 중인 지표에 고유한 선의 교차점에 위치한 일련의 점입니다.

배출 지점에는 다음과 같은 몇 가지 특성이 있습니다.

  • 동일한 유형의 배출 지점은 클러스터 되는 경향이 있습니다.
  • 밀집된 점 클러스터는 가격을 끌어당기거나 반대로 가격을 물러나도록 할 수 있습니다.

배출 갤러리:

DCMV의 배출 iMA 및 iEnvelopes의 배출
DCMV의 배출 iMA 및 iEnvelopes의 배출

그림 1. 지표 배출 도표의 예. 왼쪽: DCMV 지표의 배출. 오른쪽: iMAiEnvelopes 지표의 배출

배출의 적분 특성 계산을 설명하기 위해 다음과 같이 입력 매개변수를 사용하여 이동 평균 엔벨로프(Envelopes)와 이동 평균(Moving Average) 자체를 취합니다.

//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};

따라서 선택한 지표에 고유한 선의 교차점을 찾습니다. 라인 수와 특성(평균 기간 및 편차)은 무작위로 선택됩니다. 실제로 배출은 이러한 지표에 대한 매개변수 세트를 사용하여 표시할 수 있습니다(공간에서 교차하는 한).

지표를 선택했으므로 이제 배출 분석을 위한 기본 프로그램 역할을 할 Expert Advisor를 생성해 보겠습니다. iMAiEnvelopes 기술 지표에서 계산된 데이터를 가져와야 합니다. 저는 Expert Advisor의 기술 지표 사용 가이드에 설명된 방법을 사용할 것을 제안합니다.

교차점을 찾아야 하는 선을 표시하려면 각 선에 대해 두 개의 점만 설정하면 됩니다. 따라서 두 개의 바(예: 현재 및 이전)에 대한 지표 값만 얻는 것으로 충분합니다. 이전 바의 가격은 정적이지만 현재 바의 가격은 동적이므로 새 틱마다 새로운 포인트가 계속 생성됩니다. 코드는 다음과 같습니다.

//+------------------------------------------------------------------+
//|                                      emission_of_MA_envelope.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
//--- external variable for storing averaging period of the iEnvelopes indicator
input int   ma_period=140;      // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double      ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing the iMA indicator periods
int         MA[]={4,7,11,19,31,51,85};
//--- array for storing pointers to the iMA and iEnvelopes indicators
int         handle_MA[];
int         handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,300);
PointEmission  pEmission;
//--- drawing styles for points of emission
#define     COLOR_UPPER  C'51,255,255'
#define     COLOR_LOWER  C'0,51,255'
#define     COLOR_MA     C'255,51,255'
color       colorPoint[]={COLOR_UPPER,COLOR_LOWER,COLOR_MA};
CodeColor   styleUpper={158,COLOR_UPPER,SMALL};
CodeColor   styleLower={158,COLOR_LOWER,SMALL};
CodeColor   styleMA={158,COLOR_MA,SMALL};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(UPPER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleUpper);
           }
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, draw it in the chart
           {
            name="iEnvelopes(LOWER_LINE)"+(string)j+"=iMA"+(string)i+(string)GTC;
            EnvMa.CreatePoint(name,pEmission,styleLower);
           }
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, draw it in the chart
              {
               name="iMA"+(string)j+"=iMA"+(string)i+(string)GTC;
               EnvMa.CreatePoint(name,pEmission,styleMA);
              }
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar) // delete once per bar
     {
      int  total=ObjectsTotal(0,0,-1);
      prevTimeBar=T[0];
      for(int obj=total-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TEXT);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0])
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008       Objects = ",total);
     }
//---
  }

이 Expert Advisor의 모든 디테일에 대해서는 언급하지 않겠습니다. 여기서 주목해야 할 주요 사항은 배출을 플롯하기 위해 두 선의 교차점 계산 및 표시를 담당하는 CEmission 클래스 인스턴스를 사용한다는 것입니다.

//+------------------------------------------------------------------+
//|                                                     Emission.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
#define  BIG   7    // point size
#define  SMALL 3    // point size
//+------------------------------------------------------------------+
//| pMABB structure                                                  |
//+------------------------------------------------------------------+
struct PointEmission
  {
   double            x;       // X-coordinate of the time point
   double            y;       // Y-coordinate of the price point
   datetime          t;       // t-coordinate of the point's time
   bool              real;    // whether the point exists
  };
//+------------------------------------------------------------------+
//| CodeColor structure                                              |
//+------------------------------------------------------------------+
struct CodeColor
  {
   long              Code;    // point symbol code 
   color             Color;   // point color
   int               Width;   // point size
  };
//+------------------------------------------------------------------+
//| Base class for emissions                                         |
//+------------------------------------------------------------------+
class CEmission
  {
private:
   int               sec;
   int               lim_Left;   // limiting range of visibility in bars
   int               lim_Right;  // limiting range of visibility in bars

public:
   PointEmission     CalcPoint(double   y1,  // Y-coordinate of straight line 1 on bar [1]
                               double   y0,  // Y-coordinate of straight line 1 on bar [0]
                               double   yy1, // Y-coordinate of straight line 2 on bar [1] 
                               double   yy0, // Y-coordinate of straight line 2 on bar [0]
                               datetime t0   // t-coordinate of the current bar Time[0]
                               );
   bool              CreatePoint(string name,            // point name
                                 PointEmission &point,   // coordinates of the point
                                 CodeColor &style);      // point drawing style
                                 CEmission(int limitLeft,int limitRight);
                    ~CEmission();
  };
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::CEmission(int limitLeft,int limitRight)
  {
   sec=PeriodSeconds();
   lim_Left=limitLeft;
   lim_Right=limitRight;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CEmission::~CEmission()
  {
  }
//+------------------------------------------------------------------+
//| The CalcPoint method of the CEmission class                      |
//+------------------------------------------------------------------+
PointEmission CEmission::CalcPoint(double   y1, // Y-coordinate of straight line 1 on bar [1]
                                   double   y0, // Y-coordinate of straight line 1 on bar [0]
                                   double   yy1,// Y-coordinate of straight line 2 on bar [1]
                                   double   yy0,// Y-coordinate of straight line 2 on bar [0]
                                   datetime t0  // t-coordinate of the current bar Time[0]
                                   )
  {
   PointEmission point={NULL,NULL,NULL,false};
   double y0y1=y0-y1;
   double y1yy1=y1-yy1;
   double yy0yy1=yy0-yy1;
   double del0=yy0yy1-y0y1;
   if(MathAbs(del0)>0)
     {
      point.x=y1yy1/del0;
      if(point.x<lim_Left || point.x>lim_Right) return(point);
      point.y=y1+y0y1*y1yy1/del0;
      if(point.y<0) return(point);
      point.t=t0+(int)(point.x*sec);
      point.real=true;
      return(point);
     }
   return(point);
  }
//+------------------------------------------------------------------+
//| The CreatePoint method of the CEmission class                    |
//+------------------------------------------------------------------+
bool CEmission::CreatePoint(string name,            // point name
                            PointEmission &point,  // coordinates of the point
                            CodeColor &style)      // point drawing style
  {
   if(ObjectCreate(0,name,OBJ_TEXT,0,0,0))
     {
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,style.Width);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString((uchar)style.Code));
      ObjectSetDouble(0,name,OBJPROP_PRICE,point.y);
      ObjectSetInteger(0,name,OBJPROP_TIME,point.t);
      ObjectSetInteger(0,name,OBJPROP_COLOR,style.Color);
      return(true);
     }
   return(false);
  }

배출 지점은 텍스트와 같은 그래픽 개체로 표시됩니다. 우선 개체 앵커가 기호 중심에 정렬되어야 한다는 사실에서 비롯됩니다. 둘째, 넓은 범위에서 개체 크기를 변경할 수 있습니다. 이러한 점 속성은 복잡한 배출을 얻을 수 있는 큰 잠재력을 제공합니다.

그림 2. iMA 및 iEnvelopes 지표의 원래 배출

그림 2. iMA 및 iEnvelopes 지표의 원래 배출

 

배출의 적분 특성

따라서 제안된 Expert Advisor를 차트에 배치한 후 다양한 색상으로 많은 포인트를 얻었습니다(그림 2 참조).

  • 아쿠아 - iMA와 iEnvelopes의 교차점, UPPER_LINE 버퍼.
  • 파란색 - iMA와 iEnvelopes의 교차점, LOWER_LINE 버퍼.
  • 마젠타색 - iMA와 iMA의 교차점입니다.

이 혼돈은 자동 거래에서 사용할 수 없습니다. 신호, 수준 및 기타 양적 시장 특성이 필요하지만 여기서는 명상과 chiromancy에 대한 시각적 이미지만 얻을 수 있으며 숫자는 없습니다.

배출의 적분 특성은 지표 배출의 결과로 얻은 데이터를 일반화하는 역할을 합니다. 

배출의 통합 특성에 대한 필요성은 또한 통합 채널, 라인, 레벨, 신호 등의 새로운 유형의 지표를 사용하여 시장 조사 기회를 제공한다는 사실에 의해 주도됩니다. 가장 일반적인 배출 값을 결정하기 위해 작게 시작하여 모든 포인트 유형에 대한 평균 가격을 계산하여 아래와 같이 수평선을 추가로 그립니다.

그림 3. 모든 포인트 유형에 대한 평균 가격의 수평선

그림 3. 모든 포인트 유형에 대한 평균 가격의 수평선

이를 위해 기존 코드에 몇 가지 추가 코드 블록을 추가합니다. 데이터 섹션으로:

//--- arrays for calculation and display of integral characteristics of emissions
#define     NUMBER_TYPES_POINT   3
double      sum[NUMBER_TYPES_POINT],sumprev[NUMBER_TYPES_POINT];
datetime    sum_time[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};

OnTick() 모듈:

//--- calculation of integral characteristics of emissions
   ArrayInitialize(n,0);
   ArrayInitialize(sum,0.0);
   ArrayInitialize(sum_time,0.0);
   for(int obj=total-1;obj>=0;obj--)
     {
      string   obj_name=ObjectName(0,obj,0,OBJ_TEXT);
      datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
      if(obj_time>T[0])
        {
         color    obj_color=(color)ObjectGetInteger(0,obj_name,OBJPROP_COLOR);
         double   obj_price=ObjectGetDouble(0,obj_name,OBJPROP_PRICE);
         for(int i=ArraySize(n)-1; i>=0; i--)
            if(obj_color==colorPoint[i])
              {
               n[i]++;
               sum[i]+=obj_price;
               sum_time[i]+=obj_time;
              }
        }
     }
//--- displaying integral characteristics of emissions
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
        }
     }

계속 진행합니다. 이제 모든 포인트 세트에 대한 평균 시간 값을 계산하고 평균 가격의 해당 라인에 표시해 보겠습니다(그림 4 참조). 따라서 우리는 결코 정적이지 않고 항상 공간에서 움직이는 배출의 양적 특성을 처음으로 얻었습니다.

차트에는 일시적인 위치만 표시됩니다. 우리는 그것들을 나중에 연구할 수 있도록 어떻게든 내역을 고정시켜야 합니다. 지금까지 이것이 어떻게 수행될 수 있는지 아직 불분명하며 신중하게 고려해야 합니다... 그 동안 우리는 더 개선하고 차트의 마커 옆에 계산에 관련된 포인트 수를 표시합니다. 이는 추가 분석에도 유용할 획득된 특성의 가중치입니다.

그림 4. 평균 가격과 평균 시간의 교차점에 있는 마커

그림 4. 평균 가격과 평균 시간의 교차점에 있는 마커

그러나 분석의 편의를 위해 백분율 비율을 사용합니다. 주요 배출 지점은 iMA 및 iEnvelopes 지표의 교차로 인한 것이므로 합계를 100%로 간주합니다. 우리가 지금 무엇을 가지고 있는지 보자:

그림 5. 모든 유형의 배출 지점에 대한 백분율 비율

그림 5. 모든 유형의 배출 지점에 대한 백분율 비율

세 값을 더하면 합계가 100% 이상입니다. 마젠타 색으로 표시된 값 34.4는 특정 시점에서 iMA와 iMA의 교차점 속성입니다. 즉, 지표가 자체 교차하지만 입력 데이터가 다릅니다. 이 경우 기준값이며 추후 시장분석에 어떻게 활용될 수 있을지 생각해 볼 수 있습니다.

그러나 포인트 수의 백분율 비율을 얻을 때 또 다른 문제가 발생합니다. 특히 변하기 때문에 특히 배출 특성의 백분율 값을 기록에서 어떻게 고칠 수 있습니까?

 

그래픽 분석

우리는 이제 배출량의 통합적인 특성을 가지고 있지만 얻은 데이터를 기반으로 한 거래 전략의 분석 및 개발에 여전히 가깝지 않습니다. 그러나 주의 깊은 독자는 이미 이 문제에 대한 해결책을 찾았을 것입니다(그림 1 참조). 해결책은 다음과 같습니다. 저는 주요 배출 지점의 백분율 비율에 비례하는 다른 두께를 사용하여 적분 곡선을 그릴 것을 제안합니다.

곡선의 현재 부분은 현재 바와 이전 바 사이의 평균 가격선을 따라 표시되며 이러한 좌표는 실제로 미래에서 가져온 것임을 명심하세요. 지표 배출의 일종의 선도적인 통합 채널입니다. 나는 그것이 실제로 매우 혼란스럽게 들린다는 것을 알고 있습니다 ... 그리고 계속 읽어야 하는지 생각해야 합니다. 하지만 진행하면서 이것이 점점 더 흥미로워지기를 바랍니다.

그림 6. 지표 배출의 통합 채널

그림 6. 지표 배출의 통합 채널

그래서 우리는 "iMA & iMA" 배출(차트에서 마젠타색으로 표시)에 대한 일부 용도를 찾은 것 같습니다. 그리고 우리는 통합 이동 평균이라는 새로운 지표를 얻었습니다.

이제 Expert Advisor의 코드로 돌아가서 OnTick() 모듈에서 어떤 변경 사항이 발생했는지 확인합니다.

//--- displaying integral characteristics of emissions
   ArrayInitialize(W,10);
   W[ArrayMaximum(n)]=20;
   W[ArrayMinimum(n)]=3;
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      if(n[i]>0)
        {
         //--- horizontal lines of mean prices
         name="H.line."+(string)i;
         ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         //--- markers
         name="P."+(string)i;
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,17);
         ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,sum[i]/n[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,sum_time[i]/n[i]);
         //--- integral curves
         name="T"+(string)i+".line"+(string)T[1];
         ObjectCreate(0,name,OBJ_TREND,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
         if(sumprev[i]>0)
           {
            ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
            ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
            ObjectSetDouble(0,name,OBJPROP_PRICE,1,(sum[i]/n[i]));
            ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
           }
         //--- numerical values of integral characteristics
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,30);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)n[i]/(double)(n[0]+n[1])*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,(sum[i]/n[i]));
         ObjectSetInteger(0,name,OBJPROP_TIME,0,sum_time[i]/n[i]);
        }
     }

그래픽 분석을 계속하겠습니다. 하지만 뭔가 부족합니다... 또 다른 중요한 배출 특성을 놓친 것 같습니다. 적분 곡선은 평균 가격을 기반으로만 그려졌습니다. 그러나 평균 시간 좌표를 고려해야 합니다. 아래 그림을 보고 채널 제한에 특히 주의하세요.

  • 아쿠아 라인은 채널의 상한선입니다.
  • 파란색 선은 채널의 하한선입니다.

시간상 제로 바에 더 가까운 마커를 식별해야 합니다.

채널의 선행 상한선
채널의 선행 하한선

그림 7. 시간을 선도하는 완전한 특성. 왼쪽: 채널의 선행 상한선입니다. 오른쪽: 채널의 선행 하한선입니다.

이 문제는 다음과 같이 해결할 수 있습니다. 가격선(PRICE_MEDIAN)을 가격 차트에 추가하고 선의 색상에 따라 선의 색상을 변경합니다. 마지막 바에 더 가까운 마커(청록색 또는 파란색)입니다(그림 7 참조). 또한 기존 코드에 다음 코드 블록을 삽입합니다.

//---
   if(n[ArrayMinimum(n)]>0)
     {
      datetime d[2];
      for(int j=0;j<2;j++)
        {
         d[j]=sum_time[j]/n[j];
        }
      int i=ArrayMinimum(d);

      name="Price.line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,8);
      ObjectSetDouble(0,name,OBJPROP_PRICE,0,HL(H[1],L[1]));
      ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,1,HL(H[0],L[0]));
      ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine1[i]);
     }
//---

이제 다음 단계를 준비하세요. 2차 배출과 같은 원래 배출의 적분 특성을 기반으로 배출을 플롯하려고 하면 어떻게 될까요? 결국, 그 선들은 또한 서로 교차하므로 결과적으로 배출점이 있어야 합니다. 어떤 결과가 나올 수 있는지 알아보겠습니다. 다음 코드 줄을 추가하여 이전 코드 블록을 향상시킵니다.

      //--- emissions of integral characteristics of the original emissions
      pEmission=EnvMa.CalcPoint(sumprev[0],sum[0]/n[0],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/up"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleUpper2);
        }
      pEmission=EnvMa.CalcPoint(sumprev[1],sum[1]/n[1],sumprev[2],sum[2]/n[2],T[0]);
      if(pEmission.real) // if the intersection point is found, draw it in the chart
        {
         name="test/dn"+(string)GTC;
         EnvMa.CreatePoint(name,pEmission,styleLower2);
        }

그리고 데이터 섹션에 다음 줄을 삽입합니다.

#define     COLOR_2_UPPER  C'102,255,255'
#define     COLOR_2_LOWER  C'51,102,255'
CodeColor   styleUpper2={178,COLOR_2_UPPER,BIG};
CodeColor   styleLower2={178,COLOR_2_LOWER,BIG};

아래 그림에서 결과를 확인할 수 있습니다. 우리는 지금까지 아무것도 제안하지 않는 새로운 점을 볼 수 있습니다.

그림 8. 적분 라인의 배출

그림 8. 적분 라인의 배출

적분 특성은 차트에 표시된 배출량을 사용하여 새 포인트(그림 9 참조)에 대해서도 분명히 계산할 수 있습니다!

배출 배출
배출 배출

그림 9. 배출의 적분 특성

그래서 우리는 우리가 필요로 하는 모든 것을 플로팅하고 배출의 적분 특성을 얻었습니다. 이제 거래 전략의 분석 및 개발을 진행할 수 있습니다. 하지만 여전히 불가능해 보입니다! 지금 우리를 막고 있는 것은 무엇입니까?

 

시계열 배출

그래픽 분석을 통해 배출의 통합적 특성을 연구할 수 있지만 너무 자원 집약적입니다. 전략 테스터의 비주얼 모드에서 제안된 코드를 실행하려고 하면 테스트 속도가 곧 0으로 떨어질 것입니다! 이는 차트에 그래픽 개체가 많기 때문입니다.

따라서 자연스럽게 많은 점을 제거하고 적분 곡선만 남기고 싶을 것입니다. 이 문제를 해결하기 위해 특수 배열(버퍼)을 사용합니다.

배출량의 시계열은 배출량에 대한 정보가 축적되는 특별히 배열된 배열입니다.

시간이 핵심 필드임에도 불구하고 포함된 데이터가 시간순으로 정렬되지 않는다는 점에서 표준 시계열과 다릅니다.

시계열 배출

그림 10. 배출 특성의 시계열

이러한 배열은 새 요소가 빈 셀이나 이전 값으로 채워진 셀에 저장되는 방식으로 배열됩니다. 이를 위해 CTimeEmission 클래스를 사용합니다. 코드에서 구현하는 방법은 다음과 같습니다.

//+------------------------------------------------------------------+
//|                                                 TimeEmission.mqh |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <Emission.mqh>
#define ARRMAX       64
#define ARRDELTA     8
//+------------------------------------------------------------------+
//| pIntegral structure                                              |
//+------------------------------------------------------------------+
struct pIntegral
  {
   double            y;       // Y-coordinate of the price point (mean price of the points with the same time)
   datetime          t;       // t-coordinate of the point's time
   int               n;       // n-number of points with the same time
  };
//+------------------------------------------------------------------+
//| Base class for time series of emissions                          |
//+------------------------------------------------------------------+
class CTimeEmission
  {
private:
   pIntegral         time_series_Emission[]; // time series of emission
   int               size_ts; // number of elements in time series 
   datetime           t[1];
public:
   //--- method of writing new elements to time series of emission
   void              Write(PointEmission &point);
   //--- method of reading integral characteristics of emissions
   pIntegral         Read();
                     CTimeEmission();
                    ~CTimeEmission();
  };

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::CTimeEmission()
  {
   ArrayResize(time_series_Emission,ARRMAX,ARRMAX);
   size_ts=ArraySize(time_series_Emission);
   for(int i=size_ts-1; i>=0; i--)
      time_series_Emission[i].t=0;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
CTimeEmission::~CTimeEmission()
  {
  }
//+------------------------------------------------------------------+
//| The Write method of the CTimeEmission class                      |
//+------------------------------------------------------------------+
void CTimeEmission::Write(PointEmission &point)
  {
   CopyTime(NULL,0,0,1,t);
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t<t[0]) // find the first empty cell
        {
         if(k>size_ts-ARRDELTA)
           {   // increase the array size, if necessary
            int narr=ArrayResize(time_series_Emission,size_ts+ARRMAX,ARRMAX);
            for(int l=size_ts-1;l<narr;l++)
               time_series_Emission[l].t=0;
           }
         time_series_Emission[k].y=point.y;
         time_series_Emission[k].t=point.t;
         time_series_Emission[k].n=1;
         return;
        }
      if(time_series_Emission[k].t==point.t) // find the first similar cell
        {
         time_series_Emission[k].y=(time_series_Emission[k].y*time_series_Emission[k].n+point.y)/(time_series_Emission[k].n+1);
         time_series_Emission[k].n++;
         return;
        }
     }
  }
//+------------------------------------------------------------------+
//| The Read method of the CTimeEmission class                       |
//+------------------------------------------------------------------+
pIntegral CTimeEmission::Read()
  {
   CopyTime(NULL,0,0,1,t);
   pIntegral property_Emission={0.0,0,0};
   size_ts=ArraySize(time_series_Emission);
   for(int k=0;k<size_ts;k++)
     {
      if(time_series_Emission[k].t>=t[0])
        {
         property_Emission.y+=time_series_Emission[k].y*time_series_Emission[k].n;
         property_Emission.t+=(time_series_Emission[k].t-t[0])*time_series_Emission[k].n;
         property_Emission.n+=time_series_Emission[k].n;
        }
     }
   if(property_Emission.n>0)
     {
      property_Emission.y=property_Emission.y/property_Emission.n;
      property_Emission.t=property_Emission.t/property_Emission.n+t[0];
     }
   return(property_Emission);
  }

여기에서 두 가지 클래스 방법의 구현을 볼 수 있습니다. 배출 지점을 시계열에 쓰는 것과 배출의 적분 특성 값을 읽는 것입니다.

 

적분 특성의 간결한 계산

이제 배출량의 시계열이 있으므로 거래 전략을 추가로 개발하기 위해 적분 특성 계산을 위한 간결한 알고리즘을 만들 수 있습니다. 원래 Expert Advisor를 업데이트하겠습니다.

//+------------------------------------------------------------------+
//|                                   emission_of_MA_envelope_ts.mq5 |
//|                                           Copyright 2013, DC2008 |
//|                           https://www.mql5.com/ru/users/DC2008 |
//+------------------------------------------------------------------+
#property copyright "Copyright 2013, DC2008"
#property link      "https://www.mql5.com/ru/users/DC2008"
#property version   "1.00"
//---
#include <GetIndicatorBuffers.mqh>
#include <Emission.mqh>
#include <TimeEmission.mqh>
//--- number of point types
#define     NUMBER_TYPES_POINT   3
//--- array for storing the iMA indicator periods
int      MA[]={4,7,11,19,31,51,85};
//--- external variable for storing averaging period of the iEnvelopes indicator
input int ma_period=140; // averaging period of the iEnvelopes indicator
//--- array for storing deviations of the iEnvelopes indicator
double   ENV[]={0.01,0.0165,0.0273,0.0452,0.0747,01234,0.204,0.3373,0.5576,0.9217,1.5237};
//--- array for storing pointers to the iMA indicator
int      handle_MA[];
//--- array for storing pointers to the iEnvelopes indicator
int      handle_Envelopes[];
//--- market data
datetime    T[],prevTimeBar=0;
double      H[],L[];
#define     HL(a, b) (a+b)/2
//--- class instances
CEmission      EnvMa(0,200);
PointEmission  pEmission;
CTimeEmission  tsMA[NUMBER_TYPES_POINT];
pIntegral      integral[NUMBER_TYPES_POINT];
//--- drawing styles for points of emission
#define     DEL            500
//--- arrays for calculation and display of integral characteristics of emissions
double      sumprev[NUMBER_TYPES_POINT];
int         n[NUMBER_TYPES_POINT],W[NUMBER_TYPES_POINT];
color       colorLine[]={clrAqua,clrBlue,clrMagenta};
int         fontPoint[]={30,30,30};
int         fontMarker[]={16,16,16};
//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
int OnInit()
  {
   ArraySetAsSeries(T,true);
   ArraySetAsSeries(H,true);
   ArraySetAsSeries(L,true);
   ArrayInitialize(sumprev,0.0);
//---
   int size=ArraySize(MA);
   ArrayResize(handle_MA,size);
//--- create a pointer to the object - the iMA indicator
   for(int i=0; i<size; i++)
     {
      handle_MA[i]=iMA(NULL,0,MA[i],0,MODE_SMA,PRICE_MEDIAN);
      //--- if an error occurs when creating the object, print the message
      if(handle_MA[i]<0)
        {
         Print("The iMA object[",MA[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//+------------------------------------------------------------------+
   size=ArraySize(ENV);
   ArrayResize(handle_Envelopes,size);
//--- create a pointer to the object - the iEnvelopes indicator
   for(int i=0; i<size; i++)
     {
      handle_Envelopes[i]=iEnvelopes(NULL,0,ma_period,0,MODE_SMA,PRICE_MEDIAN,ENV[i]);
      //--- if an error occurs when creating the object, print the message
      if(handle_Envelopes[i]<0)
        {
         Print("The iEnvelopes object[",ENV[i],"] has not been created: Error = ",GetLastError());
         //--- forced program termination
         return(-1);
        }
     }
//---
   return(0);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//---

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//--- market data
   CopyTime(NULL,0,0,2,T);
   CopyHigh(NULL,0,0,2,H);
   CopyLow(NULL,0,0,2,L);
//--- fill the declared arrays with current values from all indicator buffers
   string name;
   uint GTC=GetTickCount();
//---- indicator buffers
   double   ibMA[],ibMA1[];      // arrays for the iMA indicator
   double   ibEnvelopesUpper[];  // array for the iEnvelopes indicator (UPPER_LINE)
   double   ibEnvelopesLower[];  // array for the iEnvelopes indicator (LOWER_LINE)
   for(int i=ArraySize(handle_MA)-1; i>=0; i--)
     {
      if(!CopyBufferAsSeries(handle_MA[i],0,0,2,true,ibMA))
         return;
      //---
      for(int j=ArraySize(handle_Envelopes)-1; j>=0; j--)
        {
         if(!GetEnvelopesBuffers(handle_Envelopes[j],0,2,ibEnvelopesUpper,ibEnvelopesLower,true))
            return;
         //--- find the intersection point of the iEnvelopes(UPPER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesUpper[1],ibEnvelopesUpper[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[0].Write(pEmission);
         //--- find the intersection point of the iEnvelopes(LOWER_LINE) and iMA indicators
         pEmission=EnvMa.CalcPoint(ibEnvelopesLower[1],ibEnvelopesLower[0],ibMA[1],ibMA[0],T[0]);
         if(pEmission.real) // if the intersection point is found, add it to the time series of emission
            tsMA[1].Write(pEmission);
        }
      //---
      for(int j=ArraySize(handle_MA)-1; j>=0; j--)
        {
         if(i!=j)
           {
            if(!CopyBufferAsSeries(handle_MA[j],0,0,2,true,ibMA1))
               return;
            //--- find the intersection point of the iMA and iMA indicators
            pEmission=EnvMa.CalcPoint(ibMA1[1],ibMA1[0],ibMA[1],ibMA[0],T[0]);
            if(pEmission.real) // if the intersection point is found, add it to the time series of emission
               tsMA[2].Write(pEmission);
           }
        }
     }
//--- deletion of the graphical objects of emission not to stuff the chart
   if(T[0]>prevTimeBar)
     {
      prevTimeBar=T[0];
      //---
      for(int i=ArraySize(n)-1; i>=0; i--)
         sumprev[i]=integral[i].y;
      //---
      for(int obj=ObjectsTotal(0,0,-1)-1;obj>=0;obj--)
        {
         string obj_name=ObjectName(0,obj,0,OBJ_TREND);
         datetime obj_time=(datetime)ObjectGetInteger(0,obj_name,OBJPROP_TIME);
         if(obj_time<T[0]-DEL*PeriodSeconds())
            ObjectDelete(0,obj_name);
        }
      Comment("Emission © DC2008   Graphical objects = ",ObjectsTotal(0,0,-1));
     }
//--- calculation of integral characteristics of emission
   for(int i=ArraySize(n)-1; i>=0; i--)
      integral[i]=tsMA[i].Read();
//--- displaying integral characteristics of emission
   ArrayInitialize(W,5);
   if(integral[0].n>integral[1].n)
     {
      W[0]=20;
      W[1]=10;
     }
   else
     {
      W[0]=10;
      W[1]=20;
     }
   for(int i=ArraySize(n)-1; i>=0; i--)
     {
      //--- horizontal lines of mean prices
      name="H.line."+(string)i;
      ObjectCreate(0,name,OBJ_HLINE,0,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_DASHDOT);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      //--- markers
      name="P."+(string)i;
      ObjectCreate(0,name,OBJ_TEXT,0,0,0);
      ObjectSetString(0,name,OBJPROP_FONT,"Wingdings");
      ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_CENTER);
      ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontMarker[i]);
      ObjectSetString(0,name,OBJPROP_TEXT,CharToString(163));
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetDouble(0,name,OBJPROP_PRICE,integral[i].y);
      ObjectSetInteger(0,name,OBJPROP_TIME,integral[i].t);
      //--- integral curves
      name="T"+(string)i+".line"+(string)T[1];
      ObjectCreate(0,name,OBJ_TREND,0,0,0);
      ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
      ObjectSetInteger(0,name,OBJPROP_WIDTH,W[i]);
      if(sumprev[i]>0)
        {
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,sumprev[i]);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,T[1]);
         ObjectSetDouble(0,name,OBJPROP_PRICE,1,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,1,T[0]);
        }
      //--- numerical values of integral characteristics
      if(integral[0].n+integral[1].n>0)
        {
         name="Text"+(string)i+".control";
         ObjectCreate(0,name,OBJ_TEXT,0,0,0);
         ObjectSetInteger(0,name,OBJPROP_ANCHOR,ANCHOR_LEFT_LOWER);
         ObjectSetInteger(0,name,OBJPROP_FONTSIZE,fontPoint[i]);
         ObjectSetInteger(0,name,OBJPROP_COLOR,colorLine[i]);
         string str=DoubleToString((double)integral[i].n/(double)(integral[0].n+integral[1].n)*100,1);
         ObjectSetString(0,name,OBJPROP_TEXT,str);
         ObjectSetDouble(0,name,OBJPROP_PRICE,0,integral[i].y);
         ObjectSetInteger(0,name,OBJPROP_TIME,0,integral[i].t);
        }
     }
  }

코드는 짧아지고계산 속도는 빨라졌습니다. 이제 시각화 없이 거래 로봇을 테스트하고 최적화할 수 있습니다!

 

거래에서 적분 특성의 사용

적분 특성은 다음에 대한 신호 발생기로 사용할 수 있습니다.

  • 채널 혁신,
  • 서로 교차하거나 가격,
  • 방향으로 변경합니다.
예를 들어, 아래 그림은 배출량의 적분 특성이 가격과의 교차점에서 가설적으로 어떻게 사용될 수 있는지를 보여줍니다. 파란색 곡선이 가격을 상향 교차할 때 매도 신호가 생성되고, 아쿠아 곡선과 가격이 하향 교차할 때 매수 신호가 생성됩니다.

그림 11. 지표 배출의 통합 특성 계산은 시장 분석(시계열)을 위한 새로운 도구와 방법을 제공합니다.

Fig.  11. 지표 배출의 통합 특성 계산은 시장 분석(시계열)을 위한 새로운 도구와 방법을 제공합니다.

 

결론

  1. 지표 배출의 통합 특성 계산은 시장 분석(시계열)을 위한 새로운 도구와 방법을 제공합니다.
  2. 시계열을 사용하여 적분 특성 계산 속도를 높이는 데 성공했습니다.
  3. 그리고 그것은 우리가 배출량을 사용하는 자동 거래 전략을 개발할 수 있는 가능성을 열어주었습니다.

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

MetaTrader 4 및 MetaTrader 5의 신호 거래에 대한 일반 정보 MetaTrader 4 및 MetaTrader 5의 신호 거래에 대한 일반 정보
MetaTrader 4 / MetaTrader 5 거래 신호는 거래자가 신호 제공자의 거래 작업을 복사할 수 있도록 하는 서비스입니다. 우리의 목표는 가입자를 보호하고 불필요한 비용을 덜어주는 새로운 대량 사용 서비스를 개발하는 것이었습니다.
MQL5 프로그래밍 기본: 시간 MQL5 프로그래밍 기본: 시간
이 글은 시간 작업을 위한 표준 MQL5 기능과 Expert Advisors 및 지표를 생성할 때 필요한 시간 작업을 위한 프로그래밍 기술 및 실질적으로 유용한 기능에 중점을 둡니다. 시간 측정의 일반 이론에 특히 주의를 기울입니다. 이 글은 주로 초보 MQL5 프로그래머가 관심을 가져야 합니다.
MetaTrader 4 및 MetaTrader 5 거래 신호 위젯 MetaTrader 4 및 MetaTrader 5 거래 신호 위젯
최근 MetaTrader 4 및 MetaTrader 5 사용자는 신호 제공자가 되어 추가 수익을 얻을 수 있는 기회를 얻었습니다. 이제 새 위젯을 사용하여 웹 사이트, 블로그 또는 소셜 네트워크 페이지에 거래 성공을 표시할 수 있습니다. 위젯 사용의 이점은 분명합니다. 신호 제공자의 인기를 높이고 성공적인 거래자로서의 명성을 확립하며 새로운 가입자를 유치합니다. 다른 웹 사이트에 위젯을 배치하는 모든 거래자는 이러한 이점을 누릴 수 있습니다.
MetaTrader 4 및 MetaTrader 5의 신호 제공자가 되는 방법 MetaTrader 4 및 MetaTrader 5의 신호 제공자가 되는 방법
거래 시그널을 제공하고 수익을 내고 싶으시나요? MQL5.com 웹사이트에 판매자로 등록하고 거래 계정을 지정하고 트레이더들이 여러분의 거래를 복사할 수 있는 구독을 제공하세요.