A key goal in finance is maximizing return on your money while minimizing your risk. There are trade-offs between risk and return, but for a set risk it's always better to have a higher return, and for a set return it's always better to have lower risk.

A basic approach to optimizing the risk and return of a portfolio is to maximize its *Sharpe ratio*, which is the ratio of its expected return to its standard deviation. Standard deviation is a measure of how much you can expect the portfolio to go up or down, so the Sharpe ratio measures how much money you're expecting to make for each dollar you're risking. In theory, you can always borrow money at some interest rate, so it's best to make the investment with the highest Sharpe ratio. That way you can maximize the amount you're expecting to make without risking more than you're comfortable with.

One way to reduce risk is diversification, or splitting your investment between stocks that don't go up and down together. For example, let's say we have a portfolio of two stocks, each with 10% expected return and 15% standard deviation. The return of the portfolio is also 10%, since that's what we expect to make on each part. Its standard deviation, however, depends not only on the risk of each stock, but also how the stocks move together.

If these stocks are perfectly correlated (they move together exactly), our standard deviation is still 15%. (In this case, we haven't diversified our risk at all.) If they're perfectly uncorrelated (they move randomly with respect to each other), our standard deviation drops to 10.6%. And if they have perfect negative correlation (they move in opposite directions), we'll have no risk at all, guaranteeing a profit of 10%. In this case you should invest as much money as you can possibly borrow for less than 10% - at least in theory.

In real life, the correlation between stocks isn't known, but is something we need to figure out. One way to do this is to look at past returns and come up with the historical correlation. With DataNitro, we can use Python and Excel to get historical data, compute the correlations between the stocks in a portfolio, and automatically balance it for an optimal Sharpe ratio. (Follow along with the example script and spreadsheet here, or on github. You'll need DataNitro, SciPy and ystockquote.py installed.)

We want to input the stocks we have in our portfolio, their expected returns, and the rate we can borrow money at (called the risk-free interest rate). [Calculating the expected return of a stock is the subject of another blog post, as well as much of modern finance.]

As output, we want a portfolio with the highest possible Sharpe ratio. It's also nice to see the correlation matrix between all the stocks. We can compute both of these with SciPy.

First, we need to get the historical stock data. In this case, we're getting it from Yahoo finance using the ystockquote library. After reading in the stock tickers in the portfolio and deciding on a date range (I'm using 10 years of data), here's how to pull the closing prices from yahoo:

1 2 3 4 5 6 7 8 9 10 | ```
data = []
which_price = {'Open': 1, 'High': 2, 'Low': 3, 'Close': 4, 'Adjusted Close': 6}
for ticker in tickers:
prices = get_historical_prices(ticker, start_date, end_date)
prices.reverse() # time series order
prices.pop() # remove header
f = lambda x: float(x[which_price['Close']])
prices = map((lambda x: f(x)), prices) # just closing prices
data.append(prices)
``` |

Getting the data is the hardest part of this program - SciPy takes care of the calculations for us. Here's how we get the correlation matrix:

1 2 | ```
x = scipy.array(data)
cor = scipy.corrcoef(x)
``` |

Next, we want to find a portfolio with the optimal Sharpe ratio. SciPy can do this too - first, we write a function that returns the Sharpe ratio of a portfolio, and it'll maximize it for us.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | ```
def sharpe_ratio(weights):
'''Returns the sharpe ratio of the portfolio with weights.'''
var = portfolio_variance(weights)
returns = scipy.array(exp_return)
return (scipy.dot(weights, returns) - r)/sqrt(var)
def portfolio_variance(a):
'''Returns the variance of the portfolio with weights a.'''
var = 0.0
# to speed up sum covariance over i < j and variance over i
for i in xrange(L):
for j in xrange(L):
var += a[i]*a[j]*std_dev[i]*std_dev[j]*cor[i, j]
if var <= 0: # floating point errors for very low variance
return 10**(-6)
return var
``` |

(Actually, SciPy has a minimizer, so we need a function that returns the negative of the Sharpe ratio, and SciPy will minimize it. Oh well, what can you do.)

1 2 3 4 5 6 7 8 9 10 | ```
def sharpe_optimizer(weights):
# for optimization - computes last weight and returns negative of sharpe
# ratio (for minimizer to work)
weights = scipy.append(weights, 1 - sum(weights)) # sum of weights = 1
return - sharpe_ratio(weights)
guess = scipy.ones(L - 1, dtype=float) * 1.0 / L
optimizer = fmin(sharpe_optimizer, guess)
optimal_weights = scipy.append(optimizer, 1 - sum(optimizer))
optimal_val = sharpe_ratio(optimal_weights)
``` |

Here's the result - an optimally balanced portfolio, along with its Sharpe ratio and correlation matrix.