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

@@ -52,7 +52,7 @@ where
52
52
  or (fin.ExpireDate is null and ExpireDate is null)
53
53
  )
54
54
  )
55
-
55
+ and fin.isParent = 'false'
56
56
  and fin.EstPermID in (
57
57
  {% for instrument in instruments %}
58
58
  {{ instrument }}{% if not loop.last %},{% endif %}
@@ -299,4 +299,7 @@ def trigger_partial_update(
299
299
  for _, security_id in cursor.execute(
300
300
  f"SELECT UpdateFlag_, {id_field} FROM {table_change_name}"
301
301
  ).fetchall():
302
- update_or_create_item(security_id)
302
+ try:
303
+ update_or_create_item(security_id)
304
+ except Exception as e:
305
+ logger.error(f"Error updating instrument {security_id}: {e}")
@@ -8,6 +8,7 @@ from django.contrib.postgres.search import TrigramSimilarity
8
8
  from django.core.exceptions import MultipleObjectsReturned
9
9
  from django.db import IntegrityError, models
10
10
  from django.db.models import Q
11
+ from slugify import slugify
11
12
  from wbcore.contrib.currency.import_export.handlers import CurrencyImportHandler
12
13
  from wbcore.contrib.geography.models import Geography
13
14
  from wbcore.contrib.io.exceptions import DeserializationError
@@ -24,6 +25,7 @@ class InstrumentLookup:
24
25
  "refinitiv_mnemonic_code",
25
26
  "identifier",
26
27
  "ticker",
28
+ "currency",
27
29
  ]
28
30
 
29
31
  def __init__(self, model, trigram_similarity_min_score: float = 0.8):
@@ -33,10 +35,18 @@ class InstrumentLookup:
33
35
 
34
36
  @classmethod
35
37
  def _get_cache_key(cls, **data):
36
- if data:
37
- return "-".join([f"{k}:{data.get(k, None)}" for k in cls.ORDERED_KEYS if data.get(k, None) is not None])
38
+ return "-".join([f"{k}:{slugify(str(data[k]))}" for k in cls.ORDERED_KEYS if data.get(k, None) is not None])
38
39
 
39
- def _lookup_instrument(
40
+ def _get_cache(self, **kwargs):
41
+ cache_key = self._get_cache_key(**kwargs)
42
+ if cache_key and cache_key in self.cache:
43
+ return self.cache[cache_key]
44
+
45
+ def _set_cache(self, instrument, **kwargs):
46
+ cache_key = self._get_cache_key(**kwargs)
47
+ self.cache[cache_key] = instrument
48
+
49
+ def _lookup_security(
40
50
  self,
41
51
  instrument_type=None,
42
52
  currency=None,
@@ -47,10 +57,6 @@ class InstrumentLookup:
47
57
  **identifiers,
48
58
  ):
49
59
  identifiers = {k: v for k, v in identifiers.items() if v is not None}
50
- # General lookup, we try to gracefully find the instrument based on all available identifier fields
51
- cache_key = self._get_cache_key(**identifiers)
52
- if cache_key and cache_key in self.cache:
53
- return self.cache[cache_key]
54
60
 
55
61
  instrument = None
56
62
 
@@ -126,7 +132,7 @@ class InstrumentLookup:
126
132
  instrument = instruments.first()
127
133
  elif instrument_type and identifiers:
128
134
  # if instrument type was provided but we still didn't find the security, we try without the instrument type in case it was mislabeled
129
- instrument = self._lookup_instrument(
135
+ instrument = self._lookup_security(
130
136
  only_investable_universe=only_investable_universe,
131
137
  exact_lookup=exact_lookup,
132
138
  currency=currency,
@@ -135,7 +141,7 @@ class InstrumentLookup:
135
141
  )
136
142
  if not instrument and name and identifiers:
137
143
  # Sometime, identifier provided emptied the queryset of possible instruments. In a last chance approach, we try to only look for security with the given name
138
- instrument = self._lookup_instrument(
144
+ instrument = self._lookup_security(
139
145
  only_investable_universe=only_investable_universe,
140
146
  exact_lookup=exact_lookup,
141
147
  instrument_type=instrument_type,
@@ -143,27 +149,40 @@ class InstrumentLookup:
143
149
  exchange=exchange,
144
150
  name=name,
145
151
  )
146
- if instrument:
147
- self.cache[cache_key] = instrument
152
+ if instrument and only_investable_universe and instrument.parent:
153
+ instrument = instrument.parent
148
154
  return instrument
149
155
 
156
+ def _lookup_quote(self, security, currency=None, exchange=None, **kwargs):
157
+ quotes = security.children.all()
158
+ if not quotes.exists():
159
+ return security
160
+ if quotes.count() == 1:
161
+ return quotes.first()
162
+ if exchange and quotes.filter(exchange=exchange).count() == 1:
163
+ return quotes.get(exchange=exchange)
164
+ if currency:
165
+ quotes = quotes.filter(currency=currency)
166
+ if quotes.count() == 1:
167
+ return quotes.first()
168
+ if quotes.filter(is_investable_universe=True).count() == 1:
169
+ return quotes.get(is_investable_universe=True)
170
+ return security.children.filter(is_primary=True).first()
171
+
150
172
  def lookup(self, only_security: bool = False, exact_lookup: bool = False, **lookup_kwargs):
151
173
  # To speed up lookup process, we try to get the quote from the investable universe first
152
- security = self._lookup_instrument(only_investable_universe=True, exact_lookup=exact_lookup, **lookup_kwargs)
153
- if not security:
154
- security = self._lookup_instrument(
174
+ if instrument := self._get_cache(**lookup_kwargs):
175
+ return instrument
176
+ instrument = self._lookup_security(only_investable_universe=True, exact_lookup=exact_lookup, **lookup_kwargs)
177
+ if not instrument:
178
+ instrument = self._lookup_security(
155
179
  only_investable_universe=False, exact_lookup=exact_lookup, **lookup_kwargs
156
180
  )
157
- if not only_security and security:
158
- quotes = security.children.all()
159
- if quotes.exists():
160
- # We try to find the quote for that security based on the given exchange (if provided). Otherwise, we default to the security primary exchange
161
- exchange = lookup_kwargs.get("exchange")
162
- if exchange and quotes.filter(exchange=exchange).exists():
163
- return quotes.filter(exchange=exchange).first()
164
- else:
165
- return quotes.filter(is_primary=True).first()
166
- return security
181
+ if not only_security and instrument:
182
+ instrument = self._lookup_quote(instrument, **lookup_kwargs)
183
+ if instrument:
184
+ self._set_cache(instrument, **lookup_kwargs)
185
+ return instrument
167
186
 
168
187
 
169
188
  class InstrumentImportHandler(ImportExportHandler):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.55.5
3
+ Version: 1.55.6
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.*
@@ -113,10 +113,10 @@ wbfdm/contrib/qa/jinja2/qa/sql/ibes/base_estimates.sql,sha256=xmIrDN0LSzWPRFp2cd
113
113
  wbfdm/contrib/qa/jinja2/qa/sql/ibes/calendarized.sql,sha256=w2vi0lgNDDMoFB07bNv4HB_FULQ-kbcb2VAhaQIc5pc,1671
114
114
  wbfdm/contrib/qa/jinja2/qa/sql/ibes/complete.sql,sha256=bkF1h7FcLdeXmmKy2W4rdnBZw9xRVIo_Cu1sVobU-RM,328
115
115
  wbfdm/contrib/qa/jinja2/qa/sql/ibes/estimates.sql,sha256=OWgeogSFj7-OdXvJTvNsThNBz-7kxtygKYvS7dkU3aw,156
116
- wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql,sha256=0jXNMdX8ixVRJ8YyvtoJRQ510pHFYEioMy7NTp5ecck,2582
116
+ wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql,sha256=i8esPCG_ARiXlfSKajqBRH0jiXT_efOvw3No6zEvwn4,2612
117
117
  wbfdm/contrib/qa/sync/exchanges.py,sha256=XU7dj-rQzMlDku9lnmAACaTRoxx8pFSyr5kCK79cYAc,3124
118
118
  wbfdm/contrib/qa/sync/instruments.py,sha256=8aTQVJ_cw1phe4FWikn79pjCfUijaTcwkdhQCtSXKH0,3156
119
- wbfdm/contrib/qa/sync/utils.py,sha256=LUnjNR28moT92cjP04SVCRQ_Ssp6SaO9kehgWV4zvOs,11782
119
+ wbfdm/contrib/qa/sync/utils.py,sha256=Pd7qFTk4X_pC8Q7UMtDy37xoDd6HK7IAY47JDZZwsLM,11940
120
120
  wbfdm/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
121
121
  wbfdm/dataloaders/cache.py,sha256=K9BeVxT7p-BMvjurINt18bfrUDccp840uIjfDBLJRNk,4841
122
122
  wbfdm/dataloaders/protocols.py,sha256=LPuf3edDpP_jkqJpuiakbDR-XNgOxxN5JdDAo2f93Ms,3218
@@ -164,7 +164,7 @@ wbfdm/import_export/backends/refinitiv/mixin.py,sha256=DlNHOWOO71PgY0umaZd0Nbbjs
164
164
  wbfdm/import_export/backends/refinitiv/utils/__init__.py,sha256=Rz38xsLAHEyEwIuJksejYExEznlPJb9tRzwJ7JG9L1s,35
165
165
  wbfdm/import_export/backends/refinitiv/utils/controller.py,sha256=yG8V4C2TGhJdKwTeuMfaG1lzJ3MjNaV632KTe0nuym8,7348
166
166
  wbfdm/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
167
- wbfdm/import_export/handlers/instrument.py,sha256=ZtXwqoCh--_Bgn7mB_A7U2w1S6HfMr9MqFCc4VMw7ls,12071
167
+ wbfdm/import_export/handlers/instrument.py,sha256=3HFEFvU2vQkrlZJS_PS3bQ3VoT04yDGDRncaWNSE4bQ,12633
168
168
  wbfdm/import_export/handlers/instrument_list.py,sha256=mZRfpJFi6BhhrjH2qaFEPqqCK2ybg-DQm43Uck7G9_w,4864
169
169
  wbfdm/import_export/handlers/instrument_price.py,sha256=RbNTo78zZuttzlVFKxJrHcW7DRfcsta7QDEI8OiiDrA,3498
170
170
  wbfdm/import_export/handlers/option.py,sha256=MPzluMPJ3Yu7Ahmw9BA7-ssAbvPDdyca_rC-YVhU8bY,2378
@@ -362,6 +362,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
362
362
  wbfdm/viewsets/statements/statements.py,sha256=gA6RCI8-B__JwjEb6OZxpn8Y-9aF-YQ3HIQ7e1vfJMw,4304
363
363
  wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
364
364
  wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=O1j8CGfOranL74LqVvcf7jERaDIboEJZiBf_AbbVDQ8,3974
365
- wbfdm-1.55.5.dist-info/METADATA,sha256=eiRCemxe43h8H6U7eMbN_WF4jL5xJc8Wl-VzFxabwI0,768
366
- wbfdm-1.55.5.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
367
- wbfdm-1.55.5.dist-info/RECORD,,
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,,
File without changes