Files
catalyst/zipline/utils/calendars/_calendar_helpers.pyx
T
Nathan Wolfe 4865ade9b2 ENH: Add fast "vectorized" minute_to_session_label for DatetimeIndex
The new TradingCalendar method is called `minute_index_to_session_labels`.
It takes a DatetimeIndex of in-order market minutes and returns a
DatetimeIndex of the corresponding sessions.

The new method is approximately 100x faster than mapping
`minute_to_session_label` over a large DatetimeIndex.
2016-08-18 17:27:47 -04:00

75 lines
2.3 KiB
Cython

from numpy cimport ndarray, int64_t
from numpy import empty, searchsorted, int64
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
cpdef int next_divider_idx(ndarray[int64_t, ndim=1] dividers, int64_t minute_val):
cdef int divider_idx
cdef int64_t target
divider_idx = searchsorted(dividers, minute_val, side="right")
target = dividers[divider_idx]
if minute_val == target:
# if dt is exactly on the divider, go to the next value
return divider_idx + 1
else:
return divider_idx
@cython.boundscheck(False)
@cython.wraparound(False)
def previous_divider_idx(ndarray[int64_t, ndim=1] dividers,
int64_t minute_val):
cdef int divider_idx
divider_idx = searchsorted(dividers, minute_val)
if divider_idx == 0:
raise ValueError("Cannot go earlier in calendar!")
return divider_idx - 1
def is_open(ndarray[int64_t, ndim=1] opens,
ndarray[int64_t, ndim=1] closes,
int64_t minute_val):
cdef open_idx, close_idx
open_idx = searchsorted(opens, minute_val)
close_idx = searchsorted(closes, minute_val)
if open_idx != close_idx:
# if the indices are not same, that means the market is open
return True
else:
try:
# if they are the same, it might be the first minute of a
# session
return minute_val == opens[open_idx]
except IndexError:
# this can happen if we're outside the schedule's range (like
# after the last close)
return False
@cython.boundscheck(False)
@cython.wraparound(False)
def minutes_to_session_labels(ndarray[int64_t, ndim=1] minutes,
minute_to_session_label,
ndarray[int64_t, ndim=1] closes):
cdef int current_idx, next_idx, close_idx
current_idx = next_idx = close_idx = 0
cdef ndarray[int64_t, ndim=1] results = empty(len(minutes), dtype=int64)
while current_idx < len(minutes):
close_idx += searchsorted(closes[close_idx:],
minutes[current_idx], side="right")
next_idx += next_divider_idx(minutes[next_idx:], closes[close_idx])
results[current_idx:next_idx] = minute_to_session_label(
minutes[current_idx]
)
current_idx = next_idx
return results