Acknowledgments
4.4 Linear algebra
4.4.8 Modern portfolio theory
Modern portfolio theory [34] is an investment approach that tries to max- imize return given a fixed risk. Many different metrics have been pro- posed. One of them is theSharpe ratio.
For a stock or a portfolio with an average returnrand riskσ, the Sharpe ratio is defined as
Sharpe(r,σ)≡(r−¯r)/σ (4.73) Here ¯r is the current risk-free investment rate. Usually the risk is mea- sured as the standard deviation of its daily (or monthly or yearly) return.
Consider the stock price pit of stock i at timet and its arithmetic daily returnrit = (pi,t+1−pit)/pit given a risk-free interest equal to ¯r.
For each stock, we can compute the average return and average risk (vari- ance of daily returns) and display it in a risk-return plot as we did in chapter2.
We can try to build arbitrary portfolios by investing in multiple stocks at the same time. Modern portfolio theory states that there is a maximum Sharpe ratio and there is one portfolio that corresponds to it. It is called the tangency portfolio.
A portfolio is identified by fractions of $1 invested in each stock in the portfolio. Our goal is to determine the tangent portfolio.
If we assume that daily returns for the stocks are Gaussian, then the solv- ing algorithm is simple.
All we need is to compute the average return for each stock, defined as ri =1/T
∑
t
rit (4.74)
and the covariance matrix Aij = 1
T
∑
t
(rit−ri)(rjt−rj) (4.75)
Modern portfolio theory tells us that the tangent portfolio is given by x= A−1(r−r1¯ ) (4.76) The inputs of the formula are the covariance matrix (A), a vector or arith- metic returns for the assets in the portfolio (r), the risk free rate (¯r). The output is a vector (x) whose elements are the percentages to be invested in each asset to obtain a tangency portfolio. Notice that some elements of xcan be negative and this corresponds to short position (sell, not buy, the asset).
Here is the algorithm:
Listing4.36: in file: nlib.py
1 def Markowitz(mu, A, r_free):
2 """Assess Markowitz risk/return.
3 Example:
4 >>> cov = Matrix([[0.04, 0.006,0.02],
5 ... [0.006,0.09, 0.06],
6 ... [0.02, 0.06, 0.16]])
7 >>> mu = Matrix([[0.10],[0.12],[0.15]])
8 >>> r_free = 0.05
9 >>> x, ret, risk = Markowitz(mu, cov, r_free)
10 >>> print x
11 [0.556634..., 0.275080..., 0.1682847...]
12 >>> print ret, risk
13 0.113915... 0.186747...
14 """
15 x = Matrix([[0.0]for r in xrange(A.nrows)])
16 x = (1/A)*(mu - r_free)
17 x = x/sum(x[r,0] for r in xrange(x.nrows))
18 portfolio = [x[r,0] for r in xrange(x.nrows)]
19 portfolio_return = mu*x
20 portfolio_risk = sqrt(x*(A*x))
21 returnportfolio, portfolio_return, portfolio_risk
Here is an example. We consider three assets (0,1,2) with the following covariance matrix:
1 >>> cov = Matrix([[0.04, 0.006,0.02],
2 ... [0.006,0.09, 0.06],
3 ... [0.02, 0.06, 0.16]])
and the following expected returns (arithmetic returns, not log returns, because the former are additive, whereas the latter are not):
1 >>> mu = Matrix([[0.10],[0.12],[0.15]])
Given the risk-free interest rate
1 >>> r_free = 0.05
we compute the tangent portfolio (highest Sharpe ratio), its return, and its risk with one function call:
1 >>> x, ret, risk = Markowitz(mu, cov, r_free)
2 >>> print x
3 [0.5566343042071198, 0.27508090614886727, 0.16828478964401297]
4 >>> print ret, risk
5 0.113915857605 0.186747095412
6 >>> print (ret-r_free).risk
7 0.34225891152
8 >>> for r in xrange(3): print (mu[r,0]-r_free)/sqrt(cov[r,r])
9 0.25
10 0.233333333333
11 0.25
Investing55% in asset0,27% in asset1, and16% in asset2, the resulting portfolio has an expected return of 11.39% and a risk of18.67%, which corresponds to a Sharpe ratio of 0.34, much higher than0.25,0.23, and 0.23for the individual assets.
Notice that the tangency portfolio is not the only one with the highest Sharpe ratio (return for unit of risk). In fact, any linear combination of the tangency portfolio with a risk-free asset (putting money in the bank) has the same Sharpe ratio. For any target risk, one can find a linear combination of the risk-free asset and the tangent portfolio that has a better Sharpe ratio than any other possible portfolio comprising the same assets.
If we call αthe fraction of the money to invest in the tangency portfolio and 1−αthe fraction to keep in the bank at the risk free rate, the resulting
combined portfolio has return:
αx·r+ (1−α)r¯ (4.77) and risk
α
√
xtAx (4.78)
We can determine α by deciding how much risk we are willing to take, and these formulas tell us the optimal portfolio for that amount of risk.
4.4.9 Linear least squares,χ2
Consider a set of data points(xJ,yj) = (tj,oj±doj). We want to fit them with a linear combination of linear independent functions fi so that
c0f0(t0) +c1f1(t0) +c2f2(t0) +. . .=e0'o0±do0 (4.79) c0f0(t1) +c1f1(t1) +c2f2(t1) +. . .=e1'o1±do1 (4.80) c0f0(t2) +c1f1(t2) +c2f2(t2) +. . .=e2'o2±do2 (4.81) . . .=. . . (4.82) We want to find the{ci}that minimizes the sum of the squared distances between the actual “observed” dataojand the predicted “expected” data ej, in units ofdoj. This metric is calledχ2in general [35]. An algorithm that minimizes theχ2and is linear in theci coefficients (our case here) is calledlinear least squaresorlinear regression.
χ2=
∑
j
ej−oj
doj
2
(4.83)
If we define the matrixAand Bas
A=
f0(t0) do0
f1(t0) do0
f2(t0) do0 . . .
f0(t1) do1
f1(t1) do1
f2(t1) do1 . . .
f0(t2) do2
f1(t2) do2
f2(t2) do2 . . . . . . .
b=
o0 do0
o1 do1
o2 do2
. . .
(4.84)
then the problem is reduced to
minc χ2=min
c |Ac−b|2 (4.85)
=min
c (Ac−b)t(Ac−b) (4.86)
=min
c (ctAtAx−2btAc+btb) (4.87) This is the same as solving the following equation:
∇c(ctAtAx−2ctAtb+btb) =0 (4.88) AtAc−Atb=0 (4.89) Its solution is
c= (AtA)−1(Atb) (4.90) The following algorithm implements a fitting function based on the pre- ceding procedure. It takes as input a list of functions fiand a list of points pj = (tj,oj,doj)and returns three objects—a list with theccoefficients, the value ofχ2for the best fit, and the fitting function:
Listing4.37: in file:nlib.py
1 def fit_least_squares(points, f):
2 """
3 Computes c_j for best linear fit of y[i] \pm dy[i] = fitting_f(x[i])
4 where fitting_f(x[i]) is \sum_j c_j f[j](x[i])
5
6 parameters:
7 - a list of fitting functions
8 - a list with points (x,y,dy)
9
10 returns:
11 - column vector with fitting coefficients
12 - the chi2 for the fit
13 - the fitting function as a lambda x: ....
14 """
15 def eval_fitting_function(f,c,x):
16 if len(f)==1:return c*f[0](x)
17 else: return sum(func(x)*c[i,0] for i,func in enumerate(f))
18 A = Matrix(len(points),len(f))
19 b = Matrix(len(points))
20 for i in xrange(A.nrows):
21 weight = 1.0/points[i][2] if len(points[i])>2 else 1.0
22 b[i,0] = weight*float(points[i][1])
23 for j in xrange(A.ncols):
24 A[i,j] = weight*f[j](float(points[i][0]))
25 c = (1.0/(A.T*A))*(A.T*b)
26 chi = A*c-b
27 chi2 = norm(chi,2)**2
28 fitting_f = lambdax, c=c, f=f, q=eval_fitting_function: q(f,c,x)
29 if isinstance(c,Matrix): return c.flatten(), chi2, fitting_f
30 else: return c, chi2, fitting_f
31
32 # examples of fitting functions
33 def POLYNOMIAL(n):
34 return[(lambda x, p=p: x**p) for p in xrange(n+1)]
35 CONSTANT = POLYNOMIAL(0)
36 LINEAR = POLYNOMIAL(1)
37 QUADRATIC = POLYNOMIAL(2)
38 CUBIC = POLYNOMIAL(3)
39 QUARTIC = POLYNOMIAL(4)
As an example, we can use it to perform a polynomial fit: given a set of points, we want to find the coefficients of a polynomial that best approxi- mate those points.
In other words, we want to find thecisuch that, giventjandoj,
c0+c1t10+c2t20+. . .=e0'o0±do0 (4.91) c0+c1t11+c2t21+. . .=e1'o1±do1 (4.92) c0+c1t12+c2t22+. . .=e2'o2±do2 (4.93) . . .=. . . (4.94)
Here is how we can generate some random points and solve the problem for a polynomial of degree2(or quadratic fit):
Listing4.38: in file:nlib.py
1 >>> points = [(k,5+0.8*k+0.3*k*k+math.sin(k),2) for k in xrange(100)]
2 >>> a,chi2,fitting_f = fit_least_squares(points,QUADRATIC)
3 >>> for p in points[-10:]:
4 ... printp[0], round(p[1],2), round(fitting_f(p[0]),2)
5 90 2507.89 2506.98
6 91 2562.21 2562.08
7 92 2617.02 2617.78
8 93 2673.15 2674.08
9 94 2730.75 2730.98
10 95 2789.18 2788.48
11 96 2847.58 2846.58
12 97 2905.68 2905.28
13 98 2964.03 2964.58
14 99 3023.5 3024.48
15 >>> Canvas(title='polynomial fit',xlab='t',ylab='e(t),o(t)'
16 ... ).errorbar(points[:10],legend='o(t)'
17 ... ).plot([(p[0],fitting_f(p[0])) for p in points[:10]],legend='e(t)'
18 ... ).save('images/polynomialfit.png')
Fig.4.4.9is a plot of the first10points compared with the best fit:
Figure4.4: Random data with their error bars and the polynomial best fit.
We can also define a χ2do f = χ2/(N−1) where N is the number of c parameters determined by the fit. A value of χ2do f ' 1 indicates a good fit. In general, the smaller χ2do f, the better the fit. A large value ofχ2do f is a symptom of poor modeling (the assumptions of the fit are wrong), whereas a valueχ2do f much smaller than1is a symptom of an overestimate of the errorsdoj(or perhaps manufactured data).