Frictions and Constraints





Kerry Back

Different borrowing and saving rates

  • \(r_s=\) saving rate, \(r_b=\) borrowing rate,
  • \(x_s \ge 0\) is fraction saved, \(x_b \ge 0\) is fraction borrowed
  • choose \((x_s, x_b, w_1, \ldots, w_n)\)
  • variance = \(w^\top C w\) where \(w=(w_1, \ldots, w_n)\)
  • expected return = \(x_s r_s - x_b r_b + \bar{r}^\top w\)
  • accounting identity is \(x_b = x_s + \sum w_i - 1\)

Position constraints

  • There are various reasons to impose ex-ante constraints (like \(\ge 0\) or \(\le 1\)) on portfolio weights.
  • The inputs are not 100% trustworthy, so we may want to over-ride extreme allocations.
  • We may not want to choose or recommend a long-term short position in a major asset class.
  • Or, we may think we should have at least some minimum investment in some asset classes.
  • And there are costs to short selling.

Margin constraints

  • The Fed Reg T limits position sizes as \(\sum |w_i| \le 2\).
  • If allowing \(w_i<0\), then instead of choosing \(w_i\),
    • choose \(w_i^+ \ge 0\) and \(w_i^-\ge 0\)
    • and set \(w_i = w_i^+ - w_i^-\)
  • Fed Reg T is

\[\sum_{i=1}^n w_i^+ + \sum_{i=1}^n w_i^- \le 2\]

  • Set \(w^+ = (w_1^+, \ldots, w_n^+)\) and \(w^- = (w_1^-, \ldots, w_n^-)\) as column vectors.
  • Set \(\hat{w} = (w^+, w^-)\) as \(2n\) column vector. Choice vector is \((x_s, x_b, \hat{w})\).
  • \(I_n =\) identity matrix, \(D = (I_n, -I_n)\) as \(n \times 2n\) matrix

\[w= I_n w^+ - I_n w^- =\begin{pmatrix} I_n & - I_n \end{pmatrix} \begin{pmatrix} w^+ \\ w^- \end{pmatrix} = D\hat{w}\]

  • Variance= \(\hat{w}^\top D^\top C D \hat{w}\). Expected return = \(r_sx_x - r_bx_b + \bar{r}^\top D \hat{w}\). Accounting identity is \(x_s - x_b + 1_n'D\hat{w} = 1\).

Example

  • Find optimal portfolio for given risk aversion
  • Different borrowing and saving rates
  • No short sales

  • minimize

\[(1/2) \times \text{raver} \times w^\top C w - r_s x_s + r_b x_b - \bar r^\top w\]

  • subject to \(x_s \ge 0\), \(x_b \ge 0\), \(w \ge 0\)
  • and \(x_s - x_b + 1_n^\top w = 1\)

Set-up

import numpy as np
rs = 0.02
rb = 0.05

mn1, mn2 = 0.05, 0.1
sd1, sd2 = 0.1, 0.1
corr = 0.9
raver = 2

R = np.identity(2)
R[0, 1] = R[1, 0] = corr
S = np.diag([sd1, sd2])
C = S @ R @ S

Define cvxopt arrays

P = np.zeros((4, 4))
P[2:,2:] = raver*C
q = [-rs, rb, -mn1, -mn2]
G = -np.identity(4)
h = np.zeros(4)
A = [1., -1., 1., 1.]
b = [1.]

convert to cvxopt matrices and solve

from cvxopt import matrix
from cvxopt.solvers import qp

P = matrix(P, (4, 4))
q = matrix(q, (4, 1))
G = matrix(G, (4, 4))
h = matrix(h, (4, 1))
A = matrix(A, (1, 4))
b = matrix(b, (1, 1))

sol = qp(P=P, q=q, G=G, h=h, A=A, b=b)
print(sol["x"])
     pcost       dcost       gap    pres   dres
 0: -5.5226e-02 -4.4750e-01  6e+00  3e+00  3e+00
 1: -4.5212e-02 -7.9829e-01  9e-01  3e-01  3e-01
 2: -5.0337e-02 -1.3104e-01  8e-02  2e-02  2e-02
 3: -1.0537e-01 -1.2652e-01  2e-02  2e-04  3e-04
 4: -1.1243e-01 -1.1304e-01  6e-04  4e-06  4e-06
 5: -1.1250e-01 -1.1251e-01  6e-06  4e-08  4e-08
 6: -1.1250e-01 -1.1250e-01  6e-08  4e-10  4e-10
Optimal solution found.
[ 2.01e-07]
[ 1.50e+00]
[ 2.69e-08]
[ 2.50e+00]