# How US Stock Market Hours Validation (9:30-16:00 ET) Works in AI-Trader

> Learn how AI-Trader validates US stock market hours (9:30-16:00 ET) using minute-based arithmetic and timezone conversions. Explore the implementation in routes shared Python.

- Repository: [✨Data Intelligence Lab@HKU✨/AI-Trader](https://github.com/HKUDS/AI-Trader)
- Tags: how-to-guide
- Published: 2026-05-09

---

**AI-Trader validates US stock trades against the official 9:30 AM to 4:00 PM Eastern Time window using minute-based arithmetic and Eastern Time zone conversions in [`service/server/routes_shared.py`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/routes_shared.py).**

AI-Trader is an open-source trading system that enforces strict compliance with US equity market regulations. The repository implements precise market-hours validation to ensure trade orders are only accepted during official New York Stock Exchange hours, while allowing unrestricted 24/7 trading for cryptocurrency assets.

## Core Validation Logic in routes_shared.py

The validation system centers on [`service/server/routes_shared.py`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/routes_shared.py), which contains the primary time-checking functions. The implementation uses mathematical conversion of time to minutes rather than string parsing, enabling efficient range comparisons.

### Minute-Based Time Comparison

The `is_us_market_open()` function converts the current Eastern Time into total minutes since midnight to determine if the market is active. This approach simplifies the boundary check against the 9:30 AM (570 minutes) and 4:00 PM (960 minutes) thresholds.

```python
from zoneinfo import ZoneInfo
from datetime import datetime

def is_us_market_open() -> bool:
    et_tz = ZoneInfo('America/New_York')
    now_et = datetime.now(et_tz)
    day = now_et.weekday()
    time_in_minutes = now_et.hour * 60 + now_et.minute
    return day < 5 and 570 <= time_in_minutes < 960

```

This function returns `True` only when the day is a weekday (Monday through Friday, where `weekday()` returns 0-4) and the time falls within the 570-960 minute window.

### The is_market_open() Router

The system delegates market status checks through `is_market_open()`, which acts as a central switch. According to the source code in [`routes_shared.py`](https://github.com/HKUDS/AI-Trader/blob/main/routes_shared.py), this function bypasses time validation for crypto markets while routing US stock requests to the dedicated checker:

```python
def is_market_open(market: str) -> bool:
    if market in ('crypto', 'polymarket'):
        return True
    if market == 'us-stock':
        return is_us_market_open()
    return True

```

This design pattern ensures that **US stock market hours validation** is applied consistently across all equity trading routes while maintaining flexibility for non-traditional markets.

## Validating Execution Timestamps

When processing trade requests, AI-Trader validates user-provided execution timestamps through `validate_executed_at()`. This function handles both immediate execution requests (`"now"`) and specific datetime strings, converting all inputs to US Eastern Time before validation.

### Handling "Now" Requests

For real-time trade validation, the function checks if the current moment falls within trading hours when the client specifies `"now"` as the execution time:

```python
def validate_executed_at(executed_at: str, market: str) -> tuple[bool, str]:
    # ... parsing logic ...

    if executed_at.lower() == 'now':
        if not is_market_open(market):
            if market == 'us-stock':
                et_tz = ZoneInfo('America/New_York')
                now_et = datetime.now(et_tz)
                return (
                    False,
                    'US market is closed. '
                    f"Current time (ET): {now_et.strftime('%Y-%m-%d %H:%M:%S')}. "
                    'Trading hours: Mon-Fri 9:30-16:00 ET',
                )
            return False, f'{market} is currently closed'
        return True, ''

```

### Validating Specific Timestamps

For historical or scheduled trades, the function parses the timestamp and applies the same weekday and minute-range logic:

```python
    # ... conversion to dt_et ...

    if market == 'us-stock':
        day = dt_et.weekday()
        time_in_minutes = dt_et.hour * 60 + dt_et.minute
        is_weekday = day < 5
        is_market_hours = 570 <= time_in_minutes < 960
        
        if not (is_weekday and is_market_hours):
            day_names = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
            return (
                False,
                f"US market is closed on {day_names[day]} at {dt_et.strftime('%H:%M')} ET. "
                'Trading hours: Mon-Fri 9:30-16:00 ET',
            )

```

This implementation generates descriptive error messages that include the specific day and time, making troubleshooting straightforward for API consumers.

## Time Zone Handling and DST

AI-Trader utilizes Python's `zoneinfo.ZoneInfo('America/New_York')` to handle Eastern Time conversions. This approach automatically respects daylight saving time transitions, ensuring that the 9:30-16:00 window shifts appropriately between EST (UTC-5) and EDT (UTC-4) without requiring manual offset calculations. The validation logic remains consistent year-round because `ZoneInfo` abstracts the complexity of seasonal clock changes.

## Integration in Trade Routes

The validation functions integrate directly with the trading API endpoints defined in [`service/server/routes_trading.py`](https://github.com/HKUDS/AI-Trader/blob/main/service/server/routes_trading.py). When a client submits a trade creation payload, the route handler invokes `validate_executed_at()` before processing the order. This centralized validation gate ensures that every US stock order passes through the same **9:30 to 16:00 ET** compliance check, regardless of which endpoint receives the request.

## Summary

- **Minute-based comparison**: The system converts hours and minutes to total minutes since midnight (570-960 range) to validate the 9:30 AM to 4:00 PM window.
- **Eastern Time enforcement**: All timestamps are converted to `America/New_York` using `ZoneInfo`, automatically handling daylight saving time.
- **Centralized routing**: `is_market_open()` in [`routes_shared.py`](https://github.com/HKUDS/AI-Trader/blob/main/routes_shared.py) directs validation logic while exempting crypto markets from time restrictions.
- **Descriptive error messages**: Failed validations return specific feedback including current ET time and official trading hours.
- **Dual validation paths**: The system handles both immediate execution (`"now"`) and specific historical timestamps with the same underlying logic.

## Frequently Asked Questions

### How does AI-Trader handle daylight saving time changes?

AI-Trader uses Python's standard library `ZoneInfo` with the `'America/New_York'` identifier rather than hardcoded UTC offsets. This implementation automatically adjusts for EST (UTC-5) and EDT (UTC-4) transitions, ensuring that the 9:30-16:00 validation window remains accurate regardless of the season.

### What happens when a trade is submitted outside US market hours?

When `validate_executed_at()` detects a time outside the 570-960 minute window or a weekend day, it returns a tuple containing `False` and a descriptive error string. For example, a Saturday submission generates: `"US market is closed on Sat at 08:15 ET. Trading hours: Mon-Fri 9:30-16:00 ET"`. This prevents order execution and informs the user of the exact reason for rejection.

### Does the validation apply to all asset types?

No. The `is_market_open()` function explicitly returns `True` for `crypto` and `polymarket` assets without time checking. Only the `us-stock` market type triggers the `is_us_market_open()` validation, allowing cryptocurrency trades to execute 24/7 while restricting equities to official exchange hours.

### Can I use is_us_market_open() in my own scripts?

Yes. The function is importable from `service.server.routes_shared` and can be used independently to check market status. Since it relies only on the system clock and `ZoneInfo`, it requires no database connections or API keys to function, making it suitable for standalone market monitoring tools.