wbfdm 1.55.9__py2.py3-none-any.whl → 1.55.10rc0__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 (44) hide show
  1. wbfdm/contrib/dsws/client.py +3 -3
  2. wbfdm/contrib/dsws/dataloaders/market_data.py +1 -1
  3. wbfdm/contrib/internal/dataloaders/market_data.py +1 -1
  4. wbfdm/contrib/metric/backends/base.py +2 -2
  5. wbfdm/contrib/metric/backends/statistics.py +2 -2
  6. wbfdm/contrib/metric/exceptions.py +1 -1
  7. wbfdm/contrib/metric/models.py +6 -0
  8. wbfdm/contrib/metric/orchestrators.py +4 -4
  9. wbfdm/contrib/metric/viewsets/mixins.py +6 -6
  10. wbfdm/contrib/msci/client.py +3 -0
  11. wbfdm/contrib/qa/database_routers.py +1 -1
  12. wbfdm/contrib/qa/dataloaders/adjustments.py +2 -1
  13. wbfdm/contrib/qa/dataloaders/corporate_actions.py +2 -1
  14. wbfdm/contrib/qa/dataloaders/market_data.py +1 -1
  15. wbfdm/contrib/qa/dataloaders/officers.py +1 -1
  16. wbfdm/contrib/qa/sync/utils.py +4 -2
  17. wbfdm/dataloaders/protocols.py +1 -1
  18. wbfdm/figures/financials/financial_analysis_charts.py +2 -8
  19. wbfdm/filters/instruments.py +1 -1
  20. wbfdm/import_export/backends/cbinsights/utils/client.py +8 -8
  21. wbfdm/import_export/backends/refinitiv/utils/controller.py +1 -1
  22. wbfdm/import_export/handlers/instrument.py +2 -2
  23. wbfdm/import_export/parsers/cbinsights/equities.py +2 -3
  24. wbfdm/jinja2.py +2 -1
  25. wbfdm/models/esg/controversies.py +3 -0
  26. wbfdm/models/fields.py +2 -2
  27. wbfdm/models/fk_fields.py +3 -3
  28. wbfdm/models/instruments/instrument_relationships.py +3 -0
  29. wbfdm/models/instruments/instruments.py +6 -6
  30. wbfdm/models/instruments/mixin/instruments.py +2 -2
  31. wbfdm/models/instruments/options.py +6 -0
  32. wbfdm/models/instruments/private_equities.py +3 -0
  33. wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py +0 -1
  34. wbfdm/viewsets/configs/display/instruments_relationships.py +3 -1
  35. wbfdm/viewsets/configs/titles/instrument_prices.py +2 -1
  36. wbfdm/viewsets/esg.py +2 -2
  37. wbfdm/viewsets/financial_analysis/financial_metric_analysis.py +2 -2
  38. wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py +1 -1
  39. wbfdm/viewsets/financial_analysis/financial_summary.py +6 -6
  40. wbfdm/viewsets/instruments/financials_analysis.py +8 -11
  41. wbfdm/viewsets/market_data.py +1 -1
  42. {wbfdm-1.55.9.dist-info → wbfdm-1.55.10rc0.dist-info}/METADATA +1 -1
  43. {wbfdm-1.55.9.dist-info → wbfdm-1.55.10rc0.dist-info}/RECORD +44 -44
  44. {wbfdm-1.55.9.dist-info → wbfdm-1.55.10rc0.dist-info}/WHEEL +0 -0
@@ -3,7 +3,7 @@ import re
3
3
  from datetime import date, datetime
4
4
  from typing import Generator, List, Optional
5
5
 
6
- import DatastreamPy as dsweb
6
+ import DatastreamPy as dsweb # noqa
7
7
  import numpy as np
8
8
  import pandas as pd
9
9
  import pytz
@@ -13,7 +13,7 @@ from wbcore.contrib.currency.models import Currency, CurrencyFXRates
13
13
 
14
14
 
15
15
  class CachedTokenDataClient(dsweb.DataClient):
16
- def _get_token(self, isProxy=False):
16
+ def _get_token(self, isProxy=False): # noqa
17
17
  if (token := cache.get("dsws_token")) and (token_expiry := cache.get("dsws_token_expiry")):
18
18
  self.token = token
19
19
  self.tokenExpiry = timezone.make_aware(datetime.fromtimestamp(token_expiry), timezone=pytz.UTC)
@@ -102,7 +102,7 @@ class Client:
102
102
  if len(requests_data) > self.MAXIMUM_REQUESTS_PER_BUNDLE:
103
103
  raise ValueError(f"number of request exceed {self.MAXIMUM_REQUESTS_PER_BUNDLE}")
104
104
  # Construct the requests bundle
105
- for request_tickers, request_symbols in requests_data:
105
+ for request_tickers, _ in requests_data:
106
106
  # Convert a list of string into a valid string
107
107
  converted_ticker = ",".join(request_tickers)
108
108
  if "start" in extra_client_kwargs or "end" in extra_client_kwargs:
@@ -30,7 +30,7 @@ FIELD_MAP = {
30
30
  class DSWSMarketDataDataloader(MarketDataProtocol, Dataloader):
31
31
  def market_data(
32
32
  self,
33
- values: list[MarketData] = [MarketData.CLOSE],
33
+ values: list[MarketData] | None = None,
34
34
  from_date: date | None = None,
35
35
  to_date: date | None = None,
36
36
  exact_date: date | None = None,
@@ -36,7 +36,7 @@ def _cast_decimal_to_float(value: float | Decimal) -> float:
36
36
  class MarketDataDataloader(MarketDataProtocol, Dataloader):
37
37
  def market_data(
38
38
  self,
39
- values: list[MarketData] = [MarketData.CLOSE],
39
+ values: list[MarketData] | None = None,
40
40
  from_date: date | None = None,
41
41
  to_date: date | None = None,
42
42
  exact_date: date | None = None,
@@ -13,7 +13,7 @@ from wbcore.contrib.currency.models import CurrencyFXRates
13
13
  from wbfdm.models import Instrument, InstrumentPrice
14
14
 
15
15
  from ..dto import Metric, MetricField, MetricKey
16
- from ..exceptions import MetricInvalidParameterException
16
+ from ..exceptions import MetricInvalidParameterError
17
17
  from .utils import get_today
18
18
 
19
19
  T = TypeVar("T", bound=Model)
@@ -94,7 +94,7 @@ class InstrumentMetricBaseBackend(AbstractBackend[Instrument]):
94
94
  [val_date, (get_today() - pd.tseries.offsets.BDay(1)).date()]
95
95
  ) # ensure that value date is at least lower than today (otherwise, we might compute performance for intraday, which we do not want yet
96
96
  else:
97
- raise MetricInvalidParameterException()
97
+ raise MetricInvalidParameterError()
98
98
 
99
99
 
100
100
  class BaseDataloader:
@@ -11,7 +11,7 @@ from wbfdm.models import Instrument, InstrumentPrice
11
11
 
12
12
  from ..decorators import register
13
13
  from ..dto import Metric, MetricField, MetricKey
14
- from ..exceptions import MetricInvalidParameterException
14
+ from ..exceptions import MetricInvalidParameterError
15
15
  from .base import BaseDataloader, InstrumentMetricBaseBackend
16
16
 
17
17
  STATISTICS_METRIC = MetricKey(
@@ -207,7 +207,7 @@ class InstrumentFinancialStatisticsMetricBackend(InstrumentMetricBaseBackend):
207
207
  elif self.val_date:
208
208
  with suppress(InstrumentPrice.DoesNotExist):
209
209
  return instrument.valuations.filter(date__lte=self.val_date).latest("date").date
210
- raise MetricInvalidParameterException()
210
+ raise MetricInvalidParameterError()
211
211
 
212
212
 
213
213
  @register(move_first=True)
@@ -1,4 +1,4 @@
1
- class MetricInvalidParameterException(Exception):
1
+ class MetricInvalidParameterError(Exception):
2
2
  """
3
3
  If instantiated backend parameters are invalid, the orchestrator or backend itself are expected to raise that exception
4
4
  """
@@ -48,6 +48,12 @@ class InstrumentMetric(models.Model):
48
48
  self.basket_repr = str(self.basket)
49
49
  super().save(*args, **kwargs)
50
50
 
51
+ def __str__(self) -> str:
52
+ repr = f"{self.basket} - {self.key}"
53
+ if self.date:
54
+ repr += f"({self.date})"
55
+ return repr
56
+
51
57
  @classmethod
52
58
  def update_or_create_from_metric(cls, metric: Metric, parent_instrument_metric: Self | None = None):
53
59
  """
@@ -8,7 +8,7 @@ from tqdm import tqdm
8
8
 
9
9
  from .backends.base import AbstractBackend
10
10
  from .dto import Metric
11
- from .exceptions import MetricInvalidParameterException
11
+ from .exceptions import MetricInvalidParameterError
12
12
  from .models import InstrumentMetric
13
13
  from .registry import backend_registry
14
14
 
@@ -73,9 +73,9 @@ class MetricOrchestrator:
73
73
  if debug:
74
74
  # if debug mode is enabled, we wrap the parameters list into a tqdm generator
75
75
  parameters = tqdm(parameters)
76
- for parameters in parameters:
77
- with suppress(MetricInvalidParameterException):
78
- yield from parameters[0].compute_metrics(parameters[1])
76
+ for param in parameters:
77
+ with suppress(MetricInvalidParameterError):
78
+ yield from param[0].compute_metrics(param[1])
79
79
 
80
80
  def process(self, debug: bool = False):
81
81
  """
@@ -185,19 +185,19 @@ class InstrumentMetricMixin(_Base):
185
185
  serializer_class = self.get_serializer_class()
186
186
  kwargs.setdefault("context", self.get_serializer_context())
187
187
 
188
- BaseMeta = serializer_class.Meta
189
- fields = list(getattr(BaseMeta, "fields", ()))
190
- read_only_fields = list(getattr(BaseMeta, "read_only_fields", ()))
188
+ base_meta = serializer_class.Meta
189
+ fields = list(getattr(base_meta, "fields", ()))
190
+ read_only_fields = list(getattr(base_meta, "read_only_fields", ()))
191
191
  for extra_field in self._metric_serializer_fields.keys():
192
192
  fields.append(extra_field)
193
193
  read_only_fields.append(extra_field)
194
194
 
195
- Meta = type(str("Meta"), (BaseMeta,), {"fields": fields, "read_only_fields": read_only_fields})
195
+ meta = type(str("Meta"), (base_meta,), {"fields": fields, "read_only_fields": read_only_fields})
196
196
  new_class = type(
197
197
  serializer_class.__name__,
198
198
  (serializer_class,),
199
199
  {
200
- "Meta": Meta,
200
+ "Meta": meta,
201
201
  **self._metric_serializer_fields,
202
202
  "SERIALIZER_CLASS_FOR_REMOTE_ADDITIONAL_RESOURCES": serializer_class,
203
203
  },
@@ -233,7 +233,7 @@ class InstrumentMetricMixin(_Base):
233
233
  # for all the missings keys (not present in the aggregates already), we compute the aggregatation based on the aggregate function given by the MetricField class
234
234
  missing_aggregate_map = {}
235
235
  for metric_key in self.metric_keys:
236
- for field_key, field_filter in metric_key.subfields_filter_map.items():
236
+ for field_key in metric_key.subfields_filter_map.keys():
237
237
  if field_key in self._metric_serializer_fields.keys() and field_key not in aggregates:
238
238
  missing_aggregate_map[field_key] = metric_key.subfields_map[field_key]
239
239
  missing_aggregate = queryset.aggregate(
@@ -38,6 +38,7 @@ class MSCIClient:
38
38
  "grant_type": "client_credentials",
39
39
  "audience": "https://esg/data",
40
40
  },
41
+ timeout=10,
41
42
  )
42
43
  if resp.status_code == requests.codes.ok:
43
44
  with suppress(KeyError, requests.exceptions.JSONDecodeError):
@@ -58,6 +59,7 @@ class MSCIClient:
58
59
  "factor_name_list": factors,
59
60
  },
60
61
  headers={"AUTHORIZATION": f"Bearer {self.oauth_token}"},
62
+ timeout=10,
61
63
  )
62
64
  if response.ok:
63
65
  for row in response.json().get("result", {}).get("issuers", []):
@@ -78,6 +80,7 @@ class MSCIClient:
78
80
  "offset": offset,
79
81
  },
80
82
  headers={"AUTHORIZATION": f"Bearer {self.oauth_token}"},
83
+ timeout=10,
81
84
  )
82
85
 
83
86
  if not response.ok:
@@ -20,6 +20,6 @@ class QARouter:
20
20
  return None
21
21
 
22
22
  def allow_migrate(self, db, app_label, model_name=None, **hints):
23
- if app_label == "qa":
23
+ if db == "qa":
24
24
  return False
25
25
  return None
@@ -57,7 +57,8 @@ class DatastreamAdjustmentsDataloader(AdjustmentsProtocol, Dataloader):
57
57
  pk.MSSQLQuery.create_table(infocode).columns(pk.Column("infocode", SqlTypes.INTEGER)).get_sql()
58
58
  )
59
59
  for batch in batched(lookup.keys(), 1000):
60
- cursor.execute(f"insert into #ds2infocode values {",".join(map(lambda x: f"({x})", batch))};")
60
+ placeholders = ",".join(map(lambda x: f"({x})", batch))
61
+ cursor.execute("insert into #ds2infocode values %s;", (placeholders,))
61
62
 
62
63
  cursor.execute(query.get_sql())
63
64
 
@@ -58,7 +58,8 @@ class DatastreamCorporateActionsDataloader(CorporateActionsProtocol, Dataloader)
58
58
  pk.MSSQLQuery.create_table(infocode).columns(pk.Column("infocode", SqlTypes.INTEGER)).get_sql()
59
59
  )
60
60
  for batch in batched(lookup.keys(), 1000):
61
- cursor.execute(f"insert into #ds2infocode values {','.join(map(lambda x: f'({x})', batch))};")
61
+ placeholders = ",".join(map(lambda x: f"({x})", batch))
62
+ cursor.execute("insert into #ds2infocode values %s;", (placeholders,))
62
63
 
63
64
  cursor.execute(query.get_sql())
64
65
  for row in dictfetchall(cursor, CorporateActionDataDict):
@@ -41,7 +41,7 @@ class DS2MarketData(Enum):
41
41
  class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
42
42
  def market_data(
43
43
  self,
44
- values: list[MarketData] = [MarketData.CLOSE],
44
+ values: list[MarketData] | None = None,
45
45
  from_date: date | None = None,
46
46
  to_date: date | None = None,
47
47
  exact_date: date | None = None,
@@ -60,7 +60,7 @@ class RKDOfficersDataloader(OfficersProtocol, Dataloader):
60
60
  )
61
61
  for batch in batched(lookup.keys(), 1000):
62
62
  placeholders = ",".join(map(lambda x: f"('{x}')", batch))
63
- cursor.execute(f"insert into #rkd_codes values {placeholders};")
63
+ cursor.execute("insert into #rkd_codes values %s;", (placeholders,))
64
64
 
65
65
  cursor.execute(query.get_sql())
66
66
 
@@ -290,14 +290,16 @@ def trigger_partial_update(
290
290
  else:
291
291
  with connections["qa"].cursor() as cursor:
292
292
  cursor.execute(
293
- f"SELECT MAX(last_user_update) FROM sys.dm_db_index_usage_stats WHERE OBJECT_NAME(object_id) = '{table_change_name}'"
293
+ "SELECT MAX(last_user_update) FROM sys.dm_db_index_usage_stats WHERE OBJECT_NAME(object_id) = %S'",
294
+ (table_change_name,),
294
295
  )
295
296
  max_last_updated_qa = (
296
297
  pytz.timezone(settings.TIME_ZONE).localize(result[0]) if (result := cursor.fetchone()) else None
297
298
  )
298
299
  if max_last_updated_qa and max_last_updated_qa > max_last_updated:
299
300
  for _, security_id in cursor.execute(
300
- f"SELECT UpdateFlag_, {id_field} FROM {table_change_name}"
301
+ "SELECT UpdateFlag_, %s FROM %s",
302
+ (id_field, table_change_name),
301
303
  ).fetchall():
302
304
  try:
303
305
  update_or_create_item(security_id)
@@ -49,7 +49,7 @@ class FXRateProtocol(Protocol):
49
49
  class MarketDataProtocol(Protocol):
50
50
  def market_data(
51
51
  self,
52
- values: list[MarketData] = [MarketData.CLOSE],
52
+ values: list[MarketData] | None = None,
53
53
  from_date: date | None = None,
54
54
  to_date: date | None = None,
55
55
  exact_date: date | None = None,
@@ -115,13 +115,7 @@ class FinancialAnalysisGenerator:
115
115
  self.instruments_repr_map = {i.id: i.name_repr for i in self.instruments}
116
116
  self.currency_map = {i.id: i.currency.id for i in self.instruments}
117
117
 
118
- def build_df(
119
- self,
120
- instrument_prices_field_names: list[str] = [],
121
- fundamental_field_names: list[str] = [],
122
- forecast_field_names: list[str] = [],
123
- daily_fundamental_field_names: list[str] = [],
124
- ):
118
+ def build_df(self, **kwargs):
125
119
  """
126
120
  Used to returns a df with all the variables passed in four separate lists
127
121
 
@@ -239,7 +233,7 @@ class FinancialAnalysisGenerator:
239
233
  @staticmethod
240
234
  def clean_data(
241
235
  df: pd.DataFrame,
242
- var_list: list[str] = [],
236
+ var_list: list[str],
243
237
  drop_negative=True,
244
238
  q_low: float = 0.05,
245
239
  q_high: float = 0.95,
@@ -138,7 +138,7 @@ class InstrumentFilterSet(TagFilterMixin, InstrumentFavoriteGroupFilterSet):
138
138
  if "parent" in data:
139
139
  data.pop("classifications", None) # remove classifications in case we are navigating the tree
140
140
  data.pop("level", None)
141
- super().__init__(data=data, *args, **kwargs)
141
+ super().__init__(*args, data=data, **kwargs)
142
142
 
143
143
  class Meta:
144
144
  model = Instrument
@@ -7,11 +7,11 @@ from celery import shared_task
7
7
  from tqdm import tqdm
8
8
 
9
9
 
10
- class RateLimitException(Exception):
10
+ class RateLimitError(Exception):
11
11
  pass
12
12
 
13
13
 
14
- class CreditLimitException(Exception):
14
+ class CreditLimitError(Exception):
15
15
  pass
16
16
 
17
17
 
@@ -38,17 +38,18 @@ class Client:
38
38
  url,
39
39
  params={**params, **{"nextPageToken": next_page_token}} if next_page_token else params,
40
40
  headers={"authorization": self.jwt_header_value},
41
+ timeout=10,
41
42
  )
42
43
  if resp.status_code != 200:
43
44
  if resp.status_code == 429:
44
- raise RateLimitException()
45
+ raise RateLimitError()
45
46
  raise requests.ConnectionError(
46
47
  f"unexpected error from api\nstatus_code: {resp.status_code}\nerror: {resp.text}"
47
48
  )
48
49
 
49
50
  if credits_remaining_str := resp.headers.get("x-cbinsights-credits-remaining", None):
50
51
  if int(credits_remaining_str) <= 0:
51
- raise CreditLimitException()
52
+ raise CreditLimitError()
52
53
 
53
54
  return resp.json()
54
55
 
@@ -72,11 +73,11 @@ class Client:
72
73
  resp = self._request(data_url, params=params, next_page_token=next_page_token)
73
74
  yield resp
74
75
  next_page_token = resp["nextPageToken"]
75
- except RateLimitException:
76
+ except RateLimitError:
76
77
  time.sleep(self.rate_limit_sleep)
77
78
  retry += 1
78
79
  if retry >= 5:
79
- raise RateLimitException()
80
+ raise RateLimitError()
80
81
 
81
82
  def _chunk_paginated_request(self, data_url, org_ids, extra_params, endpoint, debug: bool = False):
82
83
  data = []
@@ -96,8 +97,7 @@ class Client:
96
97
  auth_url = "https://api.cbinsights.com/v1/authorize"
97
98
 
98
99
  auth_resp = requests.get(
99
- auth_url,
100
- params={"clientId": self.client_id, "clientSecret": self.client_secret},
100
+ auth_url, params={"clientId": self.client_id, "clientSecret": self.client_secret}, timeout=10
101
101
  )
102
102
 
103
103
  if auth_resp.status_code != 200:
@@ -61,7 +61,7 @@ class Controller:
61
61
  instrument_ric: str = None,
62
62
  instrument_isin: str = None,
63
63
  instrument_mnemonic: str = None,
64
- perm_id_symbols: list[str] = ["QPID", "IPID"],
64
+ perm_id_symbols: tuple[str, ...] = ("QPID", "IPID"),
65
65
  ) -> str | None:
66
66
  def _process_ticker(ticker):
67
67
  if not (df := self.client.get_static_df(tickers=[ticker], fields=perm_id_symbols)).empty:
@@ -237,8 +237,8 @@ class InstrumentImportHandler(ImportExportHandler):
237
237
  if instrument_id := data.pop("id", None):
238
238
  try:
239
239
  return self.model.objects.get(id=instrument_id)
240
- except self.model.DoesNotExist:
241
- raise DeserializationError("Instrument id does not match an existing instrument")
240
+ except self.model.DoesNotExist as e:
241
+ raise DeserializationError("Instrument id does not match an existing instrument") from e
242
242
  else:
243
243
  return self.instrument_lookup.lookup(only_security=only_security, **data)
244
244
 
@@ -1,4 +1,5 @@
1
1
  import json
2
+ from contextlib import suppress
2
3
 
3
4
  from wbcore.contrib.geography.models import Geography
4
5
 
@@ -44,14 +45,12 @@ def parse(import_source):
44
45
  d["headquarter_address"] = f"{street}, {postal_code} {city_name}"
45
46
 
46
47
  if sector_id := summary.get("sectorId", None):
47
- try:
48
+ with suppress(Exception):
48
49
  code_aggregated = f"{int(sector_id):03}"
49
50
  if industry_id := summary.get("industryId", None):
50
51
  code_aggregated += f"{int(industry_id):03}"
51
52
  if subindustry_id := summary.get("subindustryId", None):
52
53
  code_aggregated += f"{int(subindustry_id):03}"
53
- except Exception:
54
- pass
55
54
  d["classifications"] = [{"code_aggregated": code_aggregated, "group": cbinsight_group.id}]
56
55
  data.append(d)
57
56
  return {"data": data}
wbfdm/jinja2.py CHANGED
@@ -3,5 +3,6 @@ from jinjasql import JinjaSql # type: ignore
3
3
 
4
4
 
5
5
  def get_environment(**options):
6
- env = Environment(**options)
6
+ # we except only SQL template, so we need to not escape special characters (possible XSS attack for HTML template)
7
+ env = Environment(**options) # noqa: S701
7
8
  return JinjaSql(env=env, param_style="format").env
@@ -56,6 +56,9 @@ class Controversy(models.Model):
56
56
  review = models.DateField(verbose_name="Reviewed", null=True, blank=True)
57
57
  initiated = models.DateField(verbose_name="initiated", null=True, blank=True)
58
58
 
59
+ def __str__(self) -> str:
60
+ return f"{self.headline} ({self.instrument})"
61
+
59
62
  @classmethod
60
63
  def dict_to_model(cls, controversy: dict[str, Any], instrument) -> Self:
61
64
  return Controversy(
wbfdm/models/fields.py CHANGED
@@ -23,7 +23,7 @@ class CompositeKey(models.AutoField):
23
23
  def __init__(self, columns: list[str], db_column_ref: str | None = None, *args, **kwargs):
24
24
  self.columns = columns
25
25
  self.db_column_ref = db_column_ref
26
- super().__init__(primary_key=True, *args, **kwargs)
26
+ super().__init__(*args, primary_key=True, **kwargs)
27
27
 
28
28
  def contribute_to_class(self, cls, name, private_only=False):
29
29
  self.set_attributes_from_name(name)
@@ -108,7 +108,7 @@ class Exact(models.Lookup):
108
108
 
109
109
  lookups = [
110
110
  lookup_class(field.get_col(self.lhs.alias), self.rhs[column])
111
- for lookup_class, field, column in zip(lookup_classes, fields, self.lhs.field.columns)
111
+ for lookup_class, field, column in zip(lookup_classes, fields, self.lhs.field.columns, strict=False)
112
112
  ]
113
113
 
114
114
  value_constraint = WhereNode()
wbfdm/models/fk_fields.py CHANGED
@@ -93,7 +93,7 @@ class CompositeForeignKey(ForeignObject):
93
93
  kwargs["on_delete"] = self.override_on_delete(kwargs["on_delete"])
94
94
 
95
95
  kwargs["to_fields"], kwargs["from_fields"] = zip(
96
- *((k, v.value) for k, v in self._raw_fields.items() if v.is_local_field)
96
+ *((k, v.value) for k, v in self._raw_fields.items() if v.is_local_field), strict=False
97
97
  )
98
98
  super().__init__(to, **kwargs)
99
99
 
@@ -220,7 +220,7 @@ class CompositeForeignKey(ForeignObject):
220
220
 
221
221
  def _check_nullifequal_fields_exists(self):
222
222
  res = []
223
- for field_name, value in self.null_if_equal:
223
+ for field_name, _ in self.null_if_equal:
224
224
  try:
225
225
  self.model._meta.get_field(field_name)
226
226
  except FieldDoesNotExist:
@@ -269,7 +269,7 @@ class CompositeForeignKey(ForeignObject):
269
269
 
270
270
  return OrderedDict(
271
271
  (k, (v if isinstance(v, CompositePart) else LocalFieldValue(v)))
272
- for k, v in (to_fields.items() if isinstance(to_fields, dict) else zip(to_fields, to_fields))
272
+ for k, v in (to_fields.items() if isinstance(to_fields, dict) else zip(to_fields, to_fields, strict=False))
273
273
  )
274
274
 
275
275
  def db_type(self, connection):
@@ -162,6 +162,9 @@ class RelatedInstrumentThroughModel(models.Model):
162
162
  class Meta:
163
163
  unique_together = ("instrument", "related_instrument", "is_primary", "related_type")
164
164
 
165
+ def __str__(self) -> str:
166
+ return f"{self.instrument} - {self.related_instrument} ({self.related_type})"
167
+
165
168
  def save(self, *args, **kwargs):
166
169
  qs = RelatedInstrumentThroughModel.objects.filter(
167
170
  instrument=self.instrument, related_type=self.related_type, is_primary=True
@@ -205,38 +205,38 @@ class InstrumentType(models.Model):
205
205
 
206
206
  @classmethod
207
207
  @property
208
- def PRODUCT(cls):
208
+ def PRODUCT(cls): # noqa
209
209
  return InstrumentType.objects.get_or_create(
210
210
  key="product", defaults={"name": "Product", "short_name": "Product"}
211
211
  )[0]
212
212
 
213
213
  @classmethod
214
214
  @property
215
- def EQUITY(cls):
215
+ def EQUITY(cls): # noqa
216
216
  return InstrumentType.objects.get_or_create(key="equity", defaults={"name": "equity", "short_name": "equity"})[
217
217
  0
218
218
  ]
219
219
 
220
220
  @classmethod
221
221
  @property
222
- def INDEX(cls):
222
+ def INDEX(cls): # noqa
223
223
  return InstrumentType.objects.get_or_create(key="index", defaults={"name": "Index", "short_name": "Index"})[0]
224
224
 
225
225
  @classmethod
226
226
  @property
227
- def CASH(cls):
227
+ def CASH(cls): # noqa
228
228
  return InstrumentType.objects.get_or_create(key="cash", defaults={"name": "Cash", "short_name": "Cash"})[0]
229
229
 
230
230
  @classmethod
231
231
  @property
232
- def CASHEQUIVALENT(cls):
232
+ def CASHEQUIVALENT(cls): # noqa
233
233
  return InstrumentType.objects.get_or_create(
234
234
  key="cash_equivalent", defaults={"name": "Cash Equivalents", "short_name": "Cash Equivalents"}
235
235
  )[0]
236
236
 
237
237
  @classmethod
238
238
  @property
239
- def PRODUCT_GROUP(cls):
239
+ def PRODUCT_GROUP(cls): # noqa
240
240
  return InstrumentType.objects.get_or_create(
241
241
  key="product_group", defaults={"name": "Product Group", "short_name": "Product Group"}
242
242
  )[0]
@@ -63,7 +63,7 @@ class InstrumentPMSMixin:
63
63
  market_capitalization=price.market_capitalization,
64
64
  outstanding_shares=float(price.outstanding_shares) if price.outstanding_shares else None,
65
65
  )
66
- except InstrumentPrice.DoesNotExist:
66
+ except InstrumentPrice.DoesNotExist as e:
67
67
  prices = sorted(
68
68
  self.get_prices(from_date=(val_date - BDay(price_date_timedelta)).date(), to_date=val_date),
69
69
  key=lambda x: x["valuation_date"],
@@ -87,7 +87,7 @@ class InstrumentPMSMixin:
87
87
  market_capitalization=p.get("market_capitalization", None),
88
88
  outstanding_shares=p.get("outstanding_shares", None),
89
89
  )
90
- raise ValueError("Not price was found")
90
+ raise ValueError("Not price was found") from e
91
91
 
92
92
  # Instrument Prices Utility Functions
93
93
  @classmethod
@@ -143,6 +143,9 @@ class OptionAggregate(BaseOptionAbstractModel):
143
143
  ),
144
144
  ]
145
145
 
146
+ def __str__(self) -> str:
147
+ return f"{self.instrument} - {self.date} - {self.type}"
148
+
146
149
 
147
150
  class Option(BaseOptionAbstractModel):
148
151
  import_export_handler_class = OptionImportHandler
@@ -224,3 +227,6 @@ class Option(BaseOptionAbstractModel):
224
227
  fields=["type"],
225
228
  ),
226
229
  ]
230
+
231
+ def __str__(self):
232
+ return f"{self.contract_identifier} - {self.date} - {self.type}"
@@ -58,3 +58,6 @@ class Deal(ImportMixin, models.Model):
58
58
  null=True,
59
59
  help_text="List of URLs used to source the valuation for the Media Mentions source type.",
60
60
  )
61
+
62
+ def __str__(self) -> str:
63
+ return f"{self.equity} - {self.date}"
@@ -384,7 +384,6 @@ class TestStatementWithEstimates:
384
384
  "shares_outstanding",
385
385
  "market_capitalization",
386
386
  "close",
387
- "market_capitalization",
388
387
  "net_cash",
389
388
  "period_end_date",
390
389
  "estimate",
@@ -52,7 +52,9 @@ class ClassifiedInstrumentDisplayConfig(DisplayViewConfig):
52
52
  if group := self.view.classification_group:
53
53
  fields = [dp.Field(key="instrument", label="Instrument")]
54
54
  level_representations = group.get_levels_representation()
55
- for key, label in zip(reversed(group.get_fields_names(sep="_")), reversed(level_representations[1:])):
55
+ for key, label in zip(
56
+ reversed(group.get_fields_names(sep="_")), reversed(level_representations[1:]), strict=False
57
+ ):
56
58
  fields.append(
57
59
  dp.Field(key=f"classification_{key}", label=label),
58
60
  )
@@ -31,7 +31,8 @@ class MonthlyPerformancesInstrumentTitleConfig(TitleViewConfig):
31
31
 
32
32
  class InstrumentTitleConfigMixin(TitleViewConfig):
33
33
  def get_list_title(self):
34
- assert self.message, "No message has been set"
34
+ if not self.message:
35
+ raise AssertionError("No message has been set")
35
36
  instrument = Instrument.objects.get(id=self.view.kwargs["instrument_id"])
36
37
  return f"{self.message} {str(instrument)}"
37
38
 
wbfdm/viewsets/esg.py CHANGED
@@ -66,8 +66,8 @@ class InstrumentESGPAIViewSet(InstrumentMixin, ExportPandasAPIViewSet):
66
66
  def get_dataframe(self, request, queryset, **kwargs):
67
67
  df = pd.DataFrame(queryset.dl.esg(values=list(ESG))).reset_index()
68
68
  if not df.empty:
69
- ESG_mapping = ESG.mapping()
69
+ esg_mapping = ESG.mapping()
70
70
  df[["section", "asi", "metric", "factor"]] = pd.DataFrame(
71
- df.factor_code.map(ESG_mapping).tolist(), index=df.index
71
+ df.factor_code.map(esg_mapping).tolist(), index=df.index
72
72
  )
73
73
  return df
@@ -48,8 +48,8 @@ class FinancialMetricAnalysisPandasViewSet(InstrumentMixin, ExportPandasAPIViewS
48
48
  if group_keys := request.GET.get("group_keys"):
49
49
  try:
50
50
  financial = Financial(group_keys.lower())
51
- except ValueError:
52
- raise ParseError()
51
+ except ValueError as e:
52
+ raise ParseError() from e
53
53
  df, self._estimate_mapping, self._columns = financial_metric_estimate_analysis(
54
54
  queryset.first().id, financial
55
55
  )
@@ -43,7 +43,7 @@ class ValuationRatioChartViewSet(InstrumentMixin, viewsets.TimeSeriesChartViewSe
43
43
  fig = go.Figure()
44
44
  colors = iter(px.colors.qualitative.T10)
45
45
 
46
- for ratio, color in zip(ratios, colors):
46
+ for ratio, color in zip(ratios, colors, strict=False):
47
47
  with suppress(AttributeError):
48
48
  series = getattr(df, ratio.value)
49
49
 
@@ -97,10 +97,10 @@ class FinancialSummary(InstrumentMixin, ExportPandasAPIViewSet):
97
97
 
98
98
  # Adjust the columns to be in a different format
99
99
  df.index = df.index.map(lambda x: x.strftime("%b/%y"))
100
- MAX_ROW = 8
101
- if df.shape[0] > MAX_ROW:
100
+ max_row = 8
101
+ if df.shape[0] > max_row:
102
102
  df = df.iloc[1:] # remove first row
103
- df = df.iloc[0 : min([df.shape[0], MAX_ROW])] # keep only 8 row maximum
103
+ df = df.iloc[0 : min([df.shape[0], max_row])] # keep only 8 row maximum
104
104
 
105
105
  self._estimate_columns = df["estimate"].to_dict()
106
106
  df = df.drop(columns=["estimate"], errors="ignore")
@@ -190,7 +190,7 @@ class FinancialSummary(InstrumentMixin, ExportPandasAPIViewSet):
190
190
  return getattr(self, "_estimate_columns", {})
191
191
 
192
192
  @cached_property
193
- def FINANCIAL_VALUES(self) -> list[Financial]:
193
+ def FINANCIAL_VALUES(self) -> list[Financial]: # noqa
194
194
  return [
195
195
  Financial.REVENUE, # SAL
196
196
  Financial.GROSS_PROFIT, # GRI
@@ -216,7 +216,7 @@ class FinancialSummary(InstrumentMixin, ExportPandasAPIViewSet):
216
216
  ]
217
217
 
218
218
  @cached_property
219
- def FIELDS(self) -> list[str]:
219
+ def FIELDS(self) -> list[str]: # noqa
220
220
  return [
221
221
  "revenue",
222
222
  "revenue_growth",
@@ -240,7 +240,7 @@ class FinancialSummary(InstrumentMixin, ExportPandasAPIViewSet):
240
240
  ]
241
241
 
242
242
  @property
243
- def LABELS(self) -> list[str]:
243
+ def LABELS(self) -> list[str]: # noqa
244
244
  currency_key = self.instrument.currency.key if self.instrument.currency else "N.A."
245
245
  return [
246
246
  f"in {currency_key} MN",
@@ -297,7 +297,7 @@ class ValuationRatiosChartView(InstrumentMixin, viewsets.ChartViewSet):
297
297
 
298
298
  fig = go.Figure()
299
299
  dates = []
300
- for index, single_date in enumerate(daterange(date1, date2)):
300
+ for single_date in daterange(date1, date2):
301
301
  ratio_trace = ratios[
302
302
  (ratios["datetxt"] == single_date.strftime("%Y-%m-%d")) & (ratios[z_axis] > 0)
303
303
  ]
@@ -424,16 +424,13 @@ class ValuationRatiosChartView(InstrumentMixin, viewsets.ChartViewSet):
424
424
  if not ranges:
425
425
  fig = make_subplots(specs=[[{"secondary_y": True}]])
426
426
 
427
- for index, plot in enumerate(
428
- [
429
- ("pe", "#ff6361", VariableChoices.PE.chart_label, VariableChoices.PE, False),
430
- ("peg", "#ffa600", VariableChoices.PEG.chart_label, VariableChoices.PEG, True),
431
- ("ps", "#58508d", VariableChoices.PS.chart_label, VariableChoices.PS, False),
432
- ("evebitda", "#003f5c", VariableChoices.EVEBITDA.chart_label, VariableChoices.EVEBITDA, False),
433
- ("pfcf", "#bc5090", VariableChoices.PFCF.chart_label, VariableChoices.PFCF, False),
434
- ],
435
- start=1,
436
- ):
427
+ for plot in [
428
+ ("pe", "#ff6361", VariableChoices.PE.chart_label, VariableChoices.PE, False),
429
+ ("peg", "#ffa600", VariableChoices.PEG.chart_label, VariableChoices.PEG, True),
430
+ ("ps", "#58508d", VariableChoices.PS.chart_label, VariableChoices.PS, False),
431
+ ("evebitda", "#003f5c", VariableChoices.EVEBITDA.chart_label, VariableChoices.EVEBITDA, False),
432
+ ("pfcf", "#bc5090", VariableChoices.PFCF.chart_label, VariableChoices.PFCF, False),
433
+ ]:
437
434
  fig.add_trace(
438
435
  go.Scatter(
439
436
  x=ratios["date"],
@@ -150,7 +150,7 @@ class MarketDataChartViewSet(InstrumentMixin, viewsets.TimeSeriesChartViewSet):
150
150
  )
151
151
  fig.update_xaxes(rangebreaks=[{"pattern": "day of week", "bounds": [6, 1]}])
152
152
 
153
- for i, d in enumerate(fig.data):
153
+ for d in fig.data:
154
154
  with suppress(AttributeError, IndexError, ValueError): # Either Candlestick or OHCL
155
155
  if (y := d.y[-1]) is not None:
156
156
  text_value = (
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.55.9
3
+ Version: 1.55.10rc0
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.*
@@ -2,7 +2,7 @@ wbfdm/__init__.py,sha256=uyfGiipFnhOCQlqywx7wsgp6d-SYnqPqsPQd_xePZl8,23
2
2
  wbfdm/apps.py,sha256=83jiPNQfxUbO7KYKBS5qo5SZNuz25Kmmy_txoVmIKG0,333
3
3
  wbfdm/dynamic_preferences_registry.py,sha256=tE9ZxlQDD7rqKM3GXjxyORQqDjf39GTENkOCZFt8Ixo,1299
4
4
  wbfdm/enums.py,sha256=5AuUouk5uuSNmRc6e-SiBu4FPmHVTN60ol9ftiuVrAc,33041
5
- wbfdm/jinja2.py,sha256=pkIC1U-0rf6vn0DDEUzZ8dPYiTGEPY8LBTRMi9wYiuc,199
5
+ wbfdm/jinja2.py,sha256=E2EsNwt-4IryFH0FYFt1wwH0-gzYHOnsUAH5l7ZPaiE,332
6
6
  wbfdm/preferences.py,sha256=8ghDcaapOMso1kjtNfKbSFykPUTxzqI5R77gM3BgiMs,927
7
7
  wbfdm/signals.py,sha256=PhAsFpQZF1YVe5UpedaRelUD_TVjemqRYm1HzV-bhmY,597
8
8
  wbfdm/tasks.py,sha256=Q7iuSgV8LdPoKxgyMmTg5qukxHrM5XW1k1H_zI958zU,5104
@@ -37,21 +37,21 @@ wbfdm/analysis/technical_analysis/traces.py,sha256=GhyvVzdg1fmG5i1fai2zz9BnJ__5N
37
37
  wbfdm/backends/dto.py,sha256=5IdeGVsrk8trEi9rqtq-zisqiEDE_VLBP8RxlfZZnjk,596
38
38
  wbfdm/contrib/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
39
39
  wbfdm/contrib/dsws/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
40
- wbfdm/contrib/dsws/client.py,sha256=C598w5P85kvX7_gR0Yf-WHRLj77HqztUhofBMl3JWAE,14508
41
- wbfdm/contrib/dsws/dataloaders/market_data.py,sha256=HyTP35Pf4mhhKxEwbyrlJHftTyzNBPUUQeiKArCdhQk,7486
40
+ wbfdm/contrib/dsws/client.py,sha256=vc59bxDU35Z5X76nSqGltIwUF6_ZYMTBLvBQvrJnLEk,14510
41
+ wbfdm/contrib/dsws/dataloaders/market_data.py,sha256=ES8aoREclKx56EcbHzQyLWJSg7cGCRTZrzs42Ka1uLk,7479
42
42
  wbfdm/contrib/internal/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
43
43
  wbfdm/contrib/internal/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
44
- wbfdm/contrib/internal/dataloaders/market_data.py,sha256=QJx4DsGGN3yy0cjIRDEatt_ZHJwJPJNLAJAgRvhzWsQ,4609
44
+ wbfdm/contrib/internal/dataloaders/market_data.py,sha256=OjM4I3c3Ac_ZQn-OsAZQ5FklVHVi3UE6F8EqtUhyFik,4602
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
48
  wbfdm/contrib/metric/dispatch.py,sha256=GdJoYRFiZXWwo3hZeNTDxOUwg7iniv63ddb-A-7Pc6w,1090
49
49
  wbfdm/contrib/metric/dto.py,sha256=vS93tUvfusWdE7gUJsp320GwfwWpb8bGJDdrb1GB6M8,3413
50
- wbfdm/contrib/metric/exceptions.py,sha256=6IuEVde7aOyQaXHE817bCNdUw8LTI3sOSU9LiV3NZbM,200
50
+ wbfdm/contrib/metric/exceptions.py,sha256=NH9xFsrQJJcbt-Yn8GWNsmcRfw1MiSjHLfyii4STTDA,196
51
51
  wbfdm/contrib/metric/factories.py,sha256=b6-3fSERbZGjGw6QC0k3hhSpyQKVy2MJoZzX4y3GPEo,1123
52
52
  wbfdm/contrib/metric/filters.py,sha256=TBFnA2gWuJU_QE5BPvpnBU4SVAsUemM__gSeUvmHQxQ,1690
53
- wbfdm/contrib/metric/models.py,sha256=lI_ZmK7058GT_5ngC45UdXRc7ju-ULbcOtO5w_CMBwU,7002
54
- wbfdm/contrib/metric/orchestrators.py,sha256=YyVVKKm3Sl1zVr2mw9A7LSJs6YnmElbg1yESREF3lFk,3736
53
+ wbfdm/contrib/metric/models.py,sha256=1Tws04Ocd9JDt0Ql7zVDGyRvcL7x6FqDsXsen6ZNkzg,7157
54
+ wbfdm/contrib/metric/orchestrators.py,sha256=CTs2ho2TI4zMAxH1MUM-zK1rBkMo5AjSJCWm0Lv_HyI,3713
55
55
  wbfdm/contrib/metric/registry.py,sha256=SdZff6FIrtdbyAO0X0BpXndJAIhU6VVojNui_MEw7jI,3167
56
56
  wbfdm/contrib/metric/serializers.py,sha256=FqX2pgP4SL1oteVrnAWQezBOJD6JyTidLBEK72GMxrM,1636
57
57
  wbfdm/contrib/metric/signals.py,sha256=qe-CGNZEc7csseiGgNbz8legvz0EM3e31k8kPQ19Zyw,417
@@ -61,9 +61,9 @@ wbfdm/contrib/metric/admin/__init__.py,sha256=FW3qhfmS5tA4RNOv9Zse56dICDG7zgdHgB
61
61
  wbfdm/contrib/metric/admin/instruments.py,sha256=mPwwdwxeuo6nvyJ2_xolVdlpK05KMlzOPLaSlh1PtHE,419
62
62
  wbfdm/contrib/metric/admin/metrics.py,sha256=SJU-5ona3npgRjTgDoHvo9aCztq-VMnIVvvsdk5bWSs,1133
63
63
  wbfdm/contrib/metric/backends/__init__.py,sha256=Bl7bGEYVx38uiN2BS-0pr2WpIkbhUl7yPCEwt1W4tUg,128
64
- wbfdm/contrib/metric/backends/base.py,sha256=TTTcNHjuzGCnzoDBqYZOb-nT7fnuYjjp0D6ACqR5yXk,6765
64
+ wbfdm/contrib/metric/backends/base.py,sha256=LyU02bfcfEVWKMMMhSq4PJqXeOP5nW7NEFJwxb_X4i8,6757
65
65
  wbfdm/contrib/metric/backends/performances.py,sha256=yt9E7A_OEWQBQabf9bqt4Rc3S6oUXbSeM6NR1nYidtg,11642
66
- wbfdm/contrib/metric/backends/statistics.py,sha256=EFbTuJpKxpntkSk4Qo0BSCFFjxBqaQ7ODUkX2pbjDyY,7894
66
+ wbfdm/contrib/metric/backends/statistics.py,sha256=gWvpBqpkLIroBZZ-KceCMWRKRwdJX54OUvtbWLwwmXI,7886
67
67
  wbfdm/contrib/metric/backends/utils.py,sha256=xpsDmoL2Jv9-KTuo-ay65D4m9Kf35jGc9cbeejhFLQU,131
68
68
  wbfdm/contrib/metric/migrations/0001_initial.py,sha256=EwXRJrG7zQYT1bD6jjaf1gZNfpd8f2gzta09GYqukiM,3403
69
69
  wbfdm/contrib/metric/migrations/0002_remove_instrumentmetric_unique_instrument_metric_and_more.py,sha256=xp6MACDohMSs4YfFbprCLa5G7zEuBhfZgpVXyMsZPWI,808
@@ -78,14 +78,14 @@ wbfdm/contrib/metric/tests/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQ
78
78
  wbfdm/contrib/metric/tests/backends/test_performances.py,sha256=SvZerb0y2ifpr2gLKWgXIiV6Shqne6di0ONeC7lFoRs,7896
79
79
  wbfdm/contrib/metric/tests/backends/test_statistics.py,sha256=jtQOslHiCdZcfSJy9NU-xhoz1_BUx6FrdmhPZpJU03I,1921
80
80
  wbfdm/contrib/metric/viewsets/__init__.py,sha256=LTOyOBlhagANq164m7f0oJuz8qCkuq2R8-3lwEZejGs,85
81
- wbfdm/contrib/metric/viewsets/mixins.py,sha256=Z8RJ4QUVjYIki9FdGySXoE29v2wcVTSAdXn1WKzLJ9c,11074
81
+ wbfdm/contrib/metric/viewsets/mixins.py,sha256=Nb9jjxov3Zzz_5UFpY_Sg54bUpL7-iJ-RNpJfzs-82o,11063
82
82
  wbfdm/contrib/metric/viewsets/viewsets.py,sha256=nZBZ9MUfIwmgLSgEtpQdFKdPLYc2vaH-vC8xUplbXQY,1447
83
83
  wbfdm/contrib/metric/viewsets/configs/__init__.py,sha256=jHM2GSU1E9Bu8ZxaKjWweO3mQKuOUmIu1rmYzpccbtU,51
84
84
  wbfdm/contrib/metric/viewsets/configs/display.py,sha256=aZLy3wSCgJlfrS71qxjPfT56u52C5hi9dxqGtGRqCAo,3722
85
85
  wbfdm/contrib/metric/viewsets/configs/menus.py,sha256=GJbDm3p6qeobet09kpQSSuJT3Bs14gYpXxQ1P16b5VM,422
86
86
  wbfdm/contrib/metric/viewsets/configs/utils.py,sha256=SREiSRS4faohL6lVxmeD3zJN8bb-C-PlANUr8AgpIkI,5009
87
87
  wbfdm/contrib/msci/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
88
- wbfdm/contrib/msci/client.py,sha256=XnPATwQKaPc48uvB_BnbxwZuoyQkA1kVNp_-48A0irY,3633
88
+ wbfdm/contrib/msci/client.py,sha256=pqfwFwsRrqd_ywpBP7FJblCEH0QI0fdiUAKbgVCYN7E,3721
89
89
  wbfdm/contrib/msci/sync.py,sha256=StD2TliqxVnZ7YsITjYvdh7E95USS3_P9j8KgRlcDKY,2289
90
90
  wbfdm/contrib/msci/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
91
91
  wbfdm/contrib/msci/dataloaders/esg.py,sha256=VM2zprCC0q0CYSwGPA252czcVx9QpmxYv8FsLTKCGAI,4820
@@ -95,15 +95,15 @@ wbfdm/contrib/msci/tests/conftest.py,sha256=ae6CXNcGkDStajhWAgZWarsA2fh3PCDwOv4W
95
95
  wbfdm/contrib/msci/tests/test_client.py,sha256=cR3uE_Ln21U2p0fpKurKHxzzfmgX3V0h6ldH6lyUaiU,2866
96
96
  wbfdm/contrib/qa/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
97
97
  wbfdm/contrib/qa/apps.py,sha256=NVH9FSbJh3XnddR5coJ51jka7nd9wXjwnCqO7h8gNXA,528
98
- wbfdm/contrib/qa/database_routers.py,sha256=MIfLEqenhcdgKER4Vl2T-gMudN76rmsDoPrAVesl334,950
98
+ wbfdm/contrib/qa/database_routers.py,sha256=PAcgT-oU1W8znNGhqUon2MZS9XXEmhsB-iM5UuD3Hnw,943
99
99
  wbfdm/contrib/qa/tasks.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
100
100
  wbfdm/contrib/qa/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
101
- wbfdm/contrib/qa/dataloaders/adjustments.py,sha256=DQEexOLA7WyBB1dZJHQd-6zbzyEIURgSSgS7bJRvXzQ,2980
102
- wbfdm/contrib/qa/dataloaders/corporate_actions.py,sha256=lWT6klrTXKqxiko2HGrxHH8E2C00FJS-AOX3IhglRrI,2912
101
+ wbfdm/contrib/qa/dataloaders/adjustments.py,sha256=YAYAiCm71QjPt5dZwzezgCQpm5zRWb6EKCzw-0mdHXI,3032
102
+ wbfdm/contrib/qa/dataloaders/corporate_actions.py,sha256=NWk8OCem9niwY5mJCIR11_Wq2gVBbtcrAZedTpzQDYc,2964
103
103
  wbfdm/contrib/qa/dataloaders/financials.py,sha256=xUHpvhUkvmdPL_RyWCrs7XgChgTklX5qemmaXMedgkY,3475
104
104
  wbfdm/contrib/qa/dataloaders/fx_rates.py,sha256=IYkUV8_8Vmvm4_K9xJpz7VaTgjQUz0y4pb3KyaoiqCM,1985
105
- wbfdm/contrib/qa/dataloaders/market_data.py,sha256=-HvEcJr-D37uWomnCegrhjDAsyxJsEKUayUAIlqjm24,8002
106
- wbfdm/contrib/qa/dataloaders/officers.py,sha256=vytlQJJxmn4Y5HfNh5mHJAvuIrrsQSkNO-sONyhxftY,2940
105
+ wbfdm/contrib/qa/dataloaders/market_data.py,sha256=HS_vVGY7FxZOUl9zSIDRDv_h4MvDwhLpH8VS2a1H8Bg,7995
106
+ wbfdm/contrib/qa/dataloaders/officers.py,sha256=s3kW3sgsXuGE0T-TaZwxrF3YrUN-2v-_hN4ugupryic,2944
107
107
  wbfdm/contrib/qa/dataloaders/reporting_dates.py,sha256=q25ccB0pbGfLJLV1A1_AY1XYWJ_Fa10egY09L1J-C5A,2628
108
108
  wbfdm/contrib/qa/dataloaders/statements.py,sha256=6k8dDwJPLY6XE3G5ZA03_4wRvT7XduRsro4lzuAWCvM,10337
109
109
  wbfdm/contrib/qa/dataloaders/utils.py,sha256=E0qav459E7razVOvHKVt9ld_gteJ6eQ2oR4xN-CIOns,2941
@@ -117,10 +117,10 @@ wbfdm/contrib/qa/jinja2/qa/sql/ibes/estimates.sql,sha256=OWgeogSFj7-OdXvJTvNsThN
117
117
  wbfdm/contrib/qa/jinja2/qa/sql/ibes/financials.sql,sha256=i8esPCG_ARiXlfSKajqBRH0jiXT_efOvw3No6zEvwn4,2612
118
118
  wbfdm/contrib/qa/sync/exchanges.py,sha256=XU7dj-rQzMlDku9lnmAACaTRoxx8pFSyr5kCK79cYAc,3124
119
119
  wbfdm/contrib/qa/sync/instruments.py,sha256=8aTQVJ_cw1phe4FWikn79pjCfUijaTcwkdhQCtSXKH0,3156
120
- wbfdm/contrib/qa/sync/utils.py,sha256=Pd7qFTk4X_pC8Q7UMtDy37xoDd6HK7IAY47JDZZwsLM,11940
120
+ wbfdm/contrib/qa/sync/utils.py,sha256=OcukNGyC1S1LZvLt1us5ZejxHcgBRRwLMqs0TWgCztA,11986
121
121
  wbfdm/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
122
122
  wbfdm/dataloaders/cache.py,sha256=K9BeVxT7p-BMvjurINt18bfrUDccp840uIjfDBLJRNk,4841
123
- wbfdm/dataloaders/protocols.py,sha256=LPuf3edDpP_jkqJpuiakbDR-XNgOxxN5JdDAo2f93Ms,3218
123
+ wbfdm/dataloaders/protocols.py,sha256=QLa0y890gwnTeDGTnM58iNEYxugzj9Q9bmIRoapzc_0,3211
124
124
  wbfdm/dataloaders/proxies.py,sha256=1BTY7w3A32axWEOhP9fPZtZHGxHY2GzguteWRSxdhnM,7488
125
125
  wbfdm/dataloaders/types.py,sha256=VUqZgZJZ0mBnFp1T7AaQuWfplMx4AkPA_u52qqo8PQ4,5687
126
126
  wbfdm/factories/__init__.py,sha256=yYxAKBde_ksIr-3g4RjL6d5Wu-nmsuEDdYNyJpgfpQU,660
@@ -134,7 +134,7 @@ wbfdm/factories/instruments_relationships.py,sha256=opGQMM3sHQV5F04nGPCCsRw8ux8v
134
134
  wbfdm/factories/options.py,sha256=nna8LgB_2-XNGm37--Edkdv1oc49oeKtr7f8tcIJPU4,2463
135
135
  wbfdm/figures/__init__.py,sha256=PDF_OWeTocmJIQozLxj_OjDUeUG7OYzcS2DLpe-ECEA,49
136
136
  wbfdm/figures/financials/__init__.py,sha256=6PcHUFJeTEtz9BweUlLANHHOshiNgqX1Wj3KIbZZr90,56
137
- wbfdm/figures/financials/financial_analysis_charts.py,sha256=YJ3JW8WiuP53Ow9YGT_TGpMGQtCyGMzORb5EEn86XSo,18396
137
+ wbfdm/figures/financials/financial_analysis_charts.py,sha256=vkLI_BoNNT3L6KA8fad0iXzNzbc4G4JnqDnrBdcZV4Y,18181
138
138
  wbfdm/figures/financials/financials_charts.py,sha256=tKqBWvkLkDB2GGsPe5g4GR6d3tgnBY2LgRYdXamzBWQ,32717
139
139
  wbfdm/filters/__init__.py,sha256=skWeFdAcemysUeGEvIJ_cIxn-SXuJsUxAroTxq0N8Qo,926
140
140
  wbfdm/filters/classifications.py,sha256=8tKTAPwMzOIXkGWa4ez1layLBAlkDtdG53-75Rg0d9k,3625
@@ -142,7 +142,7 @@ wbfdm/filters/exchanges.py,sha256=84N4AQoCwgdnxTxmhMob5Yndfr5gy_DRQ_-m2ilVLVM,83
142
142
  wbfdm/filters/financials.py,sha256=jdubT5xfFTMcwJSbC_z0WkF8KlO6eAxkaMS7-oQFFp0,2512
143
143
  wbfdm/filters/financials_analysis.py,sha256=aDA33RhKCOmA62GwuAr5xDK71T0racdyDUEaxOBp4Oc,4401
144
144
  wbfdm/filters/instrument_prices.py,sha256=Nt-fInhTM_LRwwmT3U-b0eWoxe-EYEdv77wLEHkZqUc,3710
145
- wbfdm/filters/instruments.py,sha256=sgHchyA0r4qlOPfLqCR3i1_X6nPuIG2hkl8K_buixVQ,7967
145
+ wbfdm/filters/instruments.py,sha256=giL1QaJqGPRV1BBzmsPjxgCOCPuSNT5HkO27Q0kF-i4,7967
146
146
  wbfdm/filters/utils.py,sha256=6IpNoZ_yjRUCdpVXrj3kriTceAX-VGrS5NpZA2NgSmY,1870
147
147
  wbfdm/import_export/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
148
148
  wbfdm/import_export/backends/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -152,7 +152,7 @@ wbfdm/import_export/backends/cbinsights/equities.py,sha256=ucXQmFEffg-JGjvvjuubg
152
152
  wbfdm/import_export/backends/cbinsights/mixin.py,sha256=zbknufq_YKy-itQR_7XYLyU3qEWCptvCt_BCQEBc46M,557
153
153
  wbfdm/import_export/backends/cbinsights/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
154
154
  wbfdm/import_export/backends/cbinsights/utils/classifications.py,sha256=z8toT_3FauBsFZ7h2NBxp-k0Pc-gwrtjBhajCwfmokw,118238
155
- wbfdm/import_export/backends/cbinsights/utils/client.py,sha256=DuaQQRrvZpH1-E2T2qjeLGEGxR-OasxU7CkN9LT7MJA,7393
155
+ wbfdm/import_export/backends/cbinsights/utils/client.py,sha256=GGTG9sKTF0-6ZCwAu_nOOvK10W9zwb3kCUvwzlV3AIk,7392
156
156
  wbfdm/import_export/backends/refinitiv/__init__.py,sha256=sXILMzUD-PIIbmWtotQWvkPxQyRRDANIrj7ma6BKLGI,139
157
157
  wbfdm/import_export/backends/refinitiv/daily_fundamental.py,sha256=0vIAHPIL5lvk9Q2Kt0lUYOfJg5NFBAd5klQM5fB-itk,1459
158
158
  wbfdm/import_export/backends/refinitiv/fiscal_period.py,sha256=CKHX59DUU_TYkCDBsi1u0FLyKFC3RiE7NfkWDq9_wmM,2823
@@ -163,9 +163,9 @@ wbfdm/import_export/backends/refinitiv/instrument.py,sha256=JB39UNkWm4bjRHO0PLqU
163
163
  wbfdm/import_export/backends/refinitiv/instrument_price.py,sha256=cH0GzHAZn5jVXEOfHZOHwCWNULrGPzZV5W_SL_mW0N0,2942
164
164
  wbfdm/import_export/backends/refinitiv/mixin.py,sha256=DlNHOWOO71PgY0umaZd0NbbjsZyi4wa0JVOkWs_9jY8,1128
165
165
  wbfdm/import_export/backends/refinitiv/utils/__init__.py,sha256=Rz38xsLAHEyEwIuJksejYExEznlPJb9tRzwJ7JG9L1s,35
166
- wbfdm/import_export/backends/refinitiv/utils/controller.py,sha256=yG8V4C2TGhJdKwTeuMfaG1lzJ3MjNaV632KTe0nuym8,7348
166
+ wbfdm/import_export/backends/refinitiv/utils/controller.py,sha256=SCmVSyHo-NHDL1mzneS_Gl4JYrvEUhahOQfBmNSKnI8,7354
167
167
  wbfdm/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
168
- wbfdm/import_export/handlers/instrument.py,sha256=R1g8OSAspezYRW40KY_AIrMPAwKNO0tjjsXGj6UFjkM,12664
168
+ wbfdm/import_export/handlers/instrument.py,sha256=bAnar0Row9Km5NGRV0eddQ2cWvzeQsMHHSWjDqYAufc,12676
169
169
  wbfdm/import_export/handlers/instrument_list.py,sha256=mZRfpJFi6BhhrjH2qaFEPqqCK2ybg-DQm43Uck7G9_w,4864
170
170
  wbfdm/import_export/handlers/instrument_price.py,sha256=RbNTo78zZuttzlVFKxJrHcW7DRfcsta7QDEI8OiiDrA,3498
171
171
  wbfdm/import_export/handlers/option.py,sha256=MPzluMPJ3Yu7Ahmw9BA7-ssAbvPDdyca_rC-YVhU8bY,2378
@@ -173,7 +173,7 @@ wbfdm/import_export/handlers/private_equities.py,sha256=tOx4lgQOB68lYTi3UzIPzDQs
173
173
  wbfdm/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
174
174
  wbfdm/import_export/parsers/cbinsights/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
175
175
  wbfdm/import_export/parsers/cbinsights/deals.py,sha256=aHzFxF1D397xzAp3x3QpjV1comROIrbdfj3BGEI4RWI,1358
176
- wbfdm/import_export/parsers/cbinsights/equities.py,sha256=W-hXVM-iNdSxkgdlsVyy0XfFxBP7Xac_4igXK2xD-d8,2443
176
+ wbfdm/import_export/parsers/cbinsights/equities.py,sha256=0ohIXnZXbTZ6_qI_NVIsFw1M1UXznSNgaqOBzZDfh98,2437
177
177
  wbfdm/import_export/parsers/cbinsights/fundamentals.py,sha256=FgG8yFwRBL4_Jpp2-unFB-OosgYcMlR7wrzJRDUCLrc,2273
178
178
  wbfdm/import_export/parsers/refinitiv/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
179
179
  wbfdm/import_export/parsers/refinitiv/daily_fundamental.py,sha256=YJIRudY0KbiAMUYNx20Vpfnuc5EapDTxKS3gTuKlAHA,279
@@ -229,22 +229,22 @@ wbfdm/migrations/0032_alter_instrumentprice_outstanding_shares.py,sha256=uRgkf6j
229
229
  wbfdm/migrations/0033_alter_controversy_review.py,sha256=A9npErIpE0QUEjqIqpxmO5GMi0VA2Id8whn1nswWXpU,445
230
230
  wbfdm/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
231
231
  wbfdm/models/__init__.py,sha256=PWsLtlKJFDYycCohPbjsRLeWi1xaxEkZbaoUKo0yOBU,96
232
- wbfdm/models/fields.py,sha256=eQ_6EnDBMy0U7WzE2DsdXIXOJH5dFiIN2VbO2Svw4R0,3942
233
- wbfdm/models/fk_fields.py,sha256=XuOGN0Fnq4Hld9IcBKSpeSSrfAQD91B-HNYNVd69fAk,15041
232
+ wbfdm/models/fields.py,sha256=drOOKhF3dMu4nVPL8Q5IM3xrw4heX6vb0hD3DQGRS3I,3956
233
+ wbfdm/models/fk_fields.py,sha256=jTgvptVlFIrUbvHZt0WwYchy5kpqBsVUAeXGayQFIQE,15065
234
234
  wbfdm/models/indicators.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
235
235
  wbfdm/models/esg/__init__.py,sha256=FEYbRFSdfoWRsfKVxM-h6TLobj5P8bYQlZPG1iD9RMQ,29
236
- wbfdm/models/esg/controversies.py,sha256=ioAlytF3H_IKGtYfkDWyo7Xj6S4z7vvuyd5rgOed50s,2632
236
+ wbfdm/models/esg/controversies.py,sha256=jp-DxxTW7uwU7hmUYjwj9qorGabJheufiSOh08YqR_k,2717
237
237
  wbfdm/models/exchanges/__init__.py,sha256=sScz2KX9fxhhmi4CEUssC8HCL4ENvrIqSSwk0_J7v-g,32
238
238
  wbfdm/models/exchanges/exchanges.py,sha256=RmM5shyyuxEGN2Y3JmeSWyU-SbpVARrvVFW72HtHwfg,7502
239
239
  wbfdm/models/instruments/__init__.py,sha256=OvEkECJaCubBQC7B9yUrx15V982labvegeGXyEASVno,636
240
240
  wbfdm/models/instruments/classifications.py,sha256=EeZ_P8f1F1NfjUmLf9fDMF0iPM73qxQoArUfvjuCwHg,10906
241
241
  wbfdm/models/instruments/instrument_lists.py,sha256=GxfFyfYxEcJS36LAarHja49TOM8ffhIivpZX2-tPtZg,4234
242
242
  wbfdm/models/instruments/instrument_prices.py,sha256=K7oMIz76WSrLmpNwcabThvtrP6WpBZZnrE9CHB5-UPQ,22345
243
- wbfdm/models/instruments/instrument_relationships.py,sha256=zpCZCnt5CqIg5bd6le_6TyirsSwGV2NaqTVKw3bd5vM,10660
243
+ wbfdm/models/instruments/instrument_relationships.py,sha256=orBZY46jDvPfgkXakBRiByib5M_Iyeyelzg3CZWozSM,10777
244
244
  wbfdm/models/instruments/instrument_requests.py,sha256=XbpofRS8WHadHlTFjvXJyd0o7K9r2pzJtnpjVQZOLdI,7832
245
- wbfdm/models/instruments/instruments.py,sha256=Tn9vIu0kys8pVVBiO58Z0Z5fAv0KWzkp4L4kjm7oh3c,44485
246
- wbfdm/models/instruments/options.py,sha256=hFprq7B5t4ctz8nVqzFsBEzftq_KDUSsSXl1zJyh7tE,7094
247
- wbfdm/models/instruments/private_equities.py,sha256=uzwZi8IkmCKAHVTxnuFya9tehx7kh57sTlTEi1ieDaM,2198
245
+ wbfdm/models/instruments/instruments.py,sha256=NIAZLH0ArrlkJ2t9cf1J2nA3TPwcILQwIF5AzadQycs,44533
246
+ wbfdm/models/instruments/options.py,sha256=AW6mwvVL8IN9K6dEApJsGgDz7T8SBIxQrJvQZ804oas,7286
247
+ wbfdm/models/instruments/private_equities.py,sha256=-MYXLLvcOO3JVvSpT2H_HxbQzZasipPUQyUgwoaW5xw,2275
248
248
  wbfdm/models/instruments/querysets.py,sha256=7r3pXNlpROkYgKc6gQH07RNeWX6jGeBAPUabUevE6Jo,11587
249
249
  wbfdm/models/instruments/utils.py,sha256=88jnWINSSC0OwH-mCEOPLZXuhBCtEsxBpSaZ38GteaE,1365
250
250
  wbfdm/models/instruments/llm/__init__.py,sha256=dSmxRmEWb0A4O_lUoWuRKt2mBtUuLCTPVVJqGyi_n40,52
@@ -252,7 +252,7 @@ wbfdm/models/instruments/llm/create_instrument_news_relationships.py,sha256=f9MT
252
252
  wbfdm/models/instruments/mixin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
253
253
  wbfdm/models/instruments/mixin/financials_computed.py,sha256=E87I7O2WQgjY3zM3so4dzfExBzVtKTkTqnRjPwLHbyM,34920
254
254
  wbfdm/models/instruments/mixin/financials_serializer_fields.py,sha256=-OkpcUt1rZmB3nUcO2vckpJdVm8IxRqkPDEgcPqqoRU,68886
255
- wbfdm/models/instruments/mixin/instruments.py,sha256=fpt03q_Sq35R_ZmJpdcw81aA7wTocnp7ANE1jb-_cfI,10022
255
+ wbfdm/models/instruments/mixin/instruments.py,sha256=Em9Jvm8jMLu65vvi9d8rO4mCtNbAE3-HSvJUOpZimGQ,10034
256
256
  wbfdm/serializers/__init__.py,sha256=AXb03RKHo6B0ts_IQOvx89n9wKG8pxiumYv9cr4EhvA,197
257
257
  wbfdm/serializers/esg.py,sha256=epoX8cjkPuVv45aW-Jf85-rSO_ZrSnXcTxMcadKdC-I,1086
258
258
  wbfdm/serializers/exchanges.py,sha256=wYvy0XBS9tRFHqin23gABQ_pj3Rmsx1B075SZ5GqwDo,1211
@@ -275,7 +275,7 @@ wbfdm/tests/tests.py,sha256=i0CntYKvaHWmdJe34sZMLeKRiHL4uRfhdM30_4gp08Q,253
275
275
  wbfdm/tests/analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
276
276
  wbfdm/tests/analysis/test_esg.py,sha256=dE5IIzEAr6C2iwH1AreDvCjVkSyC-GOg5x2pvOeIdhM,7229
277
277
  wbfdm/tests/analysis/financial_analysis/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
278
- wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py,sha256=1DwOwwLqcnDFvduQy7jOrCnJZuqTqTPyQo1di3Y0-LU,13665
278
+ wbfdm/tests/analysis/financial_analysis/test_statement_with_estimates.py,sha256=-m-2YbCgn4CTPnJw7r_HRuBlYRLZFBBBgiBYgl8ik4Y,13628
279
279
  wbfdm/tests/analysis/financial_analysis/test_utils.py,sha256=O1_L8oj1OSTEG-qetlFMkbOriSG4_lMqW-RFEiwi4lo,12475
280
280
  wbfdm/tests/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
281
281
  wbfdm/tests/dataloaders/test_cache.py,sha256=y1qHndDWO50ULE-VzZa1DIm97v1sRlKGItuzCS27_L8,2473
@@ -289,9 +289,9 @@ wbfdm/tests/models/test_merge.py,sha256=tXD5xIxZyZtXpm9WIQ4Yc8TQwsUnkxkKIvMNwaHO
289
289
  wbfdm/tests/models/test_options.py,sha256=DoEAHhNQE4kucpBRRm2S05ozabkERz-I4mUolsE2Qi8,2269
290
290
  wbfdm/tests/models/test_queryset.py,sha256=bVNDU498vbh7ind9NbOzsI8TMv3Qe47fSMPzd58K0R4,4113
291
291
  wbfdm/viewsets/__init__.py,sha256=ZM29X0-5AkSH2rzF_gKUI4FoaEWCcMTXPjruJ4Gi_x8,383
292
- wbfdm/viewsets/esg.py,sha256=WrJaFxVUUFprGviF6GDMWuG3HQTXmyD-Ly1FRh7b11o,2867
292
+ wbfdm/viewsets/esg.py,sha256=Vjqp4rCpJTLOXh7-Wcxgdz4NuhMMzyCQVdkJprQfBmw,2867
293
293
  wbfdm/viewsets/exchanges.py,sha256=OAYOIKVVEihReeks2Pq6qcAafOxY4UL8l4TFzzr7Ckc,1785
294
- wbfdm/viewsets/market_data.py,sha256=uiMedhDVX6FIWFYMOOLjYyAxttRD3I2DIWaHnfHX2FE,6738
294
+ wbfdm/viewsets/market_data.py,sha256=ZkvQVQ_hh5aMTruGFRYjjy2RIcbOQAKDKNS73uPH3Ds,6724
295
295
  wbfdm/viewsets/mixins.py,sha256=KLL89AXC8Fdex6uCTBNllbIztg6vdWsGCVEydN2zSiI,325
296
296
  wbfdm/viewsets/officers.py,sha256=_NktFvGV79v3AAm7gOFmGdpep-Vr5TMe2MvIoVtg3Fs,1059
297
297
  wbfdm/viewsets/prices.py,sha256=cE0vRs8UEML7OjgwMPfq0ns2OHSokbLPZKFjni-9kl4,2400
@@ -310,7 +310,7 @@ wbfdm/viewsets/configs/display/instrument_lists.py,sha256=UF_M41sBDDxGLDlKxLdAHq
310
310
  wbfdm/viewsets/configs/display/instrument_prices.py,sha256=CdZg-Fwd__DP0Ym8TBsupbVZzhoMbNfOJQKCmgKvwCc,4908
311
311
  wbfdm/viewsets/configs/display/instrument_requests.py,sha256=CarX1MGe64roHZETm2N4HsEMssHVI5mWw2xTUBjgi-k,5129
312
312
  wbfdm/viewsets/configs/display/instruments.py,sha256=fG7vGnyznAi6J4SrS4FXyDjBgSCNOEaFy-M92oAmO9Y,17417
313
- wbfdm/viewsets/configs/display/instruments_relationships.py,sha256=BLAl2ZciWR5Waf3qPd1QQwdiupgIf_wGK6rmYe9byuY,2480
313
+ wbfdm/viewsets/configs/display/instruments_relationships.py,sha256=c47-iz4hFvKl4luRgCZyjtefIs4VJspTIAyw6PdMIvI,2524
314
314
  wbfdm/viewsets/configs/display/monthly_performances.py,sha256=ESsGTLhPmmXz3YjEWNjwaOjA1RNzVDKtJt3JILL2MMc,2973
315
315
  wbfdm/viewsets/configs/display/officers.py,sha256=qUwN9HPSSlT85aUSFNY-30550P35j3RZCYqRPj_rFAs,654
316
316
  wbfdm/viewsets/configs/display/prices.py,sha256=09PVAbrgxE7vkZjYaloNqi2Jot2iyRjHILcJPsVj5gI,890
@@ -339,7 +339,7 @@ wbfdm/viewsets/configs/titles/esg.py,sha256=a0BMJtSiumxz11Cswl5US87uH93pvzmbHmeH
339
339
  wbfdm/viewsets/configs/titles/exchanges.py,sha256=W9HKCsmZPV8ck2BYUJi-uY5XtaLg-gT8LfoABAJiT8g,286
340
340
  wbfdm/viewsets/configs/titles/financial_ratio_analysis.py,sha256=k1t9s6QjF8mE9KoObP9ZEsYIG5NLQiCzrjXqqqbY0s4,221
341
341
  wbfdm/viewsets/configs/titles/financials_analysis.py,sha256=jReN2cagd3hNv11_aNw_qYC8eDthD_CdF8oj3Ps_5o4,2070
342
- wbfdm/viewsets/configs/titles/instrument_prices.py,sha256=RrLm1GQB9gVz_hcB2LrU8bSdZiBVIWcfzePpvc7fAr0,1700
342
+ wbfdm/viewsets/configs/titles/instrument_prices.py,sha256=l1OnnGySNNgscWPbMIoe2VUZxj51LXs1jV_VK7b5QMQ,1734
343
343
  wbfdm/viewsets/configs/titles/instrument_requests.py,sha256=v7oaokbww-dRFuhoC7hv-Y2kSpecX7BYFKZ3cQatHD0,479
344
344
  wbfdm/viewsets/configs/titles/instruments.py,sha256=-OfXcEgwoST1_pLCBNWag6Swx0ZM23EHVHXAEPPGeSA,886
345
345
  wbfdm/viewsets/configs/titles/instruments_relationships.py,sha256=vpgQrXekD64P422i2lc_PXzuuZtjThSgt18BD0fhRLY,609
@@ -347,13 +347,13 @@ wbfdm/viewsets/configs/titles/market_data.py,sha256=L1ANMper59jNDEVL8HU4UnM_Iu4c
347
347
  wbfdm/viewsets/configs/titles/prices.py,sha256=O43pAxiZsfRl6CwJX1hX6zABWKD0a9nQLSaywtNZEBM,382
348
348
  wbfdm/viewsets/configs/titles/statement_with_estimates.py,sha256=ZL4K0hOM0dVBplu76toF4-U3VXBS31gyV3_eTGQYHjE,407
349
349
  wbfdm/viewsets/financial_analysis/__init__.py,sha256=cTTcvGnhz2Ep9RpkyUyTOpjTXJz7BWt1AGAMjiIY9C8,263
350
- wbfdm/viewsets/financial_analysis/financial_metric_analysis.py,sha256=IDSmnCiQzcqcpNezsga9j9wcujoWe5Lk74Irt7oDOwA,3316
351
- wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py,sha256=K1qcUX8pv_AZyZLbkdv_5ETyaSTp2EoqOY2sJGCAurY,3108
352
- wbfdm/viewsets/financial_analysis/financial_summary.py,sha256=G45qXpGtXe2vi9zdlb9UAkO5BTsKjf2sF4JqcW61EBM,9221
350
+ wbfdm/viewsets/financial_analysis/financial_metric_analysis.py,sha256=ISG53diS2LcjxH7Fex1wsMGHTHoRdLDHwLDKn3qA4UE,3328
351
+ wbfdm/viewsets/financial_analysis/financial_ratio_analysis.py,sha256=szq78oFKCxVjUkCVzsU7Ditq0qQlwcrnvnXVIao18Ic,3122
352
+ wbfdm/viewsets/financial_analysis/financial_summary.py,sha256=MWz5Nip5ePKkHX3W7bYJRvzY_hCvSsHmKd0gvvPtXL8,9245
353
353
  wbfdm/viewsets/financial_analysis/statement_with_estimates.py,sha256=wnBxS3b0Hsl2IfNU7WCOcRndNW8JckWDmGrgHrBmhWE,6216
354
354
  wbfdm/viewsets/instruments/__init__.py,sha256=uydDdU6oZ6W2lgFkr3-cU7WZU7TeokXAA1J0xEgiLD0,2826
355
355
  wbfdm/viewsets/instruments/classifications.py,sha256=CMRTeI6hUClXzZUr7PeRWBXhT9fMiPiu-FvNP_jUQkM,11947
356
- wbfdm/viewsets/instruments/financials_analysis.py,sha256=xcVKR2H0P07NIyxFwPPPmVi3hWA0ZrfxOWMO8KjG6Ms,29202
356
+ wbfdm/viewsets/instruments/financials_analysis.py,sha256=eWJI1oKxFFHw0X5THFL6IemhcHZAauyNc5yD4aQpO58,29074
357
357
  wbfdm/viewsets/instruments/instrument_lists.py,sha256=hwwHDNpHjjffxw08N_1LtkL5Fdi8c1Om-PLz6pTu4Ok,2878
358
358
  wbfdm/viewsets/instruments/instrument_prices.py,sha256=9mdNPU1D6ZFS5Bf0U1d3c6ZlYSCjrNMWv6Vhas3D8Ns,24075
359
359
  wbfdm/viewsets/instruments/instrument_requests.py,sha256=mmaARNl6ymDdlcLzcu16vVfFsunhtJkMw2r2NBfUp9U,1839
@@ -364,6 +364,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
364
364
  wbfdm/viewsets/statements/statements.py,sha256=gA6RCI8-B__JwjEb6OZxpn8Y-9aF-YQ3HIQ7e1vfJMw,4304
365
365
  wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
366
366
  wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=O1j8CGfOranL74LqVvcf7jERaDIboEJZiBf_AbbVDQ8,3974
367
- wbfdm-1.55.9.dist-info/METADATA,sha256=E3b45elSBbWIPyhnD0hVdM1Si0l7QDhYEiMXdHX4A2E,768
368
- wbfdm-1.55.9.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
369
- wbfdm-1.55.9.dist-info/RECORD,,
367
+ wbfdm-1.55.10rc0.dist-info/METADATA,sha256=0uOFbPkv-nVIC7jk_YD3QoHVF_S1cE3Koi2unpPWiqA,772
368
+ wbfdm-1.55.10rc0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
369
+ wbfdm-1.55.10rc0.dist-info/RECORD,,