wbfdm 1.44.5__py2.py3-none-any.whl → 1.45.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.

Files changed (144) hide show
  1. wbfdm/admin/classifications.py +1 -0
  2. wbfdm/admin/esg.py +1 -0
  3. wbfdm/admin/exchanges.py +1 -0
  4. wbfdm/admin/instrument_lists.py +1 -0
  5. wbfdm/admin/instrument_prices.py +1 -0
  6. wbfdm/admin/instrument_requests.py +1 -0
  7. wbfdm/admin/instruments.py +1 -0
  8. wbfdm/admin/instruments_relationships.py +1 -0
  9. wbfdm/admin/options.py +1 -0
  10. wbfdm/analysis/esg/enums.py +2 -3
  11. wbfdm/analysis/esg/esg_analysis.py +1 -0
  12. wbfdm/analysis/esg/utils.py +1 -0
  13. wbfdm/analysis/financial_analysis/financial_metric_analysis.py +1 -0
  14. wbfdm/analysis/financial_analysis/financial_ratio_analysis.py +1 -0
  15. wbfdm/analysis/financial_analysis/financial_statistics_analysis.py +4 -1
  16. wbfdm/analysis/financial_analysis/statement_with_estimates.py +3 -4
  17. wbfdm/analysis/financial_analysis/utils.py +1 -0
  18. wbfdm/analysis/technical_analysis/technical_analysis.py +1 -0
  19. wbfdm/contrib/dsws/client.py +17 -2
  20. wbfdm/contrib/internal/dataloaders/market_data.py +1 -0
  21. wbfdm/contrib/metric/admin/instruments.py +1 -0
  22. wbfdm/contrib/metric/backends/base.py +5 -4
  23. wbfdm/contrib/metric/backends/performances.py +4 -3
  24. wbfdm/contrib/metric/backends/statistics.py +1 -0
  25. wbfdm/contrib/metric/factories.py +1 -0
  26. wbfdm/contrib/metric/filters.py +1 -0
  27. wbfdm/contrib/metric/serializers.py +1 -0
  28. wbfdm/contrib/metric/tasks.py +2 -1
  29. wbfdm/contrib/metric/tests/backends/test_performances.py +1 -0
  30. wbfdm/contrib/metric/tests/backends/test_statistics.py +1 -0
  31. wbfdm/contrib/metric/tests/test_models.py +1 -0
  32. wbfdm/contrib/metric/tests/test_viewsets.py +1 -0
  33. wbfdm/contrib/metric/viewsets/configs/display.py +1 -0
  34. wbfdm/contrib/metric/viewsets/mixins.py +1 -0
  35. wbfdm/contrib/metric/viewsets/viewsets.py +1 -0
  36. wbfdm/contrib/msci/dataloaders/esg.py +1 -0
  37. wbfdm/contrib/msci/dataloaders/esg_controversies.py +1 -0
  38. wbfdm/contrib/msci/sync.py +1 -0
  39. wbfdm/contrib/qa/dataloaders/adjustments.py +5 -5
  40. wbfdm/contrib/qa/dataloaders/corporate_actions.py +5 -5
  41. wbfdm/contrib/qa/dataloaders/financials.py +1 -0
  42. wbfdm/contrib/qa/dataloaders/market_data.py +9 -7
  43. wbfdm/contrib/qa/dataloaders/officers.py +8 -10
  44. wbfdm/contrib/qa/dataloaders/reporting_dates.py +1 -0
  45. wbfdm/contrib/qa/dataloaders/statements.py +1 -0
  46. wbfdm/contrib/qa/dataloaders/utils.py +2 -2
  47. wbfdm/dataloaders/proxies.py +1 -0
  48. wbfdm/factories/classifications.py +1 -0
  49. wbfdm/factories/controversies.py +1 -0
  50. wbfdm/factories/exchanges.py +1 -0
  51. wbfdm/factories/instrument_list.py +1 -0
  52. wbfdm/factories/instrument_prices.py +1 -0
  53. wbfdm/factories/instruments.py +1 -0
  54. wbfdm/factories/instruments_relationships.py +1 -0
  55. wbfdm/factories/options.py +1 -0
  56. wbfdm/figures/financials/financial_analysis_charts.py +1 -0
  57. wbfdm/figures/financials/financials_charts.py +1 -0
  58. wbfdm/filters/classifications.py +1 -0
  59. wbfdm/filters/exchanges.py +1 -0
  60. wbfdm/filters/financials.py +1 -0
  61. wbfdm/filters/financials_analysis.py +1 -0
  62. wbfdm/filters/instrument_prices.py +1 -0
  63. wbfdm/filters/instruments.py +1 -0
  64. wbfdm/filters/utils.py +1 -0
  65. wbfdm/import_export/backends/cbinsights/mixin.py +1 -0
  66. wbfdm/import_export/backends/refinitiv/mixin.py +1 -0
  67. wbfdm/import_export/backends/refinitiv/utils/controller.py +1 -0
  68. wbfdm/import_export/handlers/instrument.py +9 -9
  69. wbfdm/import_export/handlers/instrument_price.py +5 -0
  70. wbfdm/import_export/parsers/cbinsights/deals.py +1 -0
  71. wbfdm/import_export/parsers/cbinsights/equities.py +1 -0
  72. wbfdm/import_export/parsers/cbinsights/fundamentals.py +1 -0
  73. wbfdm/import_export/parsers/refinitiv/instrument.py +1 -0
  74. wbfdm/import_export/parsers/refinitiv/instrument_price.py +1 -0
  75. wbfdm/import_export/resources/classification.py +1 -0
  76. wbfdm/import_export/resources/instrument_prices.py +1 -0
  77. wbfdm/import_export/resources/instruments.py +1 -0
  78. wbfdm/models/esg/controversies.py +1 -0
  79. wbfdm/models/instruments/instrument_lists.py +1 -0
  80. wbfdm/models/instruments/instrument_prices.py +1 -0
  81. wbfdm/models/instruments/instrument_requests.py +1 -0
  82. wbfdm/models/instruments/instruments.py +12 -7
  83. wbfdm/models/instruments/llm/create_instrument_news_relationships.py +2 -2
  84. wbfdm/models/instruments/mixin/instruments.py +24 -19
  85. wbfdm/models/instruments/options.py +1 -0
  86. wbfdm/models/instruments/private_equities.py +1 -0
  87. wbfdm/models/instruments/utils.py +1 -0
  88. wbfdm/serializers/esg.py +1 -0
  89. wbfdm/serializers/exchanges.py +1 -0
  90. wbfdm/serializers/instruments/__init__.py +1 -0
  91. wbfdm/serializers/instruments/classifications.py +1 -0
  92. wbfdm/serializers/instruments/instrument_lists.py +1 -0
  93. wbfdm/serializers/instruments/instrument_prices.py +1 -0
  94. wbfdm/serializers/instruments/instrument_relationships.py +6 -8
  95. wbfdm/serializers/instruments/instrument_requests.py +1 -0
  96. wbfdm/serializers/instruments/instruments.py +1 -1
  97. wbfdm/signals.py +3 -0
  98. wbfdm/tasks.py +45 -5
  99. wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +1 -0
  100. wbfdm/tests/analysis/financial_analysis/test_utils.py +1 -0
  101. wbfdm/tests/analysis/test_esg.py +1 -0
  102. wbfdm/tests/dataloaders/test_cache.py +1 -0
  103. wbfdm/tests/models/test_classifications.py +1 -0
  104. wbfdm/tests/models/test_instrument_list.py +1 -0
  105. wbfdm/tests/models/test_instrument_prices.py +1 -0
  106. wbfdm/tests/models/test_instruments.py +2 -1
  107. wbfdm/tests/models/test_merge.py +14 -9
  108. wbfdm/tests/models/test_options.py +1 -0
  109. wbfdm/urls.py +1 -0
  110. wbfdm/viewsets/configs/buttons/instruments.py +1 -0
  111. wbfdm/viewsets/configs/display/esg.py +1 -0
  112. wbfdm/viewsets/configs/display/instrument_lists.py +1 -0
  113. wbfdm/viewsets/configs/display/instrument_prices.py +1 -0
  114. wbfdm/viewsets/configs/display/instrument_requests.py +1 -0
  115. wbfdm/viewsets/configs/display/instruments.py +31 -4
  116. wbfdm/viewsets/configs/endpoints/__init__.py +1 -0
  117. wbfdm/viewsets/configs/endpoints/instrument_requests.py +1 -0
  118. wbfdm/viewsets/configs/endpoints/instruments_relationships.py +10 -0
  119. wbfdm/viewsets/configs/titles/classifications.py +1 -0
  120. wbfdm/viewsets/configs/titles/financials_analysis.py +1 -0
  121. wbfdm/viewsets/configs/titles/instrument_prices.py +1 -0
  122. wbfdm/viewsets/configs/titles/market_data.py +1 -0
  123. wbfdm/viewsets/esg.py +1 -0
  124. wbfdm/viewsets/exchanges.py +1 -0
  125. wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +1 -0
  126. wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +2 -1
  127. wbfdm/viewsets/financial_analysis/financial_summary.py +4 -4
  128. wbfdm/viewsets/financial_analysis/statement_with_estimates.py +1 -0
  129. wbfdm/viewsets/instruments/classifications.py +1 -0
  130. wbfdm/viewsets/instruments/financials_analysis.py +1 -0
  131. wbfdm/viewsets/instruments/instrument_lists.py +1 -0
  132. wbfdm/viewsets/instruments/instrument_prices.py +1 -0
  133. wbfdm/viewsets/instruments/instrument_requests.py +1 -0
  134. wbfdm/viewsets/instruments/instruments.py +1 -0
  135. wbfdm/viewsets/instruments/instruments_relationships.py +17 -0
  136. wbfdm/viewsets/market_data.py +3 -2
  137. wbfdm/viewsets/mixins.py +1 -0
  138. wbfdm/viewsets/officers.py +1 -0
  139. wbfdm/viewsets/prices.py +1 -0
  140. wbfdm/viewsets/statements/statements.py +1 -0
  141. wbfdm/viewsets/technical_analysis/monthly_performances.py +1 -0
  142. {wbfdm-1.44.5.dist-info → wbfdm-1.45.1.dist-info}/METADATA +1 -1
  143. {wbfdm-1.44.5.dist-info → wbfdm-1.45.1.dist-info}/RECORD +144 -144
  144. {wbfdm-1.44.5.dist-info → wbfdm-1.45.1.dist-info}/WHEEL +0 -0
wbfdm/tasks.py CHANGED
@@ -1,11 +1,12 @@
1
- from datetime import date
1
+ from datetime import date, timedelta
2
2
 
3
3
  from celery import shared_task
4
4
  from django.db import transaction
5
5
  from django.db.models import Q
6
6
  from pandas.tseries.offsets import BDay
7
7
  from tqdm import tqdm
8
- from wbfdm.models import Instrument
8
+
9
+ from wbfdm.models import Instrument, InstrumentPrice
9
10
  from wbfdm.sync.runner import ( # noqa: F401
10
11
  initialize_exchanges,
11
12
  initialize_instruments,
@@ -13,9 +14,13 @@ from wbfdm.sync.runner import ( # noqa: F401
13
14
  synchronize_instruments,
14
15
  )
15
16
 
17
+ from .signals import investable_universe_updated
18
+
16
19
 
17
20
  @shared_task(queue="portfolio")
18
- def update_of_investable_universe_data(start: date | None = None, end: date | None = None, clear: bool = False):
21
+ def update_of_investable_universe_data(
22
+ start: date | None = None, end: date | None = None, clear: bool = False, with_background_tasks: bool = True
23
+ ):
19
24
  """
20
25
  Update the investable universe data on a daily basis.
21
26
 
@@ -38,7 +43,6 @@ def update_of_investable_universe_data(start: date | None = None, end: date | No
38
43
  ).date() # we don't import today price in case the dataloader returns duplicates (e.g. DSWS)
39
44
  if not start:
40
45
  start = (end - BDay(3)).date() # override three last day by default
41
-
42
46
  Instrument.investable_universe.update(
43
47
  is_investable_universe=True
44
48
  ) # ensure all the investable universe is marked as such
@@ -47,8 +51,24 @@ def update_of_investable_universe_data(start: date | None = None, end: date | No
47
51
  Q(is_managed=True)
48
52
  | Q(dl_parameters__market_data__path="wbfdm.contrib.internal.dataloaders.market_data.MarketDataDataloader")
49
53
  ) # we exclude product and index managed to avoid circular import
54
+ prices = []
55
+ for instrument in tqdm(instruments, total=instruments.count()):
56
+ try:
57
+ prices.extend(list(instrument.get_price_objects(start=start, end=end, clear=clear)))
58
+ except ConnectionError:
59
+ print(f"Connection error while processing instrument {instrument}") # noqa
60
+ Instrument.bulk_save_instrument_prices(prices)
61
+ investable_universe_updated.send(sender=Instrument, end_date=end)
62
+ if with_background_tasks:
63
+ daily_update_instrument_price_statistics.delay(from_date=start, to_date=end)
64
+ update_instrument_metrics_as_task.delay()
65
+
66
+
67
+ @shared_task(queue="portfolio")
68
+ def update_instrument_metrics_as_task():
69
+ instruments = Instrument.active_objects.filter(is_investable_universe=True)
50
70
  for instrument in tqdm(instruments, total=instruments.count()):
51
- instrument.import_prices(start=start, end=end, clear=clear)
71
+ instrument.update_last_valuation_date()
52
72
 
53
73
 
54
74
  @shared_task(queue="portfolio")
@@ -67,3 +87,23 @@ def full_synchronization_as_task():
67
87
  initialize_instruments()
68
88
  with transaction.atomic():
69
89
  Instrument.objects.rebuild() # rebuild MPTT tree
90
+
91
+
92
+ # Daily synchronization tasks.
93
+ # This tasks needs to be ran at maximum once a day in order to guarantee data consitency in
94
+ # case of change in change (e.g. reimport).
95
+ @shared_task(queue="portfolio")
96
+ def daily_update_instrument_price_statistics(from_date: date = None, to_date: date = None):
97
+ if not to_date:
98
+ to_date = date.today()
99
+ if not from_date:
100
+ from_date = to_date - timedelta(days=3)
101
+ # We query for the last 7 days unsynch instrument prices.
102
+ prices = InstrumentPrice.objects.filter(date__gte=from_date, date__lte=to_date)
103
+ objs = []
104
+ for p in tqdm(prices.iterator(), total=prices.count()):
105
+ p.compute_and_update_statistics()
106
+ objs.append(p)
107
+ InstrumentPrice.objects.bulk_update(
108
+ objs, fields=["sharpe_ratio", "correlation", "beta", "annualized_daily_volatility"], batch_size=1000
109
+ )
@@ -4,6 +4,7 @@ from unittest.mock import patch
4
4
  import pandas as pd
5
5
  import pytest
6
6
  from faker import Faker
7
+
7
8
  from wbfdm.analysis.financial_analysis.statement_with_estimates import (
8
9
  StatementWithEstimates,
9
10
  )
@@ -6,6 +6,7 @@ import numpy as np
6
6
  import pandas as pd
7
7
  import pytest
8
8
  from faker import Faker
9
+
9
10
  from wbfdm.analysis.financial_analysis.utils import FinancialAnalysisResult, Loader
10
11
  from wbfdm.dataloaders.proxies import InstrumentDataloaderProxy
11
12
  from wbfdm.enums import Financial, MarketData
@@ -4,6 +4,7 @@ import pytest
4
4
  from faker import Faker
5
5
  from wbcore.contrib.currency.factories import CurrencyFXRatesFactory
6
6
  from wbcore.contrib.currency.models import CurrencyFXRates
7
+
7
8
  from wbfdm.analysis.esg.enums import ESGAggregation
8
9
  from wbfdm.analysis.esg.esg_analysis import DataLoader
9
10
 
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
  from django.core.cache import cache as cache_layer
3
3
  from faker import Faker
4
+
4
5
  from wbfdm.dataloaders.cache import Cache
5
6
 
6
7
  fake = Faker()
@@ -1,4 +1,5 @@
1
1
  import pytest
2
+
2
3
  from wbfdm.models.instruments import (
3
4
  Classification,
4
5
  ClassificationGroup,
@@ -4,6 +4,7 @@ import pytest
4
4
  from django.contrib.auth.models import Permission
5
5
  from faker import Faker
6
6
  from wbcore.contrib.io.exceptions import DeserializationError
7
+
7
8
  from wbfdm.import_export.handlers.instrument_list import InstrumentListImportHandler
8
9
  from wbfdm.models import InstrumentListThroughModel
9
10
 
@@ -6,6 +6,7 @@ import pytest
6
6
  from faker import Faker
7
7
  from pandas.tseries.offsets import BDay
8
8
  from wbcore.models import DynamicDecimalField, DynamicFloatField
9
+
9
10
  from wbfdm.models import Instrument, InstrumentPrice, RelatedInstrumentThroughModel
10
11
 
11
12
  fake = Faker()
@@ -8,6 +8,7 @@ import pandas as pd
8
8
  import pytest
9
9
  from faker import Faker
10
10
  from pandas.tseries.offsets import BDay
11
+
11
12
  from wbfdm.dataloaders.proxies import InstrumentDataloaderProxy
12
13
  from wbfdm.factories.instrument_prices import InstrumentPrice
13
14
  from wbfdm.models import Instrument, RelatedInstrumentThroughModel
@@ -164,7 +165,7 @@ class TestInstrumentModel:
164
165
  "market_capitalization": 2,
165
166
  },
166
167
  ]
167
- instrument.save_prices_in_db(from_date, to_date + timedelta(days=1))
168
+ instrument.import_prices(from_date, to_date + timedelta(days=1))
168
169
  assert InstrumentPrice.objects.get(
169
170
  instrument=instrument, date=from_date, calculated=False
170
171
  ).net_value == Decimal(1)
@@ -1,5 +1,6 @@
1
1
  import pytest
2
2
  from faker import Faker
3
+
3
4
  from wbfdm.factories.instruments import InstrumentFactory
4
5
  from wbfdm.models import (
5
6
  Instrument,
@@ -68,12 +69,14 @@ class TestMergeInstrument:
68
69
  ] # Check that the favorite group with the merged instrument removed it and included the main instrument
69
70
 
70
71
  # Check related instruments
71
- assert RelatedInstrumentThroughModel.objects.filter(
72
- instrument=main_instrument,
73
- related_instrument=merged_related_instrument_rel.related_instrument,
74
- is_primary=merged_related_instrument_rel.is_primary,
75
- related_type=merged_related_instrument_rel.related_type,
76
- ).exists() # Check that the related instrument with the merged instrument removed it and included the main instrument
72
+ assert (
73
+ RelatedInstrumentThroughModel.objects.filter(
74
+ instrument=main_instrument,
75
+ related_instrument=merged_related_instrument_rel.related_instrument,
76
+ is_primary=merged_related_instrument_rel.is_primary,
77
+ related_type=merged_related_instrument_rel.related_type,
78
+ ).exists()
79
+ ) # Check that the related instrument with the merged instrument removed it and included the main instrument
77
80
  assert main_instrument.related_instruments.filter(
78
81
  id=main_related_instrument_rel.related_instrument.id
79
82
  ).exists() # Check that the main instrument related instrument is still there
@@ -94,6 +97,8 @@ class TestMergeInstrument:
94
97
  assert main_instrument.classifications.filter(
95
98
  id=main_classification_rel.classification.id
96
99
  ).exists() # Check that the main instrument classification relationship is still there
97
- assert InstrumentClassificationThroughModel.objects.filter(
98
- related_instruments=main_instrument, classification=reversed_classification_rel.classification
99
- ).exists() # Check that the reverse classificaiton instrument relationship has been forward to the main instrument
100
+ assert (
101
+ InstrumentClassificationThroughModel.objects.filter(
102
+ related_instruments=main_instrument, classification=reversed_classification_rel.classification
103
+ ).exists()
104
+ ) # Check that the reverse classificaiton instrument relationship has been forward to the main instrument
@@ -1,6 +1,7 @@
1
1
  import pytest
2
2
  from django.forms.models import model_to_dict
3
3
  from faker import Faker
4
+
4
5
  from wbfdm.import_export.handlers.option import (
5
6
  OptionAggregateImportHandler,
6
7
  OptionImportHandler,
wbfdm/urls.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from django.urls import include, path
2
2
  from wbcore.routers import WBCoreRouter
3
+
3
4
  from wbfdm import viewsets
4
5
 
5
6
  router = WBCoreRouter()
@@ -4,6 +4,7 @@ from rest_framework.reverse import reverse
4
4
  from wbcore.contrib.icons import WBIcon
5
5
  from wbcore.metadata.configs import buttons as bt
6
6
  from wbcore.metadata.configs.buttons import ButtonViewConfig
7
+
7
8
  from wbfdm.models import Instrument
8
9
 
9
10
 
@@ -3,6 +3,7 @@ from wbcore.contrib.color.enums import WBColor
3
3
  from wbcore.enums import Operator
4
4
  from wbcore.metadata.configs import display as dp
5
5
  from wbcore.metadata.configs.display import DisplayViewConfig
6
+
6
7
  from wbfdm.enums import ESGControveryFlag
7
8
 
8
9
 
@@ -15,6 +15,7 @@ from wbcore.metadata.configs.display.instance_display.operators import default
15
15
  from wbcore.metadata.configs.display.instance_display.shortcuts import (
16
16
  create_simple_display,
17
17
  )
18
+
18
19
  from wbfdm.models import InstrumentList
19
20
 
20
21
 
@@ -3,6 +3,7 @@ from typing import Optional
3
3
  from wbcore.contrib.color.enums import WBColor
4
4
  from wbcore.metadata.configs import display as dp
5
5
  from wbcore.metadata.configs.display.view_config import DisplayViewConfig
6
+
6
7
  from wbfdm.models import Instrument, InstrumentType
7
8
 
8
9
  perf_formatting_rules = [
@@ -10,6 +10,7 @@ from wbcore.metadata.configs.display.instance_display.shortcuts import (
10
10
  )
11
11
  from wbcore.metadata.configs.display.instance_display.utils import repeat_field
12
12
  from wbcore.metadata.configs.display.view_config import DisplayViewConfig
13
+
13
14
  from wbfdm.models import InstrumentRequest
14
15
 
15
16
 
@@ -18,6 +18,7 @@ from wbcore.metadata.configs.display.instance_display.shortcuts import (
18
18
  )
19
19
  from wbcore.metadata.configs.display.instance_display.styles import Style
20
20
  from wbcore.metadata.configs.display.instance_display.utils import repeat, repeat_field
21
+
21
22
  from wbfdm.contrib.metric.viewsets.configs.utils import (
22
23
  get_performance_fields,
23
24
  get_statistic_field,
@@ -124,9 +125,30 @@ class InstrumentDisplayConfig(DisplayViewConfig):
124
125
  default(): Layout(
125
126
  grid_template_areas=[
126
127
  ["name", "ticker", "isin", "exchange", "market_data_chart", "valuation_ratios-new"],
127
- ["name_repr", "instrument_type", "currency", "country", "market_data_chart", "valuation_ratios-new"],
128
- ["inception_date", "delisted_date", ".", ".", "market_data_chart", "valuation_ratios-new"],
129
- ["description", "description", "description", "description", "market_data_chart", "valuation_ratios-new"],
128
+ [
129
+ "name_repr",
130
+ "instrument_type",
131
+ "currency",
132
+ "country",
133
+ "market_data_chart",
134
+ "valuation_ratios-new",
135
+ ],
136
+ [
137
+ "inception_date",
138
+ "delisted_date",
139
+ ".",
140
+ ".",
141
+ "market_data_chart",
142
+ "valuation_ratios-new",
143
+ ],
144
+ [
145
+ "description",
146
+ "description",
147
+ "description",
148
+ "description",
149
+ "market_data_chart",
150
+ "valuation_ratios-new",
151
+ ],
130
152
  [repeat_field(4, "fin-summary"), repeat_field(2, ".")],
131
153
  ],
132
154
  grid_template_rows=["min-content"] * 3 + ["1fr", "446px"],
@@ -134,7 +156,12 @@ class InstrumentDisplayConfig(DisplayViewConfig):
134
156
  inlines=[
135
157
  Inline(key="market_data_chart", endpoint="market_data", title="Prices"),
136
158
  Inline(key="valuation_ratios-new", endpoint="valuation_ratios-new", title="Ratios"),
137
- Inline(key="fin-summary", endpoint="fin-summary", title="Financial Summary", hide_controls=True),
159
+ Inline(
160
+ key="fin-summary",
161
+ endpoint="fin-summary",
162
+ title="Financial Summary",
163
+ hide_controls=True,
164
+ ),
138
165
  ],
139
166
  ),
140
167
  },
@@ -36,6 +36,7 @@ from .instrument_prices import (
36
36
  from .instruments_relationships import (
37
37
  ClassifiedInstrumentEndpointConfig,
38
38
  RelatedInstrumentThroughInstrumentEndpointConfig,
39
+ InstrumentFavoriteGroupEndpointConfig
39
40
  )
40
41
  from .exchanges import ExchangeEndpointConfig
41
42
  from .esg import InstrumentESGPAIEndpointViewConfig, InstrumentESGControversiesEndpointViewConfig
@@ -1,5 +1,6 @@
1
1
  from rest_framework.reverse import reverse
2
2
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
3
+
3
4
  from wbfdm.models import InstrumentRequest
4
5
 
5
6
 
@@ -29,3 +29,13 @@ class ClassifiedInstrumentEndpointConfig(EndpointViewConfig):
29
29
 
30
30
  def get_delete_endpoint(self, **kwargs):
31
31
  return None
32
+
33
+
34
+ class InstrumentFavoriteGroupEndpointConfig(EndpointViewConfig):
35
+ def get_update_endpoint(self, **kwargs):
36
+ if self.view.is_owner:
37
+ return self.get_instance_endpoint(**kwargs)
38
+ return None
39
+
40
+ def get_delete_endpoint(self, **kwargs):
41
+ return self.get_update_endpoint(**kwargs)
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbfdm.models import Classification, ClassificationGroup, Instrument
3
4
 
4
5
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbfdm.models import Instrument
3
4
 
4
5
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbfdm.models import Instrument
3
4
 
4
5
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbfdm.enums import MarketDataChartType
3
4
 
4
5
 
wbfdm/viewsets/esg.py CHANGED
@@ -3,6 +3,7 @@ from rest_framework.response import Response
3
3
  from wbcore import viewsets
4
4
  from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
5
5
  from wbcore.pandas import fields as pf
6
+
6
7
  from wbfdm.enums import ESG
7
8
  from wbfdm.models.instruments import Instrument
8
9
  from wbfdm.serializers import InstrumentControversySerializer
@@ -1,5 +1,6 @@
1
1
  from wbcore import viewsets
2
2
  from wbcore.permissions.permissions import InternalUserPermissionMixin
3
+
3
4
  from wbfdm.filters import ExchangeFilterSet
4
5
  from wbfdm.models import Exchange
5
6
  from wbfdm.serializers import ExchangeModelSerializer, ExchangeRepresentationSerializer
@@ -5,6 +5,7 @@ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
5
5
  from wbcore.pandas import fields as pf
6
6
  from wbcore.pandas.utils import override_number_to_percent
7
7
  from wbcore.serializers.fields.types import DisplayMode
8
+
8
9
  from wbfdm.analysis.financial_analysis.financial_metric_analysis import (
9
10
  financial_metric_estimate_analysis,
10
11
  financial_metric_growths,
@@ -6,6 +6,7 @@ import plotly.express as px
6
6
  import plotly.graph_objects as go
7
7
  from wbcore import viewsets
8
8
  from wbcore.utils.date import get_date_interval_from_request
9
+
9
10
  from wbfdm.analysis.financial_analysis.financial_ratio_analysis import (
10
11
  FinancialRatio,
11
12
  get_financial_ratios,
@@ -17,7 +18,7 @@ from ..configs import ValuationRatioChartTitleConfig
17
18
  from ..mixins import InstrumentMixin
18
19
 
19
20
 
20
- class ValuationRatioChartViewSet(InstrumentMixin, viewsets.ChartViewSet):
21
+ class ValuationRatioChartViewSet(InstrumentMixin, viewsets.TimeSeriesChartViewSet):
21
22
  queryset = Instrument.objects.all()
22
23
  filterset_class = FinancialRatioFilterSet
23
24
  title_config_class = ValuationRatioChartTitleConfig
@@ -4,21 +4,21 @@ from django.utils.functional import cached_property
4
4
  from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
5
5
  from wbcore.metadata.configs.endpoints import NoEndpointViewConfig
6
6
  from wbcore.pandas import fields as pf
7
- from wbcore.pandas.utils import sanitize_fields, pct_change_with_negative_values
8
7
  from wbcore.pandas.utils import (
9
8
  override_number_to_decimal,
9
+ override_number_to_integer_without_decorations,
10
10
  override_number_to_percent,
11
11
  override_number_to_x,
12
- override_number_to_integer_without_decorations,
12
+ pct_change_with_negative_values,
13
+ sanitize_fields,
13
14
  )
15
+
14
16
  from wbfdm.enums import Financial
15
17
  from wbfdm.models.instruments import Instrument
16
-
17
18
  from wbfdm.viewsets.configs.display import (
18
19
  FinancialSummaryDisplayViewConfig,
19
20
  )
20
21
 
21
-
22
22
  from ..mixins import InstrumentMixin
23
23
 
24
24
 
@@ -9,6 +9,7 @@ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
9
9
  from wbcore.pandas import fields as pf
10
10
  from wbcore.serializers.fields.types import DisplayMode
11
11
  from wbcore.utils.date import get_next_day_timedelta
12
+
12
13
  from wbfdm.analysis.financial_analysis.statement_with_estimates import (
13
14
  StatementWithEstimates,
14
15
  )
@@ -12,6 +12,7 @@ from wbcore.cache.decorators import cache_table
12
12
  from wbcore.filters import DjangoFilterBackend
13
13
  from wbcore.permissions.permissions import InternalUserPermissionMixin
14
14
  from wbcore.utils.date import get_next_day_timedelta
15
+
15
16
  from wbfdm.filters import (
16
17
  ClassificationFilter,
17
18
  ClassificationTreeChartFilter,
@@ -7,6 +7,7 @@ import plotly.graph_objects as go
7
7
  from plotly.subplots import make_subplots
8
8
  from wbcore import viewsets
9
9
  from wbcore.utils.date import get_date_interval_from_request
10
+
10
11
  from wbfdm.figures.financials import FinancialsChartGenerator
11
12
  from wbfdm.figures.financials.financial_analysis_charts import (
12
13
  FinancialAnalysisGenerator,
@@ -1,6 +1,7 @@
1
1
  from reversion.views import RevisionMixin
2
2
  from wbcore import viewsets
3
3
  from wbcore.permissions.permissions import InternalUserPermissionMixin
4
+
4
5
  from wbfdm.models.instruments.instrument_lists import (
5
6
  InstrumentList,
6
7
  InstrumentListThroughModel,
@@ -20,6 +20,7 @@ from wbcore.utils.figures import (
20
20
  get_hovertemplate_timeserie,
21
21
  )
22
22
  from wbcore.utils.strings import format_number
23
+
23
24
  from wbfdm.analysis.financial_analysis.financial_statistics_analysis import (
24
25
  FinancialStatistics,
25
26
  )
@@ -1,5 +1,6 @@
1
1
  from django.utils.functional import cached_property
2
2
  from wbcore import viewsets
3
+
3
4
  from wbfdm.models.instruments import InstrumentRequest
4
5
  from wbfdm.serializers.instruments.instrument_requests import (
5
6
  InstrumentRequestModelSerializer,
@@ -3,6 +3,7 @@ from rest_framework.filters import OrderingFilter
3
3
  from wbcore import viewsets
4
4
  from wbcore.contrib.guardian.filters import ObjectPermissionsFilter
5
5
  from wbcore.viewsets.mixins import DjangoFilterBackend
6
+
6
7
  from wbfdm.contrib.metric.backends.performances import PERFORMANCE_METRIC
7
8
  from wbfdm.contrib.metric.backends.statistics import STATISTICS_METRIC
8
9
  from wbfdm.contrib.metric.viewsets.mixins import InstrumentMetricMixin
@@ -8,6 +8,7 @@ from wbcore import serializers as wb_serializers
8
8
  from wbcore import viewsets
9
9
  from wbcore.contrib.tags.serializers import TagSerializerMixin
10
10
  from wbcore.permissions.permissions import InternalUserPermissionMixin
11
+
11
12
  from wbfdm.filters.instruments import BaseClassifiedInstrumentFilterSet
12
13
  from wbfdm.models import (
13
14
  Classification,
@@ -28,6 +29,7 @@ from wbfdm.serializers import (
28
29
  InstrumentClassificationRelatedInstrumentRepresentationSerializer,
29
30
  InstrumentFavoriteGroupModelSerializer,
30
31
  InstrumentFavoriteGroupRepresentationSerializer,
32
+ ReadOnlyInstrumentFavoriteGroupModelSerializer,
31
33
  RelatedInstrumentThroughInstrumentModelSerializer,
32
34
  )
33
35
  from wbfdm.viewsets.configs.display import ClassifiedInstrumentDisplayConfig
@@ -38,6 +40,7 @@ from ..configs import (
38
40
  ClassificationInstrumentRelatedInstrumentEndpointConfig,
39
41
  ClassifiedInstrumentEndpointConfig,
40
42
  InstrumentFavoriteGroupDisplayConfig,
43
+ InstrumentFavoriteGroupEndpointConfig,
41
44
  InstrumentFavoriteGroupTitleConfig,
42
45
  RelatedInstrumentThroughInstrumentDisplayConfig,
43
46
  RelatedInstrumentThroughInstrumentEndpointConfig,
@@ -90,6 +93,20 @@ class InstrumentFavoriteGroupModelViewSet(InternalUserPermissionMixin, viewsets.
90
93
 
91
94
  display_config_class = InstrumentFavoriteGroupDisplayConfig
92
95
  title_config_class = InstrumentFavoriteGroupTitleConfig
96
+ endpoint_config_class = InstrumentFavoriteGroupEndpointConfig
97
+
98
+ @cached_property
99
+ def is_owner(self) -> bool:
100
+ try:
101
+ group = InstrumentFavoriteGroup.objects.get(id=self.kwargs["pk"])
102
+ return group.owner == self.request.user.profile
103
+ except (KeyError, InstrumentFavoriteGroup.DoesNotExist):
104
+ return False
105
+
106
+ def get_serializer_class(self):
107
+ if self.is_owner:
108
+ return InstrumentFavoriteGroupModelSerializer
109
+ return ReadOnlyInstrumentFavoriteGroupModelSerializer
93
110
 
94
111
  def get_queryset(self):
95
112
  qs = InstrumentFavoriteGroup.objects.all()
@@ -8,6 +8,7 @@ from plotly import graph_objects as go
8
8
  from plotly.subplots import make_subplots
9
9
  from wbcore import viewsets
10
10
  from wbcore.utils.date import get_date_interval_from_request
11
+
11
12
  from wbfdm.enums import Indicator, MarketDataChartType
12
13
  from wbfdm.filters import MarketDataChartFilterSet
13
14
  from wbfdm.models.instruments import Instrument
@@ -16,7 +17,7 @@ from .configs import MarketDataChartTitleConfig, PerformanceSummaryChartTitleCon
16
17
  from .mixins import InstrumentMixin
17
18
 
18
19
 
19
- class PerformanceSummaryChartViewSet(InstrumentMixin, viewsets.ChartViewSet):
20
+ class PerformanceSummaryChartViewSet(InstrumentMixin, viewsets.TimeSeriesChartViewSet):
20
21
  queryset = Instrument.objects.all()
21
22
  title_config_class = PerformanceSummaryChartTitleConfig
22
23
 
@@ -39,7 +40,7 @@ class PerformanceSummaryChartViewSet(InstrumentMixin, viewsets.ChartViewSet):
39
40
  return fig
40
41
 
41
42
 
42
- class MarketDataChartViewSet(InstrumentMixin, viewsets.ChartViewSet):
43
+ class MarketDataChartViewSet(InstrumentMixin, viewsets.TimeSeriesChartViewSet):
43
44
  queryset = Instrument.objects.all()
44
45
  filterset_class = MarketDataChartFilterSet
45
46
  title_config_class = MarketDataChartTitleConfig
wbfdm/viewsets/mixins.py CHANGED
@@ -1,5 +1,6 @@
1
1
  from django.utils.functional import cached_property
2
2
  from rest_framework.generics import get_object_or_404
3
+
3
4
  from wbfdm.models import Instrument
4
5
 
5
6
 
@@ -1,5 +1,6 @@
1
1
  from rest_framework.response import Response
2
2
  from wbcore import viewsets
3
+
3
4
  from wbfdm.models.instruments import Instrument
4
5
  from wbfdm.serializers import OfficerSerializer
5
6
  from wbfdm.viewsets.configs.display.officers import OfficerDisplayViewConfig
wbfdm/viewsets/prices.py CHANGED
@@ -5,6 +5,7 @@ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
5
5
  from wbcore.pandas import fields as pf
6
6
  from wbcore.serializers.fields.types import DisplayMode
7
7
  from wbcore.utils.date import get_date_interval_from_request
8
+
8
9
  from wbfdm.filters.instrument_prices import FakeDateRange
9
10
  from wbfdm.models.instruments import Instrument
10
11
  from wbfdm.viewsets.configs.display.prices import InstrumentPriceDisplayConfig
@@ -5,6 +5,7 @@ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
5
5
  from wbcore.pandas import fields as pf
6
6
  from wbcore.serializers.fields.types import DisplayMode
7
7
  from wbcore.utils.date import get_next_day_timedelta
8
+
8
9
  from wbfdm.enums import DataType, PeriodType, StatementType
9
10
  from wbfdm.filters import StatementFilter
10
11
  from wbfdm.models.instruments import Instrument
@@ -6,6 +6,7 @@ from wbcore.pandas import fields as pf
6
6
  from wbcore.permissions.permissions import InternalUserPermissionMixin
7
7
  from wbcore.utils.date import get_date_interval_from_request
8
8
  from wbcore.utils.strings import format_number
9
+
9
10
  from wbfdm.filters import MonthlyPerformancesInstrumentFilterSet
10
11
  from wbfdm.models.instruments import Instrument
11
12
  from wbfdm.viewsets.configs import (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.44.5
3
+ Version: 1.45.1
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.*