Skip to content

Commit

Permalink
implementation of cost constraints: cvx.FullCovariance() <= value
Browse files Browse the repository at this point in the history
  • Loading branch information
enzbus committed Sep 3, 2023
1 parent 75e19af commit 65438e4
Show file tree
Hide file tree
Showing 4 changed files with 42 additions and 5 deletions.
11 changes: 7 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,20 @@ ifeq ($(OS), Windows_NT)
BINDIR=$(ENVDIR)/Scripts
endif

.PHONY: env docs clean test cleanenv
.PHONY: env docs clean pytest test releasetest cleanenv

env:
$(PYTHON) -m venv $(ENVDIR)
$(BINDIR)/python -m pip install --editable .
$(BINDIR)/python -m pip install -r requirements.txt

test:
$(BINDIR)/python -m unittest $(PROJECT)/tests/*.py

pytest:
$(BINDIR)/pytest $(PROJECT)/tests/*.py

hardtest: cleanenv env test
releasetest: cleanenv env pytest

test8:
flake8 --per-file-ignores='$(PROJECT)/__init__.py:F401,F403' $(PROJECT)/*.py
Expand All @@ -37,7 +40,7 @@ pep8:
# use autopep8 to make innocuous fixes
$(BINDIR)/autopep8 -i $(PROJECT)/*.py $(PROJECT)/tests/*.py

release: hardtest
release: releasetest
$(BINDIR)/python bumpversion.py
git push
$(BINDIR)/python -m build
Expand Down
2 changes: 1 addition & 1 deletion cvxportfolio/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def __init__(self, cost, value):

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile constraint to cvxpy."
return self.cost(w_plus, z, w_plus_minus_w_bm)
return self.cost._compile_to_cvxpy(w_plus, z, w_plus_minus_w_bm)

def _rhs(self):
return self.value.parameter
Expand Down
16 changes: 16 additions & 0 deletions cvxportfolio/costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,22 @@ def __sub__(self, other):
def __rsub__(self, other):
"""Subtract from other cost."""
return other.__add__(-self)

def __le__(self, other):
"""self <= other, return CostInequalityConstraint.
For now we check here the type of "other"
but it would be nicer to have CostInequalityConstraint's
internal DataEstimator throw NotImplemented instead.
"""
if isinstance(other, float) \
or isinstance(other, int) \
or isinstance(other, pd.Series):
return CostInequalityConstraint(self, other)

def __ge__(self, other):
"""self >= other, return CostInequalityConstraint."""
return (-self).__le__(other)


class CombinedCosts(BaseCost):
Expand Down
18 changes: 18 additions & 0 deletions cvxportfolio/tests/test_simulator.py
Original file line number Diff line number Diff line change
Expand Up @@ -714,6 +714,24 @@ def test_ineq_soft_constraints(self):
self.assertTrue(allshorts[0] < allshorts[1])
self.assertTrue(allshorts[1] < allshorts[2])
self.assertTrue(allshorts[2] < allshorts[3])

def test_cost_constraints(self):
"We check that cost constraints work as expected."

sim = cvx.StockMarketSimulator(
['AAPL', 'MSFT', 'GE', 'ZM', 'META'], trading_frequency='monthly', base_location=self.datadir)

policies = [
cvx.SinglePeriodOptimization(cvx.ReturnsForecast(), [cvx.FullCovariance() <= el**2])
for el in [0.01, .02, .05, .1]]

results = sim.backtest_many(policies, start_time='2023-01-01')
print(results)

self.assertTrue(results[0].volatility < results[1].volatility)
self.assertTrue(results[1].volatility < results[2].volatility)
self.assertTrue(results[2].volatility < results[3].volatility)



if __name__ == '__main__':
Expand Down

0 comments on commit 65438e4

Please sign in to comment.