santoshlite / Empyrial

An Open Source Portfolio Backtesting Engine for Everyone | 面向所有人的开源投资组合回测引擎
https://empyrial.gitbook.io/empyrial/
MIT License
914 stars 124 forks source link

TypeError is thrown when executing the first example snippet #75

Closed georgandreasjaksch closed 1 year ago

georgandreasjaksch commented 1 year ago

Describe the bug When I execute the frist example snippet an error is thrown: TypeError: Cannot join tz-naive with tz-aware DatetimeIndex

To Reproduce Steps to reproduce the behavior: Execute:

from empyrial import empyrial, Engine

portfolio = Engine(
    start_date = "2022-09-01", 
    portfolio = ["BABA", "PDD", "KO", "AMD","^IXIC"], 
    weights = [0.2, 0.2, 0.2, 0.2, 0.2],  # equal weighting is set by default
    benchmark = ["SPY"]  # SPY is set by default
)

empyrial(portfolio)

Desktop (please complete the following information):

Additional context

---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
Cell In [2], line 10
      1 from empyrial import empyrial, Engine
      3 portfolio = Engine(
      4     start_date = "2022-09-01", 
      5     portfolio = ["BABA", "PDD", "KO", "AMD","^IXIC"], 
      6     weights = [0.2, 0.2, 0.2, 0.2, 0.2],  # equal weighting is set by default
      7     benchmark = ["SPY"]  # SPY is set by default
      8 )
---> 10 empyrial(portfolio)

File ~/.local/lib/python3.10/site-packages/empyrial.py:359, in empyrial(my_portfolio, rf, sigma_value, confidence_value)
    356 VAR = np.round(VAR, decimals=2)
    357 VAR = str(VAR * 100) + " %"
--> 359 alpha, beta = alpha_beta(returns, benchmark, risk_free=rf)
    360 AL = round(alpha, 2)
    361 BTA = round(beta, 2)

File ~/.local/lib/python3.10/site-packages/empyrical/stats.py:1046, in alpha_beta(returns, factor_returns, risk_free, period, annualization, out)
   1004 def alpha_beta(returns,
   1005                factor_returns,
   1006                risk_free=0.0,
   1007                period=DAILY,
   1008                annualization=None,
   1009                out=None):
   1010     """Calculates annualized alpha and beta.
   1011 
   1012     Parameters
   (...)
   1044     beta : float
   1045     """
-> 1046     returns, factor_returns = _aligned_series(returns, factor_returns)
   1048     return alpha_beta_aligned(
   1049         returns,
   1050         factor_returns,
   (...)
   1054         out=out,
   1055     )

File ~/.local/lib/python3.10/site-packages/empyrical/stats.py:1000, in _aligned_series(*many_series)
    995     return many_series
    997 # dataframe has no ``itervalues``
    998 return (
    999     v
-> 1000     for _, v in iteritems(pd.concat(map(_to_pandas, many_series), axis=1))
   1001 )

File ~/.local/lib/python3.10/site-packages/pandas/util/_decorators.py:317, in deprecate_nonkeyword_arguments.<locals>.decorate.<locals>.wrapper(*args, **kwargs)
    311 if len(args) > num_allow_args:
    312     warnings.warn(
    313         msg.format(arguments=arguments),
    314         FutureWarning,
    315         stacklevel=find_stack_level(inspect.currentframe()),
    316     )
--> 317 return func(*args, **kwargs)

File ~/.local/lib/python3.10/site-packages/pandas/core/reshape/concat.py:369, in concat(objs, axis, join, ignore_index, keys, levels, names, verify_integrity, sort, copy)
    147 @deprecate_nonkeyword_arguments(version=None, allowed_args=["objs"])
    148 def concat(
    149     objs: Iterable[NDFrame] | Mapping[HashableT, NDFrame],
   (...)
    158     copy: bool = True,
    159 ) -> DataFrame | Series:
    160     """
    161     Concatenate pandas objects along a particular axis.
    162 
   (...)
    367     1   3   4
    368     """
--> 369     op = _Concatenator(
    370         objs,
    371         axis=axis,
    372         ignore_index=ignore_index,
    373         join=join,
    374         keys=keys,
    375         levels=levels,
    376         names=names,
    377         verify_integrity=verify_integrity,
    378         copy=copy,
    379         sort=sort,
    380     )
    382     return op.get_result()

File ~/.local/lib/python3.10/site-packages/pandas/core/reshape/concat.py:564, in _Concatenator.__init__(self, objs, axis, join, keys, levels, names, ignore_index, verify_integrity, copy, sort)
    561 self.verify_integrity = verify_integrity
    562 self.copy = copy
--> 564 self.new_axes = self._get_new_axes()

File ~/.local/lib/python3.10/site-packages/pandas/core/reshape/concat.py:634, in _Concatenator._get_new_axes(self)
    632 def _get_new_axes(self) -> list[Index]:
    633     ndim = self._get_result_dim()
--> 634     return [
    635         self._get_concat_axis if i == self.bm_axis else self._get_comb_axis(i)
    636         for i in range(ndim)
    637     ]

File ~/.local/lib/python3.10/site-packages/pandas/core/reshape/concat.py:635, in <listcomp>(.0)
    632 def _get_new_axes(self) -> list[Index]:
    633     ndim = self._get_result_dim()
    634     return [
--> 635         self._get_concat_axis if i == self.bm_axis else self._get_comb_axis(i)
    636         for i in range(ndim)
    637     ]

File ~/.local/lib/python3.10/site-packages/pandas/core/reshape/concat.py:641, in _Concatenator._get_comb_axis(self, i)
    639 def _get_comb_axis(self, i: int) -> Index:
    640     data_axis = self.objs[0]._get_block_manager_axis(i)
--> 641     return get_objs_combined_axis(
    642         self.objs,
    643         axis=data_axis,
    644         intersect=self.intersect,
    645         sort=self.sort,
    646         copy=self.copy,
    647     )

File ~/.local/lib/python3.10/site-packages/pandas/core/indexes/api.py:105, in get_objs_combined_axis(objs, intersect, axis, sort, copy)
     81 """
     82 Extract combined index: return intersection or union (depending on the
     83 value of "intersect") of indexes on given axis, or None if all objects
   (...)
    102 Index
    103 """
    104 obs_idxes = [obj._get_axis(axis) for obj in objs]
--> 105 return _get_combined_index(obs_idxes, intersect=intersect, sort=sort, copy=copy)

File ~/.local/lib/python3.10/site-packages/pandas/core/indexes/api.py:158, in _get_combined_index(indexes, intersect, sort, copy)
    156         index = index.intersection(other)
    157 else:
--> 158     index = union_indexes(indexes, sort=False)
    159     index = ensure_index(index)
    161 if sort:

File ~/.local/lib/python3.10/site-packages/pandas/core/indexes/api.py:284, in union_indexes(indexes, sort)
    278 dti_tzs = [x for x in dtis if x.tz is not None]
    279 if len(dti_tzs) not in [0, len(dtis)]:
    280     # TODO: this behavior is not tested (so may not be desired),
    281     #  but is kept in order to keep behavior the same when
    282     #  deprecating union_many
    283     # test_frame_from_dict_with_mixed_indexes
--> 284     raise TypeError("Cannot join tz-naive with tz-aware DatetimeIndex")
    286 if len(dtis) == len(indexes):
    287     sort = True

TypeError: Cannot join tz-naive with tz-aware DatetimeIndex
georgandreasjaksch commented 1 year ago

Fixed it by adding benchmark = benchmark.tz_localize(None) to empyrial.py

santoshlite commented 1 year ago

Sorry could you make a quick pull request please?