wbportfolio 1.43.2__py2.py3-none-any.whl → 1.44.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 wbportfolio might be problematic. Click here for more details.
- wbportfolio/import_export/handlers/asset_position.py +23 -20
- wbportfolio/risk_management/backends/product_integrity.py +14 -16
- wbportfolio/risk_management/tests/test_product_integrity.py +7 -14
- wbportfolio/viewsets/configs/display/esg.py +10 -20
- {wbportfolio-1.43.2.dist-info → wbportfolio-1.44.1.dist-info}/METADATA +1 -1
- {wbportfolio-1.43.2.dist-info → wbportfolio-1.44.1.dist-info}/RECORD +8 -8
- {wbportfolio-1.43.2.dist-info → wbportfolio-1.44.1.dist-info}/WHEEL +0 -0
- {wbportfolio-1.43.2.dist-info → wbportfolio-1.44.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -4,7 +4,10 @@ from decimal import Decimal
|
|
|
4
4
|
from itertools import chain
|
|
5
5
|
from typing import Any, Dict, List, Optional
|
|
6
6
|
|
|
7
|
+
from django.core.exceptions import ObjectDoesNotExist
|
|
7
8
|
from django.db import models
|
|
9
|
+
from contextlib import suppress
|
|
10
|
+
|
|
8
11
|
from wbcore.contrib.authentication.authentication import User
|
|
9
12
|
from wbcore.contrib.currency.import_export.handlers import CurrencyImportHandler
|
|
10
13
|
from wbcore.contrib.io.exceptions import DeserializationError
|
|
@@ -145,23 +148,23 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
145
148
|
for val_date in sorted(dates):
|
|
146
149
|
trigger_portfolio_change_as_task.delay(portfolio.id, val_date, recompute_weighting=True)
|
|
147
150
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
151
|
+
# check if portfolio as custodian
|
|
152
|
+
latest_date = max(dates)
|
|
153
|
+
with suppress(ObjectDoesNotExist):
|
|
154
|
+
if (custodian_rel := portfolio.dependency_through.get(type="CUSTODIAN")) and portfolio.assets.latest(
|
|
155
|
+
"date"
|
|
156
|
+
).date >= latest_date:
|
|
157
|
+
custodian_portfolio = custodian_rel.dependency_portfolio
|
|
158
|
+
differences = portfolio.check_related_portfolio_at_date(latest_date, custodian_portfolio)
|
|
159
|
+
if differences.exists():
|
|
160
|
+
for user in User.objects.filter(
|
|
161
|
+
profile_id__in=PortfolioRole.portfolio_managers().values_list("person", flat=True)
|
|
162
|
+
):
|
|
163
|
+
send_notification(
|
|
164
|
+
code="wbportfolio.portfolio.check_custodian_portfolio",
|
|
165
|
+
title="There is a discrepency between two portfolios",
|
|
166
|
+
body=f"There has been a discrepency between two portfolios: {portfolio} and {custodian_portfolio}.",
|
|
167
|
+
user=user,
|
|
168
|
+
reverse_name="wbportfolio:portfolio-modelcompositionpandas-list",
|
|
169
|
+
reverse_args=[portfolio.id],
|
|
170
|
+
)
|
|
@@ -51,7 +51,7 @@ class RuleBackend(backend.AbstractRuleBackend):
|
|
|
51
51
|
return RuleBackendSerializer
|
|
52
52
|
|
|
53
53
|
def _process_dto(self, product: Product, **kwargs) -> Generator[backend.IncidentResult, None, None]:
|
|
54
|
-
for lag_threshold in self.thresholds:
|
|
54
|
+
for lag_threshold in reversed(self.thresholds):
|
|
55
55
|
numerical_range = lag_threshold.numerical_range
|
|
56
56
|
|
|
57
57
|
last_asset_position_date = (
|
|
@@ -77,35 +77,33 @@ class RuleBackend(backend.AbstractRuleBackend):
|
|
|
77
77
|
)
|
|
78
78
|
- 1
|
|
79
79
|
)
|
|
80
|
-
|
|
80
|
+
breached_data_type = []
|
|
81
81
|
if (
|
|
82
82
|
self.DataTypeChoices.ASSET_POSITION.value in self.data_type
|
|
83
83
|
and asset_position_lag >= numerical_range[0]
|
|
84
84
|
and asset_position_lag < numerical_range[1]
|
|
85
85
|
):
|
|
86
|
-
|
|
87
|
-
breached_object=product,
|
|
88
|
-
breached_object_repr=str(product),
|
|
89
|
-
breached_value=str(asset_position_lag),
|
|
90
|
-
report_details={
|
|
91
|
-
"Last Datapoint": f"{last_asset_position_date:%d.%m.%Y}",
|
|
92
|
-
"Data Type": "Asset Position",
|
|
93
|
-
},
|
|
94
|
-
severity=lag_threshold.severity,
|
|
95
|
-
)
|
|
86
|
+
breached_data_type.append("Asset Position")
|
|
96
87
|
if (
|
|
97
88
|
self.DataTypeChoices.INSTRUMENT_PRICE.value in self.data_type
|
|
98
89
|
and instrument_price_lag >= numerical_range[0]
|
|
99
90
|
and instrument_price_lag < numerical_range[1]
|
|
100
91
|
):
|
|
92
|
+
breached_data_type.append("Valuation")
|
|
93
|
+
|
|
94
|
+
if len(breached_data_type) > 0:
|
|
95
|
+
max_lag = max([asset_position_lag, instrument_price_lag])
|
|
101
96
|
yield backend.IncidentResult(
|
|
102
97
|
breached_object=product,
|
|
103
98
|
breached_object_repr=str(product),
|
|
104
|
-
breached_value=str(
|
|
99
|
+
breached_value=str(max_lag),
|
|
105
100
|
report_details={
|
|
106
|
-
"Lag":
|
|
107
|
-
"Last Datapoint": f"{last_instrument_price_date:%d.%m.%Y}",
|
|
108
|
-
"
|
|
101
|
+
"Lag": max_lag,
|
|
102
|
+
"Last Valuation Datapoint": f"{last_instrument_price_date:%d.%m.%Y}",
|
|
103
|
+
"Last Asset Position Datapoint": f"{last_asset_position_date:%d.%m.%Y}",
|
|
104
|
+
"Valuation Lag": instrument_price_lag,
|
|
105
|
+
"Asset Position Lag": asset_position_lag,
|
|
109
106
|
},
|
|
110
107
|
severity=lag_threshold.severity,
|
|
111
108
|
)
|
|
109
|
+
break
|
|
@@ -33,23 +33,16 @@ class TestProductRuleModel:
|
|
|
33
33
|
asset_position_factory.create(date=weekday - BDay(2), portfolio=product.portfolio, is_estimated=False)
|
|
34
34
|
instrument_price_factory.create(date=weekday - BDay(1), instrument=product, calculated=False)
|
|
35
35
|
|
|
36
|
-
res = list(product_backend.check_rule())
|
|
37
|
-
low_severity = list(filter(lambda x: x.severity.name == "LOW", res))[0]
|
|
38
|
-
high_severity = list(filter(lambda x: x.severity.name == "HIGH", res))[0]
|
|
39
|
-
|
|
40
|
-
assert high_severity.report_details["Data Type"] == "Asset Position"
|
|
41
|
-
assert low_severity.report_details["Data Type"] == "Valuation"
|
|
42
|
-
assert high_severity.report_details["Last Datapoint"] == f"{(weekday - BDay(2)).date():%d.%m.%Y}"
|
|
43
|
-
assert low_severity.report_details["Last Datapoint"] == f"{(weekday - BDay(1)).date():%d.%m.%Y}"
|
|
44
|
-
|
|
45
|
-
instrument_price_factory.create(date=weekday, instrument=product, calculated=False)
|
|
46
|
-
asset_position_factory.create(date=weekday - BDay(1), portfolio=product.portfolio, is_estimated=False)
|
|
47
|
-
|
|
48
36
|
res = list(product_backend.check_rule())
|
|
49
37
|
assert len(res) == 1
|
|
50
|
-
|
|
51
|
-
assert
|
|
38
|
+
incident = res[0]
|
|
39
|
+
assert incident.severity.name == "HIGH"
|
|
40
|
+
assert incident.breached_value == str(2)
|
|
41
|
+
assert incident.report_details["Lag"] == 2
|
|
42
|
+
assert incident.report_details["Last Asset Position Datapoint"] == f"{(weekday - BDay(2)).date():%d.%m.%Y}"
|
|
43
|
+
assert incident.report_details["Last Valuation Datapoint"] == f"{(weekday - BDay(1)).date():%d.%m.%Y}"
|
|
52
44
|
|
|
45
|
+
instrument_price_factory.create(date=weekday, instrument=product, calculated=False)
|
|
53
46
|
asset_position_factory.create(date=weekday, portfolio=product.portfolio, is_estimated=False)
|
|
54
47
|
res = list(product_backend.check_rule())
|
|
55
48
|
assert len(res) == 0
|
|
@@ -14,12 +14,12 @@ class ESGMetricAggregationPortfolioPandasDisplayConfig(DisplayViewConfig):
|
|
|
14
14
|
label="Portfolio Data",
|
|
15
15
|
children=[
|
|
16
16
|
dp.Field(
|
|
17
|
-
key="underlying_instrument_repr",
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
dp.Field(
|
|
21
|
-
key="total_value_fx_usd", label="Total Asset (USD)", width=Unit.PIXEL(150), lock_position=True
|
|
17
|
+
key="underlying_instrument_repr",
|
|
18
|
+
label="Name",
|
|
19
|
+
width=Unit.PIXEL(300),
|
|
22
20
|
),
|
|
21
|
+
dp.Field(key="weighting", label="Weight", width=Unit.PIXEL(100)),
|
|
22
|
+
dp.Field(key="total_value_fx_usd", label="Total Asset (USD)", width=Unit.PIXEL(150)),
|
|
23
23
|
],
|
|
24
24
|
)
|
|
25
25
|
]
|
|
@@ -28,15 +28,12 @@ class ESGMetricAggregationPortfolioPandasDisplayConfig(DisplayViewConfig):
|
|
|
28
28
|
key="esg_data",
|
|
29
29
|
label=self.view.esg_aggregation.get_esg_code().name,
|
|
30
30
|
width=Unit.PIXEL(150),
|
|
31
|
-
lock_position=True,
|
|
32
31
|
)
|
|
33
32
|
]
|
|
34
33
|
for extra in self.view.dataloader.extra_esg_data_logs:
|
|
35
|
-
esg_data_fields.append(
|
|
36
|
-
dp.Field(key=extra.series.name, label=extra.label, width=Unit.PIXEL(150), lock_position=True)
|
|
37
|
-
)
|
|
34
|
+
esg_data_fields.append(dp.Field(key=extra.series.name, label=extra.label, width=Unit.PIXEL(150)))
|
|
38
35
|
fields.append(
|
|
39
|
-
dp.Field(key=None, label="ESG Data", children=esg_data_fields
|
|
36
|
+
dp.Field(key=None, label="ESG Data", children=esg_data_fields),
|
|
40
37
|
)
|
|
41
38
|
if self.view.dataloader.intermediary_logs:
|
|
42
39
|
intermediary_fields = []
|
|
@@ -47,7 +44,6 @@ class ESGMetricAggregationPortfolioPandasDisplayConfig(DisplayViewConfig):
|
|
|
47
44
|
key=intermediary.series.name,
|
|
48
45
|
label=intermediary.label,
|
|
49
46
|
width=Unit.PIXEL(100),
|
|
50
|
-
lock_position=True,
|
|
51
47
|
)
|
|
52
48
|
if intermediary.group:
|
|
53
49
|
intermediary_groups[intermediary.group].append(field)
|
|
@@ -58,29 +54,23 @@ class ESGMetricAggregationPortfolioPandasDisplayConfig(DisplayViewConfig):
|
|
|
58
54
|
key=intermediary.series.name,
|
|
59
55
|
label=intermediary.label,
|
|
60
56
|
width=Unit.PIXEL(150),
|
|
61
|
-
lock_position=True,
|
|
62
57
|
)
|
|
63
58
|
)
|
|
64
59
|
for group_name, intermediary_groups_fields in intermediary_groups.items():
|
|
65
|
-
intermediary_fields.append(
|
|
66
|
-
dp.Field(key=None, label=group_name, children=intermediary_groups_fields, lock_position=True)
|
|
67
|
-
)
|
|
60
|
+
intermediary_fields.append(dp.Field(key=None, label=group_name, children=intermediary_groups_fields))
|
|
68
61
|
fields.append(
|
|
69
|
-
dp.Field(key=None, label="Intermediary", children=intermediary_fields
|
|
62
|
+
dp.Field(key=None, label="Intermediary", children=intermediary_fields),
|
|
70
63
|
)
|
|
71
64
|
fields.append(
|
|
72
65
|
dp.Field(
|
|
73
66
|
key=None,
|
|
74
67
|
label="Metric",
|
|
75
68
|
children=[
|
|
76
|
-
dp.Field(
|
|
77
|
-
key="metric", label=self.view.esg_aggregation.value, width=Unit.PIXEL(150), lock_position=True
|
|
78
|
-
),
|
|
69
|
+
dp.Field(key="metric", label=self.view.esg_aggregation.value, width=Unit.PIXEL(150)),
|
|
79
70
|
dp.Field(
|
|
80
71
|
key="weights_in_coverage",
|
|
81
72
|
label="Weight in Coverage",
|
|
82
73
|
width=Unit.PIXEL(100),
|
|
83
|
-
lock_position=True,
|
|
84
74
|
),
|
|
85
75
|
],
|
|
86
76
|
)
|
|
@@ -114,7 +114,7 @@ wbportfolio/import_export/backends/wbfdm/dividend.py,sha256=iAQXnYPXmtG_Jrc8THAJ
|
|
|
114
114
|
wbportfolio/import_export/backends/wbfdm/mixin.py,sha256=JNtjgqGLson1nu_Chqb8MWyuiF3Ws8ox2vapxIRBYKE,400
|
|
115
115
|
wbportfolio/import_export/handlers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
116
116
|
wbportfolio/import_export/handlers/adjustment.py,sha256=6bdTIYFmc8_HFxcdwtnYwglMyCfAD8XrTIrEb2zWY0g,1757
|
|
117
|
-
wbportfolio/import_export/handlers/asset_position.py,sha256=
|
|
117
|
+
wbportfolio/import_export/handlers/asset_position.py,sha256=fj9ywxvfQfyQi7RZC5NmeKb4hb18atx0P8QHmnrc0Ks,8692
|
|
118
118
|
wbportfolio/import_export/handlers/dividend.py,sha256=tftdVdAzNpKSSvouOtvJfzWL362HUPIC94F6Noha8CE,3998
|
|
119
119
|
wbportfolio/import_export/handlers/fees.py,sha256=lZvxPBDHa3cmmQ4KJwBSPWfUXKdj1X8CDfNTpGQwJcI,2823
|
|
120
120
|
wbportfolio/import_export/handlers/portfolio_cash_flow.py,sha256=WsDAJoBvZ_Lw4X88jYA7JbM3h7nxP-K1qT6z0AIEyy4,2732
|
|
@@ -292,7 +292,7 @@ wbportfolio/risk_management/backends/instrument_list_portfolio.py,sha256=TD8xt9H
|
|
|
292
292
|
wbportfolio/risk_management/backends/liquidity_risk.py,sha256=KNumGhZVP82tjO_IyqTVZTLGkJFtEOQUEQsVj7ZNK0o,3687
|
|
293
293
|
wbportfolio/risk_management/backends/liquidity_stress_instrument.py,sha256=PusnD3Xkmsm2E75LDWB2E9JMJikD1bX86XlgWCnr3d4,3611
|
|
294
294
|
wbportfolio/risk_management/backends/mixins.py,sha256=79azRuBxCSDmLOOwOwRiAvHzsGe79K0lJW9yX6ze8sQ,9452
|
|
295
|
-
wbportfolio/risk_management/backends/product_integrity.py,sha256=
|
|
295
|
+
wbportfolio/risk_management/backends/product_integrity.py,sha256=4U_dodoZfRtuC9WaIsHc1u_9pvixV3ReRpbK4-72HB8,4366
|
|
296
296
|
wbportfolio/risk_management/backends/stop_loss_instrument.py,sha256=-RhvKJzzy1_Wd5X97ZTN-Ou8nOSc0dfp9mWAmgNS5tE,1127
|
|
297
297
|
wbportfolio/risk_management/backends/stop_loss_portfolio.py,sha256=nEx5U6ao-qptuPMb75MjwFSxY9d1oLBa8LAaGOIN6jY,1673
|
|
298
298
|
wbportfolio/risk_management/backends/ucits_portfolio.py,sha256=lnQNIngc9Tsni6irYIqTP_IERS1ErLlA5Te1MYsDeRw,3365
|
|
@@ -303,7 +303,7 @@ wbportfolio/risk_management/tests/test_controversy_portfolio.py,sha256=EMOn5VLNP
|
|
|
303
303
|
wbportfolio/risk_management/tests/test_exposure_portfolio.py,sha256=PUt7ZkHKSXQ79utA-wmBjP4Onp0r8Aggosk2tgvYgVk,3511
|
|
304
304
|
wbportfolio/risk_management/tests/test_instrument_list_portfolio.py,sha256=b5xiFc3O5pZ2Rsnrr6qtWPxGOpwPU7g-WiAIOUq2B3o,2762
|
|
305
305
|
wbportfolio/risk_management/tests/test_liquidity_risk.py,sha256=cPBk0trd-Eo6bypPDNNERVM7dQGstcci2kmn_hd6_ss,1712
|
|
306
|
-
wbportfolio/risk_management/tests/test_product_integrity.py,sha256=
|
|
306
|
+
wbportfolio/risk_management/tests/test_product_integrity.py,sha256=5xxXVvrGxdkrA7Tio7lojzva-FKe4zIe5GwqSjKqJsE,1958
|
|
307
307
|
wbportfolio/risk_management/tests/test_stop_loss_instrument.py,sha256=Crt8dQjPKvmvgdd7_OMGchTHwcV8zP5-wun5P0W_-aw,4196
|
|
308
308
|
wbportfolio/risk_management/tests/test_stop_loss_portfolio.py,sha256=VCsawHAVfSHvG13bFANZzJRuKfcrxVZUKsbbXEweSpY,4594
|
|
309
309
|
wbportfolio/risk_management/tests/test_ucits_portfolio.py,sha256=zZLBILyWGyiYs7gsVanXWCd1i699-PujDiunj_vfkHo,1806
|
|
@@ -422,7 +422,7 @@ wbportfolio/viewsets/configs/display/adjustments.py,sha256=L91jfYhGT7g1QyK3M1f4F
|
|
|
422
422
|
wbportfolio/viewsets/configs/display/assets.py,sha256=3rZJgLZ26fusN2Ik3O4TnXhpoGl8vSQ3BCCp6Xyyok8,10932
|
|
423
423
|
wbportfolio/viewsets/configs/display/claim.py,sha256=w3CXiU2qEgyVY7NSjfsM6rF9tTm1rEmJXFWAVwTkRCw,12040
|
|
424
424
|
wbportfolio/viewsets/configs/display/custodians.py,sha256=R-tnktfY48K-8Zz-Fg_M6IXKHv42J1ZeSpom7lvYVS8,801
|
|
425
|
-
wbportfolio/viewsets/configs/display/esg.py,sha256=
|
|
425
|
+
wbportfolio/viewsets/configs/display/esg.py,sha256=W8uetCPN2TjHtU2kvQjKOmkq7uoaYvzX2iLN6Nz78Pk,3111
|
|
426
426
|
wbportfolio/viewsets/configs/display/fees.py,sha256=_8HDJADh5bA5VMVPkhKObPmNNdPHWR8Oz23PEgd04F0,5834
|
|
427
427
|
wbportfolio/viewsets/configs/display/portfolio_cash_flow.py,sha256=CS_UGhKZSXnX-0SZ0RXzbG1WMJm6NX3GUljwIa4RWBk,5025
|
|
428
428
|
wbportfolio/viewsets/configs/display/portfolio_relationship.py,sha256=8DvsYWFCX29qj5wUf1wCtjlPwzKRd_E7JDuo_CopaJ0,1294
|
|
@@ -500,7 +500,7 @@ wbportfolio/viewsets/transactions/mixins.py,sha256=i9ICaUXZfryIrbgS-bdCcoBJO-pTn
|
|
|
500
500
|
wbportfolio/viewsets/transactions/trade_proposals.py,sha256=5mgAk60cINZHd2HfTu7StFOc882FGakNcIVZpNSwBCs,3528
|
|
501
501
|
wbportfolio/viewsets/transactions/trades.py,sha256=_rZuPRDjf3MbwZ5xvdCgczCxcIbvI-RvyAf-50Y_Ga4,14744
|
|
502
502
|
wbportfolio/viewsets/transactions/transactions.py,sha256=VgSBUs1g5etsXjt7zi4wQi82XwOGuHsd_zppnsbMZMs,4517
|
|
503
|
-
wbportfolio-1.
|
|
504
|
-
wbportfolio-1.
|
|
505
|
-
wbportfolio-1.
|
|
506
|
-
wbportfolio-1.
|
|
503
|
+
wbportfolio-1.44.1.dist-info/METADATA,sha256=C8XJhmd9qFLEqDHA1Gjxx9smfA8wIKu9PXyCSyr6xDg,645
|
|
504
|
+
wbportfolio-1.44.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
505
|
+
wbportfolio-1.44.1.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
506
|
+
wbportfolio-1.44.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|