Hello all, It is Christmas time and that means family members wanting “stock market” advice. My usual response is not to do any analysis/advice for family members as I have a rather large extended family (by my last count over 100) and I just don’t think it’s appropriate.

So I have worked up a quick example to maximize the effective number of bets using canadian retail etf’s. I did this quick analysis for my mother ( the one person I can’t say no to), however I would not use this to invest directly as different situations will warrant different objectives and constraints.

First and foremost I would like to thank Ross Bennett for his great work on Portfolio Analytics.

The following code simply downloads some etfs and builds a portfolio that minimizes (1/effective number of bets) (so it maximizes the effective number of bets).

As always this is not investment advice and i’m not responsible for the use or misuse of this. This is sample dependent so garbage in and garbage out.

library(quantmod) library(PerformanceAnalytics) library(PortfolioAnalytics) EffectiveBets = function(R, w) { # Perform PCA on the returns pca <- prcomp(R, cor = FALSE) evec <- pca$rotation[] #eigenvectors eigval <- pca$sdev^2 #eigenvalues # Calculate the factor return streams inv.evec <- solve(evec) #inverse of eigenvectors # Calculate your exposure to each factor factor.exposure <- inv.evec %*% w # Calculate the diversification distribution # The numerator is the variance concentration curve # The denominator is the total portfolio variance div.dist <- (factor.exposure^2)*eigval / sum((factor.exposure^2)*eigval) # Calculate the effective number of bets ENB <- exp(-sum(div.dist*log(div.dist))) return(ENB) } ##Estimate the inv.evec and val first when using optimization w first for easy passing to deoptim EffectiveBets_optim = function(weights,inv.evec,eigval){ factor.exposure <- inv.evec %*% weights # Calculate the diversification distribution # The numerator is the variance concentration curve # The denominator is the total portfolio variance div.dist <- (factor.exposure^2)*eigval / sum((factor.exposure^2)*eigval) # Calculate the effective number of bets ENB <- exp(-sum(div.dist*log(div.dist))) return(1/ENB) } ###Canadian ETF LISt canadian_etfs=c("xiu","xsp","cbo","xsb","XBB","XCB","CPD","XRE","ZHY","CLF","PGL","ZIC") getSymbols(paste0(canadian_etfs,".TO"),from='2000-01-01') etf_name_list = paste0(toupper(canadian_etfs),".TO") ###Combine all into a "price matrix" pricemat=NULL start_dates = data.frame(etf_name=etf_name_list) start_dates$date = NA for(etfs in etf_name_list){ step1 = Ad(get(paste0(etfs))) colnames(step1) = etfs pricemat = merge.xts(pricemat,step1) start_dates[start_dates$etf_name==etfs,]$date=as.Date(start(step1)) } returnmat = ROC(pricemat,type="discrete") ##Fix return data retmat= returnmat['2013-04-01/2015-01-01'] retmat[is.na(retmat)]=0 ##Estimate inv.evec pca <- prcomp(retmat, cor = FALSE) evec <- pca$rotation[] #eigenvectors eigval <- pca$sdev^2 #eigenvalues # Calculate the factor return streams inv.evec <- solve(evec) #inverse of eigenvectors ###Use Portfolio Analytics to quickly model the portfolio moms_portfolio = portfolio.spec(assets=colnames(returnmat)) moms_portfolio = add.constraint(portfolio=moms_portfolio,type="full_investment") moms_portfolio = add.constraint(portfolio=moms_portfolio,type="long_only") moms_portfolio = add.objective(portfolio=moms_portfolio,name="EffectiveBets_optim",type="risk",arguments=list(inv.evec=inv.evec,eigval=eigval)) ###Place holder ###Optimize (May want to switch to ROI or different optimizer if dealing with more securities) optimal_portfolio = optimize.portfolio(retmat,moms_portfolio,optimize_method="DEoptim", search_size=5000, trace=TRUE, traceDE=0)

Created by Pretty R at inside-R.org

Kyle, you seem to be the only person on the net who has provided code for the effective bet approach, so thank you for that. When I run your code though, the term optimal_portfolio does not have the expected $weights and $out components. In fact, it only has the last five variables in the return values structure, as if it never ran the optimization. Is this code working correctly for you? Thanks

Do you have the DEoptim library? As you need it for PortfolioAnalytics’s optimization.

install.packages(“DEoptim”) should rectify that.

I just ran the code and I have an output:

optimal_portfolio$weights

XIU.TO XSP.TO CBO.TO XSB.TO XBB.TO XCB.TO CPD.TO XRE.TO ZHY.TO CLF.TO PGL.TO ZIC.TO

0.000 0.000 0.742 0.020 0.006 0.008 0.000 0.000 0.150 0.064 0.000 0.010

Kyle, thanks much for your quick response. I did not have the package loaded, plus I had typed it, in my troubleshooting excursion, as DEOptim vs DEoptim. Looks like the package could use a little hardening. I’m still getting some errors and got a different set of weights, but you got me unstuck, and I should be able to sort it out. Thanks again!!

Sid

>

Hey, DEoptim will yield different answers in the case of this trial as the number of iterations is low and it’s not tuned to converge on a more precise solution. This is for the purposes of exemplifying how to do it, if you’re planning to use code like this in production let me know as there is a fair amount of tuning required in both the estimation and the optimization. Shoot me an email at kyle at kkb.io