The test of uncovered interest parity is the test that exchange rates are driven by capital flows (proxies by money market flows to places with the highest interest rate). If one currency has a higher interest rate than the other, flows into that currency will drive it higher until the expected deprecation is sufficient to offset the interest rate advantage.
Using the South African to US exchange rate and three month interest rates from the St. Louis Fed database for the period December 1980 to October 2025.
# Download data
da <- read.csv('./Data/SAUIP.csv')
# Change the column names
colnames(da) <- c("Date", "SA3m", "US3m", "SAUSD")
# Make the date a date object
da$Date <- as.Date(da$Date, format = "%Y-%m-%d")
# Remove the rows with no data
da <- da[complete.cases(da), ]
# Check
head(da)
## Date SA3m US3m SAUSD
## 564 1980-12-01 6.040000 15.49 0.7529
## 565 1981-01-01 6.486154 15.02 0.7481
## 566 1981-02-01 7.364167 14.79 0.7737
## 567 1981-03-01 7.543077 13.36 0.7906
## 568 1981-04-01 7.743478 13.69 0.8109
## 569 1981-05-01 8.540000 16.30 0.8380
The interest rate data are in raw percentages and are one-year equivalent. Therefore we need to adjust to the funds that you will actually receive or pay over three months.
# Create the 3 month equivalent interest rate
da$SA3meq <- (1 + da$SA3m/100)^(1/4)
da$US3meq <- (1 + da$US3m/100)^(1/4)
# Check
head(da)
## Date SA3m US3m SAUSD SA3meq US3meq
## 564 1980-12-01 6.040000 15.49 0.7529 1.014770 1.036659
## 565 1981-01-01 6.486154 15.02 0.7481 1.015835 1.035603
## 566 1981-02-01 7.364167 14.79 0.7737 1.017923 1.035085
## 567 1981-03-01 7.543077 13.36 0.7906 1.018347 1.031846
## 568 1981-04-01 7.743478 13.69 0.8109 1.018821 1.032596
## 569 1981-05-01 8.540000 16.30 0.8380 1.020698 1.038472
The forward rate will be equal to
\[F_{3m, SA-USD} = \frac{3m SA}{3m US} \times \frac{ZAR}{USD}\]
# Combine three NAs because we do not have data for the first three months,
# with the forward rate to create a vector of forward rates
da$SAUSDf <- c(rep(NA, 3), da$SA3meq[1:(length(da$SAUSD)-3)]
/da$US3meq[1:(length(da$SAUSD)-3)]
*da$SAUSD[1:(length(da$SAUSD)-3)])
Covered interest parity must hold if there are no frictions otherwise there is an immediate arbitrage. However, uncovered interest parity may make or lose money. If there is a consistent deviation, it suggests that there is an inefficiency that can be exploited.
Rational expectations would assume that foreign exchange players know the UIP model and will expect the exchange rate to equal the forward rate. Therefore if we test
\[\Delta[S_{+3m}] = \alpha + \beta E[\Delta_{3m} S_t] + \varepsilon_t\]
We could substitute the forward rate for the expected change and estimate the value of \(\beta\). UIP says that \(\beta\) should be equal to one.
\[\Delta[S_{+3m}] = \alpha + \beta [F_{3m} /S_t] + \varepsilon_t\] Calculate the 3 month percentage change in the exchange rate (\(\delta[S_{+3m}]\)) and the difference between the current exchange rate and the forward rate (or the forward premium, \(F_{3m}/S_t\).
# The actual change in the exchange rate over three months
da$FX3mret <- c(rep(NA, 3), da$SAUSD[4:length(da$SAUSD)] /
da$SAUSD[1:(length(da$SAUSD) - 3)] - 1)
# The expected change in the exchange rate over three months.
da$EXP3mret <- c(rep(NA, 3), da$SAUSDf[4:length(da$SAUSD)] /
da$SAUSD[1:(length(da$SAUSD) -3)] - 1)
Now run the regression to see if \(\beta\) is equal to one.
summary(lm(da$FX3mret ~ da$EXP3mret))
##
## Call:
## lm(formula = da$FX3mret ~ da$EXP3mret)
##
## Residuals:
## Min 1Q Median 3Q Max
## -0.26591 -0.04339 -0.00446 0.03229 0.32590
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 0.030619 0.007345 4.168 3.58e-05 ***
## da$EXP3mret -0.679190 0.441437 -1.539 0.124
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 0.07692 on 534 degrees of freedom
## (3 observations deleted due to missingness)
## Multiple R-squared: 0.004413, Adjusted R-squared: 0.002549
## F-statistic: 2.367 on 1 and 534 DF, p-value: 0.1245
The null hypothesis for the summary is the usual test of whether the coefficient is equal to zero. We want to test if it is equal to one:
\(H0: \beta = 1\)
\(H1: \beta \ne 1\)
Therefore the test statistic is
\[ T = \frac{\hat{\beta} - 1}{SE} = \frac{-0.6792 - 1}{0.4414} = -3.8\]
Therefore the null hypothesis is rejected.
However, the joint hypothesis problem means that we are not sure if we are rejecting UIP or the idea that expectations are formed rationally and are represented by the forward rate.
One indication that UIP does not generally hold is the popularity of the carry trade whereby investors borrow in a low interet rate currency to deposit in a high interest rate currency. The theory suggest that on average, the interest rate advantage will be offset by a fall in the value of the exchange rate.
We can calculate the profit from CIP and UIP each 3 months.
# Calculate the CIP
# (SA3m * exchange rate) / (US3m * forward rate)
da$CIP <- c(rep(NA, 3), (da$SA3meq[1:(length(da$Date) -3)] *
da$SAUSD[1:(length(da$Date) - 3)])
/ (da$US3meq[1:(length(da$Date) -3)] *
da$SAUSDf[4:length(da$Date)]))
# Calculate UIP
# (SA3m * exchange rate) / (USD3m * actual exchange rate in 3 months)
da$UIP <- c(rep(NA, 3), (da$SA3meq[1:(length(da$Date) -3)] *
da$SAUSD[1:(length(da$Date) - 3)])
/ (da$US3meq[1:(length(da$Date) -3)] *
da$SAUSD[4:length(da$Date)]))
head(da)
## Date SA3m US3m SAUSD SA3meq US3meq SAUSDf FX3mret
## 564 1980-12-01 6.040000 15.49 0.7529 1.014770 1.036659 NA NA
## 565 1981-01-01 6.486154 15.02 0.7481 1.015835 1.035603 NA NA
## 566 1981-02-01 7.364167 14.79 0.7737 1.017923 1.035085 NA NA
## 567 1981-03-01 7.543077 13.36 0.7906 1.018347 1.031846 0.7370019 0.05007305
## 568 1981-04-01 7.743478 13.69 0.8109 1.018821 1.032596 0.7338201 0.08394600
## 569 1981-05-01 8.540000 16.30 0.8380 1.020698 1.038472 0.7608717 0.08310715
## EXP3mret CIP UIP
## 564 NA NA NA
## 565 NA NA NA
## 566 NA NA NA
## 567 -0.02111576 1 0.9322058
## 568 -0.01908823 1 0.9049452
## 569 -0.01658048 1 0.9079614
Note that the CIP is equal to one (as expected). The costs are equal to the gains. However, UIP has an mean value of 0.9999.
hist(da$UIP, main = "Histogram of SA-USD carry returns",
col = 'lightblue', xlab = "Returns")
A histogram of the UIP returns also suggests that the return to the carry trade is very limited.