Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit


MIE 1622H: Assignment 1 – Mean-Variance

Portfolio Selection Strategies

2022


Introduction

The purpose of this assignment is to compare computational investment strategies based on min- imizing portfolio variance and maximizing Sharpe ratio.  You will need to take into account the effect of trading costs.

We start with the classical Markowitz model of portfolio optimization. We are trading only stocks S1, . . . , Sn, and the total number of stocks is n = 20. At holding period t the expected (daily) return of stock i is µi(t), the standard deviation of the return is σi(t).  The correlation between the returns of stocks i j is ρij(t).  To abbreviate notation we introduce the return vector µt  = (µ1(t), . . . , µn(t))T and the covariance matrix Qt  = [ρij(t)σi(t)σj(t)]i,j=1,...,n.  At time period t we estimate µt  and Qt  from the period t _ 1 time series. There are 12 holding periods and each holding period lasts 2 months (2 years in total). As a result, you can re-balance your portfolio at most 12 times.

Each transaction has a cost composed of a variable portion only.  The variable fee is due to the difference between the selling and bidding price of a stock, and is 0.5% of the traded volume. This means that if a stock is quoted at 30 dollars and the investor buys 10 shares, then they are going to pay 0.005 .30 .10 = 1.50 dollars on top of the 300 dollars the 10 shares would cost otherwise. If they sell 20 shares at the same 30 dollar price then they get 600 dollars, minus the 0 .005 . 600 = 3 dollar transaction cost. Your may not need to account for transaction fees in your optimization, but you need to take them into account when computing portfolio value.

The goal of your optimization effort is to create a tool that allows the user to make regular decisions about re-balancing their portfolio and compare different investment strategies. The user wants to consider the total return, the risk and Sharpe ratio. They may want to minimize/maximize any of these components, while limiting one or more of the other components. The basic building block is a decision made at the first trading day of each 2-month holding period: given a current portfolio, the market prices on that day, and the estimates of the mean and covariance of the daily returns, make a decision about what to buy and sell according to a strategy. You are proposed to test four strategies:

1.  “Buy and hold” strategy;


2.  “Equally weighted” (also known as “1/n”) portfolio strategy;

3.  “Minimum variance” portfolio strategy;

4.  “Maximum Sharpe ratio” portfolio strategy.

To test your bi-monthly decisions, you are given daily closing prices of 20 stocks over a two-year period. Obviously, you cannot use the actual future prices when making a decision, only the price at that day, the return and covariance estimates. These estimates were derived from the actual data and are quite accurate.  Once you are done with trades for a current holding period, you should move on to the next period, use new prices (and new estimates), and make another decision. You also need to track the value of your portfolio on each day, so that you have it handy at the first trading day of a new period. You re-balance your portfolio on the first trading day of each 2-month holding period (up to 12 re-balances during 2 years).

The stocks for the assignment are from the US stock markets and are quoted in US dollars. Quotes are given on trading days, which are the days for which a price is given. The data is from 2020 and 2021.

The initial portfolio is as follows:  “IBM” = 902 shares, “BK” = 17500 shares.

The value of the initial portfolio is about one million dollars. The initial cash account is zero USD. The cash account must be nonnegative at all times.  Your optimization algorithm may suggest buying or selling a non-integer number of shares, which is not allowed.  You need to round the number of shares bought or sold to integer values and subtract transaction fees.  If the value of your portfolio after re-balancing plus the transaction fees are smaller than the portfolio value before re-balancing, the remaining funds are accumulated in the cash account. Cash account does not pay any interest, but cash funds should be used toward stock purchases when portfolio is re-balanced next time.

An estimate of the daily returns of the stocks (for trading days) and the covariances of the returns are computed for you. These estimates are based on the previous two-month data and are updated every second month. You can only use the current estimate for the calculations and are not allowed to change or update the estimates in any way.

Note that for buying and selling asset shares, you need to optimize over asset weights.  Current weight of asset i in a portfolio is wi = vV(●)x" , where V is the current portfolio value, vi is current price of asset i and xi is the number of units (shares) of asset i in your portfolio. As initial portfolio value is 1000012.93 USD, price of IBM stock at the first trading day of holding period 1 is 117.12 USD, and we hold 902 shares, then w 1(1)0 = = = 0.106.

Questions

1. (70 %) Implement investment strategies in Python:

You need to test four portfolio re-balancing strategies:

1.  “Buy and hold” strategy: it is the simplest strategy where you hold initial portfolio for the entire investment horizon of 2 years.  The strategy is already implemented in the function strat_buy_and_hold.

2.  “Equally weighted”  (also known  as  “1/n”) portfolio  strategy:   asset weights  are  se- lected as wi(t)   =  1/n, where n is the number of assets.   You may need to re-balance your portfolio in each period as the number of shares xi(t)  changes even when wi(t)  = 1/n stays the same in each period.   The strategy should be implemented in the function strat_equally_weighted.

3.  “Minimum variance” portfolio strategy:  compute minimum variance portfolio for each period and re-balance accordingly. The strategy should be implemented in the function strat_min_variance.

4.  “Maximum Sharpe ratio” portfolio strategy: compute a portfolio that maximizes Sharpe ratio for each period and re-balance accordingly.  The strategy should be implemented in the function strat_max_Sharpe.

Design and implement a rounding procedure, so that you always trade (buy or sell) an integer number of shares.

Design and implement a validation procedure in your code to test that each of your strategies is feasible (you have enough budget to re-balance portfolio, you correctly compute transaction costs, funds in your cash account are non-negative).

There is a file portf optim.py on the course web-page.  You are required to complete the code in the file.

Your Python code should use only CPLEX optimization solver without CVXPY module. Make commenting of your code for important logics.

2. (20 %) Analyze your results:

❼ Produce the following output for the 12 periods (years 2020 and 2021):

Period  1:  start  date  01/02/2020,  end  date  02/28/2020

Strategy  "Buy  and  Hold",  value  begin  =  $  1000012.93,  value  end  =  $  893956.75 Strategy  "Equally  Weighted  Portfolio",  value  begin  =  ...  ,  value  end  =  ...    ...

Period  12:  start  date  11/01/2021,  end  date  12/31/2021

Strategy  "Buy  and  Hold",  value  begin  =  $  951350.41,  value  end  =  $  932471.35 Strategy  "Equally  Weighted  Portfolio",  value  begin  =  ...  ,  value  end  =  ...

❼ Plot one chart in Python that illustrates the daily value of your portfolio  (for each

trading strategy) over the years 2020 and 2021 using daily prices provided. Include the chart in your report.

❼ Plot two charts in Python for strategy 3 and 4 to show dynamic changes in portfolio

allocations. In each chart, x-axis represents the rolling up time horizon, y-axis denotes portfolio weights between 0 and 1, and distinct lines display the position of selected assets over time periods. You may use these figures to support your analysis or discussion.

❼ Compare your trading strategies and discuss their performance relative to each other.

Which strategy would you select for managing your own portfolio and why?

3. (10 %) Discuss possible improvements to your trading strategies:

❼ Test your Python program for different variations of your strategies, e.g., select “1/n”

portfolio at the beginning of period 1 and hold it till the end of period 12 (as if the re- balancing strategy required large transaction costs).  Discuss if you are able to achieve better results.

❼ Can you suggest any improvements of the trading strategies that you have implemented?

Python File to be Completed

#  Import  libraries

import pandas  as pd

import numpy  as np

import math

#  Complete the  following  functions

def  strat_buy_and_hold(x_init,  cash_init, mu,  Q,  cur_prices):

x_optimal  =  x_init

cash_optimal  =  cash_init

return  x_optimal,  cash_optimal

def  strat_equally_weighted(x_init,  cash_init, mu,  Q,  cur_prices):

return  x_optimal,  cash_optimal

def  strat_min_variance(x_init,  cash_init, mu,  Q,  cur_prices):

return  x_optimal,  cash_optimal

def  strat_max_Sharpe(x_init,  cash_init, mu,  Q,  cur_prices):

return  x_optimal,  cash_optimal

#  Input  file

input_file_prices  =  ’Daily_closing_prices.csv’

# Read  data  into  a  dataframe

df  = pd.read_csv (input_file_prices)

#  Convert  dates  into  array  [year month  day]

def  convert_date_to_array(datestr):

temp  =  [int(x)  for  x  in  datestr.split(’/’)]

return  [temp[-1], temp[0], temp[1]]

dates_array  = np.array(list(df[’Date’].apply(convert_date_to_array)))

data_prices  =  df.iloc[:,  1:].to_numpy()

dates  = np.array(df[’Date’])

#  Find the number  of  trading  days  in  Nov-Dec  2019  and

#  compute  expected  return  and  covariance matrix  for period  1

day_ind_start0  =  0

day_ind_end0  =  len(np.where(dates_array[:,0]==2019)[0])

cur_returns0  =  data_prices[day_ind_start0+1:day_ind_end0,:]  /  data_prices[day_ind_start0:day_ind_end0-1,:]  -  1 mu  = np.mean(cur_returns0,  axis  =  0)

Q  = np.cov(cur_returns0.T)

# Remove  datapoints  for  year  2019

data_prices  =  data_prices[day_ind_end0:,:]

dates_array  =  dates_array[day_ind_end0:,:]

dates  =  dates[day_ind_end0:]

#  Initial positions  in the portfolio

init_positions  = np.array([0,  0,  0,  0,  0,  0,  0,  0,  0,  902,  0,  0,  0,  0,  0,  0,  0,  0,  0,  17500])

#  Initial value  of the portfolio

init_value  = np.dot (data_prices[0,:],  init_positions)

print(’\nInitial portfolio value  =  $  {}\n’.format(round(init_value,  2)))

#  Initial portfolio weights

w_init  =  (data_prices[0,:]  *  init_positions)  /  init_value

#  Number  of periods,  assets, trading  days

N_periods  =  6*len(np.unique(dates_array[:,0]))  #  6 periods per  year

N  =  len(df.columns)-1

N_days  =  len(dates)

#  Annual  risk-free  rate  for  years  2020-2021  is  2.5%

r_rf  =  0.025

#  Number  of  strategies

strategy_functions  =  [’strat_buy_and_hold’,  ’strat_equally_weighted’,  ’strat_min_variance’,  ’strat_max_Sharpe’] strategy_names         =  [’Buy  and Hold’,  ’Equally Weighted Portfolio’,  ’Mininum Variance  Portfolio’,

’Maximum  Sharpe Ratio Portfolio’]

N_strat  =  1   #  comment this  in  your  code

#N_strat  =  len(strategy_functions)   # uncomment this  in  your  code

fh_array  =  [strat_buy_and_hold,  strat_equally_weighted,  strat_min_variance,  strat_max_Sharpe]

portf_value  =  [0]  *  N_strat

x  = np.zeros((N_strat,  N_periods),   dtype=np.ndarray)

cash  = np.zeros((N_strat,  N_periods),   dtype=np.ndarray)

for period  in  range(1,  N_periods+1):

#  Compute  current  year  and month,  first  and  last  day  of the period

if  dates_array[0,  0]  ==  20:

cur_year   =  20  + math.floor(period/7)

else:

cur_year   =  2020  + math.floor(period/7)

cur_month  =  2*((period-1)%6)  +  1

day_ind_start  =

min([i  for  i, val  in  enumerate((dates_array[:,0]  ==  cur_year)  &  (dates_array[:,1]  ==  cur_month))  if val]) day_ind_end  =

max([i  for  i, val  in  enumerate((dates_array[:,0]  ==  cur_year)  &  (dates_array[:,1]  ==  cur_month+1))  if  val]) print(’\nPeriod  {0}:  start  date  {1},  end  date  {2}’.format(period,  dates[day_ind_start],  dates[day_ind_end]))

# Prices  for the  current  day

cur_prices  =  data_prices[day_ind_start,:]

# Execute portfolio  selection  strategies

for  strategy    in  range(N_strat):

#  Get  current portfolio positions

if period  ==  1:

curr_positions  =  init_positions

curr_cash  =  0

portf_value[strategy]  = np.zeros((N_days,  1))

else:

curr_positions  =  x[strategy, period-2]

curr_cash  =  cash[strategy, period-2]

#  Compute  strategy

x[strategy, period-1],  cash[strategy, period-1]  =  fh_array[strategy](curr_positions,  curr_cash, mu,  Q,  cur_prices)

# Verify that  strategy  is  feasible  (you have  enough budget  to  re-balance portfolio)

#  Check that  cash  account  is  >=  0

#  Check that we  can buy new portfolio  subject to transaction  costs

######################  Insert  your  code here  ############################

#  Compute portfolio value

p_values  = np.dot (data_prices[day_ind_start:day_ind_end+1,:],  x[strategy, period-1])  +  cash[strategy, period-1] portf_value[strategy][day_ind_start:day_ind_end+1]  = np.reshape(p_values,  (p_values.size,1))

print(’    Strategy  "{0}", value begin  =  $  {1:.2f},  value  end  =  $  {2:.2f}’.format(  strategy_names[strategy], portf_value[strategy][day_ind_start][0], portf_value[strategy][day_ind_end][0]))

#  Compute  expected  returns  and  covariances  for the next period

cur_returns  =  data_prices[day_ind_start+1:day_ind_end+1,:]  /  data_prices[day_ind_start:day_ind_end,:]  -  1 mu  = np.mean(cur_returns,  axis  =  0)

Q  = np.cov(cur_returns.T)

# Plot  results

######################  Insert  your  code here  ############################

Sample Python Function for Trading Strategy

def  strat_buy_and_hold(x_init,  cash_init, mu,  Q,  cur_prices):

x_optimal  =  x_init

cash_optimal  =  cash_init

return  x_optimal,  cash_optimal