Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FactorMaxLimit error #21

Closed
marketneutral opened this issue Aug 26, 2018 · 2 comments
Closed

FactorMaxLimit error #21

marketneutral opened this issue Aug 26, 2018 · 2 comments

Comments

@marketneutral
Copy link

marketneutral commented Aug 26, 2018

I am getting an exception when trying to use FactorMaxLimit and FactorMinLimit.

This is the minimal reproducible code:

import numpy as np
import pandas as pd
import cvxportfolio as cp

np.random.seed(100)

# spoof a factor loadings matrix with 100 stocks and 6 factors (e.g., think sectors)
factor_loadings = pd.get_dummies(pd.Series(np.random.randint(0,6,100)))

# create the expected returns DataFrame
r_hat_s = pd.Series(np.random.random(100))
r_hat_s.T['USDOLLAR']=0
r_hat = pd.DataFrame(r_hat_s, columns=[pd.Timestamp('2017-01-03')]).T

# create the prices DataFrame
prices_s = pd.Series(np.random.randint(20, 75, 100))
prices_noUSD = pd.DataFrame(prices_s, columns=[pd.Timestamp('2017-01-03')]).T
prices_s.T['USDOLLAR']=1.0
prices = pd.DataFrame(prices_s, columns=[pd.Timestamp('2017-01-03')]).T

# set up the optimization policy
spo_policy = cp.SinglePeriodOpt(
    return_forecast=r_hat,
    costs=[],
    constraints=[
        cp.LeverageLimit(1),
        cp.constraints.DollarNeutral(),
        cp.constraints.MaxWeights(0.10),
        cp.constraints.MinWeights(-0.10),
        cp.FactorMaxLimit(factor_loadings, 0.2),
        cp.FactorMinLimit(factor_loadings, -0.2)        
    ]
)

# setup empty starting portfolio
current_portfolio = pd.Series(index=r_hat.columns, data=0)
current_portfolio.USDOLLAR=100000

# run the single period optimization
shares_to_trade = spo_policy.get_rounded_trades(
    current_portfolio,
    prices,
    t=pd.Timestamp('2017-01-04')
)

If I eliminate the lines

        cp.FactorMaxLimit(factor_loadings, 0.2),
        cp.FactorMinLimit(factor_loadings, -0.2) 

then the code runs fine and produces the optimal trade list.

With the FactorMaxLimit, I get the following exception:

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-4-542a0a7449e6> in <module>()
     36     current_portfolio,
     37     prices,
---> 38     t=pd.Timestamp('2017-01-04')
     39 )

/Users/jonathan/devwork/cvxportfolio/cvxportfolio/policies.pyc in get_rounded_trades(self, portfolio, prices, t)
     52         """Get trades vector as number of shares, rounded to integers."""
     53         return np.round(self.get_trades(portfolio,
---> 54                                         t) / time_locator(prices, t))[:-1]
     55 
     56 

/Users/jonathan/devwork/cvxportfolio/cvxportfolio/policies.pyc in get_trades(self, portfolio, t)
    269 
    270         constraints += [item for item in (con.weight_expr(t, wplus, z, value)
--> 271                                           for con in self.constraints)]
    272 
    273         for el in costs:

/Users/jonathan/devwork/cvxportfolio/cvxportfolio/policies.pyc in <genexpr>((con,))
    269 
    270         constraints += [item for item in (con.weight_expr(t, wplus, z, value)
--> 271                                           for con in self.constraints)]
    272 
    273         for el in costs:

/Users/jonathan/devwork/cvxportfolio/cvxportfolio/constraints.py in weight_expr(self, t, w_plus, z, v)
     46         if w_plus is None:
     47             return self._weight_expr(t, None, z, v)
---> 48         return self._weight_expr(t, w_plus - self.w_bench, z, v)
     49 
     50     @abstractmethod

/Users/jonathan/devwork/cvxportfolio/cvxportfolio/constraints.py in _weight_expr(self, t, w_plus, z, v)
    224         """
    225         #import pdb; pdb.set_trace()
--> 226         if isinstance(self.limit, pd.Series):
    227             limit = self.limit.loc[t]
    228         else:

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/ops.pyc in f(self, other, axis, level, fill_value)
   1265                 self = self.fillna(fill_value)
   1266 
-> 1267             return self._combine_const(other, na_op)
   1268 
   1269     f.__name__ = name

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/frame.pyc in _combine_const(self, other, func, errors, try_cast)
   3985         new_data = self._data.eval(func=func, other=other,
   3986                                    errors=errors,
-> 3987                                    try_cast=try_cast)
   3988         return self._constructor(new_data)
   3989 

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/internals.pyc in eval(self, **kwargs)
   3433 
   3434     def eval(self, **kwargs):
-> 3435         return self.apply('eval', **kwargs)
   3436 
   3437     def quantile(self, **kwargs):

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/internals.pyc in apply(self, f, axes, filter, do_integrity_check, consolidate, **kwargs)
   3327 
   3328             kwargs['mgr'] = self
-> 3329             applied = getattr(b, f)(**kwargs)
   3330             result_blocks = _extend_blocks(applied, result_blocks)
   3331 

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/internals.pyc in eval(self, func, other, errors, try_cast, mgr)
   1321             return block.eval(func, orig_other,
   1322                               errors=errors,
-> 1323                               try_cast=try_cast, mgr=mgr)
   1324 
   1325         # get the result, may need to transpose the other

/anaconda3/envs/py27/lib/python2.7/site-packages/pandas/core/internals.pyc in eval(self, func, other, errors, try_cast, mgr)
   1396 
   1397                 raise TypeError('Could not compare [%s] with block values' %
-> 1398                                 repr(other))
   1399 
   1400         # transpose if needed

TypeError: Could not compare [Expression(AFFINE, UNKNOWN, (100,))] with block values

This is failing on this line in constraints.py:

self.factor_exposure.T * w_plus[:-1] <= limit

I've tried to debug with no success. Any ideas on this?

Lastly, thank you for a great package!

@weiyialanchen

@wec7
Copy link
Contributor

wec7 commented Aug 26, 2018

@marketneutral

If you change those two lines in this way, you will be good (i.e. the first argument is np.array instead of pd.DataFrame) -

        cp.FactorMaxLimit(factor_loadings.values, 0.2),
        cp.FactorMinLimit(factor_loadings.values, -0.2)

Apologies for the inconvenience.

@marketneutral
Copy link
Author

Thanks @weiyialanchen for coming back so quickly. Yes, that did the trick! Fantastic.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants