J'ai fait un de ces trucs une fois...

 

Un jour, j'ai soudain réalisé une chose simple : l'approximation par les moindres carrés consiste essentiellement à minimiser une combinaison linéaire de vecteurs. C'est-à-dire qu'une sorte de fonction d'approximation universelle peut être fabriquée. C'est chose faite, voici donc le titre de la fonction :

//+------------------------------------------------------------------+
//  Аппроксимация методом наименьших квадратов                       |
//+------------------------------------------------------------------+
bool LSA(double& V[], int M, int N, double& A[], double& C[]) {
// Имеется N векторов размером M
// и вектор их линейной комбинации Y размером естестственно тоже M.
// На вход функции они подаются в виде матрицы V[0..M-1][0..N],
// где Y размещён в столбце N 
// На выходе мы должны получить вектор коэффициентов C размером M.
// Нам нужна также матрица A[N][N+1] для размещения коэффициентов системы уравнений

Détail important, tous les tableaux V et A sont en réalité unidimensionnels, le tableau A est purement fonctionnel, mais le tableau V doit être rempli correctement.

Il a également besoin d'une fonction pour résoudre un système d'équations linéaires. Lorsque j'ai inventé cela, je ne connaissais qu'une seule implémentation dans MQL, la méthode gaussienne utilisée par ANG3110 pour la régression polynomiale. Naturellement, j'ai pris la voie de la moindre résistance et utilisé cet algorithme particulier pour la fonction. En d'autres termes, il existe des algorithmes plus efficaces, d'autant plus que la matrice est symétrique, mais je ne les ai pas utilisés.

Comment l'utiliser :

Tout d'abord, nous décidons de la fonction que nous allons approximer. Soit une régression linéaire, par exemple. C'est-à-dire que nous aurons une combinaison linéaire de A*1 + B*X, juste deux vecteurs, un vecteur unitaire et l'argument lui-même.

Créons des tableaux de travail et allouons-leur de la mémoire quelque part dans init()

double V[];
double A[],С[];

...

  ArrayResize(A,6);  // размер N*(N+1)
  ArrayResize(C,2);  // размер N
  ArrayResize(V,M*3);  // M*(N+1), M - не что иное как размер выборки

Il ne reste plus qu'à remplir correctement le tableau V et à calculer les coefficients. Cela peut être fait comme suit :

    ind = 0;
    Stop = Start + M;
// Заполняем векторы
    for(pos = Start; i < Stop; i++) {
     V[ind] = 1.0;
     ind++;
     V[ind] = pos;
     ind++;
     V[ind] = Close[pos];   
     ind++;
    }
// Считаем коэффициенты
   LSA(V, M, N, A, C);

C'est fait, la régression linéaire C[0] + C[1]*pos est prête.

La première chose à faire est de vérifier l'algorithme. À cette fin, sur la base de l'indicateur ang_PR (Din)-v1.mq4 ( ANG3110 ), nous avons écrit un indicateur de régression polynomiale en utilisant LSA et avons comparé les résultats. Les résultats coïncidaient visuellement, c'était la fin du test :). L'indicateur LSA_PR.mq4 est joint.

Dossiers :
pr_lsa.mq4  7 kb
 

Tout cela s'est passé il y a bien longtemps, et récemment je m'en suis souvenu et j'ai décidé de remettre en action l'outil que j'avais fabriqué.

Ma première pensée a été de rechercher une périodicité dans le graphique de cotation. On peut se demander pourquoi, car il existe une transformée de Fourier discrète (DFT) pour la recherche des harmoniques. Mais la FFT ne donnera que les harmoniques dont la période est inférieure à la longueur de l'échantillon. Nous pouvons maintenant essayer d'adapter au graphique des prix des harmoniques dont la période est plus longue que la longueur de l'échantillon. Bien sûr, l'ajustement réussi ne sera pas un argument "à toute épreuve" en faveur de son existence réelle, la question du degré de confiance dans une approximation particulière doit être décidée séparément.

Dans l'indicateur ci-joint LSA_SinLRR.mq4 la tendance linéaire est calculée avant d'essayer sur l'harmonique. Il est calculé en utilisant l'horizon supérieur. Toutes les longueurs d'échantillon possibles dans une certaine gamme sont testées et celle qui a l'erreur RMS minimale sur l'extérieur de l' échantillon (qui est pris comme 1/4 de la taille de l'échantillon de base) est sélectionnée.

La période harmonique est liée à la longueur de l'échantillon, en la multipliant par un facteur donné. S'il est égal à 2, par exemple, alors l'échantillon contiendra une demi-période de l'harmonique, et s'il est égal à 0,5, alors deux périodes. La longueur de l'échantillon lui-même est déterminée de la même manière que pour la régression linéaire, mais la recherche est effectuée dans l'horizon le plus bas.

Pour réduire la quantité de calculs, une étape d'échantillonnage différente est prise pour chaque horizon.

La matrice vectorielle est remplie comme suit

  for(i = IntShift; i < Frame; i++) {
    pos = HShift+i*Step;
    VT[ind] = MathSin(AFreq*pos);
    ind ++;
    VT[ind] = MathCos(AFreq*pos);
    ind ++;
    VT[ind] = Resid[i];   
    ind ++;
  }  //  for(i = IntShift; i < Frame; i++)

Le résidu est la différence entre le prix et l'ancienne tendance.

Paramètres de l'indicateur :

extern double kPer = 4.0;   // Коэффициент для определения периода
extern int LRRank = 1;      // Номер старшего горизонта, больше 3-х не ставить
extern int FShift = 120;    // Расстояние в барах, на которое производится экстраполяция в будущее
extern int HShift = 1;      // Сдвиг текущего времени индикатора в прошлое в барах, бары правее него тоже будут проэктраполированы
extern double PointFactor = 0.1;  // Масштабирование гистограммы ошибок аппроксимации, 0.1 подойдёт для минуток на пятизнаке 
extern bool PriceClose = true; // Если false, то будет считаться по HL/2


Ugh, je me suis fatigué pour écrire :)

En bref, l'essentiel est le suivant : Cette fonction n'a pas la prétention d'être optimale, elle permet simplement de faire des approximations comme des crêpes et de les goûter immédiatement, dès la sortie de la poêle :) . En conséquence, les indicateurs sont réalisés de telle manière, c'est-à-dire qu'ils ne prétendent à rien, en termes de style et d'efficacité.

Ce cas ne fonctionne pas très rapidement, donc l'historique n'est pas calculé. Cela signifie qu'il est préférable d'étudier dans le visualiseur. Mais ça devient vite ennuyeux :). Mais il n'est pas exclu qu'un patient puisse trouver un moyen d'en profiter :).


En général, je suis conscient que je ne pourrais pas faire une description cohérente, si quelqu'un est intéressé, il peut probablement compter sur des explications.


En fait, nous sommes censés parler d'un autre indicateur, qui se rapproche et extrapole mieux que les indicateurs présentés. C'est-à-dire qu'il m'impressionne tellement que j'ai apparemment fini par me ranger du côté du déterminisme des prix par morceaux. Mais cela ne rend pas les choses plus faciles, car je n'ai pas encore réussi à déterminer la longueur de ces pièces :) .

Mais je n'ai plus d'énergie pour écrire, je ne peux donner que quelques photos :)

Exemple d'approximation avec extrapolation réussie

Exemple d'approximation avec extrapolation "contrariée" par une impulsion

Dossiers :
lsa_sinlr.mq4  14 kb
 
Candid:

Pourriez-vous ajouter un petit morceau de code, que HShift n'est pas fixé, mais qu'il est déterminé par la position réelle de la première ligne ? Plus précisément, s'il est fixé <0 - alors les deux mécanismes fonctionneront et il sera possible de le tirer sur le graphique profondément dans l'histoire et d'analyser comment la prévision à ce point a coïncidé avec ce qui s'est passé après. ce sera intéressant ;)

 
ForexTools:

Pourriez-vous ajouter un petit morceau de code, que HShift n'est pas fixé, mais est déterminé par la position réelle de la première ligne ? Plus précisément, s'il est fixé <0 - alors les deux mécanismes fonctionneront et vous pouvez le faire glisser sur un graphique profondément dans l'histoire et analyser comment la prévision à ce point coïncide avec ce qui s'est passé après. ce sera intéressant ;)

Oui, c'est assez pratique, je vais vous donner une version. Je dois préciser que je ne suis pas particulièrement adepte du contrôle graphique, il n'y a donc aucune garantie que tout sera fluide.


Au fait, je ne pense pas avoir dit explicitement que les histogrammes en bas à droite montrent l'erreur d'approximation sur l'échantillon de base et l'erreur d'extrapolation sur le hors échantillon. Il est raisonnable de supposer que ces informations sont pertinentes pour évaluer la situation.


P.S. Ouais, j'ai oublié une ligne à ajouter. Indicateur remplacé à 11:50

Dossiers :
 

Quelques mots encore. Pourquoi exactement une tendance linéaire ? De toute façon, les vraies tendances sont linéaires. L'hypothèse est que cette déstratification peut se faire de manière inconsciente, alors il y a un espoir qu'il puisse y avoir une réalité derrière les harmoniques également.

En principe, augmenter le degré d'un polynôme n'est pas un problème, en fait j'ai commencé par l'option parabole. Cela se fait de manière élémentaire, en quelques lignes ajoutées et corrigées, chacun peut l'essayer lui-même, à titre d'exercice.

 

Bon après-midi.

Veuillez expliquer les dessins. Je suis intéressé par les lignes verticales. ai-je bien compris que c'est dans l'intervalle entre les lignes bleues que se trouvent les données pour la prévision ? que signifie la ligne rouge ? - le moment de la divergence avec la prévision ? pourquoi les lignes rouges (bleues) de la prévision ont des écarts ?

je n'ai pas regardé le code car votre niveau de programmation MQL est trop bas pour moi, c'est comme un rêve de se rapprocher de ce niveau ?

 

Prival:

veuillez expliquer les dessins. Je suis intéressé par les lignes verticales. Ai-je bien compris que c'est dans l'intervalle entre les lignes bleues que se trouvent les données de la prévision ? Que signifie la ligne rouge ? - pourquoi les lignes de prévision rouges (bleues) ont-elles des lacunes ?


Oui, en fait l'approximation se fait entre les lignes bleues. Entre le bleu et le rouge, on calcule la RMS de l'extrapolation. Il nous suffit de la décaler avec HShift (et maintenant de faire glisser la ligne le long du graphique) et de voir ce qu'elle ne voit pas.

Les écarts sont des "déchets", la fenêtre de travail de l'indicateur se déplace dans le temps, des queues sont laissées derrière. Cela serait facile à réparer avec une fenêtre permanente, mais comme il s'adapte, un moyen bon marché de le nettoyer ne m'est pas encore venu à l'esprit.

Je vous donne la version avec les lignes repeintes.

Dossiers :
 

votre nouveau code n'a pas fonctionné comme je le voulais :(

J'ai pris la liberté de mettre à plat mes modifications. Cela fonctionne très bien, surtout lorsqu'il est associé à ft.AutoRefresh.

Dossiers :
lsa_sinlr_1.mq4  16 kb
 

ForexTools:

Ici, je me suis permis de démolir mes montages. Ça marche bien, surtout quand c'est associé à ft.AutoRefresh.

Eh bien, je pense que votre version est plus résistante aux interférences, mais vous devez probablement ajouter HShift-- là aussi, pour qu'en l'absence d'actions de l'utilisateur, la fenêtre se déplace dans le temps. Bien que, hmm, peut-être que c'est exactement ce que vous vouliez éviter ?
 
Bien sûr ! Quand on analyse l'histoire, le graphique ne doit pas aller n'importe où mais "rester" à l'endroit où j'ai mis la ligne.
 
ForexTools:
Bien sûr ! Quand on analyse l'histoire, le graphique ne doit pas aller n'importe où mais "rester" à l'endroit où j'ai mis la ligne.

Eh bien, j'ai d'abord fait une variante stationnaire, puis je l'ai remplacée :). Je m'intéressais, tout d'abord, à la dynamique du redécoupage. En fait, il est facile d'ajouter un paramètre comme

if (ModeMoving) HShift--;
Mais trop bon n'est pas bon non plus, laissez la variante en suspens.
Raison: