wbfdm 1.43.1__py2.py3-none-any.whl
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/__init__.py +2 -0
- wbfdm/admin/__init__.py +42 -0
- wbfdm/admin/classifications.py +39 -0
- wbfdm/admin/esg.py +23 -0
- wbfdm/admin/exchanges.py +53 -0
- wbfdm/admin/instrument_lists.py +23 -0
- wbfdm/admin/instrument_prices.py +62 -0
- wbfdm/admin/instrument_requests.py +33 -0
- wbfdm/admin/instruments.py +117 -0
- wbfdm/admin/instruments_relationships.py +25 -0
- wbfdm/admin/options.py +101 -0
- wbfdm/analysis/__init__.py +2 -0
- wbfdm/analysis/esg/__init__.py +0 -0
- wbfdm/analysis/esg/enums.py +82 -0
- wbfdm/analysis/esg/esg_analysis.py +217 -0
- wbfdm/analysis/esg/utils.py +13 -0
- wbfdm/analysis/financial_analysis/__init__.py +1 -0
- wbfdm/analysis/financial_analysis/financial_metric_analysis.py +88 -0
- wbfdm/analysis/financial_analysis/financial_ratio_analysis.py +125 -0
- wbfdm/analysis/financial_analysis/financial_statistics_analysis.py +277 -0
- wbfdm/analysis/financial_analysis/statement_with_estimates.py +558 -0
- wbfdm/analysis/financial_analysis/utils.py +316 -0
- wbfdm/analysis/technical_analysis/__init__.py +1 -0
- wbfdm/analysis/technical_analysis/technical_analysis.py +138 -0
- wbfdm/analysis/technical_analysis/traces.py +165 -0
- wbfdm/analysis/utils.py +32 -0
- wbfdm/apps.py +14 -0
- wbfdm/backends/dto.py +36 -0
- wbfdm/contrib/__init__.py +0 -0
- wbfdm/contrib/dsws/__init__.py +0 -0
- wbfdm/contrib/dsws/client.py +285 -0
- wbfdm/contrib/dsws/dataloaders/market_data.py +130 -0
- wbfdm/contrib/internal/__init__.py +0 -0
- wbfdm/contrib/internal/dataloaders/__init__.py +0 -0
- wbfdm/contrib/internal/dataloaders/market_data.py +87 -0
- wbfdm/contrib/metric/__init__.py +0 -0
- wbfdm/contrib/metric/admin/__init__.py +2 -0
- wbfdm/contrib/metric/admin/instruments.py +12 -0
- wbfdm/contrib/metric/admin/metrics.py +43 -0
- wbfdm/contrib/metric/apps.py +10 -0
- wbfdm/contrib/metric/backends/__init__.py +2 -0
- wbfdm/contrib/metric/backends/base.py +159 -0
- wbfdm/contrib/metric/backends/performances.py +265 -0
- wbfdm/contrib/metric/backends/statistics.py +182 -0
- wbfdm/contrib/metric/decorators.py +14 -0
- wbfdm/contrib/metric/dispatch.py +23 -0
- wbfdm/contrib/metric/dto.py +88 -0
- wbfdm/contrib/metric/exceptions.py +6 -0
- wbfdm/contrib/metric/factories.py +33 -0
- wbfdm/contrib/metric/filters.py +28 -0
- wbfdm/contrib/metric/migrations/0001_initial.py +88 -0
- wbfdm/contrib/metric/migrations/0002_remove_instrumentmetric_unique_instrument_metric_and_more.py +26 -0
- wbfdm/contrib/metric/migrations/__init__.py +0 -0
- wbfdm/contrib/metric/models.py +180 -0
- wbfdm/contrib/metric/orchestrators.py +94 -0
- wbfdm/contrib/metric/registry.py +80 -0
- wbfdm/contrib/metric/serializers.py +44 -0
- wbfdm/contrib/metric/tasks.py +27 -0
- wbfdm/contrib/metric/tests/__init__.py +0 -0
- wbfdm/contrib/metric/tests/backends/__init__.py +0 -0
- wbfdm/contrib/metric/tests/backends/test_performances.py +152 -0
- wbfdm/contrib/metric/tests/backends/test_statistics.py +48 -0
- wbfdm/contrib/metric/tests/conftest.py +92 -0
- wbfdm/contrib/metric/tests/test_dto.py +73 -0
- wbfdm/contrib/metric/tests/test_models.py +72 -0
- wbfdm/contrib/metric/tests/test_tasks.py +24 -0
- wbfdm/contrib/metric/tests/test_viewsets.py +79 -0
- wbfdm/contrib/metric/urls.py +19 -0
- wbfdm/contrib/metric/viewsets/__init__.py +1 -0
- wbfdm/contrib/metric/viewsets/configs/__init__.py +1 -0
- wbfdm/contrib/metric/viewsets/configs/display.py +92 -0
- wbfdm/contrib/metric/viewsets/configs/menus.py +11 -0
- wbfdm/contrib/metric/viewsets/configs/utils.py +137 -0
- wbfdm/contrib/metric/viewsets/mixins.py +248 -0
- wbfdm/contrib/metric/viewsets/viewsets.py +40 -0
- wbfdm/contrib/msci/__init__.py +0 -0
- wbfdm/contrib/msci/client.py +92 -0
- wbfdm/contrib/msci/dataloaders/__init__.py +0 -0
- wbfdm/contrib/msci/dataloaders/esg.py +87 -0
- wbfdm/contrib/msci/dataloaders/esg_controversies.py +81 -0
- wbfdm/contrib/msci/sync.py +58 -0
- wbfdm/contrib/msci/tests/__init__.py +0 -0
- wbfdm/contrib/msci/tests/conftest.py +1 -0
- wbfdm/contrib/msci/tests/test_client.py +70 -0
- wbfdm/contrib/qa/__init__.py +0 -0
- wbfdm/contrib/qa/apps.py +22 -0
- wbfdm/contrib/qa/database_routers.py +25 -0
- wbfdm/contrib/qa/dataloaders/__init__.py +0 -0
- wbfdm/contrib/qa/dataloaders/adjustments.py +56 -0
- wbfdm/contrib/qa/dataloaders/corporate_actions.py +59 -0
- wbfdm/contrib/qa/dataloaders/financials.py +83 -0
- wbfdm/contrib/qa/dataloaders/market_data.py +117 -0
- wbfdm/contrib/qa/dataloaders/officers.py +59 -0
- wbfdm/contrib/qa/dataloaders/reporting_dates.py +67 -0
- wbfdm/contrib/qa/dataloaders/statements.py +267 -0
- wbfdm/contrib/qa/jinja2/qa/sql/companies.sql +100 -0
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/base_estimates.sql +33 -0
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/calendarized.sql +37 -0
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/complete.sql +9 -0
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/estimates.sql +3 -0
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql +79 -0
- wbfdm/contrib/qa/jinja2/qa/sql/instruments.sql +100 -0
- wbfdm/contrib/qa/jinja2/qa/sql/quotes.sql +98 -0
- wbfdm/contrib/qa/sync/exchanges.py +70 -0
- wbfdm/contrib/qa/sync/instruments.py +94 -0
- wbfdm/contrib/qa/sync/utils.py +241 -0
- wbfdm/contrib/qa/tasks.py +0 -0
- wbfdm/dataloaders/__init__.py +0 -0
- wbfdm/dataloaders/cache.py +129 -0
- wbfdm/dataloaders/protocols.py +112 -0
- wbfdm/dataloaders/proxies.py +201 -0
- wbfdm/dataloaders/types.py +209 -0
- wbfdm/dynamic_preferences_registry.py +45 -0
- wbfdm/enums.py +657 -0
- wbfdm/factories/__init__.py +13 -0
- wbfdm/factories/classifications.py +56 -0
- wbfdm/factories/controversies.py +27 -0
- wbfdm/factories/exchanges.py +21 -0
- wbfdm/factories/instrument_list.py +22 -0
- wbfdm/factories/instrument_prices.py +79 -0
- wbfdm/factories/instruments.py +63 -0
- wbfdm/factories/instruments_relationships.py +31 -0
- wbfdm/factories/options.py +66 -0
- wbfdm/figures/__init__.py +1 -0
- wbfdm/figures/financials/__init__.py +1 -0
- wbfdm/figures/financials/financial_analysis_charts.py +469 -0
- wbfdm/figures/financials/financials_charts.py +711 -0
- wbfdm/filters/__init__.py +31 -0
- wbfdm/filters/classifications.py +100 -0
- wbfdm/filters/exchanges.py +22 -0
- wbfdm/filters/financials.py +95 -0
- wbfdm/filters/financials_analysis.py +119 -0
- wbfdm/filters/instrument_prices.py +112 -0
- wbfdm/filters/instruments.py +198 -0
- wbfdm/filters/utils.py +44 -0
- wbfdm/import_export/__init__.py +0 -0
- wbfdm/import_export/backends/__init__.py +0 -0
- wbfdm/import_export/backends/cbinsights/__init__.py +2 -0
- wbfdm/import_export/backends/cbinsights/deals.py +44 -0
- wbfdm/import_export/backends/cbinsights/equities.py +41 -0
- wbfdm/import_export/backends/cbinsights/mixin.py +15 -0
- wbfdm/import_export/backends/cbinsights/utils/__init__.py +0 -0
- wbfdm/import_export/backends/cbinsights/utils/classifications.py +4150 -0
- wbfdm/import_export/backends/cbinsights/utils/client.py +217 -0
- wbfdm/import_export/backends/refinitiv/__init__.py +5 -0
- wbfdm/import_export/backends/refinitiv/daily_fundamental.py +36 -0
- wbfdm/import_export/backends/refinitiv/fiscal_period.py +63 -0
- wbfdm/import_export/backends/refinitiv/forecast.py +178 -0
- wbfdm/import_export/backends/refinitiv/fundamental.py +103 -0
- wbfdm/import_export/backends/refinitiv/geographic_segment.py +32 -0
- wbfdm/import_export/backends/refinitiv/instrument.py +55 -0
- wbfdm/import_export/backends/refinitiv/instrument_price.py +77 -0
- wbfdm/import_export/backends/refinitiv/mixin.py +29 -0
- wbfdm/import_export/backends/refinitiv/utils/__init__.py +1 -0
- wbfdm/import_export/backends/refinitiv/utils/controller.py +182 -0
- wbfdm/import_export/handlers/__init__.py +0 -0
- wbfdm/import_export/handlers/instrument.py +253 -0
- wbfdm/import_export/handlers/instrument_list.py +101 -0
- wbfdm/import_export/handlers/instrument_price.py +71 -0
- wbfdm/import_export/handlers/option.py +54 -0
- wbfdm/import_export/handlers/private_equities.py +49 -0
- wbfdm/import_export/parsers/__init__.py +0 -0
- wbfdm/import_export/parsers/cbinsights/__init__.py +0 -0
- wbfdm/import_export/parsers/cbinsights/deals.py +39 -0
- wbfdm/import_export/parsers/cbinsights/equities.py +56 -0
- wbfdm/import_export/parsers/cbinsights/fundamentals.py +45 -0
- wbfdm/import_export/parsers/refinitiv/__init__.py +0 -0
- wbfdm/import_export/parsers/refinitiv/daily_fundamental.py +7 -0
- wbfdm/import_export/parsers/refinitiv/forecast.py +7 -0
- wbfdm/import_export/parsers/refinitiv/fundamental.py +9 -0
- wbfdm/import_export/parsers/refinitiv/geographic_segment.py +7 -0
- wbfdm/import_export/parsers/refinitiv/instrument.py +75 -0
- wbfdm/import_export/parsers/refinitiv/instrument_price.py +26 -0
- wbfdm/import_export/parsers/refinitiv/utils.py +96 -0
- wbfdm/import_export/resources/__init__.py +0 -0
- wbfdm/import_export/resources/classification.py +23 -0
- wbfdm/import_export/resources/instrument_prices.py +33 -0
- wbfdm/import_export/resources/instruments.py +176 -0
- wbfdm/jinja2.py +7 -0
- wbfdm/management/__init__.py +30 -0
- wbfdm/menu.py +11 -0
- wbfdm/migrations/0001_initial.py +71 -0
- wbfdm/migrations/0002_rename_statements_instrumentlookup_financials_and_more.py +144 -0
- wbfdm/migrations/0003_instrument_estimate_backend_and_more.py +34 -0
- wbfdm/migrations/0004_rename_financials_instrumentlookup_statements_and_more.py +86 -0
- wbfdm/migrations/0005_instrument_corporate_action_backend.py +29 -0
- wbfdm/migrations/0006_instrument_officer_backend.py +29 -0
- wbfdm/migrations/0007_instrument_country_instrument_currency_and_more.py +117 -0
- wbfdm/migrations/0008_controversy.py +75 -0
- wbfdm/migrations/0009_alter_controversy_flag_alter_controversy_initiated_and_more.py +85 -0
- wbfdm/migrations/0010_classification_classificationgroup_deal_exchange_and_more.py +1299 -0
- wbfdm/migrations/0011_delete_instrumentlookup_instrument_corporate_actions_and_more.py +169 -0
- wbfdm/migrations/0012_instrumentprice_created_instrumentprice_modified.py +564 -0
- wbfdm/migrations/0013_instrument_is_investable_universe_and_more.py +199 -0
- wbfdm/migrations/0014_alter_controversy_instrument.py +22 -0
- wbfdm/migrations/0015_instrument_instrument_investible_index.py +16 -0
- wbfdm/migrations/0016_instrumenttype_name_repr.py +18 -0
- wbfdm/migrations/0017_instrument_instrument_security_index.py +16 -0
- wbfdm/migrations/0018_instrument_instrument_level_index.py +20 -0
- wbfdm/migrations/0019_alter_controversy_source.py +17 -0
- wbfdm/migrations/0020_optionaggregate_option_and_more.py +249 -0
- wbfdm/migrations/0021_delete_instrumentdailystatistics.py +15 -0
- wbfdm/migrations/0022_instrument_cusip_option_open_interest_20d_and_more.py +91 -0
- wbfdm/migrations/0023_instrument_unique_ric_instrument_unique_rmc_and_more.py +53 -0
- wbfdm/migrations/0024_option_open_interest_10d_option_volume_10d_and_more.py +36 -0
- wbfdm/migrations/0025_instrument_is_primary_and_more.py +29 -0
- wbfdm/migrations/0026_instrument_is_cash_equivalent.py +30 -0
- wbfdm/migrations/0027_remove_instrument_unique_ric_and_more.py +100 -0
- wbfdm/migrations/0028_instrumentprice_annualized_daily_volatility.py +17 -0
- wbfdm/migrations/__init__.py +0 -0
- wbfdm/models/__init__.py +4 -0
- wbfdm/models/esg/__init__.py +1 -0
- wbfdm/models/esg/controversies.py +81 -0
- wbfdm/models/exchanges/__init__.py +1 -0
- wbfdm/models/exchanges/exchanges.py +223 -0
- wbfdm/models/fields.py +117 -0
- wbfdm/models/fk_fields.py +403 -0
- wbfdm/models/indicators.py +0 -0
- wbfdm/models/instruments/__init__.py +19 -0
- wbfdm/models/instruments/classifications.py +265 -0
- wbfdm/models/instruments/instrument_lists.py +120 -0
- wbfdm/models/instruments/instrument_prices.py +544 -0
- wbfdm/models/instruments/instrument_relationships.py +251 -0
- wbfdm/models/instruments/instrument_requests.py +196 -0
- wbfdm/models/instruments/instruments.py +991 -0
- wbfdm/models/instruments/llm/__init__.py +1 -0
- wbfdm/models/instruments/llm/create_instrument_news_relationships.py +78 -0
- wbfdm/models/instruments/mixin/__init__.py +0 -0
- wbfdm/models/instruments/mixin/financials_computed.py +804 -0
- wbfdm/models/instruments/mixin/financials_serializer_fields.py +1407 -0
- wbfdm/models/instruments/mixin/instruments.py +297 -0
- wbfdm/models/instruments/options.py +225 -0
- wbfdm/models/instruments/private_equities.py +59 -0
- wbfdm/models/instruments/querysets.py +73 -0
- wbfdm/models/instruments/utils.py +41 -0
- wbfdm/preferences.py +21 -0
- wbfdm/serializers/__init__.py +4 -0
- wbfdm/serializers/esg.py +36 -0
- wbfdm/serializers/exchanges.py +39 -0
- wbfdm/serializers/instruments/__init__.py +37 -0
- wbfdm/serializers/instruments/classifications.py +139 -0
- wbfdm/serializers/instruments/instrument_lists.py +61 -0
- wbfdm/serializers/instruments/instrument_prices.py +73 -0
- wbfdm/serializers/instruments/instrument_relationships.py +170 -0
- wbfdm/serializers/instruments/instrument_requests.py +61 -0
- wbfdm/serializers/instruments/instruments.py +274 -0
- wbfdm/serializers/instruments/mixins.py +104 -0
- wbfdm/serializers/officers.py +20 -0
- wbfdm/signals.py +7 -0
- wbfdm/sync/__init__.py +0 -0
- wbfdm/sync/abstract.py +31 -0
- wbfdm/sync/runner.py +22 -0
- wbfdm/tasks.py +69 -0
- wbfdm/tests/__init__.py +0 -0
- wbfdm/tests/analysis/__init__.py +0 -0
- wbfdm/tests/analysis/financial_analysis/__init__.py +0 -0
- wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +392 -0
- wbfdm/tests/analysis/financial_analysis/test_utils.py +322 -0
- wbfdm/tests/analysis/test_esg.py +159 -0
- wbfdm/tests/conftest.py +92 -0
- wbfdm/tests/dataloaders/__init__.py +0 -0
- wbfdm/tests/dataloaders/test_cache.py +73 -0
- wbfdm/tests/models/__init__.py +0 -0
- wbfdm/tests/models/test_classifications.py +99 -0
- wbfdm/tests/models/test_exchanges.py +7 -0
- wbfdm/tests/models/test_instrument_list.py +117 -0
- wbfdm/tests/models/test_instrument_prices.py +306 -0
- wbfdm/tests/models/test_instruments.py +202 -0
- wbfdm/tests/models/test_merge.py +99 -0
- wbfdm/tests/models/test_options.py +69 -0
- wbfdm/tests/test_tasks.py +6 -0
- wbfdm/tests/tests.py +10 -0
- wbfdm/urls.py +222 -0
- wbfdm/utils.py +54 -0
- wbfdm/viewsets/__init__.py +10 -0
- wbfdm/viewsets/configs/__init__.py +5 -0
- wbfdm/viewsets/configs/buttons/__init__.py +8 -0
- wbfdm/viewsets/configs/buttons/classifications.py +23 -0
- wbfdm/viewsets/configs/buttons/exchanges.py +9 -0
- wbfdm/viewsets/configs/buttons/instrument_prices.py +49 -0
- wbfdm/viewsets/configs/buttons/instruments.py +283 -0
- wbfdm/viewsets/configs/display/__init__.py +22 -0
- wbfdm/viewsets/configs/display/classifications.py +138 -0
- wbfdm/viewsets/configs/display/esg.py +75 -0
- wbfdm/viewsets/configs/display/exchanges.py +42 -0
- wbfdm/viewsets/configs/display/instrument_lists.py +137 -0
- wbfdm/viewsets/configs/display/instrument_prices.py +199 -0
- wbfdm/viewsets/configs/display/instrument_requests.py +116 -0
- wbfdm/viewsets/configs/display/instruments.py +340 -0
- wbfdm/viewsets/configs/display/instruments_relationships.py +65 -0
- wbfdm/viewsets/configs/display/monthly_performances.py +72 -0
- wbfdm/viewsets/configs/display/officers.py +16 -0
- wbfdm/viewsets/configs/display/prices.py +21 -0
- wbfdm/viewsets/configs/display/statement_with_estimates.py +101 -0
- wbfdm/viewsets/configs/display/statements.py +48 -0
- wbfdm/viewsets/configs/endpoints/__init__.py +41 -0
- wbfdm/viewsets/configs/endpoints/classifications.py +87 -0
- wbfdm/viewsets/configs/endpoints/esg.py +20 -0
- wbfdm/viewsets/configs/endpoints/exchanges.py +6 -0
- wbfdm/viewsets/configs/endpoints/financials_analysis.py +65 -0
- wbfdm/viewsets/configs/endpoints/instrument_lists.py +38 -0
- wbfdm/viewsets/configs/endpoints/instrument_prices.py +51 -0
- wbfdm/viewsets/configs/endpoints/instrument_requests.py +20 -0
- wbfdm/viewsets/configs/endpoints/instruments.py +13 -0
- wbfdm/viewsets/configs/endpoints/instruments_relationships.py +31 -0
- wbfdm/viewsets/configs/endpoints/statements.py +6 -0
- wbfdm/viewsets/configs/menus/__init__.py +9 -0
- wbfdm/viewsets/configs/menus/classifications.py +19 -0
- wbfdm/viewsets/configs/menus/exchanges.py +10 -0
- wbfdm/viewsets/configs/menus/instrument_lists.py +10 -0
- wbfdm/viewsets/configs/menus/instruments.py +20 -0
- wbfdm/viewsets/configs/menus/instruments_relationships.py +33 -0
- wbfdm/viewsets/configs/titles/__init__.py +42 -0
- wbfdm/viewsets/configs/titles/classifications.py +79 -0
- wbfdm/viewsets/configs/titles/esg.py +11 -0
- wbfdm/viewsets/configs/titles/exchanges.py +12 -0
- wbfdm/viewsets/configs/titles/financial_ratio_analysis.py +6 -0
- wbfdm/viewsets/configs/titles/financials_analysis.py +50 -0
- wbfdm/viewsets/configs/titles/instrument_prices.py +50 -0
- wbfdm/viewsets/configs/titles/instrument_requests.py +16 -0
- wbfdm/viewsets/configs/titles/instruments.py +31 -0
- wbfdm/viewsets/configs/titles/instruments_relationships.py +21 -0
- wbfdm/viewsets/configs/titles/market_data.py +13 -0
- wbfdm/viewsets/configs/titles/prices.py +15 -0
- wbfdm/viewsets/configs/titles/statement_with_estimates.py +10 -0
- wbfdm/viewsets/esg.py +72 -0
- wbfdm/viewsets/exchanges.py +63 -0
- wbfdm/viewsets/financial_analysis/__init__.py +3 -0
- wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +85 -0
- wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +85 -0
- wbfdm/viewsets/financial_analysis/statement_with_estimates.py +145 -0
- wbfdm/viewsets/instruments/__init__.py +80 -0
- wbfdm/viewsets/instruments/classifications.py +279 -0
- wbfdm/viewsets/instruments/financials_analysis.py +614 -0
- wbfdm/viewsets/instruments/instrument_lists.py +77 -0
- wbfdm/viewsets/instruments/instrument_prices.py +542 -0
- wbfdm/viewsets/instruments/instrument_requests.py +51 -0
- wbfdm/viewsets/instruments/instruments.py +106 -0
- wbfdm/viewsets/instruments/instruments_relationships.py +235 -0
- wbfdm/viewsets/instruments/utils.py +27 -0
- wbfdm/viewsets/market_data.py +172 -0
- wbfdm/viewsets/mixins.py +9 -0
- wbfdm/viewsets/officers.py +27 -0
- wbfdm/viewsets/prices.py +62 -0
- wbfdm/viewsets/statements/__init__.py +1 -0
- wbfdm/viewsets/statements/statements.py +100 -0
- wbfdm/viewsets/technical_analysis/__init__.py +1 -0
- wbfdm/viewsets/technical_analysis/monthly_performances.py +93 -0
- wbfdm-1.43.1.dist-info/METADATA +15 -0
- wbfdm-1.43.1.dist-info/RECORD +351 -0
- wbfdm-1.43.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import itertools
|
|
2
|
+
from typing import Any, Generic, Iterable, TypedDict, TypeVar, cast
|
|
3
|
+
|
|
4
|
+
from django.core.cache import cache
|
|
5
|
+
|
|
6
|
+
T = TypeVar("T", bound=TypedDict)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Cache(Generic[T]):
|
|
10
|
+
"""
|
|
11
|
+
A Cache Class to handle 3-Dimensional data (identifier-key-value)
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
def __init__(
|
|
15
|
+
self,
|
|
16
|
+
identifier_key: str = "instrument_id",
|
|
17
|
+
symbol_key: str = "factor_code",
|
|
18
|
+
value_key: str = "value",
|
|
19
|
+
timeout: int | None = None,
|
|
20
|
+
):
|
|
21
|
+
"""
|
|
22
|
+
Constructor of the Cache Class
|
|
23
|
+
Args:
|
|
24
|
+
identifier_key: The lookup identifier field. Default to `instrument_id`
|
|
25
|
+
symbol_key: The symbol lookup field. Default to `factor_code`
|
|
26
|
+
value_key: The value lookup field. Default to `value`
|
|
27
|
+
timeout: The cache timeout configuration value. Default to None (never expired)
|
|
28
|
+
"""
|
|
29
|
+
self.identifier_key = identifier_key
|
|
30
|
+
self.symbol_key = symbol_key
|
|
31
|
+
self.value_key = value_key
|
|
32
|
+
self.timeout = timeout
|
|
33
|
+
self.id_symbol_pairs: list[tuple[str, str]] = []
|
|
34
|
+
self.missing_keys = []
|
|
35
|
+
self.missing_ids = set()
|
|
36
|
+
self.missing_symbols = set()
|
|
37
|
+
|
|
38
|
+
def _get_cache_key(self, id: str, symbol: str) -> str:
|
|
39
|
+
"""
|
|
40
|
+
Generate the key used in the caching layer based on the given ID and symbol.
|
|
41
|
+
|
|
42
|
+
Args:
|
|
43
|
+
id (str): The ID to be used in the cache key.
|
|
44
|
+
symbol (str): The symbol to be used in the cache key.
|
|
45
|
+
|
|
46
|
+
Returns:
|
|
47
|
+
str: A cache key in the format "id_symbol" where both the ID and symbol
|
|
48
|
+
are in lowercase.
|
|
49
|
+
"""
|
|
50
|
+
return f"{str(id).lower()}_{symbol.lower()}"
|
|
51
|
+
|
|
52
|
+
def _deserialize_cache(self, id: str, symbol: str, value: Any) -> T:
|
|
53
|
+
"""
|
|
54
|
+
Data retreived from cache is deserialized using this method. We expect a key value format which is converted into a dictionary with keys as identifier, symbol and value
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
id: identifier
|
|
58
|
+
symbol: symbol
|
|
59
|
+
value: value
|
|
60
|
+
|
|
61
|
+
Returns:
|
|
62
|
+
a dictionary with keys as identifier, symbol and value
|
|
63
|
+
"""
|
|
64
|
+
res = {self.identifier_key: int(id), self.symbol_key: symbol, self.value_key: value}
|
|
65
|
+
return cast(T, res)
|
|
66
|
+
|
|
67
|
+
def initialize(self, ids: list[int], symbols: list[str]):
|
|
68
|
+
"""
|
|
69
|
+
Initialize the instance with a list of IDs and symbols.
|
|
70
|
+
|
|
71
|
+
This method takes a list of identifiers and a list of symbols and creates a list of
|
|
72
|
+
tuples containing all possible pairs of identifiers (converted to strings) and symbols.
|
|
73
|
+
It also initializes sets for symbol and identifiers not present in cache
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
ids (list[int]): A list of integer IDs.
|
|
77
|
+
symbols (list[str]): A list of symbol strings.
|
|
78
|
+
"""
|
|
79
|
+
self.id_symbol_pairs = list(map(lambda x: (str(x[0]), x[1]), itertools.product(ids, symbols)))
|
|
80
|
+
self.missing_ids = set()
|
|
81
|
+
self.missing_symbols = set()
|
|
82
|
+
self.missing_keys = list()
|
|
83
|
+
|
|
84
|
+
def fetch_from_cache(self) -> Iterable[T]:
|
|
85
|
+
"""
|
|
86
|
+
Fetch values already stored in the cache.
|
|
87
|
+
|
|
88
|
+
This method iterates over all identifiers and symbols pair and return the cached value if it exists or mark this pair as missing
|
|
89
|
+
|
|
90
|
+
Yields:
|
|
91
|
+
T: Deserialized cached values.
|
|
92
|
+
"""
|
|
93
|
+
sentinel = object()
|
|
94
|
+
for id, symbol in self.id_symbol_pairs:
|
|
95
|
+
key = self._get_cache_key(id, symbol)
|
|
96
|
+
cached_value = cache.get(key, sentinel)
|
|
97
|
+
if cached_value is not None and cached_value is not sentinel:
|
|
98
|
+
yield self._deserialize_cache(id, symbol, cached_value)
|
|
99
|
+
elif (
|
|
100
|
+
cached_value is sentinel
|
|
101
|
+
): # otherwise, it's literal None and then it means the cache contains "None" for that key
|
|
102
|
+
self.missing_symbols.add(symbol)
|
|
103
|
+
self.missing_ids.add(id)
|
|
104
|
+
self.missing_keys.append(key)
|
|
105
|
+
|
|
106
|
+
def write(self, row: T) -> T:
|
|
107
|
+
"""
|
|
108
|
+
Write given row into the cache
|
|
109
|
+
|
|
110
|
+
Args:
|
|
111
|
+
row: a dictionary typed object
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
a dictionary typed object
|
|
115
|
+
"""
|
|
116
|
+
if (key := row.get(self.identifier_key)) and (symbol := row.get(self.symbol_key)):
|
|
117
|
+
value = row.get(self.value_key)
|
|
118
|
+
key = self._get_cache_key(str(key), str(symbol))
|
|
119
|
+
cache.set(key, value, timeout=self.timeout)
|
|
120
|
+
if key in self.missing_keys: # mark row's key are "handled"
|
|
121
|
+
self.missing_keys.remove(key)
|
|
122
|
+
return row
|
|
123
|
+
|
|
124
|
+
def close(self):
|
|
125
|
+
"""
|
|
126
|
+
Close cache stream by fixing missing keys not handled as None value in the cache (it shows that the value was actually fetched but didn't returned any value)
|
|
127
|
+
"""
|
|
128
|
+
for key in self.missing_keys:
|
|
129
|
+
cache.set(key, None, timeout=self.timeout)
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
from typing import Iterator, Protocol
|
|
3
|
+
|
|
4
|
+
from wbfdm.dataloaders.types import (
|
|
5
|
+
AdjustmentDataDict,
|
|
6
|
+
CorporateActionDataDict,
|
|
7
|
+
ESGControversyDataDict,
|
|
8
|
+
ESGDataDict,
|
|
9
|
+
FinancialDataDict,
|
|
10
|
+
MarketDataDict,
|
|
11
|
+
OfficerDataDict,
|
|
12
|
+
ReportDateDataDict,
|
|
13
|
+
StatementDataDict,
|
|
14
|
+
)
|
|
15
|
+
from wbfdm.enums import (
|
|
16
|
+
ESG,
|
|
17
|
+
CalendarType,
|
|
18
|
+
DataType,
|
|
19
|
+
EstimateType,
|
|
20
|
+
Financial,
|
|
21
|
+
Frequency,
|
|
22
|
+
MarketData,
|
|
23
|
+
PeriodType,
|
|
24
|
+
SeriesType,
|
|
25
|
+
StatementType,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class ReportDateProtocol(Protocol):
|
|
30
|
+
def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]:
|
|
31
|
+
...
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
class AdjustmentsProtocol(Protocol):
|
|
35
|
+
def adjustments(self, from_date: date, to_date: date) -> Iterator[AdjustmentDataDict]:
|
|
36
|
+
...
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class MarketDataProtocol(Protocol):
|
|
40
|
+
def market_data(
|
|
41
|
+
self,
|
|
42
|
+
values: list[MarketData] | None = [MarketData.CLOSE],
|
|
43
|
+
from_date: date | None = None,
|
|
44
|
+
to_date: date | None = None,
|
|
45
|
+
exact_date: date | None = None,
|
|
46
|
+
frequency: Frequency = Frequency.DAILY,
|
|
47
|
+
target_currency: str | None = None,
|
|
48
|
+
) -> Iterator[MarketDataDict]:
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class CorporateActionsProtocol(Protocol):
|
|
53
|
+
def corporate_actions(
|
|
54
|
+
self, from_date: date | None = None, to_date: date | None = None
|
|
55
|
+
) -> Iterator[CorporateActionDataDict]:
|
|
56
|
+
...
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
class OfficersProtocol(Protocol):
|
|
60
|
+
def officers(self) -> Iterator[OfficerDataDict]:
|
|
61
|
+
...
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
class StatementsProtocol(Protocol):
|
|
65
|
+
def statements(
|
|
66
|
+
self,
|
|
67
|
+
statement_type: StatementType | None = None,
|
|
68
|
+
from_date: date | None = None,
|
|
69
|
+
to_date: date | None = None,
|
|
70
|
+
from_year: int | None = None,
|
|
71
|
+
to_year: int | None = None,
|
|
72
|
+
period_type: PeriodType = PeriodType.ALL,
|
|
73
|
+
data_type: DataType = DataType.STANDARDIZED,
|
|
74
|
+
financials: list[Financial] | None = None,
|
|
75
|
+
target_currency: str | None = None,
|
|
76
|
+
) -> Iterator[StatementDataDict]:
|
|
77
|
+
...
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class FinancialsProtocol(Protocol):
|
|
81
|
+
def financials(
|
|
82
|
+
self,
|
|
83
|
+
values: list[Financial],
|
|
84
|
+
from_date: date | None = None,
|
|
85
|
+
to_date: date | None = None,
|
|
86
|
+
from_year: int | None = None,
|
|
87
|
+
to_year: int | None = None,
|
|
88
|
+
from_index: int | None = None,
|
|
89
|
+
to_index: int | None = None,
|
|
90
|
+
from_valid: date | None = None,
|
|
91
|
+
to_valid: date | None = None,
|
|
92
|
+
period_type: PeriodType = PeriodType.ANNUAL,
|
|
93
|
+
calendar_type: CalendarType = CalendarType.FISCAL,
|
|
94
|
+
series_type: SeriesType = SeriesType.COMPLETE,
|
|
95
|
+
data_type: DataType = DataType.STANDARDIZED,
|
|
96
|
+
estimate_type: EstimateType = EstimateType.VALID,
|
|
97
|
+
target_currency: str | None = None,
|
|
98
|
+
) -> Iterator[FinancialDataDict]:
|
|
99
|
+
...
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
class ESGControversyProtocol(Protocol):
|
|
103
|
+
def esg_controversies(self) -> Iterator[ESGControversyDataDict]:
|
|
104
|
+
...
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class ESGProtocol(Protocol):
|
|
108
|
+
def esg(
|
|
109
|
+
self,
|
|
110
|
+
values: list[ESG],
|
|
111
|
+
) -> Iterator[ESGDataDict]:
|
|
112
|
+
...
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
from typing import Iterator
|
|
3
|
+
|
|
4
|
+
from wbcore.contrib.dataloader.dataloaders import DataloaderProxy
|
|
5
|
+
from wbfdm.dataloaders.protocols import (
|
|
6
|
+
AdjustmentsProtocol,
|
|
7
|
+
CorporateActionsProtocol,
|
|
8
|
+
ESGControversyProtocol,
|
|
9
|
+
ESGProtocol,
|
|
10
|
+
FinancialsProtocol,
|
|
11
|
+
MarketDataProtocol,
|
|
12
|
+
OfficersProtocol,
|
|
13
|
+
ReportDateProtocol,
|
|
14
|
+
StatementsProtocol,
|
|
15
|
+
)
|
|
16
|
+
from wbfdm.dataloaders.types import (
|
|
17
|
+
AdjustmentDataDict,
|
|
18
|
+
CorporateActionDataDict,
|
|
19
|
+
ESGControversyDataDict,
|
|
20
|
+
ESGDataDict,
|
|
21
|
+
FinancialDataDict,
|
|
22
|
+
MarketDataDict,
|
|
23
|
+
OfficerDataDict,
|
|
24
|
+
ReportDateDataDict,
|
|
25
|
+
StatementDataDict,
|
|
26
|
+
)
|
|
27
|
+
from wbfdm.enums import (
|
|
28
|
+
ESG,
|
|
29
|
+
CalendarType,
|
|
30
|
+
DataType,
|
|
31
|
+
EstimateType,
|
|
32
|
+
Financial,
|
|
33
|
+
Frequency,
|
|
34
|
+
MarketData,
|
|
35
|
+
PeriodType,
|
|
36
|
+
SeriesType,
|
|
37
|
+
StatementType,
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
from .cache import Cache
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def _market_data_row_parser(row):
|
|
44
|
+
if row.get("close") is None and (bid := row.get("bid")) is not None and (ask := row.get("ask")) is not None:
|
|
45
|
+
price = (bid + ask) / 2
|
|
46
|
+
row["close"] = price
|
|
47
|
+
row["open"] = price
|
|
48
|
+
row["low"] = price
|
|
49
|
+
row["high"] = price
|
|
50
|
+
return row
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InstrumentDataloaderProxy(
|
|
54
|
+
DataloaderProxy[
|
|
55
|
+
AdjustmentsProtocol
|
|
56
|
+
| MarketDataProtocol
|
|
57
|
+
| CorporateActionsProtocol
|
|
58
|
+
| OfficersProtocol
|
|
59
|
+
| StatementsProtocol
|
|
60
|
+
| FinancialsProtocol
|
|
61
|
+
| ReportDateProtocol
|
|
62
|
+
| ESGControversyProtocol
|
|
63
|
+
| ESGProtocol
|
|
64
|
+
]
|
|
65
|
+
):
|
|
66
|
+
def reporting_dates(self, only_next: bool = True) -> Iterator[ReportDateDataDict]:
|
|
67
|
+
for dl in self.iterate_dataloaders("reporting_dates"):
|
|
68
|
+
yield from dl.reporting_dates(only_next=only_next)
|
|
69
|
+
|
|
70
|
+
def adjustments(self, from_date: date, to_date: date) -> Iterator[AdjustmentDataDict]:
|
|
71
|
+
for dl in self.iterate_dataloaders("adjustments"):
|
|
72
|
+
yield from dl.adjustments(from_date=from_date, to_date=to_date)
|
|
73
|
+
|
|
74
|
+
def market_data(
|
|
75
|
+
self,
|
|
76
|
+
values: list[MarketData] | None = None,
|
|
77
|
+
from_date: date | None = None,
|
|
78
|
+
to_date: date | None = None,
|
|
79
|
+
exact_date: date | None = None,
|
|
80
|
+
frequency: Frequency = Frequency.DAILY,
|
|
81
|
+
target_currency: str | None = None,
|
|
82
|
+
) -> Iterator[MarketDataDict]:
|
|
83
|
+
if not values:
|
|
84
|
+
values = list(MarketData)
|
|
85
|
+
for dl in self.iterate_dataloaders("market_data"):
|
|
86
|
+
yield from map(
|
|
87
|
+
lambda row: _market_data_row_parser(row),
|
|
88
|
+
dl.market_data(
|
|
89
|
+
values=values,
|
|
90
|
+
from_date=from_date,
|
|
91
|
+
to_date=to_date,
|
|
92
|
+
exact_date=exact_date,
|
|
93
|
+
frequency=frequency,
|
|
94
|
+
target_currency=target_currency,
|
|
95
|
+
),
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def corporate_actions(
|
|
99
|
+
self, from_date: date | None = None, to_date: date | None = None
|
|
100
|
+
) -> Iterator[CorporateActionDataDict]:
|
|
101
|
+
for dl in self.iterate_dataloaders("corporate_actions"):
|
|
102
|
+
yield from dl.corporate_actions(from_date=from_date, to_date=to_date)
|
|
103
|
+
|
|
104
|
+
def officers(self) -> Iterator[OfficerDataDict]:
|
|
105
|
+
for dl in self.iterate_dataloaders("officers"):
|
|
106
|
+
yield from dl.officers()
|
|
107
|
+
|
|
108
|
+
def statements(
|
|
109
|
+
self,
|
|
110
|
+
statement_type: StatementType | None = None,
|
|
111
|
+
from_date: date | None = None,
|
|
112
|
+
to_date: date | None = None,
|
|
113
|
+
from_year: int | None = None,
|
|
114
|
+
to_year: int | None = None,
|
|
115
|
+
period_type: PeriodType = PeriodType.ALL,
|
|
116
|
+
data_type: DataType = DataType.STANDARDIZED,
|
|
117
|
+
financials: list[Financial] | None = None,
|
|
118
|
+
target_currency: str | None = None,
|
|
119
|
+
) -> Iterator[StatementDataDict]:
|
|
120
|
+
for dl in self.iterate_dataloaders("statements"):
|
|
121
|
+
yield from dl.statements(
|
|
122
|
+
statement_type=statement_type,
|
|
123
|
+
from_date=from_date,
|
|
124
|
+
to_date=to_date,
|
|
125
|
+
from_year=from_year,
|
|
126
|
+
to_year=to_year,
|
|
127
|
+
period_type=period_type,
|
|
128
|
+
data_type=data_type,
|
|
129
|
+
financials=financials,
|
|
130
|
+
target_currency=target_currency,
|
|
131
|
+
)
|
|
132
|
+
|
|
133
|
+
def financials(
|
|
134
|
+
self,
|
|
135
|
+
values: list[Financial],
|
|
136
|
+
from_date: date | None = None,
|
|
137
|
+
to_date: date | None = None,
|
|
138
|
+
from_year: int | None = None,
|
|
139
|
+
to_year: int | None = None,
|
|
140
|
+
from_index: int | None = None,
|
|
141
|
+
to_index: int | None = None,
|
|
142
|
+
from_valid: date | None = None,
|
|
143
|
+
to_valid: date | None = None,
|
|
144
|
+
period_type: PeriodType = PeriodType.ANNUAL,
|
|
145
|
+
calendar_type: CalendarType = CalendarType.FISCAL,
|
|
146
|
+
series_type: SeriesType = SeriesType.COMPLETE,
|
|
147
|
+
data_type: DataType = DataType.STANDARDIZED,
|
|
148
|
+
estimate_type: EstimateType = EstimateType.VALID,
|
|
149
|
+
target_currency: str | None = None,
|
|
150
|
+
) -> Iterator[FinancialDataDict]:
|
|
151
|
+
for dl in self.iterate_dataloaders("financials"):
|
|
152
|
+
yield from dl.financials(
|
|
153
|
+
values=values,
|
|
154
|
+
from_date=from_date,
|
|
155
|
+
to_date=to_date,
|
|
156
|
+
from_year=from_year,
|
|
157
|
+
to_year=to_year,
|
|
158
|
+
from_index=from_index,
|
|
159
|
+
to_index=to_index,
|
|
160
|
+
from_valid=from_valid,
|
|
161
|
+
to_valid=to_valid,
|
|
162
|
+
period_type=period_type,
|
|
163
|
+
calendar_type=calendar_type,
|
|
164
|
+
series_type=series_type,
|
|
165
|
+
data_type=data_type,
|
|
166
|
+
estimate_type=estimate_type,
|
|
167
|
+
target_currency=target_currency,
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
def esg_controversies(self) -> Iterator[ESGControversyDataDict]:
|
|
171
|
+
for dl in self.iterate_dataloaders("esg_controversies"):
|
|
172
|
+
yield from dl.esg_controversies()
|
|
173
|
+
|
|
174
|
+
def esg(
|
|
175
|
+
self,
|
|
176
|
+
values: list[ESG],
|
|
177
|
+
) -> Iterator[ESGDataDict]:
|
|
178
|
+
for dl in self.iterate_dataloaders("esg"):
|
|
179
|
+
if (
|
|
180
|
+
(cache_identifier_key := getattr(dl, "CACHE_IDENTIFIER_KEY", None))
|
|
181
|
+
and (cache_symbol_key := getattr(dl, "CACHE_SYMBOL_KEY", None))
|
|
182
|
+
and (cache_value_key := getattr(dl, "CACHE_VALUE_KEY", None))
|
|
183
|
+
):
|
|
184
|
+
cache = Cache(
|
|
185
|
+
identifier_key=cache_identifier_key,
|
|
186
|
+
symbol_key=cache_symbol_key,
|
|
187
|
+
value_key=cache_value_key,
|
|
188
|
+
timeout=getattr(dl, "CACHE_TIMEOUT", 10 * 24 * 3600), # default to 10days
|
|
189
|
+
)
|
|
190
|
+
cache.initialize(dl.entity_ids, [v.value for v in values])
|
|
191
|
+
|
|
192
|
+
yield from cache.fetch_from_cache()
|
|
193
|
+
if len(cache.missing_symbols) > 0 and len(cache.missing_ids) > 0:
|
|
194
|
+
dl.entities = dl.entities.filter(id__in=cache.missing_ids)
|
|
195
|
+
yield from map(
|
|
196
|
+
lambda row: cache.write(row),
|
|
197
|
+
dl.esg(values=[v for v in values if v.value in cache.missing_symbols]),
|
|
198
|
+
)
|
|
199
|
+
cache.close()
|
|
200
|
+
else:
|
|
201
|
+
yield from dl.esg(values=values)
|
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
from typing import Literal, TypedDict
|
|
3
|
+
|
|
4
|
+
from typing_extensions import NotRequired
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class BaseDict(TypedDict):
|
|
8
|
+
"""
|
|
9
|
+
Represents a base dictionary with common fields.
|
|
10
|
+
|
|
11
|
+
Attributes:
|
|
12
|
+
id: str | int
|
|
13
|
+
The unique identifier.
|
|
14
|
+
external_id: str | int
|
|
15
|
+
The external identifier.
|
|
16
|
+
source: str
|
|
17
|
+
The source of the data.
|
|
18
|
+
currency: str
|
|
19
|
+
The currency used.
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
id: str | int
|
|
23
|
+
instrument_id: int
|
|
24
|
+
external_id: str | int
|
|
25
|
+
source: str
|
|
26
|
+
currency: NotRequired[str]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class MarketDataDict(BaseDict):
|
|
30
|
+
"""
|
|
31
|
+
Represents a dictionary for daily valuation data.
|
|
32
|
+
|
|
33
|
+
Attributes:
|
|
34
|
+
valuation_date: date
|
|
35
|
+
The date of valuation.
|
|
36
|
+
open: float | None
|
|
37
|
+
The opening value (if available).
|
|
38
|
+
close: float | None
|
|
39
|
+
The closing value (if available).
|
|
40
|
+
high: float | None
|
|
41
|
+
The highest value (if available).
|
|
42
|
+
low: float | None
|
|
43
|
+
The lowest value (if available).
|
|
44
|
+
bid: float | None
|
|
45
|
+
The bid value (if available).
|
|
46
|
+
ask: float | None
|
|
47
|
+
The ask value (if available).
|
|
48
|
+
volume: float | None
|
|
49
|
+
The volume (if available).
|
|
50
|
+
market_cap: float | None
|
|
51
|
+
The market capitalization (if available).
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
valuation_date: date
|
|
55
|
+
|
|
56
|
+
open: NotRequired[float]
|
|
57
|
+
close: NotRequired[float]
|
|
58
|
+
high: NotRequired[float]
|
|
59
|
+
low: NotRequired[float]
|
|
60
|
+
bid: NotRequired[float]
|
|
61
|
+
ask: NotRequired[float]
|
|
62
|
+
volume: NotRequired[float]
|
|
63
|
+
market_cap: NotRequired[float]
|
|
64
|
+
calculated: NotRequired[bool]
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class CorporateActionDataDict(BaseDict):
|
|
68
|
+
old_shares: float
|
|
69
|
+
new_shares: float
|
|
70
|
+
|
|
71
|
+
action_code: str
|
|
72
|
+
event_code: str
|
|
73
|
+
valuation_date: date
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class AdjustmentDataDict(BaseDict):
|
|
77
|
+
adjustment_factor: float
|
|
78
|
+
cumulative_adjustment_factor: float
|
|
79
|
+
|
|
80
|
+
adjustment_date: date
|
|
81
|
+
adjustment_end_date: date
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class FinancialDataDict(BaseDict):
|
|
85
|
+
"""
|
|
86
|
+
Represents a dictionary for financial data.
|
|
87
|
+
|
|
88
|
+
Attributes:
|
|
89
|
+
period_end_date: date
|
|
90
|
+
The period end date / The reporting date
|
|
91
|
+
valid_until: date | None
|
|
92
|
+
The validity date (if available).
|
|
93
|
+
fiscal_year: int
|
|
94
|
+
The fiscal year.
|
|
95
|
+
interim: int
|
|
96
|
+
The interim period. 0 means yearly data.
|
|
97
|
+
estimate: bool
|
|
98
|
+
Indicates if the data is an estimate or actual data
|
|
99
|
+
reported: bool
|
|
100
|
+
Indicates if the data is reported or standardized
|
|
101
|
+
value: str | float | int
|
|
102
|
+
The value.
|
|
103
|
+
financial: str
|
|
104
|
+
The type of financial data.
|
|
105
|
+
"""
|
|
106
|
+
|
|
107
|
+
valid_until: NotRequired[date]
|
|
108
|
+
year: int
|
|
109
|
+
interim: int
|
|
110
|
+
estimate: NotRequired[bool]
|
|
111
|
+
# reported: bool
|
|
112
|
+
|
|
113
|
+
value: str | float | int
|
|
114
|
+
financial: str
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
class StatementDataDict(BaseDict):
|
|
118
|
+
"""
|
|
119
|
+
Represents a dictionary for statement data
|
|
120
|
+
|
|
121
|
+
Attributes:
|
|
122
|
+
external_code: str
|
|
123
|
+
The code that is used by the data vendor to identify this type of financial
|
|
124
|
+
external_ordering: int
|
|
125
|
+
The ordering that is supplied by the data vendor to sort this financial
|
|
126
|
+
external_description: str
|
|
127
|
+
The description supplied by the data vendor to describe this financial
|
|
128
|
+
period_end_date: date
|
|
129
|
+
The period end date / The reporting date
|
|
130
|
+
year: int
|
|
131
|
+
The financial year of the statement.
|
|
132
|
+
interim: int
|
|
133
|
+
The interim period. 0 means yearly data.
|
|
134
|
+
reported: bool
|
|
135
|
+
Indicates if the data is reported or standardized.
|
|
136
|
+
value: float | int
|
|
137
|
+
The value of the datapoint of the statement.
|
|
138
|
+
|
|
139
|
+
"""
|
|
140
|
+
|
|
141
|
+
external_code: str
|
|
142
|
+
external_ordering: int
|
|
143
|
+
external_description: str
|
|
144
|
+
|
|
145
|
+
period_end_date: date
|
|
146
|
+
year: int
|
|
147
|
+
interim: int
|
|
148
|
+
value: float | int
|
|
149
|
+
reported: bool
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class ReportDateDataDict(TypedDict):
|
|
153
|
+
instrument_id: int
|
|
154
|
+
external_id: int
|
|
155
|
+
source: str
|
|
156
|
+
period_end_date: date
|
|
157
|
+
is_interim: bool
|
|
158
|
+
start_date: date
|
|
159
|
+
end_date: date
|
|
160
|
+
market_phase: Literal["before_market"] | Literal["after_market"] | None
|
|
161
|
+
status: Literal["confirmed"] | Literal["tentative"]
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class OfficerDataDict(TypedDict):
|
|
165
|
+
"""
|
|
166
|
+
Represents a dictionary for officers
|
|
167
|
+
|
|
168
|
+
Attributes:
|
|
169
|
+
instrument_id: int
|
|
170
|
+
An identifier to uniquely identify the instrument linked to an officer
|
|
171
|
+
position: str
|
|
172
|
+
The title of the position
|
|
173
|
+
name: str
|
|
174
|
+
The name of the officer
|
|
175
|
+
age: int
|
|
176
|
+
The current age of the officer
|
|
177
|
+
sex: "M" | "F"
|
|
178
|
+
Indicates the sex of the officer
|
|
179
|
+
start: date
|
|
180
|
+
The date when the officer started the position
|
|
181
|
+
"""
|
|
182
|
+
|
|
183
|
+
instrument_id: int
|
|
184
|
+
position: str
|
|
185
|
+
name: str
|
|
186
|
+
age: int
|
|
187
|
+
sex: Literal["M"] | Literal["F"]
|
|
188
|
+
start: date
|
|
189
|
+
|
|
190
|
+
|
|
191
|
+
class ESGDataDict(TypedDict):
|
|
192
|
+
instrument_id: int
|
|
193
|
+
factor_code: str
|
|
194
|
+
value: str | float | int | None
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
class ESGControversyDataDict(TypedDict):
|
|
198
|
+
id: str | int
|
|
199
|
+
instrument_id: str
|
|
200
|
+
headline: str
|
|
201
|
+
narrative: str
|
|
202
|
+
source: str
|
|
203
|
+
response: str
|
|
204
|
+
status: str | None # TODO: Move to enum?
|
|
205
|
+
type: str | None # TODO: Move to enum?
|
|
206
|
+
assessment: str | None # TODO: Move to enum?
|
|
207
|
+
review: date | None
|
|
208
|
+
initiated: date | None
|
|
209
|
+
flag: str | None # TODO: Move to enum?
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from datetime import date
|
|
2
|
+
|
|
3
|
+
from dynamic_preferences.preferences import Section
|
|
4
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
5
|
+
from dynamic_preferences.types import DatePreference, IntPreference, StringPreference
|
|
6
|
+
|
|
7
|
+
fdm = Section("wbfdm")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@global_preferences_registry.register
|
|
11
|
+
class DefaultClassificationGroup(IntPreference):
|
|
12
|
+
section = fdm
|
|
13
|
+
name = "default_classification_group"
|
|
14
|
+
default = 0
|
|
15
|
+
|
|
16
|
+
verbose_name = "Default Classification Group"
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
@global_preferences_registry.register
|
|
20
|
+
class DefaultStartDateHistoricalImport(DatePreference):
|
|
21
|
+
section = fdm
|
|
22
|
+
name = "default_start_date_historical_import"
|
|
23
|
+
default = date(2015, 1, 1)
|
|
24
|
+
|
|
25
|
+
verbose_name = "Default Start Date"
|
|
26
|
+
help_text = "Default start date in historical import"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@global_preferences_registry.register
|
|
30
|
+
class NonTickerWords(StringPreference):
|
|
31
|
+
section = fdm
|
|
32
|
+
name = "non_ticker_words"
|
|
33
|
+
default = ""
|
|
34
|
+
|
|
35
|
+
verbose_name = "Non Ticker Words"
|
|
36
|
+
help_text = "Comma Separated list of non-ticker words"
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class FinancialSummarySectionName(StringPreference):
|
|
40
|
+
section = fdm
|
|
41
|
+
name = "financial_summary_section_name"
|
|
42
|
+
default = "Financial Summary"
|
|
43
|
+
|
|
44
|
+
verbose_name = "Financial Summary Section Name"
|
|
45
|
+
help_text = "This name set the tab section name shown from the instance view"
|