Strasmore Research
Edukacja Matt ConnorAutor: Matt Connor

High-Low Index: definicja i szerokość rynku

High-Low Index to 10-dniowa średnia Record High Percent. Wyjaśniono wzór na zaokrąglonych liczbach oraz pułapkę małej próby podczas spokojnej sesji.

Wskaźnik High-Low Index jest miarą szerokości rynku opartą na dwóch wartościach: stanowi 10-dniową prostą średnią kroczącą wskaźnika Record High Percent, a Record High Percent to iloraz liczby nowych 52-tygodniowych maksimów i sumy nowych 52-tygodniowych maksimów oraz minimów, pomnożony przez 100. Odczyt powyżej 50 oznacza, że więcej akcji ustanawia nowe maksima niż nowe minima, a odczyt poniżej 50 wskazuje na sytuację odwrotną. Wzór jest tak krótki. Poniżej przedstawiono obliczenia na zaokrąglonych liczbach oraz problem wielkości próby, przez który pozornie rozstrzygający odczyt może opierać się na kilku akcjach.

Jak oblicza się High-Low Index?

Dwa kroki, z których każdy mieści się w jednym wierszu.

  1. Record High Percent dla jednej sesji: należy policzyć akcje z analizowanego uniwersum, które zamknęły sesję na nowym 52-tygodniowym maksimum, policzyć te, które zamknęły sesję na nowym 52-tygodniowym minimum, podzielić liczbę maksimów przez sumę obu wartości, a następnie pomnożyć przez 100.
  2. High-Low Index: należy obliczyć średnią z dziesięciu ostatnich dziennych odczytów Record High Percent.

Zaokrąglone liczby ułatwiają zrozumienie mechanizmu. Na rynku odnotowano 90 nowych maksimów i 30 nowych minimów. Suma maksimów i minimów wynosi 120, a 90 podzielone przez 120 daje 0,75, dlatego Record High Percent dla tej sesji wynosi 75. Następnie należy wziąć dziesięć odczytów sesyjnych: 75, 70, 65, 60, 55, 50, 45, 40, 35 i 30. Ich suma wynosi 525, a 525 podzielone przez 10 daje 52,5. High-Low Index wynosi więc 52,5 w dniu, w którym bieżący Record High Percent wyniósł 75.

Ta różnica jest ceną, jaką płaci się za średnią kroczącą. Dziesięciodniowa pamięć wygładza serię, która z dnia na dzień może zmienić się ze 100 na 0, ale opóźnia sygnał. Wskaźnik pokazuje, jak kształtowała się szerokość rynku w ciągu dwóch tygodni. Nie pokazuje, co wydarzyło się dziś po południu.

Co uznaje się za nowe 52-tygodniowe maksimum?

Akcja ustanawia nowe 52-tygodniowe maksimum, gdy jej kurs przewyższa wszystkie kursy odnotowane w poprzednich 52 tygodniach. Dostawcy danych stosują różne podstawy obliczeń: jedni porównują maksima i minima śródsesyjne, inni wyłącznie kursy zamknięcia. W rezultacie dla tej samej sesji powstają różne zestawienia. Na całej tej stronie podstawę stanowią kursy zamknięcia. Nowe 52-tygodniowe maksima i minima przedstawia samo zestawienie.

Panel poniżej pokazuje liczbę obu ekstremów w każdej sesji dla stałego koszyka 40 dużych spółek z USA, w okresie od 1 kwietnia do 31 lipca 2026 r. Koszyk tej wielkości utrzymuje liczby na poziomie umożliwiającym ręczną weryfikację. Dzięki temu później wyraźnie widać wadę wzoru.

ZapytanieNowe 52-tygodniowe maksima i minima w każdej sesji: 40 amerykańskich spółek o dużej kapitalizacji, kwiecień–lipiec 2026
Dokładny kod SQL dla każdej liczby
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_date
Run this yourself

W ciągu 77 sesji obie liczby rzadko rosły jednocześnie. W Jul 29, czyli w ostatniej sesji analizowanego okresu, 3 z 40 spółek zamknęło sesję na 52-tygodniowym maksimum, a 0 na 52-tygodniowym minimum. W Apr 1, czyli w pierwszej sesji, proporcja wynosiła 1 maksimów wobec 1 minimów. Wszystkie pozostałe spółki z koszyka znajdowały się w obrębie własnego przedziału i nie weszły do obliczeń.

Jaki odczyt High-Low Index uznaje się za dobry?

Poziom 50 jest punktem równowagi między maksimami i minimami. Za konwencjonalny sygnał silnego rynku uznaje się poziom 70. Oznacza on, że w całej dziesięciodniowej średniej nowych maksimów było więcej niż nowych minimów w proporcji większej niż two-to-one. Konwencjonalny słaby poziom to 30, czyli lustrzane odbicie tej sytuacji. Między 30 a 70 wskaźnik sygnalizuje mieszany obraz ekstremów rynkowych. W tym przedziale znajduje się przez większość czasu.

Panel poniżej przedstawia dzienny Record High Percent oraz jego własną średnią dziesięciodniową dla tego samego koszyka. Opóźnienie jest widoczne na wykresie i nie wymaga dodatkowego opisu.

ZapytanieOdsetek rekordowych maksimów i jego 10-dniowa średnia (indeks High-Low), koszyk 40 spółek
Dokładny kod SQL dla każdej liczby
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_date
Run this yourself

Zakres na wykresie rozpoczyna się od Record High Percent na poziomie 100 w dniu Apr 15, przy wartości wskaźnika wynoszącej 52.5. Kończy się na poziomie 100 w dniu Jul 29, przy wartości wskaźnika 64. Każdy odczyt należy porównywać z poziomami 70 i 30. Odległość między obiema liniami pokazuje cenę wygładzenia: w dowolnym dniu średnia nadal obejmuje dziewięć starszych sesji. Pierwszych dziewięć sesji okresu pominięto w panelu, ponieważ średnia dziesięciodniowa wymaga dziesięciu dni danych.

Mianownik pomija większość rynku

To ograniczenie należy zapamiętać. Mianownik wskaźnika Record High Percent obejmuje nowe maksima i nowe minima, i nic więcej. Akcja znajdująca się w środku swojego 52-tygodniowego przedziału nie występuje ani w liczniku, ani w mianowniku. Wskaźnik nie odróżnia sesji, podczas której ekstremum osiągnęło 900 z 3 000 spółek, od sesji, podczas której zrobiło to 9 spółek. W obu przypadkach pokazuje tę samą, pozornie precyzyjną liczbę dwucyfrową.

Wyobraźmy sobie giełdę z 6 000 spółek podczas spokojnej sierpniowej sesji: 40 akcji ustanawia nowe maksima, a 20 nowe minima. Record High Percent wynosi 40 podzielone przez 60, czyli 66,7, co wygląda jak szeroki wzrost rynku. Wartość obliczono jednak na podstawie 1% notowanych spółek. Pozostałe 5 940 spółek nie miało wpływu na odczyt.

Koszyk 40 spółek pokazuje ten problem w sposób możliwy do policzenia. Każda sesja w analizowanym okresie została przypisana do przedziału według liczby spółek, które ustanowiły dowolne ekstremum.

ZapytanieJak kurczy się mianownik: sesje pogrupowane według liczby spółek na 52-tygodniowym ekstremum
Dokładny kod SQL dla każdej liczby
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_denominator
Run this yourself

W 39 sesjach należących do przedziału 1 to 3 names cały odczyt opierał się średnio na 2 spółkach z 40. Mediana Record High Percent w tych sesjach wyniosła 100, a mediana odległości od poziomu 50 wyniosła 50 punktów. W 10 or more names sesjach, z których 1 przypadło na średnio 10 spółek, mediana wyniosła 70, a odczyty znajdowały się 20 punktów od środka skali.

Arytmetyka ogranicza zakres możliwych odczytów w sesji o niskiej liczbie obserwacji. Przy trzech spółkach ustanawiających ekstremum możliwe są tylko wartości 0, 33,3, 66,7 i 100. Przy dwóch spółkach możliwe są wyłącznie wartości 0, 50 i 100. Odczyt 66,7 oparty na dwóch maksimach i jednym minimum zawiera miejsce dziesiętne, którego nie uzasadnia wielkość próby. Rozwiązanie jest proste: obok wskaźnika należy analizować surowe liczby maksimów i minimów, a nie sam wskaźnik.

Szerokość rynku: High-Low Index a advance/decline

Obie miary pokazują, ile akcji uczestniczy w ruchu rynku. Robią to jednak w różnych horyzontach. Miara advance/decline obejmuje każdą spółkę, która zakończyła sesję wzrostem lub spadkiem względem poprzedniego dnia. Jej mianownik stanowi całe uniwersum, a miara opisuje jeden dzień. High-Low Index obejmuje wyłącznie spółki znajdujące się na 52-tygodniowym ekstremum. Jego mianownik jest niewielki, a wskaźnik pokazuje położenie kursów względem pełnego roku historii. Rynek może szeroko rosnąć w ciągu dnia, podczas gdy bardzo niewiele spółek znajduje się w pobliżu 52-tygodniowego maksimum.

Panel poniżej wygładza obie miary w tym samym okresie dziesięciu sesji i dla tego samego koszyka. Dzięki temu można je porównać na jednej skali.

ZapytanieDwie miary szerokości rynku, ten sam koszyk: 10-dniowy indeks High-Low wobec 10-dniowego odsetka spółek zwyżkujących
Dokładny kod SQL dla każdej liczby
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_date
Run this yourself

Zakres na wykresie rozpoczyna się na poziomie 52.5 dla High-Low Index oraz 52.8 dla 10-dniowego udziału spółek rosnących w dniu Apr 15. Kończy się odpowiednio na poziomach 64 i 52.5 w dniu Jul 29, po 68 sesjach pokazanych na wykresie. Udział spółek rosnących porusza się w wąskim przedziale. W typowej sesji około połowa spółek z koszyka zamyka się wyżej, a średnia z dziesięciu takich odczytów pozostaje w pobliżu środka skali. High-Low Index nie ma takiego punktu odniesienia. Jeżeli przez dziesięć kolejnych sesji żadna spółka z koszyka nie ustanowi 52-tygodniowego minimum, każdy dzienny odczyt wynosi 100, podobnie jak średnia.

Szerokość rynku lepiej interpretować razem z miarami uczestnictwa. Wolumen względny pokazuje, czy obrót daną spółką jest dziś wyjątkowo wysoki względem jej własnej normy. Największe tygodniowe ruchy kursów akcji wskazuje spółki, których kursy faktycznie wykonały największy ruch, a spółki o nietypowo wysokim wolumenie w tym tygodniu pokazuje, gdzie koncentrował się obrót.

FAQ dotyczące High-Low Index

Co oznacza odczyt High-Low Index powyżej 70?

Oznacza, że w średniej z dziesięciu ostatnich sesji nowych 52-tygodniowych maksimów było więcej niż nowych 52-tygodniowych minimów w proporcji większej niż two-to-one. Jest to konwencjonalny sygnał silnego rynku. Nie pokazuje jednak, ile spółek w ogóle osiągnęło ekstremum. Tę liczbę należy sprawdzić obok wskaźnika.

Jaka jest różnica między Record High Percent a High-Low Index?

Record High Percent to wartość dla jednej sesji: liczba nowych maksimów podzielona przez sumę nowych maksimów i minimów, pomnożona przez 100. High-Low Index jest 10-dniową prostą średnią kroczącą tej wartości. Pierwsza miara opisuje bieżący dzień. Druga opisuje dwa ostatnie tygodnie.

Czy High-Low Index może wynosić 0 lub 100?

Tak. Jeżeli żadna spółka z uniwersum przez dziesięć kolejnych sesji nie ustanowi nowego 52-tygodniowego minimum, każdy dzienny odczyt wynosi 100 i tyle samo wynosi średnia. Jeżeli żadna spółka nie ustanowi ani maksimum, ani minimum, ułamek ma zerowy mianownik, a dla tej sesji odczyt jest niezdefiniowany.

Czy High-Low Index jest tym samym co szerokość rynku advance/decline?

Nie. Miara advance/decline dzieli przez całe uniwersum i opisuje kierunek ruchu w jednej sesji. High-Low Index dzieli przez niewielką grupę spółek znajdujących się na 52-tygodniowych ekstremach i pokazuje ich położenie względem cen z całego roku.

Ile spółek zwykle znajduje się w mianowniku High-Low Index?

W koszyku 40 spółek analizowanym tutaj od kwietnia do lipca 2026 r. w sesjach należących do przedziału 1 to 3 names w mianowniku znajdowało się średnio 2 spółek. Liczby dla całej giełdy są bezwzględnie większe, ale nadal stanowią niewielką część wszystkich notowanych spółek. Dlatego surowe liczby powinny być wyświetlane obok wskaźnika.


Każda liczba na tej stronie pochodzi z przechowywanego, wersjonowanego zapytania opartego na kursach zamknięcia. Po otwarciu dowolnego panelu można odczytać stojący za nim kod SQL albo odtworzyć tę samą serię szerokości rynku dla własnego koszyka w terminalu Strasmore.

#market breadth#52-week highs#indicators#record high percent