Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 38 additions & 0 deletions optimization/sharpe_opt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""An optimizer for Sharpe Ratio"""

import numpy as np
import scipy.optimize
# from cvxopt import solvers, matrix
# solvers.options["show_progress"] = False
# solvers.options['maxiters'] = 500


def optimize_sharpe(returns, r_f=1):
"""
Optimize the Sharpe Ratio of a portfolio,
short_sales not working yet...
"""
returns = np.asmatrix(returns)
num_stocks, _ = returns.shape
covar = np.cov(returns)
means = np.mean(returns, axis=1)

def transform_input(decision_vars):
"""Make sure the decision vars sum to 1"""
mod_vars = list(decision_vars)
mod_vars.append(1 - sum(mod_vars))
return mod_vars

def neg_sharpe(dec_vars):
"""Compute -1*sharpe_ratio"""
dec_vars = np.asmatrix(transform_input(dec_vars)).T
sharpe = (r_f - means.T * dec_vars) \
/ np.sqrt(dec_vars.T * covar * dec_vars)
return sharpe

sol = scipy.optimize.fmin(
neg_sharpe,
scipy.ones(num_stocks - 1, dtype=float) * 1. / num_stocks,
disp=False,
full_output=False)
return transform_input(sol)
20 changes: 19 additions & 1 deletion tests/test_optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import csv
from collections import defaultdict
import numpy as np
from optimization import mad, mvo, downside_var
from optimization import mad, mvo, downside_var, sharpe_opt

# Might want to consider breaking this function out

Expand Down Expand Up @@ -57,9 +57,27 @@ def smoke_test(optimizers):
assert not all(shorting_test)


def smoke_test2(optimizers):
"""A different smoke test for other models"""
rets = load_data()
gross_returns = []
for k in sorted(rets.keys()):
gross_returns.append([1.0 + i / 100 for i in rets[k]])
means = np.mean(gross_returns, axis=1)
steps = np.linspace(0.0, min(means), num=100)
for opt_model in optimizers:
allocations = [np.transpose(opt_model(gross_returns, x))
for x in steps]
shorting_test = [all([x >= -np.finfo(np.float32).eps for x in row])
for row in allocations]
assert not all(shorting_test)


def test_models():
"""Run over all the models"""
smoke_test([
mvo.optimize_mv,
mad.optimize_mad,
downside_var.optimize_downside_variance])
# Sharpe doesn't support turning on and off short sales
smoke_test2([sharpe_opt.optimize_sharpe])