cvxgrp / cvxportfolio

Portfolio optimization and back-testing.
https://www.cvxportfolio.com
GNU General Public License v3.0
955 stars 249 forks source link

Failure on non-numeric (object dtpye) user-provided data difficult to understand #134

Closed pcgm-team closed 7 months ago

pcgm-team commented 7 months ago

To test the behavior, I'm doing a simple dummy test with manual data. However, I fail to get the backtest to run and do not understand the error report.

The code is:

prices = pd.DataFrame(index = [pd.Timestamp('2021-01-01', tz = 'utc'), pd.Timestamp('2021-01-02', tz = 'utc'), pd.Timestamp('2021-01-03', tz = 'utc')], columns = ['STOCK1', 'STOCK2', 'USDOLLAR'])
volume = pd.DataFrame(index = [pd.Timestamp('2021-01-01', tz = 'utc'), pd.Timestamp('2021-01-02', tz = 'utc'), pd.Timestamp('2021-01-03', tz = 'utc'), pd.Timestamp('2021-01-04', tz = 'utc'), pd.Timestamp('2021-01-05', tz = 'utc'), pd.Timestamp('2021-01-06', tz = 'utc'), pd.Timestamp('2021-01-07', tz = 'utc')], columns = ['STOCK1', 'STOCK2'])
prices.loc[pd.Timestamp('2021-01-01', tz = 'utc'), 'STOCK1'] = 100
prices.loc[pd.Timestamp('2021-01-02', tz = 'utc'), 'STOCK1'] = 10
prices.loc[pd.Timestamp('2021-01-03', tz = 'utc'), 'STOCK1'] = 100
prices.loc[pd.Timestamp('2021-01-04', tz = 'utc'), 'STOCK1'] = 10
prices.loc[pd.Timestamp('2021-01-05', tz = 'utc'), 'STOCK1'] = 100
prices.loc[pd.Timestamp('2021-01-06', tz = 'utc'), 'STOCK1'] = 101
prices.loc[pd.Timestamp('2021-01-07', tz = 'utc'), 'STOCK1'] = 100

prices.loc[pd.Timestamp('2021-01-01', tz = 'utc'), 'STOCK2'] = 10
prices.loc[pd.Timestamp('2021-01-02', tz = 'utc'), 'STOCK2'] = 100
prices.loc[pd.Timestamp('2021-01-03', tz = 'utc'), 'STOCK2'] = 10
prices.loc[pd.Timestamp('2021-01-04', tz = 'utc'), 'STOCK2'] = 100
prices.loc[pd.Timestamp('2021-01-05', tz = 'utc'), 'STOCK2'] = 10
prices.loc[pd.Timestamp('2021-01-06', tz = 'utc'), 'STOCK2'] = 100
prices.loc[pd.Timestamp('2021-01-07', tz = 'utc'), 'STOCK2'] = 101

prices.loc[pd.Timestamp('2021-01-01', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-02', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-03', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-04', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-05', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-06', tz = 'utc'), 'USDOLLAR'] = 1
prices.loc[pd.Timestamp('2021-01-07', tz = 'utc'), 'USDOLLAR'] = 1

# using constant large volume bc we don't really care about this for dummy test
volume['STOCK1'] = 1_000_000
volume['STOCK2'] = 1_000_000
returns = prices.pct_change(fill_method=None).dropna()
prices = prices.drop(['USDOLLAR'], axis =1)

r_hat = returns.copy()
ret_forecast1 = cvx.ReturnsForecast(r_hat = r_hat)

def make_policy_single(ret_forecast1, leverage_limit = 1):
    return  cvx.SinglePeriodOptimization(
        objective = 
        ret_forecast1,

        constraints= [cvx.LeverageLimit(leverage_limit)],

        solver='ECOS', ignore_dpp=True, include_cash_return= True)

policy = make_policy_single(ret_forecast1)

sim = cvx.MarketSimulator(returns = returns, volumes = volume, prices = prices, cash_key= 'USDOLLAR',
                                   min_history=pd.Timedelta('1d'))

bt_result = sim.backtest(policy, initial_value = 1_500_000, start_time = pd.Timestamp('2021-01-02', tz = 'utc'), end_time=pd.Timestamp('2021-01-07', tz = 'utc'))

And the full error message is:

TypeError                                 Traceback (most recent call last)
Cell In[237], [line 18](vscode-notebook-cell:?execution_count=237&line=18)
     [13](vscode-notebook-cell:?execution_count=237&line=13) policy = make_policy_single(ret_forecast1)
     [15](vscode-notebook-cell:?execution_count=237&line=15) sim = cvx.MarketSimulator(returns = returns, volumes = volume, prices = prices, cash_key= 'USDOLLAR',
     [16](vscode-notebook-cell:?execution_count=237&line=16)                                    min_history=pd.Timedelta('1d'))
---> [18](vscode-notebook-cell:?execution_count=237&line=18) bt_result = sim.backtest(policy, initial_value = 1_500_000, start_time = pd.Timestamp('2021-01-02', tz = 'utc'), end_time=pd.Timestamp('2021-01-07', tz = 'utc'))

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\simulator.py:573](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:573), in MarketSimulator.backtest(self, policy, start_time, end_time, initial_value, h)
    [544](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:544) def backtest(
    [545](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:545)         self, policy, start_time=None, end_time=None, initial_value=1E6,
    [546](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:546)         h=None):
    [547](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:547)     """Back-test a trading policy.
    [548](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:548) 
    [549](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:549)     The default initial portfolio is all cash, or you can pass any
   (...)
    [571](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:571)     :rtype: :class:`cvxportfolio.BacktestResult`
    [572](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:572)     """
--> [573](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:573)     return self.backtest_many(
    [574](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:574)         [policy], start_time=start_time, end_time=end_time,
    [575](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:575)         initial_value=initial_value, h=None if h is None else [h],
    [576](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:576)         parallel=False)[0]

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\simulator.py:683](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:683), in MarketSimulator.backtest_many(self, policies, start_time, end_time, initial_value, h, parallel)
    [679](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:679) zip_args = zip(policies, [self] * n,
    [680](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:680)                [start_time] * n, [end_time] * n, h)
    [682](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:682) if (not parallel) or len(policies) == 1:
--> [683](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:683)     result = list(starmap(self._worker, zip_args))
    [684](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:684) else:
    [685](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:685)     with Pool(initializer=_mp_init, initargs=(Lock(),)) as p:

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\simulator.py:436](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:436), in MarketSimulator._worker(policy, simulator, start_time, end_time, h)
    [434](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:434) @staticmethod
    [435](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:435) def _worker(policy, simulator, start_time, end_time, h):
--> [436](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:436)     return simulator._backtest(policy, start_time, end_time, h)

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\simulator.py:344](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:344), in MarketSimulator._backtest(self, policy, start_time, end_time, h)
    [339](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:339)     h = self._adjust_h_new_universe(h, current_universe)
    [340](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:340)     used_policy = self._get_initialized_policy(
    [341](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:341)         policy, universe=current_universe,
    [342](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:342)         trading_calendar=trading_calendar[trading_calendar >= t])
--> [344](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:344) h_next, z, u, realized_costs, policy_time = self.simulate(
    [345](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:345)     t=t, h=h, policy=used_policy,
    [346](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:346)     t_next=t_next,
    [347](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:347)     past_returns=past_returns,
    [348](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:348)     current_returns=current_returns,
    [349](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:349)     past_volumes=past_volumes,
    [350](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:350)     current_volumes=current_volumes,
    [351](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:351)     current_prices=current_prices)
    [353](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:353) if hasattr(used_policy, 'benchmark'):
    [354](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:354)     w_bm = used_policy.benchmark.current_value

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\simulator.py:210](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:210), in MarketSimulator.simulate(self, t, t_next, h, policy, past_returns, current_returns, past_volumes, current_volumes, current_prices)
    [208](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:208) s = time.time()
    [209](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:209) logger.info('Evaluating the policy at time %s', t)
--> [210](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:210) policy_w = policy.values_in_time_recursive(
    [211](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:211)     t=t, current_weights=current_weights,
    [212](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:212)     current_portfolio_value=current_portfolio_value,
    [213](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:213)     past_returns=past_returns, past_volumes=past_volumes,
    [214](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:214)     current_prices=current_prices)
    [216](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:216) z = policy_w - current_weights
    [218](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/simulator.py:218) policy_time = time.time() - s

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\policies.py:793](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:793), in MultiPeriodOptimization.values_in_time_recursive(self, t, current_weights, current_portfolio_value, **kwargs)
    [790](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:790) assert np.isclose(sum(current_weights), 1)
    [792](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:792) for i, obj in enumerate(self.objective):
--> [793](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:793)     obj.values_in_time_recursive(
    [794](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:794)         t=t, current_weights=current_weights,
    [795](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:795)         current_portfolio_value=current_portfolio_value,
    [796](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:796)         mpo_step=i, cache=self._cache,
    [797](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:797)         **kwargs)
    [799](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:799) for i, constr_at_lag in enumerate(self.constraints):
    [800](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/policies.py:800)     for constr in constr_at_lag:

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\costs.py:181](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:181), in CombinedCosts.values_in_time_recursive(self, **kwargs)
    [175](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:175) """Evaluate estimators by iterating over constituent costs.
    [176](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:176) 
    [177](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:177) :param kwargs: All parameters passed to :meth:`values_in_time`.
    [178](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:178) :type kwargs: dict
    [179](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:179) """
    [180](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:180) for el in self.costs:
--> [181](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/costs.py:181)     el.values_in_time_recursive(**kwargs)

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\estimator.py:183](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:183), in Estimator.values_in_time_recursive(self, **kwargs)
    [181](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:181) for _, subestimator in self.__dict__.items():
    [182](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:182)     if hasattr(subestimator, "values_in_time_recursive"):
--> [183](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:183)         subestimator.values_in_time_recursive(**kwargs)
    [184](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:184) if hasattr(self, "values_in_time"):
    [185](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:185)     # pylint: disable=assignment-from-no-return
    [186](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:186)     self._current_value = self.values_in_time(**kwargs)

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\estimator.py:186](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:186), in Estimator.values_in_time_recursive(self, **kwargs)
    [183](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:183)         subestimator.values_in_time_recursive(**kwargs)
    [184](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:184) if hasattr(self, "values_in_time"):
    [185](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:185)     # pylint: disable=assignment-from-no-return
--> [186](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:186)     self._current_value = self.values_in_time(**kwargs)
    [187](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:187)     return self.current_value
    [188](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:188) return None

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\estimator.py:508](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:508), in DataEstimator.values_in_time(self, **kwargs)
    [495](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:495) """Obtain value of `self.data` at time t or right before.
    [496](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:496) 
    [497](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:497) :param kwargs: All parameters passed to :meth:`values_in_time`.
   (...)
    [505](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:505) :rtype: int, float, numpy.ndarray
    [506](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:506) """
    [507](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:507) try:
--> [508](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:508)     result = self._internal_values_in_time(**kwargs)
    [509](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:509) except NaNError as exc:
    [510](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:510)     raise NaNError(f"{self.__class__.__name__} found NaNs"
    [511](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:511)         + f" at time {kwargs['t']}.") from exc

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\estimator.py:476](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:476), in DataEstimator._internal_values_in_time(self, t, **kwargs)
    [473](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:473)     else:
    [474](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:474)         tmp = self.data.loc[t]
--> [476](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:476)     return self.value_checker(self._universe_subselect(tmp))
    [478](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:478) except (KeyError, IndexError) as exc:
    [479](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:479)     raise MissingTimesError(
    [480](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:480)         "%s.values_in_time_recursive could not find data"
    [481](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:481)         + " for time %s. This could be due to wrong timezone"
    [482](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:482)         + " setting: in general Cvxportfolio objects are timezone"
    [483](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:483)         + " aware, the data you pass should be as well.",
    [484](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:484)          self, t) from exc

File [c:\Users\Passage11\anaconda3\envs\ENVISAGE\Lib\site-packages\cvxportfolio\estimator.py:366](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:366), in DataEstimator.value_checker(self, result)
    [363](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:363)     return result
    [365](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:365) if isinstance(result, np.ndarray):
--> [366](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:366)     if np.any(np.isnan(result)) and not self._allow_nans:
    [367](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:367)         message = f"{self.__class__.__name__}.values_in_time_recursive"
    [368](file:///C:/Users/Passage11/anaconda3/envs/ENVISAGE/Lib/site-packages/cvxportfolio/estimator.py:368)         message += " result is an array with np.nan's."

TypeError: ufunc 'isnan' not supported for the input types, and the inputs could not be safely coerced to any supported types according to the casting rule ''safe''
pcgm-team commented 7 months ago

Could there be a simple minimal manual data test like this included in the examples and some insight into the failure?

enzbus commented 7 months ago

Please refrain from posting unless you found a bug in Cvxportfolio.Thanks.

pcgm-team commented 7 months ago

I believe this is a bug though? It's the simplest possible test I could come up with.

enzbus commented 7 months ago

This should fix your "dummy" code

returns = returns.astype(float)
volume = volume.astype(float)
prices = prices.astype(float)

But what's the point? The default examples use Yahoo Finance (which vendors ICE data) and they all work. I'm happy to review PRs of data interfaces to other data vendors, so that the user gets the same experience. The only reason I'm not doing it myself is that I don't think it's needed. And, for user-provided data, the old examples (e.g., the one on data provision , should get you started.

pcgm-team commented 7 months ago

Apologies, I wrongly assumed it was a more subtle issue. Thanks.

enzbus commented 7 months ago

Amend DataEstimator and UserProvidedMarketData, if dtypes not numeric coerce to float, if failure throw ValueError. Otherwise exception is thrown deep in the data checks and failure is difficult to understand.