equity-aggregator 1.0.0__tar.gz → 1.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/PKG-INFO +1 -1
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/pyproject.toml +1 -1
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/fuzzy.py +10 -2
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_fuzzy.py +66 -1
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/uv.lock +1 -1
- equity_aggregator-1.0.0/.claude/settings.local.json +0 -25
- equity_aggregator-1.0.0/debug_yfinance.py +0 -473
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.dockerignore +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.env_example +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.github/workflows/publish-build-release.yml +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.github/workflows/publish-pypi.yml +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.github/workflows/validate-push.yml +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.gitignore +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.python-version +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/Dockerfile +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/LICENCE.txt +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/README.md +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/docker-compose.yml +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/intrinio_equity.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/lseg_equities.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/sec_equity.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/stock_analysis_equity.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/tradingview_equities.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/xetra_equities.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/yfinance_quote_summary_equity.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/yfinance_search_equity.json +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/__main__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/analyzers.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/formatters.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/main.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/models.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/examples/data_integrity_analysis/rendering.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/README.md +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/_utils/_client.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/_utils/_record_types.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/intrinio.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/lseg.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/sec.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/stock_analysis/stock_analysis.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/tradingview.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/xetra.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/api.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/download.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/gleif.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/json.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/quote_summary.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/search.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/auth.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/ranking.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/transport.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/yfinance.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/reference_lookup/exchange_rate_api.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/adapters/data_sources/reference_lookup/openfigi.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/dispatcher.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/main.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/cli/signals.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/_utils/_load_converter.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/_utils/_merge.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/_utils/_merge_config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/_utils/_strategies.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/resolve.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/runner.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/seed.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/canonicalise.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/convert.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/enrich.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/group.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/identify.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/pipeline/transforms/parse.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/retrieval/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/domain/retrieval/retrieval.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/logging_config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/canonical.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/feed_validators.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/gleif_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/intrinio_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/lseg_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/sec_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/stock_analysis_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/tradingview_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/xetra_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/feeds/yfinance_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/raw.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/types.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/schemas/validators.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/_utils.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/cache.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/data_store.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/export.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/src/equity_aggregator/storage/metadata.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/README.md +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/conftest.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/stock_analysis/test_stock_analysis.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/reference_lookup/exchange_rate_api/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/reference_lookup/exchange_rate_api/test_exchange_rate_api.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/reference_lookup/openfigi/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/live/adapters/data_sources/reference_lookup/openfigi/test_openfigi.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/_utils/test_client.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/stock_analysis/test_stock_analysis.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/_helpers.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_api.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_download.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_helpers.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_backoff.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_json.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/test_quote_summary.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/test_search.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_auth.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_ranking.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_session.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_transport.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/reference_lookup/test_exchange_rate_api.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/adapters/data_sources/reference_lookup/test_openfigi.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/cli/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/cli/test_config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/cli/test_dispatcher.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/cli/test_main.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/cli/test_parser.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/_utils/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/_utils/test__merge.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/_utils/test__merge_config.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/_utils/test__strategies.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/_utils/test_load_converter.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/test_resolve.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_canonicalise.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_convert.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_enrich.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_group.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_identify.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/pipeline/transforms/test_parse.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/domain/retrieval/test_retrieval.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_feed_validators.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_gleif_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_intrinio_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_lseg_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_sec_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_stock_analysis_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_tradingview_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_xetra_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/feeds/test_yfinance_feed_data.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/test_canonical.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/test_raw.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/test_types.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/schemas/test_validators.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/__init__.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/test__utils.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/test_cache.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/test_data_store.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/test_export.py +0 -0
- {equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/tests/unit/storage/test_metadata.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: equity-aggregator
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.1
|
|
4
4
|
Summary: Financial equity data aggregation toolkit
|
|
5
5
|
Project-URL: Homepage, https://github.com/gregorykelleher/equity-aggregator
|
|
6
6
|
Project-URL: Repository, https://github.com/gregorykelleher/equity-aggregator
|
|
@@ -70,6 +70,14 @@ def _score_quote(
|
|
|
70
70
|
`name_key`) and the expected name. Applies minimum score thresholds to prevent
|
|
71
71
|
matching completely unrelated equities.
|
|
72
72
|
|
|
73
|
+
Note:
|
|
74
|
+
Symbol comparison uses `partial_ratio` rather than `ratio` because
|
|
75
|
+
exchange symbols follow a `[prefix]ROOT[.suffix]` pattern (e.g.
|
|
76
|
+
`MELE.BR` vs `2MELE`). `partial_ratio` aligns the shorter string
|
|
77
|
+
against the best-matching substring of the longer one, effectively
|
|
78
|
+
matching on the shared root symbol regardless of exchange-specific
|
|
79
|
+
decoration.
|
|
80
|
+
|
|
73
81
|
Args:
|
|
74
82
|
quote (dict): The quote dictionary containing at least a "symbol" key and
|
|
75
83
|
a name field specified by `name_key`.
|
|
@@ -80,12 +88,12 @@ def _score_quote(
|
|
|
80
88
|
Returns:
|
|
81
89
|
tuple[int, str, str]: A tuple of (total_score, actual_symbol, actual_name),
|
|
82
90
|
where total_score is the sum of the symbol and name fuzzy scores.
|
|
83
|
-
Returns (0, symbol, name) if either score is below
|
|
91
|
+
Returns (0, symbol, name) if either score is below its minimum threshold.
|
|
84
92
|
"""
|
|
85
93
|
actual_symbol = quote["symbol"]
|
|
86
94
|
actual_name = quote.get(name_key, "<no-name>")
|
|
87
95
|
|
|
88
|
-
symbol_score = fuzz.
|
|
96
|
+
symbol_score = fuzz.partial_ratio(
|
|
89
97
|
actual_symbol,
|
|
90
98
|
expected_symbol,
|
|
91
99
|
processor=utils.default_process,
|
|
@@ -86,7 +86,7 @@ def test_score_quote_total_matches_component_sum() -> None:
|
|
|
86
86
|
expected_name="Microsoft Corporation",
|
|
87
87
|
)
|
|
88
88
|
|
|
89
|
-
symbol_score = fuzz.
|
|
89
|
+
symbol_score = fuzz.partial_ratio(symbol, "MSFT", processor=rf_utils.default_process)
|
|
90
90
|
name_score = fuzz.WRatio(
|
|
91
91
|
name,
|
|
92
92
|
"Microsoft Corporation",
|
|
@@ -94,3 +94,68 @@ def test_score_quote_total_matches_component_sum() -> None:
|
|
|
94
94
|
)
|
|
95
95
|
|
|
96
96
|
assert total == symbol_score + name_score
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def test_score_quote_accepts_cross_exchange_symbol_variant() -> None:
|
|
100
|
+
"""
|
|
101
|
+
ARRANGE: quote with exchange-decorated symbol (MELE.BR) vs prefixed symbol (2MELE)
|
|
102
|
+
ACT: call _score_quote
|
|
103
|
+
ASSERT: total_score is non-zero (shared root symbol matched via partial_ratio)
|
|
104
|
+
"""
|
|
105
|
+
|
|
106
|
+
quote = {"symbol": "MELE.BR", "longname": "Melexis NV"}
|
|
107
|
+
total, _, _ = _score_quote(
|
|
108
|
+
quote=quote,
|
|
109
|
+
name_key="longname",
|
|
110
|
+
expected_symbol="2MELE",
|
|
111
|
+
expected_name="MELEXIS NV",
|
|
112
|
+
)
|
|
113
|
+
|
|
114
|
+
assert total > 0
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def test_score_quote_rejects_when_name_score_below_threshold() -> None:
|
|
118
|
+
"""
|
|
119
|
+
ARRANGE: quote where the name has no similarity to expected name
|
|
120
|
+
ACT: call _score_quote
|
|
121
|
+
ASSERT: total_score is zero (candidate rejected)
|
|
122
|
+
"""
|
|
123
|
+
|
|
124
|
+
quote = {"symbol": "MELE.BR", "longname": "Unrelated Corp"}
|
|
125
|
+
total, _, _ = _score_quote(
|
|
126
|
+
quote=quote,
|
|
127
|
+
name_key="longname",
|
|
128
|
+
expected_symbol="2MELE",
|
|
129
|
+
expected_name="MELEXIS NV",
|
|
130
|
+
)
|
|
131
|
+
|
|
132
|
+
assert total == 0
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def test_score_quote_substring_symbol_with_similar_name_is_not_rejected() -> None:
|
|
136
|
+
"""
|
|
137
|
+
ARRANGE: quote whose symbol is a superstring of the expected symbol
|
|
138
|
+
AND whose name is similar (META/MET, MetLife/Meta Platforms)
|
|
139
|
+
ACT: call _score_quote
|
|
140
|
+
ASSERT: total_score is non-zero — partial_ratio cannot distinguish these
|
|
141
|
+
by symbol alone; the caller's min_score ranking ensures the exact
|
|
142
|
+
match (MET) outscores the substring match (META)
|
|
143
|
+
|
|
144
|
+
Note:
|
|
145
|
+
This is a known limitation of partial_ratio for very short symbols.
|
|
146
|
+
It is not a regression: fuzz.ratio("META", "MET") = 85.7, which also
|
|
147
|
+
clears the score_cutoff=70 gate. The name gate (WRatio) is the primary
|
|
148
|
+
discriminator, but when two companies share a lexical root (Met-) it
|
|
149
|
+
cannot distinguish them either. In practice, ISIN lookups return the
|
|
150
|
+
correct ticker, so the exact match ranks first.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
quote = {"symbol": "META", "longname": "Meta Platforms Inc"}
|
|
154
|
+
total, _, _ = _score_quote(
|
|
155
|
+
quote=quote,
|
|
156
|
+
name_key="longname",
|
|
157
|
+
expected_symbol="MET",
|
|
158
|
+
expected_name="MetLife Inc",
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
assert total > 0
|
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(uv run pytest:*)",
|
|
5
|
-
"Bash(uv run:*)",
|
|
6
|
-
"Bash(tree:*)",
|
|
7
|
-
"Bash(find:*)",
|
|
8
|
-
"Bash(sqlite3:*)",
|
|
9
|
-
"Bash(xargs basename:*)",
|
|
10
|
-
"Bash(xargs cat:*)",
|
|
11
|
-
"Bash(cat:*)",
|
|
12
|
-
"WebFetch(domain:docs.intrinio.com)",
|
|
13
|
-
"WebFetch(domain:mapping.gleif.org)",
|
|
14
|
-
"WebSearch",
|
|
15
|
-
"WebFetch(domain:www.gleif.org)",
|
|
16
|
-
"Bash(python3 -m py_compile src/equity_aggregator/**/*.py)",
|
|
17
|
-
"Bash(python3 -m pytest:*)",
|
|
18
|
-
"Bash(wc:*)",
|
|
19
|
-
"Bash(grep:*)",
|
|
20
|
-
"Bash(git -C /Users/gregory.kelleher/Documents/equity-aggregator log --oneline -10)"
|
|
21
|
-
],
|
|
22
|
-
"deny": [],
|
|
23
|
-
"ask": []
|
|
24
|
-
}
|
|
25
|
-
}
|
|
@@ -1,473 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
"""
|
|
3
|
-
Debug script to investigate Yahoo Finance API responses for specific tickers.
|
|
4
|
-
|
|
5
|
-
This script tests the YFinance endpoints:
|
|
6
|
-
1. search_url - Search for ticker/company name
|
|
7
|
-
2. quote_summary_url - Detailed quote data endpoint
|
|
8
|
-
3. Validation - Test Pydantic validation and show failures
|
|
9
|
-
|
|
10
|
-
Usage:
|
|
11
|
-
uv run python debug_yfinance.py BKSC
|
|
12
|
-
uv run python debug_yfinance.py AAPL
|
|
13
|
-
uv run python debug_yfinance.py CMC
|
|
14
|
-
"""
|
|
15
|
-
|
|
16
|
-
import asyncio
|
|
17
|
-
import json
|
|
18
|
-
import sys
|
|
19
|
-
|
|
20
|
-
from pydantic import ValidationError
|
|
21
|
-
|
|
22
|
-
from equity_aggregator.adapters.data_sources.enrichment_feeds.yfinance.api.quote_summary import (
|
|
23
|
-
_get_quote_summary_fallback,
|
|
24
|
-
get_quote_summary,
|
|
25
|
-
)
|
|
26
|
-
from equity_aggregator.adapters.data_sources.enrichment_feeds.yfinance.config import (
|
|
27
|
-
FeedConfig,
|
|
28
|
-
)
|
|
29
|
-
from equity_aggregator.adapters.data_sources.enrichment_feeds.yfinance.session import (
|
|
30
|
-
YFSession,
|
|
31
|
-
)
|
|
32
|
-
from equity_aggregator.schemas.feeds.yfinance_feed_data import YFinanceFeedData
|
|
33
|
-
from equity_aggregator.schemas.raw import RawEquity
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
async def debug_ticker(
|
|
37
|
-
ticker: str, query: str | None = None, isin: str | None = None, export: bool = False
|
|
38
|
-
) -> None:
|
|
39
|
-
"""
|
|
40
|
-
Debug Yahoo Finance API endpoints for a specific ticker.
|
|
41
|
-
|
|
42
|
-
Args:
|
|
43
|
-
ticker: The ticker symbol to query (e.g., "BKSC", "AAPL")
|
|
44
|
-
query: Optional search query (defaults to ticker if not provided)
|
|
45
|
-
isin: Optional ISIN to test identifier-based lookup flow
|
|
46
|
-
export: Whether to export raw API responses to JSON files
|
|
47
|
-
"""
|
|
48
|
-
query = query or ticker
|
|
49
|
-
|
|
50
|
-
config = FeedConfig()
|
|
51
|
-
|
|
52
|
-
print("=" * 80)
|
|
53
|
-
print(f"DEBUGGING TICKER: {ticker}")
|
|
54
|
-
print(f"SEARCH QUERY: {query}")
|
|
55
|
-
if isin:
|
|
56
|
-
print(f"ISIN: {isin}")
|
|
57
|
-
print("=" * 80)
|
|
58
|
-
print()
|
|
59
|
-
|
|
60
|
-
session = YFSession(config)
|
|
61
|
-
|
|
62
|
-
try:
|
|
63
|
-
# ===================================================================
|
|
64
|
-
# TEST 1: Search URL
|
|
65
|
-
# ===================================================================
|
|
66
|
-
print("📍 TEST 1: SEARCH URL")
|
|
67
|
-
print(f" URL: {config.search_url}")
|
|
68
|
-
print(f" Query: {query}")
|
|
69
|
-
print("-" * 80)
|
|
70
|
-
|
|
71
|
-
try:
|
|
72
|
-
search_response = await session.get(
|
|
73
|
-
config.search_url,
|
|
74
|
-
params={"q": query},
|
|
75
|
-
)
|
|
76
|
-
print(f" ✓ Status Code: {search_response.status_code}")
|
|
77
|
-
|
|
78
|
-
search_data = search_response.json()
|
|
79
|
-
|
|
80
|
-
# Export search data if requested
|
|
81
|
-
if export:
|
|
82
|
-
import os
|
|
83
|
-
|
|
84
|
-
export_path = "documentation/reference_data/yfinance_search_equity.json"
|
|
85
|
-
os.makedirs(os.path.dirname(export_path), exist_ok=True)
|
|
86
|
-
with open(export_path, "w") as f:
|
|
87
|
-
json.dump(search_data, f, indent=2)
|
|
88
|
-
print(f" ✓ Exported to {export_path}")
|
|
89
|
-
quotes = search_data.get("quotes", [])
|
|
90
|
-
print(f" ✓ Found {len(quotes)} results")
|
|
91
|
-
|
|
92
|
-
if quotes:
|
|
93
|
-
print("\n Results:")
|
|
94
|
-
for i, quote in enumerate(quotes[:5], 1): # Show first 5
|
|
95
|
-
symbol = quote.get("symbol", "N/A")
|
|
96
|
-
name = quote.get("longName") or quote.get("shortName", "N/A")
|
|
97
|
-
quote_type = quote.get("quoteType", "N/A")
|
|
98
|
-
exchange = quote.get("exchange", "N/A")
|
|
99
|
-
print(f" {i}. {symbol} - {name}")
|
|
100
|
-
print(f" Type: {quote_type}, Exchange: {exchange}")
|
|
101
|
-
else:
|
|
102
|
-
print(" ⚠ No results found")
|
|
103
|
-
|
|
104
|
-
except Exception as e:
|
|
105
|
-
print(f" ✗ ERROR: {e}")
|
|
106
|
-
|
|
107
|
-
print()
|
|
108
|
-
|
|
109
|
-
# ===================================================================
|
|
110
|
-
# TEST 2: Quote Summary URL (Primary)
|
|
111
|
-
# ===================================================================
|
|
112
|
-
print("📍 TEST 2: QUOTE SUMMARY URL (PRIMARY)")
|
|
113
|
-
print(f" URL: {config.quote_summary_primary_url}{ticker}")
|
|
114
|
-
print(f" Modules: {len(config.modules)} modules requested")
|
|
115
|
-
print("-" * 80)
|
|
116
|
-
|
|
117
|
-
try:
|
|
118
|
-
summary_url = config.quote_summary_primary_url + ticker
|
|
119
|
-
# Add 30-second timeout to prevent hanging
|
|
120
|
-
summary_response = await asyncio.wait_for(
|
|
121
|
-
session.get(
|
|
122
|
-
summary_url,
|
|
123
|
-
params={
|
|
124
|
-
"modules": ",".join(config.modules),
|
|
125
|
-
"corsDomain": "finance.yahoo.com",
|
|
126
|
-
"formatted": "false",
|
|
127
|
-
"symbol": ticker,
|
|
128
|
-
"lang": "en-US",
|
|
129
|
-
"region": "US",
|
|
130
|
-
},
|
|
131
|
-
),
|
|
132
|
-
timeout=30.0,
|
|
133
|
-
)
|
|
134
|
-
|
|
135
|
-
print(f" ✓ Status Code: {summary_response.status_code}")
|
|
136
|
-
print(
|
|
137
|
-
f" ✓ Content-Type: {summary_response.headers.get('content-type', 'N/A')}"
|
|
138
|
-
)
|
|
139
|
-
print(f" ✓ Content-Length: {len(summary_response.content)} bytes")
|
|
140
|
-
|
|
141
|
-
if summary_response.status_code == 200:
|
|
142
|
-
summary_data = summary_response.json()
|
|
143
|
-
|
|
144
|
-
# Export quote summary data if requested
|
|
145
|
-
if export:
|
|
146
|
-
import os
|
|
147
|
-
|
|
148
|
-
export_path = "documentation/reference_data/yfinance_quote_summary_equity.json"
|
|
149
|
-
os.makedirs(os.path.dirname(export_path), exist_ok=True)
|
|
150
|
-
with open(export_path, "w") as f:
|
|
151
|
-
json.dump(summary_data, f, indent=2)
|
|
152
|
-
print(f" ✓ Exported to {export_path}")
|
|
153
|
-
|
|
154
|
-
result = summary_data.get("quoteSummary", {}).get("result", [])
|
|
155
|
-
error = summary_data.get("quoteSummary", {}).get("error")
|
|
156
|
-
|
|
157
|
-
if error:
|
|
158
|
-
print(f" ✗ API Error: {error}")
|
|
159
|
-
elif result:
|
|
160
|
-
print(f" ✓ Data received for {len(result)} ticker(s)")
|
|
161
|
-
|
|
162
|
-
# Show available modules
|
|
163
|
-
modules_present = list(result[0].keys())
|
|
164
|
-
print(
|
|
165
|
-
f" ✓ Available modules ({len(modules_present)}): {', '.join(modules_present)}"
|
|
166
|
-
)
|
|
167
|
-
|
|
168
|
-
# Flatten all module data to get total field count
|
|
169
|
-
all_fields = {}
|
|
170
|
-
for module_name in modules_present:
|
|
171
|
-
module_data = result[0].get(module_name)
|
|
172
|
-
if isinstance(module_data, dict):
|
|
173
|
-
all_fields.update(module_data)
|
|
174
|
-
|
|
175
|
-
print(f" ✓ Total flattened fields: {len(all_fields)}")
|
|
176
|
-
print(f"\n All fields from quote_summary_url:")
|
|
177
|
-
for field_name in sorted(all_fields.keys()):
|
|
178
|
-
value = all_fields[field_name]
|
|
179
|
-
# Truncate long values
|
|
180
|
-
if isinstance(value, (dict, list)):
|
|
181
|
-
value_str = str(type(value).__name__)
|
|
182
|
-
else:
|
|
183
|
-
value_str = str(value)[:50]
|
|
184
|
-
print(f" {field_name}: {value_str}")
|
|
185
|
-
else:
|
|
186
|
-
print(" ⚠ Empty result array")
|
|
187
|
-
print(
|
|
188
|
-
f" Raw response: {json.dumps(summary_data, indent=2)[:500]}..."
|
|
189
|
-
)
|
|
190
|
-
else:
|
|
191
|
-
print(f" ✗ Non-200 status code")
|
|
192
|
-
print(f" Response preview: {summary_response.text[:500]}...")
|
|
193
|
-
|
|
194
|
-
except Exception as e:
|
|
195
|
-
print(f" ✗ ERROR: {e}")
|
|
196
|
-
|
|
197
|
-
print()
|
|
198
|
-
|
|
199
|
-
# ===================================================================
|
|
200
|
-
# TEST 3: Quote Summary Fallback URL
|
|
201
|
-
# ===================================================================
|
|
202
|
-
print("📍 TEST 3: QUOTE SUMMARY FALLBACK URL")
|
|
203
|
-
print(f" URL: {config.quote_summary_fallback_url}")
|
|
204
|
-
print(f" Ticker: {ticker}")
|
|
205
|
-
print("-" * 80)
|
|
206
|
-
|
|
207
|
-
try:
|
|
208
|
-
fallback_data = await _get_quote_summary_fallback(session, ticker)
|
|
209
|
-
|
|
210
|
-
if fallback_data:
|
|
211
|
-
print(f" ✓ Data received for ticker")
|
|
212
|
-
print(f" ✓ Total fields: {len(fallback_data)}")
|
|
213
|
-
|
|
214
|
-
print(f"\n All fields from quote_summary_fallback_url:")
|
|
215
|
-
for field_name in sorted(fallback_data.keys()):
|
|
216
|
-
value = fallback_data[field_name]
|
|
217
|
-
# Truncate long values
|
|
218
|
-
if isinstance(value, (dict, list)):
|
|
219
|
-
value_str = str(type(value).__name__)
|
|
220
|
-
else:
|
|
221
|
-
value_str = str(value)[:50]
|
|
222
|
-
print(f" {field_name}: {value_str}")
|
|
223
|
-
|
|
224
|
-
# Compare with primary endpoint
|
|
225
|
-
print(f"\n 📊 FIELD COMPARISON:")
|
|
226
|
-
print(f" Primary endpoint would have returned flattened module data")
|
|
227
|
-
print(
|
|
228
|
-
f" Fallback endpoint returns {len(fallback_data)} direct fields"
|
|
229
|
-
)
|
|
230
|
-
|
|
231
|
-
except Exception as e:
|
|
232
|
-
print(f" ✗ ERROR: {e}")
|
|
233
|
-
|
|
234
|
-
print()
|
|
235
|
-
|
|
236
|
-
# ===================================================================
|
|
237
|
-
# TEST 3.5: ISIN-based Lookup (Pipeline Simulation)
|
|
238
|
-
# ===================================================================
|
|
239
|
-
if isin:
|
|
240
|
-
print("📍 TEST 3.5: ISIN-BASED LOOKUP (PIPELINE SIMULATION)")
|
|
241
|
-
print(
|
|
242
|
-
" Simulating actual pipeline flow: search by ISIN → get symbol → fetch data"
|
|
243
|
-
)
|
|
244
|
-
print("-" * 80)
|
|
245
|
-
|
|
246
|
-
try:
|
|
247
|
-
# Search for the ISIN
|
|
248
|
-
isin_search_response = await session.get(
|
|
249
|
-
config.search_url,
|
|
250
|
-
params={"q": isin},
|
|
251
|
-
)
|
|
252
|
-
isin_search_data = isin_search_response.json()
|
|
253
|
-
isin_quotes = isin_search_data.get("quotes", [])
|
|
254
|
-
|
|
255
|
-
# Filter for EQUITY type only (like search_quotes does)
|
|
256
|
-
isin_equities = [
|
|
257
|
-
q for q in isin_quotes if q.get("quoteType") == "EQUITY"
|
|
258
|
-
]
|
|
259
|
-
|
|
260
|
-
print(f" ✓ Searched for ISIN: {isin}")
|
|
261
|
-
print(f" ✓ Found {len(isin_equities)} EQUITY results")
|
|
262
|
-
|
|
263
|
-
if isin_equities:
|
|
264
|
-
print("\n ISIN Search Results:")
|
|
265
|
-
for i, quote in enumerate(isin_equities, 1):
|
|
266
|
-
symbol = quote.get("symbol", "N/A")
|
|
267
|
-
name = quote.get("longname") or quote.get("shortname", "N/A")
|
|
268
|
-
exchange = quote.get("exchange", "N/A")
|
|
269
|
-
print(f" {i}. {symbol} ({exchange}) - {name}")
|
|
270
|
-
|
|
271
|
-
# Pick the first equity (simplified - pipeline does fuzzy matching)
|
|
272
|
-
chosen_symbol = isin_equities[0].get("symbol")
|
|
273
|
-
print(f"\n → Pipeline would fetch data for: {chosen_symbol}")
|
|
274
|
-
|
|
275
|
-
# Now fetch quote summary for this symbol
|
|
276
|
-
print(f"\n Fetching quote summary for {chosen_symbol}...")
|
|
277
|
-
isin_raw_data = await get_quote_summary(session, chosen_symbol)
|
|
278
|
-
|
|
279
|
-
if isin_raw_data:
|
|
280
|
-
print(f" ✓ Data fetched: {len(isin_raw_data)} fields")
|
|
281
|
-
|
|
282
|
-
# Validate this data
|
|
283
|
-
print(f"\n Validating data from ISIN-based lookup...")
|
|
284
|
-
try:
|
|
285
|
-
yf_data = YFinanceFeedData.model_validate(isin_raw_data)
|
|
286
|
-
coerced = yf_data.model_dump()
|
|
287
|
-
_ = RawEquity.model_validate(coerced)
|
|
288
|
-
print(f" ✓ Validation PASSED for {chosen_symbol}")
|
|
289
|
-
except ValidationError as ve:
|
|
290
|
-
print(f" ✗ Validation FAILED for {chosen_symbol}")
|
|
291
|
-
print(
|
|
292
|
-
f"\n ⚠️ THIS IS THE ACTUAL VALIDATION FAILURE IN THE PIPELINE!"
|
|
293
|
-
)
|
|
294
|
-
print(f"\n Failed fields ({len(ve.errors())}):")
|
|
295
|
-
for err in ve.errors():
|
|
296
|
-
field_name = err["loc"][0] if err["loc"] else "unknown"
|
|
297
|
-
error_msg = err["msg"]
|
|
298
|
-
|
|
299
|
-
# Try to get value from either stage
|
|
300
|
-
if field_name in coerced:
|
|
301
|
-
raw_value = coerced.get(field_name)
|
|
302
|
-
else:
|
|
303
|
-
raw_value = isin_raw_data.get(field_name)
|
|
304
|
-
|
|
305
|
-
print(f"\n ❌ Field: {field_name}")
|
|
306
|
-
print(f" Error: {error_msg}")
|
|
307
|
-
print(f" Raw value: {raw_value!r}")
|
|
308
|
-
print(
|
|
309
|
-
f" Value type: {type(raw_value).__name__}"
|
|
310
|
-
)
|
|
311
|
-
|
|
312
|
-
# Show related fields
|
|
313
|
-
if field_name in ["revenue", "revenue_per_share"]:
|
|
314
|
-
print(f" Related fields:")
|
|
315
|
-
for related in ["totalRevenue", "revenuePerShare"]:
|
|
316
|
-
if related in isin_raw_data:
|
|
317
|
-
print(
|
|
318
|
-
f" {related}: {isin_raw_data[related]!r}"
|
|
319
|
-
)
|
|
320
|
-
elif field_name == "trailing_pe":
|
|
321
|
-
print(f" Related fields:")
|
|
322
|
-
for related in ["trailingPE", "forwardPE"]:
|
|
323
|
-
if related in isin_raw_data:
|
|
324
|
-
print(
|
|
325
|
-
f" {related}: {isin_raw_data[related]!r}"
|
|
326
|
-
)
|
|
327
|
-
else:
|
|
328
|
-
print(" ⚠ No EQUITY results found for ISIN")
|
|
329
|
-
|
|
330
|
-
except Exception as e:
|
|
331
|
-
print(f" ✗ ERROR: {e}")
|
|
332
|
-
import traceback
|
|
333
|
-
|
|
334
|
-
traceback.print_exc()
|
|
335
|
-
|
|
336
|
-
print()
|
|
337
|
-
|
|
338
|
-
# ===================================================================
|
|
339
|
-
# TEST 4: Validation Testing
|
|
340
|
-
# ===================================================================
|
|
341
|
-
print("📍 TEST 4: VALIDATION TESTING (Direct Symbol Lookup)")
|
|
342
|
-
print(" Testing Pydantic validation against YFinanceFeedData schema")
|
|
343
|
-
print("-" * 80)
|
|
344
|
-
|
|
345
|
-
try:
|
|
346
|
-
# Fetch raw data using the quote_summary function
|
|
347
|
-
raw_data = await get_quote_summary(session, ticker)
|
|
348
|
-
|
|
349
|
-
if not raw_data:
|
|
350
|
-
print(" ⚠ No data returned from get_quote_summary()")
|
|
351
|
-
else:
|
|
352
|
-
print(f" ✓ Raw data fetched: {len(raw_data)} fields")
|
|
353
|
-
|
|
354
|
-
# Step 1: Try validating with YFinanceFeedData
|
|
355
|
-
print("\n Step 1: Validating with YFinanceFeedData model...")
|
|
356
|
-
try:
|
|
357
|
-
yf_data = YFinanceFeedData.model_validate(raw_data)
|
|
358
|
-
print(" ✓ YFinanceFeedData validation PASSED")
|
|
359
|
-
|
|
360
|
-
# Step 2: Try converting to RawEquity
|
|
361
|
-
print("\n Step 2: Converting to RawEquity model...")
|
|
362
|
-
try:
|
|
363
|
-
coerced = yf_data.model_dump()
|
|
364
|
-
_ = RawEquity.model_validate(coerced)
|
|
365
|
-
print(" ✓ RawEquity validation PASSED")
|
|
366
|
-
print(f" ✓ All validation successful for ticker {ticker}")
|
|
367
|
-
|
|
368
|
-
except ValidationError as ve:
|
|
369
|
-
print(" ✗ RawEquity validation FAILED")
|
|
370
|
-
print(f"\n Failed fields ({len(ve.errors())}):")
|
|
371
|
-
for err in ve.errors():
|
|
372
|
-
field_name = err["loc"][0] if err["loc"] else "unknown"
|
|
373
|
-
error_type = err["type"]
|
|
374
|
-
error_msg = err["msg"]
|
|
375
|
-
|
|
376
|
-
# Get the actual raw value that failed
|
|
377
|
-
raw_value = coerced.get(field_name, "<not found>")
|
|
378
|
-
|
|
379
|
-
print(f"\n ❌ Field: {field_name}")
|
|
380
|
-
print(f" Error: {error_msg}")
|
|
381
|
-
print(f" Type: {error_type}")
|
|
382
|
-
print(f" Raw value: {raw_value!r}")
|
|
383
|
-
print(f" Value type: {type(raw_value).__name__}")
|
|
384
|
-
|
|
385
|
-
except ValidationError as ve:
|
|
386
|
-
print(" ✗ YFinanceFeedData validation FAILED")
|
|
387
|
-
print(f"\n Failed fields ({len(ve.errors())}):")
|
|
388
|
-
for err in ve.errors():
|
|
389
|
-
field_name = err["loc"][0] if err["loc"] else "unknown"
|
|
390
|
-
error_type = err["type"]
|
|
391
|
-
error_msg = err["msg"]
|
|
392
|
-
|
|
393
|
-
# Get the actual raw value that failed
|
|
394
|
-
raw_value = raw_data.get(field_name, "<not found>")
|
|
395
|
-
|
|
396
|
-
print(f"\n ❌ Field: {field_name}")
|
|
397
|
-
print(f" Error: {error_msg}")
|
|
398
|
-
print(f" Type: {error_type}")
|
|
399
|
-
print(f" Raw value: {raw_value!r}")
|
|
400
|
-
print(f" Value type: {type(raw_value).__name__}")
|
|
401
|
-
|
|
402
|
-
# Show context: what other related fields look like
|
|
403
|
-
if field_name in ["revenue", "revenue_per_share"]:
|
|
404
|
-
print(f" Related fields:")
|
|
405
|
-
for related in [
|
|
406
|
-
"totalRevenue",
|
|
407
|
-
"revenuePerShare",
|
|
408
|
-
"revenue",
|
|
409
|
-
"revenue_per_share",
|
|
410
|
-
]:
|
|
411
|
-
if related in raw_data:
|
|
412
|
-
print(
|
|
413
|
-
f" {related}: {raw_data[related]!r}"
|
|
414
|
-
)
|
|
415
|
-
elif field_name == "trailing_pe":
|
|
416
|
-
print(f" Related fields:")
|
|
417
|
-
for related in ["trailingPE", "trailing_pe", "forwardPE"]:
|
|
418
|
-
if related in raw_data:
|
|
419
|
-
print(
|
|
420
|
-
f" {related}: {raw_data[related]!r}"
|
|
421
|
-
)
|
|
422
|
-
|
|
423
|
-
except Exception as e:
|
|
424
|
-
print(f" ✗ ERROR: {e}")
|
|
425
|
-
import traceback
|
|
426
|
-
|
|
427
|
-
traceback.print_exc()
|
|
428
|
-
|
|
429
|
-
print()
|
|
430
|
-
print("=" * 80)
|
|
431
|
-
print("DEBUG COMPLETE")
|
|
432
|
-
print("=" * 80)
|
|
433
|
-
|
|
434
|
-
finally:
|
|
435
|
-
await session.aclose()
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
async def main() -> None:
|
|
439
|
-
"""Main entry point for the debug script."""
|
|
440
|
-
if len(sys.argv) < 2:
|
|
441
|
-
print(
|
|
442
|
-
"Usage: uv run python debug_yfinance.py TICKER [QUERY] [--isin ISIN] [--export]"
|
|
443
|
-
)
|
|
444
|
-
print("\nExamples:")
|
|
445
|
-
print(" uv run python debug_yfinance.py BKSC")
|
|
446
|
-
print(" uv run python debug_yfinance.py AIT --isin GG00BB0RDB98")
|
|
447
|
-
print(" uv run python debug_yfinance.py CMC --isin GB00BL6NGV24")
|
|
448
|
-
print(" uv run python debug_yfinance.py AAPL --export")
|
|
449
|
-
sys.exit(1)
|
|
450
|
-
|
|
451
|
-
ticker = sys.argv[1].upper()
|
|
452
|
-
query = None
|
|
453
|
-
isin = None
|
|
454
|
-
export = False
|
|
455
|
-
|
|
456
|
-
# Parse optional arguments
|
|
457
|
-
i = 2
|
|
458
|
-
while i < len(sys.argv):
|
|
459
|
-
if sys.argv[i] == "--isin" and i + 1 < len(sys.argv):
|
|
460
|
-
isin = sys.argv[i + 1]
|
|
461
|
-
i += 2
|
|
462
|
-
elif sys.argv[i] == "--export":
|
|
463
|
-
export = True
|
|
464
|
-
i += 1
|
|
465
|
-
else:
|
|
466
|
-
query = sys.argv[i]
|
|
467
|
-
i += 1
|
|
468
|
-
|
|
469
|
-
await debug_ticker(ticker, query, isin, export)
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
if __name__ == "__main__":
|
|
473
|
-
asyncio.run(main())
|
|
File without changes
|
|
File without changes
|
{equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/.github/workflows/publish-build-release.yml
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/lseg_equities.json
RENAMED
|
File without changes
|
{equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/sec_equity.json
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{equity_aggregator-1.0.0 → equity_aggregator-1.0.1}/documentation/reference_data/xetra_equities.json
RENAMED
|
File without changes
|