Search
• John Hawver

# The Currency Wash

Updated: Apr 28, 2019

Investing in emerging markets has always perplexed me. Multiple problems exist when investing overseas (financials quality, currency risk, data quality, etc) and being a quant, the hardest to overcome for me was modeling the currency component (risk). Well, this week I responded to a tweet from Meb Faber saying that he had his 401k largely allocated to emerging markets. I asked him his thoughts [on currency risk]? His answer: It’s a wash over time.

So, let’s run some numbers, dive in, and see if he is correct (spoiler alert: he is!).

To preface this post, about six years ago I spent a few weeks trying to accurately model currency risks so I could justify investing in emerging market ETF’s. I “nuked” (Navy term for going mathematically overboard) the problem and applied every type of model in my arsenal at the time. To zero avail.

To test the assertion that currency risk is a wash, my hypothesis is that currency returns should have a mean close to zero AND have roughly an equal probability of going up or down. If these conditions are true, then over the long-term, an investment in a well-diversified emerging market ETF has very low currency risk.

I thought of a few ways to check this hypothesis and opted for the most straightforward. Let’s take all the currency pairs and calculate their returns, group those returns together, and take a look at their distribution. The code is below and you can replicate it easily. I performed this analysis from the standpoint of a USD investor, but it could be done from any currency perspective with some adjustments to the data.

So, what did I find? The currency pairs as a group have a mean of .000323, which IS close to zero. The mean of the ‘up’ returns was .00788 and the mean of the ‘down’ returns was -.00691; both roughly equal. And the probability of an ‘up’ return each day was 49%. Those numbers pretty closely support the simple hypothesis. Currency returns are largely a wash to the long-term investor.

Here’s an interesting aside, let’s plot histograms of the FX returns next to SPY returns (below). Clearly, SPY has more kurtosis (it is more peaked around zero) and has a positive skew. So what are the SPY stats? SPY has a mean close to zero also, .000527. The mean ‘up’ return is .00626 and the mean ‘down’ is -.00669. BUT, the probability of having an ‘up’ day is a whopping 55%. I posted that recently on Twitter. Let that stat sink in for a bit. There’s a very powerful built-in advantage to being a long-term investor in equities.

And, for the volatility geeks, this is also a reasonably good answer to why equities have a put skew; stocks can go to zero, the SPY ‘down’ days have a larger average than ‘up’ days, and there is this large, positive, probability that the market will go up each day. In comparison, FX volatility surfaces are largely symmetric. Currencies have a hard time going to zero generally (Venezuela and cryptocurrencies excluded) and statistically the return distribution is very balanced.

So, in summary. Hat-tip to Meb. He’s right. Currency exposures and risks are largely a wash to the long-term investor. Now I want that time back I wasted six years ago... ##### Code to Replicate #####

library('quantmod')

library('PerformanceAnalytics')

# Define ccy symbols

ccy_symbols <- c('EURUSD', 'JPY', 'GBPUSD', 'AUDUSD', 'IDR', 'RUB',

'CNY', 'HKD', 'SGD', 'MXN', 'PHP', 'THB', 'MYR', 'ZAR')

# loop through, get all data, take returns

app = F

for (ccy in ccy_symbols) {

# only taking data after 2010

ccy_pair <- na.omit(getSymbols(paste0(ccy, '=X'), auto.assign = F)['2010::'][, 6])

# flipping these pairs so exchange rate in dollars

if (ccy %in% c('EURUSD', 'GBPUSD', 'AUDUSD')) ccy_pair <- 1 / ccy_pair

ccy_rtns <- CalculateReturns(ccy_pair)

# Removing large incorrect outlier data found in RUB, IDR Yahoo data

ccy_rtns[abs(ccy_rtns) > .3] <- NA

ccy_rtns <- na.omit(ccy_rtns)

print(paste0(ccy, ' mean: ', mean(ccy_rtns)))

print(paste0(ccy, ' max: ', max(abs(ccy_rtns))))

all_ccy_rtns <- if (app) rbind(all_ccy_rtns, ccy_rtns) else ccy_rtns; app = T

print(paste0(ccy, ': is done'))

}

# Explore the data

mean(ccy_rtns)

mean(ccy_rtns[ccy_rtns>0])

mean(ccy_rtns[ccy_rtns<0])

sum(ccy_rtns>0) / length(ccy_rtns)

# compare to SPY returns

spy <- na.omit(getSymbols('spy', auto.assign = F)['2010::'][, 6])

spy_rtns <- na.omit(CalculateReturns(spy))

mean(spy_rtns)

mean(spy_rtns[spy_rtns>0])

mean(spy_rtns[spy_rtns<0])

sum(spy_rtns>0) / length(spy_rtns)

# plot histograms

hist(spy_rtns, 50, col = rgb(1, 0, 0, 0.5), main = 'Return Distributions (Red = Spy; Blue = FX)',

xlab = 'Returns'); par(new = T)

hist(ccy_rtns, 50, col = rgb(0, 0, 1, 0.5), add = T)