Code covered by the BSD License  

Highlights from
Treynor-Black portfolio management model

Treynor-Black portfolio management model

by

 

Treynor-Black portfolio management model

[pct_w_pos_opti beta_pos_opti pct_w_active measures_port measures_active risk_para_symbol_cell]...
%% Treynor-Black portfolio optimization
% Author: Benjamin J. J. Voigt (bvoigt@gmail.com)
% Published: Oct 2012
% Version: 0.0.2
% Licence: BSD 2-Clause, free to use and copy retaining original author reference
%
% Purpose: May this code evolve and be enhanced by many smarter minds to
% reflect all the beauty of estimations we dare to dream of.
%
% Required toolboxes: Financial Toolbox, Data Feed Toolbox, Statistics
% Toolbox
%
% Notes: This initial version contains hard coded values and referefces to replicate the
% exact example data set and formulas described in Z. Bodie, A. Kane, A. J. Marcus 
% INVESTMENTS,9th Edition, 2012, McGraw-Hill, NewYork
% The use of adjusted prices may distort the statistics slightly compared
% to the ones published in the book.
%
% Disclaimer: USE AT YOUR OWN RISK; NO INVESTMENT RECOMMENDATION IMPLIED;
% NOT ASSOCIATED WITH PAST, CURRENT OR FUTURE EMPLOYER OR ASSOCIETES OF THE
% AUTHOR; DO NOT USE THIS CODE TO INVEST YOUR OWN MONEY OR TO 
% ENCOURAGE OTHERS TO INVEST MONEY;
%
% Known limitations:
% 1)The index date array is used to align individual stocks, actual trade
% dates may NOT match. The reason is data problems in some sources
% regarding dates and the low importance of dates for the statistical
% calculations performed bythe function
% 2)Annualization from monthly to 1 year yields estimates for a 1 year
% investment horizont and holding period only
% 3)To improve readability many for-loops are used which limits application
% to a larger number of portfolio holdy without optimization
% 4)The sequence of symbols cannot change or else the weight calculation
% may fail or result in wrong results
%


function [pct_w_pos_opti beta_pos_opti pct_w_active measures_port measures_active risk_para_symbol_cell]...
    = TreynorBlack(symbol_cell, index_cell, start_date_str, end_date_str,...
    risk_free_rate, symbol_alpha_forecast_cell, symbol_alpha_forecast_acuracy_cell)

% Global, function wide variables
g_connect = yahoo;
g_symbol_cell = {'HPQ', 'DELL', 'WMT', 'TGT', 'BP', 'RDS-B'};
g_symbol_alpha_estimates_mat = [0.015, -0.01, -0.005, 0.0075, 0.012, 0.0025];
g_rfr = 0.06;
g_index_cell = {'^GSPC'};
g_price_fints = (zeros(61,7));
g_return_fints = (zeros(61,7));
g_reg_results = (zeros(6,19));
g_symbol_riks_para = (zeros(6,4));
g_index_risk_para = (zeros(1,4));

% Local, dummy, loop or sub-section specific variables
l_60months_cell = (zeros(61,2));
l_reg_mat = (zeros(60,2));
l_whichstats = (zeros(6,1));
l_reg_stats = (0);


% Load index data for 60 months, monthly adjusted close startin May 2001
l_60months_cell = fetch(g_connect, g_index_cell(1), 'Adj Close', 'May 01 01','May 01 06', 'm');
g_price_fints = fints(l_60months_cell(1:end,1), l_60months_cell(1:end,2), strrep(g_index_cell(1), '^', ''));
g_return_fints = tick2ret(g_price_fints.GSPC);

% Load stock data 60 months, monthly adjusted close starting May 2001
% The index date array is used to align individual stocks, actual trade
% dates may NOT match, yahoo price vector is fliped and attached to index
% dates
for i=1:length(g_symbol_cell)
    l_60months_cell = fetch(g_connect, g_symbol_cell(i), 'Adj Close', 'May 01 01','May 01 06', 'm');
    g_price_fints = [g_price_fints (fints(g_price_fints.dates, flipud(l_60months_cell(1:end,2)), strrep(cell2mat(g_symbol_cell(i)), '-', '')))];
    g_return_fints = [g_return_fints tick2ret(g_price_fints.(strrep(cell2mat(g_symbol_cell(i)),'-','')))];
end

% Visualize returns data
plot(g_return_fints);

% Run regressions
l_whichstats ={'R', 'rsquare', 'adjrsquare', 'fstat', 'tstat', 'mse'};
for i=1:length(g_symbol_cell)
    l_reg_mat = fts2mat([g_return_fints.(strrep(cell2mat(g_index_cell(1)),'^','')) ...
        g_return_fints.(strrep(cell2mat(g_symbol_cell(i)),'-',''))]);
    l_reg_stats = regstats(l_reg_mat(1:end,2), l_reg_mat(1:end,1), 'linear', l_whichstats);
    % 1)rsq,2)adj_rsq,3)SE,4)av_DF_R,5)av_DF_E,6)av_SS_R,7)av_SS_E,8)av_MS_R,...
    % 9)av_MS_E,10)av_F,11)av_F_p,12)alpha,13)beta,14)a_se,15)a_t,16)a_p,17)b_se,18)b_t,19)b_p
    g_reg_results(i,1:19) = [l_reg_stats.rsquare l_reg_stats.adjrsquare...
        (l_reg_stats.fstat.sse/l_reg_stats.fstat.dfe)^.5 l_reg_stats.fstat.dfr...
        l_reg_stats.fstat.dfe l_reg_stats.fstat.ssr l_reg_stats.fstat.sse...
        l_reg_stats.fstat.ssr/l_reg_stats.fstat.dfr ...
        l_reg_stats.fstat.sse/l_reg_stats.fstat.dfe ...
        l_reg_stats.fstat.f l_reg_stats.fstat.pval ...
        l_reg_stats.tstat.beta(1,1) l_reg_stats.tstat.beta(2,1)...
        l_reg_stats.tstat.se(1,1) l_reg_stats.tstat.t(1,1) l_reg_stats.tstat.pval(1,1)...
        l_reg_stats.tstat.se(2,1) l_reg_stats.tstat.t(2,1) l_reg_stats.tstat.pval(2,1)];
        
        
end

% Annulization of monthly regression results and risk parameter collection
% sdt_excess_return = SDT(i)*SQR(12), beta, sdt_sys = beta*sdt_INDEX_excess_return, 
% sdt_resid = SE(i-stock)*SRQ(12)
g_index_risk_para(1,1:4) = [...
        std(fts2mat(g_return_fints.(strrep(cell2mat(g_index_cell(1)),'^',''))))*(12^(1/2)) ...
        1 ...
        1*(std(fts2mat(g_return_fints.(strrep(cell2mat(g_index_cell(1)),'^',''))))*(12^(1/2))) ...
        0
        ];
for i=1:length(g_symbol_cell)
    g_symbol_riks_para(i,1:4) = [...
        std(fts2mat(g_return_fints.(strrep(cell2mat(g_symbol_cell(i)),'-',''))))*(12^(1/2))...
        g_reg_results(i,13)...
        g_reg_results(i,13)*g_index_risk_para(1,1)...
        g_reg_results(i,3)*(12^(1/2))
        ];
end


% Calculate weight support values
% std_resid^, alpha/std_resid^2
l_std_alpha_mat = zeros(6,1);
for i=1:length(g_symbol_cell)
    l_std_alpha_mat(i,1:1) = [g_symbol_alpha_estimates_mat(i)/(g_symbol_riks_para(i,4)^2)];
end
l_sum_of_std_alpha = sum(l_std_alpha_mat);

% Calculate active weights
% w(i), w(i)^2
l_active_weights_mat = zeros(6,1);
l_active_weights_squared_mat = zeros(6,1);
for i=1:length(g_symbol_cell)
    l_active_weights_mat(i,1:1) = [(l_std_alpha_mat(i,1)/l_sum_of_std_alpha)];
    l_active_weights_squared_mat(i,1:1) = [(l_std_alpha_mat(i,1)/l_sum_of_std_alpha)^2];
end

% Calculate total weights
l_active_port_alpha = g_symbol_alpha_estimates_mat*l_active_weights_mat;
l_active_port_resid_var = (g_symbol_riks_para(1:end,4).^2)'*l_active_weights_squared_mat;
l_w_0 = (l_active_port_alpha/l_active_port_resid_var)/(g_rfr/...
    ((std(fts2mat(g_return_fints.(strrep(cell2mat(g_index_cell(1)),'^',''))))*(12^(1/2)))^2));
l_active_port_beta = g_reg_results(1:end,13)'*l_active_weights_mat;
l_active_port_pct_of_total = l_w_0/(1+(1-l_active_port_beta)*l_w_0);
g_symbol_optimal_weights = l_active_weights_mat(1:end,1:1)*l_active_port_pct_of_total;

% Fomulate output
fprintf('Pct to active: %8.4f\n',l_active_port_pct_of_total*100);
fprintf('Pct to passive: %8.4f\n',(1-l_active_port_pct_of_total)*100);
fprintf('Beta of active: %8.4f\n',l_active_port_beta);
for i=1:length(g_symbol_cell)
   fprintf('Pct invested in symbol %4.4s: %8.4f\n',cell2mat(g_symbol_cell(i)),g_symbol_optimal_weights(i)*100); 
end






Contact us