trader.marketdata.sector module

Sector/industry classification for a symbol (issue #65).

docs/ideas.md’s “Factors a stock analyst uses” inventory names sector and industry as “not fetched — yfinance exposes both on the ticker info, so this is an adapter addition, not research.” This is that addition, shaped the same way marketdata/analysts.py shapes its own yfinance .info read: a small, frozen domain object, a Protocol so a caller can fake it, and a failure that raises MarketDataError rather than ever returning a fabricated value.

Missing coverage is None on each field, never an empty string standing in for “no risk” — an ETF (SPY) or a newly listed symbol yfinance has not yet classified both look this way, and a caller measuring concentration must be able to tell “not computed for this name” apart from a real sector.

class trader.marketdata.sector.SectorInfo(sector, industry)[source]

Bases: object

What yfinance’s .info says about a symbol’s classification.

Both fields are None, independently, when yfinance omits that key — an ETF typically has neither. None is never coerced to “Unknown” here; callers that need a display bucket (trader/reporting/ concentration.py) choose that label themselves, so this module stays a plain reflection of what the provider actually said.

Parameters:
  • sector (str | None)

  • industry (str | None)

sector: str | None
industry: str | None
class trader.marketdata.sector.SectorProvider(*args, **kwargs)[source]

Bases: Protocol

Current sector/industry classification for a symbol.

get_sector_info(symbol)[source]

Raises MarketDataError if the lookup itself fails.

Parameters:

symbol (str)

Return type:

SectorInfo

class trader.marketdata.sector.YFinanceSectorProvider(ticker_factory=None)[source]

Bases: object

Sector/industry from yfinance’s .info. No pandas type escapes.

Caches a successful answer per symbol for this instance’s lifetime (issue #100), the same reasoning and tradeoffs as analysts.YFinanceAnalystProvider: an ETF’s “no classification” is structural, not something that changes cycle to cycle, and re-fetching it forever cost a guaranteed 404 every time for exactly the symbols this class’s own docstring already knew would never have one. No TTL; never cached on an exception.

Parameters:

ticker_factory (Callable[[str], object] | None)

get_sector_info(symbol)[source]
Parameters:

symbol (str)

Return type:

SectorInfo