API Docs

Manual, tutorials and complete function reference

Building Efficient Frontiers
for Intraday Asset Allocation


This tutorial investigates construction of an efficient frontier using HF market data for portfolios of different sizes (theoretical vs realistic) and with various short-sales assumptions (Markowitz vs. Lintner).

R Code Matlab Code
Creating Portfolio

Here we are creating an asset portfolio with three positions: Google, Apple, and S&P 500 ETF. We set portfolio metrics mode to "price", so that all portfolio metrics will be computed for a buy-and-hold strategy without rebalancing.

require(PortfolioEffectHFT)

portfolio=portfolio_create(fromTime="2014-04-13 9:30:01",
			   toTime="2014-04-16 16:00:00")
portfolio_settings(portfolio,windowLength = '360m',portfolioMetricsMode='price')
positionGOOG=position_add(portfolio,'GOOG',1)
positionAAPL=position_add(portfolio,'AAPL',1)
positionC=position_add(portfolio,'C',1)


plot(portfolio)
Original Portfolio
portfolio=portfolio_create('index','SPY', 'fromTime', '2014-04-13 9:30:01', 'toTime', '2014-04-16 16:00:00');
portfolio_settings(portfolio,'portfolioMetricsMode','price','windowLength', '360m');
portfolio_addPosition(portfolio,'GOOG',1);
portfolio_addPosition(portfolio,'AAPL',1);
portfolio_addPosition(portfolio,'C',1);

plot(portfolio)
Original Portfolio

Theoretical Efficient Frontier

The efficient frontier is a concept in modern portfolio theory which refers to the best possible expected level of return for a given level of risk. Level of risk is traditionally represented by volatility of portfolio's returns and portfolios on the efficient frontier are called optimal portfolios.

To produce theoretical efficient frontier, which is a "smooth" curve need to assume that any asset is infinitely divisible. In practice, however, it is usually enough to make portfolio value sufficiently large to achieve the same effect. In our example below we set portfolio value to 100MM USD and use spline interpolation to futher enhance the "smoothness" of the frontier.

portfolio_settings(portfolio,resultsSamplingInterval='last')

resultLintner=data.frame(Variance=0,ExpectedReturn=0)

for(x in seq(0.004,0.016,0.004)){
  optimizer=optimization_goal(variance(portfolio),"min")     
  optimizer=optimization_constraint(optimizer,value(portfolio),'=',10^9)
  optimizer=optimization_constraint(optimizer,expected_return(portfolio),"=",x)
  optimPortfolio=optimization_run(optimizer)
  resultLintner=rbind(resultLintner,c(compute(variance(optimPortfolio))[[1]][2],
  				compute(expected_return(optimPortfolio))[[1]][2]))
}

resultLintner=resultLintner[-1,]

resultLintner=data.frame(Variance=spline(resultLintner$Variance, n=100)$y,
                         ExpectedReturn=spline(resultLintner$ExpectedReturn, n=100)$y)


ggplot()+geom_path(data=resultLintner, aes(x=Variance,y=ExpectedReturn),size=1.2)+util_plotTheme()+ggtitle("Efficient Frontier")+ylab("Expected Return")
Theoretical Efficient Frontier
portfolio_settings(portfolio,'portfolioMetricsMode','price','windowLength', '360m','resultsSamplingInterval','last');

VarianceLintner=null(1);
ExpectedReturnLintner=null(1);

for x = 0:0.005:0.015
        optimizer=optimization_goal(portfolio,'Variance','minimize');
        optimizer=optimization_constraint_portfolioValue(optimizer,10^9);
        optimizer=optimization_constraint_expectedReturn(optimizer,'=',x);
        optimPortfolio=optimization_run(optimizer);
        temp1=portfolio_variance(optimPortfolio);
        temp2=portfolio_expectedReturn(optimPortfolio);
        VarianceLintner=[VarianceLintner,temp1(2)];
        ExpectedReturnLintner=[ExpectedReturnLintner,temp2(2)];
end

y1=min(ExpectedReturnLintner):(max(ExpectedReturnLintner))/100:max(ExpectedReturnLintner);
x1=spline(ExpectedReturnLintner,VarianceLintner,y1);

close
figure('position',[800 200 1000 700])
plot(x1,y1,'LineSmoothing','on','Color',[0 74/255 97/255],'LineWidth',1.5);
set(gca,'Color',[213/255 228/255 235/255]);
set(gcf,'Color',[213/255 228/255 235/255]);
xlabel('Variance');
ylabel('Expected Return');
grid on
title('Efficient Frontier','FontSize',15,'FontWeight','bold');
Theoretical Efficient Frontier

Actual Efficient Frontiers

Market value of real-world portfolios is rarely large enough, so that discretness of optimal position weights could be neglected for drawing the efficient frontier. To demonstrate how discretness of the weights influences the shape of an effcient frontier, we overlay our previous frontier for a 100MM USD portfolio with a frontiers for small 800 USD and 400 USD portfolios (optimal portfolio value is a second arguement of optimization_goal method)

resultLintner3000Portfolio=data.frame(Variance=0,ExpectedReturn=0)

for(x in seq(0.004,0.016,0.004)){
  optimizer=optimization_goal(variance(portfolio),"min")   
  optimizer=optimization_constraint(optimizer,value(portfolio),'=',3000)
  optimizer=optimization_constraint(optimizer,expected_return(portfolio),"=",x)
  optimPortfolio=optimization_run(optimizer)
  resultLintner3000Portfolio=rbind(resultLintner3000Portfolio,c(compute(variance(optimPortfolio))[[1]][2],compute(expected_return(optimPortfolio))[[1]][2]))
}

resultLintner3000Portfolio=resultLintner3000Portfolio[-1,]

resultLintner20000Portfolio=data.frame(Variance=0,ExpectedReturn=0)

for(x in seq(0.004,0.016,0.004)){
  optimizer=optimization_goal(variance(portfolio),"min")   
  optimizer=optimization_constraint(optimizer,value(portfolio),'=',20000)
  optimizer=optimization_constraint(optimizer,expected_return(portfolio),"=",x)
  optimPortfolio=optimization_run(optimizer)
  resultLintner20000Portfolio=rbind(resultLintner20000Portfolio,c(compute(variance(optimPortfolio))[[1]][2],compute(expected_return(optimPortfolio))[[1]][2]))
}

resultLintner20000Portfolio=resultLintner20000Portfolio[-1,]

resultLintner3000Portfolio$legend="$3000 Portfolio"
resultLintner20000Portfolio$legend="$20000 Portfolio"
resultLintner$legend="Theoretical Portfolio"
result=rbind(resultLintner3000Portfolio,resultLintner20000Portfolio,resultLintner)

ggplot()+geom_path(data=result, aes(x=Variance,y=ExpectedReturn,col=legend),size=1.2)+
util_plotTheme()+ggtitle("Efficient Frontier of Theoretical/$20000/$3000  portfolio")+
ylab("Expected Return")+util_colorScheme()
Actual Efficient Frontiers
Variance6000Lintner=null(1);
ExpectedReturn6000Lintner=null(1);

for x =  0:0.004:0.016
  optimizer=optimization_goal(portfolio,'Variance','minimize');
  optimizer=optimization_constraint_portfolioValue(optimizer,6000);
  optimizer=optimization_constraint_expectedReturn(optimizer,'=',x);
  optimPortfolio=optimization_run(optimizer);
  temp1=portfolio_variance(optimPortfolio);
  temp2=portfolio_expectedReturn(optimPortfolio);
  Variance6000Lintner=[Variance6000Lintner,temp1(2)];
  ExpectedReturn6000Lintner=[ExpectedReturn6000Lintner,temp2(2)];
end

Variance20000Lintner=null(1);
ExpectedReturn20000Lintner=null(1);

for x = 0:0.004:0.016
  optimizer=optimization_goal(portfolio,'Variance','minimize');
  optimizer=optimization_constraint_portfolioValue(optimizer,20000);
  optimizer=optimization_constraint_expectedReturn(optimizer,'=',x);
  optimPortfolio=optimization_run(optimizer);
  temp1=portfolio_variance(optimPortfolio);
  temp2=portfolio_expectedReturn(optimPortfolio);
  Variance20000Lintner=[Variance20000Lintner,temp1(2)];
  ExpectedReturn20000Lintner=[ExpectedReturn20000Lintner,temp2(2)];
end

plot(x1,y1,Variance20000Lintner,ExpectedReturn20000Lintner,Variance6000Lintner,ExpectedReturn6000Lintner,'LineSmoothing','on','LineWidth',1.5);
set(gca,'Color',[213/255 228/255 235/255]);
set(gcf,'Color',[213/255 228/255 235/255]);
xlabel('Variance');
ylabel('Expected Return');
grid on
title('Efficient Frontier of Theoretical/$2000/$6000  portfolio','FontSize',15,'FontWeight','bold');
legend('Theoretical Portfolio','$20000 Portfolio','$6000 Portfolio');
Actual Efficient Frontiers

Short Sales Assumptions

Finally, we explore how changing from Markowitz to Lintner short-sales assumptions would influence the shape of the efficient frontier.

Markowitz definition of short sales assumes the investor, by employing short sales, can create portfolios of extreme risk and return through this costless leveraging of starting capital. In other words, Markowitz short sales constraint states that the sum of position weights must equal to 1 and it is used to normalize the weights: \begin{equation} \sum_{i=1}^n w_i = 1 \end{equation}

But individual investors pay a high fee for short sales, cannot short sell a managed portfolio, and the use of funds that arise from short sales of individual securities is restricted by brokerage firms. Lintner short sales constraint is more realitic, and while it also states that the sum of position weights must equals to 1, it is the sum of absolute weights, which is used to normalize position weights: \begin{equation} \sum_{i=1}^n |w_i| = 1 \end{equation}

As the chart below shows, Lintner weights produce a quite different efficient set. It seems to produce optimal portfolios with lower level of risk given the same level of return. This seems to support the claim that Markowitz short sales assumption favors excessive risk-taking.

portfolio_settings(portfolio,
		   windowLength = '360m',
		   resultsSamplingInterval='last',
		   shortSalesMode = 'markowitz',portfolioMetricsMode='price')

resultMarkowitz=data.frame(Variance=0,ExpectedReturn=0)

for(x in seq(0.004,0.016,0.004)){
  optimizer=optimization_goal(variance(portfolio),"min")    
  optimizer=optimization_constraint(optimizer,value(portfolio),'=',10^9)
  optimizer=optimization_constraint(optimizer,expected_return(portfolio),"=",x)
  optimPortfolio=optimization_run(optimizer)
  resultMarkowitz=rbind(resultMarkowitz,c(compute(variance(optimPortfolio))[[1]][2],compute(expected_return(optimPortfolio))[[1]][2]))
}

resultMarkowitz=resultMarkowitz[-1,]

resultMarkowitz=data.frame(Variance=spline(resultMarkowitz$Variance, n=100)$y,
                           ExpectedReturn=spline(resultMarkowitz$ExpectedReturn, n=100)$y)

resultMarkowitz$legend="Markowitz"
resultLintner$legend="Lintner"
result=rbind(resultMarkowitz,resultLintner)

ggplot()+geom_path(data=result, aes(x=Variance,y=ExpectedReturn,col=legend),size=1.2)+
util_plotTheme()+ggtitle("Markowitz and Lintner Efficient Frontier")+ylab("Expected Return")+
util_colorScheme()
Short Sales Assumptions
portfolio_settings(portfolio,'portfolioMetricsMode','price','windowLength', '360m','resultsSamplingInterval','last','shortSalesMode', 'markowitz')

VarianceMarkowitz=null(1);
ExpectedReturnMarkowitz=null(1);

for x =  0:0.005:0.015
  optimizer=optimization_goal(portfolio,'Variance','minimize');
  optimizer=optimization_constraint_portfolioValue(optimizer,10^9);
  optimizer=optimization_constraint_expectedReturn(optimizer,'=',x);
  optimPortfolio=optimization_run(optimizer);
  temp1=portfolio_variance(optimPortfolio);
  temp2=portfolio_expectedReturn(optimPortfolio);
  VarianceMarkowitz=[VarianceMarkowitz,temp1(2)];
  ExpectedReturnMarkowitz=[ExpectedReturnMarkowitz,temp2(2)];
end

y2=min(ExpectedReturnMarkowitz):(max(ExpectedReturnMarkowitz))/100:max(ExpectedReturnMarkowitz);
x2=spline(ExpectedReturnMarkowitz,VarianceMarkowitz,y2);

plot(x1,y1,x2,y2,'LineSmoothing','on','LineWidth',1.5);
set(gca,'Color',[213/255 228/255 235/255]);
set(gcf,'Color',[213/255 228/255 235/255]);
xlabel('Variance');
ylabel('Expected Return');
grid on
title('Markowitz and Lintner Efficient Frontier','FontSize',15,'FontWeight','bold');
legend('Lintner','Markowitz');
Short Sales Assumptions