wbfdm 1.43.1__tar.gz → 1.44.0__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.
Potentially problematic release.
This version of wbfdm might be problematic. Click here for more details.
- {wbfdm-1.43.1 → wbfdm-1.44.0}/PKG-INFO +3 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/pyproject.toml +3 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/utils.py +3 -1
- wbfdm-1.44.0/wbfdm/contrib/qa/dataloaders/adjustments.py +69 -0
- wbfdm-1.44.0/wbfdm/contrib/qa/dataloaders/corporate_actions.py +69 -0
- wbfdm-1.44.0/wbfdm/contrib/qa/dataloaders/market_data.py +142 -0
- wbfdm-1.44.0/wbfdm/contrib/qa/dataloaders/officers.py +74 -0
- wbfdm-1.44.0/wbfdm/contrib/qa/dataloaders/utils.py +22 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dataloaders/protocols.py +11 -18
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dataloaders/proxies.py +1 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dataloaders/types.py +3 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/enums.py +3 -3
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/mixin/instruments.py +1 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/instruments.py +1 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +1 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_instruments.py +3 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/urls.py +1 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/buttons/instruments.py +1 -1
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/__init__.py +1 -0
- wbfdm-1.44.0/wbfdm/viewsets/configs/display/financial_summary.py +133 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/instruments.py +11 -12
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/financial_analysis/__init__.py +1 -0
- wbfdm-1.44.0/wbfdm/viewsets/financial_analysis/financial_summary.py +256 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/mixins.py +2 -0
- wbfdm-1.43.1/wbfdm/contrib/qa/dataloaders/adjustments.py +0 -56
- wbfdm-1.43.1/wbfdm/contrib/qa/dataloaders/corporate_actions.py +0 -59
- wbfdm-1.43.1/wbfdm/contrib/qa/dataloaders/market_data.py +0 -117
- wbfdm-1.43.1/wbfdm/contrib/qa/dataloaders/officers.py +0 -59
- {wbfdm-1.43.1 → wbfdm-1.44.0}/.gitignore +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/admin/options.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/esg/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/esg/enums.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/esg/esg_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/esg/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/financial_metric_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/financial_ratio_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/financial_statistics_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/financial_analysis/statement_with_estimates.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/technical_analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/technical_analysis/technical_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/technical_analysis/traces.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/analysis/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/apps.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/backends/dto.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/dsws/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/dsws/client.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/dsws/dataloaders/market_data.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/internal/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/internal/dataloaders/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/internal/dataloaders/market_data.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/admin/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/admin/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/admin/metrics.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/apps.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/backends/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/backends/base.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/backends/performances.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/backends/statistics.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/decorators.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/dispatch.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/dto.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/exceptions.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/factories.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/filters.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/migrations/0001_initial.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/migrations/0002_remove_instrumentmetric_unique_instrument_metric_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/migrations/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/models.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/orchestrators.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/registry.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/serializers.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tasks.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/backends/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/backends/test_performances.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/backends/test_statistics.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/conftest.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/test_dto.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/test_models.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/test_tasks.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/tests/test_viewsets.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/urls.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/configs/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/configs/display.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/configs/menus.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/configs/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/mixins.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/metric/viewsets/viewsets.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/client.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/dataloaders/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/dataloaders/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/dataloaders/esg_controversies.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/sync.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/tests/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/tests/conftest.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/msci/tests/test_client.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/apps.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/database_routers.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/dataloaders/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/dataloaders/financials.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/dataloaders/reporting_dates.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/dataloaders/statements.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/companies.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/base_estimates.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/calendarized.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/complete.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/estimates.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/instruments.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/jinja2/qa/sql/quotes.sql +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/sync/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/sync/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/sync/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/contrib/qa/tasks.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dataloaders/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dataloaders/cache.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/dynamic_preferences_registry.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/controversies.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/instrument_list.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/factories/options.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/figures/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/figures/financials/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/figures/financials/financial_analysis_charts.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/figures/financials/financials_charts.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/financials.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/financials_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/filters/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/deals.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/equities.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/mixin.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/utils/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/utils/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/cbinsights/utils/client.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/daily_fundamental.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/fiscal_period.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/forecast.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/fundamental.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/geographic_segment.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/instrument.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/instrument_price.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/mixin.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/utils/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/backends/refinitiv/utils/controller.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/instrument.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/instrument_list.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/instrument_price.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/option.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/handlers/private_equities.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/cbinsights/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/cbinsights/deals.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/cbinsights/equities.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/cbinsights/fundamentals.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/daily_fundamental.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/forecast.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/fundamental.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/geographic_segment.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/instrument.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/instrument_price.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/parsers/refinitiv/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/resources/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/resources/classification.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/resources/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/import_export/resources/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/jinja2.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/management/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/menu.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0001_initial.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0002_rename_statements_instrumentlookup_financials_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0003_instrument_estimate_backend_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0004_rename_financials_instrumentlookup_statements_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0005_instrument_corporate_action_backend.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0006_instrument_officer_backend.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0007_instrument_country_instrument_currency_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0008_controversy.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0009_alter_controversy_flag_alter_controversy_initiated_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0010_classification_classificationgroup_deal_exchange_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0011_delete_instrumentlookup_instrument_corporate_actions_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0012_instrumentprice_created_instrumentprice_modified.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0013_instrument_is_investable_universe_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0014_alter_controversy_instrument.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0015_instrument_instrument_investible_index.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0016_instrumenttype_name_repr.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0017_instrument_instrument_security_index.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0018_instrument_instrument_level_index.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0019_alter_controversy_source.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0020_optionaggregate_option_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0021_delete_instrumentdailystatistics.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0022_instrument_cusip_option_open_interest_20d_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0023_instrument_unique_ric_instrument_unique_rmc_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0024_option_open_interest_10d_option_volume_10d_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0025_instrument_is_primary_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0026_instrument_is_cash_equivalent.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0027_remove_instrument_unique_ric_and_more.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/0028_instrumentprice_annualized_daily_volatility.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/migrations/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/esg/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/esg/controversies.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/exchanges/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/exchanges/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/fields.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/fk_fields.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/indicators.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/instrument_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/llm/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/llm/create_instrument_news_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/mixin/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/mixin/financials_computed.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/mixin/financials_serializer_fields.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/options.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/private_equities.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/querysets.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/models/instruments/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/preferences.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/instrument_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/instruments/mixins.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/serializers/officers.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/signals.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/sync/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/sync/abstract.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/sync/runner.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tasks.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/analysis/financial_analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/analysis/financial_analysis/test_utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/analysis/test_esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/conftest.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/dataloaders/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/dataloaders/test_cache.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_instrument_list.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_merge.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/models/test_options.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/test_tasks.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/tests/tests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/buttons/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/buttons/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/buttons/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/buttons/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/monthly_performances.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/officers.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/statement_with_estimates.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/display/statements.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/financials_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/endpoints/statements.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/menus/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/financial_ratio_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/financials_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/market_data.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/configs/titles/statement_with_estimates.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/esg.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/exchanges.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/financial_analysis/statement_with_estimates.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/classifications.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/financials_analysis.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/instrument_lists.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/instrument_prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/instrument_requests.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/instruments.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/instruments_relationships.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/instruments/utils.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/market_data.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/officers.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/prices.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/statements/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/statements/statements.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/technical_analysis/__init__.py +0 -0
- {wbfdm-1.43.1 → wbfdm-1.44.0}/wbfdm/viewsets/technical_analysis/monthly_performances.py +0 -0
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wbfdm
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.44.0
|
|
4
4
|
Summary: The workbench module ensures rapid access to diverse financial data (market, fundamental, forecasts, ESG), with features for storing instruments, classifying them, and conducting financial analysis.
|
|
5
5
|
Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
|
|
6
6
|
Requires-Dist: roman==4.*
|
|
7
|
+
Requires-Dist: sentry-sdk==2.*
|
|
7
8
|
Requires-Dist: stockstats==0.6.*
|
|
8
9
|
Requires-Dist: wbcore
|
|
9
10
|
Requires-Dist: wbnews
|
|
@@ -13,3 +14,4 @@ Requires-Dist: requests-cache==1.0.*; extra == 'dsws'
|
|
|
13
14
|
Provides-Extra: qa
|
|
14
15
|
Requires-Dist: jinjasql2==0.1.*; extra == 'qa'
|
|
15
16
|
Requires-Dist: mssql-django==1.4.*; extra == 'qa'
|
|
17
|
+
Requires-Dist: pypika; extra == 'qa'
|
|
@@ -9,12 +9,14 @@ dependencies = [
|
|
|
9
9
|
"wbnews",
|
|
10
10
|
"stockstats == 0.6.*",
|
|
11
11
|
"roman == 4.*",
|
|
12
|
+
"sentry-sdk == 2.*",
|
|
12
13
|
]
|
|
13
14
|
|
|
14
15
|
[project.optional-dependencies]
|
|
15
16
|
qa = [
|
|
16
17
|
"mssql-django == 1.4.*",
|
|
17
18
|
"jinjasql2 == 0.1.*",
|
|
19
|
+
"pypika",
|
|
18
20
|
]
|
|
19
21
|
dsws = [
|
|
20
22
|
"requests-cache == 1.0.*",
|
|
@@ -24,6 +26,7 @@ dsws = [
|
|
|
24
26
|
[tool.uv.sources]
|
|
25
27
|
wbcore = { workspace = true }
|
|
26
28
|
wbnews = { workspace = true }
|
|
29
|
+
pypika = { git = "https://github.com/kayak/pypika.git" }
|
|
27
30
|
|
|
28
31
|
[tool.uv]
|
|
29
32
|
package = true
|
|
@@ -25,6 +25,7 @@ class Loader:
|
|
|
25
25
|
calendar_type: CalendarType = CalendarType.FISCAL,
|
|
26
26
|
market_data_values: list[MarketData] | None = None,
|
|
27
27
|
statement_values: list[Financial] | None = None,
|
|
28
|
+
period_type: PeriodType = PeriodType.ALL,
|
|
28
29
|
):
|
|
29
30
|
self.instrument = instrument
|
|
30
31
|
self.calendar_type = calendar_type
|
|
@@ -35,6 +36,7 @@ class Loader:
|
|
|
35
36
|
self.statement_values = (
|
|
36
37
|
statement_values # specify if any extra statement needs to be merged into the dataframe
|
|
37
38
|
)
|
|
39
|
+
self.period_type = period_type
|
|
38
40
|
self.errors: dict[str, list[str]] = defaultdict(list)
|
|
39
41
|
|
|
40
42
|
def load(self) -> pd.DataFrame:
|
|
@@ -54,9 +56,9 @@ class Loader:
|
|
|
54
56
|
df = pd.DataFrame(
|
|
55
57
|
Instrument.objects.filter(id=self.instrument.id).dl.financials(
|
|
56
58
|
values=self.values,
|
|
57
|
-
period_type=PeriodType.ALL,
|
|
58
59
|
from_year=date.today().year - 5,
|
|
59
60
|
calendar_type=self.calendar_type,
|
|
61
|
+
period_type=self.period_type,
|
|
60
62
|
)
|
|
61
63
|
)
|
|
62
64
|
if df.empty:
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from datetime import date
|
|
3
|
+
from itertools import batched
|
|
4
|
+
from typing import Iterator
|
|
5
|
+
|
|
6
|
+
from django.db import ProgrammingError, connections
|
|
7
|
+
from wbcore.contrib.dataloader.dataloaders import Dataloader
|
|
8
|
+
from wbcore.contrib.dataloader.utils import dictfetchall
|
|
9
|
+
from wbfdm.contrib.qa.dataloaders.utils import SOURCE_DS2
|
|
10
|
+
from wbfdm.dataloaders.protocols import AdjustmentsProtocol
|
|
11
|
+
from wbfdm.dataloaders.types import AdjustmentDataDict
|
|
12
|
+
|
|
13
|
+
import pypika as pk
|
|
14
|
+
from pypika import functions as fn
|
|
15
|
+
from pypika.enums import SqlTypes, Order
|
|
16
|
+
from pypika.terms import LiteralValue
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DatastreamAdjustmentsDataloader(AdjustmentsProtocol, Dataloader):
|
|
20
|
+
def adjustments(self, from_date: date | None = None, to_date: date | None = None) -> Iterator[AdjustmentDataDict]:
|
|
21
|
+
lookup = {k: v for k, v in self.entities.values_list("dl_parameters__adjustments__parameters", "id")}
|
|
22
|
+
|
|
23
|
+
adj = pk.Table("DS2Adj")
|
|
24
|
+
adj_date = fn.Cast(adj.AdjDate, SqlTypes.DATE).as_("adjustment_date")
|
|
25
|
+
adj_end_date = fn.Cast(adj.EndAdjDate, SqlTypes.DATE).as_("adjustment_end_date")
|
|
26
|
+
|
|
27
|
+
infocode = pk.Table("#ds2infocode")
|
|
28
|
+
|
|
29
|
+
query = (
|
|
30
|
+
pk.MSSQLQuery.select(
|
|
31
|
+
adj.InfoCode.as_("external_identifier"),
|
|
32
|
+
fn.Concat(adj.InfoCode, "_", adj_date).as_("id"),
|
|
33
|
+
adj_date,
|
|
34
|
+
adj_end_date,
|
|
35
|
+
SOURCE_DS2,
|
|
36
|
+
adj.AdjFactor.as_("adjustment_factor"),
|
|
37
|
+
adj.CumAdjFactor.as_("cumulative_adjustement_factor"),
|
|
38
|
+
)
|
|
39
|
+
.from_(adj)
|
|
40
|
+
.where(adj.AdjType == 2)
|
|
41
|
+
.where(adj.InfoCode.isin([LiteralValue("select infocode from #ds2infocode")]))
|
|
42
|
+
.orderby(adj.AdjDate, order=Order.desc)
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
if from_date:
|
|
46
|
+
query = query.where(adj.AdjDate >= from_date)
|
|
47
|
+
|
|
48
|
+
if to_date:
|
|
49
|
+
query = query.where(adj.AdjDate <= to_date)
|
|
50
|
+
|
|
51
|
+
with connections["qa"].cursor() as cursor:
|
|
52
|
+
# we suppress an error here, because if the temporary table already exists
|
|
53
|
+
# then we do not want to fail. It should not fail, but if a previous run did
|
|
54
|
+
# not clean up the table properly, then at least we do not get stuck here
|
|
55
|
+
with suppress(ProgrammingError):
|
|
56
|
+
cursor.execute(
|
|
57
|
+
pk.MSSQLQuery.create_table(infocode).columns(pk.Column("infocode", SqlTypes.INTEGER)).get_sql()
|
|
58
|
+
)
|
|
59
|
+
for batch in batched(lookup.keys(), 1000):
|
|
60
|
+
cursor.execute(f"insert into #ds2infocode values {",".join(map(lambda x: f"({x})", batch))};")
|
|
61
|
+
|
|
62
|
+
cursor.execute(query.get_sql())
|
|
63
|
+
|
|
64
|
+
for row in dictfetchall(cursor, AdjustmentDataDict):
|
|
65
|
+
row["instrument_id"] = lookup[row["external_identifier"]]
|
|
66
|
+
yield row
|
|
67
|
+
|
|
68
|
+
# here we remove the temporary table again to avoid data spillage
|
|
69
|
+
# cursor.execute(pk.MSSQLQuery.drop_table(infocode).get_sql())
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from datetime import date
|
|
3
|
+
from itertools import batched
|
|
4
|
+
from typing import Iterator
|
|
5
|
+
|
|
6
|
+
from django.db import ProgrammingError, connections
|
|
7
|
+
from wbcore.contrib.dataloader.dataloaders import Dataloader
|
|
8
|
+
from wbcore.contrib.dataloader.utils import dictfetchall
|
|
9
|
+
from wbfdm.contrib.qa.dataloaders.utils import SOURCE_DS2
|
|
10
|
+
from wbfdm.dataloaders.protocols import CorporateActionsProtocol
|
|
11
|
+
from wbfdm.dataloaders.types import CorporateActionDataDict
|
|
12
|
+
|
|
13
|
+
import pypika as pk
|
|
14
|
+
from pypika import functions as fn
|
|
15
|
+
from pypika.enums import SqlTypes
|
|
16
|
+
from pypika.terms import LiteralValue
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class DatastreamCorporateActionsDataloader(CorporateActionsProtocol, Dataloader):
|
|
20
|
+
def corporate_actions(
|
|
21
|
+
self,
|
|
22
|
+
from_date: date | None = None,
|
|
23
|
+
to_date: date | None = None,
|
|
24
|
+
) -> Iterator[CorporateActionDataDict]:
|
|
25
|
+
lookup = {k: v for k, v in self.entities.values_list("dl_parameters__corporate_actions__parameters", "id")}
|
|
26
|
+
|
|
27
|
+
cap_event = pk.Table("Ds2CapEvent")
|
|
28
|
+
effective_date = fn.Cast(cap_event.EffectiveDate, SqlTypes.DATE)
|
|
29
|
+
infocode = pk.Table("#ds2infocode")
|
|
30
|
+
|
|
31
|
+
query = (
|
|
32
|
+
pk.MSSQLQuery.select(
|
|
33
|
+
cap_event.InfoCode.as_("external_identifier"),
|
|
34
|
+
fn.Concat(cap_event.InfoCode, "_", effective_date).as_("id"),
|
|
35
|
+
effective_date.as_("valuation_date"),
|
|
36
|
+
SOURCE_DS2,
|
|
37
|
+
cap_event.ActionTypeCode.as_("action_code"),
|
|
38
|
+
cap_event.EventStatusCode.as_("event_code"),
|
|
39
|
+
cap_event.NumOldShares.as_("old_shares"),
|
|
40
|
+
cap_event.NumNewShares.as_("new_shares"),
|
|
41
|
+
cap_event.ISOCurrCode.as_("currency"),
|
|
42
|
+
)
|
|
43
|
+
.from_(cap_event)
|
|
44
|
+
.where(cap_event.InfoCode.isin([LiteralValue("select infocode from #ds2infocode")]))
|
|
45
|
+
.orderby(cap_event.EffectiveDate, order=pk.Order.desc)
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
if from_date:
|
|
49
|
+
query = query.where(cap_event.EffectiveDate >= from_date)
|
|
50
|
+
|
|
51
|
+
if to_date:
|
|
52
|
+
query = query.where(cap_event.EffectiveDate <= to_date)
|
|
53
|
+
|
|
54
|
+
with connections["qa"].cursor() as cursor:
|
|
55
|
+
# Create temporary table if it doesn't exist
|
|
56
|
+
with suppress(ProgrammingError):
|
|
57
|
+
cursor.execute(
|
|
58
|
+
pk.MSSQLQuery.create_table(infocode).columns(pk.Column("infocode", SqlTypes.INTEGER)).get_sql()
|
|
59
|
+
)
|
|
60
|
+
for batch in batched(lookup.keys(), 1000):
|
|
61
|
+
cursor.execute(f"insert into #ds2infocode values {','.join(map(lambda x: f'({x})', batch))};")
|
|
62
|
+
|
|
63
|
+
cursor.execute(query.get_sql())
|
|
64
|
+
for row in dictfetchall(cursor, CorporateActionDataDict):
|
|
65
|
+
row["instrument_id"] = lookup[row["external_identifier"]]
|
|
66
|
+
yield row
|
|
67
|
+
|
|
68
|
+
# Clean up temporary table
|
|
69
|
+
cursor.execute(pk.MSSQLQuery.drop_table(infocode).get_sql())
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from functools import reduce
|
|
3
|
+
from itertools import batched
|
|
4
|
+
from datetime import date
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Iterator
|
|
7
|
+
import pypika as pk
|
|
8
|
+
from pypika import Column, MSSQLQuery, functions as fn
|
|
9
|
+
from pypika.enums import SqlTypes, Order
|
|
10
|
+
from pypika.terms import ValueWrapper, LiteralValue
|
|
11
|
+
|
|
12
|
+
from django.db import ProgrammingError, connections
|
|
13
|
+
from wbcore.contrib.dataloader.dataloaders import Dataloader
|
|
14
|
+
from wbcore.contrib.dataloader.utils import dictfetchall
|
|
15
|
+
from wbfdm.dataloaders.protocols import MarketDataProtocol
|
|
16
|
+
from wbfdm.contrib.qa.dataloaders.utils import create_table
|
|
17
|
+
from wbfdm.dataloaders.types import MarketDataDict
|
|
18
|
+
from wbfdm.enums import Frequency, MarketData
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class DS2MarketData(Enum):
|
|
22
|
+
OPEN = ("Open_", None)
|
|
23
|
+
CLOSE = ("Close_", None)
|
|
24
|
+
HIGH = ("High", None)
|
|
25
|
+
LOW = ("Low", None)
|
|
26
|
+
BID = ("Bid", None)
|
|
27
|
+
ASK = ("Ask", None)
|
|
28
|
+
VWAP = ("VWAP", None)
|
|
29
|
+
VOLUME = ("Volume", None)
|
|
30
|
+
MARKET_CAPITALIZATION = ("ConsolMktVal", 1_000_000)
|
|
31
|
+
SHARES_OUTSTANDING = ("ConsolNumShrs", 1_000)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
35
|
+
def market_data(
|
|
36
|
+
self,
|
|
37
|
+
values: list[MarketData] | None = [MarketData.CLOSE],
|
|
38
|
+
from_date: date | None = None,
|
|
39
|
+
to_date: date | None = None,
|
|
40
|
+
exact_date: date | None = None,
|
|
41
|
+
frequency: Frequency = Frequency.DAILY,
|
|
42
|
+
target_currency: str | None = None,
|
|
43
|
+
**kwargs,
|
|
44
|
+
) -> Iterator[MarketDataDict]:
|
|
45
|
+
"""Get market data for instruments.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
queryset (QuerySet["Instrument"]): The queryset of instruments.
|
|
49
|
+
values (list[MarketData]): List of values to include in the results.
|
|
50
|
+
from_date (date | None): The starting date for filtering prices. Defaults to None.
|
|
51
|
+
to_date (date | None): The ending date for filtering prices. Defaults to None.
|
|
52
|
+
frequency (Frequency): The frequency of the requested data
|
|
53
|
+
|
|
54
|
+
Returns:
|
|
55
|
+
Iterator[MarketDataDict]: An iterator of dictionaries conforming to the DailyValuationDict.
|
|
56
|
+
"""
|
|
57
|
+
|
|
58
|
+
lookup = {
|
|
59
|
+
f"{k[0]},{k[1]}": v for k, v in self.entities.values_list("dl_parameters__market_data__parameters", "id")
|
|
60
|
+
}
|
|
61
|
+
value_mapping = [(DS2MarketData[x.name].value, x.value) for x in values or []]
|
|
62
|
+
|
|
63
|
+
# Define tables
|
|
64
|
+
pricing = pk.Table("vw_DS2Pricing")
|
|
65
|
+
market_val = pk.Table("DS2MktVal")
|
|
66
|
+
fx_code = pk.Table("DS2FxCode")
|
|
67
|
+
fx = pk.Table("DS2FxRate")
|
|
68
|
+
|
|
69
|
+
mapping, create_mapping_table = create_table(
|
|
70
|
+
"#ds2infoexchcode", Column("InfoCode", SqlTypes.INTEGER), Column("ExchIntCode", SqlTypes.INTEGER)
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
# Base query to get data we always need unconditionally
|
|
74
|
+
query = (
|
|
75
|
+
pk.MSSQLQuery.from_(pricing)
|
|
76
|
+
.select(
|
|
77
|
+
fn.Concat(pricing.InfoCode, ",", pricing.ExchIntCode).as_("external_identifier"),
|
|
78
|
+
fn.Concat(
|
|
79
|
+
pricing.InfoCode, ",", pricing.ExchIntCode, "_", fn.Cast(pricing.MarketDate, SqlTypes.DATE)
|
|
80
|
+
).as_("id"),
|
|
81
|
+
fn.Cast(pricing.MarketDate, SqlTypes.DATE).as_("valuation_date"),
|
|
82
|
+
ValueWrapper("qa-ds2").as_("source"),
|
|
83
|
+
)
|
|
84
|
+
.left_join(market_val)
|
|
85
|
+
.on((pricing.InfoCode == market_val.InfoCode) & (pricing.MarketDate == market_val.ValDate))
|
|
86
|
+
# We join on _codes, which removes all instruments not in _codes - implicit where
|
|
87
|
+
.join(mapping)
|
|
88
|
+
.on((pricing.InfoCode == mapping.InfoCode) & (pricing.ExchIntCode == mapping.ExchIntCode))
|
|
89
|
+
.where(pricing.AdjType == 2)
|
|
90
|
+
.orderby(pricing.MarketDate, order=Order.desc)
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# If we need to convert to a target currency, we need the fx rate table and multiply all values with the fx rate
|
|
94
|
+
if target_currency:
|
|
95
|
+
query = (
|
|
96
|
+
query.select(
|
|
97
|
+
ValueWrapper(target_currency).as_("currency"),
|
|
98
|
+
*[
|
|
99
|
+
(LiteralValue(value[0][0]) * fn.Coalesce(fx.midrate, 1)).as_(value[1])
|
|
100
|
+
for value in value_mapping
|
|
101
|
+
],
|
|
102
|
+
)
|
|
103
|
+
.left_join(fx_code)
|
|
104
|
+
.on(
|
|
105
|
+
(fx_code.FromCurrCode == target_currency)
|
|
106
|
+
& (fx_code.ToCurrCode == pricing.Currency)
|
|
107
|
+
& (fx_code.RateTypeCode == "SPOT")
|
|
108
|
+
)
|
|
109
|
+
.left_join(fx)
|
|
110
|
+
.on((fx_code.ExRateIntCode == fx.ExRateIntCode) & (fx.ExRateDate == pricing.MarketDate))
|
|
111
|
+
)
|
|
112
|
+
else:
|
|
113
|
+
query = query.select(
|
|
114
|
+
pricing.Currency.as_("currency"),
|
|
115
|
+
*[LiteralValue(value[0][0]).as_(value[1]) for value in value_mapping],
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
# Add conditional where clauses
|
|
119
|
+
if from_date:
|
|
120
|
+
query = query.where(pricing.MarketDate >= from_date)
|
|
121
|
+
|
|
122
|
+
if to_date:
|
|
123
|
+
query = query.where(pricing.MarketDate <= to_date)
|
|
124
|
+
|
|
125
|
+
if exact_date:
|
|
126
|
+
query = query.where(pricing.MarketDate == exact_date)
|
|
127
|
+
|
|
128
|
+
with connections["qa"].cursor() as cursor:
|
|
129
|
+
with suppress(ProgrammingError):
|
|
130
|
+
cursor.execute(create_mapping_table.get_sql())
|
|
131
|
+
for batch in batched(
|
|
132
|
+
self.entities.values_list("dl_parameters__market_data__parameters", flat=True), 1000
|
|
133
|
+
):
|
|
134
|
+
cursor.execute(reduce(lambda x, y: x.insert(y), batch, MSSQLQuery.into(mapping)).get_sql())
|
|
135
|
+
|
|
136
|
+
cursor.execute(query.get_sql())
|
|
137
|
+
|
|
138
|
+
for row in dictfetchall(cursor, MarketDataDict):
|
|
139
|
+
row["instrument_id"] = lookup[row["external_identifier"]]
|
|
140
|
+
yield row
|
|
141
|
+
|
|
142
|
+
cursor.execute(MSSQLQuery.drop_table(mapping).get_sql())
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
from typing import Iterator
|
|
2
|
+
|
|
3
|
+
from django.db import connections, ProgrammingError
|
|
4
|
+
from wbcore.contrib.dataloader.dataloaders import Dataloader
|
|
5
|
+
from wbcore.contrib.dataloader.utils import dictfetchall
|
|
6
|
+
from wbfdm.dataloaders.protocols import OfficersProtocol
|
|
7
|
+
from wbfdm.dataloaders.types import OfficerDataDict
|
|
8
|
+
from itertools import batched
|
|
9
|
+
from contextlib import suppress
|
|
10
|
+
|
|
11
|
+
import pypika as pk
|
|
12
|
+
from pypika import functions as fn
|
|
13
|
+
from pypika.enums import SqlTypes
|
|
14
|
+
from pypika.terms import LiteralValue
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
from pypika.analytics import RowNumber
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class RKDOfficersDataloader(OfficersProtocol, Dataloader):
|
|
21
|
+
def officers(
|
|
22
|
+
self,
|
|
23
|
+
) -> Iterator[OfficerDataDict]:
|
|
24
|
+
lookup = {k: v for k, v in self.entities.values_list("dl_parameters__officers__parameters", "id")}
|
|
25
|
+
|
|
26
|
+
# Define tables
|
|
27
|
+
designation = pk.Table("RKDFndCmpOffTitleChg")
|
|
28
|
+
officer = pk.Table("RKDFndCmpOfficer")
|
|
29
|
+
temp_codes = pk.Table("#rkd_codes")
|
|
30
|
+
|
|
31
|
+
# Build the query
|
|
32
|
+
query = (
|
|
33
|
+
pk.MSSQLQuery.select(
|
|
34
|
+
fn.Concat(designation.Code, "-", RowNumber().orderby(officer.OfficerRank)).as_("id"),
|
|
35
|
+
designation.Code.as_("external_identifier"),
|
|
36
|
+
designation.Title.as_("position"),
|
|
37
|
+
fn.Concat(
|
|
38
|
+
officer.Prefix,
|
|
39
|
+
" ",
|
|
40
|
+
officer.FirstName,
|
|
41
|
+
" ",
|
|
42
|
+
officer.LastName,
|
|
43
|
+
pk.Case().when(officer.Suffix.isnull(), "").else_(fn.Concat(", ", officer.Suffix)),
|
|
44
|
+
).as_("name"),
|
|
45
|
+
officer.Age.as_("age"),
|
|
46
|
+
officer.Sex.as_("sex"),
|
|
47
|
+
fn.Cast(designation.DesgStartDt, SqlTypes.DATE).as_("start"),
|
|
48
|
+
)
|
|
49
|
+
.from_(designation)
|
|
50
|
+
.join(officer)
|
|
51
|
+
.on((designation.Code == officer.Code) & (designation.OfficerID == officer.Officerid))
|
|
52
|
+
.where(designation.Code.isin([LiteralValue("select code from #rkd_codes")]))
|
|
53
|
+
.where(designation.DesgEndDt.isnull())
|
|
54
|
+
.orderby(officer.OfficerRank)
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
with connections["qa"].cursor() as cursor:
|
|
58
|
+
# Create and populate temporary table
|
|
59
|
+
with suppress(ProgrammingError):
|
|
60
|
+
cursor.execute(
|
|
61
|
+
pk.MSSQLQuery.create_table(temp_codes).columns(pk.Column("code", SqlTypes.INTEGER)).get_sql()
|
|
62
|
+
)
|
|
63
|
+
for batch in batched(lookup.keys(), 1000):
|
|
64
|
+
placeholders = ",".join(map(lambda x: f"('{x}')", batch))
|
|
65
|
+
cursor.execute(f"insert into #rkd_codes values {placeholders};")
|
|
66
|
+
|
|
67
|
+
cursor.execute(query.get_sql())
|
|
68
|
+
|
|
69
|
+
for row in dictfetchall(cursor, OfficerDataDict):
|
|
70
|
+
row["instrument_id"] = lookup[row["external_identifier"]]
|
|
71
|
+
yield row
|
|
72
|
+
|
|
73
|
+
# Clean up temporary table
|
|
74
|
+
cursor.execute(pk.MSSQLQuery.drop_table(temp_codes).get_sql())
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
from typing import TYPE_CHECKING
|
|
2
|
+
|
|
3
|
+
from pypika.terms import ValueWrapper
|
|
4
|
+
from pypika import Column, MSSQLQuery, Table
|
|
5
|
+
|
|
6
|
+
if TYPE_CHECKING:
|
|
7
|
+
from pypika.terms import Term
|
|
8
|
+
from pypika.queries import CreateQueryBuilder
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def compile_source(source: str) -> "Term":
|
|
12
|
+
return ValueWrapper(source).as_("source")
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
SOURCE_DS2 = compile_source("qa-ds2")
|
|
16
|
+
SOURCE_RKD = compile_source("qa-rkd")
|
|
17
|
+
SOURCE_IBES = compile_source("qa-ibes")
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def create_table(tablename: "str", *columns: "Column") -> tuple[Table, "CreateQueryBuilder"]:
|
|
21
|
+
table = Table(tablename)
|
|
22
|
+
return table, MSSQLQuery.create_table(table).columns(*columns)
|
|
@@ -27,13 +27,13 @@ from wbfdm.enums import (
|
|
|
27
27
|
|
|
28
28
|
|
|
29
29
|
class ReportDateProtocol(Protocol):
|
|
30
|
-
def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]:
|
|
31
|
-
...
|
|
30
|
+
def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]: ...
|
|
32
31
|
|
|
33
32
|
|
|
34
33
|
class AdjustmentsProtocol(Protocol):
|
|
35
|
-
def adjustments(
|
|
36
|
-
|
|
34
|
+
def adjustments(
|
|
35
|
+
self, from_date: date | None = None, to_date: date | None = None
|
|
36
|
+
) -> Iterator[AdjustmentDataDict]: ...
|
|
37
37
|
|
|
38
38
|
|
|
39
39
|
class MarketDataProtocol(Protocol):
|
|
@@ -45,20 +45,17 @@ class MarketDataProtocol(Protocol):
|
|
|
45
45
|
exact_date: date | None = None,
|
|
46
46
|
frequency: Frequency = Frequency.DAILY,
|
|
47
47
|
target_currency: str | None = None,
|
|
48
|
-
) -> Iterator[MarketDataDict]:
|
|
49
|
-
...
|
|
48
|
+
) -> Iterator[MarketDataDict]: ...
|
|
50
49
|
|
|
51
50
|
|
|
52
51
|
class CorporateActionsProtocol(Protocol):
|
|
53
52
|
def corporate_actions(
|
|
54
53
|
self, from_date: date | None = None, to_date: date | None = None
|
|
55
|
-
) -> Iterator[CorporateActionDataDict]:
|
|
56
|
-
...
|
|
54
|
+
) -> Iterator[CorporateActionDataDict]: ...
|
|
57
55
|
|
|
58
56
|
|
|
59
57
|
class OfficersProtocol(Protocol):
|
|
60
|
-
def officers(self) -> Iterator[OfficerDataDict]:
|
|
61
|
-
...
|
|
58
|
+
def officers(self) -> Iterator[OfficerDataDict]: ...
|
|
62
59
|
|
|
63
60
|
|
|
64
61
|
class StatementsProtocol(Protocol):
|
|
@@ -73,8 +70,7 @@ class StatementsProtocol(Protocol):
|
|
|
73
70
|
data_type: DataType = DataType.STANDARDIZED,
|
|
74
71
|
financials: list[Financial] | None = None,
|
|
75
72
|
target_currency: str | None = None,
|
|
76
|
-
) -> Iterator[StatementDataDict]:
|
|
77
|
-
...
|
|
73
|
+
) -> Iterator[StatementDataDict]: ...
|
|
78
74
|
|
|
79
75
|
|
|
80
76
|
class FinancialsProtocol(Protocol):
|
|
@@ -95,18 +91,15 @@ class FinancialsProtocol(Protocol):
|
|
|
95
91
|
data_type: DataType = DataType.STANDARDIZED,
|
|
96
92
|
estimate_type: EstimateType = EstimateType.VALID,
|
|
97
93
|
target_currency: str | None = None,
|
|
98
|
-
) -> Iterator[FinancialDataDict]:
|
|
99
|
-
...
|
|
94
|
+
) -> Iterator[FinancialDataDict]: ...
|
|
100
95
|
|
|
101
96
|
|
|
102
97
|
class ESGControversyProtocol(Protocol):
|
|
103
|
-
def esg_controversies(self) -> Iterator[ESGControversyDataDict]:
|
|
104
|
-
...
|
|
98
|
+
def esg_controversies(self) -> Iterator[ESGControversyDataDict]: ...
|
|
105
99
|
|
|
106
100
|
|
|
107
101
|
class ESGProtocol(Protocol):
|
|
108
102
|
def esg(
|
|
109
103
|
self,
|
|
110
104
|
values: list[ESG],
|
|
111
|
-
) -> Iterator[ESGDataDict]:
|
|
112
|
-
...
|
|
105
|
+
) -> Iterator[ESGDataDict]: ...
|
|
@@ -67,7 +67,7 @@ class InstrumentDataloaderProxy(
|
|
|
67
67
|
for dl in self.iterate_dataloaders("reporting_dates"):
|
|
68
68
|
yield from dl.reporting_dates(only_next=only_next)
|
|
69
69
|
|
|
70
|
-
def adjustments(self, from_date: date, to_date: date) -> Iterator[AdjustmentDataDict]:
|
|
70
|
+
def adjustments(self, from_date: date | None = None, to_date: date | None = None) -> Iterator[AdjustmentDataDict]:
|
|
71
71
|
for dl in self.iterate_dataloaders("adjustments"):
|
|
72
72
|
yield from dl.adjustments(from_date=from_date, to_date=to_date)
|
|
73
73
|
|
|
@@ -33,6 +33,8 @@ class MarketDataDict(BaseDict):
|
|
|
33
33
|
Attributes:
|
|
34
34
|
valuation_date: date
|
|
35
35
|
The date of valuation.
|
|
36
|
+
external_identifier: str
|
|
37
|
+
The external identifier of the instrument
|
|
36
38
|
open: float | None
|
|
37
39
|
The opening value (if available).
|
|
38
40
|
close: float | None
|
|
@@ -52,6 +54,7 @@ class MarketDataDict(BaseDict):
|
|
|
52
54
|
"""
|
|
53
55
|
|
|
54
56
|
valuation_date: date
|
|
57
|
+
external_identifier: str
|
|
55
58
|
|
|
56
59
|
open: NotRequired[float]
|
|
57
60
|
close: NotRequired[float]
|
|
@@ -50,12 +50,12 @@ class Financial(ChoiceEnum):
|
|
|
50
50
|
NET_INCOME_BEFORE_TAXES = "pbt"
|
|
51
51
|
NET_INCOME = "net_income"
|
|
52
52
|
EPS = "eps"
|
|
53
|
-
FREE_CASH_FLOW = "
|
|
53
|
+
FREE_CASH_FLOW = "free_cash_flow"
|
|
54
54
|
EBITDA = "ebitda"
|
|
55
55
|
EBITDA_PER_SHARE = "ebitda_sh"
|
|
56
56
|
NET_DEBT = "net_debt"
|
|
57
57
|
ENTERPRISE_VALUE = "ev"
|
|
58
|
-
SHARES_OUTSTANDING = "
|
|
58
|
+
SHARES_OUTSTANDING = "shares_outstanding"
|
|
59
59
|
COST_OF_GOODS_SOLD = "cogs"
|
|
60
60
|
GROSS_PROFIT_MARGIN = "gross_profit_margin"
|
|
61
61
|
SELLING_MARKETING_EXPENSES = "selling_marketing_expenses"
|
|
@@ -79,7 +79,7 @@ class Financial(ChoiceEnum):
|
|
|
79
79
|
CASH_FLOW_FROM_OPERATIONS = "cash_flow_from_operations"
|
|
80
80
|
CAPEX = "capex"
|
|
81
81
|
CASH_FLOW_FROM_INVESTING = "cash_flow_from_investing"
|
|
82
|
-
FREE_CASH_FLOW_PER_SHARE = "
|
|
82
|
+
FREE_CASH_FLOW_PER_SHARE = "free_cash_flow_per_share"
|
|
83
83
|
TOTAL_DIVIDENDS = "total_dividends"
|
|
84
84
|
CASH_FLOW_FROM_FINANCING = "cash_flow_from_financing"
|
|
85
85
|
CASH_FLOW_PER_SHARE = "cash_flow_per_share"
|
|
@@ -136,7 +136,7 @@ class InstrumentPMSMixin:
|
|
|
136
136
|
self, start: Optional[date] = None, end: Optional[date] = None, **kwargs
|
|
137
137
|
) -> pd.DataFrame:
|
|
138
138
|
if not (prices := self.get_prices_df_with_calculated(from_date=start, to_date=end, **kwargs)).empty:
|
|
139
|
-
calculated_mask = prices[["calculated"]].copy().
|
|
139
|
+
calculated_mask = prices[["calculated"]].copy().groupby([prices.index.year, prices.index.month]).tail(1)
|
|
140
140
|
calculated_mask["year"] = calculated_mask.index.year
|
|
141
141
|
calculated_mask["month"] = calculated_mask.index.month
|
|
142
142
|
calculated_mask = (
|
|
@@ -192,6 +192,7 @@ class InstrumentModelSerializer(InstrumentAdditionalResourcesMixin, InstrumentMo
|
|
|
192
192
|
if not instance.is_managed:
|
|
193
193
|
res.update(
|
|
194
194
|
{
|
|
195
|
+
"fin-summary": reverse("wbfdm:financial-summary-list", args=[instance.id], request=request),
|
|
195
196
|
"swe-income-statement": reverse(
|
|
196
197
|
"wbfdm:statementwithestimates-list", args=[instance.id, "income"], request=request
|
|
197
198
|
),
|
|
@@ -88,7 +88,7 @@ class TestInstrumentModel:
|
|
|
88
88
|
|
|
89
89
|
def test_get_monthly_return_summary(self, instrument, instrument_price_factory):
|
|
90
90
|
instrument_price_factory.create_batch(10, instrument=instrument)
|
|
91
|
-
res,
|
|
91
|
+
res, calculated_mask = instrument.get_monthly_return_summary()
|
|
92
92
|
assert "performance" in res.columns
|
|
93
93
|
assert "month" in res.columns
|
|
94
94
|
assert "year" in res.columns
|
|
@@ -100,6 +100,8 @@ class TestInstrumentModel:
|
|
|
100
100
|
for month in res[year].keys():
|
|
101
101
|
assert month in calendar.month_abbr or month == "annual"
|
|
102
102
|
assert "performance" in res[year][month]
|
|
103
|
+
if month == "annual":
|
|
104
|
+
assert res[year][month]["performance"] is not None
|
|
103
105
|
|
|
104
106
|
def test_get_prices_df(self, instrument, instrument_price_factory):
|
|
105
107
|
price = instrument_price_factory.create(instrument=instrument)
|
|
@@ -195,6 +195,7 @@ instrument_router.register(
|
|
|
195
195
|
)
|
|
196
196
|
instrument_router.register(r"valuation_ratios", viewsets.ValuationRatioChartViewSet, basename="valuation_ratios")
|
|
197
197
|
instrument_router.register(r"prices", viewsets.InstrumentPriceViewSet, basename="prices")
|
|
198
|
+
instrument_router.register(r"financial-summary", viewsets.FinancialSummary, basename="financial-summary")
|
|
198
199
|
|
|
199
200
|
instrument_statement_router = WBCoreRouter()
|
|
200
201
|
instrument_statement_router.register(
|
|
@@ -20,3 +20,4 @@ from .instruments_relationships import (
|
|
|
20
20
|
from .exchanges import ExchangeDisplayConfig
|
|
21
21
|
from .monthly_performances import MonthlyPerformancesInstrumentDisplayViewConfig
|
|
22
22
|
from .esg import InstrumentESGPAIDisplayViewConfig, InstrumentESGControversyDisplayViewConfig
|
|
23
|
+
from .financial_summary import FinancialSummaryDisplayViewConfig
|