
L'ultima crociata
Introduzione
Ci sono tre modalità predefinite di presentazione del prezzo dello strumento disponibili nel terminale МetaТrader 5 (così come su МetaТrader 4): barre, candele e linee. Essenzialmente, tutti rappresentano gli stessi grafici temporali. Oltre al metodo tradizionale di presentazione dei prezzi in base al tempo, esistono ancora altri mezzi non legati al tempo e che sono molto popolari tra investitori e speculatori: Renko e Kagi, interruzione di tre righe e punti e cifre dei grafici.
Non voglio affermare il loro vantaggio rispetto ai classici, ma togliere di vista la variabile tempo aiuta alcuni trader a concentrarsi sulla variabile prezzo. Suggerisco di considerare qui i grafici punti e cifre insieme a un algoritmo di creazione di grafici pertinente, dare un'occhiata a prodotti di mercato ben noti che servono a generare tali grafici e scrivere uno script chiaro e semplice che implementa l'algoritmo. Un libro di Thomas J. Dorsey "Point and Figure Charting: The Essential Application for Forecasting and Tracking Market Prices" sarà il nostro libro dell’ABC.
Bull's-Eye Broker è il pacchetto software più popolare per disegnare grafici offline. Il software è disponibile per 21 giorni di prova (numerose prove possibili) e la nuova versione Beta è disponibile durante il periodo Beta. Questo pacchetto software verrà utilizzato per stimare i risultati delle prestazioni degli script. Una delle migliori risorse online in termini di grafici a punti e cifre è StockCharts. Il sito web è orientato alla borsa e quindi, sfortunatamente, non fornisce i prezzi degli strumenti Forex.
Per confrontare i risultati delle prestazioni dello script che introdurremo, i future sull'oro, i future sul petrolio greggio leggero e i grafici CFD S&P 500 verranno generati utilizzando il software e il sito Web; un grafico dei prezzi EURUSD verrà disegnato utilizzando solo Bull's-Eye Broker (ricorda le limitazioni di StockChart).
Algoritmo per grafici a punti e cifre
Quindi, ecco l'algoritmo.
Ci sono due parametri chiave nei grafici a punti e cifre:
- Dimensione della scatola che è la variazione minima del prezzo dello strumento; variazioni inferiori alla variazione di prezzo minimo non influiscono sul grafico;
- Inversione che è il numero di caselle che rappresentano il movimento del prezzo nella direzione opposta all'attuale direzione del grafico a seguito del quale tale movimento verrà visualizzato nella nuova colonna.
Poiché la creazione di grafici richiede la cronologia delle quotazioni memorizzate sotto forma di prezzi Open-High-Low-Close, assumiamo quanto segue:
- Il grafico è disegnato in base ai prezzi High-Low;
- Il prezzo alto viene arrotondato per difetto alla dimensione della scatola (MathFloor), il prezzo basso viene arrotondato per eccesso alla dimensione della scatola (MathCeil).
Faccio un esempio. Supponiamo di voler disegnare un grafico del petrolio greggio leggero con una dimensione della scatola uguale a $ 1 (uno) e un'inversione di 3 (tre) scatola. Ciò significa che tutti i prezzi High vengono arrotondati per difetto al $1 più vicino e tutti i prezzi Low vengono arrotondati allo stesso modo:
Data | High | Low | XO High | XO Basso |
---|---|---|---|---|
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 |
Le X (croci) sono utilizzate per illustrare un movimento di prezzo al rialzo sul grafico, mentre le O (zero) rappresentano un movimento di prezzo in calo.
Come determinare la direzione iniziale del prezzo (se la prima colonna è X o O):
Tieni a mente i valori XO High e XO Low [Bars-1] e attendi fino a:
- Il valore di XO Basso diminuisce del numero di caselle di inversione rispetto a XO Alto iniziale (la prima colonna è О); o
- il valore XO High aumenta del numero di caselle di inversione rispetto a XO Low iniziale (la prima colonna è Х).
Nel nostro esempio di petrolio greggio, dovremmo tenere a mente XO High[Bars-1]=100 e XO Low[Bars-1]=100.
Quindi aspetta di vedere cosa succede prima:
- Il valore XO Low[i] della barra successiva diventa minore o uguale a $97, suggerendo che la prima colonna è O; o
- il valore XO High[i] della barra successiva diventa maggiore o uguale a $ 103, suggerendo che la prima colonna è Х.
Possiamo determinare la prima colonna il 17 febbraio: XO High price ha raggiunto $ 103 e la prima colonna è X. Fallo disegnando quattro X da $ 100 a $ 103.
Come determinare un ulteriore movimento del grafico:
Se la colonna corrente è X, controlla se XO High della barra corrente è aumentato della dimensione della casella rispetto al prezzo XO corrente (cioè il 20 febbraio controlleremo prima se XO High è maggiore o uguale a $ 104). Se XO High[2012.02.20] è $ 104 o $ 105 o superiore, aggiungeremo il numero rilevante di X alla colonna esistente di X.
Se XO High della barra corrente non è aumentato della dimensione della scatola rispetto al prezzo XO corrente, controlla se XO Low della barra corrente è inferiore a XO High del numero di inversione di scatole (nel nostro esempio, se XO Low[ 2012.02.20] è inferiore o uguale a $ 103-3* $ 1 = $ 100 o $ 99 o inferiore). Se è inferiore, tracciamo una colonna di O a destra della colonna di X da $ 102 a $ 100.
Nel caso in cui la colonna corrente sia O, tutte le considerazioni di cui sopra valgono viceversa.
IMPORTANTE: ogni nuova colonna di O è sempre disegnata a destra e a una casella più bassa del valore High della precedente colonna di X e ogni nuova colonna di X è sempre disegnata a destra e a una casella più alta del valore Low della precedente colonna di O.
I principi della creazione di grafici sono ora chiari. Passiamo alle linee di supporto e resistenza.
Le linee di supporto e resistenza nei grafici a punti e cifre convenzionali sono sempre angolate a 45 gradi.
La prima riga dipende dalla prima colonna. Se la prima colonna è X, la prima linea sarà una linea di resistenza che inizia un riquadro più in alto del massimo della prima colonna, con un'angolazione di 45 gradi GI e verso destra. Se la prima colonna è O, la prima linea sarà una linea di supporto che inizia un riquadro più in basso del minimo della prima colonna, con un'angolazione di 45 gradi verso l'alto e verso destra. Le linee di supporto e resistenza vengono tracciate fino a raggiungere il grafico dei prezzi.
Non appena la linea di supporto/resistenza raggiunge il grafico dei prezzi, iniziamo a tracciare una linea di resistenza/supporto, di conseguenza. Quando si disegna, il principio chiave è assicurarsi che la linea tracciata sia più a destra della precedente linea di tendenza sul grafico. Quindi, per tracciare una linea di supporto identifichiamo prima il valore minimo del grafico sotto la linea di resistenza che abbiamo appena disegnato e tracciamo la linea di supporto iniziando una casella più in basso del minimo identificato UP a destra fino a raggiungere il grafico o l'ultima colonna di il grafico.
Se la linea di supporto tracciata partendo dal minimo sotto la precedente linea di resistenza sale e inciampa sul grafico sotto la stessa linea di resistenza, spostati a destra e trova un nuovo minimo di prezzo all'interno dell'intervallo dal minimo più basso sotto la resistenza fino alla fine della linea di resistenza. Continua finché la linea di tendenza così tracciata non va a destra, oltre la linea di tendenza precedente.
Tutto quanto sopra sarà più chiaro se illustrato con esempi di grafici reali forniti più avanti.
Ormai abbiamo già risolto l'algoritmo di creazione di grafici. Aggiungiamo alcune belle funzionalità al nostro script:
- Selezione modalità: creazione di grafici solo per un simbolo corrente o per tutti i simboli nel MarketWatch;
- Selezione dell'intervallo di tempo (sembra più logico disegnare grafici di 100 pip su intervalli di tempo giornalieri e grafici di 1-3 pip su M1);
- Impostazione della dimensione della scatola in pip;
- Impostazione del numero di caselle per l’inversione;
- Imposta il numero di caratteri per visualizzare i volumi (nello script, spunta i volumi poiché non ho incontrato broker che forniscono volumi reali) in colonne e righe (come l'indicatore MarketDepth);
- Impostazione della profondità della cronologia in base alla quale verrà disegnato il grafico;
- Selezione del formato di output: i risultati possono essere salvati come file di testo normale o file di immagine;
- E infine, una funzionalità per i principianti: l'autocharting (imposta automaticamente la dimensione della casella in base all'altezza richiesta del grafico).
Ora che sono state fornite le descrizioni dell'algoritmo e dei requisiti, è giunto il momento di presentare lo 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); } } } //+------------------------------------------------------------------+
A seconda del valore del parametro di input pic, i risultati dello script verranno generati sotto forma di file di testo con file di immagine (directory_data_terminale\MQL5\Images) o solo file di testo (salvati in directory_dati_terminale\MQL5\Files).
Risultati a confronto
Per confrontare i risultati, disegniamo un grafico del petrolio greggio leggero con i seguenti parametri: la dimensione della scatola è $ 1, l'inversione è di 3 scatole.
StockCharts.com:
Fig.1. Grafico a punti e cifre per il petrolio greggio generato da StockCharts.com
Bull's-Eye Broker:
Fig.2. Grafico a punti e cifre per il petrolio greggio generato dal software Bull's-Eye Broker
I nostri risultati delle prestazioni dello script:
Fig.3. Grafico a punti e cifre per il petrolio greggio leggero generato dal nostro script
Tutti e tre i grafici sono identici. Congratulazioni! Sappiamo come creare i grafici a punti e cifre.
Tipici modelli di grafici a punti e cifre
Come possono essere utilizzati?
Diamo prima un'occhiata agli schemi tipici, soprattutto perché si possono contare sulle dita.
Questi sono:
Fig.4. Modelli di prezzo: Il doppio massimo, il triplo massimo, il doppio minimo di breakout e il triplo minimo
per di più:
Fig.5. Modelli di prezzo: Triangolo rialzista e triangolo ribassista
e infine:
Fig.6. Modelli di prezzo: Catapulta rialzista e catapulta ribassista
E ora qualche consiglio.
- Apri solo posizioni long sopra la linea di supporto e solo posizioni corte sotto la linea di resistenza. Ad esempio, a partire dalla metà di dicembre 2011, dopo aver superato la linea di resistenza che si è formata dalla fine di settembre 2011, apri solo posizioni long sui future sul petrolio greggio leggero.
- Utilizza le linee di supporto e resistenza per gli ordini trailing stop loss.
- Utilizza il conteggio verticale prima di aprire una posizione per stimare un rapporto tra possibile profitto e possibile perdita.
Il conteggio verticale è meglio dimostrato dal seguente esempio.
Nel dicembre 2011, la colonna di X è salita dal prezzo iniziale di $ 76 oltre la precedente colonna di X a $ 85, ha superato la linea di resistenza a $ 87 e ha raggiunto $ 89. Secondo il conteggio verticale, ciò suggerisce che il prezzo potrebbe salire fino a raggiungere il livello di $ 76+ ($ 89- $ 75)*3 (inversione di 3 scatole) = $ 118.
Il movimento successivo è stato correttivo, portando il prezzo al livello di 85 dollari. Gli speculatori possono piazzare un ordine di stop loss su una posizione long a $1 in meno, ovvero a $84.
L'ingresso nella posizione long può essere pianificato dopo un movimento correttivo completato di una casella in più rispetto alla precedente colonna di X, cioè al prezzo di $90.
Stimiamo la possibile perdita - può ammontare a $90-$84=$6 per un contratto future. Il possibile profitto può raggiungere $ 118- $ 90 = $ 28. Possibile rapporto di perdita tra profitti e perdite: $28/$6>4.5 Buone prestazioni, secondo me. A questo punto il nostro profitto sarebbe stato di $ 105- $ 90 = $ 15 per ogni contratto future.
Licenze
Lo script è stato scritto e fornito con licenza BSD dall'autore Roman Rich. Il testo della licenza si trova nel file Lic.txt. La libreria cIntBMP è stata creata da Dmitry, alias Integer. I marchi StockCharts.com e Bull's-Eye Broker sono di proprietà dei rispettivi proprietari.
Conclusione
Questo articolo ha proposto un algoritmo e uno script per la creazione di grafici a punti e cifre ("naught and cross"). È stata data considerazione a vari modelli di prezzo il cui uso pratico è stato delineato nelle raccomandazioni fornite.
Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/368





- App di trading gratuite
- Oltre 8.000 segnali per il copy trading
- Notizie economiche per esplorare i mercati finanziari
Accetti la politica del sito e le condizioni d’uso