English Русский 中文 Español Deutsch 日本語 Português 한국어 Français Türkçe
Indicatore per Kagi Charting

Indicatore per Kagi Charting

MetaTrader 5Esempi | 11 gennaio 2022, 17:15
140 0
Dmitriy Zabudskiy
Dmitriy Zabudskiy

Introduzione

L'articolo "Indicatore per grafici a punti e figure" ha descritto uno dei modi di programmazione per creare grafico a punti e figure. Questo grafico è noto dal 19 ° secolo. Tuttavia, questo non è l'unico grafico antico ancora in uso. Un altro rappresentante notevole dei primi tipi di rappresentazione del mercato finanziario è grafico Kagi. Questo grafico sarà discusso nel presente articolo.

La borsa – istituzione finanziaria sconosciuta al Giappone del 19 ° secolo – è stata fondata nel maggio 1878. Al giorno d'oggi è conosciuta come Borsa di Tokyo. Questo evento ha svolto un ruolo vitale nella creazione e nel successivo sviluppo dei grafici Kagi. Europa e Stati Uniti hanno conosciuto le classifiche Kagi dopo la pubblicazione del libro di Steve Nison "Beyond Candlesticks: New Japanese Charting Techniques Revealed" nel 1994.

Le parole giapponesi "Kagi" significano una chiave a forma di L che era in uso al momento dello sviluppo del grafico. Inoltre, esiste una versione modificata del nome - "grafico chiave". In "Beyond Candlesticks" di Steve Nison, puoi anche trovare nomi alternativi del grafico: grafico della fascia di prezzo, grafico a gancio, grafico a delta o a catena.

Cosa c'è di così speciale in questo grafico? La sua caratteristica principale è che ignora la scala temporale lasciando solo quella del prezzo (a differenza delle candele, delle barre e delle linee giapponesi). Pertanto, il grafico nasconde fluttuazioni di prezzo insignificanti lasciando solo quelle più significative.

Il grafico rappresenta un insieme di linee Yang spesse e Yin sottili che si sostituiscono a vicenda a seconda della situazione del mercato. Nel caso in cui il mercato si muova nella stessa direzione, la linea viene estesa raggiungendo una nuova fascia di prezzo. Tuttavia, se il mercato torna indietro e raggiunge una quantità predefinita, la linea Kagi viene disegnata nella direzione opposta nella nuova colonna. L'importo predefinito è impostato in punti (di solito utilizzati per le coppie di valute) o in valore percentuale del prezzo corrente (solitamente utilizzato per le azioni). Lo spessore della linea varia a seconda della rottura alta o bassa più vicina.


1. Esempio di grafici

Usiamo i dati storici su EURUSD, H1 dall'8 all'11 ottobre.

Un esempio di imaging standard con una soglia inversa di 15 punti è visualizzato in Fig. 1:

Grafico Kagi, EURUSD H1

Fig. 1. Grafico Kagi, EURUSD H1

Come possiamo vedere, il prezzo ha iniziato a scendere alle 17:00. Il movimento verso il basso è continuato fino alle 21:00. Alle 22:00, il prezzo sale da 1,3566 e chiude a 1,3574. In altre parole, il prezzo supera gli 11 punti. Questo non è sufficiente per un'inversione, ma nemmeno il nuovo minimo è stato raggiunto. Nelle due ore successive il prezzo diventa piatto e infine, alle 01:00 (9 ottobre), vediamo un forte movimento al rialzo, che si chiude a 1,3591 composto da 25 punti (1,3591-1,3566). Ciò significa che il prezzo si è invertito.

La trend rialzista continua l'ora successiva. Il prezzo raggiunge 1,3599 rafforzando la spessa linea Yang. Alle 03:00, il prezzo scende bruscamente chiudendo a 1,3578, che è di 21 punti dal precedente massimo (1,3599-1,3578). Questo è più che sufficiente per l'inversione. La linea si muove verso il basso ma mantiene la sua forma (linea Yang spessa).

Fino alle 16:00, il prezzo scende e infine sfonda il minimo più vicino e cambia da Yang spesso a linea Yin sottile. Il valore basso precedentemente menzionato di 1,3566 era servito come prezzo di svolta qui. Il prezzo continua a muoversi come una linea Yin e viene cambiato in Yang alle 14:00 del 10 ottobre sfondando il massimo più vicino di 1,3524 formato alle 23:00 (9 ottobre). Questo piccolo esempio mostra come si forma il grafico Kagi.


2. Principio di creazione di grafici dell'indicatore Kagi

Al fine di rendere l'indicatore indipendente dall'intervallo di tempo corrente, è stato deciso di copiare separatamente i dati del periodo di tempo in cui l'indicatore avrebbe dovuto essere formato, e quindi creare l'indicatore utilizzando i dati ottenuti.

Ciò consente di esaminare diversi intervalli di tempo contemporaneamente su un singolo grafico espandendo i confini dell'analisi tecnica sui grafici Kagi. L'indicatore stesso si trova in una finestra separata, ma è anche possibile visualizzare i dati sul grafico principale. In altre parole, la formazione di base (aspetto standard o modificato) viene eseguita nella finestra dell'indicatore. L'indicatore viene copiato nel grafico principale, vengono disegnati anche i segni di prezzo e tempo (a seconda delle impostazioni).

Come accennato in precedenza, l'indicatore disegna il grafico sia in versione standard che modificata. Quello standard è stato descritto sopra. Ora, consideriamo la versione modificata.

Non so se sia un'idea nuova, ma non ho sentito parlare di tale versione. L'idea del filtro aggiuntivo è che ora non solo i punti inversi, ma ogni mossa del grafico viene filtrata. In altre parole, il prezzo dovrebbe spostarsi di una certa distanza specificata in modo da formare il nuovo High o Low (da non confondere con spalla / vita). Generalmente, ovunque il prezzo si muova, dovrebbe prima coprire una distanza specificata. Dopodiché, viene definito se si trattava di una continuazione della tendenza o di un'inversione.

La Fig. 2 mostra come funziona il principio. L'aspetto del grafico modificato è mostrato in blu, mentre quello standard - in rosso. Come possiamo vedere, l'aspetto modificato risponde ai cambiamenti di movimento dei prezzi più lentamente filtrando la maggior parte dei segnali minori.

Versioni standard e modificate della creazione del grafico Kagi

Fig. 2. Versioni modificate (linea blu) e standard (linea rossa) della creazione del grafico Kagi

Oltre al grafico Kagi, l'indicatore fornisce alcuni elementi aggiuntivi sia nella finestra dell'indicatore che nel grafico principale.

A seconda delle impostazioni, i segni possono essere impostati nella finestra dell'indicatore. Questi marchi forniscono dati sui prezzi di inversione. La stessa funzione viene implementata utilizzando livelli di prezzo, che (a seconda delle impostazioni) possono distribuirsi uniformemente lungo la finestra dell’intera fascia di prezzo utilizzata per formare l'indicatore o ad ogni inversione del grafico. I colori possono essere impostati in tre versioni: in base al tipo di inversione (su - giù), al tipo di linea (Yin - Yang) o nessun cambiamento di colore.

I segni di inversione dei prezzi, compresi quelli temporanei, sono forniti sul grafico principale. Questi segni (a seconda delle impostazioni) possono essere di un singolo colore o cambiare il colore in base ai colori delle linee Yin o Yang.

L'intero codice dell'indicatore viene implementato utilizzando le funzioni che comunicano tra loro attraverso variabili globali.

Il codice può essere suddiviso in tre funzioni principali e undici funzioni aggiuntive. L'onere principale dei calcoli e dei riempimenti del buffer delle costruzioni grafiche di base e degli array di buffer aggiuntivi si basa sulla funzione della formazione del grafico Kagi nella finestra dell'indicatore. Le altre due funzioni sono responsabili della fornitura dei dati: la prima copia i dati temporali, mentre l'altra - copia i dati sui prezzi di ciascuna barra dell'intervallo di tempo selezionato.

Le restanti funzioni ausiliarie sono responsabili dell'esecuzione di tutte le costruzioni, dell'eliminazione degli oggetti, dello scarico dell'indicatore accompagnato dalla cancellazione di tutti gli oggetti indicatore, del calcolo dei parametri di inversione, del disegno dei segni sul grafico principale. Sulla finestra dell'indicatore, eseguono la creazione di oggetti grafici di tipo "Linea di tendenza", del disegno di Kagi sul grafico principale e della definizione dell'arrivo della nuova barra per avviare la formazione dell'indicatore.


3. Codice indicatore e algoritmo

Ora, esaminiamo il codice dell'indicatore e l'algoritmo della sua formazione in dettaglio. Il codice è abbastanza grande e per i programmatori alle prime armi potrebbe essere abbastanza difficile da capire. Le funzioni che comunicano tra loro tramite le variabili globali rendono il codice piuttosto confuso. In questa parte dell'articolo, spiegherò separatamente ogni funzione e parte del codice. In primo luogo, descriverò le impostazioni dell'indicatore e poi ci saranno chiarimenti riguardanti le funzioni iniziali di copia dei dati, il calcolo dei parametri di inversione, la funzione principale della formazione e del calcolo del grafico Kagi e altre funzioni ausiliarie.

3.1. Parametri di input dell'indicatore

Il codice inizia con la dichiarazione dell'indicatore in una finestra separata, nonché di 12 buffer e 8 indicatori di costruzioni grafiche. Prima di tutto, definiamo perché sono state utilizzate 8 costruzioni grafiche, tra cui due "istogrammi" e sei "linee". Ogni "istogramma" costruisce la propria linea verticale. Una delle linee è responsabile della linea Yin, mentre l'altra è della linea Yang.

Il caso è un po 'più complicato con le "linee", in quanto ce ne sono tre per ogni linea. Ciò viene fatto perché la linea viene tracciata se c'è un altro punto che viene disegnato vicino al primo. In altre parole, abbiamo bisogno solo di due costruzioni grafiche di tipo "linea" da ruotare per disegnare due linee adiacenti l'una all'altra. Tuttavia, se abbiamo bisogno di queste linee per saltare i punti necessari, abbiamo bisogno che la terza costruzione sia ruotata con altre due.

Questo è spiegato nella Figura 3, dove è possibile vedere cosa succede se vengono utilizzate solo due costruzioni grafiche di tipo "linea":


 Fig. 3. Esempio di utilizzo di due e tre costruzioni grafiche di tipo "linea" per visualizzare le linee di spalla e vita

Quindi, viene creato il menu delle impostazioni. Ci sono cinque enumerazioni qui (esaminiamole nei parametri di input).

Il primo parametro di input "periodo" è un periodo in cui viene eseguita la costruzione, è seguito da "period_to_redraw" - periodo di aggiornamento della costruzione del grafico e l'ultimo parametro temporale è "start_data" - il tempo da cui inizia la costruzione.

Questi parametri sono seguiti dalla costruzione del grafico e da quelli di etichettatura aggiuntivi:

  • kagi_type – tipo di costruzione del grafico definito dall'utente, standard o modificato;
  • price_type – tipo di prezzo utilizzato per la costruzione: Chiudi, Apri, Alto e Basso;
  • type_doorstep – tipo di inversione utilizzato: punto e percentuale;
  • doorstep – valore di inversione (specificato in punti o valore percentuale a seconda del parametro di cui sopra);
  • color_yin – Colore della linea Yin nella finestra dell'indicatore;
  • color_yang - Colore della linea Yang nella finestra dell'indicatore;
  • width_yin – Larghezza della linea Yin nella finestra dell'indicatore;
  • width_yang – Larghezza della linea Yang nella finestra dell'indicatore;
  • levels_on_off – indica se i livelli dei prezzi devono essere disegnati nella finestra dell'indicatore;
  • levels_type – tipi di livelli di prezzo nella finestra dell'indicatore. Ci sono due valori tra cui scegliere: ad ogni inversione o uniformemente in tutta la fascia di prezzo;
  • levels_number – numero di livelli di prezzo nella finestra dell'indicatore;
  • levels_change_color – consente di cambiare il colore delle linee del livello dei prezzi; le opzioni sono inversioni superiore e inferiore, linee Yin e Yang o nessun cambiamento;
  • levels_first_color – il primo colore di un livello di prezzo;
  • levels_second_color – il secondo colore di un livello di prezzo;
  • label_1 – disegnare etichette di prezzo di inversione del grafico nella finestra dell'indicatore;
  • label_1_number – numero di etichette visualizzate nella finestra dell'indicatore;
  • label_1_color – colore delle etichette dei prezzi nella finestra dell'indicatore;
  • label_2 – disegnare etichette dei prezzi sul grafico principale;
  • label_2_color – colore dell'etichetta sul grafico principale;
  • time_line_draw – disegnare linee temporali di inversione sul grafico principale;
  • time_separate_windows – disegnare la continuazione delle linee temporali di inversione dal grafico principale;
  • time_line_change_color – cambia il colore della linea del tempo a seconda dell'etichetta di inversione sulla linea Yin o Yang;
  • time_first_color – il primo colore della linea del tempo sul grafico principale;
  • time_second_color – il secondo colore della linea del tempo sul grafico principale;
  • kagi_main_chart – se Kagi debba essere disegnato sul grafico principale;
  • color_yin_main - Colore della linea Yin sul grafico principale;
  • color_yang_main - Colore della linea Yang sul grafico principale;
  • width_yin_main – Larghezza della linea Yin sul grafico principale;
  • width_yang_main – Larghezza della linea Yang sul grafico principale;
  • magic_numb - numero magico utilizzato per costruire oggetti e cancellarli, nonché utilizzato nel nome dell'indicatore per lanciare diversi indicatori su un singolo grafico.

Questi parametri sono a loro volta seguiti da dichiarazioni dei buffer degli indicatori, buffer ausiliari per la memorizzazione dei valori di prezzo e temporali, variabili ausiliarie (stop_data, bars_copied, bars_copied_time, copy_history, copy_time), array per la memorizzazione di dati su quale linea Yin o Yang si è verificata la variazione del movimento del grafico, l'ora e il prezzo di tale modifica, prezzo centrale (se Yin è sostituito da Yang sulla barra o viceversa). Infine, viene dichiarata una delle variabili globali più utilizzate contenente dati sul numero di cambiamenti di movimento del grafico "а".

//+------------------------------------------------------------------+
//|                                                         BKCV.mq5 |
//|                                   Azotskiy Aktiniy ICQ:695710750 |
//|                          https://www.mql5.com/ru/users/Aktiniy |
//+------------------------------------------------------------------+
//--- Build Kagi Chart Variable
#property copyright "Azotskiy Aktiniy ICQ:695710750"
#property link      "https://www.mql5.com/en/users/Aktiniy"
#property version   "1.00"
#property description "Build Kagi Chart Variable"
#property description " "
#property description "This indicator makes drawing a chart Kagi as a matter of indicator window, and in the main chart window"
#property indicator_separate_window
#property indicator_buffers 12
#property indicator_plots   8
//--- plot Yin
#property indicator_label1  "Yin"
#property indicator_type1   DRAW_HISTOGRAM2
#property indicator_color1  clrRed
#property indicator_style1  STYLE_SOLID
#property indicator_width1  1
//--- plot Yin1
#property indicator_label2  "Yin1"
#property indicator_type2   DRAW_LINE
#property indicator_color2  clrRed
#property indicator_style2  STYLE_SOLID
#property indicator_width2  1
//--- plot Yin2
#property indicator_label3  "Yin2"
#property indicator_type3   DRAW_LINE
#property indicator_color3  clrRed
#property indicator_style3  STYLE_SOLID
#property indicator_width3  1
//--- plot Yin3
#property indicator_label4  "Yin3"
#property indicator_type4   DRAW_LINE
#property indicator_color4  clrRed
#property indicator_style4  STYLE_SOLID
#property indicator_width4  1
//--- plot Yang
#property indicator_label5  "Yang"
#property indicator_type5   DRAW_HISTOGRAM2
#property indicator_color5  clrRed
#property indicator_style5  STYLE_SOLID
#property indicator_width5  2
//--- plot Yang1
#property indicator_label6  "Yang1"
#property indicator_type6   DRAW_LINE
#property indicator_color6  clrRed
#property indicator_style6  STYLE_SOLID
#property indicator_width6  2
//--- plot Yang2
#property indicator_label7  "Yang2"
#property indicator_type7   DRAW_LINE
#property indicator_color7  clrRed
#property indicator_style7  STYLE_SOLID
#property indicator_width7  2
//--- plot Yang3
#property indicator_label8  "Yang3"
#property indicator_type8   DRAW_LINE
#property indicator_color8  clrRed
#property indicator_style8  STYLE_SOLID
#property indicator_width8  2
//--- Enumerations as input data (for more attractive setting)
//--- Kagi charting type
enum kagi_type_enum
  {
   classic=0,  // Classic
   modified=1, // Modified
  };
//--- Type of the price used for construction
enum price_type_enum
  {
   c=0, // Close
   o=1, // Open
   h=2, // High
   l=3, // Low
  };
//--- Type of the used reversal
enum type_doorstep_enum
  {
   point=0,   // Point
   procent=1, // Percent
  };
//--- Type of levels location
enum levels_type_enum
  {
   cor=0, // Cornering
   equ=1, // Equal distance
  };
//--- Level colors change type (works when "Type of levels location"="Cornering")
enum levels_change_color_enum
  {
   up_down=0,  // Up & Down
   yin_yang=1, // Yin & Yang
   no=2,       // Don't change
  };
//--- input parameters
input ENUM_TIMEFRAMES period=PERIOD_CURRENT;                // Calculation period to build the chart
input ENUM_TIMEFRAMES period_to_redraw=PERIOD_M1;           // Refresh period chart
input datetime start_data=D'2013.07.10 00:00:00';           // Start time to build the chart
input kagi_type_enum kagi_type=classic;                     // The type to build Kagi chart
input price_type_enum price_type=c;                         // Price used to build chart
input type_doorstep_enum type_doorstep=point;               // Type calculate doorstep
input double   doorstep=25;                                 // Doorstep reversal
input color    color_yin=clrRed;                            // Color Yin line (indicator window)
input color    color_yang=clrRed;                           // Color Yang line (indicator window)
input char     width_yin=1;                                 // Width Yin line (indicator window)
input char     width_yang=2;                                // Width Yang line (indicator window)
input bool     levels_on_off=false;                         // Draw level (indicator window)
input levels_type_enum levels_type=cor;                     // Type of drawing levels (indicator window)
input uint     levels_number=6;                             // Number of levels  (indicator window)
input levels_change_color_enum levels_change_color=up_down; // Type change color of levels (indicator window)
input color    levels_first_color=clrBeige;                 // The first color of level (indicator window)
input color    levels_second_color=clrCoral;                // The second color of level (indicator window)
input bool     label_1=true;                                // Draw price label on (indicator window)
input uint     label_1_number=10;                           // The number of labels (indicator window)
input color    label_1_color=clrGreenYellow;                // The color of labels (indicator window)
input bool     label_2=true;                                // Draw price label on (main chart)
input color    label_2_color=clrGreenYellow;                // The color of labels (main chart)
input bool     time_line_draw=true;                         // Draw a timeline reversal (main chart)
input bool     time_separate_windows=false;                 // Draw a timeline reversal on indicator window
input bool     time_line_change_color=true;                 // Different color timeline on the Yin and Yang lines (main chart)
input color    time_first_color=clrRed;                     // The first color of timeline (main chart)
input color    time_second_color=clrGreenYellow;            // The second color of timeline (main chart)
input bool     kagi_main_chart=true;                        // Draw Kagi on main chart (main chart)
input color    color_yin_main=clrRed;                       // Color Yin line (main chart)
input color    color_yang_main=clrRed;                      // Color Yang line (main chart)
input char     width_yin_main=1;                            // Width Yin line (main chart)
input char     width_yang_main=2;                           // Width Yang line (main chart)
input long     magic_numb=65758473787389;                   // The magic number for drawing objects
//--- indicator buffers
double         YinBuffer1[];
double         YinBuffer2[];
double         Yin1Buffer[];
double         Yin2Buffer[];
double         Yin3Buffer[];
double         YangBuffer1[];
double         YangBuffer2[];
double         Yang1Buffer[];
double         Yang2Buffer[];
double         Yang3Buffer[];
//--- additional variables
double Price[]; // Buffer for storing the copied price data
double Time[];  // Buffer for storing the copied time data
//---
datetime stop_data;      // Current time
int bars_copied=0;       // Number of the already copied bars from the initial date
int bars_copied_time;    // Number of the already copied bars having the initial date
bool copy_history=false; // Price history copying result
bool copy_time=false;    // Time history copying result
//---
datetime time_change[];      // Array for writing the time when the chart movement started changing (up or down)
char time_line[];            // Array for storing the data on what line (Yin=0 or Yang=1) direction has changed
double time_change_price[];  // Array for writing the chart movement change price
double time_central_price[]; // Array for writing the average price during the chart movement change

uint a=0; // Variable for building the chart, number of chart reversals is fixed
 

3.2. Funzione di inizializzazione dell’Indicatore

Il prossimo è la funzione di inizializzazione dell'indicatore. I buffer degli indicatori e la loro indicizzazione (principalmente come serie temporali; poiché il grafico Kagi è più corto di quello principale, è meglio disegnarlo all'indietro) sono specificati lì. Inoltre, vengono impostati i valori che non devono essere visualizzati sullo schermo (EMPTY_VALUE = -1).

Ora assegniamo il nome dell'indicatore e la precisione del display. Come accennato in precedenza, il numero magico viene aggiunto al nome. Questo viene fatto per fornire il corretto funzionamento della funzione ChartWindowFind(). In caso contrario, l'oggetto grafico disegnato nella finestra dell'indicatore viene visualizzato solo dopo il lancio del primo indicatore (se vengono utilizzati più indicatori su un singolo grafico).

Successivamente, assegniamo nomi alle linee di costruzione, vietiamo la visualizzazione dei valori numerici correnti nella finestra dell'indicatore, impostiamo il colore e la larghezza delle linee Yin e Yang, e impostiamo il numero dei livelli di prezzo visualizzati nella finestra dell'indicatore.

//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
//--- indicator buffers mapping
   SetIndexBuffer(0,YinBuffer1,INDICATOR_DATA);
   ArraySetAsSeries(YinBuffer1,true);
   SetIndexBuffer(1,YinBuffer2,INDICATOR_DATA);
   ArraySetAsSeries(YinBuffer2,true);
   SetIndexBuffer(2,Yin1Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yin1Buffer,true);
   SetIndexBuffer(3,Yin2Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yin2Buffer,true);
   SetIndexBuffer(4,Yin3Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yin3Buffer,true);
//---
   SetIndexBuffer(5,YangBuffer1,INDICATOR_DATA);
   ArraySetAsSeries(YangBuffer1,true);
   SetIndexBuffer(6,YangBuffer2,INDICATOR_DATA);
   ArraySetAsSeries(YangBuffer2,true);
   SetIndexBuffer(7,Yang1Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yang1Buffer,true);
   SetIndexBuffer(8,Yang2Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yang2Buffer,true);
   SetIndexBuffer(9,Yang3Buffer,INDICATOR_DATA);
   ArraySetAsSeries(Yang3Buffer,true);
//--- add the buffer for copying data on prices for calculation
   SetIndexBuffer(10,Price,INDICATOR_CALCULATIONS);
//--- add the buffer for copying data on bar open time for construction
   SetIndexBuffer(11,Time,INDICATOR_CALCULATIONS);

//--- set what values are not to be drawn
   for(char x=0; x<8; x++)
     {
      PlotIndexSetDouble(x,PLOT_EMPTY_VALUE,-1);
     }
//--- set the indicator's look
   IndicatorSetString(INDICATOR_SHORTNAME,"BKCV "+IntegerToString(magic_numb)); // Indicator name
   IndicatorSetInteger(INDICATOR_DIGITS,_Digits); // Display accuracy
//--- assign names to graphical constructions
   PlotIndexSetString(0,PLOT_LABEL,"Yin");
   PlotIndexSetString(1,PLOT_LABEL,"Yin");
   PlotIndexSetString(2,PLOT_LABEL,"Yin");
   PlotIndexSetString(3,PLOT_LABEL,"Yin");
   PlotIndexSetString(4,PLOT_LABEL,"Yang");
   PlotIndexSetString(5,PLOT_LABEL,"Yang");
   PlotIndexSetString(6,PLOT_LABEL,"Yang");
   PlotIndexSetString(7,PLOT_LABEL,"Yang");
//--- prohibit display of the results of the current values for graphical constructions
   PlotIndexSetInteger(0,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(1,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(2,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(3,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(4,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(5,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(6,PLOT_SHOW_DATA,false);
   PlotIndexSetInteger(7,PLOT_SHOW_DATA,false);
//--- set color for Yin line
   PlotIndexSetInteger(0,PLOT_LINE_COLOR,color_yin);
   PlotIndexSetInteger(1,PLOT_LINE_COLOR,color_yin);
   PlotIndexSetInteger(2,PLOT_LINE_COLOR,color_yin);
   PlotIndexSetInteger(3,PLOT_LINE_COLOR,color_yin);
//--- set color for Yang line
   PlotIndexSetInteger(4,PLOT_LINE_COLOR,color_yang);
   PlotIndexSetInteger(5,PLOT_LINE_COLOR,color_yang);
   PlotIndexSetInteger(6,PLOT_LINE_COLOR,color_yang);
   PlotIndexSetInteger(7,PLOT_LINE_COLOR,color_yang);
//--- set Yin line width
   PlotIndexSetInteger(0,PLOT_LINE_WIDTH,width_yin);
   PlotIndexSetInteger(1,PLOT_LINE_WIDTH,width_yin);
   PlotIndexSetInteger(2,PLOT_LINE_WIDTH,width_yin);
   PlotIndexSetInteger(3,PLOT_LINE_WIDTH,width_yin);
//--- set Yang line width
   PlotIndexSetInteger(4,PLOT_LINE_WIDTH,width_yang);
   PlotIndexSetInteger(5,PLOT_LINE_WIDTH,width_yang);
   PlotIndexSetInteger(6,PLOT_LINE_WIDTH,width_yang);
   PlotIndexSetInteger(7,PLOT_LINE_WIDTH,width_yang);
//--- set the number of levels in the indicator window
   IndicatorSetInteger(INDICATOR_LEVELS,levels_number);
//---
   return(INIT_SUCCEEDED);
  }


3.3. Funzione di copia dei dati

Ora, esaminiamo le funzioni di copia dei dati.

Ce ne sono due qui. Il primo è per copiare i prezzi, mentre il secondo è per copiare l'orario di apertura di ogni barra. Entrambe le funzioni mantengono i loro valori nei buffer di calcolo dell'indicatore precedentemente dichiarato.

Prima di tutto, consideriamo la funzione di copia dei prezzi. Parametri di input della funzione: array per la memorizzazione dei dati, copia dei dati ora di inizio e fine (ora corrente). Il corpo della funzione contiene le variabili per rispondere alla funzione, il numero di dati (barre) copiati nell'array intermedio, l'array dinamico intermedio stesso e il numero di barre che devono essere copiate nell'array intermedio. Il numero di barre viene calcolato in base al numero totale di barre nel periodo di tempo specificato e al numero di barre (variabile globale) copiate alla chiamata di funzione precedente.

Se non è la prima volta che i dati vengono copiati, i dati sull'ultima barra copiata devono essere aggiornati. A tale scopo, riduciamo il numero di barre copiate di una e aumentiamo di una il numero di barre appena copiate. Cambiamo anche la dimensione dell'array intermedio preparandolo per copiare le barre.

A seconda delle impostazioni, copiamo i prezzi nell'array intermedio. Se la copia ha esito positivo, i dati vengono copiati dalla matrice intermedia alla fine dell'array buffer (matrice di risposta della funzione). Assegna quindi la risposta positiva alla funzione e aggiorna la variabile globale che memorizza i dati sul numero di barre copiate. Questo tipo di copia consente di copiare solo alcune ultime barre riducendo il tempo di copia.

//+------------------------------------------------------------------+
//| Func Copy History                                                |
//+------------------------------------------------------------------+
bool func_copy_history(double &result_array[],
                       datetime data_start,
                       datetime data_stop)
  {
//---
   int x=false; // Variable for answer

   int result_copy=-1; // Number of copied data

   static double price_interim[]; // Temporary dynamic array for storing copied data
   static int bars_to_copy;       // Number of bars for copying

   bars_to_copy=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval
   bars_to_copy-=bars_copied; // Calculate the number of bars to be copied

   if(bars_copied!=0) // If it is not the first time the data has been copied
     {
      bars_copied--;
      bars_to_copy++;
     }

   ArrayResize(price_interim,bars_to_copy); // Change the size of the receiving array

   switch(price_type)
     {
      case 0:
         result_copy=CopyClose(_Symbol,period,0,bars_to_copy,price_interim);
         break;
      case 1:
         result_copy=CopyOpen(_Symbol,period,0,bars_to_copy,price_interim);
         break;
      case 2:
         result_copy=CopyHigh(_Symbol,period,0,bars_to_copy,price_interim);
         break;
      case 3:
         result_copy=CopyLow(_Symbol,period,0,bars_to_copy,price_interim);
         break;
     }

   if(result_copy!=-1) // If copying to the intermediate array is successful
     {
      ArrayCopy(result_array,price_interim,bars_copied,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one
      x=true; // assign the positive answer to the function
      bars_copied+=result_copy; // Increase the value of the processed data
     }
//---
   return(x);
  }

La funzione successiva è quella per copiare i dati temporali. È diverso dal precedente in quanto si occupa di un altro tipo di variabile - datetime (che viene convertito in doppio quando copiato in Time buffer array - function answer array). Un'altra differenza è che l'istruzione switch() non viene utilizzata, in quanto non è necessario selezionare i dati copiati.

//+------------------------------------------------------------------+
//| Func Copy Time                                                   |
//+------------------------------------------------------------------+
bool func_copy_time(double &result_array[],
                    datetime data_start,
                    datetime data_stop)
  {
//---
   int x=false; // Variable for answer
   int result_copy=-1; // Number of copied data

   static datetime time_interim[]; // Temporary dynamic array for storing copied data
   static int bars_to_copy_time; // Number of bars for copying

   bars_to_copy_time=Bars(_Symbol,period,data_start,data_stop); // Find out the current number of bars on the time interval
   bars_to_copy_time-=bars_copied_time; // Calculate the number of bars to be copied

   if(bars_copied_time!=0) // If it is not the first time the data has been copied
     {
      bars_copied_time--;
      bars_to_copy_time++;
     }
   ArrayResize(time_interim,bars_to_copy_time); // Change the size of the receiving array
   result_copy=CopyTime(_Symbol,period,0,bars_to_copy_time,time_interim);

   if(result_copy!=-1) // If copying to the intermediate array is successful
     {
      ArrayCopy(result_array,time_interim,bars_copied_time,0,WHOLE_ARRAY); // Copy the data from the temporary array to the main one
      x=true; // assign the positive answer to the function
      bars_copied_time+=result_copy; // Increase the value of the processed data
     }
//---
   return(x);
  }

3.4. Funzione di calcolo del parametro di inversione

Poiché il parametro di inversione può essere un punto o una percentuale, abbiamo bisogno della funzione che calcolerà il parametro di inversione in base alle impostazioni dell'indicatore. La funzione ha un solo parametro: il prezzo per il calcolo dell'inversione percentuale. La variabile per la risposta viene prima inizializzata per tipo doppio e dopo i calcoli, viene indirettamente convertita in tipo int per la risposta.

Questo viene fatto perché i numeri in virgola mobile vengono utilizzati nei calcoli, mentre la risposta dovrebbe essere presentata sotto forma di numeri interi. La selezione viene implementata nella funzione dall'istruzione condizionale if-else. Il confronto viene eseguito direttamente con variabile di input esterna (parametri indicatore). Il calcolo dei punti viene eseguito utilizzando una semplice equazione. Innanzitutto, viene definito il numero totale di punti che il prezzo ha superato. Quindi, la percentuale specificata viene calcolata in base a questo numero e assegnata alla variabile restituita.

//+------------------------------------------------------------------+
//| Func Calculate Doorstep                                          |
//+------------------------------------------------------------------+
int func_calc_dorstep(double price)
  {
   double x=0; // Variable for answer
   if(type_doorstep==0) // If the calculation is to be performed in points
     {
      x=doorstep;
     }
   if(type_doorstep==1) // If the calculation is to be performed in percentage
     {
      x=price/_Point*doorstep/100;
     }
   return((int)x);
  }

3.5. La funzione principale - Disegnare il grafico Kagi

Abbiamo già esaminato tutte le funzioni necessarie per il funzionamento della funzione principale: disegnare il grafico Kagi nella finestra dell'indicatore (cioè riempire i buffer dell'indicatore). I parametri di input della funzione sono costituiti da array di dati. Due di questi sono i buffer di calcolo sopra descritti (Prezzo e Tempo precedentemente copiati), tutti gli altri sono gli array dei buffer di costruzione grafici dell'indicatore.

Le variabili necessarie per memorizzare i dati sulla costruzione del grafico sono dichiarate all'interno della funzione. Poiché il grafico è costruito utilizzando l'istruzione for loop, dovremmo avere i dati sulla fase in cui è terminato il passaggio precedente. Ciò può essere ottenuto da sei variabili: line_move - dove il prezzo si è mosso al passaggio precedente, line_gauge - calibro di linea (larghezza della linea) - Yin o Yang, price_1 e price_2 - prezzo precedente e corrente considerato, price_down e price_up - prezzo precedente di una spalla e vita. Come possiamo vedere, price_1 viene immediatamente equiparato al primo elemento della matrice di prezzi copiati a causa del fatto che questa variabile fin dall'inizio del ciclo è coinvolta nei calcoli prima del confronto.

Poiché le matrici di buffer della costruzione grafica dell'indicatore hanno AS_SERIES flag di indicizzazione, devono essere compilate in ordine inverso. Per raggiungere questo obiettivo, vengono implementati array temporali dalle dimensioni appropriate. Le variabili globali per la memorizzazione dei dati su tempo, tipi di linea, "spalla" e "vita", nonché i prezzi di inversione vengono quindi convertiti allo stesso modo.

Quindi, tutte le matrici devono essere riempite con valori "vuoti" (-1). Questo viene fatto usando due piccoli loop. È possibile unire tutto in un unico ciclo. Ma l'uso di due di questi rende tutte le azioni eseguite molto più chiare, e il tempo di esecuzione non cambia di molto. In altre parole, i buffer grafici e gli array di tempo di calcolo vengono compilati separatamente.

Ora, tutte le variabili vengono dichiarate, convertite e riempite, in modo che il ciclo principale possa essere avviato. È piuttosto grande (anche se il calcolo viene eseguito abbastanza velocemente) e include la scansione di tutte le barre precedentemente copiate.

Il ciclo passa attraverso tutte le barre copiate e riempie le matrici precedentemente dichiarate necessarie per lavorare ulteriormente con esse. Prima di tutto, definiamo tutti gli array utilizzati nel ciclo:

  • yin_int_1 - valore primario del prezzo verticale della linea Yin (se la linea Yin verticale viene disegnata e il grafico si muove verso il basso, questo è il valore superiore del prezzo; se il grafico si muove verso l'alto, abbiamo il caso opposto);
  • yin_int_2 - valore secondario del prezzo della linea Yin verticale (se la linea verso l'alto è disegnata, questo è il valore superiore; se la linea è verso il basso, abbiamo il caso opposto);
  • yang_int_1 - valore primario del prezzo verticale della linea Yang;
  • yang_int_2 - valore secondario del prezzo verticale della linea Yang;
  • lin_yin - valore orizzontale della linea Yin (prezzo di inversione alla linea Yin);
  • lin_yang - valore orizzontale della linea Yang (prezzo di inversione alla linea Yang);
  • time_change - tempo dell'inversione del grafico (costruzione di una spalla o di una vita);
  • time_line - la linea durante l'inversione Yin = 0 o Yang = 1;
  • time_central_price - il valore del prezzo centrale, il prezzo nel momento in cui la linea Yin si trasforma in Yang o viceversa;
  • time_change_price - il valore del prezzo di inversione (spalla o vita), la variabile è comune e non dipende dai tipi di linea Yin o Yang.

Il valore del prezzo analizzato corrente dal buffer di prezzo viene assegnato a price_2 variabile prima di ogni passaggio di loop per un ulteriore confronto nelle istruzioni condizionali if-else. Successivamente, l'array di buffer dei dati copiati viene analizzato passo dopo passo e gli array sopra menzionati vengono riempiti. Ogni istruzione condizionale if-else esegue determinate azioni a seconda delle condizioni: direzione precedente delle linee del grafico (su o giù) e aspetto precedente delle linee (Yin o Yang). Quindi le condizioni di movimento (se il prezzo ha superato un certo numero di punti) vengono controllate a seconda del tipo di costruzione (standard o modificato).

Se tutto va bene, le nuove variabili (elementi di matrice) vengono riassegnati o definiti. Il tipo di linea (Yin o Yang) è definito all'inizio. A seconda del movimento e delle azioni precedenti, viene eseguita l'ulteriore distribuzione.

Ci sono due possibili movimenti di prezzo:

  1. Il prezzo sale;
  2. Il prezzo si muove verso il basso.

Ci sono anche quattro tipi di azioni precedenti in ogni direzione:

  1. La linea precedente era Yin e si è spostata verso l'alto;
  2. La linea precedente era Yang e si è spostata verso l'alto;
  3. La linea precedente era Yin e si spostò verso il basso;
  4. La linea precedente era Yang e si è spostata verso il basso.

Quindi, abbiamo otto casi oltre alle prime due definizioni del movimento iniziale del grafico (aspetto della prima riga).

Dopodiché, il ciclo principale è finito. La riassegnazione (inversione) e il riempimento dei buffer vengono eseguiti per costruire il grafico in un ciclo più piccolo costituito dal numero di inversioni del grafico Kagi precedentemente definite nel ciclo principale e scritte nella variabile "a". Per quanto riguarda la distribuzione dei valori di prezzo superiori e inferiori e delle linee verticali, è tutto abbastanza semplice: viene eseguita una semplice inversione. In altre parole, i valori primari ottenuti in precedenza (matrici con indici 0,1,2,3...) vengono assegnati ai valori finali dei buffer (elemento con indice "а", cioè а,а-1,а-2,а-3... viene utilizzato come valore finale). Per evitare che le linee di inversione (orizzontali) si attacchino insieme, la rotazione tramite l'istruzione switch viene eseguita come menzionato sopra.

A ciò, il lavoro della funzione principale della costruzione del grafico Kagi è completo.

//+------------------------------------------------------------------+
//| Func Draw Kagi                                                   |
//+------------------------------------------------------------------+
void func_draw_kagi(double &array_input[],
                    double &arr_yin_1[],
                    double &arr_yin_2[],
                    double &arr_yin_lin1[],
                    double &arr_yin_lin2[],
                    double &arr_yin_lin3[],
                    double &arr_yang_1[],
                    double &arr_yang_2[],
                    double &arr_yang_lin1[],
                    double &arr_yang_lin2[],
                    double &arr_yang_lin3[],
                    double &arr_time[])
  {
//---
   a=0; // Variable for the chart construction fixing the number of chart reversals
   char line_move=0; // Previous price direction 1-up, -1-down
   char line_gauge=0; // Previous look of the line 1-thick yang, -1-thin yin
   double price_1=0,price_2=0; // Auxiliary variables for defining the price movement
   double price_down=-99999,price_up=99999; // Auxiliary variables for storing the reversal price values
   price_1=array_input[0];
//--- auxiliary arrays for the initial data storing before the reversal (transferring to the buffers)
   double yin_int_1[];
   double yin_int_2[];
   double lin_yin[];
   double yang_int_1[];
   double yang_int_2[];
   double lin_yang[];
//--- change the sizes of dynamic arrays
   ArrayResize(yin_int_1,bars_copied);
   ArrayResize(yin_int_2,bars_copied);
   ArrayResize(yang_int_1,bars_copied);
   ArrayResize(yang_int_2,bars_copied);
   ArrayResize(lin_yin,bars_copied);
   ArrayResize(lin_yang,bars_copied);
//--- time data storing arrays
   ArrayResize(time_change,bars_copied_time);
   ArrayResize(time_line,bars_copied_time); // Look of the line Yin = 0 or Yang = 1
   ArrayResize(time_change_price,bars_copied_time);
   ArrayResize(time_central_price,bars_copied_time);
//--- assign -1 (not displayed) value to the transferred buffers
   for(int z=0; z<bars_copied; z++)
     {
      arr_yin_1[z]=-1;
      arr_yin_2[z]=-1;
      arr_yin_lin1[z]=-1;
      arr_yin_lin2[z]=-1;
      arr_yin_lin3[z]=-1;
      arr_yang_1[z]=-1;
      arr_yang_2[z]=-1;
      arr_yang_lin1[z]=-1;
      arr_yang_lin2[z]=-1;
      arr_yang_lin3[z]=-1;
     }
//--- equate -1 (not displayed) value to the arrays
   for(int z=0; z<bars_copied; z++)
     {
      yin_int_1[z]=-1;
      yin_int_2[z]=-1;
      lin_yin[z]=-1;
      yang_int_1[z]=-1;
      yang_int_2[z]=-1;
      lin_yang[z]=-1;
      time_change[z]=-1;
      time_line[z]=-1;
      time_change_price[z]=-1;
      time_central_price[z]=-1;
     }
//--- function's main loop
   for(int z=0; z<bars_copied; z++)
     {
      price_2=array_input[z];
      //--- first, let's define the initial market direction
      //--- first THIN DESCENDING line
      if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) && line_move==0)
        {
         yin_int_1[a]=price_1;
         yin_int_2[a]=price_2;

         line_move=-1;
         line_gauge=-1;

         price_1=price_2;

         time_change[a]=(datetime)arr_time[z];
         time_line[a]=0;
        }
      //--- first THICK ASCENDING line
      if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) && line_move==0)
        {
         yang_int_1[a]=price_1;
         yang_int_2[a]=price_2;

         line_move=1;
         line_gauge=1;

         price_1=price_2;

         time_change[a]=(datetime)arr_time[z];
         time_line[a]=1;
        }
      //--- price moves DOWN
      //--- if the price moved DOWN before that, the line is THIN
      if(line_move==-1 && line_gauge==-1)
        {
         if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0))
           {
            yin_int_2[a]=price_2;

            line_move=-1;
            line_gauge=-1;

            price_1=price_2;

            time_change[a]=(datetime)arr_time[z];
            time_line[a]=0;
           }
        }
      //--- if the price moved DOWN before that, the line is THICK
      if(line_move==-1 && line_gauge==1)
        {
         if(((price_1-price_2)/_Point>func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point>0))
           {
            if(price_2<price_down) // If the thick line crossed the lower shoulder when moving downwards
              {
               yin_int_1[a]=price_down;
               yin_int_2[a]=price_2;

               yang_int_2[a]=price_down;

               line_move=-1;
               line_gauge=-1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_central_price[a]=price_down;
               time_line[a]=0;
              }
            else //if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards
              {
               yang_int_2[a]=price_2;

               line_move=-1;
               line_gauge=1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=1;
              }
           }
        }
      //--- if the price has moved UPWARDS before that, the line is THIN
      if(line_move==1 && line_gauge==-1)
        {
         if((price_1-price_2)/_Point>func_calc_dorstep(price_2))
           {
            a++;
            yin_int_1[a]=price_1;
            yin_int_2[a]=price_2;

            lin_yin[a]=price_1;

            line_move=-1;
            line_gauge=-1;

            price_up=price_1;

            price_1=price_2;

            time_change[a]=(datetime)arr_time[z];
            time_line[a]=0;
            time_change_price[a]=lin_yin[a];
           }
        }
      //--- if the price has moved UPWARDS before that, the line is THICK
      if(line_move==1 && line_gauge==1)
        {
         if((price_1-price_2)/_Point>func_calc_dorstep(price_2))
           {
            a++;
            if(price_2<price_down) // If the thick line has crossed the lower shoulder when moving downwards
              {
               yin_int_1[a]=price_down;
               yin_int_2[a]=price_2;

               yang_int_1[a]=price_1;
               yang_int_2[a]=price_down;

               lin_yang[a]=price_1;

               line_move=-1;
               line_gauge=-1;

               price_up=price_1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=0;
               time_change_price[a]=lin_yang[a];
               time_central_price[a]=price_down;
              }
            else//if(price_2>=price_down) // If the thick line has not crossed the lower shoulder when moving downwards
              {
               yang_int_1[a]=price_1;
               yang_int_2[a]=price_2;

               lin_yang[a]=price_1;

               line_move=-1;
               line_gauge=1;

               price_up=price_1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=1;
               time_change_price[a]=lin_yang[a];
              }
           }
        }
      //--- the price moves UP
      //--- if the price has moved UPWARDS before that, the line is THICK
      if(line_move==1 && line_gauge==1)
        {
         if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0))
           {
            yang_int_2[a]=price_2;

            line_move=1;
            line_gauge=1;

            price_1=price_2;

            time_change[a]=(datetime)arr_time[z];
            time_line[a]=1;
           }
        }

      //--- if the price has moved UPWARDS before that, the line is THIN
      if(line_move==1 && line_gauge==-1)
        {
         if(((price_1-price_2)/_Point<-func_calc_dorstep(price_2)) || (kagi_type==0 && (price_1-price_2)/_Point<0))
           {
            if(price_2>price_up) // If the thin line has not crossed the upper shoulder when moving upwards
              {
               yin_int_2[a]=price_up;

               yang_int_1[a]=price_up;
               yang_int_2[a]=price_2;

               line_move=1;
               line_gauge=1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_central_price[a]=price_up;
               time_line[a]=1;
              }
            else//if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards
              {
               yin_int_2[a]=price_2;

               line_move=1;
               line_gauge=-1;

               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=0;
              }
           }
        }

      //--- if the price has moved DOWNWARDS before that, the line is THICK
      if(line_move==-1 && line_gauge==1)
        {
         if((price_1-price_2)/_Point<-func_calc_dorstep(price_2))
           {
            a++;

            yang_int_1[a]=price_1;
            yang_int_2[a]=price_2;

            lin_yang[a]=price_1;

            line_move=1;
            line_gauge=1;

            price_down=price_1;
            price_1=price_2;

            time_change[a]=(datetime)arr_time[z];
            time_line[a]=1;
            time_change_price[a]=lin_yang[a];
           }
        }

      //--- if the price has moved DOWNWARDS before that, the line is THIN
      if(line_move==-1 && line_gauge==-1)
        {
         if((price_1-price_2)/_Point<-func_calc_dorstep(price_2))
           {
            a++;
            if(price_2>price_up) // If the thin line has crossed the upper shoulder when moving upwards
              {
               yin_int_1[a]=price_1;
               yin_int_2[a]=price_up;

               yang_int_1[a]=price_up;
               yang_int_2[a]=price_2;

               lin_yin[a]=price_1;

               line_move=1;
               line_gauge=1;

               price_down=price_1;
               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=1;
               time_change_price[a]=lin_yin[a];
               time_central_price[a]=price_up;
              }
            else //if(price_2<=price_up) // If the thin line has not crossed the upper shoulder when moving upwards
              {
               yin_int_1[a]=price_1;
               yin_int_2[a]=price_2;

               lin_yin[a]=price_1;

               line_move=1;
               line_gauge=-1;

               price_down=price_1;
               price_1=price_2;

               time_change[a]=(datetime)arr_time[z];
               time_line[a]=0;
               time_change_price[a]=lin_yin[a];
              }
           }
        }

     }
//--- function's main loop
//--- assign actual values to drawing buffers
   uint y=a;
//--- auxiliary variables for storing data on filling the current buffer
   char yin=1;
   char yang=1;
   for(uint z=0; z<=a; z++)
     {
      arr_yin_1[z]=yin_int_1[y];
      arr_yin_2[z]=yin_int_2[y];

      switch(yin)
        {
         case 1:
           {
            arr_yin_lin1[z]=lin_yin[y];
            arr_yin_lin1[z+1]=lin_yin[y];
            yin++;
           }
         break;
         case 2:
           {
            arr_yin_lin2[z]=lin_yin[y];
            arr_yin_lin2[z+1]=lin_yin[y];
            yin++;
           }
         break;
         case 3:
           {
            arr_yin_lin3[z]=lin_yin[y];
            arr_yin_lin3[z+1]=lin_yin[y];
            yin=1;
           }
         break;
        }

      arr_yang_1[z]=yang_int_1[y];
      arr_yang_2[z]=yang_int_2[y];

      switch(yang)
        {
         case 1:
           {
            arr_yang_lin1[z]=lin_yang[y];
            arr_yang_lin1[z+1]=lin_yang[y];
            yang++;
           }
         break;
         case 2:
           {
            arr_yang_lin2[z]=lin_yang[y];
            arr_yang_lin2[z+1]=lin_yang[y];
            yang++;
           }
         break;
         case 3:
           {
            arr_yang_lin3[z]=lin_yang[y];
            arr_yang_lin3[z+1]=lin_yang[y];
            yang=1;
           }
         break;
        }
      y--;
     }
//---
  }


3.6. Funzione per la creazione di oggetti grafici "Trend Line (linea di tendenza)"

Ora, esaminiamo la funzione per la creazione di un oggetto grafico "linea di tendenza". Questa funzione è necessaria per disegnare Kagi sul grafico principale.

La funzione è molto semplice. Contiene i parametri di input necessari per la creazione di un oggetto grafico "trend line": nome dell'oggetto, primo e secondo prezzo e punti temporali, nonché larghezza e colore della linea. Il corpo della funzione contiene la funzione di creazione dell'oggetto grafico e sei funzioni di modifica delle proprietà dell'oggetto grafico.

//+------------------------------------------------------------------+
//| Func Object Create Trend Line                                    |
//+------------------------------------------------------------------+
void func_create_trend_line(string name,
                            double price1,
                            double price2,
                            datetime time1,
                            datetime time2,
                            int width,
                            color color_line)
  {
   ObjectCreate(0,name,OBJ_TREND,0,time1,price1,time2,price2);
//--- set the line color
   ObjectSetInteger(0,name,OBJPROP_COLOR,color_line);
//--- set the line display style
   ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
//--- set the line width
   ObjectSetInteger(0,name,OBJPROP_WIDTH,width);
//--- display in the foreground (false) or background (true)
   ObjectSetInteger(0,name,OBJPROP_BACK,false);
//--- enable (true) or disable (false) the mode of continuing the line display to the left
   ObjectSetInteger(0,name,OBJPROP_RAY_LEFT,false);
//--- enable (true) or disable (false) the mode of continuing the line display to the right
   ObjectSetInteger(0,name,OBJPROP_RAY_RIGHT,false);
  }

3.7. Disegnare Kagi sul grafico principale

La funzione successiva che si applica più volte alla precedente è la funzione della costruzione Kagi sul grafico principale. Le variabili globali compilate nella funzione principale precedentemente esaminata della costruzione del grafico Kagi sono utilizzate come variabili di input: la matrice dei prezzi di inversione ("spalle" e "vita"), la matrice di cambiamento e i prezzi centrali (il prezzo, al quale la linea Yin si trasforma in Yang o viceversa), l'array del tempo di inversione (situato in tempo reale, l'indice dell'array [z-1] viene utilizzato per contrassegnare l'inizio dell'inversione), l'array del tipo di linea, in cui si è verificata l'inversione (è anche un elemento in avanti, come l'array temporale).

Il corpo della funzione è costituito da un ciclo. Il loop è diviso in due parti: disegnare linee verticali e orizzontali. Il primo è anche diviso in due: disegnare le linee verticali considerando il cambio di linea (cambio prezzo centrale) e l'assenza di cambiamento. Prendi nota dei parametri trasferiti della funzione di creazione dell'oggetto "linea di tendenza".

La denominazione viene eseguita ripetutamente. Il nome dell'oggetto inizia con un numero magico (necessario per eliminare gli oggetti di un determinato indicatore), quindi il suo tipo viene fissato e infine viene assegnato l'indice. L'indice viene aggiornato ad ogni passaggio del ciclo.

//+------------------------------------------------------------------+
//| Func Kagi Main Chart                                             |
//+------------------------------------------------------------------+
void func_kagi_main_chart(double &price[],         // Shoulder prices array
                          double &central_price[], // Array of the prices of passing through the shoulders
                          datetime &time[],        // Current location time array ([-1] - start of shoulder)
                          char &type_line_end[])   // Line type by the start of shoulder formation
  {
//--- start of the loop
   for(uint z=1; z<=a; z++)
     {
      //--- check for the pass conditions (no pass)
      if(central_price[z]==-1)
        {
         if(type_line_end[z-1]==0 && price[z+1]!=-1)
           {
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z),
                                   price[z],price[z+1],time[z],time[z],width_yin_main,color_yin_main);
           }
         if(type_line_end[z-1]==1 && price[z+1]!=-1)
           {
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z),
                                   price[z],price[z+1],time[z],time[z],width_yang_main,color_yang_main);
           }
        }
      else //--- check for the pass conditions (pass is present)
        {
         if(type_line_end[z-1]==0 && price[z+1]!=-1)
           {
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z),
                                   central_price[z],price[z],time[z],time[z],width_yin_main,color_yin_main);
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z),
                                   central_price[z],price[z+1],time[z],time[z],width_yang_main,color_yang_main);
           }
         if(type_line_end[z-1]==1 && price[z+1]!=-1)
           {
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yin_v"+IntegerToString(z),
                                   central_price[z],price[z+1],time[z],time[z],width_yin_main,color_yin_main);
            func_create_trend_line(IntegerToString(magic_numb)+"_trend_yang_v"+IntegerToString(z),
                                   central_price[z],price[z],time[z],time[z],width_yang_main,color_yang_main);
           }
        }
      //--- check for the pass conditions (pass is present)
      //--- draw the horizontals
      if(type_line_end[z-1]==0)
        {
         func_create_trend_line(IntegerToString(magic_numb)+"_trend_h"+IntegerToString(z),
                                price[z],price[z],time[z-1],time[z],width_yin_main,color_yin_main);
        }
      if(type_line_end[z-1]==1)
        {
         func_create_trend_line(IntegerToString(magic_numb)+"_trend_h"+IntegerToString(z),
                                price[z],price[z],time[z-1],time[z],width_yang_main,color_yang_main);
        }
      //--- draw the horizontals
     }
  }

3.8. Implementazione di etichette aggiuntive

Come ho già detto sopra, l'indicatore implementa etichette aggiuntive. Esaminiamo la funzione che fornisce queste etichette sul grafico principale. Ci sono solo due tipi di etichette qui: prezzo di inversione e etichette di tempo di inversione mostrate tramite "etichetta di prezzo" e "etichetta verticale". I seguenti parametri vengono passati come input: attributo del disegno dell'etichetta del prezzo di inversione e colore dell'etichetta, attributi del disegno dell'etichetta del tempo di inversione e del cambiamento di colore dell'etichetta, il primo e il secondo colore del tempo di inversione.

L'intera funzione è divisa in due parti: la prima parte è responsabile delle etichette temporali, mentre la seconda è responsabile delle etichette dei prezzi. Entrambe le parti della funzione sono costituite dai loop limitati dal numero di inversioni dei grafici (variabile "a"). L'istruzione condizionale if-else viene impostata prima del ciclo. La dichiarazione verifica la necessità del loro disegno in base alle impostazioni dell'indicatore.

Il primo ciclo crea etichette temporali, la definizione del nome dell'oggetto viene eseguita all'inizio del ciclo (il principio di generazione del nome è stato descritto sopra). Quindi, il colore viene selezionato in base alla riga della matrice del tipo di linea dichiarata a livello globale (se il parametro è impostato) e altri parametri vengono applicati alla linea.

Il secondo ciclo è responsabile della creazione di etichette di prezzo di inversione. Innanzitutto, viene generato il nome dell'oggetto. Quindi, la selezione dell'indice della matrice temporale viene impostata a seconda che Kagi debba essere costruito sul grafico principale o meno. se ciò non viene fatto, le etichette saranno posizionate "nell'aria" e non sarà abbastanza chiaro da quale luogo si è verificata l'inversione. Quindi, viene creato e configurato l'oggetto di tipo "etichetta del prezzo".

//+------------------------------------------------------------------+
//| Func Label Main Chart                                            |
//+------------------------------------------------------------------+
void func_label_main_chart(bool label_print,
                           color label_color,
                           bool time_change_print,
                           bool time_change_color,
                           color time_color_first,
                           color time_color_second)
  {
   if(time_change_print==true)
     {
      for(uint z=1; z<=a; z++)
        {
         string name=IntegerToString(magic_numb)+"_time_2_"+IntegerToString(z);
         //--- create an object of a vertical line type
         ObjectCreate(0,name,OBJ_VLINE,0,time_change[z],0);
         //--- set the line color
         color color_line=clrBlack;
         if(time_change_color==true)
           {
            if(time_line[z]==0)color_line=time_color_first;
            if(time_line[z]==1)color_line=time_color_second;
           }
         else color_line=time_color_first;
         ObjectSetInteger(0,name,OBJPROP_COLOR,color_line);
         //--- set the line display style
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         //--- set the line width
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         //--- display on the foreground (false) or background (true)
         ObjectSetInteger(0,name,OBJPROP_BACK,false);
         //--- enable (true) or disable (false) the line display mode in the chart subwindows
         ObjectSetInteger(0,name,OBJPROP_RAY,time_separate_windows);
        }
     }
   if(label_print==true)
     {
      for(uint z=1; z<=a; z++)
        {
         string name=IntegerToString(magic_numb)+"_label_2_"+IntegerToString(z);
         uint numb_time;
         if(kagi_main_chart==true)numb_time=z;
         else numb_time=z-1;
         //--- create a label type object
         ObjectCreate(0,name,OBJ_ARROW_RIGHT_PRICE,0,time_change[numb_time],time_change_price[z]);
         //--- set the label color
         ObjectSetInteger(0,name,OBJPROP_COLOR,label_color);
         //--- set the edging line style
         ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
         //--- set the label size
         ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
         //--- display on the foreground (false) or background (true)
         ObjectSetInteger(0,name,OBJPROP_BACK,false);
        }
     }
  }

Ora, vediamo come possiamo impostare le etichette nella finestra dell'indicatore.

Tutte le etichette nella finestra dell'indicatore sono per lo più quelle di prezzo e ce ne sono solo due tipi: etichette di prezzo di inversione e livelli di prezzo. Esistono due tipi di disegno dei livelli di prezzo: sulle inversioni del grafico e ad una distanza uguale dell'intera fascia di prezzo del grafico. Il primo tipo può cambiare il colore dei livelli in due modi: a seconda del tipo di linea (Yin o Yang) e in base all'inversione (su o giù).

Pertanto, la funzione stessa è divisa in due cicli: il primo è responsabile della creazione di etichette di prezzo di inversione, il secondo si occupa della designazione dei livelli di prezzo. Quest'ultimo è ulteriormente diviso in due tipi: etichetta ad ogni inversione o etichette in tutta la fascia di prezzo su un livello uguale.

Questa funzione è diversa dalla precedente in quanto ha limitazioni sul numero di etichette e livelli di prezzo a causa del fatto che quando ce ne sono molte sovraccaricano il grafico complicandone la comprensione.

A causa di questa funzione, entrambi i loop sono limitati dal numero di passaggi specificati nelle impostazioni dell'indicatore (numero di etichette e livelli di prezzo). Tale approccio è pericoloso in quanto il numero di inversioni può rivelarsi molto inferiore al numero di etichette di prezzo impostate nelle impostazioni. Per questo motivo, la presenza di inversione durante ogni passaggio di loop viene controllata per disegnare un'etichetta o un livello di prezzo.

L'unica eccezione è disegnare livelli di prezzo lungo l'intera fascia di prezzo su una distanza uguale. La creazione di oggetti grafici di tipo "Price label" viene eseguita nelle coordinate in ordine inverso, ovvero le etichette vengono posizionate dalla data corrente andando indietro nel tempo. Lo stesso vale per i livelli dei prezzi: i livelli di prezzo attuali vengono generati per primi seguiti da quelli precedenti. Le eccezioni sono i livelli dei prezzi che non dipendono dalle inversioni dei grafici.

Le modifiche del colore a livello di prezzo vengono eseguite utilizzando istruzioni condizionali if-else in base alle impostazioni.

//+------------------------------------------------------------------+
//| Func Label Indicator Window                                      |
//+------------------------------------------------------------------+
void func_label_indicator_window(bool label_print,         // Draw price labels
                                 bool levels_print,        // Draw levels
                                 char levels_type_draw,    // Type of drawing the levels by reversals or at an equal distance of the entire price range
                                 char levels_color_change) // Change line color
  {
   uint number=a;
   if(label_print==true)
     {
      for(uint z=0; z<=label_1_number; z++)
        {
         if(z<number)
           {
            string name=IntegerToString(magic_numb)+"_label_1_"+IntegerToString(z);
            //--- create label type object
            ObjectCreate(0,name,OBJ_ARROW_RIGHT_PRICE,ChartWindowFind(),(datetime)Time[(bars_copied_time-z-2)],time_change_price[number-z]);
            //--- set the label color
            ObjectSetInteger(0,name,OBJPROP_COLOR,label_1_color);
            //--- set the style of the edging line
            ObjectSetInteger(0,name,OBJPROP_STYLE,STYLE_SOLID);
            //--- set the label size
            ObjectSetInteger(0,name,OBJPROP_WIDTH,1);
            //--- display on the foreground (false) or background (true)
            ObjectSetInteger(0,name,OBJPROP_BACK,false);
           }
        }
     }
   if(levels_print==true)
     {
      if(levels_type_draw==0)
        {
         for(uint z=0; z<=levels_number; z++)
           {
            if(z<number)
              {
               IndicatorSetDouble(INDICATOR_LEVELVALUE,z,time_change_price[number-z]);
               if(levels_change_color==0)
                 {
                  double numb_even=z;
                  if(MathMod(numb_even,2)==0)
                    {
                     IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color);
                    }
                  if(MathMod(numb_even,2)!=0)
                    {
                     IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_second_color);
                    }
                 }
               if(levels_change_color==1)
                 {
                  if(time_line[number-z]==0)IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color);
                  if(time_line[number-z]==1)IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_second_color);
                 }
               if(levels_change_color==2)
                 {
                  IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color);
                 }
              }
           }
        }
      if(levels_type_draw==1)
        {
         double max_price=Price[ArrayMaximum(Price)];
         double min_price=Price[ArrayMinimum(Price,1,ArrayMinimum(Price)-1)];
         double number_difference=(max_price-min_price)/levels_number;
         NormalizeDouble(number_difference,_Digits);
         for(uint z=0; z<=levels_number; z++)
           {
            IndicatorSetDouble(INDICATOR_LEVELVALUE,z,(min_price+(z*number_difference)));
            IndicatorSetInteger(INDICATOR_LEVELCOLOR,z,levels_first_color);
           }
        }
     }
  }

3.9. Eliminazione di oggetti grafici creati in precedenza

Sappiamo già che questo indicatore è ricco di oggetti grafici. È tempo di pensare a come possiamo eliminarli in modo rapido ed efficiente.

Questa attività viene eseguita dalla funzione per l'eliminazione degli oggetti grafici. Il nome iniziale e il numero di oggetti vengono utilizzati come parametri di funzione. Come durante la creazione, il nome dell'oggetto deve contenere il numero magico e il nome di un tipo di oggetto. La chiamata di funzione nel programma è limitata dal numero di oggetti che superano la loro possibile esistenza. Tuttavia, ciò non influisce sulla funzionalità dell'indicatore.

//+------------------------------------------------------------------+
//| Func Delete Objects                                              |
//+------------------------------------------------------------------+
void func_delete_objects(string name,
                         int number)
  {
   string name_del;
   for(int x=0; x<=number; x++)
     {
      name_del=name+IntegerToString(x);
      ObjectDelete(0,name_del);
     }
  }

3.10. Funzione per l'avvio della costruzione del grafico

Ora, dopo aver esaminato tutte le funzioni per il calcolo e la costruzione del grafico Kagi, nonché per la creazione e l'eliminazione di oggetti, dovremmo considerare un'altra piccola funzione per controllare l'arrivo della nuova barra. La funzione è abbastanza semplice e ha un parametro di input - periodo analizzato. Anche la risposta della funzione è molto semplice. Ha tipo bool e contiene la risposta sul fatto che una nuova barra sia presente o meno. La base del corpo della funzione è l'istruzione switch che passa il controllo alle sue diverse istruzioni a seconda del periodo.

Nell'esempio, la funzione copre l'intero intervallo di periodo, sebbene sia possibile utilizzare anche un solo periodo.

L'algoritmo della funzione è stato preso dal codice IsNewBar: l'ora dell'apertura dell'ultima barra viene confrontata con il valore temporale precedentemente definito. Se i valori sono diversi, vuole dire che c'è una nuova barra. Il nuovo valore viene assegnato come precedentemente definito e la risposta della funzione è considerata positiva. Se l'ora di apertura dell'ultima barra coincide con il valore dell’ora determinato in precedenza, vuol dire che la nuova barra non è ancora apparsa e la risposta della funzione è negativa.

//+------------------------------------------------------------------+
//| Func New Bar                                                     |
//+------------------------------------------------------------------+
bool func_new_bar(ENUM_TIMEFRAMES period_time)
  {
//----
   static datetime old_Times[22];// array for storing old values
   bool res=false;               // analysis result variable  
   int  i=0;                     // old_Times[] array cell index    
   datetime new_Time[1];         // new bar time

   switch(period_time)
     {
      case PERIOD_M1:  i= 0; break;
      case PERIOD_M2:  i= 1; break;
      case PERIOD_M3:  i= 2; break;
      case PERIOD_M4:  i= 3; break;
      case PERIOD_M5:  i= 4; break;
      case PERIOD_M6:  i= 5; break;
      case PERIOD_M10: i= 6; break;
      case PERIOD_M12: i= 7; break;
      case PERIOD_M15: i= 8; break;
      case PERIOD_M20: i= 9; break;
      case PERIOD_M30: i=10; break;
      case PERIOD_H1:  i=11; break;
      case PERIOD_H2:  i=12; break;
      case PERIOD_H3:  i=13; break;
      case PERIOD_H4:  i=14; break;
      case PERIOD_H6:  i=15; break;
      case PERIOD_H8:  i=16; break;
      case PERIOD_H12: i=17; break;
      case PERIOD_D1:  i=18; break;
      case PERIOD_W1:  i=19; break;
      case PERIOD_MN1: i=20; break;
      case PERIOD_CURRENT: i=21; break;
     }
   // copy the time of the last bar to new_Time[0] cell  
   int copied=CopyTime(_Symbol,period_time,0,1,new_Time);
  
   if(copied>0) // all is well. Data has been copied
      {
      if(old_Times[i]!=new_Time[0])       // if the bar's old time is not equal to new one
         {
         if(old_Times[i]!=0) res=true;    // if it is not the first launch, true = new bar
         old_Times[i]=new_Time[0];        // store the bar's time
         }
      }
//----
   return(res);
  }

 

3.11. Funzioni OnCalculate() e OnChartEvent()

Tutte le funzioni sopra descritte sono consolidate nell'omonima funzione – Func Consolidation. Questa funzione viene avviata ogni volta che viene visualizzata una nuova barra nella funzione OnCalculate() e quando si preme il tasto "R" dalla funzione OnChartEvent(). 

Prima che il grafico venga generato o aggiornato, la funzione per l'eliminazione di tutti gli oggetti grafici viene chiamata nella funzione di consolidamento (Consolidamento Func). Il numero generale di chiamate di funzione è 7, poiché ci sono molti oggetti (sono divisi in etichette dei prezzi del grafico principale e della finestra dell'indicatore), linee verticali che indicano il tempo di inversione, nonché linee di tendenza verticali e orizzontali Yin e Yang.

Quindi, i dati della cronologia vengono copiati in termini di prezzo e tempo. La funzione principale per la costruzione del grafico Kagi viene lanciata in seguito. Successivamente, viene chiamata la funzione per posizionare tutte le etichette dei prezzi sul grafico principale e sulla finestra dell'indicatore. Infine, Kagi viene generato sul grafico principale e viene avviata la funzione per ridisegnare gli oggetti.

//+------------------------------------------------------------------+
//| Func Consolidation                                               |
//+------------------------------------------------------------------+
void func_consolidation()
  {
//--- date of construction end
   stop_data=TimeCurrent();

//--- deleting all graphical objects belonging to the indicator
   func_delete_objects(IntegerToString(magic_numb)+"_label_2_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_label_1_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_time_2_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_yin_v",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_yang_v",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1));

//--- copy price data to the main buffer
   copy_history=func_copy_history(Price,start_data,stop_data);

//--- display information about the error when copying price data
   if(copy_history==false)Alert("Error of copy history Price");

//--- copy time data to the main buffer
   copy_time=func_copy_time(Time,start_data,stop_data);

//--- display a notification of the error occurred while copying time data
   if(copy_time==false)Alert("Error of copy history Time");

//--- construct Kagi chart in the indicator window
   func_draw_kagi(Price,YinBuffer1,YinBuffer2,Yin1Buffer,Yin2Buffer,Yin3Buffer,
                  YangBuffer1,YangBuffer2,Yang1Buffer,Yang2Buffer,Yang3Buffer,Time);

//--- draw labels on the main chart
   func_label_main_chart(label_2,label_2_color,time_line_draw,time_line_change_color,time_first_color,time_second_color);

//--- draw labels on the indicator chart
   func_label_indicator_window(label_1,levels_on_off,levels_type,levels_change_color);

//--- construct Kagi chart in the main window
   if(kagi_main_chart==true)func_kagi_main_chart(time_change_price,time_central_price,time_change,time_line);

//--- redraw the chart
   ChartRedraw(0);
//---
  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const int begin,
                const double &price[])
  {
//---
   if(func_new_bar(period_to_redraw)==true)
     {
      func_consolidation();
     }
//--- return value of prev_calculated for next call
   return(rates_total);
  }
//+------------------------------------------------------------------+
//| OnChartEvent                                                     |
//+------------------------------------------------------------------+
void OnChartEvent(const int id,         // event ID  
                  const long& lparam,   // long type event parameter
                  const double& dparam, // double type event parameter
                  const string& sparam) // string type event parameter
  {
   if(id==CHARTEVENT_KEYDOWN) // Keyboard button pressing event
     {
      if(lparam==82) // "R" key has been pressed
        {
         func_consolidation();
        }
     }
  }

 

3.12. Funzione OnDeinit()

La cancellazione di tutti gli oggetti viene eseguita nella funzione di deinitializzazione dell'indicatore.

//+------------------------------------------------------------------+
//| OnDeinit                                                         |
//+------------------------------------------------------------------+ 
void OnDeinit(const int reason)
  {
//--- delete all graphical objects belonging to the indicator
   func_delete_objects(IntegerToString(magic_numb)+"_label_2_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_label_1_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_time_2_",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_yin_v",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_yang_v",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1));
   func_delete_objects(IntegerToString(magic_numb)+"_trend_h",ObjectsTotal(0,-1,-1));
//--- redraw the chart
   ChartRedraw(0);
  }

Ora, passiamo all'uso dell'indicatore in pratica.


4. Utilizzo di Kagi Chart nella pratica

Ci sono molte strategie di trading basate sul grafico Kagi. Ne esamineremo alcune.

Iniziamo con la strategia più popolare: vendere quando Yang cambia in Yin e acquistare nel caso opposto. Questo è mostrato in Fig. 4:

La strategia di acquisto e vendita durante gli interruttori di linea

Fig. 4. Vendere quando Yang cambia in Yin e acquistare nel caso opposto 

Come si può vedere in Fig. 4 (EURUSD M30, 5 punti), questa strategia mostra buoni risultati. La figura mostra 8 punti per 4 segnali, il primo (1) mostra che la posizione lunga dovrebbe essere aperta a 1,3518. Questo sembra essere corretto in quanto il prezzo raggiunge quindi circa 1,3560 che comprende 42 punti al giorno. Questo è un buon risultato.

Il prossimo punto (2) consiglia di vendere a 1,3519. Come possiamo vedere, il prezzo in realtà scende attraversando il livello di 1,3485 (e coprendo 34 punti) approssimativamente per due ore.

Passiamo al punto (3). La posizione lunga viene aperta a 1,3538 e il prezzo sale raggiungendo 1,3695. Pertanto, il profitto comprende 157 punti già per un giorno e mezzo. Naturalmente, questi sono i profitti più alti possibili, ma il risultato è ancora abbastanza buono.

La prossima strategia di trading sta tornando indietro dalla linea di tendenza mostrata in Fig. 5 (EURUSD M30, 5 punti), 7-18 ottobre:

Rollback dalla linea di tendenza

Fig. 5. Rollback dalla linea di tendenza

Possiamo andare oltre e fare trading seguendo i canali. Un esempio di ricerca di un canale può essere esaminato in Fig. 6 (EURUSD H1, 5 punti), all'incirca nello stesso periodo:

Trading per canali

Fig. 6. Trading per canali

La strategia meno popolare si basa sul fatto che dopo l’aumento di 7-10 "spalle" o la diminuzione delle "vite", ci sarà sicuramente un'inversione (caduta o aumento).

Questo è mostrato nella Figura 7 (GBPUSD H4, 25 punti), 10 luglio - 18 ottobre:

7-10 "spalle" in aumento o "vite" in diminuzione

Fig. 7. 7-10 "spalle" in aumento o "vite" in diminuzione

Come si può vedere nell'immagine, sette spalle ascendenti sono seguite da una caduta piuttosto considerevole all'incirca uguale alla metà dell'aumento precedente (circa 300 punti).

Esaminiamo la strategia "Trading attraverso un'etichetta di prezzo" per mostrare la necessità di utilizzare parametri indicatori aggiuntivi. L'idea è quella di entrare nel mercato quando il prezzo supera (compra) o si muove al di sotto (vendi) l'etichetta del prezzo precedente.

La strategia è mostrata in Fig. 8 (GBPUSD H4, 30 punti, costruzione modificata):

Trading attraverso un'etichetta di prezzo

Fig. 8. Trading attraverso un'etichetta di prezzo 

Le frecce rosse sulla Fig. 8 mostrano quando acquistare o vendere. Le frecce si muovono dall'etichetta del prezzo precedente che mostra le posizioni in cui le precedenti etichette di prezzo sono state sfondate.

Le etichette temporali servono principalmente come indicatori di direzione della tendenza. Poiché il colore delle etichette temporali può essere modificato rispetto al tipo di linea e il tipo di linea Yin o Yang mostra la direzione o l'inversione della tendenza, il colore può aiutarci a definire l'attuale stato d'animo del mercato.

Ad esempio, prendiamo il grafico azionario #IBM (H4, 1%, costruzione standard) mostrato in Fig. 9:

Definizione della direzione delle tendenze mediante etichette temporali

Fig. 9. Definizione della direzione delle tendenze mediante etichette temporali

Il grafico mostra che le linee blu si trovano principalmente nella parte superiore del grafico, mentre quelle rosse - in basso.


Conclusione

Il grafico Kagi può essere utilizzato con successo per il trading di mercato come base strategica o come strumento ausiliario per un'analisi più precisa.

In questo articolo, ho esaminato il codice stesso e alcune specificità della costruzione dell'indicatore. L'obiettivo principale è stato la creazione dell'indicatore multifunzionale contenente tutti gli elementi necessari con alcune funzionalità extra che possono essere disabilitate.

Sarò lieto di prendere in considerazione nuove idee e miglioramenti per l'indicatore e, forse, di attuarli in futuro. Inoltre, ti prego di fornirmi il tuo feedback. Sarò lieto di rispondere alle vostre domande sull'indicatore.

Questo articolo continua la serie dedicata allo sviluppo di indicatori per la costruzione dei grafici del passato. L'articolo precedente può essere trovato qui. Continuerò a scrivere articoli, e spero di incontrarvi di nuovo presto. Grazie per il vostro interesse! Vi auguro un trading di successo, e che i vostri codici siano ottimizzati e stabili.


Tradotto dal russo da MetaQuotes Ltd.
Articolo originale: https://www.mql5.com/ru/articles/772

File allegati |
bkcv.mq5 (44.19 KB)
Econometrics Previsioni EURUSD One-Step-Ahead Econometrics Previsioni EURUSD One-Step-Ahead
L'articolo si concentra sulla previsione anticipata per EURUSD utilizzando il software EViews e un'ulteriore valutazione dei risultati delle previsioni utilizzando i programmi in EViews. La previsione prevede modelli di regressione e viene valutata tramite un Expert Advisor sviluppato per MetaTrader 4.
Creazione di un Multi-Currency Multi-System Expert Advisor Creazione di un Multi-Currency Multi-System Expert Advisor
L'articolo introduce una struttura per un Expert Advisor che scambia più simboli e utilizza diversi sistemi di trading contemporaneamente. Se hai già identificato i parametri di input ottimali per tutti i tuoi EA e hai ottenuto buoni risultati di backtesting per ciascuno di essi separatamente, chiediti quali risultati otterresti se testassi tutti gli EA contemporaneamente, con tutte le tue strategie messe insieme.
Forum sulla programmazione MQL5 Liste Forum sulla programmazione MQL5 Liste
La nuova versione del linguaggio di programmazione per lo sviluppo di strategie di trading, MQL [MQL5], fornisce funzionalità più potenti ed efficaci rispetto alla versione precedente [MQL4]. Il vantaggio risiede essenzialmente nelle funzionalità di programmazione orientata agli oggetti. Questo articolo esamina la possibilità di utilizzare tipi di dati personalizzati complessi, come nodi ed elenchi. Fornisce inoltre un esempio di utilizzo delle liste nella programmazione pratica in MQL5.
MQL5 Cookbook: Sviluppo di un indicatore di volatilità multi-simbolo in MQL5 MQL5 Cookbook: Sviluppo di un indicatore di volatilità multi-simbolo in MQL5
In questo articolo, considereremo lo sviluppo di un indicatore di volatilità multi-simbolo. Lo sviluppo di indicatori multi-simbolo può presentare alcune difficoltà per gli sviluppatori MQL5 alle prime armi che questo articolo aiuta a chiarire. Le principali questioni che sorgono nel corso dello sviluppo di un indicatore multi-simbolo hanno a che fare con la sincronizzazione dei dati di altri simboli rispetto al simbolo corrente, con la mancanza di alcuni dati indicatori e con l'identificazione dell'inizio di barre "vere" di un determinato intervallo di tempo. Tutti questi problemi saranno attentamente considerati nell'articolo.