rsheftel / pandas_market_calendars

Exchange calendars to use with pandas for trading applications
MIT License
804 stars 173 forks source link

ValueError("cannot reindex on an axis with duplicate labels") #258

Open stopdesign opened 1 year ago

stopdesign commented 1 year ago

It looks like the special_closes_adhoc method conflicts with special_closes. If special_closes_adhoc has a rule for day which already was in special_closes, it would throw a ValueError("cannot reindex on an axis with duplicate labels").

However, it works if I split the schedule in parts.

For example:

from datetime import datetime, time

import pandas as pd
from pandas.tseries.offsets import CustomBusinessDay
from pandas_market_calendars.calendar_registry import CMEGlobexFXExchangeCalendar

mask_fri = CustomBusinessDay(weekmask="Fri")  # type: ignore
fridays = pd.date_range("2020-01-01", "2030-01-01", freq=mask_fri)

class ForexEURNZD(CMEGlobexFXExchangeCalendar):
    regular_market_times = {
        "market_open": ((None, time(14, 15), -1),),
        "market_close": ((None, time(14)),),
    }

    @property
    def special_closes_adhoc(self):
        return [
            (time(16), fridays),
        ]

def main():
    # This fails with ValueError("cannot reindex on an axis with duplicate labels")
    cal = ForexEURNZD().schedule(datetime(2023, 1, 1), datetime(2023, 12, 1))
    print(cal)

    # This works
    a = ForexEURNZD().schedule(datetime(2023, 1, 1), datetime(2023, 10, 10))
    b = ForexEURNZD().schedule(datetime(2023, 10, 11), datetime(2023, 12, 1))

    c = pd.concat([a, b])
    print(c)

if __name__ == "__main__":
    main()
Traceback (most recent call last):
  File "cal.py", line 38, in <module>
    main()
  File "cal.py", line 26, in main
    cal = ForexEURNZD().schedule(datetime(2023, 1, 1), datetime(2023, 12, 1))
          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../pandas_market_calendars/market_calendar.py", line 619, in schedule
    temp.loc[specialix] = special
    ~~~~~~~~^^^^^^^^^^^
  File ".../pandas/core/indexing.py", line 849, in __setitem__
    iloc._setitem_with_indexer(indexer, value, self.name)
  File ".../pandas/core/indexing.py", line 1830, in _setitem_with_indexer
    self._setitem_single_block(indexer, value, name)
  File ".../pandas/core/indexing.py", line 2061, in _setitem_single_block
    value = self._align_series(indexer, Series(value))
            ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../pandas/core/indexing.py", line 2238, in _align_series
    ser_values = ser.reindex(obj.axes[0][indexer[0]], copy=True)._values
                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File ".../pandas/core/series.py", line 4914, in reindex
    return super().reindex(
           ^^^^^^^^^^^^^^^^
  File ".../pandas/core/generic.py", line 5360, in reindex
    return self._reindex_axes(
           ^^^^^^^^^^^^^^^^^^^
  File ".../pandas/core/generic.py", line 5375, in _reindex_axes
    new_index, indexer = ax.reindex(
                         ^^^^^^^^^^^
  File ".../pandas/core/indexes/base.py", line 4274, in reindex
    raise ValueError("cannot reindex on an axis with duplicate labels")
ValueError: cannot reindex on an axis with duplicate labels

By the way, Is there a better way to describe this schedule? I need all the holidays from the CMEGlobexFXExchangeCalendar, but with different opening and closing times. Additionally, the opening time on Monday and closing time on Friday could be different from those during the rest of the week. I'm having some trouble describing the 'every Friday' part.

Versions: python 3.11.3 pandas 2.0.1, 1.5.2 pandas-market-calendars 4.1.4