wbfdm 2.2.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 +271 -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/contrib/__init__.py +0 -0
- wbfdm/contrib/dsws/__init__.py +0 -0
- wbfdm/contrib/dsws/client.py +285 -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 +245 -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/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/__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 +540 -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 +294 -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 +618 -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-2.2.1.dist-info/METADATA +15 -0
- wbfdm-2.2.1.dist-info/RECORD +337 -0
- wbfdm-2.2.1.dist-info/WHEEL +5 -0
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import re
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
|
|
4
|
+
from wbcore.contrib.currency.models import Currency
|
|
5
|
+
from wbcore.contrib.geography.models import Geography
|
|
6
|
+
from wbfdm.preferences import get_non_ticker_words
|
|
7
|
+
|
|
8
|
+
START_DELIMITER = r"(?:^|(?<=[(\s\.\-<]))"
|
|
9
|
+
END_DELIMITER = r"(?=[\s\.)\-\>'’,]|$)"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@lru_cache()
|
|
13
|
+
def non_ticker_words():
|
|
14
|
+
return (
|
|
15
|
+
list(Geography.countries.values_list("code_2", flat=True))
|
|
16
|
+
+ list(Geography.countries.values_list("code_3", flat=True))
|
|
17
|
+
+ list(Currency.objects.values_list("key", flat=True))
|
|
18
|
+
+ get_non_ticker_words()
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def re_ric(input: str):
|
|
23
|
+
# [(\s<]([A-Z]{2}[A-Za-z0-9_.-]+\.[A-Za-z]+)[(\s>] led to too many false positive (e.g. end of sentence when whitespace are missing. We refined by considering only uppercase code
|
|
24
|
+
return set(re.findall(START_DELIMITER + r"([A-Z0-9]{2}[A-Z0-9_.-]+\.[A-Z]+)" + END_DELIMITER, input))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def re_bloomberg(input: str):
|
|
28
|
+
return set(
|
|
29
|
+
filter(
|
|
30
|
+
lambda x: x not in non_ticker_words(),
|
|
31
|
+
re.findall(START_DELIMITER + r"([A-Z]{2,5}(?:\-[A-Z]{2})?)" + END_DELIMITER, input),
|
|
32
|
+
)
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def re_isin(input: str):
|
|
37
|
+
return set(re.findall(START_DELIMITER + r"([A-Z]{2}[A-Z0-9]{9}[0-9])" + END_DELIMITER, input))
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def re_mnemonic(input: str):
|
|
41
|
+
return set(re.findall(START_DELIMITER + r"([A-Z]+:[A-Z]+)" + END_DELIMITER, input))
|
wbfdm/preferences.py
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
|
|
3
|
+
from django.db.utils import ProgrammingError
|
|
4
|
+
from dynamic_preferences.registries import global_preferences_registry
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_default_classification_group(*args, **kwargs):
|
|
8
|
+
from wbfdm.models.instruments.classifications import ClassificationGroup
|
|
9
|
+
|
|
10
|
+
with suppress(RuntimeError, ProgrammingError):
|
|
11
|
+
global_preferences = global_preferences_registry.manager()
|
|
12
|
+
if group_id := global_preferences["wbfdm__default_classification_group"]:
|
|
13
|
+
with suppress(ClassificationGroup.DoesNotExist):
|
|
14
|
+
return ClassificationGroup.objects.get(id=group_id)
|
|
15
|
+
return ClassificationGroup.objects.get_or_create(is_primary=True, defaults={"name": "Default"})[0]
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def get_non_ticker_words(*args, **kwargs) -> list[str]:
|
|
19
|
+
global_preferences = global_preferences_registry.manager()
|
|
20
|
+
return global_preferences["wbfdm__non_ticker_words"].split(",")
|
|
21
|
+
return list()
|
wbfdm/serializers/esg.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
from wbcore import serializers
|
|
2
|
+
from wbfdm.enums import (
|
|
3
|
+
ESGControveryFlag,
|
|
4
|
+
ESGControverySeverity,
|
|
5
|
+
ESGControveryStatus,
|
|
6
|
+
ESGControveryType,
|
|
7
|
+
)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InstrumentControversySerializer(serializers.Serializer):
|
|
11
|
+
id = serializers.PrimaryKeyCharField()
|
|
12
|
+
headline = serializers.TextField()
|
|
13
|
+
narrative = serializers.TextField()
|
|
14
|
+
source = serializers.CharField()
|
|
15
|
+
status = serializers.ChoiceField(choices=ESGControveryStatus.choices)
|
|
16
|
+
type = serializers.ChoiceField(choices=ESGControveryType.choices)
|
|
17
|
+
assessment = serializers.ChoiceField(choices=ESGControverySeverity.choices)
|
|
18
|
+
response = serializers.TextField()
|
|
19
|
+
review = serializers.DateField()
|
|
20
|
+
initiated = serializers.DateField()
|
|
21
|
+
flag = serializers.ChoiceField(choices=ESGControveryFlag.choices)
|
|
22
|
+
|
|
23
|
+
class Meta:
|
|
24
|
+
fields = (
|
|
25
|
+
"id",
|
|
26
|
+
"headline",
|
|
27
|
+
"narrative",
|
|
28
|
+
"source",
|
|
29
|
+
"status",
|
|
30
|
+
"type",
|
|
31
|
+
"assessment",
|
|
32
|
+
"response",
|
|
33
|
+
"review",
|
|
34
|
+
"initiated",
|
|
35
|
+
"flag",
|
|
36
|
+
)
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
from wbcore import serializers as wb_serializers
|
|
2
|
+
from wbcore.contrib.geography.serializers import GeographyRepresentationSerializer
|
|
3
|
+
from wbfdm.models import Exchange
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class ExchangeRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
7
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:exchange-detail")
|
|
8
|
+
|
|
9
|
+
class Meta:
|
|
10
|
+
model = Exchange
|
|
11
|
+
fields = ("id", "name", "mic_code", "_detail")
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ExchangeModelSerializer(wb_serializers.ModelSerializer):
|
|
15
|
+
_country = GeographyRepresentationSerializer(source="country")
|
|
16
|
+
_city = GeographyRepresentationSerializer(source="city")
|
|
17
|
+
|
|
18
|
+
class Meta:
|
|
19
|
+
model = Exchange
|
|
20
|
+
fields = (
|
|
21
|
+
"id",
|
|
22
|
+
"name",
|
|
23
|
+
"mic_code",
|
|
24
|
+
"operating_mic_code",
|
|
25
|
+
"bbg_exchange_codes",
|
|
26
|
+
"bbg_composite_primary",
|
|
27
|
+
"bbg_composite",
|
|
28
|
+
"refinitiv_identifier_code",
|
|
29
|
+
"refinitiv_mnemonic",
|
|
30
|
+
"country",
|
|
31
|
+
"_country",
|
|
32
|
+
"city",
|
|
33
|
+
"website",
|
|
34
|
+
"opening_time",
|
|
35
|
+
"closing_time",
|
|
36
|
+
"_city",
|
|
37
|
+
"city",
|
|
38
|
+
"comments",
|
|
39
|
+
)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .instruments import (
|
|
2
|
+
InstrumentModelListSerializer,
|
|
3
|
+
InstrumentModelSerializer,
|
|
4
|
+
InstrumentRepresentationSerializer,
|
|
5
|
+
InstrumentTypeRepresentationSerializer,
|
|
6
|
+
InvestableUniverseRepresentationSerializer,
|
|
7
|
+
ClassifiableInstrumentRepresentationSerializer,
|
|
8
|
+
SecurityRepresentationSerializer,
|
|
9
|
+
InvestableInstrumentRepresentationSerializer,
|
|
10
|
+
PrimaryInvestableInstrumentRepresentationSerializer,
|
|
11
|
+
EquityRepresentationSerializer,
|
|
12
|
+
ProductRepresentationSerializer,
|
|
13
|
+
ManagedInstrumentRepresentationSerializer,
|
|
14
|
+
)
|
|
15
|
+
from .instrument_prices import InstrumentPriceModelSerializer, InstrumentPriceInstrumentModelSerializer
|
|
16
|
+
from .instrument_relationships import (
|
|
17
|
+
InstrumentClassificationRelatedInstrumentModelSerializer,
|
|
18
|
+
InstrumentClassificationRelatedInstrumentRepresentationSerializer,
|
|
19
|
+
RelatedInstrumentThroughInstrumentModelSerializer,
|
|
20
|
+
InstrumentFavoriteGroupRepresentationSerializer,
|
|
21
|
+
InstrumentFavoriteGroupModelSerializer,
|
|
22
|
+
InstrumentClassificationThroughModelSerializer,
|
|
23
|
+
)
|
|
24
|
+
from .instrument_requests import InstrumentRequestRepresentationSerializer, InstrumentRequestModelSerializer
|
|
25
|
+
from .classifications import (
|
|
26
|
+
ClassificationRepresentationSerializer,
|
|
27
|
+
ClassificationZeroHeightRepresentationSerializer,
|
|
28
|
+
ClassificationIsFavoriteZeroHeightRepresentationSerializer,
|
|
29
|
+
ClassificationGroupRepresentationSerializer,
|
|
30
|
+
ClassificationModelSerializer,
|
|
31
|
+
ClassificationGroupModelSerializer,
|
|
32
|
+
)
|
|
33
|
+
from .instrument_lists import (
|
|
34
|
+
InstrumentListModelSerializer,
|
|
35
|
+
InstrumentListRepresentationSerializer,
|
|
36
|
+
InstrumentListThroughModelSerializer,
|
|
37
|
+
)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from rest_framework import serializers as rf_serializers
|
|
2
|
+
from rest_framework.reverse import reverse
|
|
3
|
+
from wbcore import serializers as wb_serializers
|
|
4
|
+
from wbcore.serializers import DefaultAttributeFromRemoteField
|
|
5
|
+
from wbfdm.models.instruments import Classification, ClassificationGroup
|
|
6
|
+
from wbfdm.preferences import get_default_classification_group
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class ClassificationRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
10
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:classification-detail")
|
|
11
|
+
|
|
12
|
+
class Meta:
|
|
13
|
+
model = Classification
|
|
14
|
+
fields = (
|
|
15
|
+
"id",
|
|
16
|
+
"name",
|
|
17
|
+
"computed_str",
|
|
18
|
+
"level",
|
|
19
|
+
"height",
|
|
20
|
+
"code_aggregated",
|
|
21
|
+
"_detail",
|
|
22
|
+
)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class ClassificationZeroHeightRepresentationSerializer(ClassificationRepresentationSerializer):
|
|
26
|
+
def get_filter_params(self, request):
|
|
27
|
+
filter_params = {"height": 0}
|
|
28
|
+
if (view := request.parser_context.get("view", None)) and (
|
|
29
|
+
instrument_id := view.kwargs.get("instrument_id", None)
|
|
30
|
+
):
|
|
31
|
+
filter_params["instruments_neq"] = instrument_id
|
|
32
|
+
return filter_params
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class ClassificationIsFavoriteZeroHeightRepresentationSerializer(ClassificationRepresentationSerializer):
|
|
36
|
+
def get_filter_params(self, request):
|
|
37
|
+
filter_params = {
|
|
38
|
+
"height": 0,
|
|
39
|
+
"instruments_through__is_favorite": True,
|
|
40
|
+
}
|
|
41
|
+
if group := get_default_classification_group():
|
|
42
|
+
filter_params["group"] = group.id
|
|
43
|
+
return filter_params
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class ClassificationGroupRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
47
|
+
max_depth = wb_serializers.IntegerField(read_only=True)
|
|
48
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:classificationgroup-detail")
|
|
49
|
+
|
|
50
|
+
class Meta:
|
|
51
|
+
model = ClassificationGroup
|
|
52
|
+
fields = ("id", "name", "is_primary", "max_depth", "_detail")
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class ClassificationModelSerializer(wb_serializers.ModelSerializer):
|
|
56
|
+
parent = wb_serializers.PrimaryKeyRelatedField(
|
|
57
|
+
queryset=Classification.objects.all(), default=DefaultAttributeFromRemoteField("parent_id", Classification)
|
|
58
|
+
)
|
|
59
|
+
_parent = ClassificationRepresentationSerializer(source="parent")
|
|
60
|
+
group = wb_serializers.PrimaryKeyRelatedField(
|
|
61
|
+
queryset=ClassificationGroup.objects.all(),
|
|
62
|
+
default=DefaultAttributeFromRemoteField("parent_id", Classification, source="group"),
|
|
63
|
+
)
|
|
64
|
+
_group = ClassificationGroupRepresentationSerializer(source="group")
|
|
65
|
+
code_aggregated = wb_serializers.CharField(required=False, default="")
|
|
66
|
+
level_representation = wb_serializers.CharField(required=False, default="")
|
|
67
|
+
description = wb_serializers.TextAreaField(label="Description", allow_null=True, allow_blank=True, required=False)
|
|
68
|
+
|
|
69
|
+
@wb_serializers.register_only_instance_resource()
|
|
70
|
+
def additional_resources(self, instance, request, user, **kwargs):
|
|
71
|
+
resources = {
|
|
72
|
+
"childs": reverse("wbfdm:classificationparent-classification-list", args=[instance.id], request=request),
|
|
73
|
+
}
|
|
74
|
+
if instance.children.exists():
|
|
75
|
+
resources[
|
|
76
|
+
"iciclechart"
|
|
77
|
+
] = f'{reverse("wbfdm:classificationgroup-iciclechart-list", args=[instance.group.id], request=request)}?top_classification={instance.id}'
|
|
78
|
+
resources[
|
|
79
|
+
"treechart"
|
|
80
|
+
] = f'{reverse("wbfdm:classificationgroup-treechart-list", args=[instance.group.id], request=request)}?top_classification={instance.id}'
|
|
81
|
+
|
|
82
|
+
resources["instruments"] = reverse("wbfdm:classification-instrument-list", args=[instance.id], request=request)
|
|
83
|
+
|
|
84
|
+
return resources
|
|
85
|
+
|
|
86
|
+
def validate(self, data):
|
|
87
|
+
errors = {}
|
|
88
|
+
if parent := data.get("parent", None):
|
|
89
|
+
data["level"] = parent.level + 1
|
|
90
|
+
data["group"] = parent.group
|
|
91
|
+
if (
|
|
92
|
+
(investable := data.get("investable", None))
|
|
93
|
+
and self.instance
|
|
94
|
+
and investable is True
|
|
95
|
+
and self.instance.get_ancestors().filter(investable=False).exists()
|
|
96
|
+
):
|
|
97
|
+
errors["investable"] = "This classification cannot be investable as long as its parent is non investable."
|
|
98
|
+
if len(errors.keys()) > 0:
|
|
99
|
+
raise rf_serializers.ValidationError(errors)
|
|
100
|
+
return data
|
|
101
|
+
|
|
102
|
+
class Meta:
|
|
103
|
+
model = Classification
|
|
104
|
+
fields = (
|
|
105
|
+
"id",
|
|
106
|
+
"parent",
|
|
107
|
+
"_parent",
|
|
108
|
+
"height",
|
|
109
|
+
"group",
|
|
110
|
+
"_group",
|
|
111
|
+
"level",
|
|
112
|
+
"level_representation",
|
|
113
|
+
"name",
|
|
114
|
+
"code_aggregated",
|
|
115
|
+
"investable",
|
|
116
|
+
"description",
|
|
117
|
+
"_additional_resources",
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class ClassificationGroupModelSerializer(wb_serializers.ModelSerializer):
|
|
122
|
+
@wb_serializers.register_resource()
|
|
123
|
+
def additional_resources(self, instance, request, user):
|
|
124
|
+
if instance.classifications.exists():
|
|
125
|
+
return {
|
|
126
|
+
"classifications": reverse(
|
|
127
|
+
"wbfdm:classificationgroup-classification-list", args=[instance.id], request=request
|
|
128
|
+
),
|
|
129
|
+
"treechart": reverse("wbfdm:classificationgroup-treechart-list", args=[instance.id], request=request),
|
|
130
|
+
"iciclechart": reverse(
|
|
131
|
+
"wbfdm:classificationgroup-iciclechart-list", args=[instance.id], request=request
|
|
132
|
+
),
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
return {}
|
|
136
|
+
|
|
137
|
+
class Meta:
|
|
138
|
+
model = ClassificationGroup
|
|
139
|
+
fields = ("id", "name", "is_primary", "max_depth", "code_level_digits", "_additional_resources")
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
from rest_framework.reverse import reverse
|
|
2
|
+
from wbcore import serializers as wb_serializers
|
|
3
|
+
from wbfdm.models.instruments.instrument_lists import (
|
|
4
|
+
InstrumentList,
|
|
5
|
+
InstrumentListThroughModel,
|
|
6
|
+
)
|
|
7
|
+
from wbfdm.serializers.instruments import SecurityRepresentationSerializer
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class InstrumentListRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
11
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:instrumentlist-detail")
|
|
12
|
+
|
|
13
|
+
class Meta:
|
|
14
|
+
model = InstrumentList
|
|
15
|
+
fields = (
|
|
16
|
+
"id",
|
|
17
|
+
"name",
|
|
18
|
+
"_detail",
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
class InstrumentListModelSerializer(wb_serializers.ModelSerializer):
|
|
23
|
+
@wb_serializers.register_only_instance_resource()
|
|
24
|
+
def instruments(self, instance, request, user, **kwargs):
|
|
25
|
+
if instance:
|
|
26
|
+
base_url = reverse("wbfdm:instrumentlist-instrumentlistthrough-list", args=[instance.id], request=request)
|
|
27
|
+
return {"instruments": base_url}
|
|
28
|
+
return {}
|
|
29
|
+
|
|
30
|
+
class Meta:
|
|
31
|
+
model = InstrumentList
|
|
32
|
+
read_only_fields = ("id", "identifier")
|
|
33
|
+
fields = (
|
|
34
|
+
"id",
|
|
35
|
+
"name",
|
|
36
|
+
"identifier",
|
|
37
|
+
"instrument_list_type",
|
|
38
|
+
"_additional_resources",
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
class InstrumentListThroughModelSerializer(wb_serializers.ModelSerializer):
|
|
43
|
+
_instrument = SecurityRepresentationSerializer(source="instrument")
|
|
44
|
+
_instrument_list = InstrumentListRepresentationSerializer(source="instrument_list")
|
|
45
|
+
|
|
46
|
+
class Meta:
|
|
47
|
+
model = InstrumentListThroughModel
|
|
48
|
+
read_only_fields = ("instrument_str",)
|
|
49
|
+
fields = (
|
|
50
|
+
"id",
|
|
51
|
+
"instrument_str",
|
|
52
|
+
"instrument",
|
|
53
|
+
"_instrument",
|
|
54
|
+
"instrument_list",
|
|
55
|
+
"_instrument_list",
|
|
56
|
+
"from_date",
|
|
57
|
+
"to_date",
|
|
58
|
+
"comment",
|
|
59
|
+
"validated",
|
|
60
|
+
"_additional_resources",
|
|
61
|
+
)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
from wbcore import serializers as wb_serializers
|
|
2
|
+
from wbfdm.models import InstrumentPrice
|
|
3
|
+
from wbfdm.serializers.instruments.instruments import (
|
|
4
|
+
InvestableInstrumentRepresentationSerializer,
|
|
5
|
+
)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class InstrumentPriceModelSerializer(wb_serializers.ModelSerializer):
|
|
9
|
+
_instrument = InvestableInstrumentRepresentationSerializer(source="instrument")
|
|
10
|
+
currency_symbol = wb_serializers.CharField(read_only=True)
|
|
11
|
+
net_value = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
|
|
12
|
+
net_value_usd = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
|
|
13
|
+
gross_value = wb_serializers.DecimalField(max_digits=16, decimal_places=2, default=0)
|
|
14
|
+
daily_diff_net_value = wb_serializers.FloatField(required=False, read_only=True, default=0, precision=4)
|
|
15
|
+
daily_diff_gross_value = wb_serializers.FloatField(required=False, read_only=True, default=0, precision=4)
|
|
16
|
+
real_price_exists = wb_serializers.BooleanField(default=False, read_only=True)
|
|
17
|
+
|
|
18
|
+
class Meta:
|
|
19
|
+
model = InstrumentPrice
|
|
20
|
+
percent_fields = [
|
|
21
|
+
"daily_diff_net_value",
|
|
22
|
+
"daily_diff_gross_value",
|
|
23
|
+
]
|
|
24
|
+
decorators = {
|
|
25
|
+
"market_capitalization": wb_serializers.decorator(
|
|
26
|
+
decorator_type="text", position="left", value="{{currency_symbol}}"
|
|
27
|
+
),
|
|
28
|
+
}
|
|
29
|
+
fields = (
|
|
30
|
+
"id",
|
|
31
|
+
"date",
|
|
32
|
+
"net_value",
|
|
33
|
+
"net_value_usd",
|
|
34
|
+
"gross_value",
|
|
35
|
+
"calculated",
|
|
36
|
+
"real_price_exists",
|
|
37
|
+
"sharpe_ratio",
|
|
38
|
+
"correlation",
|
|
39
|
+
"beta",
|
|
40
|
+
"daily_diff_net_value",
|
|
41
|
+
"daily_diff_gross_value",
|
|
42
|
+
"instrument",
|
|
43
|
+
"_instrument",
|
|
44
|
+
"volume",
|
|
45
|
+
"volume_50d",
|
|
46
|
+
"volume_200d",
|
|
47
|
+
"currency_symbol",
|
|
48
|
+
"outstanding_shares_consolidated",
|
|
49
|
+
"market_capitalization",
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class InstrumentPriceInstrumentModelSerializer(InstrumentPriceModelSerializer):
|
|
54
|
+
class Meta(InstrumentPriceModelSerializer.Meta):
|
|
55
|
+
fields = (
|
|
56
|
+
"id",
|
|
57
|
+
"date",
|
|
58
|
+
"net_value",
|
|
59
|
+
"net_value_usd",
|
|
60
|
+
"gross_value",
|
|
61
|
+
"sharpe_ratio",
|
|
62
|
+
"calculated",
|
|
63
|
+
"correlation",
|
|
64
|
+
"beta",
|
|
65
|
+
"daily_diff_net_value",
|
|
66
|
+
"daily_diff_gross_value",
|
|
67
|
+
"volume",
|
|
68
|
+
"volume_50d",
|
|
69
|
+
"volume_200d",
|
|
70
|
+
"currency_symbol",
|
|
71
|
+
"outstanding_shares_consolidated",
|
|
72
|
+
"market_capitalization",
|
|
73
|
+
)
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
from rest_framework import serializers
|
|
2
|
+
from rest_framework.reverse import reverse
|
|
3
|
+
from wbcore import serializers as wb_serializers
|
|
4
|
+
from wbcore.contrib.directory.models import Person
|
|
5
|
+
from wbcore.contrib.directory.serializers import PersonRepresentationSerializer
|
|
6
|
+
from wbcore.contrib.tags.serializers import TagSerializerMixin
|
|
7
|
+
from wbfdm.models import (
|
|
8
|
+
Classification,
|
|
9
|
+
Instrument,
|
|
10
|
+
InstrumentClassificationRelatedInstrument,
|
|
11
|
+
InstrumentClassificationThroughModel,
|
|
12
|
+
InstrumentFavoriteGroup,
|
|
13
|
+
RelatedInstrumentThroughModel,
|
|
14
|
+
)
|
|
15
|
+
|
|
16
|
+
from .classifications import ClassificationZeroHeightRepresentationSerializer
|
|
17
|
+
from .instruments import (
|
|
18
|
+
ClassifiableInstrumentRepresentationSerializer,
|
|
19
|
+
InvestableInstrumentRepresentationSerializer,
|
|
20
|
+
PrimaryInvestableInstrumentRepresentationSerializer,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class InstrumentFavoriteGroupRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
25
|
+
_detail = wb_serializers.HyperlinkField(reverse_name="wbfdm:favoritegroup-detail")
|
|
26
|
+
|
|
27
|
+
class Meta:
|
|
28
|
+
model = InstrumentFavoriteGroup
|
|
29
|
+
fields = ("id", "name", "owner", "public", "_detail")
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class InstrumentFavoriteGroupModelSerializer(wb_serializers.ModelSerializer):
|
|
33
|
+
_instruments = PrimaryInvestableInstrumentRepresentationSerializer(source="instruments", many=True)
|
|
34
|
+
owner = wb_serializers.PrimaryKeyRelatedField(
|
|
35
|
+
queryset=lambda: Person.objects.filter_only_internal(),
|
|
36
|
+
default=wb_serializers.CurrentUserDefault("profile"),
|
|
37
|
+
read_only=lambda view: not view.request.user.is_superuser,
|
|
38
|
+
)
|
|
39
|
+
_owner = PersonRepresentationSerializer(source="owner")
|
|
40
|
+
public = wb_serializers.BooleanField(read_only=True)
|
|
41
|
+
|
|
42
|
+
# @wb_serializers.register_only_instance_resource()
|
|
43
|
+
# def instruments(self, instance, request, user, **kwargs):
|
|
44
|
+
# if instance.instruments.exists():
|
|
45
|
+
# return {"instruments": reverse("wbfdm:favoritegroup-instrument-list", args=[instance.id], request=request)}
|
|
46
|
+
# return dict()
|
|
47
|
+
|
|
48
|
+
def validate(self, data):
|
|
49
|
+
if not data.get("owner", None):
|
|
50
|
+
data["owner"] = self.context["request"].user.profile if self.context.get("request") else None
|
|
51
|
+
return data
|
|
52
|
+
|
|
53
|
+
class Meta:
|
|
54
|
+
model = InstrumentFavoriteGroup
|
|
55
|
+
fields = (
|
|
56
|
+
"id",
|
|
57
|
+
"name",
|
|
58
|
+
"owner",
|
|
59
|
+
"_owner",
|
|
60
|
+
"public",
|
|
61
|
+
"primary",
|
|
62
|
+
"instruments",
|
|
63
|
+
"_instruments",
|
|
64
|
+
"_additional_resources",
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
class RelatedInstrumentThroughInstrumentModelSerializer(wb_serializers.ModelSerializer):
|
|
69
|
+
_related_instrument = InvestableInstrumentRepresentationSerializer(source="related_instrument")
|
|
70
|
+
_instrument = InvestableInstrumentRepresentationSerializer(source="instrument")
|
|
71
|
+
|
|
72
|
+
class Meta:
|
|
73
|
+
model = RelatedInstrumentThroughModel
|
|
74
|
+
fields = (
|
|
75
|
+
"id",
|
|
76
|
+
"_related_instrument",
|
|
77
|
+
"related_instrument",
|
|
78
|
+
"_instrument",
|
|
79
|
+
"instrument",
|
|
80
|
+
"related_type",
|
|
81
|
+
"is_primary",
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class InstrumentClassificationThroughModelSerializer(TagSerializerMixin, wb_serializers.ModelSerializer):
|
|
86
|
+
instrument = wb_serializers.PrimaryKeyRelatedField(
|
|
87
|
+
queryset=Instrument.objects.all(), default=wb_serializers.DefaultFromKwargs("instrument_id")
|
|
88
|
+
)
|
|
89
|
+
_instrument = ClassifiableInstrumentRepresentationSerializer(source="instrument")
|
|
90
|
+
classification = wb_serializers.PrimaryKeyRelatedField(
|
|
91
|
+
queryset=Classification.objects.all(), default=wb_serializers.DefaultFromKwargs("classification_id")
|
|
92
|
+
)
|
|
93
|
+
_classification = ClassificationZeroHeightRepresentationSerializer(source="classification")
|
|
94
|
+
reason = wb_serializers.TextAreaField(label="Reason", allow_null=True, allow_blank=True, required=False)
|
|
95
|
+
_related_instruments = ClassifiableInstrumentRepresentationSerializer(source="related_instruments", many=True)
|
|
96
|
+
|
|
97
|
+
@wb_serializers.register_resource()
|
|
98
|
+
def related_instrument_list(self, instance, request, user):
|
|
99
|
+
return {"related_instruments": reverse("wbfdm:related_instrument-list", args=[instance.id], request=request)}
|
|
100
|
+
|
|
101
|
+
def validate(self, data):
|
|
102
|
+
instrument = data.get("instrument", self.instance.instrument if self.instance else None)
|
|
103
|
+
classification = data.get("classification", self.instance.classification if self.instance else None)
|
|
104
|
+
if not instrument:
|
|
105
|
+
raise serializers.ValidationError({"instrument": "Instrument cannot be null"})
|
|
106
|
+
if not classification:
|
|
107
|
+
raise serializers.ValidationError({"classification": "Classification cannot be null"})
|
|
108
|
+
|
|
109
|
+
if (
|
|
110
|
+
not self.instance
|
|
111
|
+
and InstrumentClassificationThroughModel.objects.filter(
|
|
112
|
+
classification=classification, instrument=instrument
|
|
113
|
+
).exists()
|
|
114
|
+
):
|
|
115
|
+
if hasattr(data, "instrument"):
|
|
116
|
+
raise serializers.ValidationError(
|
|
117
|
+
{
|
|
118
|
+
"instrument": f"A relationship already exists between {instrument} and {classification}",
|
|
119
|
+
}
|
|
120
|
+
)
|
|
121
|
+
else:
|
|
122
|
+
raise serializers.ValidationError(
|
|
123
|
+
{
|
|
124
|
+
"classification": f"A relationship already exists between {instrument} and {classification}",
|
|
125
|
+
}
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
return data
|
|
129
|
+
|
|
130
|
+
class Meta:
|
|
131
|
+
model = InstrumentClassificationThroughModel
|
|
132
|
+
fields = (
|
|
133
|
+
"id",
|
|
134
|
+
"instrument",
|
|
135
|
+
"classification",
|
|
136
|
+
"_instrument",
|
|
137
|
+
"_classification",
|
|
138
|
+
"related_instruments",
|
|
139
|
+
"_related_instruments",
|
|
140
|
+
"is_favorite",
|
|
141
|
+
"reason",
|
|
142
|
+
"pure_player",
|
|
143
|
+
"top_player",
|
|
144
|
+
"percent_of_revenue",
|
|
145
|
+
"tags",
|
|
146
|
+
"_tags",
|
|
147
|
+
"_additional_resources",
|
|
148
|
+
)
|
|
149
|
+
percent_fields = ["percent_of_revenue"]
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class InstrumentClassificationRelatedInstrumentRepresentationSerializer(wb_serializers.ModelSerializer):
|
|
153
|
+
class Meta:
|
|
154
|
+
model = InstrumentClassificationRelatedInstrument
|
|
155
|
+
fields = ("id", "related_instrument")
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
class InstrumentClassificationRelatedInstrumentModelSerializer(wb_serializers.ModelSerializer):
|
|
159
|
+
_related_instrument = ClassifiableInstrumentRepresentationSerializer(source="related_instrument")
|
|
160
|
+
|
|
161
|
+
class Meta:
|
|
162
|
+
model = InstrumentClassificationRelatedInstrument
|
|
163
|
+
fields = (
|
|
164
|
+
"id",
|
|
165
|
+
"classified_instrument",
|
|
166
|
+
# "_classified_instrument",
|
|
167
|
+
"related_instrument",
|
|
168
|
+
"_related_instrument",
|
|
169
|
+
"related_instrument_type",
|
|
170
|
+
)
|