wbfdm 1.55.6__py2.py3-none-any.whl → 1.55.8__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.

@@ -2,6 +2,8 @@ from contextlib import suppress
2
2
  from datetime import date
3
3
  from typing import Any
4
4
 
5
+ from wbfdm.contrib.metric.signals import instrument_metric_updated
6
+
5
7
 
6
8
  def compute_metrics(val_date: date, key: str | None = None, basket: Any | None = None, **kwargs):
7
9
  """
@@ -21,3 +23,4 @@ def compute_metrics(val_date: date, key: str | None = None, basket: Any | None =
21
23
  with suppress(KeyError):
22
24
  orchestrator = MetricOrchestrator(val_date, key=key, basket=basket, **kwargs)
23
25
  orchestrator.process()
26
+ instrument_metric_updated.send(sender=basket.__class__, basket=basket, key=key, val_date=val_date)
@@ -0,0 +1,7 @@
1
+ from django.db.models.signals import ModelSignal
2
+
3
+ # this signal is triggered whenever all instruments metrics are updated. Temporary solution until we rework the framework for more dynamicity
4
+
5
+ instrument_metric_updated = ModelSignal(
6
+ use_caching=True
7
+ ) # the sender model is the type model class being updated (e.g. Instrument), expect a "basket", "key" and "val_date" keyword argument (null if all are updated)
@@ -3,7 +3,7 @@ from datetime import date
3
3
  from celery import shared_task
4
4
  from django.contrib.contenttypes.models import ContentType
5
5
 
6
- from wbfdm.contrib.metric.orchestrators import MetricOrchestrator
6
+ from wbfdm.contrib.metric.dispatch import compute_metrics
7
7
 
8
8
 
9
9
  @shared_task(queue="portfolio")
@@ -24,5 +24,4 @@ def compute_metrics_as_task(
24
24
  basket = None
25
25
  if basket_content_type_id and basket_id:
26
26
  basket = ContentType.objects.get(id=basket_content_type_id).get_object_for_this_type(pk=basket_id)
27
- routine = MetricOrchestrator(val_date, key=key, basket=basket, **kwargs)
28
- routine.process()
27
+ compute_metrics(val_date=val_date, key=key, basket=basket, **kwargs)
@@ -66,6 +66,7 @@ class MSCIClient:
66
66
  def controversies(self, identifiers: list[str], factors: list[str]) -> Generator[dict[str, str], None, None]:
67
67
  next_url = "https://api2.msci.com/esg/data/v2.0/issuers"
68
68
  offset = 0
69
+ limit = 100
69
70
  while next_url:
70
71
  with suppress(ConnectionError):
71
72
  response = requests.post(
@@ -73,7 +74,7 @@ class MSCIClient:
73
74
  json={
74
75
  "issuer_identifier_list": identifiers,
75
76
  "factor_name_list": factors,
76
- "limit": 100,
77
+ "limit": limit,
77
78
  "offset": offset,
78
79
  },
79
80
  headers={"AUTHORIZATION": f"Bearer {self.oauth_token}"},
@@ -87,6 +88,6 @@ class MSCIClient:
87
88
  next_url = json_res["paging"]["links"]["next"]
88
89
  except KeyError:
89
90
  next_url = None
90
- offset += 100
91
+ offset += limit
91
92
  for row in json_res.get("result", {}).get("issuers", []):
92
93
  yield row
@@ -149,7 +149,7 @@ class InstrumentLookup:
149
149
  exchange=exchange,
150
150
  name=name,
151
151
  )
152
- if instrument and only_investable_universe and instrument.parent:
152
+ if instrument and only_investable_universe and not instrument.is_security and instrument.parent:
153
153
  instrument = instrument.parent
154
154
  return instrument
155
155
 
@@ -0,0 +1,18 @@
1
+ # Generated by Django 5.0.12 on 2025-09-08 11:39
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('wbfdm', '0032_alter_instrumentprice_outstanding_shares'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='controversy',
15
+ name='review',
16
+ field=models.DateField(blank=True, null=True, verbose_name='Reviewed'),
17
+ ),
18
+ ]
@@ -8,7 +8,6 @@ from wbfdm.enums import (
8
8
  ESGControveryStatus,
9
9
  ESGControveryType,
10
10
  )
11
- from wbfdm.models.instruments.instruments import Instrument
12
11
 
13
12
 
14
13
  class Controversy(models.Model):
@@ -54,29 +53,23 @@ class Controversy(models.Model):
54
53
  direct_involvement = models.BooleanField(default=True, verbose_name="Direct Involvement")
55
54
  company_response = models.CharField(max_length=512, null=True, blank=True)
56
55
 
57
- review = models.DateField(verbose_name="Reviewed")
56
+ review = models.DateField(verbose_name="Reviewed", null=True, blank=True)
58
57
  initiated = models.DateField(verbose_name="initiated", null=True, blank=True)
59
58
 
60
59
  @classmethod
61
- def sync_from_dataloader(cls, controversy: dict[str, Any]) -> Self:
62
- instrument = Instrument.objects.get(
63
- pk=controversy["instrument_id"]
64
- ).get_root() # we link it only to root level
65
-
66
- return cls.objects.update_or_create(
60
+ def dict_to_model(cls, controversy: dict[str, Any], instrument) -> Self:
61
+ return Controversy(
67
62
  external_id=controversy["id"],
68
- defaults={
69
- "instrument": instrument,
70
- "headline": controversy["headline"],
71
- "description": controversy["narrative"],
72
- "source": controversy["source"],
73
- "direct_involvement": controversy.get("direct_involvement", True),
74
- "company_response": controversy["response"],
75
- "review": controversy["review"],
76
- "initiated": controversy["initiated"],
77
- "flag": controversy["flag"],
78
- "status": controversy["status"],
79
- "type": controversy["type"],
80
- "severity": controversy["assessment"],
81
- },
82
- )[0]
63
+ instrument=instrument,
64
+ headline=controversy["headline"],
65
+ description=controversy["narrative"],
66
+ source=controversy["source"],
67
+ direct_involvement=controversy.get("direct_involvement", True),
68
+ company_response=controversy["response"],
69
+ review=controversy["review"],
70
+ initiated=controversy["initiated"],
71
+ flag=controversy["flag"],
72
+ status=controversy["status"],
73
+ type=controversy["type"],
74
+ severity=controversy["assessment"],
75
+ )
wbfdm/tasks.py CHANGED
@@ -6,6 +6,7 @@ from django.db import transaction
6
6
  from django.db.models import ProtectedError, Q
7
7
  from pandas.tseries.offsets import BDay
8
8
  from tqdm import tqdm
9
+ from wbcore.utils.cache import mapping
9
10
 
10
11
  from wbfdm.models import Instrument, InstrumentPrice
11
12
  from wbfdm.sync.runner import ( # noqa: F401
@@ -15,6 +16,7 @@ from wbfdm.sync.runner import ( # noqa: F401
15
16
  synchronize_instruments,
16
17
  )
17
18
 
19
+ from .contrib.metric.signals import instrument_metric_updated
18
20
  from .signals import investable_universe_updated
19
21
 
20
22
 
@@ -71,6 +73,7 @@ def update_instrument_metrics_as_task():
71
73
  instruments = Instrument.active_objects.filter(is_investable_universe=True)
72
74
  for instrument in tqdm(instruments, total=instruments.count()):
73
75
  instrument.update_last_valuation_date()
76
+ instrument_metric_updated.send(sender=Instrument, basket=None, date=None, key=None)
74
77
 
75
78
 
76
79
  @shared_task(queue="portfolio")
@@ -92,6 +95,7 @@ def full_synchronization_as_task():
92
95
  for instrument in qs:
93
96
  with suppress(ProtectedError):
94
97
  instrument.delete()
98
+ mapping.cache_clear() # we need to clear the mapping cache because we might have deleted parent instruments
95
99
  initialize_exchanges()
96
100
  initialize_instruments()
97
101
  with transaction.atomic():
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.55.6
3
+ Version: 1.55.8
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.*
@@ -5,7 +5,7 @@ wbfdm/enums.py,sha256=5AuUouk5uuSNmRc6e-SiBu4FPmHVTN60ol9ftiuVrAc,33041
5
5
  wbfdm/jinja2.py,sha256=pkIC1U-0rf6vn0DDEUzZ8dPYiTGEPY8LBTRMi9wYiuc,199
6
6
  wbfdm/preferences.py,sha256=8ghDcaapOMso1kjtNfKbSFykPUTxzqI5R77gM3BgiMs,927
7
7
  wbfdm/signals.py,sha256=PhAsFpQZF1YVe5UpedaRelUD_TVjemqRYm1HzV-bhmY,597
8
- wbfdm/tasks.py,sha256=zGlzMl-kTWQjkFRRVbaHdcwIaPTgxOJ-ZpyvXmqidFk,4802
8
+ wbfdm/tasks.py,sha256=Q7iuSgV8LdPoKxgyMmTg5qukxHrM5XW1k1H_zI958zU,5104
9
9
  wbfdm/urls.py,sha256=pDp9I0kktxicad8sXXEUT7402jZPMJNcE5R1doTlcMw,8887
10
10
  wbfdm/utils.py,sha256=4cWrCpqXxHIjtSlt4DDPFvmtaqXw_H0nqhM6sGuXx0o,1938
11
11
  wbfdm/admin/__init__.py,sha256=Z1VtH_gjD71K79KcD-2Q2Lu_p_7j0akMZj7gNxdz1CQ,1398
@@ -45,7 +45,7 @@ wbfdm/contrib/internal/dataloaders/market_data.py,sha256=QJx4DsGGN3yy0cjIRDEatt_
45
45
  wbfdm/contrib/metric/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
46
46
  wbfdm/contrib/metric/apps.py,sha256=T-Na_lyFeLR8ebGvaW-mcjKFLqiZcsPXnUlOuVPOiWw,297
47
47
  wbfdm/contrib/metric/decorators.py,sha256=VPmyjEJaq5HqXOt_ZizqcXfRqSEXw4lanDmubUjb2GY,476
48
- wbfdm/contrib/metric/dispatch.py,sha256=io6p4EJf36OdnxZDTw-sRRKfr_q8TLYvIDGWCkb3hOM,915
48
+ wbfdm/contrib/metric/dispatch.py,sha256=GdJoYRFiZXWwo3hZeNTDxOUwg7iniv63ddb-A-7Pc6w,1090
49
49
  wbfdm/contrib/metric/dto.py,sha256=vS93tUvfusWdE7gUJsp320GwfwWpb8bGJDdrb1GB6M8,3413
50
50
  wbfdm/contrib/metric/exceptions.py,sha256=6IuEVde7aOyQaXHE817bCNdUw8LTI3sOSU9LiV3NZbM,200
51
51
  wbfdm/contrib/metric/factories.py,sha256=b6-3fSERbZGjGw6QC0k3hhSpyQKVy2MJoZzX4y3GPEo,1123
@@ -54,7 +54,8 @@ wbfdm/contrib/metric/models.py,sha256=lI_ZmK7058GT_5ngC45UdXRc7ju-ULbcOtO5w_CMBw
54
54
  wbfdm/contrib/metric/orchestrators.py,sha256=YyVVKKm3Sl1zVr2mw9A7LSJs6YnmElbg1yESREF3lFk,3736
55
55
  wbfdm/contrib/metric/registry.py,sha256=SdZff6FIrtdbyAO0X0BpXndJAIhU6VVojNui_MEw7jI,3167
56
56
  wbfdm/contrib/metric/serializers.py,sha256=FqX2pgP4SL1oteVrnAWQezBOJD6JyTidLBEK72GMxrM,1636
57
- wbfdm/contrib/metric/tasks.py,sha256=x605TO-EmvqDjlQY3EjrUJ_9xUZ4tb84_XuQuI4-TAg,941
57
+ wbfdm/contrib/metric/signals.py,sha256=qe-CGNZEc7csseiGgNbz8legvz0EM3e31k8kPQ19Zyw,417
58
+ wbfdm/contrib/metric/tasks.py,sha256=yMgPvDSKUtJy6wFMGP8tdymO2vZGSaqIxKliGrrvzHE,907
58
59
  wbfdm/contrib/metric/urls.py,sha256=hAYOvH50S9k6EJdE_2DP6oCmt0WT314iaXRtNqQnRJo,459
59
60
  wbfdm/contrib/metric/admin/__init__.py,sha256=FW3qhfmS5tA4RNOv9Zse56dICDG7zgdHgBJ-MvT7VKM,125
60
61
  wbfdm/contrib/metric/admin/instruments.py,sha256=mPwwdwxeuo6nvyJ2_xolVdlpK05KMlzOPLaSlh1PtHE,419
@@ -84,7 +85,7 @@ wbfdm/contrib/metric/viewsets/configs/display.py,sha256=aZLy3wSCgJlfrS71qxjPfT56
84
85
  wbfdm/contrib/metric/viewsets/configs/menus.py,sha256=GJbDm3p6qeobet09kpQSSuJT3Bs14gYpXxQ1P16b5VM,422
85
86
  wbfdm/contrib/metric/viewsets/configs/utils.py,sha256=SREiSRS4faohL6lVxmeD3zJN8bb-C-PlANUr8AgpIkI,5009
86
87
  wbfdm/contrib/msci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
87
- wbfdm/contrib/msci/client.py,sha256=u8pcgwS1JRMz5dEdYrH_T1uhR6KTtBE4zK0Ritv8nTU,3609
88
+ wbfdm/contrib/msci/client.py,sha256=XnPATwQKaPc48uvB_BnbxwZuoyQkA1kVNp_-48A0irY,3633
88
89
  wbfdm/contrib/msci/sync.py,sha256=StD2TliqxVnZ7YsITjYvdh7E95USS3_P9j8KgRlcDKY,2289
89
90
  wbfdm/contrib/msci/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
90
91
  wbfdm/contrib/msci/dataloaders/esg.py,sha256=VM2zprCC0q0CYSwGPA252czcVx9QpmxYv8FsLTKCGAI,4820
@@ -164,7 +165,7 @@ wbfdm/import_export/backends/refinitiv/mixin.py,sha256=DlNHOWOO71PgY0umaZd0Nbbjs
164
165
  wbfdm/import_export/backends/refinitiv/utils/__init__.py,sha256=Rz38xsLAHEyEwIuJksejYExEznlPJb9tRzwJ7JG9L1s,35
165
166
  wbfdm/import_export/backends/refinitiv/utils/controller.py,sha256=yG8V4C2TGhJdKwTeuMfaG1lzJ3MjNaV632KTe0nuym8,7348
166
167
  wbfdm/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
- wbfdm/import_export/handlers/instrument.py,sha256=3HFEFvU2vQkrlZJS_PS3bQ3VoT04yDGDRncaWNSE4bQ,12633
168
+ wbfdm/import_export/handlers/instrument.py,sha256=R1g8OSAspezYRW40KY_AIrMPAwKNO0tjjsXGj6UFjkM,12664
168
169
  wbfdm/import_export/handlers/instrument_list.py,sha256=mZRfpJFi6BhhrjH2qaFEPqqCK2ybg-DQm43Uck7G9_w,4864
169
170
  wbfdm/import_export/handlers/instrument_price.py,sha256=RbNTo78zZuttzlVFKxJrHcW7DRfcsta7QDEI8OiiDrA,3498
170
171
  wbfdm/import_export/handlers/option.py,sha256=MPzluMPJ3Yu7Ahmw9BA7-ssAbvPDdyca_rC-YVhU8bY,2378
@@ -225,13 +226,14 @@ wbfdm/migrations/0029_alter_instrumentprice_volume.py,sha256=0UFUwEaBcqiWjKw6un1
225
226
  wbfdm/migrations/0030_alter_relatedinstrumentthroughmodel_related_type.py,sha256=10-89NB7-T7t3xFPpd4fYQkKejNR36UewIhe5_20QCo,565
226
227
  wbfdm/migrations/0031_exchange_apply_round_lot_size_and_more.py,sha256=MqcHxgJIt67BEuEYK8vnJHhx_cGFw9Ca9Az2EvsDy1o,863
227
228
  wbfdm/migrations/0032_alter_instrumentprice_outstanding_shares.py,sha256=uRgkf6j97kNaXAo0-_V3XzHNE59hvxSruJB18g53YwU,570
229
+ wbfdm/migrations/0033_alter_controversy_review.py,sha256=A9npErIpE0QUEjqIqpxmO5GMi0VA2Id8whn1nswWXpU,445
228
230
  wbfdm/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
229
231
  wbfdm/models/__init__.py,sha256=PWsLtlKJFDYycCohPbjsRLeWi1xaxEkZbaoUKo0yOBU,96
230
232
  wbfdm/models/fields.py,sha256=eQ_6EnDBMy0U7WzE2DsdXIXOJH5dFiIN2VbO2Svw4R0,3942
231
233
  wbfdm/models/fk_fields.py,sha256=XuOGN0Fnq4Hld9IcBKSpeSSrfAQD91B-HNYNVd69fAk,15041
232
234
  wbfdm/models/indicators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
233
235
  wbfdm/models/esg/__init__.py,sha256=FEYbRFSdfoWRsfKVxM-h6TLobj5P8bYQlZPG1iD9RMQ,29
234
- wbfdm/models/esg/controversies.py,sha256=OnswX0ZXdO37h-AWpr5aTJXhyT3MTwAOwt5ZV25t5BY,2950
236
+ wbfdm/models/esg/controversies.py,sha256=ioAlytF3H_IKGtYfkDWyo7Xj6S4z7vvuyd5rgOed50s,2632
235
237
  wbfdm/models/exchanges/__init__.py,sha256=sScz2KX9fxhhmi4CEUssC8HCL4ENvrIqSSwk0_J7v-g,32
236
238
  wbfdm/models/exchanges/exchanges.py,sha256=RmM5shyyuxEGN2Y3JmeSWyU-SbpVARrvVFW72HtHwfg,7502
237
239
  wbfdm/models/instruments/__init__.py,sha256=OvEkECJaCubBQC7B9yUrx15V982labvegeGXyEASVno,636
@@ -362,6 +364,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
362
364
  wbfdm/viewsets/statements/statements.py,sha256=gA6RCI8-B__JwjEb6OZxpn8Y-9aF-YQ3HIQ7e1vfJMw,4304
363
365
  wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
364
366
  wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=O1j8CGfOranL74LqVvcf7jERaDIboEJZiBf_AbbVDQ8,3974
365
- wbfdm-1.55.6.dist-info/METADATA,sha256=opBTM0DoBJf4R17zOqRcOsxSrCJE5ocMd7An5nL6uKQ,768
366
- wbfdm-1.55.6.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
367
- wbfdm-1.55.6.dist-info/RECORD,,
367
+ wbfdm-1.55.8.dist-info/METADATA,sha256=6UW2WaAZh_j3qt0e6kTNiwGfRVpwKgyby7P_wITI540,768
368
+ wbfdm-1.55.8.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
369
+ wbfdm-1.55.8.dist-info/RECORD,,
File without changes