Skip to content

Commit

Permalink
Change *_minute_nanos methods to properties
Browse files Browse the repository at this point in the history
For each `*_minute_nanos` method:
- changes method to property (loses `side` option).
- renamed `*_minutes_nanos`.

Also:
- renames `all_*_minutes` properties as `*_minutes`.
- removes 'side' option from `minute_index_to_session_labels`.
  • Loading branch information
maread99 committed Oct 25, 2021
1 parent 55f9ec6 commit ac4c55d
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 56 deletions.
110 changes: 55 additions & 55 deletions exchange_calendars/exchange_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -706,65 +706,75 @@ def break_ends(self) -> pd.Series:
"""
return self.schedule.break_end

@functools.lru_cache(maxsize=1) # cache last request
def _first_minute_nanos(self, side: str | None = None) -> np.ndarray:
side = side if side is not None else self.side
if side in self._LEFT_SIDES:
@functools.lru_cache(maxsize=1)
def _first_minutes_nanos(self) -> np.ndarray:
if self.side in self._LEFT_SIDES:
return self.market_opens_nanos
else:
return one_minute_later(self.market_opens_nanos)

@functools.lru_cache(maxsize=1) # cache last request
def _last_minute_nanos(self, side: str | None = None) -> np.ndarray:
side = side if side is not None else self.side
if side in self._RIGHT_SIDES:
@property
def first_minutes_nanos(self) -> np.ndarray:
return self._first_minutes_nanos()

@functools.lru_cache(maxsize=1)
def _last_minutes_nanos(self) -> np.ndarray:
if self.side in self._RIGHT_SIDES:
return self.market_closes_nanos
else:
return one_minute_earlier(self.market_closes_nanos)

@functools.lru_cache(maxsize=1) # cache last request
def _last_am_minute_nanos(self, side: str | None = None) -> np.ndarray:
side = side if side is not None else self.side
if side in self._RIGHT_SIDES:
@property
def last_minutes_nanos(self) -> np.ndarray:
return self._last_minutes_nanos()

@functools.lru_cache(maxsize=1)
def _last_am_minutes_nanos(self) -> np.ndarray:
if self.side in self._RIGHT_SIDES:
return self.market_break_starts_nanos
else:
return one_minute_earlier(self.market_break_starts_nanos)

@functools.lru_cache(maxsize=1) # cache last request
def _first_pm_minute_nanos(self, side: str | None = None) -> np.ndarray:
side = side if side is not None else self.side
if side in self._LEFT_SIDES:
@property
def last_am_minutes_nanos(self) -> np.ndarray:
return self._last_am_minutes_nanos()

@functools.lru_cache(maxsize=1)
def _first_pm_minutes_nanos(self) -> np.ndarray:
if self.side in self._LEFT_SIDES:
return self.market_break_ends_nanos
else:
return one_minute_later(self.market_break_ends_nanos)

@property
def first_pm_minutes_nanos(self) -> np.ndarray:
return self._first_pm_minutes_nanos()

def _minutes_as_series(self, nanos: np.ndarray, name: str) -> pd.Series:
"""Convert trading minute nanos to pd.Series."""
ser = pd.Series(pd.DatetimeIndex(nanos, tz="UTC"), index=self.all_sessions)
ser.name = name
return ser

@property
def all_first_minutes(self) -> pd.Series:
def first_minutes(self) -> pd.Series:
"""First trading minute of each session."""
return self._minutes_as_series(self._first_minute_nanos(), "first_minutes")
return self._minutes_as_series(self.first_minutes_nanos, "first_minutes")

@property
def all_last_minutes(self) -> pd.Series:
def last_minutes(self) -> pd.Series:
"""Last trading minute of each session."""
return self._minutes_as_series(self._last_minute_nanos(), "last_minutes")
return self._minutes_as_series(self.last_minutes_nanos, "last_minutes")

@property
def all_last_am_minutes(self) -> pd.Series:
def last_am_minutes(self) -> pd.Series:
"""Last am trading minute of each session."""
return self._minutes_as_series(self._last_am_minute_nanos(), "last_am_minutes")
return self._minutes_as_series(self.last_am_minutes_nanos, "last_am_minutes")

@property
def all_first_pm_minutes(self) -> pd.Series:
def first_pm_minutes(self) -> pd.Series:
"""First pm trading minute of each session."""
return self._minutes_as_series(
self._first_pm_minute_nanos(), "first_pm_minutes"
)
return self._minutes_as_series(self.first_pm_minutes_nanos, "first_pm_minutes")

# Properties covering all minutes.

Expand Down Expand Up @@ -969,28 +979,28 @@ def session_first_minute(
self, session: Session, _parse: bool = True
) -> pd.Timestamp:
"""Return first trading minute of a given session."""
nanos = self._first_minute_nanos()
nanos = self.first_minutes_nanos
return self._get_session_minute_from_nanos(session, nanos, _parse)

def session_last_minute(
self, session: Session, _parse: bool = True
) -> pd.Timestamp:
"""Return last trading minute of a given session."""
nanos = self._last_minute_nanos()
nanos = self.last_minutes_nanos
return self._get_session_minute_from_nanos(session, nanos, _parse)

def session_last_am_minute(
self, session: Session, _parse: bool = True
) -> pd.Timestamp | pd.NaT: # Literal[pd.NaT] - when move to min 3.8
"""Return last trading minute of am subsession of a given session."""
nanos = self._last_am_minute_nanos()
nanos = self.last_am_minutes_nanos
return self._get_session_minute_from_nanos(session, nanos, _parse)

def session_first_pm_minute(
self, session: Session, _parse: bool = True
) -> pd.Timestamp | pd.NaT: # Literal[pd.NaT] - when move to min 3.8
"""Return first trading minute of pm subsession of a given session."""
nanos = self._first_pm_minute_nanos()
nanos = self.first_pm_minutes_nanos
return self._get_session_minute_from_nanos(session, nanos, _parse)

def session_first_and_last_minute(
Expand All @@ -1000,8 +1010,8 @@ def session_first_and_last_minute(
) -> tuple(pd.Timestamp, pd.Timestamp):
"""Return first and last trading minutes of a given session."""
idx = self._get_session_idx(session, _parse=_parse)
first = pd.Timestamp(self._first_minute_nanos()[idx], tz="UTC")
last = pd.Timestamp(self._last_minute_nanos()[idx], tz="UTC")
first = pd.Timestamp(self.first_minutes_nanos[idx], tz="UTC")
last = pd.Timestamp(self.last_minutes_nanos[idx], tz="UTC")
return (first, last)

def session_has_break(self, session: Session, _parse: bool = True) -> bool:
Expand Down Expand Up @@ -1288,9 +1298,9 @@ def is_break_minute(self, minute: Minute, _parse: bool = True) -> bool:
"""
if _parse:
minute = parse_timestamp(minute, "minute", self)
session_idx = np.searchsorted(self._first_minute_nanos(), minute.value) - 1
break_start = self._last_am_minute_nanos()[session_idx]
break_end = self._first_pm_minute_nanos()[session_idx]
session_idx = np.searchsorted(self.first_minutes_nanos, minute.value) - 1
break_start = self.last_am_minutes_nanos[session_idx]
break_end = self.first_pm_minutes_nanos[session_idx]
# NaT comparisions evalute as False
numpy_bool = break_start < minute.value < break_end
return bool(numpy_bool)
Expand Down Expand Up @@ -1577,7 +1587,7 @@ def minute_to_session_label(
)
)

idx = np.searchsorted(self._last_minute_nanos(), dt.value)
idx = np.searchsorted(self.last_minutes_nanos, dt.value)
current_or_next_session = self.schedule.index[idx]

if direction == "next":
Expand Down Expand Up @@ -1918,9 +1928,7 @@ def minutes_window(
return self.all_minutes[min(start_idx, end_idx) : max(start_idx, end_idx) + 1]

def minute_index_to_session_labels(
self,
index: pd.DatetimeIndex,
side: str | None = None,
self, index: pd.DatetimeIndex
) -> pd.DatetimeIndex:
"""Return session labels corresponding to multiple market minutes.
Expand All @@ -1934,10 +1942,6 @@ def minute_index_to_session_labels(
Sorted DatetimeIndex representing market minutes for which to get
corresponding session labels.
side : default: as `self.side`
Override `self.side` to define which side of sessions should be
considered as market minutes for the purpose of this call.
Returns
-------
pd.DatetimeIndex (indices UTC midnight)
Expand All @@ -1955,8 +1959,8 @@ def minute_index_to_session_labels(
# Find the indices of the previous first session minute and the next
# last session minute for each minute.
index_nanos = index.values.astype(np.int64)
first_min_nanos = self._first_minute_nanos(side)
last_min_nanos = self._last_minute_nanos(side)
first_min_nanos = self.first_minutes_nanos
last_min_nanos = self.last_minutes_nanos
prev_first_mins_idxs = (
first_min_nanos.searchsorted(index_nanos, side="right") - 1
)
Expand All @@ -1970,12 +1974,10 @@ def minute_index_to_session_labels(
example = index[bad_ix]

prev_session_idx = prev_first_mins_idxs[bad_ix]
prev_first_min = pd.Timestamp(first_min_nanos[prev_session_idx], tz="UTC")
prev_last_min = pd.Timestamp(last_min_nanos[prev_session_idx], tz="UTC")
next_first_min = pd.Timestamp(
first_min_nanos[prev_session_idx + 1], tz="UTC"
)
next_last_min = pd.Timestamp(last_min_nanos[prev_session_idx + 1], tz="UTC")
prev_first_min = pd.Timestamp(first_min_nanos[prev_session_idx], tz=UTC)
prev_last_min = pd.Timestamp(last_min_nanos[prev_session_idx], tz=UTC)
next_first_min = pd.Timestamp(first_min_nanos[prev_session_idx + 1], tz=UTC)
next_last_min = pd.Timestamp(last_min_nanos[prev_session_idx + 1], tz=UTC)

raise ValueError(
f"{mismatches.sum()} non-trading minutes in"
Expand Down Expand Up @@ -2232,11 +2234,9 @@ def minutes_count_for_sessions_in_range(
`start_session` through `end_session` (inclusive of both).
"""
slc = self._get_sessions_slice(start_session, end_session, _parse)
session_diff = self._last_minute_nanos()[slc] - self._first_minute_nanos()[slc]
session_diff = self.last_minutes_nanos[slc] - self.first_minutes_nanos[slc]
session_diff += NANOSECONDS_PER_MINUTE
break_diff = (
self._first_pm_minute_nanos()[slc] - self._last_am_minute_nanos()[slc]
)
break_diff = self.first_pm_minutes_nanos[slc] - self.last_am_minutes_nanos[slc]
break_diff[break_diff != 0] -= NANOSECONDS_PER_MINUTE
nanos = session_diff - break_diff
return (nanos // NANOSECONDS_PER_MINUTE).sum()
Expand Down
2 changes: 1 addition & 1 deletion tests/test_exchange_calendar.py
Original file line number Diff line number Diff line change
Expand Up @@ -2362,7 +2362,7 @@ def test_minutes_properties(self, all_calendars_with_answers):
"first_pm_minutes",
):
ans_minutes = getattr(ans, prop)
cal_minutes = getattr(cal, "all_" + prop)
cal_minutes = getattr(cal, prop)
tm.assert_series_equal(ans_minutes, cal_minutes, check_freq=False)

# Tests for properties covering all minutes.
Expand Down

0 comments on commit ac4c55d

Please sign in to comment.