Sharpe ratio-এ risk-free rate কীভাবে মিলিয়ে নেবেন
Sharpe ratio-এ risk-free rate সময়ের সঙ্গে বদলায়। bill yield-কে return frequency-এর সঙ্গে কীভাবে মেলাবেন এবং একটি স্থির rate কেন ফল বদলে দেয়, তা জানুন।
Sharpe ratio-এ risk-free rate হলো একই সময়পর্বে, আপনি যে ঝুঁকির মূল্যায়ন করছেন তা না নিয়ে যে রিটার্ন পেতে পারতেন। এটি একটি series: প্রতি period-এ একটি করে reading, এবং returns যে currency-তে প্রকাশিত, সেই currency-তেই quoted। এর frequency-কে return frequency-এর সঙ্গে মিলিয়ে নিন এবং period by period তা বাদ দিন। সবশেষে, একবার annualize করুন।
এই প্রক্রিয়া বাদ দেওয়াই প্রকাশিত Sharpe ratio-গুলোর বেশিরভাগ ভুলের কারণ। বিশ বছরের return history থেকে শুরুতেই একটি সংখ্যা তুলে নেওয়া—সাধারণত এই সপ্তাহে Treasury bill যত yield দিচ্ছে—2009 এবং 2024-এর ওপর একই hurdle rate চাপায়। Sharpe ratio নিয়ে আমাদের গাইড ratio-টি কী পরিমাপ করে তা ব্যাখ্যা করে। এই পেজে সেই input নিয়ে আলোচনা করা হয়েছে, যা প্রায় কেউ নথিভুক্ত করে না।
Risk-free rate কোনো স্থির সংখ্যা নয়
বিশ বছরের Sharpe ratio একটি rate history-কে অন্তর্ভুক্ত করে। নিচের panel-এ three-month Treasury bill-এর প্রতিটি calendar year-কে একটি average এবং তার আশপাশের range-এ সংকুচিত করা হয়েছে।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
SELECT
toString(toYear(date)) AS year,
round(avg(toFloat64(yield_3_month)), 2) AS avg_bill_pct,
round(min(toFloat64(yield_3_month)), 2) AS low_bill_pct,
round(max(toFloat64(yield_3_month)), 2) AS high_bill_pct
FROM global_markets.treasury_yields
WHERE date >= '2005-01-01'
AND yield_3_month IS NOT NULL
GROUP BY year
ORDER BY yearবার্ষিক average 3.22% থেকে 2005-এ এবং 3.74% থেকে 2026-এ ছিল, মোট 22টি calendar year জুড়ে। এই দুই reading-এর মধ্যকার গতিপথই গুরুত্বপূর্ণ। Line-টি একেবারে তলায় নেমে যায়, প্রায় এক দশক সেখানে থাকে, তারপর আবার ওপরে ওঠে। Low এবং high column দেখায়, একেকটি বছরে rate কত দূর পর্যন্ত উঠানামা করেছে। এ কারণেই এক বছরের Sharpe ratio-র ক্ষেত্রেও একটি মাত্র quote নয়, matched series ব্যবহার করা উচিত।
Sharpe ratio-তে কোন risk-free rate ব্যবহার করবেন
চারটি বৈশিষ্ট্য এই নির্বাচন নির্ধারণ করে।
- Short maturity। একটি measurement period জুড়ে rate-টি প্রায় নিশ্চিত হতে হবে। Monthly analysis-এর জন্য three-month bill উপযুক্ত। Ten-year note উপযুক্ত নয়, কারণ আপনি যে মাসটি মাপছেন, সেই সময়ে তার দাম বদলে যায়।
- Return-এর নিজস্ব currency। Euro-denominated strategy-কে euro bill-এর বিপরীতে মূল্যায়ন করতে হবে।
- Return-এর নিজস্ব frequency। Bill yield annual rate হিসেবে quoted হয়। Monthly return-এর সঙ্গে ব্যবহারের আগে annual quote-কে monthly rate-এ রূপান্তর করতে হবে।
- দুই পাশে তুলনীয় return definition। Bill-এর yield-ই তার সম্পূর্ণ return। তাই dividends বাদ দেওয়া strategy return একই ভিত্তিতে পরিমাপ করা হয় না। Price return বনাম total return এই পার্থক্যটি ব্যাখ্যা করে।
তৃতীয় পয়েন্টের conversion-এর দুটি প্রচলিত পদ্ধতি আছে। Simple division-এ annual quote-কে twelve দিয়ে ভাগ করা হয়। Compounding-এ one plus annual rate-এর twelfth root নেওয়া হয়। Hypothetical 5% bill-এর ক্ষেত্রে এগুলো মাসের জন্য যথাক্রমে 0.4167% এবং 0.4074% দেয়। পার্থক্যটি প্রায় এক basis point, যা sample-এর প্রতিটি মাসে পুনরাবৃত্তি হয়। এখানকার panel-গুলো compounding ব্যবহার করে। Bill yield-কে hurdle rate নয়, holding হিসেবে বিবেচনা করতে চাইলে dividend yield বনাম Treasury yield এবং অব্যবহৃত নগদ কোথায় রাখা যায় দেখুন।
Monthly excess return series কীভাবে তৈরি করবেন
প্রক্রিয়াটি যান্ত্রিক। প্রতিটি মাসের শেষ close নিন, মাসটির return হিসাব করুন, ওই মাসের bill quote-কে monthly rate-এ রূপান্তর করুন, তারপর তা বাদ দিন। এতে প্রতি মাসের জন্য একটি সংখ্যা-সম্বলিত excess return series তৈরি হয়। Monthly return কীভাবে মাপা হয় return অংশটি বিস্তারিত ব্যাখ্যা করে।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2019-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2019-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
)
SELECT
toString(cur.m) AS month,
round(100 * (cur.month_close / prv.prev_close - 1), 2) AS spy_ret_pct,
round(100 * rf.rf_month, 3) AS rf_pct,
round(100 * (cur.month_close / prv.prev_close - 1 - rf.rf_month), 2) AS excess_pct
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
ORDER BY cur.mএগুলো SPY-এর close। তাই return column হলো price return, যেখানে dividends বাদ রয়েছে। দেখা সময়পর্বের প্রথম মাসে risk-free column 0.128% থেকে শুরু হয়ে 0.359%-এ শেষ হয়েছে। কয়েক শতাংশ ওঠানামা করা equity month-এর পাশে risk-free strip-টি rounding-এর মতো দেখায়। কিন্তু 60 মাস ধরে এটি বাদ দিলে, একই বিষয় পরিমাপ করার দাবি করা দুটি Sharpe ratio-র মধ্যকার পুরো পার্থক্যটি এর ওপর নির্ভর করতে পারে।
প্রথমে বাদ দিন, তারপর annualize করুন
Series-গুলো aligned করার পর কাজের দুটি ক্রম ব্যবহার করা যায়, এবং দুটির ফল এক নয়। Excess first: monthly return থেকে monthly rate বাদ দিন, তারপর excess series annualize করুন। Annualize first: return-গুলো compound করে annual figure তৈরি করুন, bill-কে compound করে annual figure তৈরি করুন, তারপর একটিকে অন্যটি থেকে বাদ দিন।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2004-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2004-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
),
excess AS
(
SELECT
cur.m AS m,
cur.month_close / prv.prev_close - 1 AS ret,
rf.rf_month AS rf_month,
cur.month_close / prv.prev_close - 1 - rf.rf_month AS exc
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
)
SELECT
concat(toString(intDiv(count(), 12)), '-year') AS horizon,
round(100 * (exp(12 * avg(log(1 + exc))) - 1), 2) AS excess_first_pct,
round(100 * ((exp(12 * avg(log(1 + ret))) - 1)
- (exp(12 * avg(log(1 + rf_month))) - 1)), 2) AS annualize_first_pct,
round(100 * ((exp(12 * avg(log(1 + ret))) - 1)
- (exp(12 * avg(log(1 + rf_month))) - 1)
- (exp(12 * avg(log(1 + exc))) - 1)), 3) AS gap_pct
FROM excess
CROSS JOIN (SELECT arrayJoin([1, 3, 5, 10, 20]) AS years) AS hz
WHERE m >= subtractYears(toDate('2025-01-01'), years)
GROUP BY years
ORDER BY years20-year সময়পর্বে excess-first পদ্ধতির ফল বছরে 6.49%, আর অন্য পদ্ধতিতে 6.59%। পার্থক্য 0.099 percentage points। 1-year সময়পর্বে একই দুটি হিসাবের মধ্যে 0.814 points পার্থক্য রয়েছে। এখানকার প্রতিটি window-তেই annualize-first figure excess-first figure-এর ওপরে রয়েছে। পার্থক্যটি একটি cross term থেকে আসে। Return series-কে annual number-এ compound করলে risk premium-এর ওপরেও bill rate অর্জিত হয়। পরে annualized bill বাদ দিলেও ওই অংশটি আর বাদ যায় না। Cross term দুটি annualized number-এর গুণফলের সঙ্গে বাড়ে। তাই bill yield বেশি হলে পার্থক্যও বেশি হয়।
Annualizing-এর আরেকটি বিভাজন আছে। Arithmetic annualization-এ average monthly excess-কে twelve দিয়ে গুণ করা হয়। Geometric annualization-এ compounding করা হয়: cumulative result পুনরুৎপাদন করতে পারে এমন constant annual rate নির্ণয় করা হয়। Hypothetical two-period run ধরুন: প্রথমে +50%, তারপর -33.3%। এতে ফলাফল ঠিক শুরুর অবস্থানে ফিরে আসে। Arithmetic average হলো প্রতি period-এ +8.35%, আর geometric average হলো zero। এখানকার panel-গুলো compounding ব্যবহার করে। একটি গুরুত্বপূর্ণ footnote: arithmetic annualization-এ twelve times mean return minus twelve times mean bill rate, algebraically, twelve times mean excess-এর সমান। এই convention-এ subtraction-এর ক্রম numerator বদলায় না। তবে denominator বদলায়, কারণ rate নিজে পরিবর্তিত হলে excess return-এর standard deviation এবং raw return-এর standard deviation আর এক থাকে না।
একটি fixed rate ফলাফলে কতটা প্রভাব ফেলে
প্রচলিত shortcut হলো current bill yield নিয়ে history-র প্রতিটি period থেকে সেটি বাদ দেওয়া। নিচের panel-এ একই তারিখে শেষ হওয়া পাঁচটি window জুড়ে Sharpe ratio দুইভাবে হিসাব করা হয়েছে। একবার matched monthly series-এর বিপরীতে, আরেকবার window-এর শেষে কার্যকর থাকা bill yield-এর বিপরীতে।
প্রতিটি সংখ্যার পেছনের সঠিক SQL
WITH
monthly_px AS
(
SELECT
toStartOfMonth(date) AS m,
argMax(toFloat64(close), date) AS month_close
FROM global_markets.stocks_daily_aggs
WHERE ticker = 'SPY'
AND date >= '2004-12-01'
AND date < '2025-01-01'
GROUP BY m
),
prior_px AS
(
SELECT
addMonths(m, 1) AS m,
month_close AS prev_close
FROM monthly_px
),
monthly_rf AS
(
SELECT
toStartOfMonth(date) AS m,
pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_month
FROM global_markets.treasury_yields
WHERE date >= '2004-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
GROUP BY m
),
excess AS
(
SELECT
cur.m AS m,
cur.month_close / prv.prev_close - 1 AS ret,
rf.rf_month AS rf_month
FROM monthly_px AS cur
INNER JOIN prior_px AS prv ON prv.m = cur.m
INNER JOIN monthly_rf AS rf ON rf.m = cur.m
)
SELECT
concat(toString(intDiv(count(), 12)), '-year') AS horizon,
round(sqrt(12) * avg(ret - rf_month) / stddevSamp(ret - rf_month), 2) AS sharpe_matched_rf,
round(sqrt(12) * avg(ret - rf_fixed) / stddevSamp(ret - rf_fixed), 2) AS sharpe_fixed_rf,
round(abs(sqrt(12) * avg(ret - rf_month) / stddevSamp(ret - rf_month)
- sqrt(12) * avg(ret - rf_fixed) / stddevSamp(ret - rf_fixed)), 2) AS abs_gap
FROM excess
CROSS JOIN
(
SELECT pow(1 + avg(toFloat64(yield_3_month)) / 100, 1.0 / 12) - 1 AS rf_fixed
FROM global_markets.treasury_yields
WHERE date >= '2024-12-01'
AND date < '2025-01-01'
AND yield_3_month IS NOT NULL
) AS fixed_rate
CROSS JOIN (SELECT arrayJoin([1, 3, 5, 10, 20]) AS years) AS hz
WHERE m >= subtractYears(toDate('2025-01-01'), years)
GROUP BY years
ORDER BY years1-year window-এ দুটি reading-এর পার্থক্য 0.07। Twelve-month window-এ fixed rate-এর পক্ষে window-এর নিজস্ব average rate থেকে খুব বেশি দূরে সরে যাওয়ার সুযোগ থাকে না। 20-year window-এ পার্থক্য 0.18: matched series-এ 0.49, আর fixed rate-এ 0.32। Error নির্ভর করে আপনার বেছে নেওয়া একক rate এবং বাস্তবে কার্যকর থাকা average rate-এর দূরত্বের ওপর। Window যত দীর্ঘ হয়, সেই দূরত্ব বাড়ার সুযোগও তত বেশি হয়। পরবর্তী প্রতিটি হিসাব এই error বহন করে, এবং volatility targeting ও position sizing ঠিক এই ধরনের input-এর ওপর নির্ভর করে।
Currency trap
একটি currency-তে আয় করা strategy-কে অন্য currency-র bill-এর বিপরীতে মূল্যায়ন করলে ফলাফলটি কোনো currency-তেই অর্থবহ থাকে না। একটি currency-র ভেতরেই excess return হিসাব করুন: euro return-এর বিপরীতে euro bill, yen return-এর বিপরীতে yen bill। Hedged strategy-তে আরও একটি trap আছে। Currency hedge forward-এর ভিত্তিতে মূল্য নির্ধারণ করে, আর forward points দুই currency-র interest rate differential-এর কাছাকাছি থাকে। ফলে hedged foreign return-এর মধ্যে domestic rate-এর একটি অংশ আগে থেকেই থাকে। এর ওপর foreign bill বাদ দিলে একই rate দুইবার charge করা হয়। Rate-এর পাশে currency-টির নাম লিখলেই ambiguity দূর হয়।
Ratio-এর সঙ্গে rate-ও প্রকাশ করুন
Risk-free source এবং frequency উল্লেখ না করে প্রকাশিত Sharpe ratio কেউ যাচাই করতে পারে না। একই return stream থেকে দুটি desk 0.8 এবং 1.1 হিসাব করতে পারে, এবং ভিন্ন rate series ও ভিন্ন conversion convention ব্যবহার করলে দুটিই সঠিক হতে পারে। সংখ্যাটির সঙ্গে চারটি তথ্য থাকা উচিত: rate কোন instrument থেকে এসেছে, তার frequency, conversion convention এবং সঠিক window। এটাই এমন একটি সংখ্যার পার্থক্য, যা পাঠক audit করতে পারেন, আর এমন একটি সংখ্যার সঙ্গে, যা পাঠককে বিশ্বাস করেই নিতে হয়।
Data notes এবং reproducibility
প্রতিটি panel-এর rate series হলো daily Treasury yield curve থেকে নেওয়া three-month Treasury bill। প্রতিটি calendar month-এর মধ্যে এর average নেওয়া হয়েছে এবং annual quote-এর one plus-এর twelfth root হিসেবে monthly rate-এ রূপান্তর করা হয়েছে। Returns হলো SPY-এর month-end close; এগুলো শুধু price return এবং dividends বাদ দেওয়া হয়েছে। Ratio-গুলো monthly excess return-এর sample standard deviation এবং annualization-এর জন্য square root of twelve ব্যবহার করে। শেষের দুটি panel একই তারিখে শেষ হওয়া window ব্যবহার করে। Fixed-rate column-এ window-এর শেষ মাসের average bill quote নেওয়া হয়েছে। উপরের prose-এর প্রতিটি figure তার পাশের panel থেকে নেওয়া।
FAQ
Sharpe ratio-তে কোন risk-free rate ব্যবহার করা উচিত?
Returns যে currency-তে প্রকাশিত, সেই একই currency-র একটি short-term government bill। এটিকে returns-এর frequency-এ রূপান্তর করতে হবে। Monthly USD returns-এর ক্ষেত্রে এটি one-month অথবা three-month Treasury bill। দীর্ঘমেয়াদি maturity measurement period জুড়ে price risk বহন করে। তাই risk-free leg হিসেবে সেগুলো উপযুক্ত নয়।
দীর্ঘ return history থেকে কি আজকের Treasury bill yield বাদ দিতে পারি?
এটি প্রকাশিত Sharpe ratio-গুলোর সবচেয়ে প্রচলিত ভুল। উপরের 20-year window-এ fixed end-of-window rate এবং matched monthly series একই return-এর ওপর 0.18 পার্থক্যের reading তৈরি করে।
Risk-free rate বাদ দেওয়ার আগে কি সেটিকে annualize করব?
না। Annual bill quote-কে return-এর frequency-এ রূপান্তর করুন, period by period তা বাদ দিন, তারপর শেষে একবার excess series annualize করুন। প্রতিটি leg আলাদাভাবে annualize করে পরে বাদ দিলে ফলাফলে একটি cross term থেকে যায়।
Risk-free rate Sharpe ratio-কে কতটা বদলে দেয়?
মোটামুটি rate-এর পরিবর্তনকে annualized volatility দিয়ে ভাগ করলে যে ফল পাওয়া যায়, ততটা। Hypothetical strategy-র annualized volatility 15% হলে assumed rate-এ 4% পার্থক্য ratio-কে প্রায় 0.27 বদলে দেয়। এটিই একটি সাধারণ track record এবং একটি বহুল প্রশংসিত track record-এর মধ্যকার দূরত্ব হতে পারে।
Arithmetic এবং geometric annualization-এর মধ্যে পার্থক্য কী?
Arithmetic পদ্ধতিতে average period excess-কে বছরে period-এর সংখ্যা দিয়ে গুণ করা হয়। Geometric পদ্ধতিতে period-গুলো compound করে এমন constant rate নির্ণয় করা হয়, যা cumulative result পুনরুৎপাদন করে। প্রতি period-এ geometric figure arithmetic figure-এর সমান বা তার নিচে থাকে। Volatility বাড়লে দুটির দূরত্বও বাড়ে।
এখানকার প্রতিটি panel-এ সেটি তৈরির SQL রয়েছে। ফলে rate series এবং window—দুটিই দেখা যায়। অন্য ticker বা history-র অন্য কোনো সময়পর্বে একই construction চালাতে Strasmore terminal-এ plain English-এ অনুরোধ করুন।