When I see extremes, I feel compelled to explore. The US 10y Treasury yield is at an extreme versus the annualized 3 month CPI rate of change.
From TimelyPortfolio |
Of course, I have to try to build a system around the idea. While this 3 month CPI rate of change generates a decent signal of entry and exit for the S&P 500, it appears the 6 to 12 month rate of change works better. Let’s just use US 10y Treasury minus the lagged (since CPI released middle of following month) 9 month rate of change on CPI. If the 9 month S&P 500 rate of change exceeds this US10y-9monthCPI rate by –5%, then enter a long S&P 500 position.
From TimelyPortfolio |
Results are better than I would have expected, and the degrees of freedom are fairly robust.
From TimelyPortfolio |
From TimelyPortfolio |
I use these for illustrative purposes. In no way am I providing financial advice. You are responsible for your own profits and losses.
R code:
require(PerformanceAnalytics)
require(quantmod)
getSymbols("CPIAUCNS",src="FRED") #load CPI from Fed Fred
getSymbols("GS10",src="FRED") #load US Treasury 10y from Fed Fred
getSymbols("GS20",src="FRED") #load US Treasury 20y from Fed Fred
getSymbols("GS30",src="FRED") #load US Treasury 30y from Fed Fred
getSymbols("SP500",src="FRED") #load SP500 from Fed Fred
#fill 20y gap from discontinued 20y Treasuries with 30y
GS20["1987-01::1993-09"]<-GS30["1987-01::1993-09"]
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))
#subtract the annualized 3mo ROC of CPI from US 10y
US10yMinus3moCPI<-GS10/100-((1+ROC(CPIAUCNS,3))^4-1)
chartSeries(US10yMinus3moCPI,theme="white.mono")
#get the 12 month rate of change on CPI
#subtract the lagged amount from the 10y Treasury
#I retrieved the 20y series also if you would like to use that here
#it does not make much difference
US10yMinusCPI<-GS10/100-lag(ROC(CPIAUCNS,9,type="discrete"),k=1)
signal<-ifelse(ROC(SP500,n=9)-lag(US10yMinusCPI) > -0.05,1,0)
signal<-lag(signal,k=1)
signal[is.na(signal)]<-0
SPreturn<-ROC(SP500,1,type="discrete") # 1 month SP500 rate of change
SPreturn[1]<-0
SystemReturn<-signal*SPreturn
SystemEquity<-cumprod(1+signal*SPreturn)*coredata(SP500)[1]
return_compare<-merge(SystemReturn,SPreturn)
colnames(return_compare)<-c("SP500 System based on US10y & CPI","SP500")
charts.PerformanceSummary(return_compare,ylog=TRUE,
main="Performance Comparison of SP500 and System",
colorset=c("cadetblue","darkolivegreen3"))
chartSeries(SystemEquity,theme="white.mono",log=TRUE,
TA="addTA(SP500,on=1);addTA(ROC(SP500,n=9)-lag(US10yMinusCPI))",
name="Performance Comparison of SP500 and System with Signal")
#now with some hindsight optimization to really limit the drawdown
#add an extreme upside filter and 1987 magically disappears
#don't recommend this approach but a good example
signal<-ifelse(ROC(SP500,n=9)-lag(US10yMinusCPI) > -0.05 & ROC(SP500,n=9)-lag(US10yMinusCPI) < 0.2,1,0)
signal<-lag(signal,k=1)
signal[is.na(signal)]<-0
SPreturn<-ROC(SP500,1,type="discrete") # 1 month SP500 rate of change
SPreturn[1]<-0
SystemReturn<-signal*SPreturn
SystemEquity<-cumprod(1+signal*SPreturn)*coredata(SP500)[1]
return_compare<-merge(SystemReturn,return_compare)
colnames(return_compare)[1]<-"System with Upside filter"
charts.PerformanceSummary(return_compare,ylog=TRUE,
main="Performance Comparison of SP500 and System with Upside Extreme Limit",
colorset=c("gray70","darkolivegreen3","cadetblue"))
No comments:
Post a Comment