equity-aggregator 0.1.7__tar.gz → 0.1.8__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-0.1.7 → equity_aggregator-0.1.8}/PKG-INFO +1 -1
- equity_aggregator-0.1.8/examples/data_integrity_analysis/__init__.py +24 -0
- equity_aggregator-0.1.8/examples/data_integrity_analysis/__main__.py +6 -0
- equity_aggregator-0.1.7/examples/data_integrity_analysis.py → equity_aggregator-0.1.8/examples/data_integrity_analysis/analyzers.py +18 -408
- equity_aggregator-0.1.8/examples/data_integrity_analysis/formatters.py +224 -0
- equity_aggregator-0.1.8/examples/data_integrity_analysis/main.py +102 -0
- equity_aggregator-0.1.8/examples/data_integrity_analysis/models.py +60 -0
- equity_aggregator-0.1.8/examples/data_integrity_analysis/rendering.py +73 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/pyproject.toml +1 -1
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/uv.lock +1 -1
- equity_aggregator-0.1.7/documentation/reference_data/tiprank_equity.json +0 -474
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.dockerignore +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.env_example +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/publish-build-release.yml +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/publish-pypi.yml +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/validate-push.yml +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.gitignore +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.python-version +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/Dockerfile +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/LICENCE.txt +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/README.md +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/docker-compose.yml +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/intrinio_equity.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/lseg_equities.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/sec_equity.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/stock_analysis_equity.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/tradingview_equities.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/xetra_equities.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/yfinance_quote_summary_equity.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/yfinance_search_equity.json +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/README.md +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/_client.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/_record_types.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/intrinio.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/lseg.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/sec.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/stock_analysis/stock_analysis.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/tradingview.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/xetra.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/api.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/download.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/gleif.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/fuzzy.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/json.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/quote_summary.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/search.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/auth.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/ranking.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/transport.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/yfinance.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/exchange_rate_api.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/openfigi.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/dispatcher.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/main.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/signals.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_load_converter.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_merge.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_merge_config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_strategies.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/resolve.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/runner.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/seed.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/canonicalise.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/convert.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/enrich.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/group.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/identify.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/parse.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/retrieval/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/retrieval/retrieval.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/logging_config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/canonical.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/feed_validators.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/gleif_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/intrinio_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/lseg_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/sec_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/stock_analysis_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/tradingview_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/xetra_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/yfinance_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/raw.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/types.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/validators.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/_utils.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/cache.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/data_store.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/export.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/metadata.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/README.md +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/conftest.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/stock_analysis/test_stock_analysis.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/exchange_rate_api/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/exchange_rate_api/test_exchange_rate_api.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/openfigi/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/openfigi/test_openfigi.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/_utils/test_client.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/stock_analysis/test_stock_analysis.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/_helpers.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_api.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_download.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_helpers.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_backoff.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_fuzzy.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_json.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/test_quote_summary.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/test_search.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_auth.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_ranking.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_session.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_transport.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/test_exchange_rate_api.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/test_openfigi.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_dispatcher.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_main.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_parser.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__merge.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__merge_config.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__strategies.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test_load_converter.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/test_resolve.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_canonicalise.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_convert.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_enrich.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_group.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_identify.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_parse.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/retrieval/test_retrieval.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_feed_validators.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_gleif_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_intrinio_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_lseg_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_sec_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_stock_analysis_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_tradingview_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_xetra_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_yfinance_feed_data.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_canonical.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_raw.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_types.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_validators.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/__init__.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test__utils.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_cache.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_data_store.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_export.py +0 -0
- {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/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: 0.1.
|
|
3
|
+
Version: 0.1.8
|
|
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
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# data_integrity_analysis/__init__.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Data Integrity Analysis package for Equity Aggregator.
|
|
5
|
+
|
|
6
|
+
This package provides comprehensive data quality analysis for canonical equity
|
|
7
|
+
records, examining financial outliers, temporal anomalies, data consistency,
|
|
8
|
+
identifier quality, and completeness metrics.
|
|
9
|
+
|
|
10
|
+
Usage:
|
|
11
|
+
python -m examples.data_integrity_analysis
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
from .main import main, run_analysis
|
|
15
|
+
from .models import AnalysisSettings, Finding, SectionReport, default_settings
|
|
16
|
+
|
|
17
|
+
__all__ = [
|
|
18
|
+
"AnalysisSettings",
|
|
19
|
+
"Finding",
|
|
20
|
+
"SectionReport",
|
|
21
|
+
"default_settings",
|
|
22
|
+
"main",
|
|
23
|
+
"run_analysis",
|
|
24
|
+
]
|
|
@@ -1,295 +1,27 @@
|
|
|
1
|
-
#
|
|
1
|
+
# data_integrity_analysis/analyzers.py
|
|
2
2
|
|
|
3
3
|
from collections import Counter, defaultdict
|
|
4
|
-
from collections.abc import
|
|
5
|
-
from dataclasses import dataclass
|
|
4
|
+
from collections.abc import Sequence
|
|
6
5
|
from decimal import Decimal
|
|
7
6
|
from itertools import islice
|
|
8
7
|
from statistics import mean, median, stdev
|
|
9
8
|
|
|
10
9
|
from equity_aggregator import CanonicalEquity
|
|
11
|
-
from equity_aggregator.storage import load_canonical_equities
|
|
12
10
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
dividend_yield_alert: Decimal = Decimal("15")
|
|
28
|
-
profit_margin_high: Decimal = Decimal("100")
|
|
29
|
-
profit_margin_low: Decimal = Decimal("-100")
|
|
30
|
-
price_tolerance: Decimal = Decimal("1.1")
|
|
31
|
-
price_to_min_factor: Decimal = Decimal("0.9")
|
|
32
|
-
isin_length: int = 12
|
|
33
|
-
cusip_length: int = 9
|
|
34
|
-
lei_length: int = 20
|
|
35
|
-
penny_stock_threshold: Decimal = Decimal("0.01")
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
def default_settings() -> AnalysisSettings:
|
|
39
|
-
"""
|
|
40
|
-
Return default analysis thresholds.
|
|
41
|
-
|
|
42
|
-
Returns:
|
|
43
|
-
Default configuration values.
|
|
44
|
-
"""
|
|
45
|
-
return AnalysisSettings()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
@dataclass(frozen=True)
|
|
49
|
-
class Finding:
|
|
50
|
-
"""Captures a single insight or anomaly."""
|
|
51
|
-
|
|
52
|
-
message: str
|
|
53
|
-
highlights: tuple[str, ...] = ()
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
@dataclass(frozen=True)
|
|
57
|
-
class SectionReport:
|
|
58
|
-
"""Structured results for an analysis section."""
|
|
59
|
-
|
|
60
|
-
title: str
|
|
61
|
-
findings: tuple[Finding, ...]
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def limit_items(items: Iterable[str], limit: int) -> tuple[str, ...]:
|
|
65
|
-
"""
|
|
66
|
-
Limit items to specified maximum count.
|
|
67
|
-
|
|
68
|
-
Args:
|
|
69
|
-
items: Items to limit.
|
|
70
|
-
limit: Maximum count.
|
|
71
|
-
|
|
72
|
-
Returns:
|
|
73
|
-
Limited items.
|
|
74
|
-
"""
|
|
75
|
-
return tuple(islice(items, limit))
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def format_equity(eq: CanonicalEquity) -> str:
|
|
79
|
-
"""
|
|
80
|
-
Format equity as 'Name (SYMBOL)'.
|
|
81
|
-
|
|
82
|
-
Args:
|
|
83
|
-
eq: Canonical equity to format.
|
|
84
|
-
|
|
85
|
-
Returns:
|
|
86
|
-
Formatted equity string.
|
|
87
|
-
"""
|
|
88
|
-
name = (eq.identity.name or "Unknown")[:40]
|
|
89
|
-
symbol = eq.identity.symbol or "N/A"
|
|
90
|
-
return f"{name} ({symbol})"
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
def format_equity_with_figi(eq: CanonicalEquity) -> str:
|
|
94
|
-
"""
|
|
95
|
-
Format equity as 'Name (SYMBOL) [FIGI]'.
|
|
96
|
-
|
|
97
|
-
Args:
|
|
98
|
-
eq: Canonical equity to format.
|
|
99
|
-
|
|
100
|
-
Returns:
|
|
101
|
-
Formatted equity string with FIGI.
|
|
102
|
-
"""
|
|
103
|
-
name = (eq.identity.name or "Unknown")[:40]
|
|
104
|
-
symbol = eq.identity.symbol or "N/A"
|
|
105
|
-
figi = eq.identity.share_class_figi or "No FIGI"
|
|
106
|
-
return f"{name} ({symbol}) [{figi}]"
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
def format_currency(value: Decimal | float) -> str:
|
|
110
|
-
"""
|
|
111
|
-
Format value as currency with thousands separators.
|
|
112
|
-
|
|
113
|
-
Args:
|
|
114
|
-
value: Monetary amount.
|
|
115
|
-
|
|
116
|
-
Returns:
|
|
117
|
-
Formatted currency string.
|
|
118
|
-
"""
|
|
119
|
-
number = float(value)
|
|
120
|
-
return f"${int(number):,}" if number.is_integer() else f"${number:,.2f}"
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
def format_percentage(value: float) -> str:
|
|
124
|
-
"""
|
|
125
|
-
Format value as percentage with one decimal place.
|
|
126
|
-
|
|
127
|
-
Args:
|
|
128
|
-
value: Percentage value.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
Formatted percentage string.
|
|
132
|
-
"""
|
|
133
|
-
return f"{value:.1f}%"
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
def format_coverage_table(items: list[tuple[str, int, int]]) -> tuple[str, ...]:
|
|
137
|
-
"""
|
|
138
|
-
Format coverage data as aligned table rows.
|
|
139
|
-
|
|
140
|
-
Args:
|
|
141
|
-
items: List of (label, count, total) tuples.
|
|
142
|
-
|
|
143
|
-
Returns:
|
|
144
|
-
Formatted table rows.
|
|
145
|
-
"""
|
|
146
|
-
if not items:
|
|
147
|
-
return ()
|
|
148
|
-
|
|
149
|
-
max_label = max(len(label) for label, _, _ in items)
|
|
150
|
-
max_count = max(len(f"{count:,}") for _, count, _ in items)
|
|
151
|
-
max_total = max(len(f"{total:,}") for _, _, total in items)
|
|
152
|
-
|
|
153
|
-
return tuple(
|
|
154
|
-
_format_coverage_row(label, count, total, (max_label, max_count, max_total))
|
|
155
|
-
for label, count, total in items
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
def _format_coverage_row(
|
|
160
|
-
label: str,
|
|
161
|
-
count: int,
|
|
162
|
-
total: int,
|
|
163
|
-
widths: tuple[int, int, int],
|
|
164
|
-
) -> str:
|
|
165
|
-
"""
|
|
166
|
-
Format a single coverage table row.
|
|
167
|
-
|
|
168
|
-
Args:
|
|
169
|
-
label: Field label.
|
|
170
|
-
count: Number of populated instances.
|
|
171
|
-
total: Total number of instances.
|
|
172
|
-
widths: Column widths (label, count, total).
|
|
173
|
-
|
|
174
|
-
Returns:
|
|
175
|
-
Formatted row string.
|
|
176
|
-
"""
|
|
177
|
-
max_label, max_count, max_total = widths
|
|
178
|
-
percentage = (count / total * 100) if total > 0 else 0.0
|
|
179
|
-
count_str = f"{count:,}".rjust(max_count)
|
|
180
|
-
total_str = f"{total:,}".rjust(max_total)
|
|
181
|
-
return (
|
|
182
|
-
f"{label.ljust(max_label)} {count_str} / {total_str} "
|
|
183
|
-
f"({format_percentage(percentage)})"
|
|
184
|
-
)
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
def describe_price_vs_max(eq: CanonicalEquity) -> str:
|
|
188
|
-
"""
|
|
189
|
-
Describe price relative to 52-week maximum.
|
|
190
|
-
|
|
191
|
-
Args:
|
|
192
|
-
eq: Canonical equity.
|
|
193
|
-
|
|
194
|
-
Returns:
|
|
195
|
-
Formatted comparison string.
|
|
196
|
-
"""
|
|
197
|
-
price = eq.financials.last_price
|
|
198
|
-
maximum = eq.financials.fifty_two_week_max
|
|
199
|
-
return f"{format_equity(eq)} -> price {price} vs max {maximum}"
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
def describe_price_vs_min(eq: CanonicalEquity) -> str:
|
|
203
|
-
"""
|
|
204
|
-
Describe price relative to 52-week minimum.
|
|
205
|
-
|
|
206
|
-
Args:
|
|
207
|
-
eq: Canonical equity.
|
|
208
|
-
|
|
209
|
-
Returns:
|
|
210
|
-
Formatted comparison string.
|
|
211
|
-
"""
|
|
212
|
-
price = eq.financials.last_price
|
|
213
|
-
minimum = eq.financials.fifty_two_week_min
|
|
214
|
-
return f"{format_equity(eq)} -> price {price} vs min {minimum}"
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
def describe_range_bounds(eq: CanonicalEquity) -> str:
|
|
218
|
-
"""
|
|
219
|
-
Describe 52-week price range.
|
|
220
|
-
|
|
221
|
-
Args:
|
|
222
|
-
eq: Canonical equity.
|
|
223
|
-
|
|
224
|
-
Returns:
|
|
225
|
-
Formatted range string.
|
|
226
|
-
"""
|
|
227
|
-
minimum = eq.financials.fifty_two_week_min
|
|
228
|
-
maximum = eq.financials.fifty_two_week_max
|
|
229
|
-
return f"{format_equity(eq)} -> min {minimum}, max {maximum}"
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
def describe_cap_gap(eq: CanonicalEquity) -> str:
|
|
233
|
-
"""
|
|
234
|
-
Describe market cap without corresponding price.
|
|
235
|
-
|
|
236
|
-
Args:
|
|
237
|
-
eq: Canonical equity.
|
|
238
|
-
|
|
239
|
-
Returns:
|
|
240
|
-
Formatted gap description.
|
|
241
|
-
"""
|
|
242
|
-
cap_value = eq.financials.market_cap
|
|
243
|
-
return f"{format_equity(eq)} -> cap {format_currency(cap_value)}, price missing"
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
def score_equity_completeness(equity: CanonicalEquity) -> int:
|
|
247
|
-
"""
|
|
248
|
-
Calculate completeness score based on populated fields.
|
|
249
|
-
|
|
250
|
-
Args:
|
|
251
|
-
equity: Canonical equity to score.
|
|
252
|
-
|
|
253
|
-
Returns:
|
|
254
|
-
Completeness score (higher is more complete).
|
|
255
|
-
"""
|
|
256
|
-
identity_score = sum(
|
|
257
|
-
1
|
|
258
|
-
for field in (
|
|
259
|
-
equity.identity.name,
|
|
260
|
-
equity.identity.isin,
|
|
261
|
-
equity.identity.cusip,
|
|
262
|
-
equity.identity.cik,
|
|
263
|
-
equity.identity.lei,
|
|
264
|
-
)
|
|
265
|
-
if field
|
|
266
|
-
)
|
|
267
|
-
financial_score = sum(
|
|
268
|
-
1
|
|
269
|
-
for field in (
|
|
270
|
-
equity.financials.sector,
|
|
271
|
-
equity.financials.last_price,
|
|
272
|
-
equity.financials.trailing_pe,
|
|
273
|
-
equity.financials.dividend_yield,
|
|
274
|
-
)
|
|
275
|
-
if field
|
|
276
|
-
)
|
|
277
|
-
market_cap_bonus = 2 if equity.financials.market_cap else 0
|
|
278
|
-
return identity_score + financial_score + market_cap_bonus
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
def print_separator(title: str) -> None:
|
|
282
|
-
"""
|
|
283
|
-
Print formatted section separator.
|
|
284
|
-
|
|
285
|
-
Args:
|
|
286
|
-
title: Section heading.
|
|
287
|
-
"""
|
|
288
|
-
print()
|
|
289
|
-
print()
|
|
290
|
-
print("─" * 80)
|
|
291
|
-
print(f" {title.upper()}")
|
|
292
|
-
print("─" * 80)
|
|
11
|
+
from .formatters import (
|
|
12
|
+
describe_cap_gap,
|
|
13
|
+
describe_price_vs_max,
|
|
14
|
+
describe_price_vs_min,
|
|
15
|
+
describe_range_bounds,
|
|
16
|
+
format_coverage_table,
|
|
17
|
+
format_currency,
|
|
18
|
+
format_equity,
|
|
19
|
+
format_equity_with_figi,
|
|
20
|
+
format_percentage,
|
|
21
|
+
limit_items,
|
|
22
|
+
score_equity_completeness,
|
|
23
|
+
)
|
|
24
|
+
from .models import AnalysisSettings, Finding, SectionReport
|
|
293
25
|
|
|
294
26
|
|
|
295
27
|
def build_dataset_overview(equities: Sequence[CanonicalEquity]) -> SectionReport:
|
|
@@ -1422,9 +1154,7 @@ def detect_cap_without_price(
|
|
|
1422
1154
|
def detect_missing_price_and_cap(
|
|
1423
1155
|
equities: Sequence[CanonicalEquity],
|
|
1424
1156
|
) -> tuple[Finding, ...]:
|
|
1425
|
-
"""
|
|
1426
|
-
Report equities missing both price and market cap.
|
|
1427
|
-
"""
|
|
1157
|
+
"""Report equities missing both price and market cap."""
|
|
1428
1158
|
|
|
1429
1159
|
missing = [
|
|
1430
1160
|
eq
|
|
@@ -1509,13 +1239,10 @@ def analyse_cross_field_logic(
|
|
|
1509
1239
|
)
|
|
1510
1240
|
return SectionReport("Cross-field Logic Consistency", findings)
|
|
1511
1241
|
|
|
1512
|
-
|
|
1513
1242
|
def identity_completeness(
|
|
1514
1243
|
equities: Sequence[CanonicalEquity],
|
|
1515
1244
|
) -> tuple[Finding, ...]:
|
|
1516
|
-
"""
|
|
1517
|
-
Summarise completion of core identity fields.
|
|
1518
|
-
"""
|
|
1245
|
+
"""Summarise completion of core identity fields."""
|
|
1519
1246
|
|
|
1520
1247
|
total = len(equities)
|
|
1521
1248
|
if total == 0:
|
|
@@ -1693,120 +1420,3 @@ def analyse_currency_and_geography(
|
|
|
1693
1420
|
|
|
1694
1421
|
findings = currency_distribution(equities) + geography_proxies(equities)
|
|
1695
1422
|
return SectionReport("Currency and Geography", findings)
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
def run_analysis(
|
|
1699
|
-
equities: Sequence[CanonicalEquity],
|
|
1700
|
-
settings: AnalysisSettings | None = None,
|
|
1701
|
-
) -> tuple[SectionReport, ...]:
|
|
1702
|
-
"""
|
|
1703
|
-
Execute complete data integrity analysis suite.
|
|
1704
|
-
|
|
1705
|
-
Args:
|
|
1706
|
-
equities: Equities to analyse.
|
|
1707
|
-
settings: Analysis thresholds (defaults to standard settings).
|
|
1708
|
-
|
|
1709
|
-
Returns:
|
|
1710
|
-
Ordered section reports with findings.
|
|
1711
|
-
"""
|
|
1712
|
-
active_settings = settings or default_settings()
|
|
1713
|
-
|
|
1714
|
-
return (
|
|
1715
|
-
build_dataset_overview(equities),
|
|
1716
|
-
analyse_financial_outliers(equities, active_settings),
|
|
1717
|
-
detect_temporal_anomalies(equities, active_settings),
|
|
1718
|
-
detect_extreme_financial_values(equities, active_settings),
|
|
1719
|
-
analyse_data_consistency(equities, active_settings),
|
|
1720
|
-
analyse_identifier_quality(equities, active_settings),
|
|
1721
|
-
analyse_cross_field_logic(equities, active_settings),
|
|
1722
|
-
analyse_data_quality(equities, active_settings),
|
|
1723
|
-
analyse_currency_and_geography(equities),
|
|
1724
|
-
)
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
def render_finding(finding: Finding, *, add_spacing: bool) -> None:
|
|
1728
|
-
"""
|
|
1729
|
-
Render finding with message and highlights.
|
|
1730
|
-
|
|
1731
|
-
Args:
|
|
1732
|
-
finding: Finding to render.
|
|
1733
|
-
add_spacing: Whether to add spacing before finding.
|
|
1734
|
-
"""
|
|
1735
|
-
if add_spacing:
|
|
1736
|
-
print()
|
|
1737
|
-
print(f"\n • {finding.message}")
|
|
1738
|
-
if finding.highlights:
|
|
1739
|
-
print()
|
|
1740
|
-
for highlight in finding.highlights:
|
|
1741
|
-
print(f" {highlight}")
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
def render_reports(reports: Sequence[SectionReport]) -> None:
|
|
1745
|
-
"""
|
|
1746
|
-
Render analysis reports to stdout.
|
|
1747
|
-
|
|
1748
|
-
Args:
|
|
1749
|
-
reports: Section reports to render.
|
|
1750
|
-
"""
|
|
1751
|
-
for report in reports:
|
|
1752
|
-
print_separator(report.title)
|
|
1753
|
-
if not report.findings:
|
|
1754
|
-
print("\n ✓ No notable findings in this section.\n")
|
|
1755
|
-
continue
|
|
1756
|
-
for idx, finding in enumerate(report.findings, 1):
|
|
1757
|
-
render_finding(finding, add_spacing=(idx > 1))
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
def print_summary_header(total_equities: int, reports: Sequence[SectionReport]) -> None:
|
|
1761
|
-
"""
|
|
1762
|
-
Print analysis summary header.
|
|
1763
|
-
|
|
1764
|
-
Args:
|
|
1765
|
-
total_equities: Total number of equities analysed.
|
|
1766
|
-
reports: Section reports for summary statistics.
|
|
1767
|
-
"""
|
|
1768
|
-
total_findings = sum(len(report.findings) for report in reports)
|
|
1769
|
-
sections_with_findings = sum(1 for report in reports if report.findings)
|
|
1770
|
-
|
|
1771
|
-
print("\n" + "=" * 80)
|
|
1772
|
-
print(" EQUITY AGGREGATOR DATA INTEGRITY ANALYSIS")
|
|
1773
|
-
print("=" * 80)
|
|
1774
|
-
print(f"\n Dataset Size: {total_equities:,} equities")
|
|
1775
|
-
print(f" Sections Analysed: {len(reports)}")
|
|
1776
|
-
print(f" Sections with Issues: {sections_with_findings}")
|
|
1777
|
-
print(f" Total Findings: {total_findings}")
|
|
1778
|
-
print()
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
def main() -> None:
|
|
1782
|
-
"""
|
|
1783
|
-
Run data integrity analysis on stored canonical equities.
|
|
1784
|
-
|
|
1785
|
-
Loads equities from local database and generates comprehensive
|
|
1786
|
-
analysis report covering multiple data quality dimensions.
|
|
1787
|
-
"""
|
|
1788
|
-
try:
|
|
1789
|
-
equities = load_canonical_equities(refresh_fn=None)
|
|
1790
|
-
except Exception as exc: # pragma: no cover - defensive for CLI usage
|
|
1791
|
-
print(f"\n✗ Failed to load canonical equities: {exc}")
|
|
1792
|
-
print(
|
|
1793
|
-
" Ensure the local database exists at"
|
|
1794
|
-
" ~/Library/Application Support/equity-aggregator/data_store.db\n",
|
|
1795
|
-
)
|
|
1796
|
-
return
|
|
1797
|
-
|
|
1798
|
-
if not equities:
|
|
1799
|
-
print("\n✗ No canonical equities were loaded; aborting analysis.")
|
|
1800
|
-
print(" Run 'equity-aggregator download' to populate the data store.\n")
|
|
1801
|
-
return
|
|
1802
|
-
|
|
1803
|
-
reports = run_analysis(equities, default_settings())
|
|
1804
|
-
print_summary_header(len(equities), reports)
|
|
1805
|
-
render_reports(reports)
|
|
1806
|
-
print("\n" + "=" * 80)
|
|
1807
|
-
print(" Analysis complete.")
|
|
1808
|
-
print("=" * 80 + "\n")
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
if __name__ == "__main__":
|
|
1812
|
-
main()
|