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.
Files changed (249) hide show
  1. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/PKG-INFO +1 -1
  2. equity_aggregator-0.1.8/examples/data_integrity_analysis/__init__.py +24 -0
  3. equity_aggregator-0.1.8/examples/data_integrity_analysis/__main__.py +6 -0
  4. equity_aggregator-0.1.7/examples/data_integrity_analysis.py → equity_aggregator-0.1.8/examples/data_integrity_analysis/analyzers.py +18 -408
  5. equity_aggregator-0.1.8/examples/data_integrity_analysis/formatters.py +224 -0
  6. equity_aggregator-0.1.8/examples/data_integrity_analysis/main.py +102 -0
  7. equity_aggregator-0.1.8/examples/data_integrity_analysis/models.py +60 -0
  8. equity_aggregator-0.1.8/examples/data_integrity_analysis/rendering.py +73 -0
  9. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/pyproject.toml +1 -1
  10. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/uv.lock +1 -1
  11. equity_aggregator-0.1.7/documentation/reference_data/tiprank_equity.json +0 -474
  12. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.dockerignore +0 -0
  13. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.env_example +0 -0
  14. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/publish-build-release.yml +0 -0
  15. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/publish-pypi.yml +0 -0
  16. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.github/workflows/validate-push.yml +0 -0
  17. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.gitignore +0 -0
  18. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/.python-version +0 -0
  19. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/Dockerfile +0 -0
  20. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/LICENCE.txt +0 -0
  21. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/README.md +0 -0
  22. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/docker-compose.yml +0 -0
  23. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/intrinio_equity.json +0 -0
  24. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/lseg_equities.json +0 -0
  25. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/sec_equity.json +0 -0
  26. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/stock_analysis_equity.json +0 -0
  27. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/tradingview_equities.json +0 -0
  28. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/xetra_equities.json +0 -0
  29. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/yfinance_quote_summary_equity.json +0 -0
  30. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/documentation/reference_data/yfinance_search_equity.json +0 -0
  31. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/README.md +0 -0
  32. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/__init__.py +0 -0
  33. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/__init__.py +0 -0
  34. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/__init__.py +0 -0
  35. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/__init__.py +0 -0
  36. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/_client.py +0 -0
  37. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/_utils/_record_types.py +0 -0
  38. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/__init__.py +0 -0
  39. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
  40. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
  41. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/backoff.py +0 -0
  42. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/_utils/parser.py +0 -0
  43. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/intrinio.py +0 -0
  44. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/intrinio/session.py +0 -0
  45. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
  46. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
  47. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/backoff.py +0 -0
  48. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/_utils/parser.py +0 -0
  49. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/lseg.py +0 -0
  50. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/lseg/session.py +0 -0
  51. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
  52. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/sec/sec.py +0 -0
  53. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
  54. {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
  55. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
  56. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/tradingview/tradingview.py +0 -0
  57. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
  58. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/discovery_feeds/xetra/xetra.py +0 -0
  59. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
  60. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
  61. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/api.py +0 -0
  62. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/download.py +0 -0
  63. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/gleif.py +0 -0
  64. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/gleif/parser.py +0 -0
  65. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
  66. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
  67. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/backoff.py +0 -0
  68. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/fuzzy.py +0 -0
  69. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/_utils/json.py +0 -0
  70. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
  71. {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
  72. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/api/search.py +0 -0
  73. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/auth.py +0 -0
  74. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/config.py +0 -0
  75. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/ranking.py +0 -0
  76. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/session.py +0 -0
  77. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/transport.py +0 -0
  78. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/enrichment_feeds/yfinance/yfinance.py +0 -0
  79. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/__init__.py +0 -0
  80. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/exchange_rate_api.py +0 -0
  81. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/adapters/data_sources/reference_lookup/openfigi.py +0 -0
  82. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/__init__.py +0 -0
  83. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/config.py +0 -0
  84. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/dispatcher.py +0 -0
  85. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/main.py +0 -0
  86. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/parser.py +0 -0
  87. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/cli/signals.py +0 -0
  88. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/__init__.py +0 -0
  89. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/__init__.py +0 -0
  90. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_load_converter.py +0 -0
  91. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_merge.py +0 -0
  92. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_merge_config.py +0 -0
  93. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/_utils/_strategies.py +0 -0
  94. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/__init__.py +0 -0
  95. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/resolve.py +0 -0
  96. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/runner.py +0 -0
  97. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/seed.py +0 -0
  98. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/__init__.py +0 -0
  99. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/canonicalise.py +0 -0
  100. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/convert.py +0 -0
  101. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/enrich.py +0 -0
  102. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/group.py +0 -0
  103. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/identify.py +0 -0
  104. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/pipeline/transforms/parse.py +0 -0
  105. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/retrieval/__init__.py +0 -0
  106. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/domain/retrieval/retrieval.py +0 -0
  107. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/logging_config.py +0 -0
  108. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/__init__.py +0 -0
  109. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/canonical.py +0 -0
  110. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/__init__.py +0 -0
  111. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/feed_validators.py +0 -0
  112. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/gleif_feed_data.py +0 -0
  113. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/intrinio_feed_data.py +0 -0
  114. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/lseg_feed_data.py +0 -0
  115. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/sec_feed_data.py +0 -0
  116. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/stock_analysis_feed_data.py +0 -0
  117. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/tradingview_feed_data.py +0 -0
  118. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/xetra_feed_data.py +0 -0
  119. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/feeds/yfinance_feed_data.py +0 -0
  120. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/raw.py +0 -0
  121. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/types.py +0 -0
  122. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/schemas/validators.py +0 -0
  123. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/__init__.py +0 -0
  124. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/_utils.py +0 -0
  125. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/cache.py +0 -0
  126. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/data_store.py +0 -0
  127. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/export.py +0 -0
  128. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/src/equity_aggregator/storage/metadata.py +0 -0
  129. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/README.md +0 -0
  130. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/__init__.py +0 -0
  131. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/conftest.py +0 -0
  132. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/__init__.py +0 -0
  133. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/__init__.py +0 -0
  134. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/__init__.py +0 -0
  135. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/__init__.py +0 -0
  136. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
  137. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
  138. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
  139. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
  140. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
  141. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
  142. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/stock_analysis/__init__.py +0 -0
  143. {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
  144. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
  145. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
  146. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
  147. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
  148. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
  149. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
  150. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
  151. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
  152. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
  153. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/__init__.py +0 -0
  154. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/exchange_rate_api/__init__.py +0 -0
  155. {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
  156. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/openfigi/__init__.py +0 -0
  157. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/live/adapters/data_sources/reference_lookup/openfigi/test_openfigi.py +0 -0
  158. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/__init__.py +0 -0
  159. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/__init__.py +0 -0
  160. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/_utils/__init__.py +0 -0
  161. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/_utils/test_client.py +0 -0
  162. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/__init__.py +0 -0
  163. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/__init__.py +0 -0
  164. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/__init__.py +0 -0
  165. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/__init__.py +0 -0
  166. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_backoff.py +0 -0
  167. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/_utils/test_parser.py +0 -0
  168. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_intrinio.py +0 -0
  169. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/intrinio/test_session.py +0 -0
  170. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/__init__.py +0 -0
  171. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/__init__.py +0 -0
  172. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_backoff.py +0 -0
  173. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/_utils/test_parser.py +0 -0
  174. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_lseg.py +0 -0
  175. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/lseg/test_session.py +0 -0
  176. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/sec/__init__.py +0 -0
  177. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/sec/test_sec.py +0 -0
  178. {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
  179. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/__init__.py +0 -0
  180. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/tradingview/test_tradingview.py +0 -0
  181. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/xetra/__init__.py +0 -0
  182. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/discovery_feeds/xetra/test_xetra.py +0 -0
  183. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/__init__.py +0 -0
  184. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/__init__.py +0 -0
  185. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/_helpers.py +0 -0
  186. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_api.py +0 -0
  187. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_download.py +0 -0
  188. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_gleif.py +0 -0
  189. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/gleif/test_parser.py +0 -0
  190. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/__init__.py +0 -0
  191. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_helpers.py +0 -0
  192. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/__init__.py +0 -0
  193. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_backoff.py +0 -0
  194. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_fuzzy.py +0 -0
  195. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/_utils/test_json.py +0 -0
  196. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/__init__.py +0 -0
  197. {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
  198. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/api/test_search.py +0 -0
  199. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_auth.py +0 -0
  200. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_config.py +0 -0
  201. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_ranking.py +0 -0
  202. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_session.py +0 -0
  203. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_transport.py +0 -0
  204. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/enrichment_feeds/yfinance/test_yfinance.py +0 -0
  205. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/__init__.py +0 -0
  206. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/test_exchange_rate_api.py +0 -0
  207. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/adapters/data_sources/reference_lookup/test_openfigi.py +0 -0
  208. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/__init__.py +0 -0
  209. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_config.py +0 -0
  210. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_dispatcher.py +0 -0
  211. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_main.py +0 -0
  212. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/cli/test_parser.py +0 -0
  213. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/__init__.py +0 -0
  214. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/__init__.py +0 -0
  215. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__merge.py +0 -0
  216. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__merge_config.py +0 -0
  217. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test__strategies.py +0 -0
  218. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/_utils/test_load_converter.py +0 -0
  219. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/__init__.py +0 -0
  220. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/test_resolve.py +0 -0
  221. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/__init__.py +0 -0
  222. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_canonicalise.py +0 -0
  223. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_convert.py +0 -0
  224. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_enrich.py +0 -0
  225. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_group.py +0 -0
  226. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_identify.py +0 -0
  227. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/pipeline/transforms/test_parse.py +0 -0
  228. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/domain/retrieval/test_retrieval.py +0 -0
  229. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/__init__.py +0 -0
  230. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/__init__.py +0 -0
  231. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_feed_validators.py +0 -0
  232. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_gleif_feed_data.py +0 -0
  233. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_intrinio_feed_data.py +0 -0
  234. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_lseg_feed_data.py +0 -0
  235. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_sec_feed_data.py +0 -0
  236. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_stock_analysis_feed_data.py +0 -0
  237. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_tradingview_feed_data.py +0 -0
  238. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_xetra_feed_data.py +0 -0
  239. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/feeds/test_yfinance_feed_data.py +0 -0
  240. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_canonical.py +0 -0
  241. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_raw.py +0 -0
  242. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_types.py +0 -0
  243. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/schemas/test_validators.py +0 -0
  244. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/__init__.py +0 -0
  245. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test__utils.py +0 -0
  246. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_cache.py +0 -0
  247. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_data_store.py +0 -0
  248. {equity_aggregator-0.1.7 → equity_aggregator-0.1.8}/tests/unit/storage/test_export.py +0 -0
  249. {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.7
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
+ ]
@@ -0,0 +1,6 @@
1
+ # data_integrity_analysis/__main__.py
2
+
3
+ from .main import main
4
+
5
+ if __name__ == "__main__":
6
+ main()
@@ -1,295 +1,27 @@
1
- # examples/data_integrity_analysis.py
1
+ # data_integrity_analysis/analyzers.py
2
2
 
3
3
  from collections import Counter, defaultdict
4
- from collections.abc import Iterable, Sequence
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
- @dataclass(frozen=True)
15
- class AnalysisSettings:
16
- """Configuration values controlling analysis thresholds."""
17
-
18
- min_sample_size: int = 10
19
- mega_cap_threshold: int = 200_000_000_000
20
- micro_cap_threshold: int = 300_000_000
21
- rare_currency_count: int = 10
22
- round_price_threshold: float = 30.0
23
- identifier_gap_alert: float = 50.0
24
- symbol_length_limit: int = 5
25
- duplicate_group_limit: int = 3
26
- finding_sample_limit: int = 5
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()