代做MIE 1622H: Assignment 1 – Mean-Variance代做Python编程

- 首页 >> Web

MIE 1622H: Assignment 1 Mean-Variance

Portfolio Selection Strategies

January 27, 2025

Due: Saturday, February 15, 2025, not later than 11:59p.m.

Use Python for all MIE1622H assignments.

You should hand in:

Your report (pdf file and docx file). Maximum page limit is 4 pages.

•  Compress all of your Python code  (i.e., ipynb notebook with plots and necessary outputs intact) into a zip file and submit it via Quercus portal no later than 11:59p.m. on February 15.

Where to hand in: Online via Quercus portal, both your code and report.

Introduction

The purpose of this assignment is to compare computational investment strategies based on mini- mizing portfolio variance, maximizing expected return 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 isn = 30. 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 five strategies:

1.  “Buy and hold” strategy;

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

3.  “Minimum Variance” portfolio strategy;

4.  “Maximum Expected Return” portfolio strategy;

5.  “Maximum Sharpe ratio” portfolio strategy.

To test your bi-monthly decisions, you are given adjusted closing prices of 30 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 expected 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 30 stocks for this assignment are from U.S. stock market, priced in U.S. dollars. Their quotes are given on trading days as adjusted closing prices. The data set is from January 2020 to Decem- ber 2021. The list of assets and their sectors is:

1. Technology: AAPL, MSFT, NVDA, IBM, AMD, CSCO, HPQ, SONY

2. Financial Services: JPM, BAC, MS

3. Healthcare: JNJ, UNH, PFE

4. Consumer Cyclical: AMZN, F, HOG

5. Consumer Defensive: KO, PG

6. Energy: XOM, CVX

7. Real Estate: AMT, PLD

8. Communication Services: GOOG, T, VZ

9. Industrials: HON, CAT

10. Utilities: NEE, DUK

The initial portfolio is as follows:“HOG” = 3447 shares, “VZ” = 19385 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 = V/vi·xi , 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 the initial portfolio value for the 2020-2021 period is $1,000,016.96 USD, the price of the HOG stock on the first trading day of holding period 1 is 34.08 USD, and we hold 3447 shares, then w12 1 = V1/v1 12·x1 12 = 1000016.96/34.08·3447 = 0.1175.

Questions

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

You need to test five 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 儿i(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 Expected Return” portfolio strategy:  build a portfolio that maximizes ex- pected return for each period and re-balance accordingly.  The strategy should be im- plemented in the function strat_max_return.

5.  “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 tore-balance portfolio, you correctly compute transaction costs, funds in your cash account are non-negative).

There is a file portf optim.ipynb on the course web-page.  You are required to complete the code in the file. Make sure to restart the notebook and re-run all cells on Google Colab before submitting, and have all outputs and plots intact when saving the notebook.

Your Python code should use only CPLEX optimization solver without CVXPY module. You are required to briefly comment on your code to explain important logic and implementation details. Some marks may be deducted for lack of explanation or poorly commented code.

You are required to provide a mathematical formulation to the optimization problem you solve in strategy 3, 4, and 5 and explain relevant information (variables, constraints, objec- tive function, data parameters, etc).   This should be done in the report and can refer to comments/code from the ipynb file.

For this assignment you need to use Google Colab and install the trial version of CPLEX (available on Colab) as sizes of the optimization problems are small.  To install CPLEX on Google Colab just run  !pip  install  cplex.

2. (25 %) Analyze your results:

Produce the following output for the 12 periods (two years):

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

Strategy  "Buy  and  Hold",  value  begin  =  $  1000016 .96,  value  end  =  $  887595 .87,  cash  account  =  $0 .00 Strategy  "Equally  Weighted  Portfolio",  value  begin  =  . . . ,  value  end  =  . . . ,  cash  account  =  . . .

...

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

Strategy  "Buy  and  Hold",  value  begin  =  $  964589 .81,  value  end  =  $  942602 .39,  cash  account  =  $0 .00 Strategy  "Equally  Weighted  Portfolio",  value  begin  =  . . . ,  value  end  =  . . . ,  cash  account  =  . . .

•  Plot one chart in Python that illustrates the daily value of your portfolio (for each trading strategy) over the two years using daily adjusted closing prices provided.  Include the chart in your report.

•  Plot three charts in Python for strategy 3, 4, and 5 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?

•  Compute the risk measures (variance, maximum drawdown, and Sharpe ratio) for the “Maximum Expected Return” portfolio strategy over the 2020-2021 time period and compare those to measures for other strategies.

3. (25 %) 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?

•  To potentially reduce risk measures for the “Maximum Expected Return” portfolio strat- egy, apply sector diversification constraints by ensuring that the total weight of stocks in each sector is between 0% and 25%.  Then,  compare your results with those in the previous section.

•  Re-test all of your strategies for the 2023-2024 time period and plot the daily value of your portfolio over these two years using the daily adjusted closing prices provided in the new dataset (adjclose_2023_2024.csv file). Use the new initial portfolio consisting of “HOG” = 10,904 shares and “CVX” = 3,542 shares,whose total value is again about one million dollars, and apply the updated risk-free rate of 4.5% (instead of 1.5% for 2020- 2021). Then, considering the economic contexts of these two distinct two-year periods, compare the performance of all strategies and clearly discuss how market conditions may have influenced performances, rewards and risks of your portfolios during 2020–2021 versus 2023–2024 time periods.

(Optional Question) Using a generative AI tool (e.g., ChatGPT), produce a one-page, executive-style summary of your portfolio modeling results and analyses.  Include this AI-generated summary in your report and briefly discuss its clarity, accuracy, and any important points it may have missed relative to your own written conclusions. You can get additional 5% for answering this optional question, but your maximal mark for the assignment cannot exceed 16 points.

Python Code to be Completed (available on Quercus)

#  Import  libraries   import  pandas  as  pd import  numpy  as  np   import  math

"""#  Strategies

For  strategies  3,4  and  5  include  mathematical  formulation  of  optimization  problem  in  report  and/or  in  notebook

"""

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_max_return(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

"""#  Data  loading  and  initialization  of  portfolios"""

#  Input  file

input_file_prices=’adjclose_2020_2021 .csv’  #  path  to  close_2020_2021  file

#  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

if  ’2021’  in  input_file_prices:

day_ind_end0  =  len(np.where(dates_array[:,0]==2019)[0]) elif  ’2022’  in  input_file_prices:

day_ind_end0  =  len(np.where(dates_array[:,0]==2020)[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,  0,  0,  3447,  0,  0,  0,

0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  19385,  0])

#  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  1.5% r_rf  =  0 .015

#  Number  of  strategies

strategy_functions  =  [’strat_buy_and_hold’,  ’strat_equally_weighted’,  ’strat_min_variance’,

’strat_max_return’,  ’strat_max_Sharpe’]

strategy_names        =  [’Buy  and  Hold’,  ’Equally  Weighted  Portfolio’,  ’Minimum  Variance  Portfolio’,

’Maximum  Expected  Return  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_return,  strat_max_Sharpe] """#  Running  computations  and  printing  results"""

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  ’2020’  in  input_file_prices:

if  dates_array[0,  0]  ==  20:

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

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

elif  ’2021’  in  input_file_prices:

if  dates_array[0,  0]  ==  21:

cur_year    =  21  +  math.floor(period/7) else:

cur_year    =  2021  +  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},  cash  account  =  ${3: .2f}’ .format( strategy_names[strategy],  portf_value[strategy][day_ind_start][0],

portf_value[strategy][day_ind_end][0],  cash[strategy,  period-1]))

#  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"""

#  Plot  results

######################  Insert  your  code  here  ############################ """#  Repeat  for  years  2023-2024"""

#  Input  file

input_file_prices_new=’adjclose_2023_2024 .csv’  #  path  to  close_2023_2024  file

#  Read  data  into  a  dataframe.

df_new  =  pd.read_csv(input_file_prices_new)

#  Initial  positions  in  the  portfolio

init_positions_new  =  np .array([0,  0,  0,  0,  0,  0,  0,  3542,  0,  0,  0,  10904,  0,  0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0])

#  Annual  risk-free  rate  for  years  2023-2024  is  4.5% r_rf2023_2024  =  0 .045

#  Repeate  the  previous  calculation  for  the  time  period  2023-2024

######################  Insert  your  code  here  ############################ """#  Plot  the  results  for  years  2023-2024"""

#  Plot  results  for  2023-2024

######################  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


站长地图