www.gusucode.com > GAVPai_Book_MathworksCntrlFileEx_May2019 > GAVPai_Book_MathworksCntrlFileEx_May2019/Chapter7_ESHOF_PortfolioRebalancing_TrCosts.m

    % Vijayalakshmi Pai G A, Metaheuristics for Portfolio Optimization, An
% Introduction using MATLAB, ISTE-Wiley, 2017.

% Evolution Stategy with Hall of Fame (ES HOF)for Portfolio Rebalancing with Transaction Costs 

% Chapter 7   Sec. 7.3  
% The constrained portfolio rebalancing model  is represented by equations [7.8]-[7.9] for
% its objective function and equations [7.2]-[7.6] for its constraints

% The portfolio considered is a high risk portfolio of  assets comprising the top 15 percentile of 
% high volatility  stocks of S&PBSE200 Index 
% Sec. 7.4.1

% The data file S&PBSE200_RebalPortfolio.xls records the mean returns of the
% assets of the high risk portfolio, followed by variance-covariance matrix
% of returns of the assets, with the  asset labels displayed in the last row


% Program coding:  Dr G A Vijayalakshmi Pai
% Note: Coding style has been kept naive and direct to favor novices in
% MATLAB. Users familiar with MATLAB are encouraged to improvise the code
%------------------------------------------------------------------------

clear all

portfolio_size = 32; % 32 high risk assets comprising the portfolio

% obtain mean returns and variance-covariance matrix of returns for the
% portfolio 
file_name = 'S&PBSE200_RebalPortfolio.xls';  
m = xlsread(file_name);
mean_data = m(1,:);
cov_data = m(2:portfolio_size+1, :);

% obtain optimal weights, maximal diversification ratio, risk and return of
% the original portfolio
OriginalPortfolio_Optimal_Wgts = [0.0248	0.0137	0.0010	0.0010	0.0512	0.0209	0.0316	0.0576	0.0323	0.0010	0.0409	0.0010	0.0020	0.1115	0.0250	0.0010	0.0010	0.0149	0.0151	0.0316	0.0010	0.0695	0.0635	0.0687	0.0595	0.0059	0.0308	0.0617	0.0575	0.0425	0.0435	0.0171];
OriginalPortfolio_MxDR = 2.7822;		
OriginalPortfolio_Daily_Risk = 0.0208;	
OriginalPortfolio_Daily_Retrn = 0.0034;

% set Transaction cost 
p=0.0044; 

% set lower and upper bounds of buy and sell weights 
buy_lowbounds = zeros(1, portfolio_size);
buy_upbounds = ones(1,portfolio_size)*0.025;
sell_lowbounds = zeros(1, portfolio_size);
sell_upbounds = OriginalPortfolio_Optimal_Wgts;



% Set  Evolutionary  algorithm parameters
popln_size = 320;   
chromosm_length = portfolio_size;  
total_generations = 100;  


% Joines and Houck's (1994)  dynamic penalty (dp) function strategy 
% Set parameters (C, alpha, beta)
C_dp = 0.5; 
beta_dp=2;
alpha_dp=2;
epsilon = 0.0009;

% initialize Hall of Fame
HOF_fitness = -9999;


fix(clock)

% generation counter
gen_indx = 1;    
% index for HOF fitness trace
i1=1; 
    
% generate random initial population of buy sell weights subject to their respective bounds                
rebal_popln_raw = generate_bounded_popln(popln_size, portfolio_size,sell_lowbounds , sell_upbounds, buy_lowbounds,  buy_upbounds);

% determine the respective lower and upper bounds of the genes in the
% population
low_up_bounds = determine_bounds(rebal_popln_raw, buy_lowbounds,  buy_upbounds, sell_lowbounds, sell_upbounds);

% repair weights 
initial_rebal_popln_stdzn = PortfolioRebalancing_WeightRepair(rebal_popln_raw, low_up_bounds,p );

% compute the population of rebalanced weights
initial_popln = ones(popln_size,1)*OriginalPortfolio_Optimal_Wgts + initial_rebal_popln_stdzn;

% compute constraint violation function
[G_parent, parent_psi]  = compute_constrvioln_fn_Rebal( initial_popln, cov_data, OriginalPortfolio_Daily_Risk, C_dp, beta_dp, alpha_dp, gen_indx); %compute constraint violation functions using Joines and Houck's dynamic penalty functions              

% compute fitness function 
[parent_fitness ] = Rebal_comp_fitness(initial_popln, cov_data, parent_psi);
    

% set parent population 
feasX_parent_popln = initial_rebal_popln_stdzn;
feasW_parent_popln = initial_popln;
feasW_parent_fitness = parent_fitness;
feasW_parent_psi = parent_psi;

% counter for P measure
pa_count =1; 


% ES HOF generation cycles begin
while (gen_indx <= total_generations) 
    
        gen_indx    
    
        % perform cross over on the parent population 
        offsprngX_popln_raw= rand_varpt_arith_crossover(feasX_parent_popln, popln_size, chromosm_length);
        
        % perform mutation to yield offspring population
        offsprngX_popln_mutat = realnum_unifrm_mutation(offsprngX_popln_raw, popln_size, chromosm_length);
        
        % Normalize offspring population
        offsprngX_popln_norm = normalize_weight(offsprngX_popln_mutat, sell_lowbounds , sell_upbounds, buy_lowbounds,  buy_upbounds);
        
        % determine lower and upper bounds of the buy sell weights
        low_up_bounds = determine_bounds(offsprngX_popln_norm, buy_lowbounds,  buy_upbounds, sell_lowbounds , sell_upbounds);
        
        % repair weights of the offspring population
        offsprngX_popln = PortfolioRebalancing_WeightRepair(offsprngX_popln_norm, low_up_bounds,p );
        
        % compute the population of rebalanced weights
        offsprngW_popln = ones(popln_size,1)*OriginalPortfolio_Optimal_Wgts + offsprngX_popln; % Xi
        
        % compute constraint violation function
        [G_offsprngW, offsprngW_psi]  = compute_constrvioln_fn_Rebal(offsprngW_popln, cov_data, OriginalPortfolio_Daily_Risk, C_dp, beta_dp, alpha_dp, gen_indx); %compute constraint violation functions using Joines and Houck's dynamic penalty functions              
        
        % compute fitness function
        [offsprngW_fitness] = Rebal_comp_fitness(offsprngW_popln, cov_data,   offsprngW_psi);
       
        % construct the new generation selecting the best of parent and
        % offspring population
        [NextGenPool_X, NextGenPool_W, NextGenPool_fitness, NextGenPool_psi] = construct_newgen(feasX_parent_popln, feasW_parent_popln, feasW_parent_fitness, feasW_parent_psi ,  offsprngX_popln, offsprngW_popln, offsprngW_fitness, offsprngW_psi);
        
        %induct best fit  individual into Hall of Fame
        for i=1:popln_size
            if (NextGenPool_psi(i)== 0)
                                       
                    if (NextGenPool_fitness(i) > HOF_fitness)
                    HOF_fitness = NextGenPool_fitness(i)
                    HOF_individualW = NextGenPool_W(i,:);
                    HOF_individualX = NextGenPool_X(i,:);
           
                    HOF_genarray(i1) = gen_indx;
                    HOF_fitarray(i1) = HOF_fitness;
                    i1=i1+1;
                    end
            else continue;
            end
        end
        

        % compute Population measure             
        p_measure_gen = compute_Pmeasure(NextGenPool_W);
        perfanaly_pmeasure(pa_count, :)= [gen_indx, p_measure_gen];
        pa_count=pa_count+1;

        
        % set parent population for the next generation cycle    
        feasX_parent_popln = NextGenPool_X;
        feasW_parent_popln = NextGenPool_W; 
        feasW_parent_fitness = NextGenPool_fitness;
        feasW_parent_psi = NextGenPool_psi;
    
        gen_indx = gen_indx + 1;
end 


fix (clock)

% extract the optimal solution (rebalanced weights)  from the Hall of Fame
disp('Optimal Rebalanced Portfolio Weights')
Optimal_RebalWeights = HOF_individualW 

% compute  risk, return and Diversification Ratio of the optimal rebalanced
% portfolio

daily_rebal_portfolio_return = sum(mean_data .* Optimal_RebalWeights);
disp('Rebalanced portfolio annualized return %')
ann_rebal_portfolio_return =  261 * daily_rebal_portfolio_return*100
rebal_portfolio_risk = sqrt(Optimal_RebalWeights * cov_data * Optimal_RebalWeights');
disp('Rebalanced portfolio annualized risk %')
ann_rebal_portfolio_risk = sqrt(261)* rebal_portfolio_risk*100
stdev_portfolio = sqrt(diag(cov_data));
disp('Rebalanced portfolio Diversification Ratio')
rebal_portfolio_DR  = (sum(stdev_portfolio .* Optimal_RebalWeights') / rebal_portfolio_risk)


% compare risk, return and Diversification Ratio of the original portfolio
disp('Original portfolio annualized return %')
original_portfolio_return = OriginalPortfolio_Daily_Retrn * 261*100
disp('Original portfolio annualized risk %')
original_portfolio_risk = OriginalPortfolio_Daily_Risk * sqrt(261)*100
disp('Original portfolio Diversification Ratio')
original_portfolio_DR = OriginalPortfolio_MxDR

disp('Successful Execution');