In this chapter, we address a simple but consequential problem: how to construct a risk-free rate series for empirical finance in Vietnam. We evaluate available proxies, such as government bond yields, interbank overnight rates, and State Bank of Vietnam (SBV) policy rates, develop interpolation and frequency-alignment procedures, and quantify the sensitivity of key asset pricing outputs to the choice of risk-free proxy.
The risk-free rate is the most important single number in finance. It anchors excess returns, discount rates, factor premiums, the cost of equity, performance evaluation, and derivative pricing. Despite its foundational role, the risk-free rate is often treated as a given: a number downloaded from a database and plugged into formulas without further thought. In developed markets with deep, liquid government securities markets, this casual approach is usually harmless. In Vietnam, it is not.
Vietnam’s fixed-income market is thin, fragmented, and characterized by irregular issuance of short-term government securities. There is no single, universally accepted risk-free rate analogous to the 1-month Treasury bill rate that anchors virtually all asset pricing research in mature markets. Instead, researchers face a choice among imperfect proxies, each with distinct advantages and limitations. This choice is not innocuous: different proxies can produce meaningfully different excess returns, factor premiums, and valuation estimates.
This chapter develops a systematic approach to risk-free rate construction. We begin with the theoretical requirements for a risk-free asset, then evaluate available Vietnamese proxies against these requirements. We construct monthly risk-free rate series under alternative specifications, demonstrate frequency alignment and interpolation techniques, and conduct sensitivity analysis to quantify how the choice of proxy affects downstream results.
5.1 The Role of the Risk-Free Rate in Finance
5.1.1 Excess Returns
The most fundamental use of the risk-free rate is in the computation of excess returns. The excess return on asset \(i\) in period \(t\) is:
\[
r_{i,t}^{e} = r_{i,t} - r_{f,t}
\tag{5.1}\]
where \(r_{i,t}\) is the raw return and \(r_{f,t}\) is the risk-free rate over the same period, in the same currency, and under the same compounding convention. Excess returns isolate the compensation for bearing risk, removing the return that could be earned without risk exposure.
Mismeasurement of \(r_{f,t}\) directly contaminates every excess return observation and, by extension, every quantity derived from excess returns. If \(r_{f,t}\) is systematically biased upward, excess returns are systematically understated, factor premiums are compressed, and the cost of equity is overstated.
5.1.2 Factor Premiums
In the Fama and French (1993) three-factor model, the market risk premium is:
\[
\text{MKTRF}_t = r_{m,t} - r_{f,t}
\tag{5.2}\]
where \(r_{m,t}\) is the value-weighted market return. The size (SMB) and value (HML) premiums are defined as returns on long-short portfolios and do not directly depend on \(r_{f,t}\). However, the intercept (alpha) from a time-series regression of any portfolio’s excess return on the factors does depend on \(r_{f,t}\) through the dependent variable. A biased risk-free rate shifts all alphas uniformly.
where the weighted average cost of capital (WACC) depends on the cost of equity, which in turn depends on the risk-free rate through the Capital Asset Pricing Model:
A 100 basis point error in \(r_f\) flows through to the cost of equity and can change the present value of a long-duration cash flow stream by 10-20%, depending on the duration profile.
5.1.4 Performance Evaluation
Risk-adjusted performance measures such as the Sharpe ratio:
both depend directly on \(r_f\). The Sharpe ratio is particularly sensitive because the denominator (excess return volatility) is also affected by the level and variability of \(r_f\).
5.2 What Does “Risk-Free” Mean in Practice?
A truly risk-free asset must satisfy four conditions simultaneously (Table 5.1).
Table 5.1: Requirements for a Risk-Free Asset
Condition
Definition
Practical Challenge
No default risk
The issuer cannot fail to pay
Only sovereign debt in one’s own currency qualifies
Known cash flows
Payoff is certain ex ante
Rules out floating-rate instruments
No reinvestment risk
Maturity matches the investment horizon
Requires zero-coupon securities of exact maturity
High liquidity
Can be traded at a low cost
Thin government bond markets fail this test
No real-world asset perfectly satisfies all four conditions. Even in the deepest government bond markets, there is a liquidity premium in off-the-run securities and a convenience yield in on-the-run issues (Krishnamurthy and Vissing-Jorgensen 2012). The practical question is: which available instrument comes closest?
5.2.1 The Ideal Proxy
The ideal risk-free rate proxy for empirical asset pricing research has the following properties:
Short maturity: Minimizes reinvestment risk and term premium contamination. The conventional choice is 1-month maturity.
Government-backed: Eliminates credit risk (in domestic currency).
Actively traded: Ensures that the observed yield reflects current market conditions.
Regular issuance: Provides a continuous time series without gaps.
Consistent methodology: Yield computation is unambiguous and comparable over time.
5.3 Available Proxies in Vietnam
Vietnam’s financial infrastructure provides several candidate instruments, none of which perfectly satisfies all criteria. We evaluate each in turn.
5.3.1 Government Bond Yields
The Vietnamese government issues bonds across a range of maturities through the State Treasury and the Vietnam Bond Market (VBM). Key characteristics:
Table 5.2: Vietnamese Government Bond Characteristics
Feature
Description
Issuer
State Treasury of Vietnam
Primary market
Auction through HNX
Available maturities
1, 2, 3, 5, 7, 10, 15, 20, 30 years
Shortest benchmark
1-year (sometimes shorter tenors via T-bills)
Coupon structure
Fixed, semi-annual
Issuance frequency
Regular weekly/bi-weekly auctions
Secondary market liquidity
Concentrated in 3-5 year segment; short end is thin
Data availability
Available through DataCore.vn
The primary limitation of government bond yields as a risk-free proxy is the scarcity of short-maturity securities. One-year bonds are the shortest regularly issued benchmark, and their yield includes a term premium that is absent from a true risk-free rate. Treasury bills (maturity < 1 year) are issued irregularly and in small volumes, making them unsuitable as a continuous series.
5.3.2 Interbank Overnight Rate
The Vietnam interbank market sets overnight lending rates between commercial banks. The overnight rate is reported by the SBV.
Advantages: Very short maturity (overnight), high frequency (daily), reflects actual borrowing costs in the financial system.
Limitations: Reflects banking sector credit risk (interbank default risk, though small), can be volatile during liquidity crunches, and does not correspond to a tradeable zero-coupon instrument.
5.3.3 SBV Policy Rates
The State Bank of Vietnam sets several administered rates (Table 5.3).
Table 5.3: SBV Policy Rates
Rate
Role
Frequency of Change
Refinancing rate
Rate at which SBV lends to banks
Infrequent (policy meetings)
Discount rate
Rate for rediscounting eligible paper
Infrequent
Overnight lending rate
Ceiling for interbank overnight
Infrequent
Deposit rate cap
Maximum rate banks can pay on deposits
Infrequent
Advantages: Stable (changes infrequently), reflects the monetary policy stance, available for the entire sample period.
Limitations: Not a traded return (i.e., no investor can actually earn the policy rate). Represents an administrative target, not a market-clearing price. Responds to macroeconomic conditions with a lag.
5.3.4 Savings Deposit Rates
Commercial banks offer term deposits at rates subject to SBV caps. Short-term (1-month or 3-month) deposit rates are sometimes used as informal risk-free proxies in practitioner contexts.
Advantages: Represent an investable return for small investors, widely available.
Limitations: Subject to bank credit risk, vary across banks, caps create a ceiling that may not reflect true equilibrium rates, not standardized for research use.
5.3.5 Summary Comparison
Table 5.4: Comparison of Risk-Free Rate Proxies in Vietnam
Proxy
Default Risk
Maturity Match
Continuity
Liquidity
Recommended Use
1-Year Government Bond
Minimal (sovereign)
Poor (1Y vs 1M)
Good
Moderate
Annual/quarterly analysis
Treasury Bills (< 1Y)
Minimal (sovereign)
Good (when available)
Poor (irregular issuance)
Low
When available, preferred
Interbank Overnight Rate
Low (interbank)
Very short (overnight)
Excellent
High (interbank)
Daily/monthly analysis
SBV Refinancing Rate
None (administered)
N/A (not traded)
Excellent
N/A
Long-run comparisons only
1-Month Bank Deposit Rate
Low-moderate (bank)
Good (1M)
Good
N/A
Practitioner DCF
5.4 Constructing the Risk-Free Rate Series
We now construct alternative monthly risk-free rate series and examine their properties.
5.4.1 Loading and Cleaning Rate Data
Show code
import pandas as pdimport numpy as np# Assume rf_data contains: date, rate_type, rate_annual (annualized, in %)rf_raw = pd.read_parquet("data/risk_free_rates.parquet")# Preview available rate typesprint("Available rate types:")print(rf_raw["rate_type"].value_counts())
Asset pricing tests require monthly risk-free rates. Raw data may arrive at daily, weekly, or irregular frequencies. We use the following conversion logic:
Daily to monthly: Take the average of daily rates within each month, then convert from annualized to monthly.
Irregular to monthly: For series with gaps (e.g., treasury bills), forward-fill the most recent observation, then average within each month.
Annualized to monthly: Under simple compounding, \(r_f^{monthly} = r_f^{annual} / 12\). Under continuous compounding, \(r_f^{monthly} = r_f^{annual} / 12\) (since continuous rates are additive). We use simple compounding for consistency with the convention that stock returns are computed as arithmetic returns.
Show code
# Construct monthly risk-free rates from each proxydef construct_monthly_rf(rf_raw, rate_type, method="mean"):""" Convert raw rate data to monthly frequency. Parameters ---------- rf_raw : pd.DataFrame Raw rate data with columns: date, rate_type, rate_annual rate_type : str Which rate proxy to use method : str Aggregation method: 'mean', 'last', or 'first' Returns ------- pd.DataFrame Monthly risk-free rate with columns: date, rf_monthly """ subset = ( rf_raw[rf_raw["rate_type"] == rate_type] .sort_values("date") .set_index("date") )# Forward-fill gaps (for irregular series) subset = subset.resample("D").ffill()# Aggregate to monthlyif method =="mean": monthly = subset.resample("ME")["rate_annual"].mean()elif method =="last": monthly = subset.resample("ME")["rate_annual"].last()else: monthly = subset.resample("ME")["rate_annual"].first() monthly = monthly.reset_index() monthly.columns = ["date", "rf_annual"]# Convert annualized rate (%) to monthly decimal monthly["rf_monthly"] = monthly["rf_annual"] /100/12return monthly[["date", "rf_monthly", "rf_annual"]]# Construct series for each proxyrf_proxies = {}for proxy in ["govt_bond_1y", "interbank_overnight", "sbv_refinancing"]: rf_proxies[proxy] = construct_monthly_rf(rf_raw, proxy) rf_proxies[proxy]["proxy"] = proxyrf_all = pd.concat(rf_proxies.values(), ignore_index=True)
5.4.3 Handling Missing Data and Structural Breaks
Vietnamese rate data may contain gaps due to market closures, reporting changes, or the introduction of new instruments. We handle these systematically:
The spread between proxies is informative. A consistently positive spread (bond yield > interbank rate) reflects the term premium embedded in the 1-year bond. Periods where the interbank rate spikes above the bond yield typically correspond to liquidity crunches in the banking system.
5.4.5 Correlation Across Proxies
Table 5.7: Pairwise Correlation of Monthly Risk-Free Rate Proxies
Show code
rf_corr = rf_wide.corr().round(3)rf_corr.index = [x.replace("_", " ").title() for x in rf_corr.index]rf_corr.columns = [x.replace("_", " ").title() for x in rf_corr.columns]rf_corr
High correlation (> 0.8) between proxies suggests that the level and direction of interest rate movements are captured similarly by all proxies. Low correlation would indicate that the choice of proxy introduces substantial idiosyncratic variation into excess returns.
5.5 Excess Return Construction
With the risk-free rate series in hand, we now construct excess returns for individual stocks and for the market portfolio.
5.5.1 Matching Conventions
Excess return construction requires strict consistency across three dimensions (Table 5.8).
Table 5.8: Consistency Requirements for Excess Returns
Dimension
Requirement
Common Error
Currency
Same currency for \(r_i\) and \(r_f\)
Using USD rate for VND-denominated returns
Frequency
Same holding period
Using annualized \(r_f\) with monthly \(r_i\)
Compounding
Same convention
Mixing log and arithmetic returns
Show code
# Load monthly stock returnsstock_returns = pd.read_parquet("data/monthly_returns.parquet")# Assume columns: symbol, date (month-end), ret# Merge with risk-free rate# Use the blended series as the baselinerf_for_merge = rf_blended[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf"})stock_returns = stock_returns.merge(rf_for_merge, on="date", how="left")# Compute excess returnsstock_returns["ret_excess"] = stock_returns["ret"] - stock_returns["rf"]
5.6 Sensitivity Analysis: How Much Does the Proxy Choice Matter?
This is the central empirical question of the chapter. If different risk-free proxies produce essentially the same downstream results, the choice is inconsequential. If they produce different results, researchers must justify their choice and report robustness.
5.6.1 Effect on the Equity Premium
Table 5.9: Annualized Equity Premium Under Alternative Risk-Free Proxies
Note that SMB and HML are constructed as long-short portfolio returns and should be identical regardless of the risk-free proxy. Only MKTRF differs. However, if the researcher uses the risk-free rate to compute individual stock excess returns before sorting into factor portfolios, small differences in sorting may arise.
5.6.3 Effect on Alpha Estimates
The choice of risk-free proxy affects alpha estimates for any portfolio evaluated against a factor model. We illustrate this by estimating the alpha of a momentum portfolio under each proxy.
Table 5.11: Momentum Portfolio Alpha Sensitivity to Risk-Free Proxy
Even modest differences in the risk-free rate (50-150 basis points across proxies) can produce terminal value differences of 10-30%. Researchers and practitioners must document their risk-free rate choice explicitly and report sensitivity to alternatives.
5.7 Term Structure Considerations
When longer-horizon discount rates are needed (e.g., for multi-year DCF or cost of capital estimation), the risk-free rate should be maturity-matched. This requires constructing a yield curve from available government bond data.
5.7.1 Yield Curve Estimation
Gürkaynak, Sack, and Wright (2007) develop a parametric approach to yield curve estimation using the Nelson and Siegel (1987) and Svensson (1994) models. The Nelson-Siegel model parameterizes the instantaneous forward rate as:
where \(\tau\) is the maturity, \(\beta_0\) is the long-run level, \(\beta_1\) determines the slope, \(\beta_2\) determines the curvature, and \(\lambda\) controls the location of the hump.
The Nelson-Siegel yield curve allows extraction of a risk-free rate at any maturity. For monthly asset pricing, evaluate the curve at \(\tau = 1/12\) (one month). For DCF valuation with a 10-year horizon, evaluate at \(\tau = 10\). This maturity-matching approach is superior to using a single proxy for all purposes.
5.7.2 Extracting the Short-Rate from the Yield Curve
Show code
# Extract 1-month rate from Nelson-Siegel curve at each datedef extract_ns_short_rate(govt_yields, target_maturity=1/12):""" For each date, fit Nelson-Siegel and extract the yield at the target maturity. """ dates = govt_yields["date"].unique() short_rates = []for d in dates: obs = govt_yields[govt_yields["date"] == d].sort_values("maturity_years")iflen(obs) <3: # Need at least 3 points to fit short_rates.append({"date": d, "rf_ns": np.nan})continuetry: params = fit_nelson_siegel( obs["maturity_years"].values, obs["yield_pct"].values ) rf_ns = nelson_siegel_yield(target_maturity, *params) short_rates.append({"date": d, "rf_ns": rf_ns})exceptException: short_rates.append({"date": d, "rf_ns": np.nan})return pd.DataFrame(short_rates)ns_short_rates = extract_ns_short_rate(govt_yields)
5.7.3 Duration-Matched Excess Returns
The yield curve is also the input to a more radical proposal about what “excess return” should mean. The convention used throughout this book, subtracting a short rate from a monthly stock return, aligns the maturity of the benchmark with the frequency at which returns are measured rather than with the maturity of the cash flows being priced. Equities are long-duration claims; a one-month bill is not. Binsbergen, Ma, and Schwert (2026) argue that a cleaner counterfactual replaces each portfolio’s claim to the cash flow at horizon \(h\) with a zero-coupon government bond of maturity \(h\), strip by strip, and defines the excess return as the raw return less the return on that duration-matched bond portfolio. What remains is compensation for bearing risky cash flows, with the term premium stripped out and left to the fixed-income literature.
The consequences are larger than the mechanical nature of the adjustment suggests. On U.S. data from 1962 to 2020, the conventional market excess return averages 0.53% per month, while the duration-adjusted version averages \(-0.20\%\) per month with roughly double the volatility, and the two series correlate below 0.5. In the cross-section, the value and investment premia grow under the duration-adjusted definition, the size premium shrinks, and momentum is essentially unchanged because winner and loser portfolios have similar duration. Across 153 published anomalies, 20 change significance status when only the excess return definition is altered (Binsbergen, Ma, and Schwert 2026), a point we return to in Section 21.1.
For Vietnam the same logic applies over a shorter and steeper rate path. The Nelson-Siegel curve fitted above is the raw material for a duration-matched benchmark, but two practical obstacles stand in the way. First, secondary market liquidity is concentrated in the 3-5 year segment (Table 5.2), so the fitted curve is extrapolation as much as estimation at both the very short and the very long end, precisely the maturities the strip-matching requires. Second, the strip weights need a dividend yield and an expected growth rate for each portfolio, which is fragile for firms with irregular payout histories, and Vietnamese payout policy is irregular by developed-market standards. A workable compromise is to report factor premia against both a short rate and a fixed long-maturity government bond, and to disclose the dividend yield differential between the long and short legs so readers can judge how much of a premium could be a duration bet.
5.8 Real vs. Nominal Risk-Free Rates
For certain applications, particularly long-horizon valuation and real return analysis, the real (inflation-adjusted) risk-free rate is more appropriate than the nominal rate. The Fisher equation relates them:
where \(\pi^e\) is expected inflation. In practice, we can use realized CPI inflation as a proxy for expected inflation (under the assumption of rational expectations, or as an ex-post adjustment).
In periods of high inflation, the real risk-free rate can be substantially negative. This has implications for real excess return computation and for interpreting the equity premium in real terms. A negative real risk-free rate implies that nominal government securities do not preserve purchasing power, which strengthens the case for equity investment from a real-return perspective.
5.9 International Comparison
It is instructive to compare Vietnam’s risk-free rate environment with that of other emerging and developed markets to contextualize the magnitudes involved (Table 5.13).
Table 5.13: Risk-Free Rate Proxies: International Comparison
Country
Typical Proxy
Short-Term Maturity Available
Typical Level (%, 2020-2024)
Vietnam
Interbank overnight / 1Y govt bond
Limited (<1Y sparse)
2.5-6.0
Thailand
1-day bilateral repurchase rate
Yes (1-day repo)
0.5-2.5
Indonesia
Bank Indonesia 7-day reverse repo rate
Yes (7-day, 1M)
3.5-6.0
Philippines
91-day T-bill
Yes (91-day T-bill)
1.5-6.0
India
91-day T-bill
Yes (91-day T-bill)
3.5-7.0
South Korea
91-day CD rate
Yes (91-day CD)
1.0-3.5
Japan
Uncollateralized overnight call rate
Yes (overnight)
-0.1-0.1
Show code
# get the risk-free rate of Asian markets
Vietnam’s risk-free rate environment is characterized by relatively high nominal rates (reflecting inflation and growth dynamics), limited availability of very-short-maturity sovereign instruments, and greater reliance on interbank rates as the operational proxy. This is broadly similar to other ASEAN frontier markets but contrasts sharply with developed Asian markets, where deep government securities markets provide clean short-term benchmarks.
5.10 Best Practices Checklist
Based on the analysis in this chapter, we summarize the recommended practices for risk-free rate construction in Vietnamese financial research (Table 5.14).
Table 5.14: Best Practices for Risk-Free Rate Construction
Practice
Rationale
Use the shortest available maturity
Minimizes term premium contamination
Match frequency to return data
Avoids compounding mismatches between rf and stock returns
Enables replication; different proxies give different results
Report sensitivity to alternative proxies
Demonstrates robustness of conclusions
Avoid forward-looking policy rates
Policy rates are not investable returns
Handle gaps with documented interpolation
Forward-fill, then average within month; document procedure
Use Nelson-Siegel for maturity matching
Enables extraction of any-maturity rate from sparse data
Consider real rates for long-horizon analysis
Nominal rates overstate real compensation in high-inflation periods
Maintain a single consistent series per study
Mixing proxies across periods introduces structural breaks
5.11 Saving the Risk-Free Rate for Downstream Use
The final step is to save the constructed risk-free rate series for use in subsequent chapters.
Show code
# Save all variants for flexibilityrf_output = rf_blended[["date", "rf_monthly", "source"]].copy()rf_output["rf_annual_pct"] = rf_output["rf_monthly"] *12*100# Also save individual proxiesfor proxy_name, proxy_df in rf_proxies.items(): col_name =f"rf_{proxy_name}" rf_output = rf_output.merge( proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": col_name} ), on="date", how="left" )# Save to parquet for use in later chaptersrf_output.to_parquet("data/risk_free_rate.parquet", index=False)print(f"Risk-free rate series saved: {len(rf_output)} months")print(f"Date range: {rf_output['date'].min()} to {rf_output['date'].max()}")print(f"\nColumns: {list(rf_output.columns)}")
Tip
By saving the risk-free rate as a separate, well-documented file, all downstream chapters can merge it consistently. This avoids the common pitfall of reconstructing the risk-free rate differently in different analyses within the same study.
5.12 Summary
This chapter has established that risk-free rate construction is a first-order modeling decision in Vietnamese financial research, not a technical afterthought. The key takeaways are:
No perfect proxy exists in Vietnam. The interbank overnight rate, 1-year government bond yield, and SBV policy rate each have distinct strengths and limitations. A blended series using a documented priority hierarchy provides the most robust baseline.
The choice of proxy matters quantitatively. Different proxies can shift the estimated equity premium by 50-200 basis points annually, alter portfolio alphas, and change DCF terminal values by 10-30%.
Frequency alignment and compounding conventions must be handled with care. Converting annualized rates to monthly requires specifying the compounding convention. Gaps in the data require documented interpolation.
The Nelson-Siegel yield curve model enables the extraction of any-maturity risk-free rate from sparse government bond data, which is particularly valuable for maturity-matched discount rate estimation.
Sensitivity analysis is mandatory. Any study that reports results under a single risk-free proxy without reporting robustness to alternatives has an unquantified source of specification uncertainty.
Binsbergen, Jules H. van, Liang Ma, and Michael Schwert. 2026. “The Factor Multiverse: The Role of Interest Rates in Factor Return Measurement.”Management Science. https://doi.org/10.1287/mnsc.2024.08851.
Fama, Eugene F., and Kenneth R. French. 1993. “Common risk factors in the returns on stocks and bonds.”Journal of Financial Economics 33 (1): 3–56. https://doi.org/10.1016/0304-405X(93)90023-5.
Gürkaynak, Refet S, Brian Sack, and Jonathan H Wright. 2007. “The US Treasury Yield Curve: 1961 to the Present.”Journal of Monetary Economics 54 (8): 2291–2304.
Krishnamurthy, Arvind, and Annette Vissing-Jorgensen. 2012. “The Aggregate Demand for Treasury Debt.”Journal of Political Economy 120 (2): 233–67.
Nelson, Charles R, and Andrew F Siegel. 1987. “Parsimonious Modeling of Yield Curves.”Journal of Business, 473–89.
Svensson, Lars EO. 1994. “Estimating and Interpreting Forward Interest Rates: Sweden 1992-1994.” National bureau of economic research Cambridge, Mass., USA.
# Risk-Free Rate Construction in Vietnam::: callout-noteIn this chapter, we address a simple but consequential problem: how to construct a risk-free rate series for empirical finance in Vietnam. We evaluate available proxies, such as government bond yields, interbank overnight rates, and State Bank of Vietnam (SBV) policy rates, develop interpolation and frequency-alignment procedures, and quantify the sensitivity of key asset pricing outputs to the choice of risk-free proxy.:::The risk-free rate is the most important single number in finance. It anchors excess returns, discount rates, factor premiums, the cost of equity, performance evaluation, and derivative pricing. Despite its foundational role, the risk-free rate is often treated as a given: a number downloaded from a database and plugged into formulas without further thought. In developed markets with deep, liquid government securities markets, this casual approach is usually harmless. In Vietnam, it is not.Vietnam's fixed-income market is thin, fragmented, and characterized by irregular issuance of short-term government securities. There is no single, universally accepted risk-free rate analogous to the 1-month Treasury bill rate that anchors virtually all asset pricing research in mature markets. Instead, researchers face a choice among imperfect proxies, each with distinct advantages and limitations. This choice is not innocuous: different proxies can produce meaningfully different excess returns, factor premiums, and valuation estimates.This chapter develops a systematic approach to risk-free rate construction. We begin with the theoretical requirements for a risk-free asset, then evaluate available Vietnamese proxies against these requirements. We construct monthly risk-free rate series under alternative specifications, demonstrate frequency alignment and interpolation techniques, and conduct sensitivity analysis to quantify how the choice of proxy affects downstream results.## The Role of the Risk-Free Rate in Finance### Excess ReturnsThe most fundamental use of the risk-free rate is in the computation of excess returns. The excess return on asset $i$ in period $t$ is:$$r_{i,t}^{e} = r_{i,t} - r_{f,t}$$ {#eq-excess-return}where $r_{i,t}$ is the raw return and $r_{f,t}$ is the risk-free rate over the same period, in the same currency, and under the same compounding convention. Excess returns isolate the compensation for bearing risk, removing the return that could be earned without risk exposure.Mismeasurement of $r_{f,t}$ directly contaminates every excess return observation and, by extension, every quantity derived from excess returns. If $r_{f,t}$ is systematically biased upward, excess returns are systematically understated, factor premiums are compressed, and the cost of equity is overstated.### Factor PremiumsIn the @Fama1993 three-factor model, the market risk premium is:$$\text{MKTRF}_t = r_{m,t} - r_{f,t}$$ {#eq-mktrf}where $r_{m,t}$ is the value-weighted market return. The size (SMB) and value (HML) premiums are defined as returns on long-short portfolios and do not directly depend on $r_{f,t}$. However, the intercept (alpha) from a time-series regression of any portfolio's excess return on the factors does depend on $r_{f,t}$ through the dependent variable. A biased risk-free rate shifts all alphas uniformly.### Discount Rates and ValuationThe discounted cash flow model values a firm as:$$V_0 = \sum_{t=1}^{\infty} \frac{E[CF_t]}{(1 + r_{WACC})^t}$$ {#eq-dcf}where the weighted average cost of capital (WACC) depends on the cost of equity, which in turn depends on the risk-free rate through the Capital Asset Pricing Model:$$r_{e} = r_f + \beta_i (\bar{r}_m - r_f)$$ {#eq-capm-cost}A 100 basis point error in $r_f$ flows through to the cost of equity and can change the present value of a long-duration cash flow stream by 10-20%, depending on the duration profile.### Performance EvaluationRisk-adjusted performance measures such as the Sharpe ratio:$$\text{SR} = \frac{\bar{r}_p - \bar{r}_f}{\sigma(r_p - r_f)}$$ {#eq-sharpe}and Jensen's alpha:$$\alpha = \bar{r}_p - r_f - \hat{\beta}_p (\bar{r}_m - r_f)$$ {#eq-jensen}both depend directly on $r_f$. The Sharpe ratio is particularly sensitive because the denominator (excess return volatility) is also affected by the level and variability of $r_f$.## What Does "Risk-Free" Mean in Practice?A truly risk-free asset must satisfy four conditions simultaneously (@tbl-rf-requirements).| Condition | Definition | Practical Challenge ||--------------------|--------------------|--------------------------------|| No default risk | The issuer cannot fail to pay | Only sovereign debt in one's own currency qualifies || Known cash flows | Payoff is certain ex ante | Rules out floating-rate instruments || No reinvestment risk | Maturity matches the investment horizon | Requires zero-coupon securities of exact maturity || High liquidity | Can be traded at a low cost | Thin government bond markets fail this test |: Requirements for a Risk-Free Asset {#tbl-rf-requirements}No real-world asset perfectly satisfies all four conditions. Even in the deepest government bond markets, there is a liquidity premium in off-the-run securities and a convenience yield in on-the-run issues [@krishnamurthy2012aggregate]. The practical question is: which available instrument comes closest?### The Ideal ProxyThe ideal risk-free rate proxy for empirical asset pricing research has the following properties:1. **Short maturity**: Minimizes reinvestment risk and term premium contamination. The conventional choice is 1-month maturity.2. **Government-backed**: Eliminates credit risk (in domestic currency).3. **Actively traded**: Ensures that the observed yield reflects current market conditions.4. **Regular issuance**: Provides a continuous time series without gaps.5. **Consistent methodology**: Yield computation is unambiguous and comparable over time.## Available Proxies in VietnamVietnam's financial infrastructure provides several candidate instruments, none of which perfectly satisfies all criteria. We evaluate each in turn.### Government Bond YieldsThe Vietnamese government issues bonds across a range of maturities through the State Treasury and the Vietnam Bond Market (VBM). Key characteristics:| Feature | Description ||---|---|| Issuer | State Treasury of Vietnam || Primary market | Auction through HNX || Available maturities | 1, 2, 3, 5, 7, 10, 15, 20, 30 years || Shortest benchmark | 1-year (sometimes shorter tenors via T-bills) || Coupon structure | Fixed, semi-annual || Issuance frequency | Regular weekly/bi-weekly auctions || Secondary market liquidity | Concentrated in 3-5 year segment; short end is thin || Data availability | Available through DataCore.vn |: Vietnamese Government Bond Characteristics {#tbl-govt-bond-characteristics}The primary limitation of government bond yields as a risk-free proxy is the scarcity of short-maturity securities. One-year bonds are the shortest regularly issued benchmark, and their yield includes a term premium that is absent from a true risk-free rate. Treasury bills (maturity \< 1 year) are issued irregularly and in small volumes, making them unsuitable as a continuous series.### Interbank Overnight RateThe Vietnam interbank market sets overnight lending rates between commercial banks. The overnight rate is reported by the SBV.**Advantages**: Very short maturity (overnight), high frequency (daily), reflects actual borrowing costs in the financial system.**Limitations**: Reflects banking sector credit risk (interbank default risk, though small), can be volatile during liquidity crunches, and does not correspond to a tradeable zero-coupon instrument.### SBV Policy RatesThe State Bank of Vietnam sets several administered rates (@tbl-sbv-rates).| Rate | Role | Frequency of Change ||------------------|------------------|------------------------------------|| Refinancing rate | Rate at which SBV lends to banks | Infrequent (policy meetings) || Discount rate | Rate for rediscounting eligible paper | Infrequent || Overnight lending rate | Ceiling for interbank overnight | Infrequent || Deposit rate cap | Maximum rate banks can pay on deposits | Infrequent |: SBV Policy Rates {#tbl-sbv-rates}**Advantages**: Stable (changes infrequently), reflects the monetary policy stance, available for the entire sample period.**Limitations**: Not a traded return (i.e., no investor can actually earn the policy rate). Represents an administrative target, not a market-clearing price. Responds to macroeconomic conditions with a lag.### Savings Deposit RatesCommercial banks offer term deposits at rates subject to SBV caps. Short-term (1-month or 3-month) deposit rates are sometimes used as informal risk-free proxies in practitioner contexts.**Advantages**: Represent an investable return for small investors, widely available.**Limitations**: Subject to bank credit risk, vary across banks, caps create a ceiling that may not reflect true equilibrium rates, not standardized for research use.### Summary Comparison| Proxy | Default Risk | Maturity Match | Continuity | Liquidity | Recommended Use ||---|---|---|---|---|---|| 1-Year Government Bond | Minimal (sovereign) | Poor (1Y vs 1M) | Good | Moderate | Annual/quarterly analysis || Treasury Bills (< 1Y) | Minimal (sovereign) | Good (when available) | Poor (irregular issuance) | Low | When available, preferred || Interbank Overnight Rate | Low (interbank) | Very short (overnight) | Excellent | High (interbank) | Daily/monthly analysis || SBV Refinancing Rate | None (administered) | N/A (not traded) | Excellent | N/A | Long-run comparisons only || 1-Month Bank Deposit Rate | Low-moderate (bank) | Good (1M) | Good | N/A | Practitioner DCF |: Comparison of Risk-Free Rate Proxies in Vietnam {#tbl-proxy-comparison}## Constructing the Risk-Free Rate SeriesWe now construct alternative monthly risk-free rate series and examine their properties.### Loading and Cleaning Rate Data```{python}#| label: load-rf-data#| eval: falseimport pandas as pdimport numpy as np# Assume rf_data contains: date, rate_type, rate_annual (annualized, in %)rf_raw = pd.read_parquet("data/risk_free_rates.parquet")# Preview available rate typesprint("Available rate types:")print(rf_raw["rate_type"].value_counts())``````{python}#| label: fig-rf-raw-series#| eval: false#| fig-cap: "Raw Risk-Free Rate Proxies (Annualized, %)"import matplotlib.pyplot as pltfig, ax = plt.subplots(figsize=(8, 4.5))colors = {"govt_bond_1y": "#2C73D2","interbank_overnight": "#FF6B6B","sbv_refinancing": "#5DCEAF","tbill_3m": "#FFB347","deposit_1m": "#B19CD9"}for rate_type, color in colors.items(): subset = rf_raw[rf_raw["rate_type"] == rate_type].sort_values("date")iflen(subset) >0: ax.plot( subset["date"], subset["rate_annual"], label=rate_type.replace("_", " ").title(), color=color, linewidth=1.2, alpha=0.85 )ax.set_ylabel("Annualized Rate (%)")ax.set_xlabel("")ax.legend(frameon=False, fontsize=9, loc="upper right")ax.spines["top"].set_visible(False)ax.spines["right"].set_visible(False)plt.tight_layout()plt.show()```### Frequency AlignmentAsset pricing tests require monthly risk-free rates. Raw data may arrive at daily, weekly, or irregular frequencies. We use the following conversion logic:**Daily to monthly**: Take the average of daily rates within each month, then convert from annualized to monthly.**Irregular to monthly**: For series with gaps (e.g., treasury bills), forward-fill the most recent observation, then average within each month.**Annualized to monthly**: Under simple compounding, $r_f^{monthly} = r_f^{annual} / 12$. Under continuous compounding, $r_f^{monthly} = r_f^{annual} / 12$ (since continuous rates are additive). We use simple compounding for consistency with the convention that stock returns are computed as arithmetic returns.```{python}#| label: construct-monthly-rf#| eval: false# Construct monthly risk-free rates from each proxydef construct_monthly_rf(rf_raw, rate_type, method="mean"):""" Convert raw rate data to monthly frequency. Parameters ---------- rf_raw : pd.DataFrame Raw rate data with columns: date, rate_type, rate_annual rate_type : str Which rate proxy to use method : str Aggregation method: 'mean', 'last', or 'first' Returns ------- pd.DataFrame Monthly risk-free rate with columns: date, rf_monthly """ subset = ( rf_raw[rf_raw["rate_type"] == rate_type] .sort_values("date") .set_index("date") )# Forward-fill gaps (for irregular series) subset = subset.resample("D").ffill()# Aggregate to monthlyif method =="mean": monthly = subset.resample("ME")["rate_annual"].mean()elif method =="last": monthly = subset.resample("ME")["rate_annual"].last()else: monthly = subset.resample("ME")["rate_annual"].first() monthly = monthly.reset_index() monthly.columns = ["date", "rf_annual"]# Convert annualized rate (%) to monthly decimal monthly["rf_monthly"] = monthly["rf_annual"] /100/12return monthly[["date", "rf_monthly", "rf_annual"]]# Construct series for each proxyrf_proxies = {}for proxy in ["govt_bond_1y", "interbank_overnight", "sbv_refinancing"]: rf_proxies[proxy] = construct_monthly_rf(rf_raw, proxy) rf_proxies[proxy]["proxy"] = proxyrf_all = pd.concat(rf_proxies.values(), ignore_index=True)```### Handling Missing Data and Structural BreaksVietnamese rate data may contain gaps due to market closures, reporting changes, or the introduction of new instruments. We handle these systematically:```{python}#| label: check-missing#| eval: false# Check coverage for each proxycoverage = ( rf_all .groupby("proxy") .agg( start_date=("date", "min"), end_date=("date", "max"), n_months=("rf_monthly", "count"), n_missing=("rf_monthly", lambda x: x.isna().sum()), avg_rate_pct=("rf_annual", "mean") ) .round(2))print(coverage)```For periods where the primary proxy is unavailable, we construct a blended series using a priority hierarchy:```{python}#| label: construct-blended-rf#| eval: falsedef construct_blended_rf(rf_proxies, priority=None):""" Construct a blended monthly risk-free rate using proxy priority. Priority order (default): 1. Treasury bills (shortest maturity, sovereign) 2. Interbank overnight (short maturity, high frequency) 3. 1-year government bond (sovereign, regular) 4. SBV refinancing rate (fallback) """if priority isNone: priority = ["tbill_3m","interbank_overnight","govt_bond_1y","sbv_refinancing" ]# Create full date range all_dates = pd.date_range( start=min(df["date"].min() for df in rf_proxies.values()), end=max(df["date"].max() for df in rf_proxies.values()), freq="ME" ) blended = pd.DataFrame({"date": all_dates}) blended["rf_monthly"] = np.nan blended["source"] =""for proxy in priority:if proxy in rf_proxies: proxy_df = rf_proxies[proxy][["date", "rf_monthly"]].rename( columns={"rf_monthly": f"rf_{proxy}"} ) blended = blended.merge(proxy_df, on="date", how="left")# Fill missing values from this proxy mask = blended["rf_monthly"].isna() & blended[f"rf_{proxy}"].notna() blended.loc[mask, "rf_monthly"] = blended.loc[mask, f"rf_{proxy}"] blended.loc[mask, "source"] = proxy blended = blended.drop(columns=[f"rf_{proxy}"])return blendedrf_blended = construct_blended_rf(rf_proxies)``````{python}#| label: tbl-blended-source#| eval: false#| tbl-cap: "Data Source Composition of Blended Risk-Free Rate Series"source_comp = ( rf_blended .groupby("source") .agg( n_months=("date", "count"), pct=("date", lambda x: len(x) /len(rf_blended) *100) ) .round(1) .sort_values("n_months", ascending=False))source_comp```### Properties of the Constructed Series```{python}#| label: tbl-rf-summary-stats#| eval: false#| tbl-cap: "Summary Statistics of Monthly Risk-Free Rate Proxies"rf_wide = rf_all.pivot_table( index="date", columns="proxy", values="rf_monthly")summary = rf_wide.describe(percentiles=[0.10, 0.25, 0.50, 0.75, 0.90]).Tsummary = summary[["mean", "std", "min", "10%", "50%", "90%", "max"]]summary.columns = ["Mean", "Std", "Min", "P10", "Median", "P90", "Max"]# Convert to annualized percentage for interpretability(summary *12*100).round(2)``````{python}#| label: fig-rf-monthly-comparison#| eval: false#| fig-cap: "Monthly Risk-Free Rate Across Proxies"fig, axes = plt.subplots(2, 1, figsize=(8, 6), sharex=True)# Levelfor proxy, color in [ ("govt_bond_1y", "#2C73D2"), ("interbank_overnight", "#FF6B6B"), ("sbv_refinancing", "#5DCEAF")]: subset = rf_proxies[proxy].sort_values("date") axes[0].plot( subset["date"], subset["rf_monthly"] *100, label=proxy.replace("_", " ").title(), color=color, linewidth=1 )axes[0].set_ylabel("Monthly Rate (%)")axes[0].legend(frameon=False, fontsize=9)axes[0].spines["top"].set_visible(False)axes[0].spines["right"].set_visible(False)# Pairwise spread: govt bond - interbankmerged = rf_proxies["govt_bond_1y"][["date", "rf_monthly"]].merge( rf_proxies["interbank_overnight"][["date", "rf_monthly"]], on="date", suffixes=("_bond", "_interbank"))merged["spread"] = (merged["rf_monthly_bond"] - merged["rf_monthly_interbank"]) *100axes[1].fill_between( merged["date"], merged["spread"], 0, where=merged["spread"] >0, alpha=0.4, color="#2C73D2", label="Bond > Interbank")axes[1].fill_between( merged["date"], merged["spread"], 0, where=merged["spread"] <=0, alpha=0.4, color="#FF6B6B", label="Bond < Interbank")axes[1].axhline(0, color="black", linewidth=0.5)axes[1].set_ylabel("Spread (% monthly)")axes[1].set_xlabel("")axes[1].legend(frameon=False, fontsize=9)axes[1].spines["top"].set_visible(False)axes[1].spines["right"].set_visible(False)plt.tight_layout()plt.show()```The spread between proxies is informative. A consistently positive spread (bond yield \> interbank rate) reflects the term premium embedded in the 1-year bond. Periods where the interbank rate spikes above the bond yield typically correspond to liquidity crunches in the banking system.### Correlation Across Proxies```{python}#| label: tbl-rf-correlation#| eval: false#| tbl-cap: "Pairwise Correlation of Monthly Risk-Free Rate Proxies"rf_corr = rf_wide.corr().round(3)rf_corr.index = [x.replace("_", " ").title() for x in rf_corr.index]rf_corr.columns = [x.replace("_", " ").title() for x in rf_corr.columns]rf_corr```High correlation (\> 0.8) between proxies suggests that the level and direction of interest rate movements are captured similarly by all proxies. Low correlation would indicate that the choice of proxy introduces substantial idiosyncratic variation into excess returns.## Excess Return ConstructionWith the risk-free rate series in hand, we now construct excess returns for individual stocks and for the market portfolio.### Matching ConventionsExcess return construction requires strict consistency across three dimensions (@tbl-rf-consistency).| Dimension | Requirement | Common Error ||----------------------|------------------------|--------------------------|| Currency | Same currency for $r_i$ and $r_f$ | Using USD rate for VND-denominated returns || Frequency | Same holding period | Using annualized $r_f$ with monthly $r_i$ || Compounding | Same convention | Mixing log and arithmetic returns |: Consistency Requirements for Excess Returns {#tbl-rf-consistency}```{python}#| label: construct-excess-returns#| eval: false# Load monthly stock returnsstock_returns = pd.read_parquet("data/monthly_returns.parquet")# Assume columns: symbol, date (month-end), ret# Merge with risk-free rate# Use the blended series as the baselinerf_for_merge = rf_blended[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf"})stock_returns = stock_returns.merge(rf_for_merge, on="date", how="left")# Compute excess returnsstock_returns["ret_excess"] = stock_returns["ret"] - stock_returns["rf"]```### Market Excess Return```{python}#| label: compute-mktrf#| eval: false# Value-weighted market returnmarket_monthly = ( stock_returns .groupby("date") .apply(lambda g: np.average( g["ret"].dropna(), weights=g["mktcap"].loc[g["ret"].dropna().index] ) if g["ret"].dropna().shape[0] >0else np.nan, include_groups=False ) .reset_index(name="rm"))market_monthly = market_monthly.merge(rf_for_merge, on="date", how="left")market_monthly["mktrf"] = market_monthly["rm"] - market_monthly["rf"]``````{python}#| label: fig-mktrf-timeseries#| fig-cap: "Monthly Market Excess Return (MKTRF)"#| eval: falsefig, ax = plt.subplots(figsize=(8, 3.5))ax.bar( market_monthly["date"], market_monthly["mktrf"] *100, color=np.where(market_monthly["mktrf"] >=0, "#2C73D2", "#FF6B6B"), width=25, alpha=0.8)ax.axhline(0, color="black", linewidth=0.5)ax.set_ylabel("Market Excess Return (%)")ax.set_xlabel("")ax.spines["top"].set_visible(False)ax.spines["right"].set_visible(False)plt.tight_layout()plt.show()```## Sensitivity Analysis: How Much Does the Proxy Choice Matter?This is the central empirical question of the chapter. If different risk-free proxies produce essentially the same downstream results, the choice is inconsequential. If they produce different results, researchers must justify their choice and report robustness.### Effect on the Equity Premium```{python}#| label: tbl-equity-premium-sensitivity#| eval: false#| tbl-cap: "Annualized Equity Premium Under Alternative Risk-Free Proxies"results = []for proxy_name, proxy_df in rf_proxies.items(): rf_merge = proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf_proxy"} ) merged = market_monthly[["date", "rm"]].merge(rf_merge, on="date", how="inner") merged["mktrf_proxy"] = merged["rm"] - merged["rf_proxy"] n_months = merged["mktrf_proxy"].count() mean_monthly = merged["mktrf_proxy"].mean() std_monthly = merged["mktrf_proxy"].std() sharpe = mean_monthly / std_monthly if std_monthly >0else np.nan t_stat = mean_monthly / (std_monthly / np.sqrt(n_months)) results.append({"Proxy": proxy_name.replace("_", " ").title(),"N Months": n_months,"Mean (% ann.)": round(mean_monthly *12*100, 2),"Std (% ann.)": round(std_monthly * np.sqrt(12) *100, 2),"Sharpe (ann.)": round(sharpe * np.sqrt(12), 3),"t-stat": round(t_stat, 2) })pd.DataFrame(results).style.hide(axis="index")```### Effect on Factor Premiums```{python}#| label: tbl-factor-premium-sensitivity#| eval: false#| tbl-cap: "Factor Premium Sensitivity to Risk-Free Proxy (Annualized %)"# Load or construct factor returns# Assume factors_monthly has: date, smb, hml (these are long-short, rf-independent)# Only MKTRF changes with the proxyfactors_monthly = pd.read_parquet("data/factors_monthly.parquet")for proxy_name, proxy_df in rf_proxies.items(): rf_merge = proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf_proxy"} ) factors_merged = factors_monthly.merge(rf_merge, on="date", how="inner") factors_merged = factors_merged.merge( market_monthly[["date", "rm"]], on="date", how="inner" ) factors_merged[f"mktrf_{proxy_name}"] = ( factors_merged["rm"] - factors_merged["rf_proxy"] ) mean_mktrf = factors_merged[f"mktrf_{proxy_name}"].mean() *12*100 mean_smb = factors_merged["smb"].mean() *12*100 mean_hml = factors_merged["hml"].mean() *12*100print(f"{proxy_name:>25s}: MKTRF = {mean_mktrf:6.2f}%, "f"SMB = {mean_smb:6.2f}%, HML = {mean_hml:6.2f}%" )```Note that SMB and HML are constructed as long-short portfolio returns and should be identical regardless of the risk-free proxy. Only MKTRF differs. However, if the researcher uses the risk-free rate to compute individual stock excess returns before sorting into factor portfolios, small differences in sorting may arise.### Effect on Alpha EstimatesThe choice of risk-free proxy affects alpha estimates for any portfolio evaluated against a factor model. We illustrate this by estimating the alpha of a momentum portfolio under each proxy.```{python}#| label: tbl-alpha-sensitivity#| eval: false#| tbl-cap: "Momentum Portfolio Alpha Sensitivity to Risk-Free Proxy"import statsmodels.api as sm# Assume momentum_ret contains: date, mom_ret (raw return of WML portfolio)momentum_ret = pd.read_parquet("data/momentum_returns.parquet")alpha_results = []for proxy_name, proxy_df in rf_proxies.items(): rf_merge = proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf_proxy"} ) merged = ( momentum_ret .merge(rf_merge, on="date", how="inner") .merge(market_monthly[["date", "rm"]], on="date", how="inner") .merge(factors_monthly[["date", "smb", "hml"]], on="date", how="inner") ) merged["mom_excess"] = merged["mom_ret"] - merged["rf_proxy"] merged["mktrf"] = merged["rm"] - merged["rf_proxy"] X = sm.add_constant(merged[["mktrf", "smb", "hml"]]) y = merged["mom_excess"] model = sm.OLS(y, X).fit(cov_type="HAC", cov_kwds={"maxlags": 6}) alpha_results.append({"Proxy": proxy_name.replace("_", " ").title(),"Alpha (% monthly)": round(model.params["const"] *100, 3),"t-stat": round(model.tvalues["const"], 2),"R²": round(model.rsquared, 3) })pd.DataFrame(alpha_results).style.hide(axis="index")```### Effect on ValuationTo illustrate the valuation impact, consider a simple DCF exercise where the cost of equity is estimated via the CAPM.```{python}#| label: tbl-valuation-sensitivity#| eval: false#| tbl-cap: "Cost of Equity and Terminal Value Sensitivity to Risk-Free Proxy"# Example: firm with beta = 1.0, expected CF = 1 billion VND, growth = 3%beta_example =1.0cf =1e9# VNDgrowth =0.03valuation_results = []for proxy_name, proxy_df in rf_proxies.items(): rf_ann = proxy_df["rf_annual"].dropna().iloc[-12:].mean() /100# Latest year avg rf_merge = proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": "rf_proxy"} ) mkt_merged = market_monthly[["date", "rm"]].merge( rf_merge, on="date", how="inner" ) mkt_merged["mktrf"] = mkt_merged["rm"] - mkt_merged["rf_proxy"] erp = mkt_merged["mktrf"].mean() *12# Annualized equity premium cost_equity = rf_ann + beta_example * erp terminal_value = cf / (cost_equity - growth) if cost_equity > growth else np.nan valuation_results.append({"Proxy": proxy_name.replace("_", " ").title(),"Rf (% ann.)": round(rf_ann *100, 2),"ERP (% ann.)": round(erp *100, 2),"Cost of Equity (%)": round(cost_equity *100, 2),"Terminal Value (B VND)": round(terminal_value /1e9, 1) if terminal_value else"N/A" })pd.DataFrame(valuation_results).style.hide(axis="index")```::: callout-important## Key FindingEven modest differences in the risk-free rate (50-150 basis points across proxies) can produce terminal value differences of 10-30%. Researchers and practitioners must document their risk-free rate choice explicitly and report sensitivity to alternatives.:::## Term Structure ConsiderationsWhen longer-horizon discount rates are needed (e.g., for multi-year DCF or cost of capital estimation), the risk-free rate should be maturity-matched. This requires constructing a yield curve from available government bond data.### Yield Curve Estimation@gurkaynak2007us develop a parametric approach to yield curve estimation using the @nelson1987parsimonious and @svensson1994estimating models. The Nelson-Siegel model parameterizes the instantaneous forward rate as:$$f(\tau) = \beta_0 + \beta_1 \exp\left(-\frac{\tau}{\lambda}\right) + \beta_2 \frac{\tau}{\lambda} \exp\left(-\frac{\tau}{\lambda}\right)$$ {#eq-nelson-siegel}where $\tau$ is the maturity, $\beta_0$ is the long-run level, $\beta_1$ determines the slope, $\beta_2$ determines the curvature, and $\lambda$ controls the location of the hump.The corresponding yield is:$$y(\tau) = \beta_0 + \beta_1 \frac{1 - \exp(-\tau/\lambda)}{\tau/\lambda} + \beta_2 \left[\frac{1 - \exp(-\tau/\lambda)}{\tau/\lambda} - \exp(-\tau/\lambda)\right]$$ {#eq-ns-yield}```{python}#| label: nelson-siegel-estimation#| eval: falsefrom scipy.optimize import minimizedef nelson_siegel_yield(tau, beta0, beta1, beta2, lam):"""Nelson-Siegel yield curve model.""" tau_lam = tau / lam factor1 = (1- np.exp(-tau_lam)) / tau_lam factor2 = factor1 - np.exp(-tau_lam)return beta0 + beta1 * factor1 + beta2 * factor2def fit_nelson_siegel(maturities, yields):"""Fit Nelson-Siegel model to observed yields."""def objective(params): beta0, beta1, beta2, lam = paramsif lam <=0:return1e10 fitted = nelson_siegel_yield(maturities, beta0, beta1, beta2, lam)return np.sum((yields - fitted) **2) result = minimize( objective, x0=[yields[-1], yields[0] - yields[-1], 0, 2.0], method="Nelder-Mead", options={"maxiter": 10000} )return result.x# Example: fit to latest available government bond yields# Assume govt_yields contains: date, maturity_years, yield_pctgovt_yields = pd.read_parquet("data/govt_bond_yields.parquet")latest_date = govt_yields["date"].max()latest_yields = govt_yields[govt_yields["date"] == latest_date].sort_values("maturity_years")maturities = latest_yields["maturity_years"].valuesyields = latest_yields["yield_pct"].valuesparams = fit_nelson_siegel(maturities, yields)beta0, beta1, beta2, lam = params``````{python}#| label: fig-yield-curve#| eval: false#| fig-cap: "Vietnamese Government Bond Yield Curve (Nelson-Siegel Fit)"tau_fine = np.linspace(0.25, 30, 200)fitted_yields = nelson_siegel_yield(tau_fine, *params)fig, ax = plt.subplots(figsize=(7, 4))ax.scatter( maturities, yields, color="#FF6B6B", s=60, zorder=5, label="Observed yields", edgecolors="white")ax.plot( tau_fine, fitted_yields, color="#2C73D2", linewidth=2, label="Nelson-Siegel fit")ax.set_xlabel("Maturity (Years)")ax.set_ylabel("Yield (%)")ax.legend(frameon=False)ax.spines["top"].set_visible(False)ax.spines["right"].set_visible(False)plt.tight_layout()plt.show()print(f"Nelson-Siegel parameters:")print(f" β₀ (level) = {beta0:.4f}")print(f" β₁ (slope) = {beta1:.4f}")print(f" β₂ (curvature) = {beta2:.4f}")print(f" λ (decay) = {lam:.4f}")```::: callout-tipThe Nelson-Siegel yield curve allows extraction of a risk-free rate at any maturity. For monthly asset pricing, evaluate the curve at $\tau = 1/12$ (one month). For DCF valuation with a 10-year horizon, evaluate at $\tau = 10$. This maturity-matching approach is superior to using a single proxy for all purposes.:::### Extracting the Short-Rate from the Yield Curve```{python}#| label: extract-short-rate#| eval: false# Extract 1-month rate from Nelson-Siegel curve at each datedef extract_ns_short_rate(govt_yields, target_maturity=1/12):""" For each date, fit Nelson-Siegel and extract the yield at the target maturity. """ dates = govt_yields["date"].unique() short_rates = []for d in dates: obs = govt_yields[govt_yields["date"] == d].sort_values("maturity_years")iflen(obs) <3: # Need at least 3 points to fit short_rates.append({"date": d, "rf_ns": np.nan})continuetry: params = fit_nelson_siegel( obs["maturity_years"].values, obs["yield_pct"].values ) rf_ns = nelson_siegel_yield(target_maturity, *params) short_rates.append({"date": d, "rf_ns": rf_ns})exceptException: short_rates.append({"date": d, "rf_ns": np.nan})return pd.DataFrame(short_rates)ns_short_rates = extract_ns_short_rate(govt_yields)```### Duration-Matched Excess ReturnsThe yield curve is also the input to a more radical proposal about what "excess return" should mean. The convention used throughout this book, subtracting a short rate from a monthly stock return, aligns the maturity of the benchmark with the *frequency at which returns are measured* rather than with the *maturity of the cash flows being priced*. Equities are long-duration claims; a one-month bill is not. @binsbergen2026factor argue that a cleaner counterfactual replaces each portfolio's claim to the cash flow at horizon $h$ with a zero-coupon government bond of maturity $h$, strip by strip, and defines the excess return as the raw return less the return on that duration-matched bond portfolio. What remains is compensation for bearing risky cash flows, with the term premium stripped out and left to the fixed-income literature.The consequences are larger than the mechanical nature of the adjustment suggests. On U.S. data from 1962 to 2020, the conventional market excess return averages 0.53% per month, while the duration-adjusted version averages $-0.20\%$ per month with roughly double the volatility, and the two series correlate below 0.5. In the cross-section, the value and investment premia grow under the duration-adjusted definition, the size premium shrinks, and momentum is essentially unchanged because winner and loser portfolios have similar duration. Across 153 published anomalies, 20 change significance status when only the excess return definition is altered [@binsbergen2026factor], a point we return to in @sec-factor-zoo-scale.For Vietnam the same logic applies over a shorter and steeper rate path. The Nelson-Siegel curve fitted above is the raw material for a duration-matched benchmark, but two practical obstacles stand in the way. First, secondary market liquidity is concentrated in the 3-5 year segment (@tbl-govt-bond-characteristics), so the fitted curve is extrapolation as much as estimation at both the very short and the very long end, precisely the maturities the strip-matching requires. Second, the strip weights need a dividend yield and an expected growth rate for each portfolio, which is fragile for firms with irregular payout histories, and Vietnamese payout policy is irregular by developed-market standards. A workable compromise is to report factor premia against both a short rate and a fixed long-maturity government bond, and to disclose the dividend yield differential between the long and short legs so readers can judge how much of a premium could be a duration bet.## Real vs. Nominal Risk-Free RatesFor certain applications, particularly long-horizon valuation and real return analysis, the real (inflation-adjusted) risk-free rate is more appropriate than the nominal rate. The Fisher equation relates them:$$r_f^{real} \approx r_f^{nominal} - \pi^{e}$$ {#eq-fisher}where $\pi^e$ is expected inflation. In practice, we can use realized CPI inflation as a proxy for expected inflation (under the assumption of rational expectations, or as an ex-post adjustment).```{python}#| label: compute-real-rf#| eval: false# Load CPI data# Assume cpi_data contains: date, cpi_index (or inflation_mom for month-over-month)cpi_data = pd.read_parquet("data/cpi_monthly.parquet")cpi_data = cpi_data.sort_values("date")cpi_data["inflation_monthly"] = cpi_data["cpi_index"].pct_change()rf_real = rf_blended[["date", "rf_monthly"]].merge( cpi_data[["date", "inflation_monthly"]], on="date", how="inner")rf_real["rf_real"] = rf_real["rf_monthly"] - rf_real["inflation_monthly"]``````{python}#| label: fig-real-vs-nominal#| eval: false#| fig-cap: "Nominal vs. Real Monthly Risk-Free Rate"fig, ax = plt.subplots(figsize=(8, 4))ax.plot( rf_real["date"], rf_real["rf_monthly"] *100, color="#2C73D2", label="Nominal", linewidth=1)ax.plot( rf_real["date"], rf_real["rf_real"] *100, color="#FF6B6B", label="Real", linewidth=1)ax.axhline(0, color="black", linewidth=0.5, linestyle="--")ax.set_ylabel("Monthly Rate (%)")ax.set_xlabel("")ax.legend(frameon=False)ax.spines["top"].set_visible(False)ax.spines["right"].set_visible(False)plt.tight_layout()plt.show()```::: callout-noteIn periods of high inflation, the real risk-free rate can be substantially negative. This has implications for real excess return computation and for interpreting the equity premium in real terms. A negative real risk-free rate implies that nominal government securities do not preserve purchasing power, which strengthens the case for equity investment from a real-return perspective.:::## International ComparisonIt is instructive to compare Vietnam's risk-free rate environment with that of other emerging and developed markets to contextualize the magnitudes involved (@tbl-international-comparison).| Country | Typical Proxy | Short-Term Maturity Available | Typical Level (%, 2020-2024) ||---|---|---|---|| Vietnam | Interbank overnight / 1Y govt bond | Limited (<1Y sparse) | 2.5-6.0 || Thailand | 1-day bilateral repurchase rate | Yes (1-day repo) | 0.5-2.5 || Indonesia | Bank Indonesia 7-day reverse repo rate | Yes (7-day, 1M) | 3.5-6.0 || Philippines | 91-day T-bill | Yes (91-day T-bill) | 1.5-6.0 || India | 91-day T-bill | Yes (91-day T-bill) | 3.5-7.0 || South Korea | 91-day CD rate | Yes (91-day CD) | 1.0-3.5 || Japan | Uncollateralized overnight call rate | Yes (overnight) | -0.1-0.1 |: Risk-Free Rate Proxies: International Comparison {#tbl-international-comparison}```{python}# get the risk-free rate of Asian markets```Vietnam's risk-free rate environment is characterized by relatively high nominal rates (reflecting inflation and growth dynamics), limited availability of very-short-maturity sovereign instruments, and greater reliance on interbank rates as the operational proxy. This is broadly similar to other ASEAN frontier markets but contrasts sharply with developed Asian markets, where deep government securities markets provide clean short-term benchmarks.## Best Practices ChecklistBased on the analysis in this chapter, we summarize the recommended practices for risk-free rate construction in Vietnamese financial research (@tbl-best-practices).| Practice | Rationale ||---|---|| Use the shortest available maturity | Minimizes term premium contamination || Match frequency to return data | Avoids compounding mismatches between rf and stock returns || Use the same compounding convention | Arithmetic returns require arithmetic rf conversion || Document the proxy and source explicitly | Enables replication; different proxies give different results || Report sensitivity to alternative proxies | Demonstrates robustness of conclusions || Avoid forward-looking policy rates | Policy rates are not investable returns || Handle gaps with documented interpolation | Forward-fill, then average within month; document procedure || Use Nelson-Siegel for maturity matching | Enables extraction of any-maturity rate from sparse data || Consider real rates for long-horizon analysis | Nominal rates overstate real compensation in high-inflation periods || Maintain a single consistent series per study | Mixing proxies across periods introduces structural breaks |: Best Practices for Risk-Free Rate Construction {#tbl-best-practices}## Saving the Risk-Free Rate for Downstream UseThe final step is to save the constructed risk-free rate series for use in subsequent chapters.```{python}#| label: save-rf-series#| eval: false# Save all variants for flexibilityrf_output = rf_blended[["date", "rf_monthly", "source"]].copy()rf_output["rf_annual_pct"] = rf_output["rf_monthly"] *12*100# Also save individual proxiesfor proxy_name, proxy_df in rf_proxies.items(): col_name =f"rf_{proxy_name}" rf_output = rf_output.merge( proxy_df[["date", "rf_monthly"]].rename( columns={"rf_monthly": col_name} ), on="date", how="left" )# Save to parquet for use in later chaptersrf_output.to_parquet("data/risk_free_rate.parquet", index=False)print(f"Risk-free rate series saved: {len(rf_output)} months")print(f"Date range: {rf_output['date'].min()} to {rf_output['date'].max()}")print(f"\nColumns: {list(rf_output.columns)}")```::: callout-tipBy saving the risk-free rate as a separate, well-documented file, all downstream chapters can merge it consistently. This avoids the common pitfall of reconstructing the risk-free rate differently in different analyses within the same study.:::## SummaryThis chapter has established that risk-free rate construction is a first-order modeling decision in Vietnamese financial research, not a technical afterthought. The key takeaways are:1. **No perfect proxy exists** in Vietnam. The interbank overnight rate, 1-year government bond yield, and SBV policy rate each have distinct strengths and limitations. A blended series using a documented priority hierarchy provides the most robust baseline.2. **The choice of proxy matters quantitatively**. Different proxies can shift the estimated equity premium by 50-200 basis points annually, alter portfolio alphas, and change DCF terminal values by 10-30%.3. **Frequency alignment and compounding conventions** must be handled with care. Converting annualized rates to monthly requires specifying the compounding convention. Gaps in the data require documented interpolation.4. **The Nelson-Siegel yield curve model** enables the extraction of any-maturity risk-free rate from sparse government bond data, which is particularly valuable for maturity-matched discount rate estimation.5. **Sensitivity analysis is mandatory**. Any study that reports results under a single risk-free proxy without reporting robustness to alternatives has an unquantified source of specification uncertainty.<!-- ## Exercises1. **Proxy substitution test**: Re-estimate the Fama-French three-factor model for the Vietnamese market using each of the three risk-free proxies. Report the market premium, SMB, and HML under each specification. Are the cross-sectional patterns in factor loadings sensitive to the proxy choice?2. **Breakpoint analysis**: Identify structural breaks in the interbank overnight rate series using the @bai2003critical sequential break detection procedure. Do these breaks correspond to known monetary policy regime changes (e.g., SBV rate adjustments, regulatory changes)?3. **Inflation-adjusted equity premium**: Compute the real equity premium by subtracting realized CPI inflation from both the market return and the nominal risk-free rate. Compare the Sharpe ratio of the market portfolio in nominal vs. real terms.4. **Yield curve dynamics**: Estimate the Nelson-Siegel model at monthly frequency and track the time series of $\beta_0$ (level), $\beta_1$ (slope), and $\beta_2$ (curvature). Do these factors predict future stock market returns or macroeconomic variables, following @Ang2006 @ang2006does?5. **Currency-adjusted risk-free rate**: For foreign investors, the relevant risk-free rate includes currency hedging costs. Construct a USD-hedged risk-free rate using the VND/USD forward premium (covered interest parity) and compare it to the local-currency risk-free rate. How does this affect the equity premium from a foreign investor's perspective?6. **Deposit rate ceiling effects**: During periods when the SBV imposes binding deposit rate ceilings, the observed deposit rate may be below the market-clearing rate. Identify such periods and test whether the deposit-rate-based risk-free proxy produces systematically different excess returns compared to the interbank rate during ceiling-binding vs. non-binding periods. -->