English Русский 中文 Español Deutsch 日本語 한국어 Français Italiano Türkçe
A última cruzada

A última cruzada

MetaTrader 5Exemplos | 20 fevereiro 2014, 15:18
1 286 0
Roman Zamozhnyy
Roman Zamozhnyy

Introdução

Há três meios padrão de apresentação de preço de instrumento disponível no terminal do МetaТrader 5 (assim como no МetaТrader 4): barras, candlesticks (em vela) e linhas. Essencialmente, todos deles representam o mesmo - gráficos de tempo. Além do método tradicional de apresentação de preço relacionado com o tempo, ainda existem outros meios não relacionados com o tempo que são bastante populares entre os investidores e especuladores: Gráficos de Renko e de Kagi, três quebras de linha e gráficos de ponto e figura.

Eu não vou afirmar a sua vantagem sobre os clássicos, mas deixando a variável de tempo fora da vista, auxilia alguns traders a se concentrarem na variável de preço. Sugiro que consideremos aqui gráficos de ponto e figura, juntamente com um algoritmo de gráficos relevante, darmos uma olhada no mercado de produtos bem conhecido que serve para gerar tais gráficos e escrever um script claro e simples implementando o algoritmo. Um livro de Thomas J. Dorsey "Point and Figure Charting: A aplicação essencial para previsão e rastreamento de preços de mercado" será o nosso livro de ABC.

Bull's-Eye Broker é o pacote de software mais popular para desenhar gráficos offline. O software está disponível para teste de 21 dias (numerosos testes possíveis) e a nova versão Beta está disponível durante o período Beta. Este pacote de software será utilizado para estimar os resultados de desempenho do script. Um dos melhores recursos online em termos de gráficos de ponto e figura é StockCharts. O site é baseado na bolsa de valores, entretanto, não fornece preços de instrumento Forex.

Para comparar os resultados de desempenho do script, introduziríamos mercados futuros Gold, mercados futuros Light Crude Oil e S&P 500 CFD, gráficos serão gerados usando o software o site, um gráfico de preço EURUSD será desenhado usando somente Bull's-Eye Broker (lembre-se de limitações do StockChart).


Algoritmo para gráficos de ponto e figura

Então, aqui está o algoritmo.

Há dois parâmetros importantes no gráfico de ponto e figura:

  1. O tamanho da caixa que seja a alteração de preço de instrumento mínima; muda menor do que a alteração de preço mínimo que não afetam o gráfico;
  2. A reversão, que é o número de caixas que representam o movimento de preço no sentido contrário à direção do gráfico atual seguinte, cujo movimento será exibido na nova coluna.

Visto que gráficos requerem a história de cotas armazenados na forma de preços de abertura-alta-baixa-fechamento, supomos o seguinte:

  1. O gráfico é desenhado com base nos preços alto-baixo;
  2. O preço alto é arredondado para baixo ao tamanho da caixa (MathFloor), o preço Baixo é arredondado para cima ao tamanho da caixa (MathCeil).

Deixe-me dar um exemplo. Suponha que desejamos desenhar um gráfico Light Crude Oil com tamanho de caixa igual a $1 (um) e uma reversão de caixa 3 (três). Isto significa que todos os preços altos são arredondados para baixo ao $1 mais próximo e todos os preços baixos são arredondados para cima da mesma maneira:

Data Alto Baixo XO alto XO Baixo
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


As Xs (cruzes do jogo da velha) são usadas ​​para ilustrar um movimento de preço ascendente no gráfico, enquanto os Os (do jogo da velha) representam um movimento de preços em queda.

Como determinar a direção inicial do preço (se a primeira coluna é X ou O):

Tenha em mente valores de [Barras-1] XO Alto e XO Baixo e espere até:

  • O valor XO baixo diminui pelo número de reversão de caixas em comparação com o XO alto inicial ( a primeira coluna é О ); ou
  • O valor XO alto aumenta o número de reversão de caixas de em comparação com o XO baixo inicial (a primeira coluna é Х).

No nosso exemplo de Light Crude Oil, devemos ter em mente XO Alta[Barras-1]=100 e XO Baixa[Barras-1]=100.

Então espere para ver o que ocorre mais cedo:

  • O valor XO Baixo[i] da barra seguinte torna-se menor ou igual a $97, sugerindo que a primeira coluna seja O; ou
  • O valor XO Alto[i] da barra seguinte torna-se maior do que ou igual a $103, sugerindo que a primeira coluna seja Х.

Podemos determinar a primeira coluna em 17 de fevereiro: O preço XO High alcançou $103 e a primeira coluna é X. Faça-a ao desenhar quatro X a de $100 até $103.

Como determinar mais movimento de gráfico:

Se a coluna atual é X, verifique se XO alto da barra atual aumentou pelo tamanho da caixa, em comparação com o preço XO atual (por exemplo, em 20 de fevereiro, vamos primeiro verificar se XO alto é maior ou igual a $ 104). Se XO Alto[ 2012.02.20 ] for de $ 104, $105 ou mais, vamos adicionar o número relevante de X para a coluna existente de X.

Se o XO alto da barra atual não aumentou pelo tamanho da caixa, em comparação com o preço atual XO, verifique se o XO baixo da barra atual é menor que o XO alto pelo número de reversão de caixas (no nosso exemplo, se XO baixo[2012.02.20] for menor do que ou igual a $103-3*$1=$100, ou $99 ou menos do que isso). Se for menor, então desenhamos uma coluna de O à direita da coluna de X de $102 a $100.

No caso da coluna atual ser O, todas as considerações acima são aplicáveis ​​e vice-versa.

IMPORTANTE: Cada nova coluna de O é sempre desenhada à direita e à uma caixa mais baixa do que o valor Alto da coluna anterior de X e cada nova coluna de X é sempre desenhada à direita de e à uma caixa mais alta do que o valor Baixo da coluna anterior de O.

Os princípios de gráfico estão claros agora. Vamos continuar com linhas de suporte e resistência.

Linhas de suporte e resistência em gráficos de ponto e figura são sempre inclinados a um ângulo de 45 graus.

A primeira linha depende da primeira coluna. Se a primeira coluna é X, a primeira linha será uma linha de resistência a partir de uma caixa mais alta do que o primeiro máximo de coluna, em ângulo de 45 graus para baixo e à direita. Se a primeira coluna for O, a primeira linha será uma linha de suporte, que inicia uma caixa mais baixa do que o primeiro mínimo da coluna, em ângulo de 45 graus para cima e à direita. Linhas de suporte e resistência são desenhadas até que atinjam o gráfico de preço.

Assim como a linha de suporte/resistência atinge o gráfico de preço, começamos a desenhar uma linha de resistência/suporte, como consequência. Ao desenhar, o princípio fundamental é assegurar que a linha traçada seja mais à direita da linha de tendência no gráfico anterior. Assim, para desenhar uma linha de suporte, primeiro identificamos o valor de gráfico mínimo sob a linha de resistência que acabamos de desenhar e traçamos a linha de suporte iniciando uma caixa mais baixa do que o mínimo UP identificado à direita até que atinja o gráfico ou a última coluna do gráfico.

Se a linha de suporte desenhada a partir do mínimo abaixo da linha de resistência anterior subir e tropeçar no gráfico sob a mesma linha de resistência, mova à direita e encontre um novo preço mínimo no intervalo do menor mínimo sob a resistência no fim da linha de resistência. Continue até que a tão atraída linha de tendência vá para direita, além da linha de tendência anterior.

Todos os itens acima ficarão mais claros quando ilustrados com exemplos reais de gráfico fornecidos mais adiante.

Até agora já resolvemos o algoritmo de gráfico. Vamos adicionar alguns recursos simples ao nosso script:

  • Seleção de modo: gráficos para apenas ou para todos os símbolos atuais no MarketWatch;
  • Seleção de prazo (parece mais lógico desenhar gráficos de 100 pips em prazos diários e gráficos de 1-3 pips na M1);
  • Definição do tamanho da caixa em pips;
  • Definição do número de caixas para reversão;
  • Definição do número de caracteres para exibir volumes (no script - volumes de ticks, pois eu não encontrei corretores que forneçam volumes reais) em colunas e linhas (como o indicador MarketDepth);
  • Definição da profundidade da história com base no qual o gráfico será desenhado;
  • A seleção do formato de saída - resultados podem ser salvos como arquivos de texto ou arquivos de imagem;
  • E, por fim, um recurso para os novatos - autocharting (define automaticamente o tamanho da caixa com base na altura necessária do gráfico).

Agora que as descrições do algoritmo e os requisitos foram dados, é hora de apresentar o script.

//+------------------------------------------------------------------+
//|                                         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);
        }
     }
  }
//+------------------------------------------------------------------+

Dependendo do valor do parâmetro de entrada pic, os resultados de script serão gerados quer sob a forma de arquivos de texto com arquivos de imagem (terminal_data_directory\MQL5\Images) ou apenas arquivos de texto (salvos em terminal_data_directory\MQL5\Arquivos).


Comparação de resultados

Para comparar os resultados, vamos desenhar um gráfico Light Crude Oil com os seguintes parâmetros: tamanho da caixa é de $1, reversão é de 3 caixas.

StockCharts.com:

Fig. 1. Gráfico de ponto e figura para Light Crude Oil gerado pelo StockCharts.com

Fig. 1. Gráfico de ponto e figura para Light Crude Oil gerado pelo StockCharts.com

Bull's-Eye Broker:

Fig. 2. Gráfico de ponto e figura para Light Crude Oil gerado pelo software Bull's-Eye Broker

Fig. 2. Gráfico de ponto e figura para Light Crude Oil gerado pelo software Bull's-Eye Broker


Nossos resultados de desempenho de script:

Fig. 3. Gráfico de ponto e figura para Light Crude Oil gerado pelo nosso script

Fig. 3. Gráfico de ponto e figura para Light Crude Oil gerado pelo nosso script

Todos os três gráficos são idênticos. Parabéns! Pegamos o jeito do gráfico de ponto e figura.


Padrões de gráfico de ponto e figura típicos

Como eles podem ser usados?

Vamos primeiro dar uma olhada nos padrões típicos, especialmente como eles podem ser contados nos dedos.

Estes são:

Fig. 4. Padrões de preço: O Double Top, o Triple Top, o Double Bottom e o Triple Bottom

Fig. 4. Padrões de preço: O Double Top, o Triple Top, o Double Bottom Breakout e os Triple Bottoms

Além disso:

Fig. 5. Padrões de preço: Mercado em alta e mercado em baixa

Fig. 5. Padrões de preço: Mercado em alta e mercado em baixa

e finalmente:

Fig. 6. Padrões de preço: Catapulta de alta e catapulta de baixa

Fig. 6. Padrões de preço: Catapulta de alta e catapulta de baixa

E agora algumas dicas.

  1. Abra apenas posições longas acima da linha de suporte e as posições curtas somente sob a linha de resistência. Por exemplo, a partir de meados de dezembro de 2011, depois da quebra da linha de resistência que vem se formando desde o final de setembro de 2011, abra apenas as posições longas em Light Crude Oil futures.
  2. Use linhas de suporte e resistência para arrastar ordens de stop loss.
  3. Use contagem vertical, antes de abrir uma posição para estimar uma relação entre possível lucro e um possível prejuízo.

A contagem vertical é melhor demonstrada pelo seguinte exemplo.

Em dezembro de 2011, a coluna de X moveu-se para cima partir do preço inicial de $76 além da coluna anterior de X em $85, quebrada através da linha de resistência em $87 e alcançada em $89. De acordo com a contagem vertical, isto sugere que o preço possa subir para atingir o nível de $76+($89 - $75)*3 (3 caixa de reversão)=$118.

O próximo movimento foi corretivo, trazendo o preço ao nível de $85. Especuladores podem colocar uma ordem de stop loss em uma posição longa em menos de $1, por ex. de $84.

A entrada para a posição longa pode ser planejada após um movimento corretivo concluído de uma caixa mais alta do que a coluna anterior de X, por exemplo, no preço de $90.

Vamos estimar o possível prejuízo - pode chegar a $90 - $ 84 = $6 por um contrato de mercados futuros. Lucro possível pode alcançar $118-$90=$28. Lucro possível-possível taxa de prejuízo: $28/$6>4.5 Bom desempenho, na minha opinião. Até agora nosso lucro deveria equivaler a $105-$90=$15 por cada contrato de mercado futuro.


Licenças

O script foi escrito e fornecido sob a licença BSD pelo autor Roman Rich. O texto da licença pode ser encontrado no arquivo Lic.txt. A biblioteca cIntBMP foi criada por Dmitry, também conhecido como o número inteiro. As marcas registradas StockCharts.com e Bull's-Eye Broker são propriedades dos seus respectivos proprietários.


Conclusão

Este artigo propôs um algoritmo e um script para gráficos de ponto e figura ("Jogo da velha"). A consideração foi dada a vários padrões de preços, cujo uso prático foi destacado nas recomendações fornecidas.

Traduzido do russo pela MetaQuotes Ltd.
Artigo original: https://www.mql5.com/ru/articles/368

Arquivos anexados |
pnf.zip (659.49 KB)
cintbmp.mqh (39.68 KB)
pnf2.mq5 (27.36 KB)
lic.txt (1.35 KB)
AutoElliottWaveMaker - Ferramenta do MetaTrader 5 para análise semi-automática de Ondas de Elliott AutoElliottWaveMaker - Ferramenta do MetaTrader 5 para análise semi-automática de Ondas de Elliott
O artigo fornece uma análise de AutoElliottWaveMaker - o primeiro desenvolvimento para a análise Elliot Wave no MetaTrader 5 que representa uma combinação de rotulagem de onda manual e automática. A ferramenta de análise de onda é escrita exclusivamente no MQL5 e não inclui bibliotecas dll externas. Esta é mais uma prova de que programas sofisticados e interessantes podem (e devem) ser desenvolvidos no MQL5.
Promova seus projetos de desenvolvimento utilizando bibliotecas EX5 Promova seus projetos de desenvolvimento utilizando bibliotecas EX5
Ocultando os detalhes de implementação de classes/funções em um arquivo .ex5 vai permitir que você compartilhe seus algoritmos experientes com outros desenvolvedores, defina projetos comuns e promova-os na Internet. E enquanto a equipe MetaQuotes não mede esforços para viabilizar a possibilidade de herança direta de classes de biblioteca ex5, vamos implementá-la agora.
Como colocar um produto no Mercado Como colocar um produto no Mercado
Ofereça seus desenvolvimentos a milhões de usuários MetaTrader em todo o mundo, publique-os no Mercado. O serviço oferece uma infraestrutura pronta para realizar vendas: acesso ao público, mecanismos de licenciamento, disponibilização de versões de teste, entrega de atualizações e aceitação de pagamentos. Tudo que você precisa fazer é passar por um rápido procedimento de registro e publicação de produto. Comece a ganhar dinheiro com seus empreendimentos, enquanto o serviço tomará conta de todos os detalhes técnicos.
Código MQL5 de segurança: proteção de senha, geradores de chaves, limites de tempo, licenças remotas e técnicas de codificação de chave de licença de EA avançadas Código MQL5 de segurança: proteção de senha, geradores de chaves, limites de tempo, licenças remotas e técnicas de codificação de chave de licença de EA avançadas
A maioria dos desenvolvedores precisa ter seu código protegido. Este artigo apresentará alguns meios diferentes para proteger o software MQL5 - ele apresenta métodos para fornecer recursos de licenciamento para Scripts do MQL5, Exper Advisors e Indicadores. Ele cobre a proteção de senha, geradores de chave, licença de conta, avaliação de limite de tempo e proteção remota usando chamadas MQL5-RPC.