You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
50 lines
1.7 KiB
Python
50 lines
1.7 KiB
Python
"""Compute the reaction date for a filing based on its time bucket."""
|
|
from __future__ import annotations
|
|
|
|
import datetime as dt
|
|
|
|
from libs.common.time_utils import is_trading_day
|
|
|
|
|
|
def _advance_to_next_trading_day(date: dt.date) -> dt.date:
|
|
"""Return the next calendar day that is a trading day (starting from date+1)."""
|
|
check = date + dt.timedelta(days=1)
|
|
for _ in range(30): # guard against infinite loop
|
|
if is_trading_day(check):
|
|
return check
|
|
check += dt.timedelta(days=1)
|
|
raise RuntimeError(f"Could not find trading day within 30 days of {date}")
|
|
|
|
|
|
def _to_trading_day_on_or_after(date: dt.date) -> dt.date:
|
|
"""Return date itself if a trading day, else the next trading day."""
|
|
for _ in range(30):
|
|
if is_trading_day(date):
|
|
return date
|
|
date += dt.timedelta(days=1)
|
|
raise RuntimeError("Could not find trading day within 30 days")
|
|
|
|
|
|
def compute_reaction_date(
|
|
event_date: dt.date,
|
|
filing_time_bucket: str,
|
|
) -> dt.date:
|
|
"""Return the first trading day on which the market can react to the filing.
|
|
|
|
Rules:
|
|
- pre_market / regular_hours → same day if it is a trading day, else next.
|
|
- post_market / unknown → next trading day after event_date.
|
|
|
|
Args:
|
|
event_date: The calendar date of the filing.
|
|
filing_time_bucket: One of pre_market, regular_hours, post_market, unknown.
|
|
|
|
Returns:
|
|
The reaction date (a trading day).
|
|
"""
|
|
if filing_time_bucket in ("pre_market", "regular_hours"):
|
|
return _to_trading_day_on_or_after(event_date)
|
|
else:
|
|
# post_market or unknown: market reacts next trading day
|
|
return _advance_to_next_trading_day(event_date)
|