wbfdm 1.54.6__py2.py3-none-any.whl → 1.54.7__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.
- wbfdm/contrib/internal/dataloaders/market_data.py +37 -4
- wbfdm/contrib/qa/dataloaders/market_data.py +4 -3
- wbfdm/dataloaders/protocols.py +1 -0
- wbfdm/dataloaders/proxies.py +2 -0
- wbfdm/dataloaders/types.py +1 -1
- wbfdm/models/instruments/mixin/instruments.py +1 -1
- {wbfdm-1.54.6.dist-info → wbfdm-1.54.7.dist-info}/METADATA +1 -1
- {wbfdm-1.54.6.dist-info → wbfdm-1.54.7.dist-info}/RECORD +9 -9
- {wbfdm-1.54.6.dist-info → wbfdm-1.54.7.dist-info}/WHEEL +0 -0
|
@@ -2,11 +2,14 @@ from datetime import date
|
|
|
2
2
|
from decimal import Decimal
|
|
3
3
|
from typing import Iterator
|
|
4
4
|
|
|
5
|
+
from django.db.models import Value
|
|
6
|
+
from django.db.models.functions import Coalesce
|
|
7
|
+
from wbcore.contrib.currency.models import Currency, CurrencyFXRates
|
|
5
8
|
from wbcore.contrib.dataloader.dataloaders import Dataloader
|
|
6
9
|
|
|
7
10
|
from wbfdm.dataloaders.protocols import MarketDataProtocol
|
|
8
11
|
from wbfdm.dataloaders.types import MarketDataDict
|
|
9
|
-
from wbfdm.enums import MarketData
|
|
12
|
+
from wbfdm.enums import Frequency, MarketData
|
|
10
13
|
from wbfdm.models.instruments.instrument_prices import InstrumentPrice
|
|
11
14
|
|
|
12
15
|
MarketDataMap = {
|
|
@@ -33,11 +36,13 @@ def _cast_decimal_to_float(value: float | Decimal) -> float:
|
|
|
33
36
|
class MarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
34
37
|
def market_data(
|
|
35
38
|
self,
|
|
36
|
-
values: list[MarketData]
|
|
39
|
+
values: list[MarketData] = [MarketData.CLOSE],
|
|
37
40
|
from_date: date | None = None,
|
|
38
41
|
to_date: date | None = None,
|
|
39
42
|
exact_date: date | None = None,
|
|
40
|
-
|
|
43
|
+
frequency: Frequency = Frequency.DAILY,
|
|
44
|
+
target_currency: str | None = None,
|
|
45
|
+
apply_fx_rate: bool = True,
|
|
41
46
|
**kwargs,
|
|
42
47
|
) -> Iterator[MarketDataDict]:
|
|
43
48
|
"""Get prices for instruments.
|
|
@@ -51,7 +56,27 @@ class MarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
51
56
|
Returns:
|
|
52
57
|
Iterator[MarketDataDict]: An iterator of dictionaries conforming to the DailyValuationDict.
|
|
53
58
|
"""
|
|
54
|
-
|
|
59
|
+
try:
|
|
60
|
+
target_currency = Currency.objects.get(key=target_currency)
|
|
61
|
+
except Currency.DoesNotExist:
|
|
62
|
+
target_currency = None
|
|
63
|
+
fx_rate = (
|
|
64
|
+
Coalesce(
|
|
65
|
+
CurrencyFXRates.get_fx_rates_subquery_for_two_currencies(
|
|
66
|
+
"date", "instrument__currency", target_currency
|
|
67
|
+
),
|
|
68
|
+
Value(Decimal("1")),
|
|
69
|
+
)
|
|
70
|
+
if target_currency
|
|
71
|
+
else Value(Decimal("1"))
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
prices = (
|
|
75
|
+
InstrumentPrice.objects.filter(instrument__in=self.entities)
|
|
76
|
+
.annotate_market_data()
|
|
77
|
+
.annotate(fx_rate=fx_rate)
|
|
78
|
+
) # type: ignore
|
|
79
|
+
calculated = kwargs.get("calculated", None)
|
|
55
80
|
if calculated is not None:
|
|
56
81
|
prices = prices.filter(calculated=calculated)
|
|
57
82
|
else:
|
|
@@ -72,11 +97,18 @@ class MarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
72
97
|
"date",
|
|
73
98
|
"instrument",
|
|
74
99
|
"calculated",
|
|
100
|
+
"fx_rate",
|
|
75
101
|
*set(values_map.values()),
|
|
76
102
|
):
|
|
77
103
|
external_id = row.pop("instrument")
|
|
78
104
|
val_date = row.pop("date")
|
|
79
105
|
if row:
|
|
106
|
+
fx_rate = row["fx_rate"]
|
|
107
|
+
if apply_fx_rate and row.get("net_value"):
|
|
108
|
+
row["net_value"] = row["net_value"] * fx_rate
|
|
109
|
+
if apply_fx_rate and row.get("market_capitalization"):
|
|
110
|
+
row["market_capitalization"] = row["market_capitalization"] * float(fx_rate)
|
|
111
|
+
|
|
80
112
|
yield MarketDataDict(
|
|
81
113
|
id=f"{external_id}_{val_date}",
|
|
82
114
|
valuation_date=val_date,
|
|
@@ -84,5 +116,6 @@ class MarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
84
116
|
external_id=external_id,
|
|
85
117
|
source="wbfdm",
|
|
86
118
|
calculated=row["calculated"],
|
|
119
|
+
fx_rate=_cast_decimal_to_float(fx_rate),
|
|
87
120
|
**{MarketData[k].value: _cast_decimal_to_float(row[v]) for k, v in values_map.items()},
|
|
88
121
|
)
|
|
@@ -45,6 +45,7 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
45
45
|
exact_date: date | None = None,
|
|
46
46
|
frequency: Frequency = Frequency.DAILY,
|
|
47
47
|
target_currency: str | None = None,
|
|
48
|
+
apply_fx_rate: bool = True,
|
|
48
49
|
**kwargs,
|
|
49
50
|
) -> Iterator[MarketDataDict]:
|
|
50
51
|
"""Get market data for instruments.
|
|
@@ -97,7 +98,7 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
97
98
|
fx_code = pk.Table("DS2FxCode")
|
|
98
99
|
fx_rate = pk.Table("DS2FxRate")
|
|
99
100
|
query = (
|
|
100
|
-
query
|
|
101
|
+
query.select((1 / fx_rate.midrate).as_("fx_rate"))
|
|
101
102
|
# Join FX code table matching currencies and ensuring SPOT rate type
|
|
102
103
|
.left_join(fx_code)
|
|
103
104
|
.on(
|
|
@@ -127,7 +128,7 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
127
128
|
)
|
|
128
129
|
|
|
129
130
|
value = pricing_2.Close_
|
|
130
|
-
if fx_rate:
|
|
131
|
+
if fx_rate and apply_fx_rate:
|
|
131
132
|
value /= Case().when(pricing_2.Currency == target_currency, 1).else_(fx_rate.midrate)
|
|
132
133
|
|
|
133
134
|
query = query.select(value.as_("undadjusted_close"))
|
|
@@ -145,7 +146,7 @@ class DatastreamMarketDataDataloader(MarketDataProtocol, Dataloader):
|
|
|
145
146
|
):
|
|
146
147
|
ds2_value = DS2MarketData[market_data.name].value
|
|
147
148
|
value = getattr(pricing, ds2_value)
|
|
148
|
-
if fx_rate and market_data is not MarketData.SHARES_OUTSTANDING:
|
|
149
|
+
if fx_rate and apply_fx_rate and market_data is not MarketData.SHARES_OUTSTANDING:
|
|
149
150
|
value /= Case().when(pricing.Currency == target_currency, 1).else_(fx_rate.midrate)
|
|
150
151
|
|
|
151
152
|
query = query.select(value.as_(market_data.value))
|
wbfdm/dataloaders/protocols.py
CHANGED
wbfdm/dataloaders/proxies.py
CHANGED
|
@@ -80,6 +80,7 @@ class InstrumentDataloaderProxy(
|
|
|
80
80
|
exact_date: date | None = None,
|
|
81
81
|
frequency: Frequency = Frequency.DAILY,
|
|
82
82
|
target_currency: str | None = None,
|
|
83
|
+
apply_fx_rate: bool = True,
|
|
83
84
|
) -> Iterator[MarketDataDict]:
|
|
84
85
|
if not values:
|
|
85
86
|
values = list(MarketData)
|
|
@@ -93,6 +94,7 @@ class InstrumentDataloaderProxy(
|
|
|
93
94
|
exact_date=exact_date,
|
|
94
95
|
frequency=frequency,
|
|
95
96
|
target_currency=target_currency,
|
|
97
|
+
apply_fx_rate=apply_fx_rate,
|
|
96
98
|
),
|
|
97
99
|
)
|
|
98
100
|
|
wbfdm/dataloaders/types.py
CHANGED
|
@@ -65,7 +65,7 @@ class MarketDataDict(BaseDict):
|
|
|
65
65
|
volume: NotRequired[float]
|
|
66
66
|
market_cap: NotRequired[float]
|
|
67
67
|
calculated: NotRequired[bool]
|
|
68
|
-
|
|
68
|
+
fx_rate: NotRequired[float]
|
|
69
69
|
unadjusted_close: NotRequired[float]
|
|
70
70
|
unadjusted_outstanding_shares: NotRequired[float | int]
|
|
71
71
|
|
|
@@ -42,7 +42,7 @@ class InstrumentPMSMixin:
|
|
|
42
42
|
def get_price(self, val_date: date, price_date_timedelta: int = 3) -> Decimal:
|
|
43
43
|
if self.is_cash:
|
|
44
44
|
return Decimal(1)
|
|
45
|
-
return self._build_dto(val_date, price_date_timedelta=price_date_timedelta).close
|
|
45
|
+
return Decimal(self._build_dto(val_date, price_date_timedelta=price_date_timedelta).close)
|
|
46
46
|
|
|
47
47
|
def _build_dto(self, val_date: date, price_date_timedelta: int = 3) -> PriceDTO: # for backward compatibility
|
|
48
48
|
try:
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: wbfdm
|
|
3
|
-
Version: 1.54.
|
|
3
|
+
Version: 1.54.7
|
|
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.*
|
|
@@ -41,7 +41,7 @@ wbfdm/contrib/dsws/client.py,sha256=C598w5P85kvX7_gR0Yf-WHRLj77HqztUhofBMl3JWAE,
|
|
|
41
41
|
wbfdm/contrib/dsws/dataloaders/market_data.py,sha256=7Vj64nLqJAA3BiNeJPr3uLnnZ5kFOY2XGyAAJRL7vOk,6097
|
|
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=
|
|
44
|
+
wbfdm/contrib/internal/dataloaders/market_data.py,sha256=FA7_f_20Gx1EjWOK9HDcWfX_gbBpOYXaxMR_O5T-K-Q,4542
|
|
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
|
|
@@ -100,7 +100,7 @@ wbfdm/contrib/qa/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
|
|
|
100
100
|
wbfdm/contrib/qa/dataloaders/adjustments.py,sha256=DQEexOLA7WyBB1dZJHQd-6zbzyEIURgSSgS7bJRvXzQ,2980
|
|
101
101
|
wbfdm/contrib/qa/dataloaders/corporate_actions.py,sha256=lWT6klrTXKqxiko2HGrxHH8E2C00FJS-AOX3IhglRrI,2912
|
|
102
102
|
wbfdm/contrib/qa/dataloaders/financials.py,sha256=xUHpvhUkvmdPL_RyWCrs7XgChgTklX5qemmaXMedgkY,3475
|
|
103
|
-
wbfdm/contrib/qa/dataloaders/market_data.py,sha256=
|
|
103
|
+
wbfdm/contrib/qa/dataloaders/market_data.py,sha256=0LjTN04WM2i9rrJ_M3M04cY0UbxMElsWiaqOC75xpHQ,8221
|
|
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
106
|
wbfdm/contrib/qa/dataloaders/statements.py,sha256=hC6YErJcvBTmaAmzscgeC4sBK3lYE2U5eIKRIE9b_cs,10094
|
|
@@ -118,9 +118,9 @@ wbfdm/contrib/qa/sync/instruments.py,sha256=8aTQVJ_cw1phe4FWikn79pjCfUijaTcwkdhQ
|
|
|
118
118
|
wbfdm/contrib/qa/sync/utils.py,sha256=LUnjNR28moT92cjP04SVCRQ_Ssp6SaO9kehgWV4zvOs,11782
|
|
119
119
|
wbfdm/dataloaders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
120
120
|
wbfdm/dataloaders/cache.py,sha256=K9BeVxT7p-BMvjurINt18bfrUDccp840uIjfDBLJRNk,4841
|
|
121
|
-
wbfdm/dataloaders/protocols.py,sha256=
|
|
122
|
-
wbfdm/dataloaders/proxies.py,sha256=
|
|
123
|
-
wbfdm/dataloaders/types.py,sha256=
|
|
121
|
+
wbfdm/dataloaders/protocols.py,sha256=1vornH4tCIsd7HLL3lCiE0ni6YQEI6fF6Em_I-AUSFc,3023
|
|
122
|
+
wbfdm/dataloaders/proxies.py,sha256=gA5QFXgbC78tQpmypow1dJ5k7UyqFGXDEyeS-xpUGEw,7157
|
|
123
|
+
wbfdm/dataloaders/types.py,sha256=8PNHfBQj4C0xVn6cJxKQV3oBFxkTW3MGn4dMMRKVGJ4,5596
|
|
124
124
|
wbfdm/factories/__init__.py,sha256=yYxAKBde_ksIr-3g4RjL6d5Wu-nmsuEDdYNyJpgfpQU,660
|
|
125
125
|
wbfdm/factories/classifications.py,sha256=GJ0eARFTsj5dnKUsUYbLSIZLzTCy7RWhy7_f8Dn6IMQ,1827
|
|
126
126
|
wbfdm/factories/controversies.py,sha256=GhuoEms1O7DIMVNAIbFEzD9DRv8j1MXIv0u1JK6Pi-o,929
|
|
@@ -248,7 +248,7 @@ wbfdm/models/instruments/llm/create_instrument_news_relationships.py,sha256=f9MT
|
|
|
248
248
|
wbfdm/models/instruments/mixin/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
249
249
|
wbfdm/models/instruments/mixin/financials_computed.py,sha256=L5wjXDsR0maiwfOKP6KyWNJNH4nGOoAjSc_hDM7fsj0,35105
|
|
250
250
|
wbfdm/models/instruments/mixin/financials_serializer_fields.py,sha256=-OkpcUt1rZmB3nUcO2vckpJdVm8IxRqkPDEgcPqqoRU,68886
|
|
251
|
-
wbfdm/models/instruments/mixin/instruments.py,sha256=
|
|
251
|
+
wbfdm/models/instruments/mixin/instruments.py,sha256=fpt03q_Sq35R_ZmJpdcw81aA7wTocnp7ANE1jb-_cfI,10022
|
|
252
252
|
wbfdm/serializers/__init__.py,sha256=AXb03RKHo6B0ts_IQOvx89n9wKG8pxiumYv9cr4EhvA,197
|
|
253
253
|
wbfdm/serializers/esg.py,sha256=epoX8cjkPuVv45aW-Jf85-rSO_ZrSnXcTxMcadKdC-I,1086
|
|
254
254
|
wbfdm/serializers/exchanges.py,sha256=wYvy0XBS9tRFHqin23gABQ_pj3Rmsx1B075SZ5GqwDo,1211
|
|
@@ -359,6 +359,6 @@ wbfdm/viewsets/statements/__init__.py,sha256=odxtFYUDICPmz8WCE3nx93EvKZLSPBEI4d7
|
|
|
359
359
|
wbfdm/viewsets/statements/statements.py,sha256=gA6RCI8-B__JwjEb6OZxpn8Y-9aF-YQ3HIQ7e1vfJMw,4304
|
|
360
360
|
wbfdm/viewsets/technical_analysis/__init__.py,sha256=qtCIBg0uSiZeJq_1tEQFilnorMBkMe6uCMfqar6-cLE,77
|
|
361
361
|
wbfdm/viewsets/technical_analysis/monthly_performances.py,sha256=O1j8CGfOranL74LqVvcf7jERaDIboEJZiBf_AbbVDQ8,3974
|
|
362
|
-
wbfdm-1.54.
|
|
363
|
-
wbfdm-1.54.
|
|
364
|
-
wbfdm-1.54.
|
|
362
|
+
wbfdm-1.54.7.dist-info/METADATA,sha256=aa803KkLY9b9cQMX2W5Hn4jWv1apafyFnkqOeDBcCzQ,768
|
|
363
|
+
wbfdm-1.54.7.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
364
|
+
wbfdm-1.54.7.dist-info/RECORD,,
|
|
File without changes
|