Skip to content

Commit

Permalink
bunch of whitespaces, debugged coverage reports
Browse files Browse the repository at this point in the history
 (when running in parallel it loses lcov information!)
  • Loading branch information
enzbus committed Sep 3, 2023
1 parent 60e1a84 commit 211f0bc
Show file tree
Hide file tree
Showing 14 changed files with 259 additions and 229 deletions.
1 change: 0 additions & 1 deletion .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ jobs:
coverage lcov
- name: Coveralls GitHub Action
if: ${{ matrix.python-version == '3.10'}} && ${{ matrix.os == 'ubuntu-latest'}}
uses: coverallsapp/github-action@v1
with:
path-to-lcov: coverage.lcov
Expand Down
79 changes: 41 additions & 38 deletions cvxportfolio/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,28 +52,29 @@ class BaseTradeConstraint(BaseConstraint):

pass


class EqualityConstraint(BaseConstraint):
"""Base class for equality constraints.
This class is not exposed to the user, each equality
constraint inherits from this and overrides the
:func:`InequalityConstraint._compile_constr_to_cvxpy` and
:func:`InequalityConstraint._rhs` methods.
We factor this code in order to streamline the
design of :class:`SoftConstraint` costs.
"""

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

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"""Cvxpy expression of the left-hand side of the constraint.
"""
raise NotImplementedError

def _rhs(self):
"""Cvxpy expression of the right-hand side of the constraint.
"""
Expand All @@ -82,25 +83,26 @@ def _rhs(self):

class InequalityConstraint(BaseConstraint):
"""Base class for inequality constraints.
This class is not exposed to the user, each inequality
constraint inherits from this and overrides the
:func:`InequalityConstraint._compile_constr_to_cvxpy` and
:func:`InequalityConstraint._rhs` methods.
We factor this code in order to streamline the
design of :class:`SoftConstraint` costs.
"""

def _compile_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile constraint to cvxpy."
return self._compile_constr_to_cvxpy(w_plus, z, w_plus_minus_w_bm) <= \
self._rhs()

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"""Cvxpy expression of the left-hand side of the constraint.
"""
raise NotImplementedError

def _rhs(self):
"""Cvxpy expression of the right-hand side of the constraint.
"""
Expand All @@ -109,27 +111,27 @@ def _rhs(self):

class CostInequalityConstraint(InequalityConstraint):
"""Linear inequality constraint applied to a cost term.
The user does not interact with this class directly,
it is returned by an expression such as `cost <= value`
where `cost` is a :class:`BaseCost` instance and `value`
is a scalar.
"""

def __init__(self, cost, value):
self.cost = cost
self.value = DataEstimator(value, compile_parameter=True)
self.value = DataEstimator(value, compile_parameter=True)

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile constraint to cvxpy."
return self.cost._compile_to_cvxpy(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

def __repr__(self):
return self.cost.__repr__() + ' <= ' + self.value.__repr__()


class BaseWeightConstraint(BaseConstraint):
"""Base class for constraints that operate on weights.
Expand Down Expand Up @@ -167,7 +169,7 @@ def _values_in_time(self, t, past_volumes, past_returns, **kwargs):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return w_plus[:-1].T @ self.market_vector

def _rhs(self):
"Compile right hand side of the constraint expression."
return 0
Expand All @@ -187,8 +189,8 @@ def __init__(self, delta):

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return .5 * cp.norm1(z[:-1])
return .5 * cp.norm1(z[:-1])

def _rhs(self):
"Compile right hand side of the constraint expression."
return self.delta.parameter
Expand Down Expand Up @@ -217,11 +219,12 @@ def _values_in_time(self, current_portfolio_value, **kwargs):

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return cp.multiply(cp.abs(z[:-1]), self.portfolio_value)
return cp.multiply(cp.abs(z[:-1]), self.portfolio_value)

def _rhs(self):
"Compile right hand side of the constraint expression."
return cp.multiply(self.volumes.parameter, self.max_participation_rate.parameter)
return cp.multiply(self.volumes.parameter, self.max_participation_rate.parameter)


class LongOnly(BaseWeightConstraint, InequalityConstraint):
"""A long only constraint.
Expand All @@ -234,7 +237,7 @@ class LongOnly(BaseWeightConstraint, InequalityConstraint):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"""Return a Cvxpy constraint."""
return -w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return 0
Expand All @@ -248,7 +251,8 @@ def __init__(self, asset, periods):
self.periods = periods

def _pre_evaluation(self, universe, backtest_times):
self.index = (universe.get_loc if hasattr(universe, 'get_loc') else universe.index)(self.asset)
self.index = (universe.get_loc if hasattr(
universe, 'get_loc') else universe.index)(self.asset)
self.low = cp.Parameter()
self.high = cp.Parameter()

Expand Down Expand Up @@ -320,11 +324,10 @@ def __init__(self):
class DollarNeutral(BaseWeightConstraint, EqualityConstraint):
"""Long-short dollar neutral strategy."""


def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return w_plus[-1]
return w_plus[-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return 1
Expand All @@ -343,7 +346,7 @@ def __init__(self, limit):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return self.limit.parameter
Expand All @@ -362,7 +365,7 @@ def __init__(self, limit):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return -w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return -self.limit.parameter
Expand Down Expand Up @@ -390,25 +393,25 @@ def _values_in_time(self, t, mpo_step, **kwargs):

class MinWeightsAtTimes(MinMaxWeightsAtTimes, InequalityConstraint):

sign = -1. # used in _values_in_time of parent class
sign = -1. # used in _values_in_time of parent class

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return -w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return -self.limit


class MaxWeightsAtTimes(MinMaxWeightsAtTimes, InequalityConstraint):

sign = 1. # used in _values_in_time of parent class
sign = 1. # used in _values_in_time of parent class

def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return self.limit
Expand Down Expand Up @@ -444,7 +447,7 @@ def __init__(self, factor_exposure, limit):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return self.factor_exposure.parameter.T @ w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return self.limit.parameter
Expand Down Expand Up @@ -480,7 +483,7 @@ def __init__(self, factor_exposure, limit):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return -self.factor_exposure.parameter.T @ w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return -self.limit.parameter
Expand Down Expand Up @@ -520,7 +523,7 @@ def __init__(self, factor_exposure, target):
def _compile_constr_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"Compile left hand side of the constraint expression."
return self.factor_exposure.parameter.T @ w_plus[:-1]

def _rhs(self):
"Compile right hand side of the constraint expression."
return self.target.parameter
18 changes: 9 additions & 9 deletions cvxportfolio/costs.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,20 +92,20 @@ 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):
or isinstance(other, int) \
or isinstance(other, pd.Series):
return CostInequalityConstraint(self, other)
return NotImplemented

def __ge__(self, other):
"""self >= other, return CostInequalityConstraint."""
return (-self).__le__(other)
Expand Down Expand Up @@ -184,23 +184,23 @@ def __repr__(self):

class SoftConstraint(BaseCost):
"""Soft constraint cost.
:param constraint: cvxportfolio constraint instance whose
violation we penalize
:type constraint: cvx.BaseConstraint
"""

def __init__(self, constraint):
self.constraint = constraint

def _compile_to_cvxpy(self, w_plus, z, w_plus_minus_w_bm):
"""Compile cost to cvxpy expression."""
try:
expr = (self.constraint._compile_constr_to_cvxpy(w_plus, z, w_plus_minus_w_bm)
- self.constraint._rhs())
except AttributeError:
raise SyntaxError(f"{self.__class__.__name__} can only be used with"
" EqualityConstraint or InequalityConstraint instances.")
" EqualityConstraint or InequalityConstraint instances.")
if isinstance(self.constraint, EqualityConstraint):
return cp.sum(cp.abs(expr))
if isinstance(self.constraint, InequalityConstraint):
Expand Down
25 changes: 13 additions & 12 deletions cvxportfolio/data.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
from .estimator import DataEstimator

__all__ = ["YfinanceTimeSeries", "FredTimeSeries",
"FredRateTimeSeries", "BASE_LOCATION"]
# "FredRateTimeSeries",
"BASE_LOCATION"]

BASE_LOCATION = Path.home() / "cvxportfolio_data"

Expand Down Expand Up @@ -491,15 +492,15 @@ def _recursive_pre_evaluation(self, *args, **kwargs):
self.data = self.update_and_load(self.symbol)


class FredRateTimeSeries(DataEstimator, FredBase, RateBase, PickleStore):

def __init__(self, symbol, use_last_available_time=False, base_location=BASE_LOCATION):
self.symbol = symbol
self.base_location = base_location
self.use_last_available_time = use_last_available_time

def _recursive_pre_evaluation(self, *args, **kwargs):
self.data = self.update_and_load(self.symbol)
# class FredRateTimeSeries(DataEstimator, FredBase, RateBase, PickleStore):
#
# def __init__(self, symbol, use_last_available_time=False, base_location=BASE_LOCATION):
# self.symbol = symbol
# self.base_location = base_location
# self.use_last_available_time = use_last_available_time
#
# def _recursive_pre_evaluation(self, *args, **kwargs):
# self.data = self.update_and_load(self.symbol)


class TimeSeries(DataEstimator):
Expand Down Expand Up @@ -545,8 +546,8 @@ def __init__(
cls.__name__ + "With" + source.__name__, (cls, source), {}
)

if isinstance(storage, str) and storage == "sqlite":
storage = SqliteDataStore
# if isinstance(storage, str) and storage == "sqlite":
# storage = SqliteDataStore
if isinstance(storage, str) and storage == "csv":
storage = LocalDataStore
if isinstance(storage, str) and storage == "pickle":
Expand Down
Loading

0 comments on commit 211f0bc

Please sign in to comment.