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는 어떻게 계산하는가?
두 단계이며, 각각 한 줄이면 충분하다.
- 단일 거래일의 Record High Percent: 분석 대상 종목군에서 신규 52주 고가로 마감한 종목 수와 신규 52주 저가로 마감한 종목 수를 센다. 고가 종목 수를 두 수의 합으로 나눈 뒤 100을 곱한다.
- 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다. 해당 거래일의 Record High Percent가 75여도 High-Low Index는 52.5로 표시된다.
이 차이가 이동평균이 치르는 대가다. 10일간의 흐름을 반영하므로 하루 만에 100에서 0까지 움직일 수 있는 지표를 완화하지만, 그만큼 반응이 늦어진다. 이 지수는 지난 2주 동안 시장 폭이 어디에 있었는지를 보여준다. 당일 오후에 무슨 일이 일어났는지는 보여주지 않는다.
신규 52주 고가에는 무엇이 포함되는가?
주가가 이전 52주 동안 기록한 모든 가격을 웃돌면 해당 종목은 신규 52주 고가를 기록한다. 데이터 제공업체마다 기준이 다르다. 일부는 장중 고가와 저가를 비교하고, 다른 곳은 종가만 비교한다. 따라서 같은 거래일에도 집계값이 달라질 수 있다. 이 페이지에서는 모든 계산에 종가를 사용한다. 신규 52주 고가와 저가에서 해당 목록 자체를 확인할 수 있다.
아래 패널은 2026년 4월 1일부터 7월 31일까지 고정된 미국 대형주 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 <= 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_date77개 거래일 동안 두 집계값이 함께 증가하는 경우는 드물다. 구간의 마지막 거래일인 Jul 29에는 40개 종목 중 3개가 52주 고가로 마감했고, 0개가 52주 저가로 마감했다. 첫 거래일인 Apr 1에는 고가 종목이 1개, 저가 종목이 1개였다. 나머지 종목은 각자의 가격 범위 안에 있었으므로 계산에 포함되지 않았다.
High-Low Index의 양호한 수치는 얼마인가?
50이 기준선이다. 고가와 저가가 균형을 이루는 지점이다. 통상적으로 강세 신호로 보는 기준은 70이다. 10일 평균 전체에서 신규 고가가 신규 저가보다 two-to-one을 웃도는 수준으로 많다는 뜻이다. 약세 기준은 그 반대인 30이다. 지수가 30과 70 사이에 있으면 시장의 양쪽 극단이 혼재한다는 의미다. 대부분의 기간에 지수는 이 구간에 머문다.
아래 패널은 같은 종목군을 대상으로 일별 원자료인 Record High Percent와 자체 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
),
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표시된 구간은 Apr 15의 Record High Percent 100에서 시작하며, 당시 지수는 52.5였다. Jul 29의 100에서 마감했고, 지수는 64였다. 각 수치를 70과 30 기준선에 대조해 보아야 한다. 두 선 사이의 거리는 평활화에 따른 대가다. 어느 날이든 평균에는 이전 9개 거래일의 수치가 포함되어 있다. 10일 평균을 계산하려면 10개 거래일이 필요하므로 구간의 첫 9개 거래일은 패널에서 제외했다.
분모는 시장 대부분을 무시한다
기억해야 할 핵심적인 한계는 다음과 같다. Record High Percent의 분모는 신규 고가와 신규 저가의 합뿐이다. 그 외의 종목은 모두 제외된다. 52주 가격 범위의 중간에 있는 종목은 분자에도 분모에도 들어가지 않는다. 따라서 이 지수는 3,000개 종목 중 900개가 극단값을 기록한 거래일과 9개만 기록한 거래일을 구분하지 못한다. 두 경우 모두 같은 두 자릿수 수치로 표시된다.
거래가 한산한 8월의 어느 거래소에 6,000개 종목이 상장되어 있다고 하자. 신규 고가 종목은 40개, 신규 저가 종목은 20개다. Record High Percent는 40을 60으로 나눈 66.7이며, 이는 시장이 폭넓게 상승한 것처럼 보인다. 그러나 전체 상장 종목의 1%만으로 계산한 수치다. 나머지 5,940개 종목에는 투표권이 없었다.
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
)
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_denominator1 to 3 names 구간에 속한 39개 거래일에는 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와 상승·하락 종목선 비교
두 지표 모두 시장에 몇 개 종목이 참여하는지를 묻는다. 다만 측정 기간이 다르다. 상승·하락 종목선은 전일 대비 상승 또는 하락으로 마감한 모든 종목을 집계한다. 분모는 전체 종목군이며, 하루 동안의 흐름을 보여준다. High-Low Index는 52주 극단값에 있는 종목만 집계한다. 분모가 작고, 1년 전체의 가격 흐름에 비해 현재 가격이 어디에 있는지를 보여준다. 특정 거래일에 시장 전체가 폭넓게 상승하더라도 52주 고가 부근에 있는 종목은 매우 적을 수 있다.
아래 패널은 같은 종목군에서 두 지표를 동일한 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표시 구간은 Apr 15에 High-Low Index 52.5, 10일 상승 종목 비율 52.8에서 시작한다. Jul 29에는 각각 64과 52.5로 마감했으며, 표시된 거래일은 68개다. 상승 종목 비율은 좁은 범위에 머문다. 일반적인 거래일에는 종목군의 절반가량이 상승 마감하며, 이를 10일 평균하면 선은 눈금의 중간 부근에 남는다. High-Low Index에는 이러한 기준점이 없다. 종목군에서 10개 거래일 연속으로 신규 52주 저가가 나오지 않으면 매일의 수치는 모두 100이고 평균도 100이다.
시장 폭은 참여도 지표와 함께 볼 때 더 정확하게 해석할 수 있다. 상대 거래량은 특정 종목의 당일 거래량이 평소 수준에 비해 이례적으로 많은지를 보여준다. 이번 주 주가 변동이 가장 큰 종목은 실제로 큰 폭으로 움직인 종목을 보여주고, 이번 주 비정상 거래량 종목은 거래가 집중된 종목을 보여준다.
High-Low Index FAQ
High-Low Index가 70을 웃돌면 무엇을 의미하는가?
최근 10개 거래일의 평균에서 신규 52주 고가 종목 수가 신규 52주 저가 종목 수보다 two-to-one을 웃도는 수준으로 많았다는 뜻이다. 통상적인 강세장 기준이다. 다만 극단값에 도달한 종목이 전체적으로 몇 개인지는 보여주지 않는다. 이 수치는 지수와 함께 확인해야 한다.
Record High Percent와 High-Low Index의 차이는 무엇인가?
Record High Percent는 단일 거래일의 수치다. 신규 고가 종목 수를 신규 고가와 신규 저가 종목 수의 합으로 나눈 뒤 100을 곱한다. High-Low Index는 이 수치의 10일 단순이동평균이다. 전자는 당일을 설명하고, 후자는 최근 2주를 설명한다.
High-Low Index가 0 또는 100이 될 수 있는가?
그렇다. 분석 대상 종목군에서 10개 거래일 연속으로 신규 52주 저가 종목이 나오지 않으면 매일의 수치는 100이고 평균도 100이다. 어떤 종목도 고가나 저가를 기록하지 않으면 분모가 0이 되어 해당 거래일의 수치는 정의되지 않는다.
High-Low Index는 상승·하락 종목선과 같은가?
아니다. 상승·하락 종목선은 전체 종목군을 분모로 사용하며 단일 거래일의 방향성을 보여준다. High-Low Index는 52주 극단값에 있는 소수의 종목을 분모로 사용하며 1년간 가격 흐름에 대비한 현재 위치를 보여준다.
High-Low Index의 분모에는 보통 몇 개 종목이 들어가는가?
2026년 4월부터 7월까지 측정한 40개 종목군에서는 1 to 3 names 구간에 속한 거래일의 분모 종목 수가 평균 2개였다. 거래소 전체의 집계값은 절대적인 종목 수로는 더 크지만 전체 상장 종목 중에서는 여전히 일부에 불과하다. 따라서 지수 옆에 원자료 집계값을 함께 표시해야 한다.
이 페이지의 모든 집계값은 종가를 기준으로 저장되고 버전이 관리되는 쿼리에서 산출했다. 각 패널을 열면 그 배후의 SQL을 확인할 수 있다. Strasmore terminal에서 직접 구성한 종목군으로 동일한 시장 폭 시계열을 다시 계산할 수도 있다.