Skip to content

sync dev -> main - #2935

Draft
ValueRaider wants to merge 43 commits into
mainfrom
dev
Draft

sync dev -> main#2935
ValueRaider wants to merge 43 commits into
mainfrom
dev

Conversation

@ValueRaider

Copy link
Copy Markdown
Collaborator

It's time ...

shanehull and others added 30 commits July 5, 2026 09:24
…ner fields

The Yahoo Finance screener API supports both `dividendyield` (trailing
yield percentage) and `dividendpershare.lasttwelvemonths` (trailing DPS)
as query/filter/sort fields. These were missing from the profitability
category in EQUITY_SCREENER_FIELDS, causing EquityQuery to reject
queries referencing them.

Forward equivalents (forward_dividend_yield, forward_dividend_per_share)
were already present.
…r-field

fix: add dividendyield and dividendpershare.lasttwelvemonths to screener fields
pd.Timedelta() was called with bare interval strings (e.g. "1h", "30m"),
which numpy>=2.5 flags with 'The generic unit for NumPy timedelta is
deprecated'. Parse minute/hour intervals with explicit units in
_interval_to_timedelta and route _dts_in_same_interval through it so both
warning sites are covered.

Fixes #2882

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The Lookup class stores the search term as self.query, but two error-handling paths in _fetch_lookup referenced self.ticker, which does not exist on the class. When Yahoo returns a finance error payload (or faulty JSON), the intended YFDataException / error log is never produced; instead the code raises a confusing 'Lookup object has no attribute ticker' AttributeError that masks the real cause.

Replace both self.ticker references with self.query so the error is reported as intended. Add an offline unit test that feeds a mocked finance-error response and asserts YFDataException is raised with the query in the message.
Add missing balance sheet keys: FixedMaturityInvestments, EquityInves…
Fix generic-unit timedelta DeprecationWarning for sub-day intervals (#2882)
Series.to_numpy() can return a read-only view under Pandas copy-on-write, so the in-place reduction of huge 'Adj Close' values (added in #2860) crashed with 'ValueError: assignment destination is read-only' e.g. for ENV.CR. Copy the array before modifying; it is written back to df2 afterwards anyway. Add offline regression test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
yfinance works around a Yahoo API bug by fetching 15m data and
resampling it into 30m bars. That internal 15m interval leaked into
YFPricesMissingError messages: a failed 30m request reported '15m
data not available', confusing users who never asked for 15m
(reported 2022, still reproducible on 1.4.1).

- Build the error context from the interval the user requested.
- When Yahoo's quoted error names the internally fetched interval,
  append a note explaining the substitution.
- Document the 30m-to-15m mapping in history() and download()
  docstrings, which the docs website is generated from.
- Add live regression test that fails before this change.

Closes #1029

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: read-only 'Adj Close' array crash in dividend-adjust repair
…-ticker

Fix AttributeError in Lookup error handling (self.ticker -> self.query)
Use the phrasing requested by ValueRaider in PR #2900:
'(30m resampled from 15m)'.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…-message

Fix error messages showing internal 15m interval for 30m requests
pandas 3 attaches zoneinfo timezones to DatetimeIndex, so comparing
against a pytz object fails on any pandas >= 3:

  AssertionError: zoneinfo.ZoneInfo(key='America/New_York')
                  != <DstTzInfo 'America/New_York' LMT-1 day, 19:04:00 STD>

Compare the timezone key string instead, which is identical for the
zoneinfo (pandas 3) and pytz (pandas < 3) representations, matching
the pandas floor of >= 1.3 in requirements.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Every YFPricesMissingError message speculates 'possibly delisted',
even when Yahoo's response carries an explicit reason that has nothing
to do with delisting, e.g. an intraday range outside the last 60 days.
That speculation has misled users for years (see #1713, #1797, #2044,
#2052). And when a ticker really is dead, Yahoo's quoted description
already says 'No data found, symbol may be delisted', making the
prefix redundant there too.

Add possibly_delisted=True parameter to YFTickerMissingError and
YFPricesMissingError (default keeps every other callsite unchanged)
and pass False in the one history() branch where Yahoo supplied an
error description, letting Yahoo's stated reason stand.

Adds an offline test of both message formats and a live test that a
range error no longer claims delisting.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ndas3-tz

Fix pandas 3 timezone assertion in test_download_multi_small_interval
Per review on PR #2903: when Yahoo explains why data is missing, drop
the remaining boilerplate too, not just the 'possibly delisted' prefix.
The message is now just the ticker and Yahoo's reason:

  $SPY: 1m data not available for startTime=... Only 8 days worth of 1m
  granularity data are allowed to be fetched per request.
  $SPSPS: No data found, symbol may be delisted

Replace the possibly_delisted flag on YFPricesMissingError with a
yahoo_reason argument that becomes the whole message. The generic
'no price data found' text and the request-context wrapper are dropped
for this path; the request context is still kept on the .debug_info
attribute. The #2900 resample note still appends when the fetched
interval differs, so a 30m failure does not regress to reading as 15m.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…aim-on-yahoo-error

Don't claim 'possibly delisted' when Yahoo explains the missing data
Fix: handle null result from Yahoo API in _fetch_info
docs: fix grammar and formatting in advanced documentation
- calibration resilient against sudden-changes in df_new
- better calibration of 'Adj Close' in df_new
- repair invalid OHLC e.g. Close<Low

- Use Volume to decide if a sudden-change is unit-switch or missing-split

- Fix intraday div-repair by resampling to 1d then backporting repairs
- Handle more bad-div scenarios
- correct_columns_individually auto-set according to data
- recalc invalid Low/High

- unit-switch repair updates currency in history_metadata

- Improve handle nan-prices with dividend
Re-enable test_no_expensive_calls_introduced without requests_cache
ruff 0.16.0 expanded the default rule set, so the unpinned, config-less
lint job started failing on pre-existing code across the repo. Add ruff.toml
pinning select to E4,E7,E9,F (ignore E702, exclude the generated
pricing_pb2.py) and simplify the workflow args. No code changes.
Pin ruff ruleset for deterministic CI
Move build config and metadata from setup.py/setup.cfg to pyproject.toml so
[project.dependencies] is the single source of truth, and switch the publish
workflow to python -m build. Also declare lxml (needed by pandas.read_html),
add Python 3.11-3.13 classifiers, and drop the unusable nospam extra.
DMZ22 and others added 13 commits July 25, 2026 18:58
On pandas 2.x with numpy>=2.5, constructing a Timedelta from a bare string
or from a keyword like days=/minutes= emits the "'generic' unit for NumPy
timedelta is deprecated" DeprecationWarning; only the (value, unit=...)
form is silent.

An earlier fix switched the sub-day branches of _interval_to_timedelta to
minutes=/hours=, but that keyword form still warns, so the warning
persisted. Use the (value, unit=...) form there and in Quote.shares.
…rvals

_interval_to_timedelta returns a relativedelta for day intervals, which
cannot be compared against the Timedelta (dt2 - dt1), so _dts_in_same_interval
raised TypeError for a multi-day interval such as "5d". Build a Timedelta
directly for that case, using the (value, unit="D") form so it does not
reintroduce the generic-unit deprecation warning.
Migrate packaging to pyproject.toml
… main currency

_standardise_currency() converts subunit currencies (pence, cents, agora) to
main currency internally to help repair dividend-adjustment math, but this
conversion was leaking into the final returned data and metadata, even when
no actual repair was needed. Now reverts prices/dividends/currency back to
original units before returning to the user.

Verified against XDEV.L, HSBA.L (incl. auto_adjust), NPN.JO, and AAPL.
Confirmed bug reproduces on unmodified dev and is fixed on this branch.
Ran tests/test_price_repair.py: 2 pre-existing failures (test_resampling,
test_repair_zeroes_daily) reproduce identically on unmodified dev, unrelated
to this change.

- Refactored currency scaling dict into _CURRENCY_CONVERSIONS module-level constant
- Added regression test for issue #2866

Fixes #2866
Fix: repair=True should not permanently convert GBp/ZAc/ILA prices to main currency
Fix multi-day interval TypeError and actually silence the numpy>=2.5 Timedelta warning
download()'s ignore_tz docstring explained the parameter's effect on
combining timezones, but never stated what timezone the returned
index actually carries in either case. That's a real gap: since 1.4.0
(#2825, "Fix localized intraday download() always returning UTC"),
ignore_tz=False (the intraday default) tz-converts to the most common
exchange timezone among the requested tickers, not UTC as before -
correct and changelog'd, but an upgrade a caller pinning old behavior
would only discover by diffing output, since the docstring itself
never said what to expect either before or after.

Verified against reindex_dfs(): tz_localize(None) when ignore_tz=True,
tz_convert(tz_mode) (mode of each df's index.tz) when False. No
behavior change, docstring only.
docs: state download()'s actual returned index timezone contract
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.