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

@@ -239,6 +239,9 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
239
239
  ) -> Iterator[StatementDataDict]:
240
240
  lookup = {k: v for k, v in self.entities.values_list("dl_parameters__statements__parameters", "id")}
241
241
  sql = reported_sql if data_type is DataType.REPORTED else standardized_sql
242
+ if financials is None:
243
+ financials = []
244
+ external_codes = [RKDFinancial[fin.name].value for fin in financials if fin in RKDFinancial]
242
245
  query, bind_params = JinjaSql(param_style="format").prepare_query(
243
246
  sql,
244
247
  {
@@ -249,7 +252,7 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
249
252
  "from_date": from_date,
250
253
  "to_date": to_date,
251
254
  "period_type": period_type.value,
252
- "external_codes": [RKDFinancial[fin.name].value for fin in financials or []],
255
+ "external_codes": external_codes,
253
256
  },
254
257
  )
255
258
  with connections["qa"].cursor() as cursor:
@@ -263,6 +266,10 @@ class RKDStatementsDataloader(StatementsProtocol, Dataloader):
263
266
  # sometime we get None for the year. We default to the period end date year then
264
267
  row["year"] = int(row["year"] or row["period_end_date"].year)
265
268
  row["instrument_id"] = lookup[row["external_identifier"]]
269
+
266
270
  if financials:
267
- row["financial"] = Financial[RKDFinancial(row["external_code"]).name].value
271
+ try:
272
+ row["financial"] = Financial[RKDFinancial(row["external_code"]).name].value
273
+ except (ValueError, KeyError):
274
+ continue
268
275
  yield row
@@ -21,7 +21,7 @@ class InstrumentFactory(factory.django.DjangoModelFactory):
21
21
  instrument_type = factory.SubFactory(InstrumentTypeFactory)
22
22
  inception_date = factory.Faker("past_date")
23
23
  delisted_date = None
24
- currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyFactory")
24
+ currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyUSDFactory")
25
25
  country = factory.SubFactory("wbcore.contrib.geography.factories.CountryFactory")
26
26
  exchange = factory.SubFactory("wbfdm.factories.exchanges.ExchangeFactory")
27
27
 
@@ -54,7 +54,7 @@ class InstrumentFactory(factory.django.DjangoModelFactory):
54
54
 
55
55
  class CashFactory(factory.django.DjangoModelFactory):
56
56
  is_cash = True
57
- currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyFactory")
57
+ currency = factory.SubFactory("wbcore.contrib.currency.factories.CurrencyUSDFactory")
58
58
  name = factory.LazyAttribute(lambda o: o.currency.title)
59
59
  instrument_type = factory.LazyAttribute(
60
60
  lambda o: InstrumentType.objects.get_or_create(key="cash", defaults={"name": "Cash", "short_name": "Cash"})[0]
@@ -26,7 +26,7 @@ class OptionAggregateImportHandler(ImportExportHandler):
26
26
 
27
27
  def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
28
28
  with suppress(ObjectDoesNotExist):
29
- return self.model.objects.filter(instrument=data["instrument"], date=data["date"], type=data["type"])
29
+ return self.model.objects.get(instrument=data["instrument"], date=data["date"], type=data["type"])
30
30
 
31
31
 
32
32
  class OptionImportHandler(ImportExportHandler):
@@ -46,7 +46,7 @@ class OptionImportHandler(ImportExportHandler):
46
46
 
47
47
  def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
48
48
  with suppress(ObjectDoesNotExist):
49
- return self.model.objects.filter(
49
+ return self.model.objects.get(
50
50
  instrument=data["instrument"],
51
51
  contract_identifier=data["contract_identifier"],
52
52
  date=data["date"],
@@ -0,0 +1,18 @@
1
+ # Generated by Django 5.0.14 on 2025-08-27 07:59
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('wbfdm', '0031_exchange_apply_round_lot_size_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AlterField(
14
+ model_name='instrumentprice',
15
+ name='outstanding_shares',
16
+ field=models.DecimalField(blank=True, decimal_places=4, help_text='The amount of outstanding share for this instrument', max_digits=16, null=True, verbose_name='Outstanding Shares'),
17
+ ),
18
+ ]
@@ -195,9 +195,11 @@ class InstrumentPrice(
195
195
  verbose_name="Value (Gross)",
196
196
  ) # TODO: I think we need to remove this field that is not really used here.
197
197
 
198
- outstanding_shares = DynamicDecimalField(
198
+ outstanding_shares = models.DecimalField(
199
199
  decimal_places=4,
200
200
  max_digits=16,
201
+ blank=True,
202
+ null=True,
201
203
  verbose_name="Outstanding Shares",
202
204
  help_text="The amount of outstanding share for this instrument",
203
205
  )
@@ -697,10 +697,6 @@ import pandas as pd
697
697
  #
698
698
  #
699
699
  class InstrumentPriceComputedMixin:
700
- def _compute_outstanding_shares(self):
701
- if self.outstanding_shares is None and (previous_price := self.previous_price):
702
- return previous_price.outstanding_shares
703
-
704
700
  def _compute_outstanding_shares_consolidated(self):
705
701
  if self.outstanding_shares_consolidated is None and self.outstanding_shares is not None:
706
702
  return self.outstanding_shares
@@ -200,7 +200,7 @@ class InstrumentQuerySet(QuerySet):
200
200
  padded_from_date = from_date - timedelta(days=15)
201
201
  padded_to_date = to_date + timedelta(days=3)
202
202
  logger.info(
203
- f"Loading returns from {from_date:%Y-%m-%d} (padded to {padded_from_date:%Y-%m-%d}) to {to_date:%Y-%m-%d} (padded to {padded_to_date:%Y-%m-%d})"
203
+ f"Loading returns from {from_date:%Y-%m-%d} (padded to {padded_from_date:%Y-%m-%d}) to {to_date:%Y-%m-%d} (padded to {padded_to_date:%Y-%m-%d}) for {self.count()} instruments"
204
204
  )
205
205
 
206
206
  if use_dl:
@@ -248,13 +248,12 @@ class InstrumentQuerySet(QuerySet):
248
248
  (df.index <= pd.Timestamp(to_date)) & (df.index >= pd.Timestamp(from_date))
249
249
  ] # ensure the returned df corresponds to requested date range
250
250
  prices_df = df["close"]
251
-
252
251
  if "fx_rate" in df.columns:
253
252
  fx_rate_df = df["fx_rate"].fillna(1.0)
254
253
  else:
255
254
  fx_rate_df = pd.DataFrame(np.ones(prices_df.shape), index=prices_df.index, columns=prices_df.columns)
256
255
  returns = prices_to_returns(fx_rate_df * prices_df, drop_inceptions_nan=False, fill_nan=True)
257
- return {ts.date(): row for ts, row in prices_df.to_dict("index").items()}, returns.replace(
258
- [np.inf, -np.inf, np.nan], 0
259
- )
256
+ return {
257
+ ts.date(): row for ts, row in prices_df.replace([np.nan], None).to_dict("index").items()
258
+ }, returns.replace([np.inf, -np.inf, np.nan], 0)
260
259
  return {}, pd.DataFrame()
@@ -1,10 +1,8 @@
1
1
  from datetime import date
2
- from decimal import Decimal
3
2
 
4
3
  import pandas as pd
5
4
  import pytest
6
5
  from faker import Faker
7
- from pandas.tseries.offsets import BDay
8
6
  from wbcore.models import DynamicDecimalField, DynamicFloatField
9
7
 
10
8
  from wbfdm.models import Instrument, InstrumentPrice, RelatedInstrumentThroughModel
@@ -168,18 +166,6 @@ class TestInstrumentPriceModel:
168
166
  assert isinstance(instrument_price._meta.get_field("gross_value"), DynamicDecimalField)
169
167
  assert instrument_price.gross_value == instrument_price.net_value
170
168
 
171
- @pytest.mark.parametrize("instrument_price__outstanding_shares", [Decimal(10)])
172
- def test_compute_outstanding_shares(self, instrument_price, instrument_price_factory):
173
- next_price = instrument_price_factory.create(
174
- instrument=instrument_price.instrument,
175
- date=instrument_price.date + BDay(1),
176
- outstanding_shares=None,
177
- calculated=instrument_price.calculated,
178
- )
179
- assert hasattr(instrument_price, "_compute_outstanding_shares")
180
- assert isinstance(instrument_price._meta.get_field("outstanding_shares"), DynamicDecimalField)
181
- assert next_price.outstanding_shares == instrument_price.outstanding_shares
182
-
183
169
  @pytest.mark.parametrize("instrument_price__volume_50d", [None])
184
170
  def test_compute_volume_50d(self, instrument_price, instrument_price_factory):
185
171
  assert hasattr(instrument_price, "_compute_volume_50d")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbfdm
3
- Version: 1.54.23
3
+ Version: 1.55.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.*
@@ -103,7 +103,7 @@ wbfdm/contrib/qa/dataloaders/financials.py,sha256=xUHpvhUkvmdPL_RyWCrs7XgChgTklX
103
103
  wbfdm/contrib/qa/dataloaders/market_data.py,sha256=_B_QgoA_TAUK3KkHYsi1FM-K265wqiDCU-3ztA4mpiM,8374
104
104
  wbfdm/contrib/qa/dataloaders/officers.py,sha256=vytlQJJxmn4Y5HfNh5mHJAvuIrrsQSkNO-sONyhxftY,2940
105
105
  wbfdm/contrib/qa/dataloaders/reporting_dates.py,sha256=q25ccB0pbGfLJLV1A1_AY1XYWJ_Fa10egY09L1J-C5A,2628
106
- wbfdm/contrib/qa/dataloaders/statements.py,sha256=hC6YErJcvBTmaAmzscgeC4sBK3lYE2U5eIKRIE9b_cs,10094
106
+ wbfdm/contrib/qa/dataloaders/statements.py,sha256=nLD4SQYb2g4Sm04NiIepNwJ6Q28m2_nzzdRX-zO1li8,10324
107
107
  wbfdm/contrib/qa/dataloaders/utils.py,sha256=E0qav459E7razVOvHKVt9ld_gteJ6eQ2oR4xN-CIOns,2941
108
108
  wbfdm/contrib/qa/jinja2/qa/sql/companies.sql,sha256=RzTkfVjBVOgyirgKxp2rnJdjsKl8d3YM-d2qdjHx9cw,3801
109
109
  wbfdm/contrib/qa/jinja2/qa/sql/instruments.sql,sha256=7p31aJDtKusfSzhrjyUo8FlmbPXNyffWtNclm8DZkFM,3863
@@ -127,7 +127,7 @@ wbfdm/factories/controversies.py,sha256=GhuoEms1O7DIMVNAIbFEzD9DRv8j1MXIv0u1JK6P
127
127
  wbfdm/factories/exchanges.py,sha256=heJHQE59dCDFeDuScJJti4C_SsMsz3O0kmczpGYVNlQ,831
128
128
  wbfdm/factories/instrument_list.py,sha256=ypnrTLCl0XRfGj6y-3XJSQ2Wl5TULxZU0I3nF6svH3Y,743
129
129
  wbfdm/factories/instrument_prices.py,sha256=EjRFbMjP3pLrxoNsNqNo37FGjayIiV99bkQPVgZLj4I,3623
130
- wbfdm/factories/instruments.py,sha256=A4BP06Ma66uG6klsfkMjGfiP9WYh85OZPTRiXFxwUM0,2552
130
+ wbfdm/factories/instruments.py,sha256=sJqHNA6Cs-NNm9RQrCimUVjKTrJS-ajjpTP4taPRTqA,2558
131
131
  wbfdm/factories/instruments_relationships.py,sha256=opGQMM3sHQV5F04nGPCCsRw8ux8vSQ78tHNJjIDPyUE,1138
132
132
  wbfdm/factories/options.py,sha256=nna8LgB_2-XNGm37--Edkdv1oc49oeKtr7f8tcIJPU4,2463
133
133
  wbfdm/figures/__init__.py,sha256=PDF_OWeTocmJIQozLxj_OjDUeUG7OYzcS2DLpe-ECEA,49
@@ -166,7 +166,7 @@ wbfdm/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
166
166
  wbfdm/import_export/handlers/instrument.py,sha256=ZtXwqoCh--_Bgn7mB_A7U2w1S6HfMr9MqFCc4VMw7ls,12071
167
167
  wbfdm/import_export/handlers/instrument_list.py,sha256=mZRfpJFi6BhhrjH2qaFEPqqCK2ybg-DQm43Uck7G9_w,4864
168
168
  wbfdm/import_export/handlers/instrument_price.py,sha256=RbNTo78zZuttzlVFKxJrHcW7DRfcsta7QDEI8OiiDrA,3498
169
- wbfdm/import_export/handlers/option.py,sha256=DtqqdOMEA-u3jWVjmxRPKJ8miENj_t1k2DzAZEoOtXU,2384
169
+ wbfdm/import_export/handlers/option.py,sha256=MPzluMPJ3Yu7Ahmw9BA7-ssAbvPDdyca_rC-YVhU8bY,2378
170
170
  wbfdm/import_export/handlers/private_equities.py,sha256=tOx4lgQOB68lYTi3UzIPzDQsfay5k2pu5qv8jGzG030,1957
171
171
  wbfdm/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
172
172
  wbfdm/import_export/parsers/cbinsights/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -223,6 +223,7 @@ wbfdm/migrations/0028_instrumentprice_annualized_daily_volatility.py,sha256=pO5M
223
223
  wbfdm/migrations/0029_alter_instrumentprice_volume.py,sha256=0UFUwEaBcqiWjKw6un1gf8sluKCRRh9snDM4z4THDw8,510
224
224
  wbfdm/migrations/0030_alter_relatedinstrumentthroughmodel_related_type.py,sha256=10-89NB7-T7t3xFPpd4fYQkKejNR36UewIhe5_20QCo,565
225
225
  wbfdm/migrations/0031_exchange_apply_round_lot_size_and_more.py,sha256=MqcHxgJIt67BEuEYK8vnJHhx_cGFw9Ca9Az2EvsDy1o,863
226
+ wbfdm/migrations/0032_alter_instrumentprice_outstanding_shares.py,sha256=uRgkf6j97kNaXAo0-_V3XzHNE59hvxSruJB18g53YwU,570
226
227
  wbfdm/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
227
228
  wbfdm/models/__init__.py,sha256=PWsLtlKJFDYycCohPbjsRLeWi1xaxEkZbaoUKo0yOBU,96
228
229
  wbfdm/models/fields.py,sha256=eQ_6EnDBMy0U7WzE2DsdXIXOJH5dFiIN2VbO2Svw4R0,3942
@@ -235,18 +236,18 @@ wbfdm/models/exchanges/exchanges.py,sha256=RmM5shyyuxEGN2Y3JmeSWyU-SbpVARrvVFW72
235
236
  wbfdm/models/instruments/__init__.py,sha256=OvEkECJaCubBQC7B9yUrx15V982labvegeGXyEASVno,636
236
237
  wbfdm/models/instruments/classifications.py,sha256=EeZ_P8f1F1NfjUmLf9fDMF0iPM73qxQoArUfvjuCwHg,10906
237
238
  wbfdm/models/instruments/instrument_lists.py,sha256=GxfFyfYxEcJS36LAarHja49TOM8ffhIivpZX2-tPtZg,4234
238
- wbfdm/models/instruments/instrument_prices.py,sha256=4xDZ2ulwQ1grVuznchz3m3920LTmHkxWfiSLy-c2u0g,22306
239
+ wbfdm/models/instruments/instrument_prices.py,sha256=K7oMIz76WSrLmpNwcabThvtrP6WpBZZnrE9CHB5-UPQ,22345
239
240
  wbfdm/models/instruments/instrument_relationships.py,sha256=zpCZCnt5CqIg5bd6le_6TyirsSwGV2NaqTVKw3bd5vM,10660
240
241
  wbfdm/models/instruments/instrument_requests.py,sha256=XbpofRS8WHadHlTFjvXJyd0o7K9r2pzJtnpjVQZOLdI,7832
241
242
  wbfdm/models/instruments/instruments.py,sha256=Tn9vIu0kys8pVVBiO58Z0Z5fAv0KWzkp4L4kjm7oh3c,44485
242
243
  wbfdm/models/instruments/options.py,sha256=hFprq7B5t4ctz8nVqzFsBEzftq_KDUSsSXl1zJyh7tE,7094
243
244
  wbfdm/models/instruments/private_equities.py,sha256=uzwZi8IkmCKAHVTxnuFya9tehx7kh57sTlTEi1ieDaM,2198
244
- wbfdm/models/instruments/querysets.py,sha256=MNBep2F3G_MlbCu-IuzQIsxoRSWKjJBkj7FirNrWMT8,11533
245
+ wbfdm/models/instruments/querysets.py,sha256=7r3pXNlpROkYgKc6gQH07RNeWX6jGeBAPUabUevE6Jo,11587
245
246
  wbfdm/models/instruments/utils.py,sha256=88jnWINSSC0OwH-mCEOPLZXuhBCtEsxBpSaZ38GteaE,1365
246
247
  wbfdm/models/instruments/llm/__init__.py,sha256=dSmxRmEWb0A4O_lUoWuRKt2mBtUuLCTPVVJqGyi_n40,52
247
248
  wbfdm/models/instruments/llm/create_instrument_news_relationships.py,sha256=f9MT-8cWYlexUfCkaOJa9erI9RaUNI-nqCEyf2tDkbA,3809
248
249
  wbfdm/models/instruments/mixin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
249
- wbfdm/models/instruments/mixin/financials_computed.py,sha256=L5wjXDsR0maiwfOKP6KyWNJNH4nGOoAjSc_hDM7fsj0,35105
250
+ wbfdm/models/instruments/mixin/financials_computed.py,sha256=E87I7O2WQgjY3zM3so4dzfExBzVtKTkTqnRjPwLHbyM,34920
250
251
  wbfdm/models/instruments/mixin/financials_serializer_fields.py,sha256=-OkpcUt1rZmB3nUcO2vckpJdVm8IxRqkPDEgcPqqoRU,68886
251
252
  wbfdm/models/instruments/mixin/instruments.py,sha256=fpt03q_Sq35R_ZmJpdcw81aA7wTocnp7ANE1jb-_cfI,10022
252
253
  wbfdm/serializers/__init__.py,sha256=AXb03RKHo6B0ts_IQOvx89n9wKG8pxiumYv9cr4EhvA,197
@@ -279,7 +280,7 @@ wbfdm/tests/models/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuF
279
280
  wbfdm/tests/models/test_classifications.py,sha256=f2aM9UyV54fkEncp-uewEdOc3_0D-iPMN5LwhIhJC9w,4979
280
281
  wbfdm/tests/models/test_exchanges.py,sha256=KwK278MpA3FkpVgjW2l2PIHL7e8uDur7dOzIaTQEwyw,138
281
282
  wbfdm/tests/models/test_instrument_list.py,sha256=UIxKgBd4U-T2I4WDZfwacgJ1nKwJWYX1HKhdQDpx1tA,4899
282
- wbfdm/tests/models/test_instrument_prices.py,sha256=ObqFbJxZveiOPAK9_kC_JO9VBNmZB6bvGM4BejsFJ3c,16633
283
+ wbfdm/tests/models/test_instrument_prices.py,sha256=dRaFGc3epG_N6p0KtDzXOH7Gkx_aCSUKNn3JZBhHr8M,15875
283
284
  wbfdm/tests/models/test_instruments.py,sha256=Vg2cYWAwdu00dziKDUe_MrTzrsygHaZQHnvibF8pvew,9784
284
285
  wbfdm/tests/models/test_merge.py,sha256=tXD5xIxZyZtXpm9WIQ4Yc8TQwsUnkxkKIvMNwaHOvgM,4632
285
286
  wbfdm/tests/models/test_options.py,sha256=DoEAHhNQE4kucpBRRm2S05ozabkERz-I4mUolsE2Qi8,2269
@@ -360,6 +361,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
360
361
  wbfdm/viewsets/statements/statements.py,sha256=gA6RCI8-B__JwjEb6OZxpn8Y-9aF-YQ3HIQ7e1vfJMw,4304
361
362
  wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
362
363
  wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=O1j8CGfOranL74LqVvcf7jERaDIboEJZiBf_AbbVDQ8,3974
363
- wbfdm-1.54.23.dist-info/METADATA,sha256=rSS6J-mci-A7rRrt0UhvnXRzWnKSxiBmvbcU-iSTG_8,769
364
- wbfdm-1.54.23.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
365
- wbfdm-1.54.23.dist-info/RECORD,,
364
+ wbfdm-1.55.1.dist-info/METADATA,sha256=Fd7TZoh4t4Osc-BzujFsIrlDHsLjzELt6aOsDLOtZ-c,768
365
+ wbfdm-1.55.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
366
+ wbfdm-1.55.1.dist-info/RECORD,,