Strasmore Research
学習 Matt Connor著者: Matt Connor

High-Low Indexとは?市場の広がりを測る指標

High-Low IndexはRecord High Percentの10日平均です。概算値による計算式と、少数銘柄に左右されるサンプル数の問題を解説します。

High-Low Indexは、二つの集計値から算出する市場の広がりを測る指標である。Record High Percentの10日単純移動平均であり、Record High Percentは、新52週高値銘柄数を新52週高値銘柄数と新52週安値銘柄数の合計で割り、100を掛けた値である。50を上回ると、新安値よりも新高値を付ける銘柄が多いことを示す。50を下回る場合は逆である。計算式はこれだけだ。以下では、概算値を使った算術と、決定的に見える数値が少数の銘柄に基づいてしまうサンプル数の問題を説明する。

High-Low Indexはどのように計算するのか?

二つの手順で計算できる。どちらも一行に収まる。

  1. 単一セッションのRecord High Percent:対象ユニバースで新52週高値を付けて引けた銘柄数と、新52週安値を付けて引けた銘柄数を数える。高値銘柄数を両者の合計で割り、100を掛ける。
  2. High-Low Index:直近10日間のRecord High Percentを平均する。

概算値を使うと分かりやすい。あるセッションで新高値が90銘柄、新安値が30銘柄だったとする。高値と安値の合計は120で、90を120で割ると0.75になる。したがって、そのセッションのRecord High Percentは75である。次に、10セッションの値が75、70、65、60、55、50、45、40、35、30だったとする。合計は525で、525を10で割ると52.5になる。High-Low Indexは、当日のRecord High Percentが75だった日に52.5を示す。

この差が移動平均によるトレードオフである。10日間の値を使うことで、一晩で100から0まで変動し得る系列を平滑化できる。一方で、反応は遅れる。この指数が示すのは、過去約二週間の市場の広がりである。当日の午後に何が起きたかを示すものではない。

新52週高値には何が含まれるのか?

株価が過去52週間に付けたすべての価格を上回ると、その株は新52週高値を付けたことになる。データプロバイダーによって基準は異なる。日中の高値・安値を比較する場合もあれば、終値だけを比較する場合もあり、同じセッションでも集計値が変わる。このページではすべて終値を基準とする。新52週高値と新52週安値では、対象銘柄の一覧を確認できる。

下のパネルは、2026年4月1日から7月31日まで、40銘柄の米国大型株で構成する固定バスケットについて、各セッションの両極値を集計している。この規模なら集計値を手計算で確認できる。そのため、後述する計算式の問題が見えやすい。

クエリ各セッションの52週高値・安値更新:米国大型株40銘柄、2026年4月〜7月
各数値の背後にある正確なSQL
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

77セッションを通じて、二つの集計値が同時に増えることはほとんどない。期間の最後のセッションであるJul 29には、40銘柄のうち3銘柄が52週高値で引け、0銘柄が52週安値で引けた。最初のセッションであるApr 1には、高値が1銘柄、安値が1銘柄だった。残る銘柄はすべて各銘柄のレンジ内にあり、計算には入らなかった。

High-Low Indexの良い読み取り値とは?

50が分岐点であり、高値と安値が均衡する水準である。一般的に70が強さの目安となる。10日平均全体で、新高値が新安値を二対一超で上回った状態だ。弱さの目安は、その反対の30である。30から70の間では、市場の両極が混在していることを示す。指数は通常この範囲にある。

下のパネルは、同じバスケットについて、日次のRecord High Percentとその10日平均を表示している。遅行は説明ではなくチャート上で確認できる。

クエリ過去最高値比率とその10日平均(High-Low Index)、40銘柄バスケット
各数値の背後にある正確なSQL
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

表示範囲は、Apr 15のRecord High Percent 100、High-Low Index 52.5で始まる。Jul 29にはRecord High Percent 100、指数64で終わる。70と30の目安に照らしてそれぞれを確認し、二本の線の間隔を平滑化のコストとして読む必要がある。任意の日の平均値には、前日までの九セッションがまだ含まれている。10日平均には10日分が必要なため、期間の最初の九セッションはパネルから除外している。

分母は市場の大半を無視する

ここで押さえておくべき制約がある。Record High Percentの分母は新高値と新安値の合計だけであり、それ以外は含まれない。52週レンジの中央付近にある銘柄は、分子にも分母にも入らない。この指数は、3,000銘柄のうち900銘柄が極値を付けたセッションと、9銘柄だけが極値を付けたセッションを区別できない。どちらも同じ、確信があるように見える二桁の数値を示す。

8月の低調なセッションに、6,000銘柄の取引所を想定してみよう。新高値が40銘柄、新安値が20銘柄だった場合、Record High Percentは40を60で割った66.7となる。市場全体が広く上昇したように見えるが、計算の対象となったのは上場銘柄の1%である。残る5,940銘柄には投票権がなかった。

40銘柄のバスケットでは、この問題を数えられる形で表示できる。期間中の各セッションを、何銘柄がいずれかの極値を付けたかによって分類する。

クエリ分母がどれほど薄くなるか:52週極値銘柄数別のセッション分類
各数値の背後にある正確なSQL
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

39セッションが含まれる1 to 3 namesバケットでは、各セッションの数値が、40銘柄中平均2銘柄に基づいていた。これらのセッションのRecord High Percentの中央値は100で、50の水準からの乖離は中央値で50ポイントだった。10 or more namesセッションでは、1セッションの平均対象銘柄数が10銘柄だった。Record High Percentの中央値は70で、中心値から20ポイント離れていた。

対象銘柄数が少ないセッションでは、表示できる数値自体に制約がある。極値を付けた銘柄が3銘柄の場合、取り得る値は0、33.3、66.7、100だけである。2銘柄の場合は0、50、100だけになる。高値2銘柄、安値1銘柄に基づく66.7という値は、そのサンプル数では小数点以下を支えられない。この問題への対処は明確だ。指数単独ではなく、高値と安値の実数を並べて確認する必要がある。

市場の広がり:High-Low Indexとadvance/declineの比較

どちらの指標も、何銘柄が相場に参加しているかを問う。ただし、対象とする時間軸が異なる。advance/declineの広がりは、前日比で上昇または下落して引けたすべての銘柄を数える。分母はユニバース全体で、1日間の動きを示す。High-Low Indexは、52週の極値にある銘柄だけを数える。分母は小さく、株価が1年間の履歴のどこに位置するかを示す。そのため、当日は市場全体が広く上昇していても、52週高値に近い銘柄はごく少ない場合がある。

下のパネルでは、同じバスケットについて両指標を同じ10セッションで平滑化し、同じ尺度で比較している。

クエリ同じバスケットの2つの騰落指標:10日High-Low Index対10日上昇銘柄比率
各数値の背後にある正確なSQL
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

表示範囲はApr 15に始まり、High-Low Indexは52.5、10日間の上昇銘柄比率は52.8だった。Jul 29にはそれぞれ6452.5で終わった。表示セッション数は68である。上昇銘柄比率は狭い範囲で推移する。通常のセッションでは、バスケットの約半数が上昇して引ける。その値を10日平均にすると、線は尺度の中央付近にとどまる。High-Low Indexにはこのような基準点がない。バスケット内で10セッション連続して52週安値を付ける銘柄がなければ、各日の値は100となり、平均も100になる。

市場の広がりは、参加度を測る指標と併せて読むと分かりやすい。Relative volumeは、ある銘柄の当日の売買高が通常時と比べて異常に大きいかを確認する。今週の株価上昇・下落率上位銘柄は実際に大きく動いた銘柄を示し、今週の異常な出来高銘柄は売買がどこに集中したかを示す。

High-Low Index FAQ

High-Low Indexが70を上回ると何を意味するのか?

直近10セッションの平均で、新52週高値が新52週安値を二対一超で上回ったことを意味する。これは一般的な相場の強さの目安である。ただし、極値に到達した銘柄数は示さない。この点は指数と併せて確認する必要がある。

Record High PercentとHigh-Low Indexの違いは何か?

Record High Percentは単一セッションの値である。新高値を新高値と新安値の合計で割り、100を掛ける。High-Low Indexは、その値の10日単純移動平均である。一方は当日を示し、もう一方は直近約二週間を示す。

High-Low Indexが0または100になることはあるか?

ある。ユニバース内で10セッション連続して新52週安値を付ける銘柄がなければ、日次の値はすべて100となり、平均も100になる。高値も安値も付ける銘柄がない場合は、分母が0になるため、そのセッションの値は定義されない。

High-Low Indexはadvance/declineの広がりと同じか?

異なる。advance/declineの広がりはユニバース全体を分母とし、単一日の方向性を示す。High-Low Indexは52週の極値にある少数の銘柄を分母とし、株価が1年間の価格推移のどこに位置するかを示す。

High-Low Indexの分母には通常何銘柄が含まれるのか?

2026年4月から7月まで測定した40銘柄のバスケットでは、1 to 3 namesバケットのセッションにおける分母の銘柄数は平均2だった。取引所全体では絶対数が増えるが、上場銘柄全体に占める割合は小さいままである。そのため、指数の横には高値と安値の実数を表示する必要がある。


このページのすべての集計値は、終値を対象とする保存済みのバージョン管理クエリから取得している。各パネルを開けば背後のSQLを確認できる。Strasmore terminalで、自分のバスケットを使って同じ市場の広がりを再構築することもできる。

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