⚠ Le trading comporte un risque important de perte. Tout le contenu de ce site est fourni à des fins éducatives uniquement et ne constitue pas un conseil financier.
Leçon 6 sur 13 · Gratuit

Les indicateurs en code : SMA, EMA, RSI, ATR et bandes de Bollinger vectorisés, vérifiés par rapport à une plateforme graphique

Écrivez des fonctions pandas vectorisées pour les cinq indicateurs les plus utilisés, et découvrez pourquoi leurs valeurs peuvent différer de celles d'une plateforme graphique et comment les réconcilier.

Auteur: Moustafa HijaziContenu relu le: 2026-10-306 min de lectureCours en autoformation

Ce que vous allez apprendre

  • Comment rolling et ewm implémentent la SMA, l'EMA, le lissage de Wilder, l'ATR et les bandes de Bollinger, en quelques lignes chacun.
  • Quels paramètres (adjust, alpha, ddof) modifient silencieusement les chiffres.
  • Pourquoi votre RSI ou votre EMA diffère de la plateforme graphique sur les premières barres, et comment comparer correctement les deux.
  • Comment organiser les indicateurs sous forme de fonctions pures dans src/indicators.py pour les réutiliser et les tester.

Explication

Le cours L'analyse technique approfondie expliquait ce que signifient ces indicateurs ; ici, l'objectif est un code correct, rapide et testable. Chaque fonction prend une Series et renvoie une Series sur le même index.

SMA (simple moving average, moyenne mobile simple) : def sma(s, n): return s.rolling(n).mean().

EMA (exponential moving average, moyenne mobile exponentielle) : def ema(s, n): return s.ewm(span=n, adjust=False).mean(). Avec span=n, la constante de lissage vaut α = 2 ÷ (n + 1) ; pour n = 20, α = 0.0952. adjust=False donne la formule récursive EMAt = α × Pt + (1 − α) × EMAt−1 qu'utilisent les plateformes ; la valeur par défaut adjust=True pondère différemment les quelques dizaines de premières barres. pandas initialise avec le premier prix ; la plupart des plateformes initialisent avec la SMA des n premières barres. Les deux initialisations s'estompent ; après environ 3n barres, les séries concordent étroitement.

RSI (relative strength index, indice de force relative), version de Wilder :

delta = s.diff()

gain = delta.clip(lower=0); loss = -delta.clip(upper=0)

avg_gain = gain.ewm(alpha=1/n, adjust=False).mean()

avg_loss = loss.ewm(alpha=1/n, adjust=False).mean()

rsi = 100 - 100 / (1 + avg_gain / avg_loss)

Le lissage de Wilder est une EMA avec α = 1 ÷ n, et non 2 ÷ (n + 1) ; utiliser span=14 ici est le bug de RSI le plus fréquent. Lorsque avg_loss vaut zéro, le RSI devient correctement 100.

ATR (average true range, étendue vraie moyenne) : l'étendue vraie (true range) est la plus grande des valeurs plus haut − plus bas, |plus haut − clôture précédente| et |plus bas − clôture précédente| :

pc = close.shift(1)

tr = pd.concat([high - low, (high - pc).abs(), (low - pc).abs()], axis=1).max(axis=1)

atr = tr.ewm(alpha=1/n, adjust=False).mean()

Certaines plateformes affichent plutôt un ATR fondé sur une SMA ; vérifiez avant de comparer. La leçon 8 utilise l'ATR pour les stops et le dimensionnement des positions.

Bandes de Bollinger : bande centrale = SMA(n), bandes supérieure et inférieure = centrale ± k × écart-type sur les mêmes n barres, typiquement n = 20, k = 2. Le piège est ddof : dans pandas, rolling(n).std() divise par n − 1 (échantillon), alors que les plateformes divisent généralement par n (population). Écrivez std(ddof=0) pour concorder. La valeur d'échantillon est plus grande, suffisamment pour transformer un « contact » avec la bande en « absence de contact ».

Vérifier par rapport à une plateforme. Utilisez la même série ajustée que la plateforme, calculez votre indicateur et comparez les 100 dernières valeurs, car les écarts d'initialisation s'atténuent. Utilisez np.allclose avec une petite tolérance. Les écarts persistants proviennent de cinq sources habituelles : données ajustées ou non ajustées, initialisation, span au lieu de alpha, ddof, ou un autre prix d'entrée. Corrigez ou documentez l'écart ; n'« ajustez » jamais un paramètre jusqu'à ce que les chiffres concordent.

Exemple commenté

Exemple hypothétique : dix clôtures journalières en euros : 20.00, 20.50, 21.00, 20.80, 21.40, 21.00, 21.60, 22.00, 21.80, 22.40.

SMA(5) sur la dernière barre : (21.00 + 21.60 + 22.00 + 21.80 + 22.40) ÷ 5 = 108.80 ÷ 5 = €21.76.

Bollinger(5, 2) sur la dernière barre. Écarts par rapport à 21.76 : −0.76, −0.16, 0.24, 0.04, 0.64 ; somme des carrés 1.0720. Variance de population = 1.0720 ÷ 5 = 0.2144, écart-type 0.4630, bande supérieure = 21.76 + 2 × 0.4630 = €22.69, bande inférieure €20.83. Formule d'échantillon : 1.0720 ÷ 4 = 0.2680, écart-type 0.5177, bande supérieure €22.80, bande inférieure €20.72.

EMA(5) avec α = 2 ÷ 6 = 0.3333 et adjust=False : EMA1 = 20.00 (initialisation), EMA2 = 0.3333 × 20.50 + 0.6667 × 20.00 = 20.1667, EMA3 = 0.3333 × 21.00 + 0.6667 × 20.1667 = 20.4444, et ainsi de suite jusqu'à 21.8310 sur la dernière barre.

Étendue vraie d'une barre avec un plus haut de €21.20, un plus bas de €20.60 et une clôture précédente de €20.80 : max(0.60, |21.20 − 20.80| = 0.40, |20.60 − 20.80| = 0.20) = €0.60.

Erreur fréquente

Confondre span et alpha dans ewmewm(span=14) utilise α = 2 ÷ 15 = 0.133, alors que le RSI et l'ATR de Wilder exigent ewm(alpha=1/14), α = 0.0714. La version avec span réagit presque deux fois plus vite et ne concordera avec aucune plateforme standard. Écrivez explicitement l'α voulu et consignez-le dans la docstring de la fonction.

Exercice pratique

Sur papier, avec un RSI de Wilder sur 3 périodes à titre purement illustratif (l'usage réel est de 14) : clôtures 50.00, 50.50, 51.00, 50.80. (a) Listez les gains et les pertes par barre. (b) ewm(alpha=1/3, adjust=False) de pandas initialise avec la première observation ; calculez avg_gain et avg_loss sur la dernière barre, ainsi que le RSI. (c) Expliquez en une phrase pourquoi une plateforme qui initialise avec la moyenne simple des trois premières variations afficherait ici une valeur différente, et ce que vous feriez avant de conclure que votre code est faux.

Afficher la solution

(a) Variations : +0.50, +0.50, −0.20. Gains : 0.50, 0.50, 0.00. Pertes : 0.00, 0.00, 0.20.

(b) α = 1/3. avg_gain : 0.50 (initialisation) → (1/3)(0.50) + (2/3)(0.50) = 0.50 → (1/3)(0) + (2/3)(0.50) = 0.3333. avg_loss : 0 → 0 → (1/3)(0.20) + (2/3)(0) = 0.0667. RS = 0.3333 ÷ 0.0667 = 5.0 ; RSI = 100 − 100 ÷ (1 + 5) = 83.33.

(c) Ici, l'initialisation par moyenne simple (gains 0.3333, pertes 0.0667) donne par hasard le même 83.33, mais en général les deux initialisations diffèrent sur les quelques dizaines de premières barres ; comparez donc les 100 valeurs les plus récentes d'une longue série avant de toucher au code.

Limites : un RSI sur 3 périodes est un outil pédagogique ; quatre barres ne peuvent pas montrer le comportement de convergence qui compte en pratique.

Points clés à retenir

  • La SMA s'écrit rolling(n).mean() ; l'EMA ewm(span=n, adjust=False) ; le lissage de Wilder pour le RSI et l'ATR ewm(alpha=1/n, adjust=False).
  • Les bandes de Bollinger de la plupart des plateformes utilisent l'écart-type de population : passez ddof=0.
  • Les écarts d'initialisation s'estompent ; comparez les 100 dernières barres avec une tolérance, et cherchez les cinq causes habituelles d'écart avant de modifier le code.
  • Conservez les indicateurs sous forme de fonctions pures documentées afin de pouvoir les tester unitairement et les réutiliser dans chaque backtest.

Étape suivante

La leçon 7 assemble les éléments en un backtest vectorisé : signaux, positions, le décalage qui empêche le biais d'anticipation, coûts de transaction et courbe de capital.

Auto-évaluation

Répondez aux questions, puis vérifiez vos réponses. Vous pouvez recommencer autant de fois que vous le souhaitez.

1. Quel appel pandas implémente le lissage de Wilder pour un RSI ou un ATR sur 14 périodes ?

2. Cinq clôtures ont une moyenne de €40.00 et une somme des carrés des écarts de 2.00. Où se situe la bande de Bollinger supérieure (k = 2) avec la formule de population, puis avec la formule d'échantillon ?

3. Votre EMA(20) concorde avec la plateforme à 0.01 près sur les 200 dernières barres, mais diffère jusqu'à €0.40 sur les 30 premières. Quelle est la conclusion correcte ?

Auto-évaluation automatique pour vos propres révisions. Vos réponses sont vérifiées dans votre navigateur ; nous ne les voyons pas et ne les évaluons pas. Ce n'est ni un examen ni une qualification.

Votre progression

« Terminée » signifie seulement que vous avez marqué la leçon comme lue. Ce n'est pas un test de votre compréhension. La progression et les notes sont enregistrées uniquement dans ce navigateur, sur cet appareil — pas dans un compte.