wbportfolio 1.54.21__py2.py3-none-any.whl → 1.54.22__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 wbportfolio might be problematic. Click here for more details.
- wbportfolio/constants.py +1 -0
- wbportfolio/import_export/parsers/vontobel/valuation_api.py +4 -1
- wbportfolio/models/builder.py +7 -5
- wbportfolio/models/portfolio.py +15 -8
- wbportfolio/viewsets/charts/assets.py +2 -2
- wbportfolio/viewsets/positions.py +3 -2
- {wbportfolio-1.54.21.dist-info → wbportfolio-1.54.22.dist-info}/METADATA +1 -1
- {wbportfolio-1.54.21.dist-info → wbportfolio-1.54.22.dist-info}/RECORD +10 -9
- {wbportfolio-1.54.21.dist-info → wbportfolio-1.54.22.dist-info}/WHEEL +0 -0
- {wbportfolio-1.54.21.dist-info → wbportfolio-1.54.22.dist-info}/licenses/LICENSE +0 -0
wbportfolio/constants.py
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
EQUITY_TYPE_KEYS = ["american_depository_receipt", "equity"] # TODO might want to move this into a dynamic preference
|
|
@@ -10,7 +10,10 @@ def parse(import_source):
|
|
|
10
10
|
with suppress(KeyError):
|
|
11
11
|
series_data = json.loads(import_source.file.read())["payload"]["series"]
|
|
12
12
|
for series in series_data:
|
|
13
|
-
|
|
13
|
+
try:
|
|
14
|
+
isin = series["key"]["priceIdentifier"]
|
|
15
|
+
except KeyError:
|
|
16
|
+
isin = series["priceIdentifier"]
|
|
14
17
|
if Product.objects.filter(isin=isin).exists(): # ensure the timeseries contain data for products we handle
|
|
15
18
|
for point in series["points"]:
|
|
16
19
|
data.append(
|
wbportfolio/models/builder.py
CHANGED
|
@@ -130,9 +130,9 @@ class AssetPositionBuilder:
|
|
|
130
130
|
def set_prices(self, prices: dict[date, dict[int, float]] | None = None):
|
|
131
131
|
self.prices = prices
|
|
132
132
|
|
|
133
|
-
def load_returns(self, instrument_ids: list[int], from_date: date, to_date: date):
|
|
133
|
+
def load_returns(self, instrument_ids: list[int], from_date: date, to_date: date, use_dl: bool = True):
|
|
134
134
|
self.prices, self.returns = Instrument.objects.filter(id__in=instrument_ids).get_returns_df(
|
|
135
|
-
from_date=from_date, to_date=to_date, to_currency=self.portfolio.currency, use_dl=
|
|
135
|
+
from_date=from_date, to_date=to_date, to_currency=self.portfolio.currency, use_dl=use_dl
|
|
136
136
|
)
|
|
137
137
|
|
|
138
138
|
def add(
|
|
@@ -221,9 +221,11 @@ class AssetPositionBuilder:
|
|
|
221
221
|
|
|
222
222
|
for val_date in self.get_dates():
|
|
223
223
|
if self.portfolio.is_tracked:
|
|
224
|
-
|
|
224
|
+
try:
|
|
225
225
|
changed_portfolio = self._get_portfolio(val_date)
|
|
226
|
-
|
|
226
|
+
except KeyError:
|
|
227
|
+
changed_portfolio = None
|
|
228
|
+
self._change_at_date_tasks[val_date] = changed_portfolio
|
|
227
229
|
self._compute_metrics_tasks.add(val_date)
|
|
228
230
|
self._positions = defaultdict(dict)
|
|
229
231
|
|
|
@@ -237,7 +239,7 @@ class AssetPositionBuilder:
|
|
|
237
239
|
for d in self._compute_metrics_tasks
|
|
238
240
|
]
|
|
239
241
|
).apply_async()
|
|
240
|
-
self._change_at_date_tasks =
|
|
242
|
+
self._change_at_date_tasks = dict()
|
|
241
243
|
|
|
242
244
|
def schedule_change_at_dates(self, synchronous: bool = True, **task_kwargs):
|
|
243
245
|
from wbportfolio.models.portfolio import trigger_portfolio_change_as_task
|
wbportfolio/models/portfolio.py
CHANGED
|
@@ -38,6 +38,7 @@ from wbportfolio.pms.analytics.portfolio import Portfolio as AnalyticPortfolio
|
|
|
38
38
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
39
39
|
from wbportfolio.pms.typing import Position as PositionDTO
|
|
40
40
|
|
|
41
|
+
from ..constants import EQUITY_TYPE_KEYS
|
|
41
42
|
from . import ProductGroup
|
|
42
43
|
|
|
43
44
|
logger = logging.getLogger("pms")
|
|
@@ -337,8 +338,12 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
337
338
|
weights = self.get_weights(val_date)
|
|
338
339
|
return_date = (val_date + BDay(1)).date()
|
|
339
340
|
returns = self.builder.returns
|
|
340
|
-
if
|
|
341
|
-
|
|
341
|
+
if (
|
|
342
|
+
return_date <= date.today()
|
|
343
|
+
and pd.Timestamp(return_date) not in returns.index
|
|
344
|
+
or not set(weights.keys()).issubset(set(returns.columns))
|
|
345
|
+
):
|
|
346
|
+
returns = self.load_builder_returns(val_date, return_date, use_dl=use_dl)
|
|
342
347
|
if pd.Timestamp(return_date) not in returns.index:
|
|
343
348
|
raise ValueError()
|
|
344
349
|
returns = returns.loc[:return_date, :]
|
|
@@ -507,7 +512,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
507
512
|
val_date=val_date,
|
|
508
513
|
exclude_cash=True,
|
|
509
514
|
exclude_index=True,
|
|
510
|
-
extra_filter_parameters={"
|
|
515
|
+
extra_filter_parameters={"underlying_instrument__instrument_type__key__in": EQUITY_TYPE_KEYS},
|
|
511
516
|
**kwargs,
|
|
512
517
|
)
|
|
513
518
|
if not df.empty:
|
|
@@ -520,7 +525,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
520
525
|
val_date=val_date,
|
|
521
526
|
exclude_cash=True,
|
|
522
527
|
exclude_index=True,
|
|
523
|
-
extra_filter_parameters={"
|
|
528
|
+
extra_filter_parameters={"underlying_instrument__instrument_type__key__in": EQUITY_TYPE_KEYS},
|
|
524
529
|
**kwargs,
|
|
525
530
|
)
|
|
526
531
|
if not df.empty:
|
|
@@ -592,7 +597,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
592
597
|
) -> pd.DataFrame:
|
|
593
598
|
qs = self._get_assets(with_cash=with_cash).filter(date__gte=start, date__lte=end)
|
|
594
599
|
if only_equity:
|
|
595
|
-
qs = qs.filter(
|
|
600
|
+
qs = qs.filter(underlying_instrument__instrument_type__key__in=EQUITY_TYPE_KEYS)
|
|
596
601
|
qs = qs.annotate_hedged_currency_fx_rate(hedged_currency)
|
|
597
602
|
df = Portfolio.get_contribution_df(
|
|
598
603
|
qs.select_related("underlying_instrument").values_list(
|
|
@@ -725,7 +730,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
725
730
|
effective_portfolio_date = (val_date - BDay(1)).date()
|
|
726
731
|
with suppress(ValueError):
|
|
727
732
|
if not analytic_portfolio:
|
|
728
|
-
analytic_portfolio = self.get_analytic_portfolio(effective_portfolio_date)
|
|
733
|
+
analytic_portfolio = self.get_analytic_portfolio(effective_portfolio_date, use_dl=False)
|
|
729
734
|
for instrument in self.pms_instruments:
|
|
730
735
|
# we assume that in t-1 we will have a portfolio (with at least estimate position). If we use the latest position date before val_date, we run into the problem of being able to compute nav at every date
|
|
731
736
|
last_price = instrument.get_latest_price(effective_portfolio_date)
|
|
@@ -839,11 +844,13 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
839
844
|
self.builder.schedule_change_at_dates(evaluate_rebalancer=False)
|
|
840
845
|
self.builder.schedule_metric_computation()
|
|
841
846
|
|
|
842
|
-
def load_builder_returns(self, from_date: date, to_date: date) -> pd.DataFrame:
|
|
847
|
+
def load_builder_returns(self, from_date: date, to_date: date, use_dl: bool = True) -> pd.DataFrame:
|
|
843
848
|
instruments_ids = list(self.get_weights(from_date).keys())
|
|
844
849
|
for tp in self.order_proposals.filter(trade_date__gte=from_date, trade_date__lte=to_date, status="APPROVED"):
|
|
845
850
|
instruments_ids.extend(tp.orders.values_list("underlying_instrument", flat=True))
|
|
846
|
-
self.builder.load_returns(
|
|
851
|
+
self.builder.load_returns(
|
|
852
|
+
set(instruments_ids), (from_date - BDay(1)).date(), (to_date + BDay(1)).date(), use_dl=use_dl
|
|
853
|
+
)
|
|
847
854
|
return self.builder.returns
|
|
848
855
|
|
|
849
856
|
def get_lookthrough_positions(
|
|
@@ -15,7 +15,6 @@ from wbfdm.models import (
|
|
|
15
15
|
ClassificationGroup,
|
|
16
16
|
Instrument,
|
|
17
17
|
InstrumentClassificationThroughModel,
|
|
18
|
-
InstrumentType,
|
|
19
18
|
)
|
|
20
19
|
|
|
21
20
|
from wbportfolio.filters.assets import DistributionFilter
|
|
@@ -26,6 +25,7 @@ from wbportfolio.models import (
|
|
|
26
25
|
PortfolioRole,
|
|
27
26
|
)
|
|
28
27
|
|
|
28
|
+
from ...constants import EQUITY_TYPE_KEYS
|
|
29
29
|
from ..configs.buttons.assets import (
|
|
30
30
|
DistributionChartButtonConfig,
|
|
31
31
|
DistributionTableButtonConfig,
|
|
@@ -70,7 +70,7 @@ class AbstractDistributionMixin:
|
|
|
70
70
|
|
|
71
71
|
def _generate_classification_df(self, queryset):
|
|
72
72
|
df = pd.DataFrame(
|
|
73
|
-
queryset.filter(
|
|
73
|
+
queryset.filter(underlying_instrument__instrument_type__key__in=EQUITY_TYPE_KEYS).values(
|
|
74
74
|
"weighting", "underlying_instrument"
|
|
75
75
|
),
|
|
76
76
|
columns=["weighting", "underlying_instrument"],
|
|
@@ -10,7 +10,7 @@ from wbcore.pandas import fields as pf
|
|
|
10
10
|
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
11
11
|
from wbcore.serializers import decorator
|
|
12
12
|
from wbcore.utils.strings import format_number
|
|
13
|
-
from wbfdm.models import Classification, ClassificationGroup, Instrument
|
|
13
|
+
from wbfdm.models import Classification, ClassificationGroup, Instrument
|
|
14
14
|
|
|
15
15
|
from wbportfolio.filters import (
|
|
16
16
|
AggregatedAssetPositionLiquidityFilter,
|
|
@@ -19,6 +19,7 @@ from wbportfolio.filters import (
|
|
|
19
19
|
from wbportfolio.filters.positions import GroupbyChoice
|
|
20
20
|
from wbportfolio.models import AssetPosition, Portfolio
|
|
21
21
|
|
|
22
|
+
from ..constants import EQUITY_TYPE_KEYS
|
|
22
23
|
from .configs import (
|
|
23
24
|
AggregatedAssetPositionLiquidityDisplayConfig,
|
|
24
25
|
AggregatedAssetPositionLiquidityEndpointConfig,
|
|
@@ -212,7 +213,7 @@ class AggregatedAssetPositionLiquidityPandasView(InternalUserPermissionMixin, Ex
|
|
|
212
213
|
|
|
213
214
|
# Take the liquidity query for the two dates.
|
|
214
215
|
qs_assets = queryset.filter(
|
|
215
|
-
|
|
216
|
+
underlying_instrument__instrument_type__key__in=EQUITY_TYPE_KEYS,
|
|
216
217
|
date__in=[historic_date, compared_date],
|
|
217
218
|
).values(
|
|
218
219
|
"date",
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
wbportfolio/__init__.py,sha256=J-j-u0itpEFT6irdmWmixQqYMadNl1X91TxUmoiLHMI,22
|
|
2
2
|
wbportfolio/apps.py,sha256=tybcoLFiw5tLdGHYV68X96n6jNZqx4BYx7Ao8mPflH8,749
|
|
3
|
+
wbportfolio/constants.py,sha256=86bfJ-xAyJQGv8DDxhVP_BM7Jr_lxQMhe4SkrxpfN_c,119
|
|
3
4
|
wbportfolio/dynamic_preferences_registry.py,sha256=SV-4JWBZBYhXt5cNMglx-yRJhxpejP_jo157ghjq2q0,2294
|
|
4
5
|
wbportfolio/permissions.py,sha256=F147DXfitbw6IdMQGEFfymCJkiG5YGkWKsLdVVliPyw,320
|
|
5
6
|
wbportfolio/preferences.py,sha256=JpowIFTrnjfomogJNrYmmfv7V35bRZNNGL_zooKzEhc,465
|
|
@@ -194,7 +195,7 @@ wbportfolio/import_export/parsers/vontobel/performance_fees.py,sha256=K-E7bRs7Lx
|
|
|
194
195
|
wbportfolio/import_export/parsers/vontobel/trade.py,sha256=Xc0ttSkdLm-ZIHtXOyHxHr3FuR89T87I9hXqiTMU1Hk,1566
|
|
195
196
|
wbportfolio/import_export/parsers/vontobel/utils.py,sha256=3-g2Jep9SxvqqQff8_3FjIeiPxSJCEfXBiBHIk0TiXQ,225
|
|
196
197
|
wbportfolio/import_export/parsers/vontobel/valuation.py,sha256=iav8_xYpTJchmTa7KOPmFr1gi9xxLwq3e-VcZ9MDiRk,1220
|
|
197
|
-
wbportfolio/import_export/parsers/vontobel/valuation_api.py,sha256=
|
|
198
|
+
wbportfolio/import_export/parsers/vontobel/valuation_api.py,sha256=z9b5zKS-Dz907Mrbg7rJjFVJocSutEiS6oo2ICTjpUI,980
|
|
198
199
|
wbportfolio/import_export/resources/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
199
200
|
wbportfolio/import_export/resources/assets.py,sha256=zjgHlQWpud41jHrKdRyqGUt1KUJQm9Z7pt0uVh4qBWQ,2234
|
|
200
201
|
wbportfolio/import_export/resources/trades.py,sha256=-HJPVYNuMRmCu4XpD00fYlRYu3N-Ys_JpyxE0HIU5bM,1723
|
|
@@ -268,11 +269,11 @@ wbportfolio/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3
|
|
|
268
269
|
wbportfolio/models/__init__.py,sha256=qU4e7HKyh8NL_0Mg92PcbHTewCv7Ya2gei1DMGe1LWE,980
|
|
269
270
|
wbportfolio/models/adjustments.py,sha256=osXWkJZOiansPWYPyHtl7Z121zDWi7u1YMtrBQtbHVo,10272
|
|
270
271
|
wbportfolio/models/asset.py,sha256=PwL16w2Rw_rJL73e0vCWMlRqsCxKW4zA9bf1EgTzD60,39574
|
|
271
|
-
wbportfolio/models/builder.py,sha256=
|
|
272
|
+
wbportfolio/models/builder.py,sha256=gGBlU0s5kvMxUas2lil0n98BxVjVocUDfU9oHKgkkJY,11622
|
|
272
273
|
wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
|
|
273
274
|
wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
|
|
274
275
|
wbportfolio/models/indexes.py,sha256=gvW4K9U9Bj8BmVCqFYdWiXvDWhjHINRON8XhNsZUiQY,639
|
|
275
|
-
wbportfolio/models/portfolio.py,sha256=
|
|
276
|
+
wbportfolio/models/portfolio.py,sha256=7PRPI8sNe4Ehe39-VJ14uPyG4gXqc3uMvwqS7pCy9yg,53266
|
|
276
277
|
wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
|
|
277
278
|
wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
|
|
278
279
|
wbportfolio/models/portfolio_relationship.py,sha256=ZGECiPZiLdlk4uSamOrEfuzO0hduK6OMKJLUSnh5_kc,5190
|
|
@@ -437,7 +438,7 @@ wbportfolio/viewsets/portfolio_cash_targets.py,sha256=CvHlrDE8qnnnfRpTYnFu-Uu15M
|
|
|
437
438
|
wbportfolio/viewsets/portfolio_relationship.py,sha256=RGyvxd8NfFEs8YdqEvVD3VbrISvAO5UtCTlocSIuWQw,2109
|
|
438
439
|
wbportfolio/viewsets/portfolio_swing_pricing.py,sha256=-57l3WLQZRslIV67OT0ucHE5JXTtTtLvd3t7MppdVn8,357
|
|
439
440
|
wbportfolio/viewsets/portfolios.py,sha256=6aF2Uh0EAdHdX1mMTQrFBlXZ5kmlaCPz49iDvT2CnYM,14438
|
|
440
|
-
wbportfolio/viewsets/positions.py,sha256=
|
|
441
|
+
wbportfolio/viewsets/positions.py,sha256=fYmkcYwNybeEZejMZVvel8yFdr7ob_jG8t6ar7snD58,13236
|
|
441
442
|
wbportfolio/viewsets/product_groups.py,sha256=YvmuXPPy98K1J_rz6YPsx9gNK-tCS2P-wc1uRYgfyo0,2399
|
|
442
443
|
wbportfolio/viewsets/product_performance.py,sha256=dRfRgifjGS1RgZSu9uJRM0SmB7eLnNUkPuqARMO4gyo,28371
|
|
443
444
|
wbportfolio/viewsets/products.py,sha256=V8UFtfqxzs67XaU1JZcJJms1WzeNPeXtNBrQuz4B5mk,20414
|
|
@@ -447,7 +448,7 @@ wbportfolio/viewsets/registers.py,sha256=eOuEhW2McHsOapCKue7M4eazrJnVpCBVxImpFcc
|
|
|
447
448
|
wbportfolio/viewsets/roles.py,sha256=vnzS1mlJMZS3GObrss6SfXOr3KRb-OHB1s4Msvtn7xQ,1556
|
|
448
449
|
wbportfolio/viewsets/signals.py,sha256=URxNz-7tKNBgvaFIE3FItfao3Md0dKQN_eVFwxxiErk,2125
|
|
449
450
|
wbportfolio/viewsets/charts/__init__.py,sha256=mNSpDrsqK-afRxGBfEsfgupUc20xU-JW08FpxIyudok,71
|
|
450
|
-
wbportfolio/viewsets/charts/assets.py,sha256=
|
|
451
|
+
wbportfolio/viewsets/charts/assets.py,sha256=d8y_9N3D3a41S-XUg7AV5GjLHoW44kRJOHTkzpeuemU,10573
|
|
451
452
|
wbportfolio/viewsets/configs/__init__.py,sha256=K5opfVQvgGwSyw3XwDGkv3lo5i9jBxOJXYhLqyCdfeQ,137
|
|
452
453
|
wbportfolio/viewsets/configs/buttons/__init__.py,sha256=hyvpxwh9ss8Q0xcE006qsTLuSsJeWt9saHRcU4g96tA,791
|
|
453
454
|
wbportfolio/viewsets/configs/buttons/adjustments.py,sha256=sUY_3vxqP0kuqs8i5hklfboZI6QiAOrmu30eb29Xupo,492
|
|
@@ -554,7 +555,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
|
|
|
554
555
|
wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
|
|
555
556
|
wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
|
|
556
557
|
wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
|
|
557
|
-
wbportfolio-1.54.
|
|
558
|
-
wbportfolio-1.54.
|
|
559
|
-
wbportfolio-1.54.
|
|
560
|
-
wbportfolio-1.54.
|
|
558
|
+
wbportfolio-1.54.22.dist-info/METADATA,sha256=dHZzJlBfD3drPh9scLSxGZPJNFdLDG_zEIqSzdyiMbo,703
|
|
559
|
+
wbportfolio-1.54.22.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
560
|
+
wbportfolio-1.54.22.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
561
|
+
wbportfolio-1.54.22.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|