L'exemple simple de création d'un indicateur à l'aide d'une logique floue
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:
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
- Applications de trading gratuites
- Plus de 8 000 signaux à copier
- Actualités économiques pour explorer les marchés financiers
Vous acceptez la politique du site Web et les conditions d'utilisation