Greedy Selection of Low-Correlation Currency Pair Baskets
Summary
The document considers selecting a small, equally weighted currency-pair universe from a larger candidate set, aiming to reduce average pairwise correlation. The original approach enumerates every fixed-size combination, computes each basket's correlation matrix, and ranks baskets using the mean correlation and its dispersion. An accepted answer notes that exhaustive combination search grows rapidly and proposes a greedy alternative: begin with the asset having the lowest average correlation to the universe, then add the candidate with the lowest average correlation to the assets already selected until the target basket size is reached.
The answer also advises expressing the desired tradeoff between average correlation and its standard deviation through a preference or utility function rather than simply adding the metrics without justification. This iterative heuristic can reduce computation, but it does not guarantee the globally best basket, and the document gives no out-of-sample performance evidence. It focuses on asset selection without optimizing weights; return construction, currency exposures, estimation error, and rebalancing effects remain outside the example.
Key ideas
- Exhaustive enumeration of fixed-size asset baskets becomes costly as the candidate universe grows.
- A greedy heuristic seeds a basket with the asset having the lowest average correlation and adds candidates with low average correlation to the selected assets.
- Average correlation and its dispersion reflect different objectives and need an explicit tradeoff rule.
- The greedy procedure reduces search effort but does not guarantee a globally optimal basket.
- The example addresses selection without weighting and provides no evidence of trading performance.
Tags
Full text
# How to create a basket of currency pairs with the lowest correlation in R?
# How to create a basket of currency pairs with the lowest correlation in R?
My strategy is designed to buy and sell all assets of a universe and rebalance periodically. It goes either long or short. To limit risk exposure to a single currency I would like the assets in the universe to have low relashionship and low price correlation between them (positive or even negative as it can go short).
For example, if the universe has 3 currency pairs A, B and C, my objective is to have price correlation c1 (between A and B), c2 (between B and C) and c3 (between A and C) as low as possible. Let's say c0 is the average of c1, c2, and c3, it will give information on the "global" correlation between pairs A, B and C.
Now imagine we have 26 currency pairs (from A to Z) to consider for creating a small universe of 5 of them (3 was for the example).
The method I apply is to create every possible combination of groups of 5 currency pairs and then it calculates c0 `correl$corr` of every single group. I also calculate standard deviation of c1, c2 and c3 `correl$stddev` as it will filter out groups with low c0 and high c1, c2 and c3. Finally I sum the global correlation and the stddev in order to rank groups with a single value `correl$"corr+stddev`.
In this example 16 pairs are candidates.
My dataset is an xts object with historical prices of the 16 currency pairs. I could extend it to ~50 to improve the selection as I guess bigger is the pool and better it must be.
This is how I proceed to achieve this :
```
# Put all symbols name in a list
pairs <- names(mydata)
# Create groups of 5 currency pairs with no duplication
group <- combn( pairs , 5 )
# Calculate number of groups
nb_group <- ncol(group)
# Create empty object to store my result
result <- NULL
# For every groups
for (i in 1:nb_group) {
# Calculate the mean correlation for the group
correl <- round(mean(cor(mydata[, group[,i]])),3)
# Transform as data frame and give a name
correl <- as.data.frame(correl)
colnames(correl) <- "cor"
rownames(correl) <- toString(group[,i])
# Calculate stddev and the sum of correlation and stddev
correl$stddev <- round(sd(cor(mydata[, group[,i]])),3)
correl$"cor+sddev" <- correl$cor + correl$stddev
# export data
result <- rbind(correl, result)
}
# Basket of currency pairs with the lowest correlation and stddev
head(result[order(result[,3]),])
```
This return something like :
```
> head(result[order(result[,3]),])
cor stddev cor+sddev
GBPUSD, USDCAD, USDRUB, USDTRY, NZDUSD 0.032 0.583 0.615
GBPUSD, USDCHF, USDCAD, USDRUB, USDTRY 0.048 0.569 0.617
GBPUSD, USDJPY, USDRUB, USDTRY, NZDUSD 0.052 0.576 0.628
GBPUSD, USDCAD, EURCHF, USDRUB, USDTRY 0.048 0.582 0.630
GBPUSD, USDCAD, USDRUB, USDMXN, NZDUSD 0.065 0.566 0.631
GBPUSD, USDCHF, USDCAD, USDRUB, USDMXN 0.097 0.536 0.633
```
Result is same when I average correlation and stddev (instead of the sum)
Do you think R could help to achieve this and is there a more efficient approach to create such basket of currency pairs ?
I've checked portfolio optimization packages like tawny, PortfolioAnalytics and fPortfolio but unfortunatly I'm not familiar with financial formulas and I got lost.
Thank you, Florent
## Answer by Kyle Balkissoon (score 1, accepted)
https://quant.stackexchange.com/a/19163
If I understand your problem correctly you are trying to search for the optimal basket of 5 pairs (without worrying about weighting).
The problem is computationally there are too many combinations to sort through.
So I will propose a simple algorithm:
Calculate correlation matrix, grab the pair that has the least avg correlation as a seed for your basket, then iterate through the correlations with the rest of pairs searching for the next pair that is the least correlated with the current basket and iteratively adding them until you have enough items required.
If you want to add correlation and stddev I suggest you come up with a preference function or utility function to model the tradeoff between them.
```
require(PerformanceAnalytics)
data(edhec)
##simple example on edhec test data
cormat = cor(edhec)
###Seed the basket
inital_asset = which.min(colMeans(cormat))
names_in_basket = labels(inital_asset)
###Grab the one least avg correlated with existing basket
while(length(names_in_basket)<5){
if(length(names_in_basket)<2){
names_in_basket=c(names_in_basket, labels(which.min(cormat[,names_in_basket[1]])))
}else{
names_in_basket=c(names_in_basket, labels(which.min(rowMeans(cormat[!rownames(cormat)%in%names_in_basket,names_in_basket]))))
}
}
###Sanity Check
mean(cormat[rownames(cormat)%in%names_in_basket,names_in_basket])<mean(cormat)
```Shown in full with attribution under the source's licence. Licence: CC BY-SA 4.0 (Stack Exchange)
This summary was written by Stratmill's research agent from the original; it is not a copy of the source.