## API Docs

### Short-term Alpha Decay in Treynor-Black Portfolio

In this tutorial we will compare alpha decay (i.e. alpha deterioration) of a portfolio with equal position weights and a portfolio, which position weights are computed according to the popular Treynor-Black model.

Treynor-Black model is using Single-Index Model (SIM) as an underlying assumption and. assigns weight of each position in the portfolio based on ratio of its mispricing to its nonsystematic risk. $$w_i = \frac{\alpha_i/\sigma_i^2}{\sum_{j=1}^N \alpha_j/\sigma_j^2}$$

##### Creating Portfolio

Here we are creating a simple portfolio with only two positions. By default SPY would be used for internal Single Index Model, unless other market index is selected. We will create a "price", so that all portfolio metrics will be computed for a buy-and-hold strategy without rebalancing.

# Load PortfolioEffectHFT package
require(PortfolioEffectHFT)

# create test portfolio
timeStart="2014-10-02 09:30:00"
timeEnd="2014-10-03 16:00:00"

portfolio=portfolio_create("SPY", timeStart, timeEnd)
portfolio_settings(portfolio,portfolioMetricsMode="price",jumpsModel='all',resultsNAFilter='false')

plot(alpha_jensens(positionAAPL),alpha_jensens(positionGOOG), title="Jensen's Alpha",legend=c("AAPL","GOOG"))

% create test portfolio
timeStart =  '2014-10-02 09:30:00';
timeEnd = '2014-10-03 16:00:00';

portfolio=portfolio_create('index','SPY', 'fromTime',timeStart, 'toTime',timeEnd);
portfolio_settings(portfolio,'portfolioMetricsMode','price','jumpsModel','all');

figure('position',[800 200 1000 700])
util_plot2d(position_jensensAlpha(portfolio,'AAPL'),'AAPL','Title','Jensens Alpha')+util_line2d(position_jensensAlpha(portfolio,'GOOG'), 'GOOG')


##### Computing Optimal Weights

We now compute optimal weights according to the Treynor-Black model. Matrix optimWeigth contains contains optimal weights for AAPL and GOOG correspondingly.

# compute optimal weights according to the Treynor-Black model
timeUTC=compute(alpha_jensens(positionAAPL))[[1]][,1]
alpha=cbind (compute(alpha_jensens(positionAAPL))[[1]][,2], compute(alpha_jensens(positionGOOG))[[1]][,2])
variance=cbind(compute(variance(positionAAPL))[[1]][,2], compute(variance(positionGOOG))[[1]][,2])

treynorBlack=alpha/variance
optimWeigth=treynorBlack/rowSums(abs(treynorBlack))

# plot optimal position weights
plot(create_metric(cbind(timeUTC[!(is.na(optimWeigth[,1]))],optimWeigth[!(is.na(optimWeigth[,1])),1]),"AAPL"),
create_metric(cbind(timeUTC[!(is.na(optimWeigth[,2]))], optimWeigth[!(is.na(optimWeigth[,2])),2]),"GOOG"), title="Optimal Weight")

% compute optimal weights according to the Treynor-Black model
paren = @(x, varargin) x(varargin{:});
alpha = [paren(position_jensensAlpha(portfolio,'AAPL'),:,2),paren(position_jensensAlpha(portfolio,'GOOG'),:,2)];
timeUTC =paren(position_jensensAlpha(portfolio,'AAPL'),:,1);
variance= bsxfun(@minus,[paren(position_variance(portfolio,'AAPL'),:,2),paren(position_variance(portfolio,'GOOG'),:,2)],(paren(position_beta(portfolio,'GOOG'),:,2).^2).*paren(position_variance(portfolio,'SPY'),:,2));

treynorBlack=alpha./variance;
optimWeigth=bsxfun(@rdivide,treynorBlack,sum(abs(treynorBlack),2));

% plot optimal position weights
util_plot2d([timeUTC, optimWeigth(:,1)],'AAPL','Title','Optimal Weight')+util_line2d([timeUTC, optimWeigth(:,2)], 'GOOG')


##### Optimal Portfolio Alpha

To see, how optimal weighting scheme imporves our portfolio alphas, we contruct another portfolio where positions have equal weights.

Chart below compares mean alpha levels in the two portfolios, and, as you can see, optimal portfolio has ~40% higher mean alpha level then simple portfolio

# compute optimal position quantities for a portfolio of given size
portfolioCash=10000000
optimPosition=portfolioCash*optimWeigth/cbind(compute(price(positionAAPL))[[1]][,2],compute(price(positionGOOG))[[1]][,2])

portfolioSimple=portfolio_create("SPY", timeStart, timeEnd)
portfolio_settings(portfolioSimple,portfolioMetricsMode="price",jumpsModel='all')
positionAAPLSimple=position_add(portfolioSimple, "AAPL", quantity = (portfolioCash/2)%/%(compute(price(positionAAPL))[[1]][,2]), time = timeUTC)
positionGOOGSimple=position_add(portfolioSimple, "GOOG", quantity = (portfolioCash/2)%/%(compute(price(positionGOOG))[[1]][,2]), time = timeUTC)

portfolioOptimal=portfolio_create("SPY", timeStart, timeEnd)
portfolio_settings(portfolioOptimal,portfolioMetricsMode="price",jumpsModel='all')
positionAAPLOptimal=position_add(portfolioOptimal,"AAPL", quantity = optimPosition[,1], time = timeUTC)
positionGOOGOptimal=position_add(portfolioOptimal,"GOOG", quantity = optimPosition[,2], time = timeUTC)

meanAAPL=mean(compute(price(positionAAPLOptimal))[[1]][,2])
meanGOOG=mean(compute(price(positionGOOGOptimal))[[1]][,2])

portfolioSimpleAlpha=compute(alpha_jensens(portfolioSimple))[[1]]
portfolioOptimAlpha=compute(alpha_jensens(portfolioOptimal))[[1]]

plot(alpha_jensens(portfolioSimple),alpha_jensens(portfolioOptimal), title="Jensen's Alpha",legend=c("Simple portfolio","Optimal portfolio"))+
util_line2d(cbind(timeUTC, mean(portfolioSimpleAlpha[,2])), legend="Avg. of simple")+
util_line2d(cbind(timeUTC, mean(portfolioOptimAlpha[,2])), legend="Avg. of optimal")

meanGOOG=mean(paren(position_price(portfolio,'GOOG'),:,2))
meanAAPL=mean(paren(position_price(portfolio,'AAPL'),:,2))

% compute optimal position quatities for a portfolio of given size
portfolioCash=10000000;
optimPosition=portfolioCash*optimWeigth./[paren(position_price(portfolio,'AAPL'),:,2),paren(position_price(portfolio,'GOOG'),:,2)];

portfolioSimple=portfolio_create('index','SPY', 'fromTime',timeStart, 'toTime',timeEnd);
portfolio_settings(portfolioSimple,'portfolioMetricsMode','price','jumpsModel','all');
portfolio_addPosition(portfolioSimple, 'AAPL', bsxfun(@rdivide,(portfolioCash/2),(paren(position_price(portfolio,'AAPL'),:,2))), 'time', timeUTC)
portfolio_addPosition(portfolioSimple, 'GOOG',bsxfun(@rdivide,(portfolioCash/2),(paren(position_price(portfolio,'GOOG'),:,2))),  'time', timeUTC)

portfolioOptimal=portfolio_create('index','SPY', 'fromTime',timeStart, 'toTime',timeEnd);
portfolio_settings(portfolioOptimal,'portfolioMetricsMode','price','jumpsModel','all');

portfolioSimpleAlpha = portfolio_jensensAlpha(portfolioSimple);
portfolioOptimAlpha = portfolio_jensensAlpha(portfolioOptimal);

util_plot2d(portfolioSimpleAlpha,'Simple portfolio','Title', 'Jensens Alpha')+util_line2d(portfolioOptimAlpha, 'Optimal portfolio')+...
util_line2d([timeUTC, mean(portfolioSimpleAlpha(:,2))*ones(length(timeUTC),1)],'Avg. of simple')+...
util_line2d([timeUTC, mean(portfolioOptimAlpha(:,2))*ones(length(timeUTC),1)], 'Avg. of optimal')


##### Alpha Decay Model

To study properties of Jensen's alpha in the original and optimal portfolios, we fit an ARIMA(1,1,0) model to the alphas series and computed 1 step ahead forecast errors for both portfolios.

As you may see, optimal portfolio weights produced by the Treynor-Balck model display a lower forecast error compared to the equal weights scheme. In other words, alpha decay becomes more predictable for the optimal portfolio.

require(forecast)
meanSimple=NULL

#forecast test for simple portfolio
#use ARIMA(1,1,0). 1 second foreacast.
for(x1 in seq(0,2,0.1)){
x2=1-x1
set_quantity(positionAAPLSimple, (portfolioCash*x1)%/%meanAAPL)
set_quantity(asset=positionGOOGSimple, quantity=(portfolioCash*x2)%/%meanGOOG)

alpha=compute(alpha_jensens(portfolioSimple))[[1]]
meanSimple=c(meanSimple,mean(alpha[,2]))

forecastErrors=array(0,dim=100)
for(i in 1:100){
if((i/21+x1*1000/21)%%5==0){
print(paste(i/21+x1*1000/21,"%"))
}
fit=arima(alpha[(3200+i*400):(3400+i*400-1),2],c(1,1,0)) #ARIMA estimation
forecastErrors[i]=abs(forecast(fit,1)$mean-alpha[3400+i*400,2])/mean(abs(alpha[(3200+i*400):(3400+i*400-1),2])) #Calculation of forecast errors } forecastErrorsSimple=c(forecastErrorsSimple,mean(forecastErrors)) } #forecast test for optimal portfolio for(i in 1:100){ if(i%%5==0){ print(paste(i,"%")) } fit=arima(portfolioOptimAlpha[(3200+i*400):(3400+i*400-1),2],c(1,1,0)) #ARIMA estimation forecastErrors[i]=abs(forecast(fit,1)$mean-portfolioOptimAlpha[3400+i*400,2])/abs(mean(portfolioOptimAlpha[(3200+i*400):(3400+i*400-1),2])) #Calculation of forecast errors
}
forecastErrorsOptim=mean(forecastErrors) #Calculation of average values

resultdf=data.frame(err=c(forecastErrorsSimple,forecastErrorsOptim) ,mean=c(meanSimple,mean(portfolioOptimAlpha[,2])),legend=c(array("Portfolio Simple Alpha",dim=21),"Portfolio Optimal Alpha"))

ggplot() + geom_point(data=resultdf, aes(x=err, y=mean,colour=legend),size=5) +
xlab("Forecast Error(%)") +
ylab("Alpha mean") +
util_plotTheme(base_size = 15)+util_colorScheme()

meanSimple=zeros(21, 1);
model=arima(1,1,0);
x=0:0.1:2;

for  j = 1:21
x1=x(j);
x2=1-x1;

position_setQuantity(portfolioSimple, 'AAPL', (portfolioCash*x1)/meanAAPL)
position_setQuantity(portfolioSimple, 'GOOG', (portfolioCash*x2)/meanGOOG)

alpha=portfolio_jensensAlpha(portfolioSimple);
meanSimple(j,1)=mean(alpha(:,2));

forecastErrors=zeros(100,1);
for i =1:100
fit=estimate(model,alpha((3200+i*400):(3400+i*400-1),2),'Display','off');
forecastErrors(i,1)=abs( forecast(fit,1,'Y0',alpha((3200+i*400):(3400+i*400-1),2)) - alpha(3400+i*400,2))*100/mean(abs(alpha(3400+i*400,2)));       %Calculation of forecast errors
end
end

x = -2:0.25:2;
[X,Y] = meshgrid(x);
Z = X.*exp(-X.^2-Y.^2);
contour3(X,Y,Z,30)

for i =1:100
fit=estimate(model,portfolioOptimAlpha((3200+i*400):(3400+i*400-1),2),'Display','off');
forecastErrors(i,1)=abs( forecast(fit,1,'Y0',portfolioOptimAlpha((3200+i*400):(3400+i*400-1),2)) - portfolioOptimAlpha(3400+i*400,2))*100/mean(abs(portfolioOptimAlpha(3400+i*400,2)));       %Calculation of forecast errors
end
forecastErrorsOptim=mean(forecastErrors);