Showing posts with label fPortfolio. Show all posts
Showing posts with label fPortfolio. Show all posts

Tuesday, October 16, 2012

Life on the Big International Frontier

Although I have used the Kenneth French data library extensively in various posts, I have not yet used the international data sets paired with the wonderful paper.

Eugene F. Fama and Kenneth R. French (2012) "Size, Value, and Momentum in International Stock Returns", Critical Finance Review

To rectify this home bias, let’s generate some efficient frontiers for the biggest cap stocks by geographic region to see how the frontiers have evolved over the last 20 years.

From TimelyPortfolio

Eventually, I would like to think through some other methods of comparing risk, return, and weights across multiple frontiers.

R code from GIST (do raw for copy/paste):

Monday, April 30, 2012

French Global Factors

I have said it already in multiple posts, but Kenneth French’s data library is one of the most generous and powerful contributions to the financial community.  To build on Systematic Investor’s series on factors, I thought I should run some basic analysis on the Global Factors maintained by Kenneth French.  I cannot imagine how long this would take without the data library and the incredible set of R packages available.

From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio

R code from GIST:

Thursday, December 15, 2011

With Size, Does Risk–>Return?

A basic tenet in finance is that higher risk should lead to higher return as the time horizon stretches to infinity.  However, in bonds, higher risk has not meant higher return with either credit risk (high-yield) or long duration risk (maturity > 15 years).  Based on some quick analysis of Kenneth French’s dataset on returns by market capitalization, it appears theory might better explain reality but not in a linear fashion.  For those more interested in risk and return on small caps, see this fascinating revelation refuting a basic tenet of finance About That Small Cap Effect: Oops!

From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio

R code from GIST:

Friday, December 9, 2011

A Tale of Two Frontiers

In a follow up to Evolving Domestic Frontier, I wanted to explore the efficient frontier including international indexes since 1980.  Life is great when your primary indexes (Barclays Aggregate and S&P 500) lie on the frontier as they did 1980-1999.  The situation becomes much more difficult with a frontier like 2000-now.

From TimelyPortfolio

If we examine return, risk, and Sharpe though, 1980 to now was really not that bad with annualized returns of all indexes stocks and bonds > 8% even including the last decade of “equity misery”.  As the S&P 500 shifted from the top of the efficient frontier to the bottom, it seems the focus over the last decade as been finding alternatives for the S&P 500. Strangely, the unbelievable riskless return of bonds has allowed some investors to claim and use bonds as one of these potential alternatives to the S&P 500.

From TimelyPortfolio
From TimelyPortfolio

Bonds as alternatives to equities have made even more sense when we look at correlations.

From TimelyPortfolio

However, bonds based on the yield to maturity of the Barclays Aggregate index suggest, even guarantee, forward returns of only 2.3%, significantly below the +8% generously provided for 30 years.  I believe the focus on alternatives should be alternatives for the guaranteed miserably low returns of bonds (WSJ Bond Buyers Dilemma).  The trick though is reducing risk (drawdown) of these alternatives to an acceptable level to most bond investors.  Max drawdown on bonds since 1982 has been 5%, which is virtually an impossible constraint for any risky alternatives, since in even very attractive secular buy-hold periods, drawdown generally is 20% to 30%.

From TimelyPortfolio

Our options are basically limited to cash, which at 0% return is unacceptable, unless we can discover a method to reduce drawdown on the risky set of alternatives to 20%, but really down to 10%.  How do we transform risky alternatives with historical drawdowns of 40%-70% to an acceptable bond alternative?  I think it requires tactical techniques blended with cash with a lot of client education and hand-holding.

R code from GIST:

Tuesday, November 1, 2011

Evolving Domestic Frontier

When we learn the efficient frontier, most are misled to believe that the frontier is static and unchanging.  However, we should have all learned by recent experience that the frontier is as volatile as the assets that construct it.  If we look at just US Stocks (SP 500) and US Bonds (Barclays Agg), we can see how this shifting frontier can dramatically affect your returns.

Using R and fPortfolio, let’s construct the frontier every rolling 5-year period to see what has happened since 1975.

From TimelyPortfolio

R code (click to download from Google Docs):

require(quantmod)
require(fPortfolio)
require(reshape)   #############################################################
#get data; unfortunately cannot share since I would violate
#copyright
sp_agg <- read.csv("C:\\Users\\Kent.TLEAVELL_NT\\Documents\\old\\R\\sp_agg.csv",stringsAsFactors=FALSE)
sp_agg <- sp_agg[2:NROW(sp_agg),3:NCOL(sp_agg)]
sp_agg <- sp_agg[,c(1,3,5)]   len <- nchar(sp_agg[,1])
xtsdate <- paste(substr(sp_agg[,1],len-3,len),"-",
ifelse(len==9,"0",""),substr(sp_agg[,1],1,len-8),"-01",sep="")   sp_agg.xts <- xts(data.matrix(sp_agg[,2:NCOL(sp_agg)]),order.by=as.Date(xtsdate))
sp_agg.xts <- sp_agg.xts/100
#############################################################     #for svg
#require(Cairo)
#CairoSVG("frontier.svg", width=8 ,height=8 )
#jpeg(filename="evolving frontier.jpg",
# quality=100,width=6, height = 7.5, units="in",res=96)#############################################################
## spec -
Spec = portfolioSpec()
setTargetReturn(Spec) = mean(colMeans(as.timeSeries(sp_agg.xts)))   ## constraints -
Constraints = "LongOnly"
#get frontiers by 5-year range
from = time(as.timeSeries(sp_agg.xts))[c(1,1,49,109,169,229,289,349,385)]
to = time(as.timeSeries(sp_agg.xts))[c(NROW(sp_agg.xts),48,108,168,228,288,348,NROW(sp_agg.xts)-8,NROW(sp_agg.xts)-8)]   rollFron <- rollingPortfolioFrontier(as.timeSeries(sp_agg.xts),Spec,Constraints,
from=from,to=to)   #chartcol <- topo.colors(length(rollFron))
chartcol <- 1:length(rollFron)
#hindsight bias; yellow is too hard to read so change
chartcol[length(rollFron)-2] <- "goldenrod"     i=1
frontierPlot(rollFron[[1]],col=rep(chartcol[1],2),xlim=c(0,0.08),ylim=c(-0.01,0.025))
frontierlabels <- frontierPoints(rollFron[[i]])
text(x=frontierlabels[NROW(frontierlabels),1],y=frontierlabels[NROW(frontierlabels),2],
labels=paste(from[i]," to ",to[i],sep=""),
pos=4,offset=0.5,cex=0.5,col = chartcol[i])   for (i in 2:(length(rollFron)-3) ) {
frontierPlot(rollFron[[i]],add=TRUE,col = rep(chartcol[i],2),pch=19,auto=FALSE,
title=FALSE)
frontierlabels <- frontierPoints(rollFron[[i]])
text(x=frontierlabels[NROW(frontierlabels),1],y=frontierlabels[NROW(frontierlabels),2],
labels=paste(from[i]," to ",to[i],sep=""),
pos=4,offset=0.5,cex=0.5,col = chartcol[i])
}   i=7
lowerFrontier = frontierPoints(rollFron[[i]], frontier = "both")
points(lowerFrontier,col = rep(chartcol[i],2),pch=19)
frontierlabels <- frontierPoints(rollFron[[i]])
text(x=frontierlabels[1,1],y=frontierlabels[1,2],
labels=paste(from[i]," to ",to[i],sep=""),
pos=4,offset=0.5,cex=0.5,col = chartcol[i])     #legend("topright",legend=paste(from,to,sep=" "),pch=19,
# col=chartcol,cex=0.7)
for (i in 8:length(rollFron)) {
lowerFrontier = frontierPoints(rollFron[[i]], frontier = "lower")
points(lowerFrontier,col = rep(chartcol[i],2),pch=19)
frontierlabels <- frontierPoints(rollFron[[i]],frontier="lower")
text(x=frontierlabels[1,1],y=frontierlabels[1,2],
labels=paste(from[i]," to ",to[i],sep=""),
pos=4,offset=0.5,cex=0.5,col = chartcol[i])
}
#
#frontier <- portfolioFrontier(as.timeSeries(sp_agg.xts))
#frontierPlot(frontier,col=rep(chartcol[length(rollFron)+1],2),add=TRUE,pch=19,auto=FALSE,
# title=FALSE)   #dev.off()

Created by Pretty R at inside-R.org

Thursday, October 6, 2011

Efficient Frontier of Buy-Hold and Tactical System

In my mind, there are two very disparate views in the money management space: Markowitz style diversification and Faber style tactical allocation.

I thought it would be fun to see what happens when we try to blend the two with an efficient frontier between two assets—”buy and hold” S&P 500 and a Faber 10-month tactical S&P 500 strategy.  In the process I will also introduce the fPortfolio package.

If we take the 10 month moving average S&P 500 system

From TimelyPortfolio

and treat it as a separate asset class, the efficient frontier since 1950 would look like this.

From TimelyPortfolio

I think this is an interesting and unique way to look at it.  If we then take the rolling tangency portfolio the allocation would fluctuate and fairly closely mark bear and bull equity markets.

From TimelyPortfolio

AS ALWAYS THIS IS NOT INVESTMENT ADVICE, JUST A FUN EXPERIMENT. SIGNIFICANT LOSSES ARE HIGHLY LIKELY IF YOU PURSUE THIS APPROACH.

The blended allocation looks fairly good.  There was no optimization or backtesting.  Please let me know if you discover improvements.

From TimelyPortfolio
From TimelyPortfolio

R code (download from Google Docs):

require(quantmod)
require(PerformanceAnalytics)   #get GSPC or S&P 500
#feel free to change to whatever you would like
#for non index do not include ^
getSymbols("^GSPC",from="1896-01-01",to=Sys.Date())   #get monthly close
sp500 <- to.monthly(GSPC)[,4]
#do this to get from mmm yyyy to yyyy-mm-dd
index(sp500) <- as.Date(index(sp500))
#get monthly returns from the monthly closes
#multiple ways of doing this
sp500.ret <- monthlyReturn(sp500)   #get 10 month Mebane Faber moving average
ma <- runMean(sp500,n=10)
#if close > 10 month moving average then 1 and 0 if <
signal <- ifelse(sp500 > ma,1,0)   #merge originial return data with this new data
#multiply the 1-month lagged signal by return
#if signal is 0 then return is 0 indicating out
returnComp <- merge(sp500.ret,lag(signal,k=1)*sp500.ret)
returnComp[is.na(returnComp[,2]),2] <- 0
colnames(returnComp) <- c("SP500","SP500.Faber")   #jpeg(filename="performance summary.jpg",
quality=100,width=6, height = 7.5, units="in",res=96)
charts.PerformanceSummary(returnComp, ylog=TRUE,
colorset=c("lightcyan4","lightgoldenrod3"),
main="S&P 500 and Mebane Faber Moving Average System
Monthly Performance Since 1950"
)
#dev.off()   #saved this require for later
#since fPortfolio and f anything does not play well
#with PerformanceAnalytics
require(fPortfolio)   #get frontier for the combination
#of the original price and the Faber mov avg system
frontier <- portfolioFrontier(as.timeSeries(returnComp))   #most of this comes directly from the fPortfolio demo
#very slight changes have been made
#we will run for the entire period
#jpeg(filename="frontier plot.jpg",
# quality=100,width=6, height = 6, units="in",res=96)
#unfortunately title cannot be changed easily
frontierPlot(frontier, pch=19, risk = "CVaR")
minvariancePoints(frontier,pch=19,col="red")
tangencyPoints(frontier,pch=19,col="blue")
tangencyLines(frontier,pch=19,col="blue")
equalWeightsPoints(frontier,pch=15,col="grey")
singleAssetPoints(frontier,pch=19,cex=1.5,col=c("lightcyan4","lightgoldenrod3"))
twoAssetsLines(frontier,lty=3,col="grey")
legend("topleft",legend=colnames(returnComp),pch=19,col=c("lightcyan4","lightgoldenrod3"))
#sharpeRatioLines(frontier,col="orange",lwd=2)
#dev.off()   #now let's see what this looks like on a rolling basis
#this from and to is not well documented in the fPortfolio
#documentation so I hope it helps some people
#will use 48 month rolling window and redo every 6 months
#window needs to be large since Faber system will have lots of
#0 returns, which can be handled by adding t-bill returns while out
from <- rollingWindows(as.timeSeries(returnComp),period="48m",by="6m")$from
to <- rollingWindows(as.timeSeries(returnComp),period="48m",by="6m")$to   Spec = portfolioSpec()
setTargetReturn(Spec) = mean(colMeans(as.timeSeries(returnComp)))
Constraints = "LongOnly"
#using Tangency but can also do Cml with rollingCmlPortfolio
#or rollingMinvariancePortfolio
rollTan <- rollingTangencyPortfolio(as.timeSeries(returnComp),Spec,Constraints,
from=from,to=to)
#sapply works very nicely with the lists used in fPortfolio
#get weights from each of the rolling periods
tanweights <- sapply(rollTan,getWeights)
rownames(tanweights) <- colnames(returnComp)   #jpeg(filename="rollling weight plot.jpg",
quality=100,width=6, height = 6, units="in",res=96)
barplot(tanweights,col=c("lightcyan4","lightgoldenrod4"),
legend.text=TRUE,names.arg=format(from,"%b %y"),
cex.names=0.7)
#dev.off()   #do not know a slick way to do this
#repeat the weights 6 times for the 6 month by
for (i in 1:NROW(t(tanweights))) {
for (j in 1:6) {
if (i==1 & j==1) {
tanweights.xts <- data.frame(t(tanweights[,i]))
} else {
#check to make sure we do not exceed number
#of rows in original return series - 48
#for the initialization
if (NROW(tanweights.xts) <= NROW(returnComp)-48)
tanweights.xts <- rbind(tanweights.xts,
data.frame(t(tanweights[,i])))
}
}
}
tanweights.xts <- xts(tanweights.xts,
order.by=index(returnComp)[48:NROW(returnComp)])   tanreturns <- lag(tanweights.xts,k=1)*returnComp[49:NROW(returnComp),]
returnComp2 <- merge(returnComp,tanreturns[,1]+tanreturns[,2])
colnames(returnComp2) <- c(colnames(returnComp)[1:2],"Cml")
#jpeg(filename="risk return.jpg",
quality=100,width=6, height = 6, units="in",res=96)
chart.RiskReturnScatter(returnComp2)
#dev.off()
#since fPortfolio gives error on charts.PerformanceSummary
#assemble quick one-pager
#jpeg(filename="perf all.jpg",
# quality=100,width=6, height = 7, units="in",res=96)
layout(matrix(c(1, 2)), height = c(2.5,1.5), width = 1)
par(mar = c(1, 4, 4, 2))
chart.CumReturns(returnComp2,xaxis=FALSE,ylab="Cumulative Return",
colorset = c("lightcyan4","lightgoldenrod4","darkolivegreen3"),
main="SP500 with Faber MA and CML Combo",legend.loc="topleft")
par(mar = c(5, 4, 0, 2))
chart.Drawdown(returnComp2,main="",ylab="Drawdown",
colorset=c("lightcyan4","lightgoldenrod4","darkolivegreen3"))
#dev.off()

Created by Pretty R at inside-R.org