feat: sell execution, correlation matrix from market data, US market holiday awareness

- Sell path: looks up existing position, sells full quantity, returns proceeds to pool
- Correlation matrix: computed from 30-day market_snapshots on startup + every 5min
- Holidays: 10 major US market holidays for 2026 checked in trading window functions
This commit is contained in:
Celes Renata
2026-04-16 15:36:49 +00:00
parent 2e77cf32fd
commit 1329df0bbf
2 changed files with 240 additions and 6 deletions
+44 -6
View File
@@ -5,12 +5,12 @@ within the allowed trading window (9:45 AM 3:45 PM ET on weekdays),
whether the US market is open, and when the next trading window opens.
Uses ``zoneinfo.ZoneInfo("America/New_York")`` for Eastern Time handling.
Does not check market holidays (simplified).
Checks major US market holidays for 2026.
"""
from __future__ import annotations
from datetime import datetime, time, timedelta
from datetime import date, datetime, time, timedelta
from zoneinfo import ZoneInfo
# US Eastern timezone
@@ -28,16 +28,49 @@ MARKET_CLOSE = time(16, 0)
_WEEKDAYS = range(0, 5)
def _us_market_holidays_2026() -> set[date]:
"""Return a set of US market holiday dates for 2026.
Major holidays observed by NYSE/NASDAQ:
- New Year's Day (Jan 1)
- MLK Day (3rd Monday of January)
- Presidents' Day (3rd Monday of February)
- Good Friday (April 3)
- Memorial Day (last Monday of May)
- Juneteenth (June 19)
- Independence Day (July 3 observed — July 4 is Saturday)
- Labor Day (1st Monday of September)
- Thanksgiving (4th Thursday of November)
- Christmas (Dec 25)
"""
return {
date(2026, 1, 1), # New Year's Day
date(2026, 1, 19), # MLK Day (3rd Monday)
date(2026, 2, 16), # Presidents' Day (3rd Monday)
date(2026, 4, 3), # Good Friday
date(2026, 5, 25), # Memorial Day (last Monday)
date(2026, 6, 19), # Juneteenth
date(2026, 7, 3), # Independence Day (observed)
date(2026, 9, 7), # Labor Day (1st Monday)
date(2026, 11, 26), # Thanksgiving (4th Thursday)
date(2026, 12, 25), # Christmas
}
_HOLIDAYS_2026 = _us_market_holidays_2026()
def is_within_trading_window(dt: datetime) -> bool:
"""Return True if *dt* is between 9:45 AM ET and 3:45 PM ET on a weekday.
The timestamp is first converted to US/Eastern time. Weekends are
always outside the window. Market holidays are **not** checked
(simplified implementation).
The timestamp is first converted to US/Eastern time. Weekends and
US market holidays (2026) are always outside the window.
"""
et_dt = dt.astimezone(ET)
if et_dt.weekday() not in _WEEKDAYS:
return False
if et_dt.date() in _HOLIDAYS_2026:
return False
t = et_dt.time()
return WINDOW_OPEN <= t < WINDOW_CLOSE
@@ -74,9 +107,14 @@ def next_window_open(dt: datetime) -> datetime:
def is_market_open(dt: datetime) -> bool:
"""Return True if *dt* is during US market hours (9:30 AM 4:00 PM ET) on a weekday."""
"""Return True if *dt* is during US market hours (9:30 AM 4:00 PM ET) on a weekday.
Returns False on weekends and US market holidays (2026).
"""
et_dt = dt.astimezone(ET)
if et_dt.weekday() not in _WEEKDAYS:
return False
if et_dt.date() in _HOLIDAYS_2026:
return False
t = et_dt.time()
return MARKET_OPEN <= t < MARKET_CLOSE