Factor Attribution 2
I want to continue with Factor Attribution theme that I presented in the Factor Attribution post. I have re-organized the code logic into the following 4 functions:
- factor.rolling.regression – Factor Attribution over given rolling window
- factor.rolling.regression.detail.plot – detail time-series plot and histogram for each factor
- factor.rolling.regression.style.plot – historical style plot for selected 2 factors
- factor.rolling.regression.bt.plot – compare fund’s performance with portfolios implied by Factor Attribution
Let’s first replicate style and performance charts from the Three Factor Rolling Regression Viewer at the mas financial tools web site.
###############################################################################
# Load Systematic Investor Toolbox (SIT)
# http://systematicinvestor.wordpress.com/systematic-investor-toolbox/
###############################################################################
setInternet2(TRUE)
con = gzcon(url('http://www.systematicportfolio.com/sit.gz', 'rb'))
source(con)
close(con)
#*****************************************************************
# Load historical data
#******************************************************************
load.packages('quantmod')
tickers = 'VISVX'
periodicity = 'months'
data <- new.env()
getSymbols(tickers, src = 'yahoo', from = '1980-01-01', env = data, auto.assign = T)
for(i in ls(data)) {
temp = adjustOHLC(data[[i]], use.Adjusted=T)
period.ends = endpoints(temp, periodicity)
period.ends = period.ends[period.ends > 0]
if(periodicity == 'months') {
# reformat date to match Fama French Data
monthly.dates = as.Date(paste(format(index(temp)[period.ends], '%Y%m'),'01',sep=''), '%Y%m%d')
data[[i]] = make.xts(coredata(temp[period.ends,]), monthly.dates)
} else
data[[i]] = temp[period.ends,]
}
data.fund = data[[tickers]]
#*****************************************************************
# Fama/French factors
#******************************************************************
factors = get.fama.french.data('F-F_Research_Data_Factors', periodicity = periodicity,download = T, clean = F)
# add factors and align
data <- new.env()
data[[tickers]] = data.fund
data$factors = factors$data / 100
bt.prep(data, align='remove.na', dates='1994::')
#*****************************************************************
# Facto Loadings Regression
#******************************************************************
obj = factor.rolling.regression(data, tickers, 36)
#*****************************************************************
# Reports
#******************************************************************
factor.rolling.regression.detail.plot(obj)
factor.rolling.regression.style.plot(obj)
factor.rolling.regression.bt.plot(obj)
Next let’s add the Momentum factor from the Kenneth R French: Data Library and run Factor Attribution one more time.
#*****************************************************************
# Fama/French factors + Momentum
#******************************************************************
factors = get.fama.french.data('F-F_Research_Data_Factors', periodicity = periodicity,download = T, clean = F)
factors.extra = get.fama.french.data('F-F_Momentum_Factor', periodicity = periodicity,download = T, clean = F)
factors$data = merge(factors$data, factors.extra$data)
# add factors and align
data <- new.env()
data[[tickers]] = data.fund
data$factors = factors$data / 100
bt.prep(data, align='remove.na', dates='1994::')
#*****************************************************************
# Facto Loadings Regression
#******************************************************************
obj = factor.rolling.regression(data, tickers, 36)
#*****************************************************************
# Reports
#******************************************************************
factor.rolling.regression.detail.plot(obj)
factor.rolling.regression.style.plot(obj)
factor.rolling.regression.bt.plot(obj)

To visualize style from the Momentum point of view, let’s create a style chart that shows fund’s attribution in the HML / Momentum space.
factor.rolling.regression.style.plot(obj, xfactor='HML', yfactor='Mom')
I designed the Factor Attribution functions to take any user specified factors. This way you can easily run Factor Attribution on any combination of the historical factor returns from the Kenneth R French: Data Library Or use your own historical factor returns data.
To view the complete source code for this example, please have a look at the three.factor.rolling.regression() function in bt.test.r at github.







Thanks for you blog, I always find it very informative. I was wondering how would you use your own factor models. could you give me an example of one factor that is loaded from a saved .txt file in same format as the FF factors are. eg. one factor I use is Emerging Market over US Market i.e. MSCI EM vs S&P 500.
John,
Let’s say you store the EEM/SPY factor in the “EEM_SPY.csv” file. For this example, I created some sample weekly data for EEM/SPY factor using following code:
#***************************************************************** # Load historical data #****************************************************************** load.packages('quantmod') tickers = spl('EEM,SPY') data <- new.env() getSymbols(tickers, src = 'yahoo', from = '1970-01-01', env = data, auto.assign = T) for(i in ls(data)) data[[i]] = adjustOHLC(data[[i]], use.Adjusted=T) bt.prep(data, align='remove.na') #***************************************************************** # Create weekly factor #****************************************************************** prices = data$prices periodicity = 'weeks' period.ends = endpoints(prices, periodicity) period.ends = period.ends[period.ends > 0] hist.returns = ROC(prices[period.ends,], type = 'discrete') hist.returns = na.omit(hist.returns) #Emerging Market over US Market i.e. MSCI EM vs S&P 500 = EEM - SPY EEM_SPY = hist.returns$EEM - hist.returns$SPY colnames(EEM_SPY) = 'EEM_SPY' write.xts(EEM_SPY, 'EEM_SPY.csv')Now let’s add the EEM/SPY factor to the Fama/French 3 factor model:
#***************************************************************** # Load historical data #****************************************************************** load.packages('quantmod') tickers = 'VISVX' data <- new.env() getSymbols(tickers, src = 'yahoo', from = '1980-01-01', env = data, auto.assign = T) for(i in ls(data)) { temp = adjustOHLC(data[[i]], use.Adjusted=T) period.ends = endpoints(temp, periodicity) period.ends = period.ends[period.ends > 0] data[[i]] = temp[period.ends,] } data.fund = data[[tickers]] #***************************************************************** # Fama/French factors #****************************************************************** factors = get.fama.french.data('F-F_Research_Data_Factors', periodicity = periodicity,download = F, clean = F) factors.extra = 100 * read.xts('EEM_SPY.csv') factors$data = merge(factors$data, factors.extra, join='inner') # add factors and align data <- new.env() data[[tickers]] = data.fund data$factors = factors$data / 100 bt.prep(data, align='remove.na') #***************************************************************** # Check Correlations, make sure the EEM/SPY factor is NOT highly correlated #****************************************************************** load.packages('psych') pairs.panels(coredata(data$factors)) #***************************************************************** # Facto Loadings Regression #****************************************************************** obj = factor.rolling.regression(data, tickers, 36) #***************************************************************** # Reports #****************************************************************** factor.rolling.regression.detail.plot(obj) factor.rolling.regression.style.plot(obj) factor.rolling.regression.style.plot(obj, xfactor='HML', yfactor='EEM_SPY') factor.rolling.regression.bt.plot(obj)Thank for your detailed reply. Much appreciate it.
best wishes,
John