Introduction

These study notes are based on Chapter 6 the Exam 9 syllabus reading Investments by Bodie, Kane, and Marcus. This chapter illustrates how to determine the optimal allocation between risk-free and risky assets, given an investor’s level of risk tolerance. This chapter corresponds to learning objective A1 on the syllabus.

The reading considers a complete portfolio that consists of two investments:

The rate of return of the complete portfolio is \[ r_C = y r_P + (1-y)r_f = r_f + y(r_P - r_f) \] Note that the second expression for \(r_C\) expresses \(r_C\) as having a risk premium that is some fraction, \(y\) of the risk premium of \(P\). The standard deviation of the complete portfolio is \[ \sigma_C = y \sigma_P \]

easypackages::packages("dplyr", "ggplot2")

Utility Function

The approach assumes that investors assign a utility score to various portfolios, and select the portfolio with the highest score. This is also called a certainty equivalent rate of return. An example of a utility function is \[ U = E(r) - \frac12 A \sigma^2, \] where \(A\) is a parameter reflecting the investor’s risk appetite:

The parameter \(A\) is a subjective view on the part of the investor. Ways of determining an appropriate value for \(A\) include:

The following example illustrates how different investors would make decisions depending on their level of risk aversion:

bkm.utility.example = read.csv("./Data/BKM_6.csv")
## Warning in read.table(file = file, header = header, sep = sep, quote
## = quote, : incomplete final line found by readTableHeader on './Data/
## BKM_6.csv'
bkm.utility.example
##   portfolio risk_premium standard_deviation
## 1         L         0.02               0.05
## 2         M         0.04               0.10
## 3         H         0.08               0.20

First, calcutate the expected return by adding the risk-free rate, assumed to be 5% in this example.

risk.free.rate = 0.05
bkm.utility.example = bkm.utility.example %>% mutate(expected_return = risk_premium + risk.free.rate)
bkm.utility.example
##   portfolio risk_premium standard_deviation expected_return
## 1         L         0.02               0.05            0.07
## 2         M         0.04               0.10            0.09
## 3         H         0.08               0.20            0.13

Next, calculate utility for three different values of \(A\):

A.values = c(2, 3.5, 5)
A.df = data.frame(A_value = A.values)
bkm.utility.comparison = merge(bkm.utility.example, A.df)
bkm.utility.comparison = bkm.utility.comparison %>% mutate(utility = expected_return - 0.5 * A_value * standard_deviation^2)
bkm.utility.comparison
##   portfolio risk_premium standard_deviation expected_return A_value
## 1         L         0.02               0.05            0.07     2.0
## 2         M         0.04               0.10            0.09     2.0
## 3         H         0.08               0.20            0.13     2.0
## 4         L         0.02               0.05            0.07     3.5
## 5         M         0.04               0.10            0.09     3.5
## 6         H         0.08               0.20            0.13     3.5
## 7         L         0.02               0.05            0.07     5.0
## 8         M         0.04               0.10            0.09     5.0
## 9         H         0.08               0.20            0.13     5.0
##    utility
## 1 0.067500
## 2 0.080000
## 3 0.090000
## 4 0.065625
## 5 0.072500
## 6 0.060000
## 7 0.063750
## 8 0.065000
## 9 0.030000

The investor with \(A = 2\) would select portfolio \(H\), while the other two investors would both select portfolio \(M\).

Portfolios can be compared graphically by plotting them such that standard deviation is on the \(y\)-axis, and expected return is on the \(x\)-axis:

ggplot(data = bkm.utility.example, aes(x = standard_deviation, y = expected_return, col = portfolio)) + geom_point(size = 4)

The mean-variance criterion states that, for a risk adverse investor, portfolio \(A\) is preferred to portfolio \(B\) if portfolio \(A\) has both a higher expected return and a lower standard deviation. (Only one of the inequalities needs to be strict.) Geometrically, this corresponds to portfolio \(A\) appearing northwest of portfolio \(B\). When this occurs, portfolio \(A\) is unambiguously preferred to portfolio \(B\). None of the portfolios in this example dominates another, so the utility function must be used to distinguish them.

For a given investor, the indifference curve for a given certainty-equivalent rate corresponds to all portfolios that have the same certainty-equivalent rate. It can be plotted, as above, by expressing the expected return as a function of standard deviation: \[ E(r) = U + \frac12 A\sigma^2 \] The following calculates indifference curves for each of the three investors at a utility value of 0.09 and 0.06:

indifference.curve = function(A, sd, U) {
  return(U + 0.5 * A * sd^2)
}
indifference.curve.data = merge(A.df, data.frame(sd = 0:25 / 100))
indifference.curve.data$utility_09 = apply(indifference.curve.data, 1, function(y){ indifference.curve(A = y['A_value'], sd = y['sd'], U = 0.09)})
indifference.curve.data$utility_06 = apply(indifference.curve.data, 1, function(y){ indifference.curve(A = y['A_value'], sd = y['sd'], U = 0.06)})

Plot the curves along with the three portfolios:

ggplot(data = indifference.curve.data, aes(x = sd, y = utility_09, col = as.factor(A_value))) + geom_line() + geom_line(aes(y = utility_06)) + expand_limits(y = 0) + geom_point(data = bkm.utility.example, aes(x = standard_deviation, y = expected_return, col = portfolio), size = 4) + labs(x = "Standard Deviation", y = "Expected Return")

*Note that higher degrees of risk aversion correspond to steeper slopes, since a more risk adverse investor will demand higher returns at large standard deviations than a less risk averse investor would.

Captial Allocation Line

The Capital Allocation Line (CAL) is a plot of the expected return of the complete portfolio against standard deviation. In order to plot this, note that for the complete portfolio \[ y = \frac{\sigma_C}{\sigma_P} \] so that \[ E[r_C] = r_f + \frac{\sigma_C}{\sigma_P}(E[r_P] - r_f) \]

Consider the following three portfolios:

bkm.utility.example.2 = read.csv("./Data/BKM_6_v2.csv")
## Warning in read.table(file = file, header = header, sep = sep, quote
## = quote, : incomplete final line found by readTableHeader on './Data/
## BKM_6_v2.csv'
bkm.utility.example.2 = bkm.utility.example.2 %>% mutate(expected_return = risk.free.rate + risk_premium)
bkm.utility.example.2
##   portfolio risk_premium standard_deviation expected_return
## 1         A         0.04                0.1            0.09
## 2         B         0.04                0.2            0.09
## 3         C         0.06                0.2            0.11

Impose the restriction that \(y \leq 1\) since we cannot allocate more than 100% of the portfolio to the risky asset.

CAL.data = merge(bkm.utility.example.2, data.frame(sd = 0:25 / 100)) %>% filter(sd <= standard_deviation)
expected.return = function(risk.free.rate, sigma.C, sigma.P, expected.return.P) {
  return(risk.free.rate + sigma.C / sigma.P * (expected.return.P - risk.free.rate))
}
CAL.data$CAL = apply(CAL.data %>% select(-portfolio), 1, function(y) {expected.return(risk.free.rate = risk.free.rate, sigma.C = y['sd'], sigma.P = y['standard_deviation'], expected.return.P = y['expected_return'])})
ggplot(data = CAL.data, aes(x = sd, y = CAL, col = portfolio)) + geom_line()

This graph plots the investment opportunity set of all feasible portfolios with \(0 \leq y \leq 1\). The slope of the Capital Allocation Line is the Sharpe Ratio, the ratio of the risk premium to standard deviation: \[ S = \frac{E(r_P) - r_f}{\sigma_P} \] Note that the Sharpe ratio increases if either the standard deviation decreases, or the expected return increases; therefore, higher values of the Sharpe ratio correspond to better risky portfolios.

It is possible to extend the Capital Allocation Line for \(y \geq 1\), but this assumes that the investor borrows money to make leveraged investments in the risky portfolio. However, the investor must typically borrow at a rate \(r_B > r_f\), so the expected return now becomes \[ E[r_C] = y r_P + (1 - y) r_B = r_B + \frac{\sigma_C}{\sigma_P}(r_P - r_B) \] The slope, and therefore the Sharpe ratio, become \[ \frac{E(r_P) - r_B}{\sigma_P} \] when \(y \geq 1\). This can be visualized as follows:

CAL.data.v2 = merge(bkm.utility.example.2, data.frame(sd = 0:25 / 100))
expected.return.v2 = function(risk.free.rate, borrowing.rate, sigma.C, sigma.P, expected.return.P) {
  return(ifelse(sigma.C <= sigma.P, risk.free.rate + sigma.C / sigma.P * (expected.return.P - risk.free.rate), borrowing.rate + sigma.C / sigma.P * (expected.return.P - borrowing.rate)))
}
CAL.data.v2$CAL = apply(CAL.data.v2 %>% select(-portfolio), 1, function(y) {expected.return.v2(risk.free.rate = risk.free.rate, borrowing.rate = 0.08, sigma.C = y['sd'], sigma.P = y['standard_deviation'], expected.return.P = y['expected_return'])})
ggplot(data = CAL.data.v2, aes(x = sd, y = CAL, col = portfolio)) + geom_line() + geom_point(data = bkm.utility.example.2, aes(x = standard_deviation, y = expected_return, col = portfolio), size = 4)

The points correspond to \(y=1\), i.e. situations in which the complete portfolio consists only of the risky portfolio \(P\).

Optimal Asset Allocation

The optimal amount of investment, \(y^*\), in the risky portfolio, is the value of \(y\) which maximizes the investor’s utility function. To determine this value, first express utility as a function of \(y\): \[ U(y) = r_f + y(r_P - r_f) - \frac12 A \sigma_P^2 y^2 \] The derivative with respect to \(y\) is \[ U'(y) = r_P - r_f - A \sigma_P^2y \] Setting \(U'(y^*) = 0\) and solving for \(y\), we obtain \[ y^* = \frac{r_P - r_f}{A\sigma_P^2} \] Rearranging the formula, we can also deduce the investor’s risk aversion based on their degree of investment in the risky portfolio: \[ A = \frac{r_P - r_f}{y^* \sigma_P^2} \]

For the three investors considered earlier, we can calculate the optimum value of \(y\) for each of the three risk portfolios described above. If this results in a value of \(y\geq 1\), then the borrowing rate is used instead subject to the additional constraint that \(y\geq 1\).

optimum.example = merge(bkm.utility.example.2, A.df)
optimum.y = function(risk.free.rate, expected.return, A, standard.deviation, borrowing.rate) {
  no.borrow.optimum = (expected.return - risk.free.rate) / (A * standard.deviation^2)
  borrowing.optimum = (expected.return - borrowing.rate) / (A * standard.deviation^2)
  return(ifelse(no.borrow.optimum <= 1, no.borrow.optimum, pmax(borrowing.optimum, 1)))
}
optimum.example$optimum_y = apply(optimum.example %>% select(-portfolio), 1, function(y) {optimum.y(risk.free.rate = risk.free.rate, expected.return = y['expected_return'], A = y['A_value'], standard.deviation = y['standard_deviation'], borrowing.rate = 0.08)})
optimum.example
##   portfolio risk_premium standard_deviation expected_return A_value
## 1         A         0.04                0.1            0.09     2.0
## 2         B         0.04                0.2            0.09     2.0
## 3         C         0.06                0.2            0.11     2.0
## 4         A         0.04                0.1            0.09     3.5
## 5         B         0.04                0.2            0.09     3.5
## 6         C         0.06                0.2            0.11     3.5
## 7         A         0.04                0.1            0.09     5.0
## 8         B         0.04                0.2            0.09     5.0
## 9         C         0.06                0.2            0.11     5.0
##   optimum_y
## 1 1.0000000
## 2 0.5000000
## 3 0.7500000
## 4 1.0000000
## 5 0.2857143
## 6 0.4285714
## 7 0.8000000
## 8 0.2000000
## 9 0.3000000

Once the optimum \(y\) has been found, we can determine the expected rate of return for the complete portfolio at this value, and the associated utility value.

expected.return.complete = function(risk.free.rate, expected.return, optimum.y) {
  return(risk.free.rate + optimum.y *(expected.return - risk.free.rate))
}
utility.complete = function(risk.free.rate, expected.return, optimum.y, standard.deviation, A) {
  return(expected.return.complete(risk.free.rate, expected.return, optimum.y) - 0.5 * A * standard.deviation^2 * optimum.y^2)
}
optimum.example$CP_expected_return = apply(optimum.example %>% select(-portfolio), 1, function(y) {expected.return.complete(risk.free.rate, y['expected_return'], y['optimum_y'])})
optimum.example$CP_utility= apply(optimum.example %>% select(-portfolio), 1, function(y) {utility.complete(risk.free.rate, y['expected_return'], y['optimum_y'], y['standard_deviation'], y['A_value'])})
optimum.example = optimum.example %>% mutate(CP_sd = standard_deviation * optimum_y)
optimum.example
##   portfolio risk_premium standard_deviation expected_return A_value
## 1         A         0.04                0.1            0.09     2.0
## 2         B         0.04                0.2            0.09     2.0
## 3         C         0.06                0.2            0.11     2.0
## 4         A         0.04                0.1            0.09     3.5
## 5         B         0.04                0.2            0.09     3.5
## 6         C         0.06                0.2            0.11     3.5
## 7         A         0.04                0.1            0.09     5.0
## 8         B         0.04                0.2            0.09     5.0
## 9         C         0.06                0.2            0.11     5.0
##   optimum_y CP_expected_return CP_utility      CP_sd
## 1 1.0000000         0.09000000 0.08000000 0.10000000
## 2 0.5000000         0.07000000 0.06000000 0.10000000
## 3 0.7500000         0.09500000 0.07250000 0.15000000
## 4 1.0000000         0.09000000 0.07250000 0.10000000
## 5 0.2857143         0.06142857 0.05571429 0.05714286
## 6 0.4285714         0.07571429 0.06285714 0.08571429
## 7 0.8000000         0.08200000 0.06600000 0.08000000
## 8 0.2000000         0.05800000 0.05400000 0.04000000
## 9 0.3000000         0.06800000 0.05900000 0.06000000

Focussing on the investor with \(A = 2\), look at the indifference curves corresponding to the optimum \(y\) value for each of the portfolios \(A\), \(B\), and \(C\). Plot these along with the capital allocation lines for each portfolio.

indifference.curve.data.2 = merge(data.frame(optimum_utility = c(0.08, 0.06, 0.0725)), data.frame(sd = 0:25 / 100))
indifference.curve.data.2$utility = apply(indifference.curve.data.2, 1, function(y){ indifference.curve(A = 2, sd = y['sd'], U = y['optimum_utility'])})
ggplot(data = indifference.curve.data.2, aes(x = sd, y = utility, col = as.factor(optimum_utility))) + geom_line() + geom_line(data = CAL.data.v2, aes(x = sd, y = CAL, col = portfolio)) + geom_point(data = optimum.example %>% filter(A_value == 2.0), aes(x = CP_sd, y = CP_expected_return, col = portfolio), size = 4) + labs(x = "Standard Deviation", y = "Expected Return")

In each case, the optimum complete portfolio is the one where the highest indifference curve lies tangent to the capital allocation line. Note that the higher the Sharpe ratio of the portfolio, the higher the optimum utility is.

To view the results from another perspective, focus on portfolio \(A\) and see how the results change as risk tolerance changes:

indifference.curve.data.3 = merge(optimum.example %>% filter(as.character(portfolio) == "A") %>% select(CP_utility, A_value), data.frame(sd = 0:25 / 100))
indifference.curve.data.3$utility = apply(indifference.curve.data.3, 1, function(y){ indifference.curve(A = y['A_value'], sd = y['sd'], U = y['CP_utility'])})
ggplot(data = indifference.curve.data.3, aes(x = sd, y = utility, col = as.factor(A_value))) + geom_line() + geom_line(data = CAL.data.v2 %>% filter(as.character(portfolio) == "A"), aes(x = sd, y = CAL, col = portfolio)) + geom_point(data = optimum.example %>% filter(as.character(portfolio) == "A"), aes(x = CP_sd, y = CP_expected_return, col = portfolio), size = 4) + xlim(0, 0.15) + ylim(0, 0.13)
## Warning: Removed 30 rows containing missing values (geom_path).
## Warning: Removed 10 rows containing missing values (geom_path).

For the investors with \(A = 2\) and \(A = 3.5\), the indifference curves are both tangent when \(y=1\). However, for the steeper indifference curve when \(A=5\), the point of tangency occurs for a smaller value of \(y = 0.80\). This corresponds to both a lower standard deviation and a lower return.

Passive versus active strategies

When determining the risky portfolio \(P\), a passive market strategy is one that avoids any security analysis, such as a portfolio consisting of a wide range of corporate stocks in proportion to their market value.

  • An example is the S&P 500 composite index.

  • The Capital Allocation Line associated with such an index, along with 1-month T-bills as the risk-free asset, is the Capital Market Line.

  • A key advantage of this approach is that it avoids the cost of actively managing a portfolio.

  • The free rider benefit results from many active market participants bidding up prices on undervalued assets, and driving down prices of overvalued assets, resulting in a fair price for passive market participants; in essence, a passive strategy is similar to that of the average active investor.