function portfolio_eff_frontier(varargin)
% Generates an efficient frontier, either by generating returns from from a
% set of tick prices passed into the function, or by generating random
% returns
%
% Created by:
% Paul Taylor
% The MathWorks Australia
% 2/05/2006
if nargin == 1
% A set of tick prices was passed into the function - calculate returns
% Extract tick prices
x = varargin{1};
% Calculate returns
r = x(2:end,:) ./ x(1:(end-1),:) - 1;
% the above could be done using the "tick2ret" function from the
% Financial Toolbox
elseif nargin == 0
% No inputs - generate random returns from a normal distribution for
% 200 observations of 6 assets
daily_ret_lim = 0.05;
r = 2*daily_ret_lim*rand(400,8) - daily_ret_lim;
end
% Calculate expected return and expected covariance
% This could also be done using the "ewstats" function from the Financial
% Toolbox: [m,c] = ewstats(r)
ExpReturn = mean(r);
ExpCovariance = cov(r);
% Convert daily return to annual - assume 252 business days per year
ExpReturn=ExpReturn*252;
% invoke the "portopt" function from the Financial Toolbox to produce the
% efficient frontier
npts = 100;
[PortRisk, PortReturn, PortWts] = portopt(ExpReturn,ExpCovariance,npts);
% Convert return to percentage
PortReturn = PortReturn*100;
%% Plot Efficient Frontier
% Create the figure and axes
h_f = figure('units','norm','pos',[0.1 0.1 0.8 0.8]);
h_a = axes('units','norm','pos',[0.1 0.1 0.73 0.8]);
% Plot the curve, add a grid, and display labels
plot(h_a,PortRisk,PortReturn,'-b.');
grid(h_a,'on')
xlabel(h_a,'Volatility (\sigma)')
ylabel(h_a,'Annualized Rate of Return (%)')
title(h_a,'Efficient Frontier')
hold(h_a,'on');
% Select a point on the frontier about half-way along
sel_node = ceil(npts/2);
% Set the crosshair location to the selected point on the frontier
x_mouse = PortRisk(sel_node);
h_ch = [];
h_an = [];
move_crosshair = 0;
set_crosshair_location(x_mouse)
%% Crosshair motion-related nested functions
function set_crosshair_location(x_mouse)
% Displays a green crosshair on the frontier. The user can use this
% crosshair to select a point on the frontier to view the weights for
% the selected portfolio
xr = xlim;
yr = ylim;
[cl_pt,idx] = min(abs(PortRisk - x_mouse));
x_ch = [repmat(PortRisk(idx),1,2) xr(1)];
y_ch = [yr(1) repmat(PortReturn(idx),1,2)];
if isempty(h_ch)
h_ch = plot(h_a,x_ch,y_ch,'g','linewidth',3);
else
set(h_ch,'xdata',x_ch);
set(h_ch,'ydata',y_ch);
end
display_port_wghts(idx)
end
function display_port_wghts(idx)
% Display the asset weights in an annotation text box on the
% right-hand side of the axes
w = PortWts(idx,:);
disp_cell = {'Weights:'};
txt = [repmat('Asset ',length(w),1) num2str((1:length(w))') ...
repmat(' ',length(w),1) num2str(w','% 6.2f')];
disp_cell = [disp_cell ; cellstr(txt) ; {''}];
disp_cell{end+1} = ['Risk: ' num2str(PortRisk(idx),'%6.3f')];
disp_cell{end+1} = ['Return (%): ' num2str(PortReturn(idx),'%6.1f')];
if isempty(h_an)
h_an = annotation('textbox',[0.85 0.4 0.12 0.5],'String',disp_cell);
else
set(h_an,'String',disp_cell)
end
end
function mouse_down(h,b)
% The user clicked down on the crosshairs
move_crosshair = 1;
end
function mouse_up(h,b)
% The user released the mouse button
move_crosshair = 0;
end
function mouse_motion(h,b)
if move_crosshair == 1
% The mouse is moving while the mouse button is down
mouse_loc = get(gca,'currentPoint');
x_mouse = mouse_loc(1);
set_crosshair_location(x_mouse)
end
end
%% Assign callbacks for crosshairs, and figure
set(h_ch,'buttondownfcn',@mouse_down);
set(h_f,'WindowButtonUpFcn',@mouse_up);
set(h_f,'WindowButtonMotionFcn',@mouse_motion);
end