Skip to content

Preserve intraday closing-auction bar dropped by Yahoo schedule end#2806

Open
dokson wants to merge 1 commit into
ranaroussi:devfrom
dokson:fix/intraday-closing-auction-bar
Open

Preserve intraday closing-auction bar dropped by Yahoo schedule end#2806
dokson wants to merge 1 commit into
ranaroussi:devfrom
dokson:fix/intraday-closing-auction-bar

Conversation

@dokson

@dokson dokson commented May 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Closes #1585.

Yahoo's tradingPeriods.end undershoots the real session close on several exchanges by omitting the closing auction. Yahoo still returns a bar at index == end holding the auction price, but fix_Yahoo_returning_prepost_unrequested was discarding it via index >= end, leaving users without the official close.

The reporter's case was Saudi (2222.SR), but a sweep of the major venues found the same pattern on at least 8 exchanges plus US half-days:

Exchange Yahoo end Notes
SAU (Tadawul) 15:00 AST actual close incl. auction is 15:20
KSC (KOSPI) 15:00 KST closing auction 15:20–15:30
SAO (B3) 17:00 BRT closing call to ~17:55
BUD (BSE) 17:00 CET
NZE (NZX) 17:00 NZST
SES (SGX) 17:00 SGT closing routine 17:00–17:06
JNB (JSE) 17:00 SAST
DFM (Dubai) 15:00 GST
US half-days 13:00 EST Thanksgiving etc.

In every case Yahoo returns a bar at exactly end with a valid Close and Volume == 0, i.e. the closing-auction print. The Volume == 0 part is acknowledged as a Yahoo data limitation in the original issue thread (auction volume not exposed intraday) and is out of scope for this PR.

Changes

  • yfinance/utils.py: switch the drop boundary in fix_Yahoo_returning_prepost_unrequested from quotes.index >= quotes['end'] to quotes.index > quotes['end']. Single-character semantic change. Pre-market bars are still pruned by the other half of the filter; bars strictly past end (post-close) still get dropped.
  • tests/test_prices.py:
    • test_fix_prepost_keeps_closing_auction_bar — synthetic, no-network regression test exercising both sides of the boundary (pre-market and post-close still drop, bar at == end survives).
    • test_intraday_closing_auction_bar_saudi — live integration check on 2222.SR.
    • test_prune_post_intraday_us assertion relaxed from < to <=: the half-day closing-auction bar at the early-close timestamp is now preserved, which is the intended behavior.

Behavior before

>>> yf.Ticker('2222.SR').history(period='5d', interval='1h').tail(2)
                              Close     Volume
2026-05-07 13:00:00+03:00     27.18    1489165
2026-05-07 14:00:00+03:00     27.12    2800336    # 15:00 closing-auction bar dropped

Behavior after

>>> yf.Ticker('2222.SR').history(period='5d', interval='1h').tail(2)
                              Close     Volume
2026-05-07 14:00:00+03:00     27.12    2800336
2026-05-07 15:00:00+03:00     27.20          0    # closing-auction print preserved

Test plan

  • python -m unittest tests.test_prices.TestPriceHistory.test_fix_prepost_keeps_closing_auction_bar tests.test_prices.TestPriceHistory.test_intraday_closing_auction_bar_saudi tests.test_prices.TestPriceHistory.test_prune_post_intraday_us tests.test_prices.TestPriceHistory.test_prune_post_intraday_asx -v — all pass
  • TDD red→green: both new tests fail on dev (verified by reverting just the >=/> change), pass with the fix
  • Spot-checked the 8 affected exchanges plus AAPL (US, unaffected) — closing-auction bars now appear, no spurious post-market bars

Yahoo's `tradingPeriods.end` undershoots the real session close on several
exchanges (SAU, SAO, KSC, BUD, NZE, SES, JNB, DFM) and on US half-days,
omitting the closing auction. Yahoo still returns a bar at index == end
holding the auction price, but `fix_Yahoo_returning_prepost_unrequested`
discarded it via `index >= end`, leaving users without the official close.

- Switch the boundary in `fix_Yahoo_returning_prepost_unrequested` from
  `>=` to `>` so the bar at the schedule end survives. Pre-market and
  post-close bars are still dropped — they're handled by the second
  half of the filter or sit clearly past `end`.
- Add `test_fix_prepost_keeps_closing_auction_bar` as a synthetic, no-network
  regression test pinning the boundary semantics on both sides.
- Add `test_intraday_closing_auction_bar_saudi` as a live check on 2222.SR.
- Relax the assertion in `test_prune_post_intraday_us` from `<` to `<=`:
  the half-day closing-auction bar at the early-close timestamp is now
  preserved too, which is the intended outcome.

Closes ranaroussi#1585
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant