Thursday, June 30, 2011

Beating Kenneth French Small - High

With 148 pageviews over the last 24 hours, my post Kenneth French Gift to the Finance World has been popular relative to most of my other posts.  I think the popularity is due to Kenneth French’s notoriety and the amazing outperformance of Small Size and High Momentum stocks since 1927.  18% annualized returns are hard to beat, but I thought I should give it a try.  My first line of attack will be reducing the drawdown with some two popular and one not so popular price-based systems.

Great success was unfortunately not achieved, but I was able to reduce the drawdown to 50% from 79%.  If anybody has better ideas, please let me know.  I would love to see them and share them.

From TimelyPortfolio
From TimelyPortfolio

Try a very subtle change by using the average return price series of all Small Size to determine the rank-based signal.  Performance is improved slightly.

From TimelyPortfolio

R code (click to download):

#the real challenge now is how to beat the best
#small momentum with a system
#get very helpful Ken French data
#for this project we will look at Momentum Portfolios
#http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/6_Portfolios_ME_Prior_12_2.zip   require(PerformanceAnalytics)
require(quantmod)
require(ggplot2)   my.url="http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/6_Portfolios_ME_Prior_12_2.zip"
my.tempfile<-paste(tempdir(),"\\frenchmomentum.zip",sep="")
my.usefile<-paste(tempdir(),"\\6_Portfolios_ME_Prior_12_2.txt",sep="")
download.file(my.url, my.tempfile, method="auto",
quiet = FALSE, mode = "wb",cacheOK = TRUE)
unzip(my.tempfile,exdir=tempdir(),junkpath=TRUE)
#read space delimited text file extracted from zip
french_momentum <- read.table(file=my.usefile,
header = TRUE, sep = "",
as.is = TRUE,
skip = 12, nrows=1013)
colnames(french_momentum) <- c(paste("Small",
colnames(french_momentum)[1:3],sep="."),
paste("Large",colnames(french_momentum)[1:3],sep="."))   #get dates ready for xts index
datestoformat <- rownames(french_momentum)
datestoformat <- paste(substr(datestoformat,1,4),
substr(datestoformat,5,7),"01",sep="-")   #get xts for analysis
french_momentum_xts <- as.xts(french_momentum[,1:6],
order.by=as.Date(datestoformat))   french_momentum_xts <- french_momentum_xts/100   charts.PerformanceSummary(french_momentum_xts[,1:3],ylog=TRUE,
main="Performance by Kenneth French Size and Momentum
Monthly Since 1927"
,
colorset=c("cadetblue3","cadetblue","cadetblue4",
"darkolivegreen3","darkolivegreen","darkolivegreen4"))
mtext("Source: http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html",
side=1,adj=0,cex=0.75)
#dev.off()     #get price series of small cap high momentum for system building
french_momentum_price <- cumprod(1+french_momentum_xts[,3])   #speedy solution for ranking from Charles Berry
# http://r.789695.n4.nabble.com/efficient-rolling-rank-td2013535.html
#rolling rank of price over last 12 months (12 means max price for last 12)
#pad first 11 with NA
nper <- 10
x.rank <- c(rep(NA,nper-1),rowSums(coredata(french_momentum_price)[ -(1:(nper-1)) ] >= embed(french_momentum_price,nper)))
x.rank <- as.xts(x.rank,order.by=index(french_momentum_price))
signalRank <- ifelse(x.rank[,1] > 3 |
french_momentum_price >= runMax(french_momentum_price,2),1,0)
retRank <- lag(signalRank,k=1)*french_momentum_xts[,3]   #try rolling 10 month moving average popularized by Mebane Faber
signalAvg <- ifelse(french_momentum_price > runMean(french_momentum_price,n=10),1,0)
retAvg <- lag(signalAvg,k=1)*french_momentum_xts[,3]   #try RSI
signalRSI <- ifelse(RSI(french_momentum_price,n=4) > 45,1,0)
retRSI <- lag(signalRSI,k=1)*french_momentum_xts[,3]   retCompare <- merge(retRank,retAvg,retRSI,french_momentum_xts[,3])
colnames(retCompare) <- c("Small.High.Rank",
"Small.High.Avg","Small.High.RSI","Small.High.Benchmark")
#jpeg(filename="performance of small-high with systems.jpg",quality=100,width=6.25, height = 8, units="in",res=96)
charts.PerformanceSummary(retCompare,ylog=TRUE,cex.legend=1.2,
colorset = c("cadetblue","darkolivegreen3","purple","gray70"),
main="Kenneth French Small Size and High Momentum Stocks
Compared To Various Price Systems"
)
#dev.off()   #jpeg(filename="capture of small-high with systems.jpg",quality=100,width=6.25, height = 8, units="in",res=96)
chart.CaptureRatios(retCompare[,1:3],retCompare[,4],
main="Kenneth French Small Size and High Momentum Stocks
Compared To Various Price Systems"
)
#dev.off()   #get average of small size for additional system testing
french_momentum_avg <- cumprod(1+apply(coredata(french_momentum_xts[,c(1:3)]),MARGIN=1,FUN=mean))
french_momentum_avg <- as.xts(french_momentum_avg,order.by=index(french_momentum_price))
nper <- 10
x.rank <- c(rep(NA,nper-1),rowSums(coredata(french_momentum_avg)[ -(1:(nper-1)) ] >= embed(french_momentum_avg,nper)))
x.rank <- as.xts(x.rank,order.by=index(french_momentum_avg))
signalRankAvg <- ifelse(x.rank[,1] > 3 |
french_momentum_price >= runMax(french_momentum_price,2),1,0)
retRankAvg <- lag(signalRankAvg,k=1)*french_momentum_xts[,3]   retCompare <- merge(retRank,retRankAvg,french_momentum_xts[,3])
colnames(retCompare) <- c("Small.High.Rank",
"Small.High.RankOnAvg","Small.High.Benchmark")
#jpeg(filename="performance of small-high with 2 rank systems.jpg",quality=100,width=6.25, height = 8, units="in",res=96)
charts.PerformanceSummary(retCompare,ylog=TRUE,cex.legend=1.2,
colorset = c("cadetblue","darkolivegreen3","gray70"),
main="Kenneth French Small Size and High Momentum Stocks
Compared To Rank-based Price Systems"
)
#dev.off()

Created by Pretty R at inside-R.org

Stocks and Commodites Separate

Stocks and Commodities



via StockCharts.com

Cash Might be Your Tail Risk

Just like James Montier Ode to the Joy of Cash and David Merkel Got Cash?, I think cash is an extremely powerful tool.  Of the 3 ingredients (land, labor, and capital) of the economy, capital (cash) is most scarce at the end of a crisis or recession while land and labor are most plentiful.  Its scarcity in disaster rewards patient holders of cash when opportunity is most plentiful and rewards most certain.  Deflation, or alternately stable to inflating currency, also rewards the most risk averse with high cash allocations.

However, if your cash is the US $, owning US $ throughout and at the end of the next collapse will not be rewarded.  Please expand your definition of cash to include other currencies besides the US $, and do not let home bias determine your cash denomination.  The tail risk most ignored in the average US investors’ portfolios is the US $.  If nothing else, at least monitor the currency markets.  You very easily could hold the most overowned and least scarce asset in the world (the US $).  Argentine Peso was not good in 2001. Russian Ruble was not good in 1998. Thai Baht, Malaysian Ringgit, and Korean Won were not good in 1997.  Mexican Peso was not good in 1994.  Cash is fine as long as cash is not the source of the tail risk.

From TimelyPortfolio

Fortunately, the Euro has been a distraction, but at some point the focus will shift to the US.  Don’t fight the Fed generally works in stocks, and it also definitely applies to the US $ here.

R code (click to download):

#monitor currencies   require(quantmod)   #get currency data from the FED FRED data series
Korea <- getSymbols("DEXKOUS",src="FRED",auto.assign=FALSE) #load Korea
Malaysia <- getSymbols("DEXMAUS",src="FRED",auto.assign=FALSE) #load Malaysia
Singapore <- getSymbols("DEXSIUS",src="FRED",auto.assign=FALSE) #load Singapore
Taiwan <- getSymbols("DEXTAUS",src="FRED",auto.assign=FALSE) #load Taiwan
China <- getSymbols("DEXCHUS",src="FRED",auto.assign=FALSE) #load China
Japan <- getSymbols("DEXJPUS",src="FRED",auto.assign=FALSE) #load Japan
Thailand <- getSymbols("DEXTHUS",src="FRED",auto.assign=FALSE) #load Thailand
Brazil <- getSymbols("DEXBZUS",src="FRED",auto.assign=FALSE) #load Brazil
Mexico <- getSymbols("DEXMXUS",src="FRED",auto.assign=FALSE) #load Mexico
India <- getSymbols("DEXINUS",src="FRED",auto.assign=FALSE) #load India
USDOther <- getSymbols("DTWEXO",src="FRED",auto.assign=FALSE) #load US Dollar Other Trading Partners
USDBroad <- getSymbols("DTWEXB",src="FRED",auto.assign=FALSE) #load US Dollar Broad       #combine all the currencies into one big currency xts
currencies <- merge(1/Korea, 1/Malaysia, 1/Singapore, 1/Taiwan,
1/China, 1/Japan, 1/Thailand, 1/Brazil, 1/Mexico, 1/India,
USDOther, USDBroad)
currencies <- na.omit(currencies)
colnames(currencies) <- c("Korea", "Malaysia", "Singapore", "Taiwan",
"China", "Japan", "Thailand", "Brazil", "Mexico", "India",
"USDOther", "USDBroad")       #use sde MODist package as described in the fine presentation
#http://www.rinfinance.com/agenda/2011/StefanoIacus.pdf
require(sde)   currenciesROC <- as.zoo(ROC(currencies,1,type="discrete"))
d <- MOdist(ROC(currencies,1,type="discrete"))
cl <- hclust( d )
groups <- cutree(cl, k=4)
#jpeg(filename="currencies.jpg",quality=100,width=6.5, height = 6.5, units="in",res=96)
plot(as.zoo(currencies), col=groups, main="Various Asian and American Currencies
1995-Current"
)
#dev.off()

Created by Pretty R at inside-R.org

Wednesday, June 29, 2011

Kenneth French Gift to the Finance World

Kenneth French gives one of the best gifts to the finance world at his website http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html.  I am surprised I have waited so long to write a post about this wonderful resource.  After seeing Systematic Relative Strength’s post The #1 Investment Return Factor No One Wants to Talk About, I thought I would play with Size and Momentum in R, and it is very clear that size and momentum have been very important return factors.

From TimelyPortfolio
From TimelyPortfolio
From TimelyPortfolio

R code (click to download):

#get very helpful Ken French data
#for this project we will look at Momentum Portfolios
#http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/6_Portfolios_ME_Prior_12_2.zip   require(PerformanceAnalytics)
require(quantmod)
require(ggplot2)   my.url="http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/ftp/6_Portfolios_ME_Prior_12_2.zip"
my.tempfile<-paste(tempdir(),"\\frenchmomentum.zip",sep="")
my.usefile<-paste(tempdir(),"\\6_Portfolios_ME_Prior_12_2.txt",sep="")
download.file(my.url, my.tempfile, method="auto",
quiet = FALSE, mode = "wb",cacheOK = TRUE)
unzip(my.tempfile,exdir=tempdir(),junkpath=TRUE)
#read space delimited text file extracted from zip
french_momentum <- read.table(file=my.usefile,
header = TRUE, sep = "",
as.is = TRUE,
skip = 12, nrows=1013)
colnames(french_momentum) <- c(paste("Small",
colnames(french_momentum)[1:3],sep="."),
paste("Large",colnames(french_momentum)[1:3],sep="."))     #get dates ready for xts index
datestoformat <- rownames(french_momentum)
datestoformat <- paste(substr(datestoformat,1,4),
substr(datestoformat,5,7),"01",sep="-")   #get xts for analysis
french_momentum_xts <- as.xts(french_momentum[,1:6],
order.by=as.Date(datestoformat))   french_momentum_xts <- french_momentum_xts/100   #jpeg(filename="performance by momentum and size.jpg",quality=100,width=6.25, height = 5, units="in",res=96)
charts.PerformanceSummary(french_momentum_xts,ylog=TRUE,
main="Performance by Kenneth French Size and Momentum
Monthly Since 1927"
,
colorset=c("cadetblue3","cadetblue","cadetblue4",
"darkolivegreen3","darkolivegreen","darkolivegreen4"))
mtext("Source: http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html",
side=1,adj=0,cex=0.75)
#dev.off()   #jpeg(filename="rolling performance by momentum and size.jpg",quality=100,width=6.25, height = 5, units="in",res=96)
chart.RollingPerformance(french_momentum_xts,width=36,
main="Performance by Kenneth French Size and Momentum
36 Month Rolling Since 1927"
,
legend.loc = "bottomright",
colorset=c("cadetblue3","cadetblue","cadetblue4",
"darkolivegreen3","darkolivegreen","darkolivegreen4"))
mtext("Source: http://mba.tuck.dartmouth.edu/pages/faculty/ken.french/data_library.html",
side=1,adj=0,cex=0.75)
#dev.off()   #use ggplot2 for boxplot
#could also use chart.Boxplot() from PerformanceAnalytics
df <- as.data.frame(
cbind(as.Date(index(french_momentum_xts)),
coredata(french_momentum_xts)))
dfmelt <- melt(df,id.vars=1)
colnames(dfmelt) <- c("date","frenchmomentum","return")
#jpeg(filename="boxplot by momentum and size.jpg",quality=100,width=6.25, height = 5, units="in",res=96)
ggplot(dfmelt,aes(x=frenchmomentum,y=return,colour=frenchmomentum)) +
geom_boxplot() + opts(title="Kenneth French Momentum and Size")
#dev.off()

Created by Pretty R at inside-R.org

Tuesday, June 28, 2011

Slideshow of Graphs since TimelyPortfolio’s November Inception

I have had a lot of fun blogging at Timely Portfolio over the last 7 months.  Here are all the graphs that I have shown.  Thanks especially to R.

Monitoring Sources of Bond Returns with ML/BAC Corporate OAS and CPI

In response to the nice comment requesting an update to Monitoring Sources of Bond Return and also longer history, I thought I would update the original and then rerun with CPI to give a longer time series.  For even longer history back to 1919, see Historical Sources of Bond Returns with Shiller Data 1919-2011.  Below are the results, and real returns are negative again.

How in the world can this quote in Institutional Investor Endowments Are Shifting To Fixed Income be valid (fixed income is not defensive)?

“With the problems of equity markets volatility and unpredictability, the case for increasing the allocation to fixed income is greater than ever, notes Michael Purves, chief market strategist and head of global derivatives research at BGC Financial in New York. But if fixed income assets were once seen as low risk, low reward instruments, they now are seen as assets with the potential to deliver real returns, says Purves.

Also, the availability of fixed assets in the emerging markets offers investors safety as well as growth, Purves notes.  Not only has the number of opportunities increased, they also offer greater rewards relative to similar products in the developed markets. “The move to fixed income is not a defensive strategy any more,” says New York’s Andrew Lawrence. “In today’s market conditions they offer relatively outsized returns.”

Expecting real returns here is a bet on prolonged deflation, and if deflation is so certain, go short the instruments that most suffer from deflation.  Please do not treat this as investment advice; I just cannot restrain my opinion that bonds guarantee failure in most cases with 3-4% 10 year total returns.  If your long-term target growth is 3-4%, then enjoy your bonds.

I will consider myself a complete failure as a money manager if I can only return 3-4% over the next 10-30 years.

From TimelyPortfolio
From TimelyPortfolio

 

R code (click to download):
#just an update as requested to
#http://timelyportfolio.blogspot.com/2011/04/monitoring-sources-of-bond-return.html?showComment=1309270268204#c6728361948693873056   require(quantmod)
require(PerformanceAnalytics)
require(reshape2)
require(ggplot2)   getSymbols("WGS10YR",src="FRED") #load 10yTreasury
getSymbols("WFII10",src="FRED") #load 10yTIP for real return
getSymbols("BAMLC0A0CM",src="FRED") #load Corporate for credit
getSymbols("CPIAUCSL",src="FRED") #load Corporate for credit    bondReturnSources<-na.omit(merge(WGS10YR-WFII10,WFII10,to.weekly(BAMLC0A0CM)[,4])["2003::"])
colnames(bondReturnSources)<-c("10yTreasury","10yTIPReal","Credit")
bondReturnSourcesToGraph<-data.frame(cbind(as.Date(index(bondReturnSources)),coredata(bondReturnSources)))
colnames(bondReturnSourcesToGraph)<-c("Date","InflationBreakEven","10yTIPReal","Credit")
bondReturnSourcesToGraph<-melt(bondReturnSourcesToGraph,id.vars=1)
colnames(bondReturnSourcesToGraph)<-c("Date","ReturnSource","Yield")
rownames(bondReturnSourcesToGraph)<-c(1:NROW(bondReturnSourcesToGraph))
ggplot(bondReturnSourcesToGraph, stat="identity",
aes(x=Date,y=Yield,fill=ReturnSource,group=ReturnSource)) +
geom_area() +scale_x_date(format = "%Y") +
opts(title = "Sources of Bond Return")     #let's do it all over again with CPI instead of TIP breakeven
getSymbols("GS10",src="FRED") #load 10yTreasury
getSymbols("BAMLC0A0CM",src="FRED") #load Corporate for credit
getSymbols("CPIAUCSL",src="FRED") #load CPI
BAMLC0A0CM <- to.monthly(BAMLC0A0CM)[,4]
index(BAMLC0A0CM) <- as.Date(index(BAMLC0A0CM))   bondReturnSources<-na.omit(merge(GS10/100-ROC(CPIAUCSL,n=12,type="discrete"),
ROC(CPIAUCSL,n=12,type="discrete"),BAMLC0A0CM/100))
colnames(bondReturnSources)<-c("10yTreasury","Inflation","Credit")
bondReturnSourcesToGraph<-data.frame(cbind(as.Date(index(bondReturnSources)),coredata(bondReturnSources)))
colnames(bondReturnSourcesToGraph)<-c("Date","RealReturn","Inflation","Credit")
bondReturnSourcesToGraph<-melt(bondReturnSourcesToGraph,id.vars=1)
colnames(bondReturnSourcesToGraph)<-c("Date","ReturnSource","Yield")
rownames(bondReturnSourcesToGraph)<-c(1:NROW(bondReturnSourcesToGraph))
#do line instead to handle the negative inflation and negative real returns
ggplot(bondReturnSourcesToGraph, stat="identity",
aes(x=Date,y=Yield)) + geom_line(aes(colour=ReturnSource)) +
scale_x_date(format = "%Y") + opts(title = "Sources of Bond Return")

Created by Pretty R at inside-R.org

Monday, June 27, 2011

Bonds Risk and Return by Rating

As an extension to the Bond Market as a Casino Game series and Historical Sources of Bond Returns-Comparison of Daily to Monthly, I thought a ggplot of risk and return by decade and Moody’s Rating might be helpful.  Anyone who has read those other posts know that my opinion of bonds Guaranteed Failure with Bonds is not very favorable, and this is just another illustration that bond returns 1980-2011 are extremely abnormal and are mathematically impossible now.

From TimelyPortfolio

 

R code (click to download):

#do everything twice to compare monthly average to daily    require(RQuantLib)
require(quantmod)
require(PerformanceAnalytics)
require(ggplot2)   getSymbols("AAA",src="FRED") # load Moody's AAA from Fed Fred
getSymbols("BAA",src="FRED") # load Moody's BAA from Fed Fred    #Fed monthly series of yields is the monthly average of daily yields
#set index to yyyy-mm-dd format rather than to.monthly mmm yyy for better merging later
index(AAA)<-as.Date(index(AAA))
index(BAA)<-as.Date(index(BAA))
AAApricereturn<-AAA
BAApricereturn<-BAA   AAApricereturn[1,1]<-0
BAApricereturn[1,1]<-0
colnames(AAApricereturn)<-"PriceReturn-monthly avg AAA"
colnames(BAApricereturn)<-"PriceReturn-monthly avg BAA"
#use quantlib to price the AAA and BAA bonds from monthly yields
#AAA and BAA series are 20-30 year bonds so will advance date by 25 years
for (i in 1:(NROW(AAA)-1)) {
AAApricereturn[i+1,1]<-FixedRateBondPriceByYield(yield=AAA[i+1,1]/100,issueDate=Sys.Date(),
maturityDate= advance("UnitedStates/GovernmentBond", Sys.Date(), 25, 3),
rates=AAA[i,1]/100,period=2)[1]/100-1
}
for (i in 1:(NROW(BAA)-1)) {
BAApricereturn[i+1,1]<-FixedRateBondPriceByYield(yield=BAA[i+1,1]/100,issueDate=Sys.Date(),
maturityDate= advance("UnitedStates/GovernmentBond", Sys.Date(), 25, 3),
rates=BAA[i,1]/100,period=2)[1]/100-1
}   #total return will be the price return + yield/12 for one month
AAAtotalreturn<-AAApricereturn+lag(AAA,k=1)/12/100
colnames(AAAtotalreturn)<-"TotalReturn-monthly avg AAA"
BAAtotalreturn<-BAApricereturn+lag(BAA,k=1)/12/100
colnames(BAAtotalreturn)<-"TotalReturn-monthly avg BAA"   charts.PerformanceSummary(merge(AAApricereturn,AAAtotalreturn,BAApricereturn,BAAtotalreturn),ylog=TRUE,
colorset=c("cadetblue","darkolivegreen3","purple","goldenrod"),
main="Simulated Returns from Moody's AAA and BAA Yield")
mtext("Source: Federal Reserve FRED",side=1,adj=0)   AAA_BAA <- na.omit(merge(AAAtotalreturn,BAAtotalreturn))
#get df for ggplot
df <- as.data.frame(cbind(index(AAA_BAA),coredata(AAA_BAA[,1:2])))
df[,1] <- paste(substr(format(as.Date(df[,1]),"%Y"),1,3),0,sep="")
colnames(df) <- c("Decade","AAA","BAA")
dfmelt <- melt(df,id.vars=1)
colnames(dfmelt) <- c("Decade","Moodys_Rating","TotalReturn")
dfsum <- ddply(dfmelt, .(Decade,Moodys_Rating), summarise,
mean = mean(TotalReturn),
sd = sd(TotalReturn))
jpeg(filename="risk and return by rating.jpg",quality=100,width=6.25, height = 5,
units="in",res=96)
ggplot(dfsum, aes(x=sd,y=mean,label=factor(Decade))) + geom_point(aes(colour=Moodys_Rating)) +
geom_line(aes(x=sd,y=mean,colour=Moodys_Rating)) + geom_text(aes(colour=Moodys_Rating)) +
opts(title="Risk (sd) and Return (mean) by Moodys Rating since 1919")
dev.off()     ####some other experimentation but not part of blog post
getSymbols("DJTA",src="FRED")
getSymbols("DJIA",src="FRED")
#convert to monthly and get monthly returns
DJTA <- ROC(to.monthly(DJTA)[,4],n=1,type="discrete")
DJIA <- ROC(to.monthly(DJIA)[,4],n=1,type="discrete")
#set index to yyyy-mm-dd format rather than to.monthly mmm yyy for better merging later
index(DJTA)<-as.Date(index(DJTA))
index(DJIA)<-as.Date(index(DJIA))   #merge AAA,BAA,DJTA,DJIA
assetReturns <- na.omit(merge(AAAtotalreturn,BAAtotalreturn,DJTA,DJIA))   charts.PerformanceSummary(assetReturns,ylog=TRUE,
colorset=c("cadetblue","darkolivegreen3","purple","goldenrod"),
main="DJIA, DJTA, and Simulated Returns from Moody's AAA and BAA Yield")
mtext("Source: Federal Reserve FRED",side=1,adj=0)   chart.RiskReturnScatter(assetReturns["1950::1959",])

Created by Pretty R at inside-R.org