English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
Indicateur pour la cartographie Kagi

Indicateur pour la cartographie Kagi

MetaTrader 5Exemples | 13 janvier 2022, 08:59
242 0
Dmitriy Zabudskiy
Dmitriy Zabudskiy

Introduction

L'article "Indicateur pour la cartographie en Point et en Figure" a décrit l'une des méthodes de programmation permettant de créer Graphique en Point et Figure. Ce graphique est connu depuis le 19ème siècle. Cependant, ce n'est pas le seul graphique du passé lointain. Un autre représentant notable des premiers types de représentation du marché financier est Graphique Kagi. Ce graphique sera discuté dans le présent article.

The Stock exchange - institution financière peu familière au Japon du 19ème siècle - a été créée en mai 1878. Il est connu sous le nom de Tokyo Stock Exchange de nos jours. Cet événement a joué un rôle essentiel dans la création et le développement ultérieur des graphiques Kagi. L'Europe et les États-Unis ont découvert les graphiques Kagi après la publication de Steve Nison "Au-delà des chandeliers : Nouvelles techniques japonaises de cartographie révélées" en 1994.

Les mots japonais "Kagi" désignent une clé en forme de L qui était utilisée au moment de l'élaboration du graphique. En outre, il existe une version modifiée du nom - "key chart". Dans "Au-delà des chandeliers" de Steve Nison, vous pouvez également trouver des noms alternatifs pour le graphique : graphique de fourchette de prix, graphique en crochet, graphique en delta ou en chaîne.

Quelle est la particularité de ce graphique ? Sa principale caractéristique est qu'il ignore l'échelle de temps en ne laissant que le prix (contrairement aux chandeliers, barres et lignes japonais). Ainsi, le graphique cache des fluctuations de prix inconsidérables ne laissant que les plus importantes.

Le graphique représente un ensemble de lignes Yang épaisses et Yin fines se remplaçant en fonction de la situation du marché. Dans le cas où le marché évolue dans la même direction, la ligne est prolongée pour atteindre une nouvelle fourchette de prix. Cependant, si le marché se retourne et atteint un montant prédéfini, la ligne Kagi est tracée en sens inverse dans la nouvelle colonne. Le montant prédéfini est défini soit en points (généralement utilisé pour les paires de devises), soit en pourcentage du prix actuel (généralement utilisé pour les actions). L'épaisseur de la ligne varie en fonction de la percée élevée ou faible la plus proche.


1. Exemple de cartographie

Utilisons les données historiques sur l'EURUSD, H1 du 8 au 11 octobre.

Un exemple d'imagerie standard avec un seuil inversé de 15 points est présenté sur la Fig. 1 :

Graphique de Kagi, EURUSD H1

Fig. 1. Graphique de Kagi, EURUSD H1

Comme nous pouvons le voir, le prix a commencé à baisser à 17h00. Le mouvement de baisse s'est poursuivi jusqu'à 21h00. À 22h00, le prix monte de 1,3566 et clôture à 1,3574. Autrement dit, le prix passe à 11 points. Ce n'est pas suffisant pour un retournement, mais le nouveau plus bas n'a pas été atteint non plus. Les deux heures suivantes, le prix reste plat et enfin, à 01h00 (9 octobre), nous assistons à un fort mouvement haussier, qui est clôturé à 1,3591 comprenant 25 points (1,3591-1,3566). Cela signifie que le prix s'est inversé.

La tendance haussière se poursuit l'heure suivante. Le prix atteint 1,3599 renforçant l'épaisse ligne Yang. À 03h00, le prix chute fortement pour clôturer à 1,3578, soit 21 points par rapport au précédent sommet (1,3599-1,3578). C'est plus que suffisant pour le retournement. La ligne descend mais conserve sa forme (ligne Yang épaisse).

Jusqu'à 16h00, le prix baisse et finalement il franchit le minimum le plus proche et passe d'une ligne Yang épaisse à une ligne Yin mince. La valeur basse de 1,3566 mentionnée précédemment avait servi de prix décisif ici. Le prix continue de se déplacer comme une ligne Yin et est changé en Yang à 14h00 le 10 octobre, franchissant le plus haut le plus proche de 1,3524 formé à 23h00 (9 octobre). Ce petit exemple montre comment le graphique de Kagi est formé.


2. Principe de cartographie de l’indicateur Kagi

Afin de rendre l'indicateur indépendant de la période actuelle, il a été décidé de copier séparément les données de la période à laquelle l'indicateur était censé être formé, puis de créer l'indicateur à partir des données obtenues.

Cela permet d'examiner plusieurs périodes simultanément sur un seul graphique, ce qui élargit les limites de l'analyse technique sur les graphiques Kagi. L'indicateur lui-même est situé dans une fenêtre séparée, mais il est également possible d'afficher des données sur le graphique principal. En d'autres termes, la formation de base (apparence standard ou modifiée) est effectuée dans la fenêtre de l'indicateur. L'indicateur est copié dans le graphique principal, des marques de prix et de temps (selon les paramètres) sont également dessinées.

Comme mentionné précédemment, l'indicateur dessine le graphique à la fois en version standard et modifiée. La norme a été décrite ci-dessus. Considérons maintenant la version modifiée.

Je ne sais pas si c'est une idée nouvelle, mais je n'ai pas entendu parler d'une telle version. L'idée du filtre supplémentaire est que non seulement les points inversés, mais chaque mouvement du graphique est maintenant filtré. En d'autres termes, le prix doit se déplacer sur une distance spécifiée pour que le nouveau haut ou bas (à ne pas confondre avec l'épaule/la taille) se forme. Généralement, partout où le prix évolue, il doit d'abord couvrir une distance spécifiée. Après cela, il est défini s'il s'agissait d'une poursuite ou d'un retournement de tendance.

La figure 2 montre comment fonctionne le principe. L'aspect modifié du graphique est affiché en bleu, tandis que l'aspect standard est en rouge. Comme nous pouvons le voir, l'apparence modifiée répond aux changements de mouvement des prix plus lentement en filtrant la plupart des signaux mineurs.

Versions standard et modifiées de la création d'un graphique Kagi

Fig. 2. Versions modifiée (ligne bleue) et standard (ligne rouge) de la création du graphique Kagi

Outre le graphique de Kagi, l'indicateur fournit des éléments supplémentaires à la fois dans la fenêtre de l'indicateur et dans le graphique principal.

Selon les réglages, les marques peuvent être placées dans la fenêtre d'indicateur. Ces marques fournissent des données sur les prix de retournement. La même fonction est mise en œuvre en utilisant des niveaux de prix, qui (selon les paramètres) peuvent se répartir uniformément le long de la fenêtre sur toute la fourchette de prix utilisée pour former l'indicateur ou à chaque retournement de graphique. Les couleurs peuvent être définies en trois versions : selon le type de retournement (haut - bas), type de ligne (Yin - Yang) ou pas de changement de couleur.

Les marques de prix de retournement, y compris temporaires, sont fournies sur le graphique principal. Ces marques (selon les réglages) peuvent être d'une seule couleur ou changer de couleur en fonction des couleurs des lignes Yin ou Yang.

L'ensemble du code indicateur est implémenté à l'aide des fonctions communiquant entre elles via des variables globales.

Le code peut être divisé en trois fonctions principales et onze fonctions supplémentaires. La charge principale des calculs et des remplissages de tampons des constructions graphiques de base et des tableaux de tampons supplémentaires repose sur la fonction de formation du graphique de Kagi dans la fenêtre d'indicateur. Les deux autres fonctions sont chargées de fournir les données : la première copie les données de temps, tandis que l'autre - les données sur les prix de chaque barre de la période sélectionnée.

Les fonctions auxiliaires restantes sont chargées d'effectuer toutes les constructions, de supprimer les objets, de décharger l'indicateur accompagné de la suppression de tous les objets indicateurs, de calculer les paramètres de retournement, de tracer des repères sur le graphique principal et la fenêtre de l'indicateur, de créer des objets graphiques de type "Ligne de tendance" , dessinant Kagi sur le graphique principal, ainsi que définissant l'arrivée de la nouvelle barre pour lancer la formation de l'indicateur.


3. Code d'indicateur et algorithme

Examinons maintenant en détail le code indicateur et l'algorithme de sa formation. Le code est assez volumineux et il peut être assez difficile pour les programmeurs novices de le comprendre. Les fonctions communiquant entre elles via les variables globales rendent le code assez confus. Dans cette partie de l'article, j'expliquerai chaque fonction et partie du code séparément. Tout d'abord, je décrirai les paramètres de l'indicateur, puis il y aura des clarifications concernant les fonctions initiales de copie de données, le calcul des paramètres de retournement, la fonction principale de la formation et du calcul du diagramme de Kagi et d'autres fonctions auxiliaires.

3.1. Paramètres d'entrée de l'indicateur

Le code commence par la déclaration de l'indicateur dans une fenêtre séparée, ainsi que de 12 tampons et 8 constructions graphiques d'indicateurs. Tout d'abord, définissons pourquoi 8 constructions graphiques, dont deux "histogrammes" et six "lignes", ont été utilisées. Chaque "histogramme" construit sa propre ligne verticale. L'une des lignes est responsable de la ligne Yin, tandis que l'autre est responsable de la ligne Yang.

Le cas est un peu plus compliqué avec les "lignes", car il y en a trois pour chaque ligne. Cela est dû au fait que la ligne est tracée s'il y a un autre point tracé près du premier. En d'autres termes, nous n'avons besoin que de deux constructions graphiques de type "ligne" à faire pivoter pour dessiner deux lignes adjacentes l'une à l'autre. Cependant, si nous avons besoin de ces lignes pour sauter des points nécessaires, nous avons besoin que la troisième construction soit tournée avec les deux autres.

Ceci est expliqué dans la figure 3, où vous pouvez voir ce qui se passe si seulement deux constructions graphiques de type "ligne" sont utilisées :


 Fig. 3. Exemple d'utilisation de deux et trois constructions graphiques de type "ligne" pour afficher les lignes des épaules et de la taille

Ensuite, le menu des paramètres est créé. Il y a cinq énumérations ici (examinons-les dans les paramètres d'entrée).

Le premier paramètre d'entrée "période" est une période à laquelle la construction est effectuée, il est suivi de "période à_refaire" - période de mise à jour de la construction du graphique et le dernier paramètre de temps est "données_début" - l'heure à laquelle la construction commence.

Ces paramètres sont suivis par la construction de graphique et des étiquetages supplémentaires :

  • kagi_type – type de construction de graphique défini par l'utilisateur, standard ou modifié ;
  • price_type – type de prix utilisé pour la construction : Fermé, Ouvert, Haut et Bas ;
  • type_doorstep – type de retournement utilisé : point et pourcentage ;
  • doorstep – valeur de retournement (spécifiée en points ou en pourcentage en fonction du paramètre ci-dessus) ;
  • color_yin – Couleur de la ligne Yin dans la fenêtre de l'indicateur ;
  • color_yang – Couleur de la ligne Yang dans la fenêtre de l'indicateur ;
  • width_yin – Largeur de ligne Yin dans la fenêtre d'indicateur ;
  • width_yang – Largeur de ligne Yang dans la fenêtre de l'indicateur ;
  • levels_on_off - si les niveaux de prix doivent être dessinés dans la fenêtre d'indicateur ;
  • levels_type – types de niveaux de prix dans la fenêtre d'indicateur. Vous avez le choix entre deux valeurs : à chaque retournement ou uniformément sur toute la fourchette de prix ;
  • level_number – nombre de niveaux de prix dans la fenêtre d'indicateur ;
  • level_change_color – permet de changer la couleur des lignes de niveau de prix ; les options sont les retournements supérieurs et inférieurs, les lignes Yin et Yang ou aucun changement ;
  • level_first_color – la première couleur d'un niveau de prix ;
  • level_second_color – la deuxième couleur d'un niveau de prix ;
  • label_1 - dessin des étiquettes de prix de retournement du graphique dans la fenêtre de l'indicateur ;
  • label_1_number – nombre d'étiquettes affichées dans la fenêtre de l'indicateur ;
  • label_1_color – couleur des étiquettes de prix dans la fenêtre de l'indicateur ;
  • label_2 - dessin des étiquettes de prix sur le graphique principal ;
  • label_2_color – couleur de l'étiquette sur le graphique principal ;
  • time_line_draw - dessin des lignes de temps de retournement sur le graphique principal ;
  • time_separate_windows - dessin de la suite des lignes de temps de retournement à partir du graphique principal ;
  • time_line_change_color - change la couleur de la ligne de temps en fonction de l'étiquette de retournement sur la ligne Yin ou Yang ;
  • time_first_color – la première couleur de la ligne de temps sur le graphique principal ;
  • time_second_color – la deuxième couleur de la ligne de temps sur le graphique principal ;
  • kagi_main_chart - si Kagi doit être dessiné sur le graphique principal ;
  • color_yin_main – Couleur de la ligne Yin sur le graphique principal ;
  • color_yang_main – Couleur de la ligne Yang sur le graphique principal ;
  • width_yin_main – Largeur de la ligne Yin sur le graphique principal ;
  • width_yang_main – Largeur de ligne Yang sur le graphique principal ;
  • magic_numb – numéro magique utilisé pour la construction d'objets et leur suppression, ainsi que dans le nom de l'indicateur afin de lancer plusieurs indicateurs sur un même graphique.

Ces paramètres sont à leur tour suivis des déclarations des tampons indicateurs, des tampons auxiliaires pour stocker les valeurs de prix et de temps, des variables auxiliaires (stop_data, bars_copied, bars_copied_time, copy_history, copy_time), des tableaux pour stocker des données sur quelle ligne Yin ou Yang le changement de le mouvement du graphique s'est produit, l'heure et le prix de ce changement, le prix central (si Yin est remplacé par Yang sur la barre ou vice versa). Enfin, l'une des variables globales les plus utilisées contenant des données sur le nombre de changements de mouvement du graphique "а" est déclarée.

//+------------------------------------------------------------------+
//|                                                         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. Fonction d'initialisation de l'indicateur

La suivante est la fonction d'initialisation de l'indicateur. Les tampons d'indicateurs et leur indexation (principalement sous forme de séries chronologiques ; comme le graphique de Kagi est plus court que le graphique principal, il est préférable de le dessiner à l'envers) y sont spécifiés. De plus, les valeurs qui ne doivent pas être affichées à l'écran sont définies (EMPTY_VALUE=-1).

Maintenant, nous attribuons le nom de l'indicateur et la précision de l'affichage. Comme mentionné précédemment, le nombre magique est ajouté au nom. Ceci est fait pour fournir un fonctionnement correct de la fonction ChartWindowFind(). Sinon, l'objet graphique dessiné dans la fenêtre des indicateurs n'est affiché qu'au premier indicateur lancé (si plusieurs indicateurs sur un même graphique sont utilisés).

Ensuite, nous attribuons des noms aux lignes de construction, interdisons l'affichage des valeurs numériques actuelles dans la fenêtre d'indicateur, définissons la couleur et la largeur des lignes Yin et Yang, définissons le nombre de niveaux de prix affichés dans la fenêtre d'indicateur.

//+------------------------------------------------------------------+
//| 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. Fonction de copie de données

Examinons maintenant les fonctions de copie de données.

Il y en a deux ici. Le premier sert à copier les prix, tandis que le second sert à copier l'heure d'ouverture de chaque barre. Les deux fonctions conservent leurs valeurs dans les tampons de calcul de l'indicateur précédemment déclaré.

Tout d'abord, considérons la fonction de copie des prix. Paramètres d'entrée de la fonction : tableau de stockage des données, heure de début et de fin de la copie des données (heure actuelle). Le corps de la fonction contient les variables pour répondre à la fonction, le nombre de données (barres) copiées dans le tableau intermédiaire, le tableau dynamique intermédiaire lui-même et le nombre de barres qui doivent être copiées dans le tableau intermédiaire. Le nombre de barres est calculé en fonction du nombre total de barres dans la période donnée et du nombre de barres (variable globale) copiées lors de l'appel de fonction précédent.

Si ce n'est pas la première fois que les données sont copiées, les données de la dernière barre copiée doivent être mises à jour. Pour ce faire, nous réduisons le nombre de mesures copiées d'une unité et augmentons d'une unité le nombre de mesures nouvellement copiées. Nous modifions également la taille du tableau intermédiaire en le préparant à copier les barres.

En fonction des paramètres, nous copions les prix dans le tableau intermédiaire. Si la copie réussit, les données sont copiées du tableau intermédiaire jusqu'à la fin du tableau tampon (tableau de réponse de fonction), attribuent la réponse positive à la fonction et mettent à jour la variable globale stockant les données sur le nombre de barres copiées. Ce type de copie permet de ne copier que quelques dernières mesures en réduisant le temps de copie.

//+------------------------------------------------------------------+
//| 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 fonction suivante est celle de copier les données de temps. Il est différent du précédent en ce qu'il traite d'un autre type de variable - datetime (qui est converti en double lorsqu'il est copié dans un tableau de tampons temporels - tableau de réponses de fonction). Une autre différence est que l'instruction switch() n'est pas utilisée, car il n'est pas nécessaire de sélectionner les données copiées.

//+------------------------------------------------------------------+
//| 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. Fonction de calcul du paramètre de retournement

Étant donné que le paramètre de retournement peut être un point ou un pourcentage, nous avons besoin de la fonction qui calculera le paramètre de retournement en fonction des paramètres de l'indicateur. La fonction n'a qu'un seul paramètre - le prix pour calculer le pourcentage de retournement. La variable pour la réponse est d'abord initialisée par type double et après les calculs, elle est indirectement convertie en type int pour la réponse.

Cela est dû au fait que des nombres à virgule flottante sont utilisés dans les calculs, tandis que la réponse doit être présentée sous forme d'entiers. La sélection est implémentée dans la fonction par l'instruction conditionnelle if-else. La comparaison est effectuée directement avec une variable d'entrée externe (paramètres indicateurs). Le calcul des points est effectué à l'aide d'une équation simple. Tout d'abord, le nombre total de points que le prix a dépassé est défini. Ensuite, le pourcentage spécifié est calculé en fonction de ce nombre et affecté à la variable renvoyée.

//+------------------------------------------------------------------+
//| 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 fonction principale - Dessin du graphique de Kagi

Nous avons déjà examiné toutes les fonctions nécessaires au fonctionnement de la fonction principale - dessin du graphique de Kagi dans la fenêtre de l'indicateur (c'est-à-dire remplir les tampons de l'indicateur). Les paramètres d'entrée de la fonction sont constitués de tableaux de données. Deux d'entre eux sont les tampons de calcul décrits ci-dessus (précédemment copiés Prix et Temps), tous les autres sont les tableaux des tampons de construction graphique de l'indicateur.

Les variables nécessaires au stockage des données sur la construction du graphique sont déclarées à l'intérieur de la fonction. Étant donné que le graphique est construit en utilisant l'instruction de boucle for, nous devrions avoir les données sur l'étape à laquelle la passe précédente s'est terminée. Cela peut être réalisé par six variables : line_move - où le prix a bougé au passage précédent, line_gauge - calibre de ligne (largeur de ligne) - Yin ou Yang, price_1 et price_2 - prix précédent et actuel considéré, price_down et price_up - prix précédent de une épaule et une taille. Comme on peut le voir, price_1 est immédiatement assimilé au premier élément du tableau des prix copiés du fait que cette variable est impliquée dans les calculs avant comparaison dès le début de la boucle.

Étant donné que les tableaux de tampons de la construction graphique de l'indicateur ont un indicateur d'indexation AS_SERIES, ils doivent être remplis dans l'ordre inverse. Pour y parvenir, des tableaux temporels ayant la taille appropriée sont implémentés. Les variables globales de stockage des données sur le temps, les types de lignes, "épaule" et "taille", ainsi que les prix de retournement sont ensuite convertis de la même manière.

Ensuite, tous les tableaux doivent être remplis de valeurs "vides" (-1). Cela se fait à l'aide de deux petites boucles. Il est possible de tout joindre en une seule boucle. Mais en utiliser deux rend toutes les actions effectuées beaucoup plus claires, tandis que le temps d'exécution ne change pas beaucoup. En d'autres termes, les tampons graphiques et les tableaux de temps de calcul sont remplis séparément.

Maintenant, toutes les variables sont déclarées, converties et remplies, afin que la boucle principale puisse être lancée. Il est assez volumineux (bien que le calcul soit effectué assez rapidement) et inclut l'analyse de toutes les barres précédemment copiées.

La boucle passe par toutes les barres copiées et remplit les tableaux préalablement déclarés nécessaires pour continuer à les utiliser. Tout d'abord, définissons tous les tableaux utilisés dans la boucle :

  • yin_int_1 - valeur principale du prix de la ligne Yin verticale (si la ligne Yin verticale est dessinée et que le graphique se déplace vers le bas, il s'agit de la valeur supérieure du prix ; si le graphique se déplace vers le haut, nous avons le cas inverse);
  • yin_int_2 - valeur secondaire du prix de la ligne Yin verticale (si la ligne ascendante est tracée, c'est la valeur supérieure ; si la ligne est descendante, nous avons le cas inverse);
  • yang_int_1 - valeur principale du prix de la ligne Yang verticale ;
  • yang_int_2 - valeur secondaire du prix de la ligne Yang verticale ;
  • lin_yin - valeur de la ligne Yin horizontale (prix de retournement à la ligne Yin) ;
  • lin_yang - valeur de la ligne Yang horizontale (prix de retournement à la ligne Yang) ;
  • time_change - heure de retournement de graphique (construction d'une épaule ou d'une taille) ;
  • time_line - la ligne pendant le retournement Yin = 0 ou Yang = 1 ;
  • time_central_price - la valeur du prix central, le prix au moment où la ligne Yin se transforme en Yang ou vice versa ;
  • time_change_price - la valeur du prix de retournement (épaule ou taille), la variable est commune et ne dépend pas des types de lignes Yin ou Yang.

La valeur du prix actuellement analysé à partir du tampon de prix est affectée à la variable price_2 avant chaque passage de boucle pour une comparaison ultérieure dans les instructions conditionnelles if-else. Après cela, le tableau tampon des données copiées est analysé étape par étape et les tableaux mentionnés ci-dessus sont remplis. Chaque instruction conditionnelle if-else exécute certaines actions en fonction des conditions : direction précédente des lignes du graphique (haut ou bas) et aspect précédent des lignes (Yin ou Yang). Ensuite, les conditions de circulation (que le prix ait dépassé un certain nombre de points) sont vérifiées selon le type de construction (standard ou modifié).

Si tout va bien, de nouvelles variables (éléments de tableau) sont réaffectées ou définies. Le type de ligne (Yin ou Yang) est défini au tout début. En fonction du mouvement et des actions précédentes, la distribution ultérieure est effectuée.

Il y a deux mouvements de prix possibles :

  1. Le prix monte;
  2. Le prix baisse.

Il y a aussi quatre types d'actions précédentes dans chaque direction :

  1. La ligne précédente était Yin et elle s'est déplacée vers le haut ;
  2. La ligne précédente était Yang et elle s'est déplacée vers le haut ;
  3. La ligne précédente était Yin et elle s'est déplacée vers le bas ;
  4. La ligne précédente était Yang et elle s'est déplacée vers le bas.

Ainsi, nous avons huit cas en dehors des deux premières définitions du mouvement initial du graphique (apparition de la première ligne).

Après cela, la boucle principale est terminée. La réaffectation (retournement) et le remplissage des tampons sont effectués pour construire le graphe dans une boucle plus petite constituée du nombre de retournements du graphe de Kagi préalablement défini dans la boucle principale et écrit dans la variable “a”. Quant à la distribution des valeurs de prix supérieures et inférieures et des lignes verticales, tout est assez simple : un simple retournement est effectué. En d'autres termes, les valeurs primaires obtenues précédemment (tableaux ayant les indices 0,1,2,3...) sont affectées aux valeurs finales des tampons (l'élément ayant l'indice "а", c'est-à-dire а,а-1,а-2,а-3... est utilisé comme valeur finale). Pour empêcher les lignes de retournement (horizontales) de coller ensemble, la rotation à l'aide de l'instruction switch est effectuée comme mentionné ci-dessus.

À cela, le travail de la fonction principale de construction du graphique Kagi est terminé.

//+------------------------------------------------------------------+
//| 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. Fonction de création d'un objet graphique "Ligne de tendance"

Examinons maintenant la fonction de création d'un objet graphique "ligne de tendance". Cette fonction est nécessaire pour dessiner Kagi sur le graphique principal.

La fonction est très simple. Il contient les paramètres d'entrée nécessaires à la création de l'objet graphique "ligne de tendance" : nom de l'objet, premier et deuxième prix et points de temps, ainsi que la largeur et la couleur de la ligne. Le corps de la fonction contient la fonction de création d'objet graphique et six fonctions de modification des propriétés de l'objet graphique.

//+------------------------------------------------------------------+
//| 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. Dessin de Kagi sur le graphique principal

La fonction suivante qui s'applique plusieurs fois à la précédente est la fonction de construction Kagi sur le graphique principal. Les variables globales remplies dans la fonction principale précédemment examinée de la construction du graphique de Kagi sont utilisées comme variables d'entrée : le tableau des prix de retournement ("épaules" et "taille"), le tableau de changement et les prix centraux (le prix auquel la ligne Yin se transforme en Yang ou vice versa), tableau de temps de retournement (situé en temps réel, l'indice de tableau [z-1] est utilisé pour marquer le début de retournement), le tableau du type de la ligne, à laquelle le retournement s'est produite (il est également un élément en avant, comme le tableau de temps).

Le corps de la fonction consiste en une boucle. La boucle est divisée en deux parties : dessin des lignes verticales et horizontales. Le premier est également divisé en deux : dessin des verticales compte tenu du changement de ligne (changement de prix central) et de l'absence de changement. Notez les paramètres transférés de la fonction de création d'objet "ligne de tendance".

Le nommage est effectué à plusieurs reprises. Le nom de l'objet commence par un nombre magique (nécessaire pour supprimer les objets d'un certain indicateur), puis son type est fixé et enfin l'index est attribué. L'index est mis à jour à chaque passage de la boucle.

//+------------------------------------------------------------------+
//| 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. Implémentation d'étiquettes supplémentaires

Comme je l'ai déjà mentionné ci-dessus, l'indicateur implémente des étiquettes supplémentaires. Examinons la fonction fournissant ces étiquettes sur le graphique principal. Il n'y a que deux types d'étiquettes ici : les étiquettes de prix de retournement et de temps de retournement affichées via "étiquette de prix" et "étiquette verticale". Les paramètres suivants sont passés en entrée : attribut du dessin de l'étiquette de prix de retournement et de la couleur de l'étiquette, attributs du dessin de l'étiquette de l'heure de retournement et du changement de couleur de l'étiquette, les première et deuxième couleurs de l'heure de retournement.

L'ensemble de la fonction est divisé en deux parties : la première partie est responsable des étiquettes de temps, tandis que la seconde - des étiquettes de prix. Les deux parties de la fonction sont constituées des boucles limitées par le nombre de retournements de graphiques (variable “a”). L'instruction conditionnelle if-else est définie avant la boucle. La déclaration vérifie la nécessité de leur dessin en fonction des paramètres de l'indicateur.

La première boucle crée des étiquettes temporelles, la définition du nom de l'objet est effectuée au début de la boucle (le principe de génération de nom a été décrit ci-dessus). Ensuite, la couleur est sélectionnée en fonction de la ligne du tableau de type de ligne déclaré globalement (si le paramètre est défini) et d'autres paramètres sont appliqués à la ligne.

La deuxième boucle est chargée de créer des étiquettes de prix de retournement. Tout d'abord, le nom de l'objet est généré. Ensuite, la sélection de l'index du tableau temporel est définie selon que Kagi doit être construit sur le graphique principal ou non. si cela n'est pas fait, les étiquettes seront situées "en l'air" et on ne verra pas assez à partir de quel endroit le retournement s'est produit. Ensuite, l'objet de type "étiquette de prix" est créé et configuré.

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

Voyons maintenant comment nous pouvons définir les étiquettes dans la fenêtre d'indicateur.

Toutes les étiquettes de la fenêtre d'indicateur sont principalement des étiquettes de prix, et il n'y en a que deux types : les étiquettes de prix de retournement et les niveaux de prix. Il existe deux types de tracé des niveaux de prix : sur les retournement du graphique et à égale distance de toute la fourchette de prix du graphique. Le premier type peut changer la couleur des niveaux de deux manières : selon le type de ligne (Yin ou Yang) et selon le retournement (haut ou bas).

Ainsi, la fonction elle-même est divisée en deux boucles : la première est chargée de créer des étiquettes de prix de retournement, la seconde s'occupe de la désignation des niveaux de prix. Ce dernier est encore divisé en deux types : étiquette à chaque retournement ou étiquettes sur toute la gamme de prix à un niveau égal.

Cette fonction est différente de la précédente en ce qu'elle a des limitations sur le nombre d'étiquettes de prix et de niveaux en raison du fait qu'elles surchargent en grand nombre le graphique ce qui complique sa compréhension.

En raison de cette fonctionnalité, les deux boucles sont limitées par le nombre de passes spécifié dans les paramètres de l'indicateur (nombre d'étiquettes de prix et de niveaux). Une telle approche est dangereuse car le nombre de retournement peut s'avérer bien inférieur au nombre d'étiquettes de prix définies dans les paramètres. Pour cette raison, la présence de retournement lors de chaque passage en boucle est vérifiée pour dessiner une étiquette de prix ou un niveau.

La seule exception consiste à tracer les niveaux de prix sur toute la gamme de prix sur une distance égale. La génération d'objets graphiques de type "Étiquette de prix" s'effectue dans les coordonnées dans l'ordre inverse, c'est-à-dire que les étiquettes sont placées de la date actuelle au passé. Il en va de même pour les niveaux de prix : les niveaux de prix actuels sont générés en premier, suivis des précédents. Les exceptions sont les niveaux de prix qui ne dépendent pas des retournements du graphique.

Les changements de couleur au niveau des prix sont effectués à l'aide d'instructions conditionnelles if-else en fonction des paramètres.

//+------------------------------------------------------------------+
//| 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. Suppression d'objets graphiques créés précédemment

On sait déjà que cet indicateur est riche en objets graphiques. Il est temps de réfléchir à la manière dont nous pouvons les supprimer rapidement et efficacement.

Cette tâche est exécutée par la fonction de suppression des objets graphiques. Le nom initial et le nombre d'objets sont utilisés comme paramètres de fonction. Comme lors de la création, le nom de l'objet doit contenir le nombre magique et le nom d'un type d'objet. L'appel de fonction dans le programme est limité par le nombre d'objets dépassant leur existence possible. Cependant, cela n'affecte pas la fonctionnalité de l'indicateur.

//+------------------------------------------------------------------+
//| 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. Fonction de lancement de la construction du graphique

Maintenant, après avoir examiné toutes les fonctions de calcul et de construction du graphique de Kagi, ainsi que de création et de suppression d'objets, nous devrions envisager une autre petite fonction pour vérifier l'arrivée de la nouvelle barre. La fonction est assez simple et a un paramètre d'entrée - la période analysée. La réponse de la fonction est également très simple. Il est de type bool et contient la réponse indiquant si une nouvelle barre est présente ou non. La base du corps de la fonction est l'instruction switch qui passe la commande à ses différentes instructions en fonction de la période.

Dans l'exemple, la fonction couvre toute la plage de périodes, bien qu'une seule période puisse également être utilisée.

L'algorithme de la fonction a été repris du code IsNewBar : l'heure de la dernière ouverture de barre est comparée à la valeur de temps précédemment définie. Si les valeurs sont différentes, il y a une nouvelle barre. La nouvelle valeur est attribuée comme précédemment définie et la réponse de la fonction est considérée comme positive. Si l'heure d'ouverture de la dernière barre coïncide avec la valeur temporelle précédemment déterminée, alors la nouvelle barre n'est pas encore apparue et la réponse de la fonction est négative.

//+------------------------------------------------------------------+
//| 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. Fonctions OnCalculate() et OnChartEvent()

Toutes les fonctions décrites ci-dessus sont regroupées dans la fonction du même nom – Func Consolidation. Cette fonction est lancée à chaque fois qu'une nouvelle barre apparaît dans la fonction OnCalculate() et lorsque la touche "R" est enfoncée depuis la fonction OnChartEvent(). 

Avant la génération ou la mise à jour du graphe, la fonction de suppression de tous les objets graphiques est appelée dans la fonction de consolidation (Func Consolidation). Comme il y a beaucoup d'objets et qu'ils sont divisés en étiquettes de prix du graphique principal et de la fenêtre d'indicateur, des lignes verticales indiquant le temps de retournement, ainsi que des lignes de tendance verticales et horizontales Yin et Yang, le nombre général d'appels de fonction est de 7.

Ensuite, les données d'historique sont copiées par prix et heure. La fonction principale de construction du graphique Kagi est lancée par la suite. Après cela, la fonction permettant de placer toutes les étiquettes de prix sur le graphique principal et la fenêtre d'indicateur est appelée. Enfin, Kagi est généré sur le graphique principal et la fonction de redessiner les objets est lancée.

//+------------------------------------------------------------------+
//| 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. Fonction OnDeinit()

La suppression de tous les objets est effectuée dans la fonction de désinitialisation de l'indicateur.

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

Passons maintenant à l'utilisation de l'indicateur dans la pratique.


4. Utilisation du graphique Kagi en pratique

Il existe de nombreuses stratégies de trading basées sur le graphique Kagi. Nous allons en examiner quelques-uns.

Commençons par la stratégie la plus populaire : vendre lorsque le Yang se transforme en Yin et acheter dans le cas contraire. Ceci est montré dans la Fig. 4:

La stratégie d'achat et de vente pendant les changements de ligne

Fig. 4. Vendre quand Yang se change en Yin et acheter dans le cas contraire 

Comme le montre la figure 4 (EURUSD M30, 5 points), cette stratégie affiche de bons résultats. Le chiffre affiche 8 points pour 4 signaux, le premier (1) montre que la position longue devrait être ouverte à 1,3518, ce qui semble correct puisque le prix atteint alors environ 1,3560 soit 42 points par jour. C'est un bon résultat.

Le point suivant (2) recommande de vendre à 1,3519. Comme nous pouvons le voir, le prix baisse en franchissant le niveau de 1,3485 (et couvrant 34 points) pendant environ deux heures.

Passons au point (3). La position longue est ouverte à 1,3538 et le prix monte pour atteindre 1,3695. Ainsi, le bénéfice comprend déjà 157 points pour un jour et demi. Bien sûr, ce sont les profits les plus élevés possibles mais le résultat est quand même assez bon.

La prochaine stratégie de trading recule par rapport à la ligne de tendance illustrée à la figure 5 (EURUSD M30, 5 points), du 7 au 18 octobre :

Revenir en arrière de la ligne de tendance

Fig. 5. Revenir en arrière de la ligne de tendance

Nous pouvons aller plus loin et trader en suivant les canaux. Un exemple de recherche de canal peut être examiné sur la figure 6 (EURUSD H1, 5 points), à peu près à la même période :

Trading par canaux

Fig. 6. Trading par canaux

La stratégie la moins populaire basée sur le fait qu'après 7-10 augmentations successives des "épaules" ou diminutions des "tailles", il y aura certainement un retournement (chute ou hausse).

Ceci est illustré dans la Figure 7 (GBPUSD H4, 25 points), du 10 juillet au 18 octobre :

7-10 "épaules" croissantes ou "tailles" décroissantes successivement

Fig. 7. 7-10 "épaules" croissantes ou "tailles" décroissantes successivement

Comme on peut le voir sur l'image, sept épaules ascendantes sont suivies d'une baisse assez importante à peu près égale à la moitié de la hausse précédente (environ 300 points).

Examinons la stratégie "Trading via une étiquette de prix" pour montrer la nécessité d'utiliser des paramètres d'indicateur supplémentaires. L'idée est d'entrer sur le marché lorsque le prix dépasse (achat) ou passe en dessous (vente) de l'étiquette de prix précédente.

La stratégie est illustrée à la figure 8 (GBPUSD H4, 30 points, construction modifiée) :

Trading via une étiquette de prix

Fig. 8. Trading via une étiquette de prix 

Les flèches rouges sur la figure 8 indiquent quand acheter ou vendre. Les flèches se déplacent depuis l'étiquette de prix précédente et affichent les emplacements où les étiquettes de prix précédentes ont été franchies.

Les étiquettes temporelles servent principalement de pointeurs de direction de tendance. Étant donné que la couleur des étiquettes temporelles peut être modifiée par rapport au type de ligne et que le type de ligne Yin ou Yang indique la direction ou le retournement de la tendance, la couleur peut nous aider à définir l'humeur actuelle du marché.

Par exemple, prenons le graphique de l'action #IBM (H4, 1%, construction standard) présenté à la Fig. 9 :

Définition de la direction de la tendance à l'aide d'étiquettes temporelles

Fig. 9. Définition de la direction de la tendance à l'aide d'étiquettes temporelles

Le graphique montre que les lignes bleues sont principalement situées en haut du graphique, tandis que les rouges - en bas.


Conclusion

Le graphique Kagi peut être utilisé avec succès pour le trading sur le marché comme base de stratégie ou comme outil auxiliaire pour une analyse plus précise.

Dans cet article, j'ai examiné le code lui-même et certaines spécificités de construction de l'indicateur. L'objectif principal a été la création de l'indicateur multifonctionnel contenant tous les éléments nécessaires avec quelques fonctionnalités supplémentaires qui peuvent être désactivées.

Je serai heureux d'envisager de nouvelles idées et améliorations pour l'indicateur et, peut-être, de les mettre en œuvre à l'avenir. Aussi, merci de me faire part de vos commentaires. Je me ferai un plaisir de répondre à vos questions concernant l'indicateur.

Cet article poursuit la série consacrée à l'élaboration d'indicateurs pour la construction des graphiques du passé. L'article précédent est disponible ici. La série est à suivre et j'espère vous revoir bientôt. Merci pour ton intérêt! Je vous souhaite un trading réussi, ainsi que des codes optimisés et stables.


Traduit du russe par MetaQuotes Ltd.
Article original : https://www.mql5.com/ru/articles/772

Fichiers joints |
bkcv.mq5 (44.19 KB)
Econometrics - Prévisions à un stade précoce de l’EURUSD Econometrics - Prévisions à un stade précoce de l’EURUSD
L'article se concentre sur les prévisions d'avance pour l'EURUSD à l'aide du logiciel EViews et sur une évaluation plus approfondie des résultats des prévisions à l'aide des programmes d'EViews. La prévision implique des modèles de régression et est évaluée au moyen d'un Expert Advisor développé pour MetaTrader 4.
Création d'un Expert Advisor multi-devises multi-systèmes Création d'un Expert Advisor multi-devises multi-systèmes
L'article présente une structure pour un Expert Advisor qui trade plusieurs symboles et utilise plusieurs systèmes de trading simultanément. Si vous avez déjà identifié les paramètres d'entrée optimaux pour tous vos EA et obtenu de bons résultats de backtesting pour chacun d'eux séparément, demandez-vous quels résultats vous obtiendriez si vous testiez tous les EA simultanément, avec toutes vos stratégies réunies.
L’algorithme de génération de ticks dans le testeur de stratégie du terminal MetaTrader 5 L’algorithme de génération de ticks dans le testeur de stratégie du terminal MetaTrader 5
MetaTrader 5 nous permet de simuler le trading automatique, au sein d’un testeur de stratégie intégré, en utilisant l’Expert Advisors et le MQL5 language. Ce type de simulation est appelé test d’Expert Advisors, et peut être mis en œuvre en utilisant l’optimisation multithread, ainsi que simultanément sur un certain nombre d’instruments. Afin de fournir un test approfondi, une génération de ticks basée sur l’historique des minutes disponibles doit être effectuée. Cet article fournit une description détaillée de l’algorithme, par lequel les ticks sont générés pour les tests historiques dans le terminal client MetaTrader 5.
Le MQL5 Cookbook : Développement d'un indicateur de volatilité multi-symboles dans MQL5 Le MQL5 Cookbook : Développement d'un indicateur de volatilité multi-symboles dans MQL5
Dans cet article, nous examinerons le développement d'un indicateur de volatilité multi-symboles. Le développement d'indicateurs multi-symboles peut présenter quelques difficultés pour les développeurs MQL5 novices que cet article aide à clarifier. Les problèmes majeurs qui se posent au cours du développement d'un indicateur multi-symboles concernent la synchronisation des données d'autres symboles par rapport au symbole courant, le manque de certaines données d'indicateur et l'identification du début des "vraies" barres d'une trame de temps donnée. Toutes ces questions seront examinées de près dans l'article.