English Русский 中文 Español Deutsch 日本語 Português 한국어 Italiano Türkçe
L'exemple simple de création d'un indicateur à l'aide d'une logique floue

L'exemple simple de création d'un indicateur à l'aide d'une logique floue

MetaTrader 5Trading | 17 novembre 2021, 16:38
165 0
Максим Востров
Максим Востров

Introduction

L’utilisation de diverses méthodes d’analyse des marchés financiers devient de plus en plus populaire parmi les traders ces dernières années. J’aimerais apporter ma contribution et expliquer comment faire un bon indicateur en rédigeant quelques dizaines de lignes de code. Aussi, je vais vous révéler brièvement les bases de la logique floue.

Quiconque s’intéresse à cette question et souhaite l’explorer plus en profondeur peut lire les ouvrages suivants:

1.  Leonenkov А. « Fuzzy Simulation in MATLAB and fuzzyTECH » (en russe).
2.  Bocharnikov V.  « Fuzzy Technology: Contexte mathématique. Pratique de la Simulation en Économie » (en russe).
3.  S.N. Sivanandam, S. Sumathi, S.N. Deepa. Introduction à la logique floue à l’aide de MATLAB.
4.  C. Kahraman. Fuzzy Engineering Economics with Applications (Études en flou et informatique logicielle).


1. Notions de Base sur la Logique Floue

Comment pouvons-nous expliquer à nos machines informatiques la signification d’expressions aussi simples que « ... un peu plus... », « ... trop vite... », « ... presque rien... »? En fait, c’est tout à fait possible en utilisant les éléments de la théorie des ensembles flous, ou plutôt les soi-disant « fonctions d’appartenance ». Voici un exemple de А. Le livre de Leonenkov :

Décrivons la fonction d’appartenance à l’expression « café chaud »: la température du café doit être considérée comme comprise entre 0 et 100 degrés Celsius pour la simple raison qu’à des températures inférieures à 0 degré, il se transformera en glace, tandis qu’à des températures supérieures à 100 degrés, il s’évaporera. Il est tout à fait évident qu’une tasse de café avec une température de 20 degrés ne peut pas être appelée chaude, c’est-à-dire que la fonction d’appartenance dans la catégorie « chaud » est égale à 0, tandis qu’une tasse de café avec une température de 70 degrés appartient définitivement à la catégorie « chaud » et, par conséquent, la valeur de la fonction est égale à 1 dans ce cas.

En ce qui concerne les valeurs de température ​qui se situent entre ces deux valeurs extrêmes, la situation n’est pas si définitive. Certaines personnes peuvent considérer qu’une tasse de café avec une température de 55 degrés est « chaude », tandis que d’autres peuvent la considérer comme « pas si chaude ». C’est le « flou ».

Néanmoins, on peut imaginer l’aspect approximatif de la fonction d’appartenance : elle est « croissante de façon monotone » :


La figure ci-dessus indique la fonction d’appartenance « linéaire à segments ».

Ainsi, la fonction peut être définie par l’expression analytique suivante :


Nous utiliserons ces fonctions pour notre indicateur.


2. Fonction d’Appartenance

D’une manière ou d’une autre, la tâche de tout indicateur technique est de déterminer l’état actuel du marché (plat, tendance haussière, tendance baissière), ainsi que la génération de signaux d’entrée / sortie du marché. Comment cela peut-il être fait avec l’aide des fonctions d’appartenance? Assez facile.

Tout d’abord, nous devons définir les conditions de limites. Ayons les conditions de limites suivantes: pour « 100% tendance haussière », ce sera le croisement de l’EMA ayant la période 2, basé sur le prix typique (H + L + C) / 3 avec la bordure supérieure des enveloppes ayant les paramètres 8, 0,08, SMA, Close, tandis que pour « tendance baissière à 100% », ce sera le croisement de la même EMA avec la bordure inférieure des enveloppes. Tout ce qui se trouve entre ces conditions sera considéré comme étant plat. Ajoutons une enveloppe de plus ayant les paramètres 32, 0.15, SMA, Close. 

En conséquence, nous obtiendrons deux fonctions d’appartenance identiques. Le signal d’achat sera activé lorsque les deux fonctions sont égales à 1, tandis que le signal de vente sera activé lorsque les deux fonctions sont respectivement égales à -1. Comme il est pratique de construire des graphiques avec la plage de -1 à 1, le graphique subséquent sera obtenu comme la moyenne arithmétique de deux fonctions F(x)= (f1(x)+f2(x))/2.

Voici à quoi cela ressemble sur le graphique:


Dans ce cas, la fonction d’appartenance aura la représentation graphique suivante :


Analytiquement, elle peut être écrite comme suit:

,

où a et b sont respectivement des lignes d’enveloppe supérieures et inférieures, tandis que х est une valeur de EMA(2).

Une fois la fonction définie, nous pouvons maintenant passer à l’écriture du code de l’indicateur.


3. Création du Code du Programme

Tout d’abord, nous devons définir ce que nous allons dessiner et comment nous allons dessiner.

Les résultats des calculs de la fonction d’appartenance seront affichés sous forme de ligne respectivement - rouge et bleue.

La moyenne arithmétique sera affichée sous forme d’histogramme à partir de la ligne zéro et peinte dans l’une des cinq couleurs en fonction de la valeur de la fonction subséquente :

DRAW_COLOR_HISTOGRAM style de dessin sera utilisé pour cela.

Dessinons des rectangles bleus et rouges comme signaux d’achat/sortie sur les barres d’histogramme, dont les valeurs sont égales à 1 ou -1.

Maintenant, il est temps d’exécuter MetaEditor et démarrer. Nouveau->Indicateur Personnalisé >Suivant... Remplissez le champ « Paramètres » :


 Créez les tampons :


Après avoir cliqué sur le bouton « Terminer », nous recevons un code source et commençons à l’améliorer.

Tout d’abord, définissons le nombre de tampons. Sept d’entre eux ont déjà été créés par l’Assistant (5 pour les données, 2 pour la couleur). Nous avons besoin de 5 de plus.

#property indicator_minimum -1.4 // Setting fractional values
#property indicator_maximum 1.4  // Expert Advisors wizard ignores fractional parts for some reason
#property indicator_buffers 12   // Changing the value from 7 to 12 (5 more buffers have been added)
Modifions les paramètres d’entrée:
input string txt1="----------";
input int                  Period_Fast=8;
input ENUM_MA_METHOD        Method_Fast = MODE_SMA; /*Smoothing method*/ //moving average smoothing method 
input ENUM_APPLIED_PRICE    Price_Fast  = PRICE_CLOSE;
input double               Dev_Fast=0.08;
input string txt2="----------";
input int                  Period_Slow=32;
input ENUM_MA_METHOD        Method_Slow = MODE_SMA;
input ENUM_APPLIED_PRICE    Price_Slow  = PRICE_CLOSE;
input double               Dev_Slow=0.15;  /*Deviation parameter*/
input string txt3="----------";
input int                  Period_Signal=2;
input ENUM_MA_METHOD        Method_Signal = MODE_EMA;
input ENUM_APPLIED_PRICE    Price_Signal  = PRICE_TYPICAL;
input string txt4="----------";

Les commentaires suivant la variable déclarée sont très pratiques. Le texte des commentaires est inséré dans la fenêtre des paramètres de l’indicateur.

La possibilité de créer des listes est également très utile:


Réserver les variables pour les poignées d’indicateurs et les tampons :

int Envelopes_Fast;     // Fast envelope
int Envelopes_Slow;     // Slow envelope
int MA_Signal;          // Signal line

double Env_Fast_Up[];   // Fast envelope upper border
double Env_Fast_Dn[];   // Fast envelope lower border

double Env_Slow_Up[];   // Slow envelope upper border
double Env_Slow_Dn[];   // Slow envelope lower border

double Mov_Sign[];      // Signal line

Maintenant, passez à la fonction OnInit().

Ajoutons un peu de beauté: indiquez le nom de l’indicateur et supprimez les zéros décimaux supplémentaires:

IndicatorSetInteger(INDICATOR_DIGITS,1); // setting display accuracy, we do not need some outstanding accuracy values 
string name;                           // indicator name 
StringConcatenate(name, "FLE ( ", Period_Fast, " , ", Dev_Fast, " | ", Period_Slow, " , ", Dev_Slow, " | ", Period_Signal, " )"); 
IndicatorSetString(INDICATOR_SHORTNAME,name);

et ajoutez les tampons manquants :

SetIndexBuffer(7,Env_Fast_Up,INDICATOR_CALCULATIONS);
SetIndexBuffer(8,Env_Fast_Dn,INDICATOR_CALCULATIONS);
SetIndexBuffer(9,Env_Slow_Up,INDICATOR_CALCULATIONS);
SetIndexBuffer(10,Env_Slow_Dn,INDICATOR_CALCULATIONS);
SetIndexBuffer(11,Mov_Sign,INDICATOR_CALCULATIONS); 

Le paramètre INDICATOR_CALCULATIONS indique que les données de la mémoire tampon sont uniquement nécessaires pour les calculs intermédiaires. Il ne sera pas affiché sur le graphique.

Notez comment les indicateurs avec des tampons de couleur sont déclarés :

SetIndexBuffer(4,SignalBuffer1,INDICATOR_DATA);      // All indicator buffers at first 
SetIndexBuffer(5,SignalBuffer2,INDICATOR_DATA);      // as this is Color Histogram2, then it has 2 data buffers
SetIndexBuffer(6,SignalColors,INDICATOR_COLOR_INDEX);// the color buffer comes next.

Remplissage des poignées :

Envelopes_Fast = iEnvelopes(NULL,0,Period_Fast,0,Method_Fast,Price_Fast,Dev_Fast);
Envelopes_Slow = iEnvelopes(NULL,0,Period_Slow,0,Method_Slow,Price_Slow,Dev_Slow);
MA_Signal      = iMA(NULL,0,Period_Signal,0,Method_Signal,Price_Signal);

Tous les travaux avec la fonction OnInit() sont terminés.

Créons maintenant la fonction qui calculera la valeur de la fonction d’appartenance:

double Fuzzy(double x,double a, double c)
{
double F;
     if (a<x)          F=1;                 // 100% uptrend
else if (x<=a && x>=c)  F=(1-2*(a-x)/(a-c));// Flat
else if (x<c)           F=-1;               // 100% downtrend
return (F);
}

Les préparatifs sont terminés. Les variables et les tampons sont déclarés, les poignées sont attribuées.

Il est maintenant temps de passer à la fonction de base OnCalculate().

Tout d’abord, écrivons les valeurs des indicateurs nécessaires dans les tampons intermédiaires. Utilisez la fonction CopyBuffer() :

CopyBuffer(Envelopes_Fast,  // Indicator handle
           UPPER_LINE,      // Indicator buffer
           0,              // The point to start 0 - from the very beginning
           rates_total,    // How many to be copied - All 
           Env_Fast_Up);   // The buffer the values are written in
// - the rest are done in a similar way
CopyBuffer(Envelopes_Fast,LOWER_LINE,0,rates_total,Env_Fast_Dn);
CopyBuffer(Envelopes_Slow,UPPER_LINE,0,rates_total,Env_Slow_Up);
CopyBuffer(Envelopes_Slow,LOWER_LINE,0,rates_total,Env_Slow_Dn);
CopyBuffer(MA_Signal,0,0,rates_total,Mov_Sign);

 Ici, nous devons ajouter le code pour l’optimisation des calculs (seul le recalcul de la dernière barre est effectué):

// declaring start variable for storing the index of the bar, recalculation of the indicator buffers will be
// carried out from.

int start;              
if (prev_calculated==0// in case no bars have been calculated
    {
    start = Period_Slow; // not all indicators have been calculated up to this value, therefore, there is no point in executing the code
    }
else start=prev_calculated-1;

for (int i=start;i<rates_total;i++)
      {
      // All remaining code will be written here
      }

Il ne reste plus grand-chose du code.

Définition des paramètres x, a, b, exécution du calcul de la valeur de la fonction d’appartenance et écriture dans le tampon approprié :
double x = Mov_Sign[i]; // Signal
// Setting the first membership function parameters:
double a1 = Env_Fast_Up[i]; // Upper border
double b1 = Env_Fast_Dn[i];
// setting the first membership function value and writing it to the buffer
Rule1Buffer[i] = Fuzzy(x,a1,b1);
// Setting the second membership function parameters:
double a2 = Env_Slow_Up[i]; // Upper border
double b2 = Env_Slow_Dn[i];
// setting the second membership function value and writing it to the buffer
Rule2Buffer[i] = Fuzzy(x,a2,b2);

Deux lignes d’indicateurs sont construites.

Calculons maintenant la valeur obtenue.

ResultBuffer[i] = (Rule1Buffer[i]+Rule2Buffer[i])/2;

Ensuite, nous devons peindre les barres d’histogramme dans les couleurs appropriées: vu que nous avons cinq couleurs, donc ResultColors[i] peut avoir n’importe quelle valeur de 0 à 4.

Généralement, le nombre de couleurs possibles est de 64. Par conséquent, c’est une belle opportunité d’appliquer ses talents créatifs

for (int ColorIndex=0;ColorIndex<=4;ColorIndex++) 
    { 
    if (MathAbs(ResultBuffer[i])>0.2*ColorIndex && MathAbs(ResultBuffer[i])<=0.2*(ColorIndex+1)) 
        { 
        ResultColors[i] = ColorIndex; 
        break; 
        } 
    }

Ensuite, nous devons dessiner les rectangles de signal. Nous utiliserons le style de dessin DRAW_COLOR_HISTOGRAM2

Il dispose de deux tampons de données avec une barre d’histogramme et un tampon de couleur en cours de construction entre eux.

Les valeurs des tampons de données seront toujours les mêmes : 1,1 et 1,3 pour un signal d’achat, -1,1 et -1,3 pour un signal de vente, respectivement.

EMPTY_VALUE indiquera l’absence du signal

      if (ResultBuffer[i]==1)
        {
        SignalBuffer1[i]=1.1;
        SignalBuffer2[i]=1.3;
        SignalColors[i]=1;
        }
      else if (ResultBuffer[i]==-1)
        {
        SignalBuffer1[i]=-1.1;
        SignalBuffer2[i]=-1.3;
        SignalColors[i]=0;
        }
      else
        {
        SignalBuffer1[i]=EMPTY_VALUE;
        SignalBuffer2[i]=EMPTY_VALUE;
        SignalColors[i]=EMPTY_VALUE;
        }

Cliquez sur « Compiler » et le tour est joué!



Conclusion

Que peut-on ajouter d’autre? Dans cet article, j’ai abordé l’approche la plus élémentaire de la logique floue.

Il y a assez d’espace ici pour diverses expériences. Par exemple, nous pouvons utiliser la fonction suivante:


Je pense qu’il ne vous sera pas difficile de rédiger l’expression analytique et de trouver des conditions appropriées.

Bonne chance!

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

Fichiers joints |
Créez votre propre Veille du Marché en utilisant les classes de bibliothèque standard Créez votre propre Veille du Marché en utilisant les classes de bibliothèque standard
Le nouveau terminal client MetaTrader 5 et le langage MQL5 offrent de nouvelles opportunités pour présenter des informations visuelles au trader. Dans cet article, nous proposons un ensemble de classes universel et extensible, qui gère tout le travail d'organisation de l'affichage des informations textuelles arbitraires sur le graphique. L'exemple de l'indicateur Veille du Marché est présenté.
Assistant MQL5 : Création d'Expert Advisors sans programmation Assistant MQL5 : Création d'Expert Advisors sans programmation
Souhaitez-vous tester une stratégie de trading sans perdre de temps en programmation ? Dans l'assistant MQL5, vous pouvez simplement sélectionner le type de signaux de trading, ajouter des modules de positions de suivi et de gestion de l'argent - et votre travail est terminé ! Créez vos propres implémentations de modules ou commandez-les via le service Jobs - et combinez vos nouveaux modules avec ceux existants.
calcul de moyenne des Séries de Prix pour les Calculs Intermédiaires Sans Utiliser de Tampons Supplémentaires calcul de moyenne des Séries de Prix pour les Calculs Intermédiaires Sans Utiliser de Tampons Supplémentaires
Cet article concerne les algorithmes traditionnels et inhabituels de calcul de moyenne regroupés dans les classes les plus simples et à type unique. Ils sont destinés à une utilisation universelle dans presque toutes les élaborations d'indicateurs. J'espère que les classes proposées seront une bonne alternative aux appels « encombrants » d'indicateurs personnalisés et techniques.
Gaz neuronal en croissance : Implémentation en MQL5 Gaz neuronal en croissance : Implémentation en MQL5
L'article étale un exemple de comment élaborer un programme MQL5 mettant en implémentant l'algorithme adaptatif de groupement appelé Growing neural gas (GNG). L'article est destiné aux utilisateurs qui ont étudié la documentation du langage et qui ont certaines compétences en programmation et des connaissances de base dans le domaine de la neuro-informatique.