Building on posts Great FAJ Article on Statistical Measure of Financial Turbulence and Great FAJ Article on Statistical Measure of Financial Turbulence Part 2, I will now build a system incorporating a new correlation-based measure of turbulence and a simple relative strength technique. First, the new correlation-based measure looks like this

From TimelyPortfolio |

From TimelyPortfolio |

Then if we build a system with just this new correlation-based turbulence, we get fairly good results. However, if we take one step extra and apply a slope-based relative strength to choose S&P500 or CRB rather than equal-weight both, we get even better results.

From TimelyPortfolio |

I always want more data in countries and years, but 1957 is pretty thorough. Please let me know how you would improve this system.

R code:

require(quantmod)

require(PerformanceAnalytics)

#get data from St. Louis Federal Reserve (FRED)

getSymbols("GS20",src="FRED") #load 20yTreasury; 20y has gap 86-93; 30y has gap in early 2000s

getSymbols("GS30",src="FRED") #load 30yTreasury to fill 20y gap 86-93

getSymbols("BAA",src="FRED") #load BAA

getSymbols("SP500",src="FRED") #load SP500

#get CRB data from a csv file

CRB<-as.xts(read.csv("crb.csv",row.names=1))[,1]

#fill 20y gap from discontinued 20y Treasuries with 30y

GS20["1987-01::1993-09"]<-GS30["1987-01::1993-09"]

#do a little manipulation to get the data lined up on monthly basis

SP500<-to.monthly(SP500)[,4]

#get monthly format to yyyy-mm-dd with the first day of the month

index(SP500)<-as.Date(index(SP500))

#my CRB data is end of month; could change but more fun to do in R

CRB<-to.monthly(CRB)[,4]

index(CRB)<-as.Date(index(CRB))

#let's merge all this into one xts object; CRB starts last in 1956

assets<-na.omit(merge(GS20,SP500,CRB))

#use ROC for SP500 and CRB and momentum for yield data

assetROC<-na.omit(merge(momentum(assets[,1])/100,ROC(assets[,2:3],type="discrete")))

#get Correlations

corrBondsSp<-runCor(assetROC[,1],assetROC[,2],n=7)

corrBondsCrb<-runCor(assetROC[,1],assetROC[,3],n=7)

corrSpCrb<-runCor(assetROC[,2],assetROC[,3],n=7)

#composite measure of correlations between asset classes and roc-weighted correlations

assetCorr<-(corrBondsSp+corrBondsCrb+corrSpCrb+

(corrBondsSp*corrSpCrb*assetROC[,2])+

(corrBondsCrb*corrSpCrb*assetROC[,3])-

assetROC[,1])/6

#sum of ROCs of asset classes

assetROCSum<-assetROC[,1]+assetROC[,2]+assetROC[,3]

#finally the turbulence measure

turbulence<-abs(assetCorr*assetROCSum*100)

colnames(turbulence)<-"Turbulence-correlation"

chartSeries(turbulence,theme="white",name="Correlation and % Change as Measure of Financial Turbulence")

abline(h=0.8)

chart.ACF(turbulence,main="Auto-correlation of Turbulence")

#wish I could remember where I got some of this code

#most likely candidate is www.fosstrading.com

#please let me know if you know the source

#so I can give adequate credit

#use turbulence to determine in or out of equal-weighted sp500 and crb

signal<-ifelse(turbulence>0.8,0,1)

#use slope of sp500/crb to determine sp500 or crb

signal<-lag(signal,k=1)

# Replace missing signals with no position

# (generally just at beginning of series)

signal[is.na(signal)] <- 0

#get returns from equal-weighted crb and sp500 position; Return.portfolio was causing problems, so did the hard way

ret<-(assetROC[,2]+assetROC[,3])/2

ret[1] <- 0

#get system performance

system_perf<-ret*signal

system_eq<- cumprod(1+ret*signal)

perf_comparison<-merge(lag((assetROC[,2]+assetROC[,3])/2,k=1),system_perf)

colnames(perf_comparison)<-c("Equal-weighted","System-with-turbulence-filter")

charts.PerformanceSummary(perf_comparison,ylog=TRUE,main="Turbulence-based System vs Equal-Weighted CRB and SP500")

#let's use basic relative strength to pick sp500 or crb

#know I can do this better in R but here is my ugly code

#to calculate 12 month slope of sp500/crb

width=12

for (i in 1:(NROW(assets)-width)) {

model<-lm(assets[i:(i+width),2]/assets[i:(i+width),3]~index(assets[i:(i+width)]))

ifelse(i==1,assetSlope<-model$coefficients[2],assetSlope<-rbind(assetSlope,model$coefficients[2]))

}

assetSlope<-xts(cbind(assetSlope),order.by=index(assets)[(width+1):NROW(assets)])

#use turbulence to determine in or out of equal-weighted sp500 and crb

signal<-ifelse(turbulence[(width):NROW(turbulence)]>0.8,0,1)

#use slope of sp500/crb to determine sp500 or crb

signal2<-ifelse(assetSlope>0,1,2)

signal<-lag(signal,k=1)

signal[1]<-0

signal2<-lag(signal2,k=1)

signal2[1]<-0

#get sp500 or crb return based on slope

ret<-ifelse(signal2==1,assetROC[(width):NROW(assetROC),2],ifelse(signal2==2,assetROC[(width):NROW(assetROC),3],0))

#get system performance

system_perf_rs<-ret*signal

system_eq_rs<- cumprod(1+ret*signal)

perf_comparison<-merge((assetROC[,2]+assetROC[,3])/2,assetROC[,2],assetROC[,3],system_perf,system_perf_rs)

colnames(perf_comparison)<-c("Equal-weighted","S&P500","CRB","System-with-turbulence-filter","System-with-turbulence-filter and RS")

charts.PerformanceSummary(perf_comparison,ylog=TRUE,main="Turbulence-based System with RS vs Equal-Weighted, CRB, and SP500")

Hello Kent, wonderfull blog. Is possible to download your crb.csv file? Thanks

ReplyDeleteI wish I could say yes, but unfortunately I cannot due to restrictions. If you would like to use ^DJUBS from Yahoo, you can get similar data but only back to 2001.

ReplyDeleteis the FRED S&P 500 series a total-return series ? I am not able to ascertain if it is from the FRED site (maybe I missed it). If not, you would be off a bit.

ReplyDeletethis is price only, but results will not be dramatically affected especially if cash is used when out of S&P.

ReplyDelete