High-Low Index : calcul et breadth du marché
Le High-Low Index est la moyenne sur 10 jours du Record High Percent. Formule avec chiffres ronds et biais de taille d’échantillon sur un marché calme.
L’High-Low Index est un indicateur de breadth du marché fondé sur deux décomptes. Il correspond à la moyenne mobile simple sur 10 jours du Record High Percent. Le Record High Percent est calculé en divisant le nombre de nouveaux plus-hauts sur 52 semaines par la somme des nouveaux plus-hauts et des nouveaux plus-bas sur 52 semaines, puis en multipliant le résultat par 100. Une valeur supérieure à 50 signifie que davantage d’actions inscrivent de nouveaux plus-hauts que de nouveaux plus-bas. En dessous de 50, c’est l’inverse. La formule est aussi courte que cela. La suite détaille le calcul avec des chiffres ronds et montre le biais lié à la taille de l’échantillon, qui permet à une valeur apparemment décisive de reposer sur une poignée d’actions.
Comment calculer le High-Low Index ?
Deux étapes, chacune tenant sur une ligne.
- Record High Percent, pour une séance donnée : comptez les actions de votre univers qui ont clôturé sur un nouveau plus-haut à 52 semaines, puis celles qui ont clôturé sur un nouveau plus-bas à 52 semaines. Divisez le nombre de plus-hauts par la somme des deux nombres, puis multipliez par 100.
- High-Low Index : calculez la moyenne des dix dernières valeurs quotidiennes de Record High Percent.
Des chiffres ronds permettent de concrétiser le calcul. Le marché affiche 90 nouveaux plus-hauts et 30 nouveaux plus-bas. La somme est de 120, et 90 divisé par 120 donne 0,75. Le Record High Percent de cette séance est donc de 75. Prenez maintenant dix séances : 75, 70, 65, 60, 55, 50, 45, 40, 35 et 30. Leur somme est de 525, et 525 divisé par 10 donne 52,5. Le High-Low Index s’établit à 52,5 alors que le Record High Percent de la séance est de 75.
Cet écart correspond au compromis lié à la moyenne mobile. Dix jours de mémoire lissent une série qui peut passer de 100 à 0 du jour au lendemain, au prix d’un retard. L’indice indique où se situe la breadth sur deux semaines. Il ne dit jamais ce qui s’est passé cet après-midi.
Qu’est-ce qui constitue un nouveau plus-haut sur 52 semaines ?
Une action atteint un nouveau plus-haut sur 52 semaines lorsque son cours dépasse tous les cours enregistrés au cours des 52 semaines précédentes. Les fournisseurs de données ne retiennent pas tous la même base : certains comparent les plus-hauts et les plus-bas intraday, tandis que d’autres ne comparent que les cours de clôture. Les deux méthodes produisent des décomptes différents pour une même séance. Les cours de clôture servent de base partout sur cette page. Nouveaux plus-hauts et plus-bas sur 52 semaines présente la liste en détail.
Le panneau ci-dessous comptabilise les deux extrêmes à chaque séance pour un panier fixe de 40 grandes capitalisations américaines, du 1er avril au 31 juillet 2026. Un panier de cette taille maintient les décomptes à un niveau suffisamment faible pour permettre une vérification manuelle. C’est ce qui rend ensuite visible le défaut de la formule.
Le SQL exact derrière chaque chiffre
WITH daily_close AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
argMax(close, window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('AAPL','MSFT','NVDA','AMZN','GOOGL','AVGO','JPM','JNJ','XOM','PG',
'KO','PEP','WMT','HD','CVX','MRK','PFE','ABBV','CSCO','ORCL',
'CRM','ADBE','MCD','NKE','VZ','T','DIS','BA','CAT','GE',
'IBM','MMM','UNH','LLY','COST','TGT','SBUX','GS','MS','LIN')
AND window_start >= toDateTime('2025-03-01 00:00:00')
AND window_start < toDateTime('2026-08-01 05:00:00')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, session_date
),
extremes AS (
SELECT cur.ticker AS ticker,
cur.session_date AS session_date,
cur.close_px AS close_px,
max(hist.close_px) AS high_52w,
min(hist.close_px) AS low_52w
FROM daily_close AS cur
INNER JOIN daily_close AS hist ON cur.ticker = hist.ticker
WHERE cur.session_date >= toDate('2026-04-01')
AND hist.session_date <= cur.session_date
AND hist.session_date > cur.session_date - 364
GROUP BY cur.ticker, cur.session_date, cur.close_px
),
daily AS (
SELECT session_date,
countIf(close_px >= high_52w) AS new_highs,
countIf(close_px <= low_52w) AS new_lows,
countIf(close_px >= high_52w) + countIf(close_px <= low_52w) AS names_at_extreme
FROM extremes
GROUP BY session_date
HAVING names_at_extreme > 0
)
SELECT session_date AS date,
formatDateTimeInJodaSyntax(session_date, 'MMM d') AS session_label,
new_highs,
new_lows
FROM daily
ORDER BY session_dateSur 77 séances, les deux décomptes progressent rarement ensemble. Le Jul 29, dernière séance de la période, 3 des 40 titres ont clôturé sur un plus-haut de 52 semaines et 0 sur un plus-bas de 52 semaines. Le Apr 1, première séance de la période, la répartition était de 1 plus-hauts contre 1 plus-bas. Tous les autres titres du panier se situaient à l’intérieur de leur propre fourchette et n’entraient jamais dans le calcul.
Quelle est une bonne valeur pour le High-Low Index ?
La ligne 50 constitue le point d’équilibre, avec autant de nouveaux plus hauts que de nouveaux plus bas. Le seuil conventionnel de vigueur est fixé à 70. À ce niveau, les nouveaux plus hauts ont dépassé les nouveaux plus bas dans un rapport supérieur à two-to-one sur l’ensemble de la moyenne mobile à 10 jours. Le seuil conventionnel de faiblesse est 30, son équivalent inverse. Entre 30 et 70, l’indice indique que les extrêmes du marché sont partagés. C’est sa zone la plus fréquente.
Le panneau ci-dessous compare le Record High Percent quotidien brut à sa propre moyenne mobile à 10 jours pour le même panier. Le retard apparaît sur le graphique, plutôt que d’être décrit.
Le SQL exact derrière chaque chiffre
WITH daily_close AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
argMax(close, window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('AAPL','MSFT','NVDA','AMZN','GOOGL','AVGO','JPM','JNJ','XOM','PG',
'KO','PEP','WMT','HD','CVX','MRK','PFE','ABBV','CSCO','ORCL',
'CRM','ADBE','MCD','NKE','VZ','T','DIS','BA','CAT','GE',
'IBM','MMM','UNH','LLY','COST','TGT','SBUX','GS','MS','LIN')
AND window_start >= toDateTime('2025-03-01 00:00:00')
AND window_start < toDateTime('2026-08-01 05:00:00')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, session_date
),
extremes AS (
SELECT cur.ticker AS ticker,
cur.session_date AS session_date,
cur.close_px AS close_px,
max(hist.close_px) AS high_52w,
min(hist.close_px) AS low_52w
FROM daily_close AS cur
INNER JOIN daily_close AS hist ON cur.ticker = hist.ticker
WHERE cur.session_date >= toDate('2026-04-01')
AND hist.session_date <= cur.session_date
AND hist.session_date > cur.session_date - 364
GROUP BY cur.ticker, cur.session_date, cur.close_px
),
daily AS (
SELECT session_date,
countIf(close_px >= high_52w) AS new_highs,
countIf(close_px >= high_52w) + countIf(close_px <= low_52w) AS names_at_extreme
FROM extremes
GROUP BY session_date
HAVING names_at_extreme > 0
),
rhp AS (
SELECT session_date,
round(100 * new_highs / names_at_extreme, 1) AS record_high_pct
FROM daily
),
smoothed AS (
SELECT session_date,
record_high_pct,
round(avg(record_high_pct) OVER (ORDER BY session_date
ROWS BETWEEN 9 PRECEDING AND CURRENT ROW), 1) AS high_low_index_pct,
count() OVER (ORDER BY session_date
ROWS BETWEEN 9 PRECEDING AND CURRENT ROW) AS sessions_in_window
FROM rhp
)
SELECT session_date AS date,
formatDateTimeInJodaSyntax(session_date, 'MMM d') AS session_label,
record_high_pct,
high_low_index_pct
FROM smoothed
WHERE sessions_in_window = 10
ORDER BY session_dateLa période représentée commence avec un Record High Percent de 100 le Apr 15, et un indice à 52.5. Elle se termine à 100 le Jul 29, avec un indice à 64. Comparez chaque valeur aux seuils de 70 et 30. Observez aussi l’écart entre les deux lignes : il correspond au coût du lissage. Un jour donné, la moyenne intègre encore les neuf séances précédentes. Les neuf premières séances de la période sont exclues du panneau, car une moyenne à 10 jours nécessite 10 jours.
Le dénominateur ignore la majeure partie du marché
Voici la limite à retenir. Le dénominateur de Record High Percent correspond à la somme des nouveaux plus-hauts et des nouveaux plus-bas, et à rien d’autre. Une action située au milieu de sa fourchette sur 52 semaines n’entre ni dans le numérateur ni dans le dénominateur. L’indice ne peut pas distinguer une séance au cours de laquelle 900 des 3 000 titres atteignent un extrême d’une séance où seuls 9 titres le font. Dans les deux cas, il affiche le même nombre à deux chiffres, avec la même assurance.
Prenons une place boursière comptant 6 000 titres lors d’une séance calme d’août : 40 actions inscrivent de nouveaux plus-hauts et 20 de nouveaux plus-bas. Record High Percent est égal à 40 divisé par 60, soit 66,7, ce qui donne l’impression d’une progression généralisée. Le calcul repose pourtant sur 1 % des valeurs cotées. Les 5 940 autres titres n’ont pas été pris en compte.
Le panier de 40 titres permet de quantifier cette situation. Chaque séance de la fenêtre d’observation est classée dans une catégorie selon le nombre de titres ayant inscrit un extrême, quel qu’il soit.
Le SQL exact derrière chaque chiffre
WITH daily_close AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
argMax(close, window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('AAPL','MSFT','NVDA','AMZN','GOOGL','AVGO','JPM','JNJ','XOM','PG',
'KO','PEP','WMT','HD','CVX','MRK','PFE','ABBV','CSCO','ORCL',
'CRM','ADBE','MCD','NKE','VZ','T','DIS','BA','CAT','GE',
'IBM','MMM','UNH','LLY','COST','TGT','SBUX','GS','MS','LIN')
AND window_start >= toDateTime('2025-03-01 00:00:00')
AND window_start < toDateTime('2026-08-01 05:00:00')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, session_date
),
extremes AS (
SELECT cur.ticker AS ticker,
cur.session_date AS session_date,
cur.close_px AS close_px,
max(hist.close_px) AS high_52w,
min(hist.close_px) AS low_52w
FROM daily_close AS cur
INNER JOIN daily_close AS hist ON cur.ticker = hist.ticker
WHERE cur.session_date >= toDate('2026-04-01')
AND hist.session_date <= cur.session_date
AND hist.session_date > cur.session_date - 364
GROUP BY cur.ticker, cur.session_date, cur.close_px
),
daily AS (
SELECT session_date,
countIf(close_px >= high_52w) AS new_highs,
countIf(close_px >= high_52w) + countIf(close_px <= low_52w) AS names_at_extreme
FROM extremes
GROUP BY session_date
HAVING names_at_extreme > 0
)
SELECT multiIf(names_at_extreme <= 3, '1 to 3 names',
names_at_extreme <= 9, '4 to 9 names',
'10 or more names') AS sample_size_bucket,
count() AS readings,
round(avg(names_at_extreme), 1) AS avg_names_in_denominator,
round(quantileDeterministic(0.5)(100 * new_highs / names_at_extreme,
cityHash64(session_date)), 1) AS median_record_high_pct,
round(quantileDeterministic(0.5)(abs(100 * new_highs / names_at_extreme - 50),
cityHash64(session_date)), 1) AS median_distance_from_50
FROM daily
GROUP BY sample_size_bucket
ORDER BY avg_names_in_denominatorLors des 39 séances de la catégorie 1 to 3 names, l’indicateur reposait sur une moyenne de 2 titres sur 40. Ces séances affichaient un Record High Percent médian de 100 et se situaient à une distance médiane de 50 points de la ligne des 50. Les 10 or more names séances, dont 1 reposaient sur une moyenne de 10 titres, affichaient une valeur médiane de 70 et se situaient à 20 points du milieu.
L’arithmétique limite les valeurs qu’une séance peu fournie peut afficher. Avec trois titres à un extrême, les seules valeurs possibles sont 0, 33,3, 66,7 et 100. Avec deux titres, seules les valeurs 0, 50 et 100 sont possibles. Une valeur de 66,7 fondée sur deux nouveaux plus-hauts et un nouveau plus-bas comporte une décimale que son échantillon ne permet pas de justifier. La bonne pratique est simple : lisez les décomptes bruts des nouveaux plus-hauts et des nouveaux plus-bas à côté de l’indice. Ne consultez jamais l’indice seul.
Largeur de marché : High-Low Index contre advance/decline
Les deux mesures cherchent à déterminer combien d’actions participent au mouvement. Elles le font sur des horizons différents. La largeur advance/decline compte chaque valeur qui a terminé en hausse ou en baisse par rapport à la veille. Son dénominateur couvre l’ensemble de l’univers, et elle décrit une seule séance. Le High-Low Index ne compte que les valeurs qui atteignent un plus-haut ou un plus-bas sur 52 semaines. Son dénominateur est réduit, et il indique où se situent les cours par rapport à une année complète d’historique. Le marché peut donc progresser largement sur la séance alors que très peu de valeurs se trouvent près d’un plus-haut sur 52 semaines.
Le panneau ci-dessous lisse les deux mesures sur les mêmes 10 séances et sur le même panier, ce qui les place sur une échelle commune.
Le SQL exact derrière chaque chiffre
WITH daily_close AS (
SELECT ticker,
toDate(toTimeZone(window_start, 'America/New_York')) AS session_date,
argMax(close, window_start) AS close_px
FROM global_markets.delayed_stocks_minute_aggs
WHERE ticker IN ('AAPL','MSFT','NVDA','AMZN','GOOGL','AVGO','JPM','JNJ','XOM','PG',
'KO','PEP','WMT','HD','CVX','MRK','PFE','ABBV','CSCO','ORCL',
'CRM','ADBE','MCD','NKE','VZ','T','DIS','BA','CAT','GE',
'IBM','MMM','UNH','LLY','COST','TGT','SBUX','GS','MS','LIN')
AND window_start >= toDateTime('2025-03-01 00:00:00')
AND window_start < toDateTime('2026-08-01 05:00:00')
AND (toHour(toTimeZone(window_start, 'America/New_York')) * 60
+ toMinute(toTimeZone(window_start, 'America/New_York'))) BETWEEN 570 AND 959
GROUP BY ticker, session_date
),
extremes AS (
SELECT cur.ticker AS ticker,
cur.session_date AS session_date,
cur.close_px AS close_px,
max(hist.close_px) AS high_52w,
min(hist.close_px) AS low_52w
FROM daily_close AS cur
INNER JOIN daily_close AS hist ON cur.ticker = hist.ticker
WHERE cur.session_date >= toDate('2026-04-01')
AND hist.session_date <= cur.session_date
AND hist.session_date > cur.session_date - 364
GROUP BY cur.ticker, cur.session_date, cur.close_px
),
daily AS (
SELECT session_date,
countIf(close_px >= high_52w) AS new_highs,
countIf(close_px >= high_52w) + countIf(close_px <= low_52w) AS names_at_extreme
FROM extremes
GROUP BY session_date
HAVING names_at_extreme > 0
),
prior AS (
SELECT ticker,
session_date,
close_px,
lagInFrame(close_px, 1) OVER (PARTITION BY ticker ORDER BY session_date
ROWS BETWEEN 1 PRECEDING AND CURRENT ROW) AS prev_close
FROM daily_close
),
breadth AS (
SELECT session_date,
round(100 * countIf(close_px > prev_close) / count(), 1) AS advancing_pct
FROM prior
WHERE session_date >= toDate('2026-04-01')
AND prev_close > 0
GROUP BY session_date
HAVING count() >= 20
),
combined AS (
SELECT d.session_date AS session_date,
round(100 * d.new_highs / d.names_at_extreme, 1) AS record_high_pct,
b.advancing_pct AS advancing_pct
FROM daily AS d
INNER JOIN breadth AS b ON d.session_date = b.session_date
),
smoothed AS (
SELECT session_date,
round(avg(record_high_pct) OVER (ORDER BY session_date
ROWS BETWEEN 9 PRECEDING AND CURRENT ROW), 1) AS high_low_index_pct,
round(avg(advancing_pct) OVER (ORDER BY session_date
ROWS BETWEEN 9 PRECEDING AND CURRENT ROW), 1) AS advancing_pct_10d,
count() OVER (ORDER BY session_date
ROWS BETWEEN 9 PRECEDING AND CURRENT ROW) AS sessions_in_window
FROM combined
)
SELECT session_date AS date,
formatDateTimeInJodaSyntax(session_date, 'MMM d') AS session_label,
high_low_index_pct,
advancing_pct_10d
FROM smoothed
WHERE sessions_in_window = 10
ORDER BY session_dateLes deux séries commencent sur la période représentée à 52.5 pour le High-Low Index et à 52.8 pour la proportion de valeurs en hausse sur 10 jours, le Apr 15. Elles terminent à 64 et 52.5 le Jul 29, sur 68 séances représentées. La proportion de valeurs en hausse évolue dans une fourchette étroite. Lors d’une séance ordinaire, environ la moitié du panier clôture en hausse. La moyenne sur dix séances laisse donc la ligne près du milieu de l’échelle. Le High-Low Index n’a pas ce point d’ancrage. Lorsqu’aucune valeur du panier n’inscrit de plus-bas sur 52 semaines pendant dix séances consécutives, chaque lecture quotidienne vaut 100, et la moyenne reste également à 100.
La largeur de marché est plus informative lorsqu’elle est accompagnée de mesures de participation. Le volume relatif indique si une valeur est exceptionnellement active aujourd’hui par rapport à sa propre norme. Les plus fortes variations de la semaine montrent quelles valeurs ont réellement évolué, et les actions à volume inhabituel cette semaine indiquent où les échanges se sont concentrés.
FAQ sur le High-Low Index
Que signifie une valeur du High-Low Index supérieure à 70 ?
Cela signifie que les nouveaux plus hauts à 52 semaines ont été plus de deux fois plus nombreux que les nouveaux plus bas à 52 semaines, en moyenne sur les dix dernières séances. C’est le signal conventionnel d’un marché particulièrement solide. Cette valeur ne dit rien du nombre total d’actions ayant atteint un extrême. C’est ce nombre qu’il faut consulter en parallèle.
Quelle est la différence entre le Record High Percent et le High-Low Index ?
Le Record High Percent est la valeur d’une seule séance : le nombre de nouveaux plus hauts divisé par la somme des nouveaux plus hauts et des nouveaux plus bas, multiplié par 100. Le High-Low Index est la moyenne mobile simple sur 10 jours de cette valeur. Le premier décrit la séance du jour. Le second décrit les deux dernières semaines.
Le High-Low Index peut-il être égal à 0 ou à 100 ?
Oui. Si aucune action de l’univers ne marque de nouveau plus bas à 52 semaines pendant dix séances consécutives, chaque valeur quotidienne est égale à 100, tout comme la moyenne. Lorsqu’aucune action ne marque ni nouveau plus haut ni nouveau plus bas, le dénominateur est nul et la valeur de la séance n’est pas définie.
Le High-Low Index est-il identique à la breadth advance/decline ?
Non. La breadth advance/decline se calcule sur l’ensemble de l’univers et décrit la direction du marché sur une seule séance. Le High-Low Index se calcule sur le petit groupe d’actions situées à des extrêmes de 52 semaines et décrit leur position par rapport à une année de cours.
Combien d’actions figurent généralement au dénominateur du High-Low Index ?
Dans le panier de 40 valeurs mesuré ici d’avril à juillet 2026, les séances de la catégorie 1 to 3 names comptaient en moyenne 2 valeurs au dénominateur. Les décomptes à l’échelle d’une place sont plus élevés en valeur absolue, tout en ne représentant qu’une faible fraction de l’ensemble des valeurs cotées. C’est pourquoi les nombres bruts doivent apparaître à l’écran à côté de l’indice.
Chaque décompte présenté sur cette page provient d’une requête stockée et versionnée portant sur les cours de clôture. Ouvrez n’importe quel panneau pour consulter le SQL correspondant, ou reconstituez la même série de breadth sur votre propre panier dans le terminal Strasmore.