High-Low Index কী এবং কীভাবে হিসাব করবেন
High-Low Index হলো Record High Percent-এর 10-day average। round-number formula, 50 reading-এর অর্থ এবং কম sample size কেন বিভ্রান্ত করে, তা উদাহরণসহ জানুন।
High-Low Index হলো market breadth-এর একটি পরিমাপ, যা 2টি গণনার ওপর ভিত্তি করে তৈরি: এটি Record High Percent-এর 10-day simple moving average, আর Record High Percent হলো new 52-week highs-কে new 52-week highs এবং new 52-week lows-এর যোগফল দিয়ে ভাগ করে 100 দিয়ে গুণ করা। 50-এর বেশি reading-এর অর্থ, new lows-এর তুলনায় বেশি সংখ্যক stock নতুন high করছে। 50-এর কম reading-এর অর্থ বিপরীত। Formula-টি এতটাই সংক্ষিপ্ত। এরপর round number ব্যবহার করে arithmetic এবং sample size-এর সেই ত্রুটি দেখানো হয়েছে, যার কারণে মাত্র কয়েকটি stock-এর ওপর নির্ভর করেও reading-টি অত্যন্ত নির্ভরযোগ্য বলে মনে হতে পারে।
High-Low Index কীভাবে হিসাব করবেন?
2টি ধাপ। দুটিই এক লাইনে লেখা যায়।
- Record High Percent, একটি session-এর জন্য: আপনার universe-এ নতুন 52-week high-এ close করা stock-এর সংখ্যা গণনা করুন, নতুন 52-week low-এ close করা stock-এর সংখ্যা গণনা করুন, highs-কে ওই 2টি সংখ্যার যোগফল দিয়ে ভাগ করুন, তারপর 100 দিয়ে গুণ করুন।
- High-Low Index: সর্বশেষ 10টি দৈনিক Record High Percent reading-এর average নিন।
Round number ব্যবহার করলে বিষয়টি স্পষ্ট হয়। একটি tape-এ 90টি new high এবং 30টি new low দেখা গেল। Highs এবং lows-এর যোগফল 120, আর 90 ভাগ 120 হলো 0.75। তাই ওই session-এর Record High Percent হলো 75। এবার 10টি session-এর reading নিন: 75, 70, 65, 60, 55, 50, 45, 40, 35 এবং 30। এগুলোর যোগফল 525, আর 525 ভাগ 10 হলো 52.5। যে দিনে ওই session-এর নিজস্ব Record High Percent ছিল 75, সেদিন High-Low Index reading হবে 52.5।
Moving average যে বিনিময়টি করে, এই ব্যবধান সেটিই দেখায়। 10 দিনের স্মৃতি এমন একটি series-কে মসৃণ করে, যা এক রাতেই 100 থেকে 0-তে নেমে যেতে পারে। এর বিনিময়ে indicator দেরিতে সাড়া দেয়। Index-টি বলে, গত 2 সপ্তাহে breadth কোথায় ছিল। আজ বিকেলে কী ঘটেছে, তা এটি কখনও বলে না।
নতুন 52-week high হিসেবে কী গণ্য হয়?
কোনো stock-এর price আগের 52 সপ্তাহে দেখা প্রতিটি price অতিক্রম করলে সেটি new 52-week high করে। Data provider-রা ভিত্তি নিয়ে একমত নয়: কেউ intraday high এবং low তুলনা করে, আবার কেউ কেবল closing price তুলনা করে। একই session-এর জন্য এই 2 পদ্ধতিতে আলাদা count পাওয়া যায়। এই পৃষ্ঠার সর্বত্র closing price-ই ভিত্তি হিসেবে ব্যবহৃত হয়েছে। New 52-week highs এবং lows তালিকাটি নিজেই দেখায়।
নিচের panel-এ 2026 সালের April 1 থেকে July 31 পর্যন্ত 40টি বড় market-cap-এর US name-এর একটি নির্দিষ্ট basket-এর প্রতিটি session-এর 2টি extreme count দেখানো হয়েছে। এই আকারের basket count-গুলোকে হাতে যাচাই করার মতো ছোট রাখে। পরবর্তী অংশে formula-টির ত্রুটি বোঝা যায় এই কারণেই।
প্রতিটি সংখ্যার পেছনের সঠিক 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টি session জুড়ে 2টি count খুব কমই একসঙ্গে বাড়ে। Jul 29, অর্থাৎ window-এর শেষ session-এ, 40টি name-এর মধ্যে 3টি 52-week high-এ এবং 0টি 52-week low-এ close করেছে। Apr 1, অর্থাৎ প্রথম session-এ, বিভাজন ছিল 1টি high এবং 1টি low। Basket-এর বাকি প্রতিটি name তার নিজস্ব range-এর মধ্যেই ছিল এবং calculation-এ প্রবেশ করেনি।
High-Low Index-এর ভালো reading কত?
50 হলো pivot, যেখানে highs এবং lows ভারসাম্যে থাকে। প্রচলিত strong marker হলো 70। এর অর্থ, পুরো 10-day average জুড়ে new high-এর সংখ্যা new low-এর সংখ্যার তুলনায় two-to-one-এর চেয়ে বেশি ছিল। প্রচলিত weak marker হলো 30, যা এর বিপরীত। 30 থেকে 70-এর মধ্যে index থাকলে বোঝায়, market-এর extremes মিশ্র অবস্থায় রয়েছে। অধিকাংশ সময় index এই range-এর মধ্যেই থাকে।
নিচের panel-এ একই basket-এর raw daily Record High Percent এবং তার নিজস্ব 10-day average দেখানো হয়েছে। Chart-এ lag-টি বর্ণনার পরিবর্তে সরাসরি দেখা যাবে।
প্রতিটি সংখ্যার পেছনের সঠিক 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_datePlotted range শুরু হয়েছে Apr 15 তারিখে Record High Percent 100 এবং index 52.5 দিয়ে। এটি শেষ হয়েছে Jul 29 তারিখে Record High Percent 100 এবং index 64-এ। প্রতিটি reading-কে 70 এবং 30 marker-এর সঙ্গে তুলনা করুন। 2টি line-এর মধ্যকার দূরত্বকে smoothing-এর মূল্য হিসেবে দেখুন: যেকোনো দিনে average এখনও আগের 9টি session বহন করছে। Window-এর প্রথম 9টি session panel-এ রাখা হয়নি, কারণ 10-day average-এর জন্য 10টি দিন প্রয়োজন।
Denominator market-এর অধিকাংশকে উপেক্ষা করে
এখানে যে সীমাবদ্ধতাটি মনে রাখা দরকার, তা হলো Record High Percent-এর denominator হলো new high এবং new low-এর যোগফল, আর কিছু নয়। কোনো stock তার 52-week range-এর মাঝামাঝি অবস্থান করলে সেটি numerator বা denominator—কোনোটিতেই থাকে না। Index এমন একটি session, যেখানে 3,000টি name-এর মধ্যে 900টি extreme-এ পৌঁছেছে, এবং এমন একটি session, যেখানে মাত্র 9টি name পৌঁছেছে—এই 2টির মধ্যে পার্থক্য করতে পারে না। উভয় ক্ষেত্রেই এটি একই আত্মবিশ্বাসী two-digit number দেখায়।
ধরা যাক, August-এর একটি ধীরগতির session-এ 6,000-name-এর একটি exchange-এ 40টি stock new high এবং 20টি new low করেছে। Record High Percent হলো 40 ভাগ 60, অর্থাৎ 66.7। এটি broad advance-এর মতো দেখায়। কিন্তু calculation-টি হয়েছে listing-এর মাত্র 1% থেকে। বাকি 5,940টি name কোনো ভোট দেয়নি।
40-name basket এই বিষয়টিকে গণনাযোগ্যভাবে screen-এ তুলে ধরে। Window-এর প্রতিটি session-কে কোনো name আদৌ extreme করেছে কি না, তার সংখ্যার ভিত্তিতে একটি bucket-এ রাখা হয়েছে।
প্রতিটি সংখ্যার পেছনের সঠিক 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 bucket-এর 39টি session-এ পুরো reading 40টির মধ্যে গড়ে 2টি name-এর ওপর নির্ভর করেছে। ওই session-গুলোর median Record High Percent ছিল 100 এবং 50 line থেকে median দূরত্ব ছিল 50 point। 10 or more namesটি session-এ, যার মধ্যে 1টি session-এ গড়ে 10টি name ছিল, median reading ছিল 70 এবং middle point থেকে দূরত্ব ছিল 20 point।
Arithmetic একটি thin session কী reading দেখাতে পারে, তার সীমা নির্ধারণ করে। কোনো extreme-এ 3টি name থাকলে সম্ভাব্য reading কেবল 0, 33.3, 66.7 এবং 100। 2টি name থাকলে কেবল 0, 50 এবং 100। 2টি high এবং 1টি low-এর ওপর ভিত্তি করে তৈরি 66.7 reading-এ এমন একটি decimal point আছে, যা তার sample সমর্থন করতে পারে না। এটি সামলানোর সহজ নিয়ম হলো: index-এর পাশে highs এবং lows-এর raw count পড়ুন। কখনও index-কে একা পড়বেন না।
Market breadth: High-Low Index বনাম advance/decline
উভয় measure-ই জানতে চায় কতগুলি stock market-এ অংশ নিচ্ছে। তবে এগুলো ভিন্ন সময়সীমায় বিষয়টি মাপে। Advance/decline breadth গতকালের তুলনায় up বা down হয়ে শেষ করা প্রতিটি name গণনা করে। এর denominator হলো পুরো universe, এবং এটি 1 দিনের চিত্র বর্ণনা করে। High-Low Index কেবল 52-week extreme-এ থাকা name গণনা করে। এর denominator ছোট, এবং এটি পুরো 1 বছরের history-এর তুলনায় price কোথায় অবস্থান করছে, তা বর্ণনা করে। কোনো দিনে market broad-based ভাবে higher হলেও খুব কম সংখ্যক name 52-week high-এর কাছাকাছি থাকতে পারে।
নিচের panel-এ একই basket-এর ওপর উভয় measure-কে একই 10টি session জুড়ে smooth করা হয়েছে। এতে 2টি measure একই scale-এ দেখা যায়।
প্রতিটি সংখ্যার পেছনের সঠিক 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_datePlotted range শুরু হয়েছে Apr 15 তারিখে High-Low Index-এর জন্য 52.5 এবং 10-day advancing share-এর জন্য 52.8 দিয়ে। এটি শেষ হয়েছে Jul 29 তারিখে যথাক্রমে 64 এবং 52.5-এ। মোট plotted session ছিল 68টি। Advancing share একটি সংকীর্ণ band-এর মধ্যে থাকে। সাধারণ session-এ একটি basket-এর প্রায় অর্ধেক name higher close করে। 10টির average নিলে line scale-এর মাঝামাঝি থাকে। High-Low Index-এর এমন কোনো anchor নেই। Basket-এ 10টি session ধরে কোনো name 52-week low print না করলে প্রতিটি daily reading হয় 100, এবং average-ও 100 হয়।
Participation measure-এর পাশে breadth পড়লে বিশ্লেষণটি ভালো হয়। Relative volume জানতে চায়, কোনো name আজ তার নিজস্ব স্বাভাবিক মাত্রার তুলনায় অস্বাভাবিকভাবে বেশি volume-এ trade করছে কি না। এই সপ্তাহের সবচেয়ে বড় stock movers দেখায় কোন name-গুলো বাস্তবে বেশি price movement করেছে, আর এই সপ্তাহের unusual volume stocks দেখায় trading কোথায় হয়েছে।
High-Low Index FAQ
70-এর বেশি High-Low Index reading-এর অর্থ কী?
এর অর্থ, সর্বশেষ 10টি session-এর average জুড়ে new 52-week high-এর সংখ্যা new 52-week low-এর সংখ্যার তুলনায় two-to-one-এর চেয়ে বেশি ছিল। এটি প্রচলিত strong-tape marker। তবে কতগুলি stock আদৌ extreme-এ পৌঁছেছে, তা এটি বলে না। সেই সংখ্যা index-এর পাশে পরীক্ষা করা উচিত।
Record High Percent এবং High-Low Index-এর মধ্যে পার্থক্য কী?
Record High Percent হলো একটি session-এর figure: new highs-কে new highs এবং new lows-এর যোগফল দিয়ে ভাগ করে 100 দিয়ে গুণ করা। High-Low Index হলো ওই figure-এর 10-day simple moving average। একটি আজকের চিত্র বর্ণনা করে। অন্যটি গত 2 সপ্তাহের চিত্র বর্ণনা করে।
High-Low Index কি 0 বা 100 হতে পারে?
হ্যাঁ। Universe-এর কোনো stock টানা 10টি session-এ new 52-week low না করলে প্রতিটি daily reading হবে 100 এবং average-ও হবে 100। কোনো stock high বা low—কোনোটিই না করলে fraction-এর denominator শূন্য হয়, তাই ওই session-এর কোনো defined reading থাকে না।
High-Low Index কি advance/decline breadth-এর সমান?
না। Advance/decline breadth পুরো universe দিয়ে ভাগ করে এবং একটি দিনের direction বর্ণনা করে। High-Low Index 52-week extreme-এ থাকা ছোট group of stocks দিয়ে ভাগ করে এবং 1 বছরের price history-এর তুলনায় তাদের অবস্থান বর্ণনা করে।
High-Low Index-এর denominator-এ সাধারণত কতগুলি stock থাকে?
2026 সালের April থেকে July পর্যন্ত এখানে মাপা 40-name basket-এ 1 to 3 names bucket-এর session-গুলোতে denominator-এ গড়ে 2টি name ছিল। Exchange-wide count absolute terms-এ বড় হলেও মোট listing-এর তুলনায় তা একটি thin slice-ই থাকে। এই কারণেই index-এর পাশে screen-এ raw count রাখা উচিত।
এই পৃষ্ঠার প্রতিটি count closing price-এর ওপর ভিত্তি করে তৈরি একটি stored, versioned query থেকে নেওয়া। যেকোনো panel খুলে এর পেছনের SQL পড়ুন, অথবা Strasmore terminal-এ নিজের পছন্দের basket-এর ওপর একই breadth series পুনর্গঠন করুন।