English Русский 中文 Español Deutsch 日本語 Português Français Italiano Türkçe
최후의 성전

최후의 성전

MetaTrader 5 | 5 8월 2021, 10:38
79 0
Roman Zamozhnyy
Roman Zamozhnyy

개요

MetaTrader 5 (MetaTrader4)에는 상품 가격을 나타내는 세 가지 방법이 기본으로 제공됩니다. 바, 캔들 그리고 선이죠. 세 가지 모두 시간 차트를 나타냅니다. 시간을 기준으로 하는 전통적인 가격 차트 외에 시간이 나타나지 않는 가격 차트 중에서도 꽤 인기를 끄는 차트들이 있습니다. 바로 Renko 차트와 Kagi 차트, 삼선전환도, 그리고 P&F 차트이죠.

고전적인 방법보다 더 나은 방법을 제시한다는 것은 아닙니다. 다만 시간 변수를 제외시키면 가격 변수에 집중하는 데에 보다 도움이 될 수 있죠. P&F 차트와 차트 알고리즘을 살펴보도록 할게요. 잘 알려진 시장 상품을 활용해 차트를 생성하고 알고리즘을 구현하는 깔끔하고 간단한 스크립트도 작성해 보겠습니다. 본문의 내용은 토마스 J 도시(Thomas J. Dorsey)의 저서 'Point and Figure Charting: The Essential Application for Forecasting and Tracking Market Prices'의 내용을 기준으로 합니다.

불스아이 브로커(Bull's-Eye Broker)는 가장 많이 이용되는 오프라인 차트 드로잉 소프트웨어 패키지입니다. 21일 동안 체험판을 이용할 수 있고 반복해서 체험할 수 있습니다. 베타 기간 동안에는 새로운 베타 버전이 제공됩니다. 해당 소프트웨어 패키지를 이용해 스크립트 실행 결과를 평가하도록 하겠습니다. P&F 차트에 가장 유용한 온라인 리소스 중 하나는 StockCharts입니다. 아쉽게도 주식시장 관련 웹사이트라서 외환시장 상품 가격은 제공하고 있지 않죠.

본문에서 소개할 스크립트 실행 결과를 비교하기 위해 불스아이 브로커와 스톡차트닷컴을 이용해 금 선물, 경질 원유 선물 및 S&P 500 CFD 차트를 생성하겠습니다. 추가적으로 불스아이 브로커만을 이용한 EURUSD 가격 차트 또한 생성합니다.


P&F 차트 알고리즘

알고리즘을 살펴보겠습니다.

P&F 차트에는 두 개의 주요 매개 변수가 있는데요.

  1. 우선 최소 가격 변동 값을 나타내는 '한칸값'이 있습니다. 해당 값보다 적은 가격 변동은 차트에 반영되지 않습니다.
  2. 그리고 '전환칸수'가 있죠. 현재의 추세의 반전을 나타내며 해당 반전폭 발생 시 새로운 열에 표시됩니다.

차트 작성에는 개장가-고가-저가-종가 형태로 저장된 시세 기록이 필요하죠.

  1. 고가와 저가를 기반으로 차트를 그리도록 하겠습니다.
  2. 고가는 한칸값에 맞추어 반내림하고(MathFloor), 저가는 한칸값에 맞추어 반올림합니다(MathCeil).

예를 들어 볼게요. 박스값이 $1(하나)이고 전환칸수가 3(셋)인 경질 원유 차트를 그리려고 합니다. 고가와 저가는 $1 단위로 반내림되거나 반올림되어야 겠죠.

일자 고가 저가 XO 고가 XO 저가
2012.02.13 100.86 99.08 100 100
2012.02.14 101.83 100.28 101 101
2012.02.15 102.53 100.62 102 101
2012.02.16 102.68 100.84 102 101
2012.02.17 103.95 102.24 103 102


X는 가격 상승을, O는 가격 하락을 나타냅니다.

초기 가격 방향 결정 방법(첫 번째 열의 XO 값 구하기)

XO 고가와 XO 저가[Bars-1] 값을 잘 기억하고 다음 이벤트가 발생할 떄까지 기다리세요.

  • 초기 XO 고가(첫 번째 열이 O인 경우)에 비해 전환칸수만큼 감소한 XO 저가 값 또는
  • 초기 XO 저가(첫 번째 열이 X인 경우)에 비해 전환칸수만큼 증가한 XO 고가 값

해당 경질 원유 차트 예시의 경우 XO 고가와 XO 저가 모두 [Bars-1]=100입니다.

다음 중 어떤 이벤트가 먼저 발생하는지 확인하세요.

  • 다음 바의 XO 저가[i] 값이 $97 이하인 경우, 즉 첫 번째 열이 O임을 시사하는 경우 또는
  • 다음 바의 XO 고가[i] 값이 $103 이상인 경우, 즉 첫 번째 열이 X임을 시사하는 경우

2월 17일의 첫 번째 열을 알 수 있네요. XO 고가가 $103에 도달했으니 첫 번째 열은 X입니다. $100부터 $103 사이에 네 개의 X를 그립니다.

향후 차트 이동 방향 예측하기

현재 열이 X인 경우, 현재 바의 XO 고가가 현재 XO 가격에 비해 박스칸만큼 증가했는지 확인합니다. 2월 20일의 XO 고가가 $104 이상인지 확인하면 됩니다. 만약 2월 20일의 XO 고가가 $104, $105 혹은 그 이상인 경우 현재 X열에 해당 수만큼의 X를 추가합니다.

현재 바의 XO 고가가 현재 XO 가격에 비해 박스칸만큼 증가하지 않은 경우, 현재 바의 XO 저가가 XO 고가에서 전환칸수를 뺀 것보다 낮은지 확인합니다. 2월 20일의 XO 저가가 $103-3*$1 값인 $100 또는 $99이거나 그 미만인 경우입니다. 이 경우 X열 오른쪽으로 $102에서 $100까지 O열을 그립니다.

현재 열이 O인 경우 전부 반대 방향으로 생각하면 됩니다.

중요: 새로운 O열은 항상 이전 X열 고가 우측의 한칸값만큼 낮은 곳에 그려지며 새로운 X열은 항상 이전 O열 저가 우측의 한칸값만큼 높은 곳에 그려집니다.

원리는 잘 아시겠죠? 이번에는 지지선과 저항선에 대해 알아보겠습니다.

전통적인 P&F 차트에서 지지선과 저항선은 항상 45도 각도를 이룹니다.

첫 번째 선은 첫 번째 열과 관련이 있죠. 첫 번째 열의 값이 X인 경우 첫 번째 선은 첫 번째 열 최고가보다 한칸값만큼 높은 곳에서 시작해 오른쪽 하단을 향해 45도 각도로 그려지는 저항선이 됩니다. 첫 번째 열의 값이 O인 경우 첫 번째 선은 첫 번째 열 최저가보다 한칸값만큼 낮은 곳에서 시작해 오른쪽 상단을 향해 45도 각도로 그려지는 지지선이 됩니다. 지지선과 저항선은 가격 차트에 도달할 때까지 반복해서 그려집니다.

지지선과 저항선이 가격 차트에 도달하면 그 다음 가격 차트에 맞추어 다시 지지선과 저항선을 그리기 시작합니다. 가장 중요한 건 라인 차트가 이전 추세선보다 오른쪽에 위치하도록 하는 것입니다. 지지선을 그리려면 우선 저항선 아래의 최소 차트값을 알아야 합니다. 최소 차트값보다 한칸값만큼 낮은 곳에서 오른쪽 상단을 향하도록 지지선을 그리기 시작해 차트에 도달하거나 차트의 마지막 열에 도달할 때까지 반복합니다.

해당 지지선이 동일한 저항선에 걸리면 오른쪽으로 이동해 저항선 아래 최소 값부터 저항선 끝 사이에서 새로운 최소값을 찾습니다. 새로운 추세선이 기존 추세선을 넘어 오른쪽에 위치할 때까지 반복합니다.

실제 차트를 이용한 하단의 예시를 보면 좀 더 이해하기 쉬울 거예요.

알고리즘은 대충 이해가 됐을 겁니다. 이제 스크립트에 몇 가지 기능을 추가해 봅시다.

  • 모드 선택: 현재 심볼/마켓워치 전체 심볼에 대한 차트 작성
  • 타임프레임 선택(일간 타임프레임에는 100핍 차트를, M1에는 1~3핍 차트를 그리는 것이 논리적)
  • 한칸값 설정(핍)
  • 전환칸수 설정
  • 행열 볼륨 글자수 설정(MarketDepth 인디케이터 참조, 스크립트의 경우 틱 볼륨)
  • 차트 적용 기록 길이 설정
  • 아웃풋 포맷(텍스트 또는 이미지) 설정
  • 마지막으로, 초보자들에게 유용할 기능을 추가합니다. 바로 자동 차트 작성 기능이죠! 차트 높이를 기준으로 한칸값이 자동으로 설정됩니다.

이제 설명은 다 끝났으니 스크립트를 확인해 볼까요?

//+------------------------------------------------------------------+
//|                                         Point&Figure text charts |
//|                                        BSD Lic. 2012, Roman Rich |
//|                                           http://www.FXRays.info |
//+------------------------------------------------------------------+
#property               copyright "Roman Rich"
#property               link      "http://www.FXRays.info"
#property               version   "1.00"
#property               script_show_inputs
#include                "cIntBMP.mqh"                                       // Include the file containing cIntBMP class

input bool              mw=true;                                    // All MarketWatch?
input ENUM_TIMEFRAMES   tf=PERIOD_M1;                                 // Time frame
input long              box=2;                                      // Box size in pips (0 - auto)
enum                    cChoice{c10=10,c25=25,c50=50,c100=100};
input cChoice           count=c50;                                 // Chart height in boxes for autocharting
enum                    rChoice{Two=2,Three,Four,Five,Six,Seven};
input rChoice           reverse=Five;                              // Number of boxes for reversal
enum                    vChoice{v10=10,v25=25,v50=50};
input vChoice           vd=v10;                                    // Characters for displaying volumes
enum                    dChoice{Little=15000,Middle=50000,Many=100000,Extremely=1000000};
input dChoice           depth=Little;                              // History depth
input bool              pic=true;                                   // Image file?
input int               cellsize=10;                                // Cell size in pixels
//+------------------------------------------------------------------+
//| cIntBMP class descendant                                          |
//+------------------------------------------------------------------+
class cIntBMPEx : public cIntBMP
  {
public:
   void              Rectangle(int aX1,int aY1,int aSizeX,int aSizeY,int aColor);
   void              Bar(int aX1,int aY1,int aSizeX,int aSizeY,int aColor);
   void              LineH(int aX1,int aY1,int aSizeX,int aColor);
   void              LineV(int aX1,int aY1,int aSizeY,int aColor);
   void              DrawBar(int aX1,int aY1,int aX2,int aY2,int aColor);
   void              TypeTextV(int aX,int aY,string aText,int aColor);
  };
cIntBMPEx bmp;    // cIntBMPEx class instance
uchar Mask_O[192]= // The naughts
  {
   217,210,241,111,87,201,124,102,206,165,150,221,237,234,248,255,255,255,255,255,255,255,255,255,
   73,42,187,137,117,211,201,192,235,140,120,212,60,27,182,178,165,226,255,255,255,255,255,255,
   40,3,174,250,249,253,255,255,255,255,255,255,229,225,245,83,54,190,152,135,216,255,255,255,
   68,36,185,229,225,245,255,255,255,255,255,255,255,255,255,247,246,252,78,48,188,201,192,235,
   140,120,212,145,126,214,255,255,255,255,255,255,255,255,255,255,255,255,188,177,230,124,102,206,
   237,234,248,58,24,181,209,201,238,255,255,255,255,255,255,255,255,255,168,153,222,124,102,206,
   255,255,255,199,189,234,63,30,183,186,174,229,247,246,252,204,195,236,60,27,182,204,195,236,
   255,255,255,255,255,255,232,228,246,117,93,203,52,18,179,83,54,190,196,186,233,255,255,255
  };
uchar Mask_X[192]= // The crosses
  {
   254,252,252,189,51,51,236,195,195,255,255,255,255,255,255,235,192,192,248,234,234,255,255,255,
   255,255,255,202,90,90,184,33,33,251,243,243,212,120,120,173,0,0,173,0,0,255,255,255,
   255,255,255,254,252,252,195,69,69,192,60,60,178,15,15,233,186,186,253,249,249,255,255,255,
   255,255,255,255,255,255,241,210,210,173,0,0,209,111,111,255,255,255,255,255,255,255,255,255,
   255,255,255,255,255,255,205,99,99,192,60,60,181,24,24,241,210,210,255,255,255,255,255,255,
   255,255,255,249,237,237,176,9,9,241,213,213,226,165,165,189,51,51,254,252,252,255,255,255,
   255,255,255,230,177,177,185,36,36,255,255,255,255,255,255,189,51,51,222,153,153,255,255,255,
   255,255,255,240,207,207,200,84,84,255,255,255,255,255,255,227,168,168,211,117,117,255,255,255
  };
//+------------------------------------------------------------------+
//| Instrument selection                                                |
//+------------------------------------------------------------------+
void OnStart()
  {
   int    mwSymb;
   string symb;
   int    height=0,width=0;
   string pnfArray[];
   if(mw==true)
     {
      mwSymb=0;
      while(mwSymb<SymbolsTotal(true))
        {
         symb=SymbolName(mwSymb,true);
         ArrayFree(pnfArray);
         ArrayResize(pnfArray,0,0);
         PNF(symb,pnfArray,height,width,pic,cellsize);
         pnf2file(symb,pnfArray,0,height);
         mwSymb++;
        };
     }
   else
     {
      symb=Symbol();
      ArrayFree(pnfArray);
      ArrayResize(pnfArray,0,0);
      PNF(symb,pnfArray,height,width,pic,cellsize);
      pnf2file(symb,pnfArray,0,height);
     };
   Alert("Ok.");
  }
//+------------------------------------------------------------------+
//| Chart calculation and drawing                      |
//+------------------------------------------------------------------+
void PNF(string sName,      // instrument
         string& array[],  // array for the output
         int& y,           // array height
         int& z,           // array width
         bool toPic,       // if true-output and draw
         int cs)           // set the cell size for drawing
  {
   string      s,ps;
   datetime    d[];
   double      o[],h[],l[],c[];
   long        v[];
   uchar       matrix[];
   long        VolByPrice[],VolByCol[],HVolumeMax,VVolumeMax;
   int         tMin[],tMax[];
   datetime    DateByCol[];
   MqlDateTime bMDT,eMDT;
   string      strDBC[];
   uchar       pnf='.';
   int         sd;
   int         b,i,j,k=0,m=0;
   int         GlobalMin,GlobalMax,StartMin,StartMax,CurMin,CurMax,RevMin,RevMax,ContMin,ContMax;
   int         height,width,beg=0,end=0;
   double      dBox,price;
   int         thBeg=1,thEnd=2,tv=0;
   uchar       trend='.';
// --------------------------------- BMP -----------------------------------------
   int RowVolWidth=10*cs;
//--- shift for prices
   int startX=5*cs;
   int yshift=cs*7;
// --------------------------------- BMP -----------------------------------------
   if(SymbolInfoInteger(sName,SYMBOL_DIGITS)<=3) sd=2; else sd=4;
   b=MathMin(Bars(sName,tf),depth);
   ArrayFree(d);
   ArrayFree(o);
   ArrayFree(h);
   ArrayFree(l);
   ArrayFree(c);
   ArrayFree(v);
   ArrayFree(matrix);
   ArrayFree(VolByPrice);
   ArrayFree(VolByCol);
   ArrayFree(DateByCol);
   ArrayFree(tMin);
   ArrayFree(tMax);
   ArrayResize(d,b,0);
   ArrayResize(o,b,0);
   ArrayResize(h,b,0);
   ArrayResize(l,b,0);
   ArrayResize(c,b,0);
   ArrayResize(v,b,0);
   ArrayInitialize(d,NULL);
   ArrayInitialize(o,NULL);
   ArrayInitialize(h,NULL);
   ArrayInitialize(l,NULL);
   ArrayInitialize(c,NULL);
   ArrayInitialize(v,NULL);
   CopyTime(sName,tf,0,b,d);
   CopyOpen(sName,tf,0,b,o);
   CopyHigh(sName,tf,0,b,h);
   CopyLow(sName,tf,0,b,l);
   CopyClose(sName,tf,0,b,c);
   CopyTickVolume(sName,tf,0,b,v);
   if(box!=0)
     {
      dBox=box/MathPow(10.0,(double)sd);
     }
   else
     {
      dBox=MathNorm((h[ArrayMaximum(h,0,WHOLE_ARRAY)]-l[ArrayMinimum(l,0,WHOLE_ARRAY)])/count,
                      1/MathPow(10.0,(double)sd),true)/MathPow(10.0,(double)sd);
     };
   GlobalMin=MathNorm(l[ArrayMinimum(l,0,WHOLE_ARRAY)],dBox,true)-(int)(reverse);
   GlobalMax=MathNorm(h[ArrayMaximum(h,0,WHOLE_ARRAY)],dBox,false)+(int)(reverse);
   StartMin=MathNorm(l[0],dBox,true);
   StartMax=MathNorm(h[0],dBox,false);
   ContMin=(int)(StartMin-1);
   ContMax=(int)(StartMax+1);
   RevMin=(int)(StartMax-reverse);
   RevMax=(int)(StartMin+reverse);
   height=(int)(GlobalMax-GlobalMin);
   width=1;
   ArrayResize(matrix,height*width,0);
   ArrayInitialize(matrix,'.');
   ArrayResize(VolByPrice,height,0);
   ArrayInitialize(VolByPrice,0);
   ArrayResize(VolByCol,width,0);
   ArrayInitialize(VolByCol,0);
   ArrayResize(DateByCol,width,0);
   ArrayInitialize(DateByCol,D'01.01.1971');
   ArrayResize(tMin,width,0);
   ArrayInitialize(tMin,0);
   ArrayResize(tMax,width,0);
   ArrayInitialize(tMax,0);
   for(i=1;i<b;i++)
     {
      CurMin=MathNorm(l[i],dBox,true);
      CurMax=MathNorm(h[i],dBox,false);
      switch(pnf)
        {
         case '.':
           {
            if(CurMax>=RevMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               beg=(int)(StartMin-GlobalMin-1);
               end=(int)(CurMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               trend='D';
               break;
              };
            if(CurMin<=RevMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               beg=(int)(CurMin-GlobalMin-1);
               end=(int)(StartMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               trend='U';
               break;
              };
            break;
           };
         case 'X':
           {
            if(CurMax>=ContMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               end=(int)(CurMax-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               break;
              };
            if(CurMin<=RevMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               beg=(int)(CurMin-GlobalMin-1);
               end--;
               width++;
               ArrayResize(matrix,height*width,0);
               ArrayResize(VolByCol,width,0);
               ArrayResize(DateByCol,width,0);
               ArrayResize(tMin,width,0);
               ArrayResize(tMax,width,0);
               SetMatrix(matrix,0,(int)(height-1),height,(int)(width-1),'.');
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=0;
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               break;
              };
            break;
           };
         case 'O':
           {
            if(CurMin<=ContMin)
              {
               pnf='O';
               ContMin=(int)(CurMin-1);
               RevMax=(int)(CurMin+reverse);
               beg=(int)(CurMin-GlobalMin-1);
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               break;
              };
            if(CurMax>=RevMax)
              {
               pnf='X';
               ContMax=(int)(CurMax+1);
               RevMin=(int)(CurMax-reverse);
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               beg++;
               end=(int)(CurMax-GlobalMin-1);
               width++;
               ArrayResize(matrix,height*width,0);
               ArrayResize(VolByCol,width,0);
               ArrayResize(DateByCol,width,0);
               ArrayResize(tMin,width,0);
               ArrayResize(tMax,width,0);
               SetMatrix(matrix,0,(int)(height-1),height,(int)(width-1),'.');
               SetMatrix(matrix,beg,end,height,(int)(width-1),pnf);
               SetVector(VolByPrice,beg,end,v[i]);
               VolByCol[width-1]=0;
               VolByCol[width-1]=VolByCol[width-1]+v[i];
               DateByCol[width-1]=d[i];
               tMin[width-1]=beg-1;
               tMax[width-1]=end+1;
               break;
              };
            break;
           };
        };
     };
//--- credits
   s="BSD License, 2012, FXRays.info by Roman Rich";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   s=SymbolInfoString(sName,SYMBOL_DESCRIPTION)+",
                      Box-"+DoubleToString(box,0)+",Reverse-"+DoubleToString(reverse,0);
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
// --------------------------------- BMP -----------------------------------------
   if(toPic==true)
     {
      //-- BMP image size on the chart display
      int XSize=cs*width+2*startX+RowVolWidth;
      int YSize=cs*height+yshift+70;
      //-- creating a bmp image sized XSize x YSize with the background color clrWhite
      bmp.Create(XSize,YSize,clrWhite);
      //-- displaying cells of the main field
      for(i=height-1;i>=0;i--)
         for(j=0;j<=width-1;j++)
           {
            bmp.Bar(RowVolWidth+startX+cs*j,yshift+cs*i,cs,cs,clrWhite);
            bmp.Rectangle(RowVolWidth+startX+cs*j,yshift+cs*i,cs,cs,clrLightGray);
           }
      bmp.TypeText(10,yshift+cs*(height)+50,array[k-2],clrDarkGray);
      bmp.TypeText(10,yshift+cs*(height)+35,array[k-1],clrGray);
     }
// --------------------------------- BMP -----------------------------------------
//--- calculating trend lines
   i=0;
   while(thEnd<width-1)
     {
      while(thBeg+i<thEnd)
        {
         if(trend=='U')
           {
            i=ArrayMinimum(tMin,thBeg,thEnd-thBeg);
            j=tMin[i];
           }
         else
           {
            i=ArrayMaximum(tMax,thBeg,thEnd-thBeg);
            j=tMax[i];
           }
         thBeg=i;
         tv=j;
         i=0;
         while(GetMatrix(matrix,j,height,(long)(thBeg+i))=='.')
           {
            i++;
            if(trend=='U') j++; else j--;
            if(thBeg+i==width-1)
              {
               thEnd=width-1;
               break;
              };
           };
         if(thBeg+i<thEnd)
           {
            thBeg=thBeg+2;
            i=0;
           };
        };
      thEnd=thBeg+i;
      if(thEnd==thBeg) thEnd++;
      for(i=thBeg;i<thEnd;i++)
        {
         SetMatrix(matrix,tv,tv,height,(long)(i),'+');
         // --------------------------------- BMP -----------------------------------------
         if(toPic==true)
           {
            //--- support and resistance lines
            if(trend=='U') { bmp.DrawLine(RowVolWidth+startX+i*cs,yshift+tv*cs,
                                         RowVolWidth+startX+(i+1)*cs,yshift+(tv+1)*cs,clrGreen); }
            if(trend=='D') { bmp.DrawLine(RowVolWidth+startX+i*cs,yshift+(tv+1)*cs,
                                         RowVolWidth+startX+(i+1)*cs,yshift+(tv)*cs,clrRed); }
            //--- broadening of support/resistance lines
            if(trend=='U') { bmp.DrawLine(RowVolWidth+1+startX+i*cs,yshift+tv*cs,
                                         RowVolWidth+1+startX+(i+1)*cs,yshift+(tv+1)*cs,clrGreen); }
            if(trend=='D') { bmp.DrawLine(RowVolWidth+1+startX+i*cs,yshift+(tv+1)*cs,
                                         RowVolWidth+1+startX+(i+1)*cs,yshift+(tv)*cs,clrRed); }
           }
         // --------------------------------- BMP -----------------------------------------
         if(trend=='U') tv++; else tv--;
        };
      if(trend=='U') trend='D'; else trend='U';
      i=0;
     };
//--- displaying data in columns
   ArrayResize(strDBC,width,0);
   TimeToStruct(DateByCol[0],bMDT);
   TimeToStruct(DateByCol[width-1],eMDT);
   if((DateByCol[width-1]-DateByCol[0])>=50000000)
     {
      for(i=0;i<=width-1;i++) StringInit(strDBC[i],4,' ');
      for(i=1;i<=width-1;i++)
        {
         TimeToStruct(DateByCol[i-1],bMDT);
         TimeToStruct(DateByCol[i],eMDT);
         if(bMDT.year!=eMDT.year) strDBC[i]=DoubleToString(eMDT.year,0);
        };
      for(i=0;i<=3;i++)
        {
         StringInit(s,vd,' ');
         s=s+"            : ";
         for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
         s=s+" : ";
         k++;
         ArrayResize(array,k,0);
         array[k-1]=s;
        };
     }
   else
     {
      if((DateByCol[width-1]-DateByCol[0])>=5000000)
        {
         for(i=0;i<=width-1;i++) StringInit(strDBC[i],7,' ');
         for(i=1;i<=width-1;i++)
           {
            TimeToStruct(DateByCol[i-1],bMDT);
            TimeToStruct(DateByCol[i],eMDT);
            if(bMDT.mon!=eMDT.mon)
              {
               if(eMDT.mon<10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"+DoubleToString(eMDT.mon,0);
               if(eMDT.mon>=10) strDBC[i]=DoubleToString(eMDT.year,0)+"."+DoubleToString(eMDT.mon,0);
              }
           };
         for(i=0;i<=6;i++)
           {
            StringInit(s,vd,' ');
            s=s+"            : ";
            for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
            s=s+" : ";
            k++;
            ArrayResize(array,k,0);
            array[k-1]=s;
           };
        }
      else
        {
         for(i=0;i<=width-1;i++) StringInit(strDBC[i],10,' ');
         for(i=1;i<=width-1;i++)
           {
            TimeToStruct(DateByCol[i-1],bMDT);
            TimeToStruct(DateByCol[i],eMDT);
            if(bMDT.day!=eMDT.day)
              {
               if(eMDT.mon<10 && eMDT.day<10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"
                                                       +DoubleToString(eMDT.mon,0)+".0"+DoubleToString(eMDT.day,0);
               if(eMDT.mon<10 && eMDT.day>=10) strDBC[i]=DoubleToString(eMDT.year,0)+".0"
                                                       +DoubleToString(eMDT.mon,0)+"."+DoubleToString(eMDT.day,0);
               if(eMDT.mon>=10&&eMDT.day< 10) strDBC[i]=DoubleToString(eMDT.year,0)+"." 
                                                      +DoubleToString(eMDT.mon,0)+".0"+DoubleToString(eMDT.day,0);
               if(eMDT.mon>=10&&eMDT.day>=10) strDBC[i]=DoubleToString(eMDT.year,0)+"." 
                                                      +DoubleToString(eMDT.mon,0)+"." +DoubleToString(eMDT.day,0);
              }
           };
         for(i=0;i<=9;i++)
           {
            StringInit(s,vd,' ');
            s=s+"            : ";
            for(j=0;j<=width-1;j++) s=s+StringSubstr(strDBC[j],i,1);
            s=s+" : ";
            k++;
            ArrayResize(array,k,0);
            array[k-1]=s;
           };
        };
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- displaying price chart
   price=GlobalMax*dBox;
   HVolumeMax=VolByPrice[ArrayMaximum(VolByPrice,0,WHOLE_ARRAY)];
   s="";
   for(i=height-1;i>=0;i--)
     {
      StringInit(ps,8-StringLen(DoubleToString(price,sd)),' ');
      s=s+ps+DoubleToString(price,sd)+" : ";
      for(j=0;j<vd;j++) if(VolByPrice[i]>HVolumeMax*j/vd) s=s+"*"; else s=s+" ";
      s=s+" : ";
      for(j=0;j<=width-1;j++) s=s+CharToString(matrix[j*height+i]);
      s=s+" : "+ps+DoubleToString(price,sd);
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
      s="";
      price=price-dBox;
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- simple markup through 10
   StringInit(s,vd,' ');
   s=s+"            : ";
   for(j=0;j<=width-1;j++) if(StringGetCharacter(DoubleToString(j,0),
                                                    StringLen(DoubleToString(j,0))-1)==57) s=s+"|"; else s=s+" ";
   s=s+" : ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- displaying volume chart in columns
   VVolumeMax=VolByCol[ArrayMaximum(VolByCol,0,WHOLE_ARRAY)];
   for(i=vd-1;i>=0;i--)
     {
      StringInit(s,vd,' ');
      s=s+"            : ";
      for(j=0;j<=width-1;j++) if(VolByCol[j]>VVolumeMax*i/vd) s=s+"*"; else s=s+" ";
      s=s+" : ";
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
     };
   StringInit(s,25+vd+width,'-');
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
//--- column history
   s="     | Start Date/Time     | End Date/Time       | ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   TimeToStruct(DateByCol[0],bMDT);
   s="   1 | 0000/00/00 00:00:00 | ";
   s=s+DoubleToString(bMDT.year,0)+"/";
   if(bMDT.mon >=10) s=s+DoubleToString(bMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(bMDT.mon ,0)+"/";
   if(bMDT.day >=10) s=s+DoubleToString(bMDT.day ,0)+" "; else s=s+"0"+DoubleToString(bMDT.day ,0)+" ";
   if(bMDT.hour>=10) s=s+DoubleToString(bMDT.hour,0)+":"; else s=s+"0"+DoubleToString(bMDT.hour,0)+":";
   if(bMDT.min >=10) s=s+DoubleToString(bMDT.min ,0)+":"; else s=s+"0"+DoubleToString(bMDT.min ,0)+":";
   if(bMDT.sec >=10) s=s+DoubleToString(bMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(bMDT.sec ,0)+" | ";
   k++;
   ArrayResize(array,k,0);
   array[k-1]=s;
   for(i=1;i<=width-1;i++)
     {
      TimeToStruct(DateByCol[i-1],bMDT);
      TimeToStruct(DateByCol[i],eMDT);
      s="";
      StringInit(ps,4-StringLen(DoubleToString(i+1,0)),' ');
      s=s+ps+DoubleToString(i+1,0)+" | ";
      s=s+DoubleToString(bMDT.year,0)+"/";
      if(bMDT.mon >=10) s=s+DoubleToString(bMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(bMDT.mon ,0)+"/";
      if(bMDT.day >=10) s=s+DoubleToString(bMDT.day ,0)+" "; else s=s+"0"+DoubleToString(bMDT.day ,0)+" ";
      if(bMDT.hour>=10) s=s+DoubleToString(bMDT.hour,0)+":"; else s=s+"0"+DoubleToString(bMDT.hour,0)+":";
      if(bMDT.min >=10) s=s+DoubleToString(bMDT.min ,0)+":"; else s=s+"0"+DoubleToString(bMDT.min ,0)+":";
      if(bMDT.sec >=10) s=s+DoubleToString(bMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(bMDT.sec ,0)+" | ";
      s=s+DoubleToString(eMDT.year,0)+"/";
      if(eMDT.mon >=10) s=s+DoubleToString(eMDT.mon ,0)+"/"; else s=s+"0"+DoubleToString(eMDT.mon ,0)+"/";
      if(eMDT.day >=10) s=s+DoubleToString(eMDT.day ,0)+" "; else s=s+"0"+DoubleToString(eMDT.day ,0)+" ";
      if(eMDT.hour>=10) s=s+DoubleToString(eMDT.hour,0)+":"; else s=s+"0"+DoubleToString(eMDT.hour,0)+":";
      if(eMDT.min >=10) s=s+DoubleToString(eMDT.min ,0)+":"; else s=s+"0"+DoubleToString(eMDT.min ,0)+":";
      if(eMDT.sec >=10) s=s+DoubleToString(eMDT.sec ,0)+" | "; else s=s+"0"+DoubleToString(eMDT.sec ,0)+" | ";
      k++;
      ArrayResize(array,k,0);
      array[k-1]=s;
     };
   y=k;
   z=25+vd+width;
// --------------------------------- BMP -----------------------------------------
   if(toPic==true)
     {
      //--- displaying dates in YYYY/MM/DD format
      for(j=0;j<=width-1;j++)
        {
         string s0=strDBC[j];
         StringReplace(s0,".","/");
         bmp.TypeTextV(RowVolWidth+startX+cs*j,yshift+cs*(height-1)+5,s0,clrDimGray);
        }
      //--- volume cell support
      for(i=height-1;i>=0;i--)
         for(j=0;j<vd;j++)
           {
            bmp.Bar(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,0xF6F6F6);
            bmp.Rectangle(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrLightGray);
           }
      for(i=0; i>-7;i--)
         for(j=0;j<=vd;j++)
           {
            bmp.Bar(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrWhite);
            bmp.Rectangle(cs+startX+cs*(j-1),yshift+cs*i,cs,cs,clrLightGray);
           }
      //--- exact volumes
      for(i=height-1;i>=0;i--)
         bmp.Bar(startX,yshift+cs*i,int(10*cs*VolByPrice[i]/HVolumeMax),cs,0xB5ABAB);
      //--- displaying naughts and crosses
      for(i=height-1;i>=0;i--)
         for(j=0;j<=width-1;j++)
           {
            int xpos=RowVolWidth+startX+cs*j+1;
            int ypos=yshift+cs*i+1;
            if(CharToString(matrix[j*height+i])=="X") ShowCell(xpos,ypos,'X');
            else
               if(CharToString(matrix[j*height+i])=="O") ShowCell(xpos,ypos,'O');
           }
      //--- volume underside support
      for(i=0;i<=60/cs;i++)
         for(j=0;j<=width-1;j++)
           {
            bmp.Bar(RowVolWidth+startX+cs*j,12+cs*i,cs,cs,0xF6F6F6);
            bmp.Rectangle(RowVolWidth+startX+cs*j,12+cs*i,cs,cs,clrLightGray);
           }
      //--- displaying volumes
      for(j=0;j<=width-1;j++) bmp.Bar(RowVolWidth+startX+cs*j,yshift-60,
                                     cs,int(60*VolByCol[j]/VVolumeMax),0xB5ABAB);
      //--- displaying the main field border
      bmp.Rectangle(RowVolWidth+startX+cs*0,yshift+cs*0,cs*(width),cs*(height),clrSilver);
      //--- displaying prices and scale
      bmp.LineV(startX,yshift,cs*height,clrBlack);
      bmp.LineV(RowVolWidth+startX+cs*width,yshift,cs*height,clrBlack);
      price=GlobalMax*dBox;
      for(i=height-1;i>=0;i--)
        {
         //-- prices on the left
         bmp.TypeText(cs,yshift+cs*i,DoubleToString(price,sd),clrBlack);
         bmp.LineH(0,yshift+cs*i,startX,clrLightGray);
         bmp.LineH(0+startX-3,yshift+cs*i,6,clrBlack);
         //-- prices on the right     
         int dx=RowVolWidth+cs*width;
         bmp.TypeText(10+startX+dx,yshift+cs*i,DoubleToString(price,sd),clrBlack);
         bmp.LineH(startX+dx,yshift+cs*i,40,clrLightGray);
         bmp.LineH(startX+dx-3,yshift+cs*i,6,clrBlack);
         price=price-dBox;
        }
      //-- saving the resulting image in a file  
      bmp.Save(sName,true);
     }
// --------------------------------- BMP -----------------------------------------
  }
//+------------------------------------------------------------------+
//|Outputting as a text file                                          |
//+------------------------------------------------------------------+
void pnf2file(string sName,        // instrument for the file name
              string& array[],    // array of lines saved in the file
              int beg,            // the line of the array first saved in the file
              int end)            // the line of the array last saved in the file
  {
   string fn;
   int    handle;
   fn=sName+"_b"+DoubleToString(box,0)+"_r"+DoubleToString(reverse,0)+".txt";
   handle=FileOpen(fn,FILE_WRITE|FILE_TXT|FILE_ANSI,';');
   for(int i=beg;i<end;i++) FileWrite(handle,array[i]);
   FileClose(handle);
  }
//+------------------------------------------------------------------+
//| Adjusting the price to the box size                                    |
//+------------------------------------------------------------------+
int MathNorm(double value,     // transforming any double-type figure into long-type figure
             double prec,      // ensuring the necessary accuracy
             bool vect)        // and if true, rounding up; if false, rounding down
  {
   if(vect==true)
      return((int)(MathCeil(value/prec)));
   else
      return((int)(MathFloor(value/prec)));
  }
//+------------------------------------------------------------------+
//| Filling the array                                                 |
//| Character one-dimensional array represented as a matrix         |
//+------------------------------------------------------------------+
void SetMatrix(uchar& array[],      // passing the array in a link to effect a replacement
               long pbeg,          // from here
               long pend,          // up to here
               long pheight,       // in the column of this height
               long pwidth,        // bearing this number among all the columns in the array
               uchar ppnf)         // with this character
  {
   long offset=0;
   for(offset=pheight*pwidth+pbeg;offset<=pheight*pwidth+pend;offset++) array[(int)offset]=ppnf;
  }
//+------------------------------------------------------------------+
//| Getting an isolated value from the array                           |
//| Character one-dimensional array represented as a matrix         |
//+------------------------------------------------------------------+
uchar GetMatrix(uchar& array[],      // passing it in a link to obtain a character...
                long pbeg,          // here
                long pheight,       // in the column of this height
                long pwidth)        // bearing this number among all the columns in the array
  {
   return(array[(int)pheight*(int)pwidth+(int)pbeg]);
  }
//+------------------------------------------------------------------+
//|Filling the vector                                                  |
//+------------------------------------------------------------------+
void SetVector(long &array[],      // passing the long-type array in a link to effect a replacement
               long pbeg,         // from here
               long pend,         // up to here
               long pv)           // with this value
  {
   long offset=0;
   for(offset=pbeg;offset<=pend;offset++) array[(int)offset]=array[(int)offset]+pv;
  }
//+------------------------------------------------------------------+
//| Displaying a horizontal line                                 |
//+------------------------------------------------------------------+
void cIntBMPEx::LineH(int aX1,int aY1,int aSizeX,int aColor)
  {
   DrawLine(aX1,aY1,aX1+aSizeX,aY1,aColor);
  }
//+------------------------------------------------------------------+
//| Displaying a vertical line                                   |
//+------------------------------------------------------------------+  
void cIntBMPEx::LineV(int aX1,int aY1,int aSizeY,int aColor)
  {
   DrawLine(aX1,aY1,aX1,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Drawing a rectangle (of a given size)                         |
//+------------------------------------------------------------------+
void cIntBMPEx::Rectangle(int aX1,int aY1,int aSizeX,int aSizeY,int aColor)
  {
   DrawRectangle(aX1,aY1,aX1+aSizeX,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Drawing a filled rectangle (of a given size)             |
//+------------------------------------------------------------------+
void cIntBMPEx::Bar(int aX1,int aY1,int aSizeX,int aSizeY,int aColor)
  {
   DrawBar(aX1,aY1,aX1+aSizeX,aY1+aSizeY,aColor);
  }
//+------------------------------------------------------------------+
//| Drawing a filled rectangle                                 |
//+------------------------------------------------------------------+
void cIntBMPEx::DrawBar(int aX1,int aY1,int aX2,int aY2,int aColor)
  {
   for(int i=aX1; i<=aX2; i++)
      for(int j=aY1; j<=aY2; j++)
        {
         DrawDot(i,j,aColor);
        }
  }
//+------------------------------------------------------------------+
//| Displaying the text vertically                                  |
//+------------------------------------------------------------------+
void cIntBMPEx::TypeTextV(int aX,int aY,string aText,int aColor)
  {
   SetDrawWidth(1);
   for(int j=0;j<StringLen(aText);j++)
     {
      string TypeChar=StringSubstr(aText,j,1);
      if(TypeChar==" ")
        {
         aY+=5;
        }
      else
        {
         int Pointer=0;
         for(int i=0;i<ArraySize(CA);i++)
           {
            if(CA[i]==TypeChar)
              {
               Pointer=i;
              }
           }
         for(int i=PA[Pointer];i<PA[Pointer+1];i++)
           {
            DrawDot(aX+YA[i],aY+MaxHeight+XA[i],aColor);
           }
         aY+=WA[Pointer]+1;
        }
     }
  }
//+------------------------------------------------------------------+
//| Transforming components into color                                    |
//+------------------------------------------------------------------+
int RGB256(int aR,int aG,int aB)
  {
   return(aR+256*aG+65536*aB);
  }
//+------------------------------------------------------------------+
//| Drawing X's or O's as an image                               |
//+------------------------------------------------------------------+
void ShowCell(int x,int y,uchar img)
  {
   uchar r,g,b;
   for(int i=0; i<8; i++)
     {
      for(int j=0; j<8; j++)
        {
         switch(img)
           {
            case 'X':
               r=Mask_X[3*(j*8+i)];
               g=Mask_X[3*(j*8+i)+1];
               b=Mask_X[3*(j*8+i)+2];
               break;
            case 'O':
               r=Mask_O[3*(j*8+i)];
               g=Mask_O[3*(j*8+i)+1];
               b=Mask_O[3*(j*8+i)+2];
               break;
           };
         int col=RGB256(r,g,b);
         bmp.DrawDot(x+i,y+j,col);
        }
     }
  }
//+------------------------------------------------------------------+

pic 명령값에 따라 스크립트 실행 결과가 이미지가 포함된 텍스트 파일(terminal_data_directory\MQL5\Images) 또는 텍스트 전용 파일(terminal_data_directory\MQL5\Files)로 생성됩니다 .


결과 비교하기

한칸값이 $1이고 전환칸수가 3인 경질 원유 차트를 그려 결과를 비교하겠습니다.

StockCharts.com

그림 1. StockCharts.com에서 생성된 경질 원유 P&F 차트

그림 1. StockCharts.com에서 생성된 경질 원유 P&F 차트

불스아이 브로커(Bull's-Eye Broker)

그림 2. 불스아이 브로커 소프트웨어로 생성한 경질 원유 P&F 차트

그림 2. 불스아이 브로커 소프트웨어로 생성한 경질 원유 P&F 차트


다음은 스크립트 실행 결과입니다.

그림 3. 스크립트가 생성한 경질 원유 P&F 차트

그림 3. 스크립트가 생성한 경질 원유 P&F 차트

세 차트가 모두 동일하네요. 잘하셨습니다! 이제 대충은 알겠죠?


기본 P&T 차트 패턴

차트 패턴을 어떻게 이용할까요?

우선 기본 패턴에 대해 알아보겠습니다. 몇 개 안됩니다.

다음의 세 가지가 있습니다.

그림 4. 가격 패턴: 이중 상단, 삼중 상단, 이중 하단 및 삼중 하단

그림 4. 가격 패턴: 이중 상단, 삼중 상단, 이중 하단 및 삼중 하단

다음 가격 패턴입니다.

그림 5. 가격 패턴: 상승 삼각형과 하락 삼각형

그림 5. 가격 패턴: 상승 삼각형과 하락 삼각형

마지막 가격 패턴입니다.

그림 6. 가격 패턴: P&F 캐터펄트

그림 6. 가격 패턴: P&F 캐터펄트

이제 몇 가지 팁을 드릴게요.

  1. 지지선 위쪽으로는 롱 포지션을, 저항선 아래쪽으로는 숏 포지션만을 오픈하세요. 예를 들어, 2011년 9월부터 형성된 저항선이 돌파된 2011년 12월 중순 이후로는 경질 원유 선물에 대한 롱 포지션만을 오픈합니다.
  2. 지지선과 저항선을 추적 손절매에 이용하세요.
  3. 포지션 오픈 전에 예상 이익과 예상 손실을 계산해 보세요.

다음의 예를 통해 설명하겠습니다.

2011년 12월, 최초 가격이 $76였던 X열이 이전 X열의 $85를 넘어선 후 $87 저항선을 돌파하고 $89에 도달했습니다. 세로 카운트를 보면 가격이 $76+($89-$75)*3(전환칸수)의 값인 $118까지 올라갈 수 있을 것으로 보입니다.

실제 다음 가격 움직임은 조정을 통해 $85로 내려왔습니다. 투기 성향이 있으신 분들은 롱 포지션을 열어 $84에 손절을 설정하세요.

롱 포지션 진입 가격은 지난 X열보다 한칸값만큼 높은 지점에서 가격 조정이 완료된 후에 계획할 수 있습니다. 여기서는 $90가 되겠네요.

예상 손실을 추정해 봅니다. 선물 계약 당 $90에서 $84를 제외한 $6에 달할 수도 있습니다. 예상 이익은 $118에서 $90을 뺀 $28가 될 수도 있겠네요. 예상 이익:예상 손실 비율이 $28/$6>4.5이므로 제 생각에는 훌륭한 실적입니다. 지금쯤이면 모든 선물 계약마다 $105에서 $90을 뺀 $15 수익이 발생했겠네요.


라이선스

본문의 스크립트는 Roman Rich에 의해 개발되었으며 BSD라이선스 하에 배포됩니다. 라이선스 관련 사항은 Lic.txt 파일을 참조하세요. cIntBMP 라이브러리는 Integer(Dmitry)에 의해 개발되었습니다. StockCharts.com 및 불스아이 브로커(Bull's-Eye Broker)에 대한 상표권이 등록되어 있습니다.


결론

P&F 차트의 스크립트와 알고리즘을 살펴보았습니다. 본문에서 언급된 가격 패턴에 대한 설명은 링크를 참조하세요.


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

파일 첨부됨 |
pnf.zip (659.49 KB)
cintbmp.mqh (39.68 KB)
pnf2.mq5 (27.36 KB)
lic.txt (1.35 KB)
하나의 지표를 다른 지표에 적용하기 하나의 지표를 다른 지표에 적용하기
OnCalculate() 함수 호출의 간단한 형식을 사용하는 지시자를 작성할 때, 가격 데이터뿐만 아니라 다른 지시자의 데이터로도 지시자를 계산할 수 있다는 사실을 놓칠 수 있습니다 (내장형이든 맞춤형이든 상관없이). 다른 지표의 데이터에 대한 올바른 적용을 위해 지표를 개선하고 싶습니까? 이 글에서는 그러한 수정에 필요한 모든 단계를 검토할 것입니다.
가장 활동적인 MQL5. 커뮤니티 구성원에게 iPhone이 수여되었습니다! 가장 활동적인 MQL5. 커뮤니티 구성원에게 iPhone이 수여되었습니다!
가장 뛰어난 MQL5.com 참가자에게 보상을 하기로 결정한 후, 커뮤니티 개발에 대한 각 참가자의 기여도를 결정하기 위한 핵심 기준을 선정했습니다. 그 결과 홈페이지에 가장 많은 양의 기사를 게재한 investeo (11개 기사)와 victorg (10개 기사)와 Code Base에 그들의 프로그램을 제출하신 분 - GODZILLA(340개 프로그램), Integer(61개 프로그램), abolk(21개 프로그램), 등의 챔피언이 탄생했습니다.
Expert Advisor의 한계 및 검증 Expert Advisor의 한계 및 검증
월요일에 이 기호를 거래할 수 있습니까? 포지션을 열 수 있는 충분한 자금이 있습니까? 손절매가 발동되면 손실이 얼마나 됩니까? 보류 중인 주문 수를 제한하는 방법은 무엇입니까? 거래 작업이 현재 바에서 실행되었습니까 아니면 이전 바에서 실행되었습니까? 거래 로봇이 이러한 종류의 검증을 수행할 수 없다면 모든 거래 전략이 패배할 수 있습니다. 이 문서는 모든 Expert Advisor에서 유용한 검증의 예를 보여줍니다.
자동 거래 시스템(Automata-Based Programming)을 위한 새로운 접근 방식 자동 거래 시스템(Automata-Based Programming)을 위한 새로운 접근 방식
이 글은 MQL4와 MQL5에서 EA, 지표 및 스크립트를 개발하는 데 있어 완전히 새로운 방향을 제시합니다. 향후 이러한 프로그래밍 패러다임은 EA 구현에 있어 모든 거래자의 기본 기준이 될 것입니다. MQL5와 MetaTrader5 개발자는 오토마타 기반 프로그래밍 패러다임을 이용하여 새로운 언어인 MQL6와 새로운 플랫폼인 MetaTrader 6를 만들 수 있습니다.