wbportfolio 1.44.5__py2.py3-none-any.whl → 1.45.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/admin/__init__.py +1 -1
- wbportfolio/admin/asset.py +2 -1
- wbportfolio/admin/custodians.py +1 -0
- wbportfolio/admin/indexes.py +15 -0
- wbportfolio/admin/portfolio.py +12 -7
- wbportfolio/admin/portfolio_relationships.py +1 -0
- wbportfolio/admin/product_groups.py +2 -0
- wbportfolio/admin/products.py +2 -1
- wbportfolio/admin/reconciliations.py +1 -0
- wbportfolio/admin/registers.py +1 -0
- wbportfolio/admin/roles.py +1 -0
- wbportfolio/admin/transactions/__init__.py +1 -0
- wbportfolio/admin/transactions/claim.py +1 -0
- wbportfolio/admin/transactions/dividends.py +1 -0
- wbportfolio/admin/transactions/fees.py +1 -0
- wbportfolio/admin/transactions/rebalancing.py +26 -0
- wbportfolio/admin/transactions/trades.py +4 -3
- wbportfolio/admin/transactions/transactions.py +1 -0
- wbportfolio/analysis/claims.py +2 -1
- wbportfolio/contrib/company_portfolio/models.py +3 -6
- wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -12
- wbportfolio/contrib/company_portfolio/tests/test_models.py +1 -0
- wbportfolio/defaults/fees/default.py +1 -0
- wbportfolio/factories/__init__.py +1 -7
- wbportfolio/factories/adjustments.py +1 -0
- wbportfolio/factories/assets.py +13 -7
- wbportfolio/factories/claim.py +1 -0
- wbportfolio/factories/custodians.py +1 -0
- wbportfolio/factories/dividends.py +1 -0
- wbportfolio/factories/fees.py +1 -0
- wbportfolio/factories/indexes.py +1 -0
- wbportfolio/factories/portfolio_cash_flow.py +1 -0
- wbportfolio/factories/portfolio_cash_targets.py +1 -0
- wbportfolio/factories/portfolio_swing_pricings.py +1 -0
- wbportfolio/factories/portfolios.py +3 -0
- wbportfolio/factories/product_groups.py +1 -0
- wbportfolio/factories/products.py +1 -0
- wbportfolio/factories/rebalancing.py +23 -0
- wbportfolio/factories/reconciliations.py +1 -0
- wbportfolio/factories/roles.py +1 -0
- wbportfolio/factories/trades.py +1 -0
- wbportfolio/factories/transactions.py +1 -0
- wbportfolio/fdm/tasks.py +1 -0
- wbportfolio/filters/__init__.py +1 -1
- wbportfolio/filters/assets.py +8 -9
- wbportfolio/filters/assets_and_net_new_money_progression.py +1 -0
- wbportfolio/filters/custodians.py +1 -0
- wbportfolio/filters/esg.py +1 -0
- wbportfolio/filters/performances.py +7 -6
- wbportfolio/filters/portfolios.py +21 -1
- wbportfolio/filters/positions.py +1 -0
- wbportfolio/filters/products.py +1 -0
- wbportfolio/filters/roles.py +1 -0
- wbportfolio/filters/signals.py +1 -0
- wbportfolio/filters/transactions/claim.py +1 -0
- wbportfolio/filters/transactions/fees.py +1 -0
- wbportfolio/filters/transactions/trades.py +2 -1
- wbportfolio/filters/transactions/transactions.py +1 -0
- wbportfolio/import_export/backends/ubs/mixin.py +1 -0
- wbportfolio/import_export/backends/wbfdm/adjustment.py +1 -0
- wbportfolio/import_export/handlers/asset_position.py +11 -13
- wbportfolio/import_export/handlers/fees.py +1 -0
- wbportfolio/import_export/handlers/portfolio_cash_flow.py +1 -0
- wbportfolio/import_export/handlers/trade.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/fees.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/strategy.py +5 -4
- wbportfolio/import_export/parsers/jpmorgan/valuation.py +1 -0
- wbportfolio/import_export/parsers/leonteq/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/leonteq/equity.py +13 -12
- wbportfolio/import_export/parsers/leonteq/fees.py +1 -0
- wbportfolio/import_export/parsers/leonteq/trade.py +1 -0
- wbportfolio/import_export/parsers/leonteq/valuation.py +1 -0
- wbportfolio/import_export/parsers/natixis/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_equity.py +3 -2
- wbportfolio/import_export/parsers/natixis/d1_fees.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_valuation.py +1 -0
- wbportfolio/import_export/parsers/natixis/equity.py +5 -5
- wbportfolio/import_export/parsers/natixis/trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/utils.py +8 -7
- wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +2 -1
- wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +2 -1
- wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/equity.py +7 -8
- wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/registers.py +2 -1
- wbportfolio/import_export/parsers/societe_generale/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/societe_generale/strategy.py +8 -9
- wbportfolio/import_export/parsers/societe_generale/valuation.py +1 -0
- wbportfolio/import_export/parsers/tellco/equity.py +5 -4
- wbportfolio/import_export/parsers/ubs/api/asset_position.py +15 -14
- wbportfolio/import_export/parsers/ubs/api/fees.py +1 -0
- wbportfolio/import_export/parsers/ubs/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/ubs/equity.py +3 -2
- wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/ubs/valuation.py +1 -0
- wbportfolio/import_export/parsers/vontobel/asset_position.py +19 -19
- wbportfolio/import_export/parsers/vontobel/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/management_fees.py +1 -0
- wbportfolio/import_export/parsers/vontobel/performance_fees.py +1 -0
- wbportfolio/import_export/parsers/vontobel/trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/valuation_api.py +23 -0
- wbportfolio/import_export/resources/assets.py +4 -3
- wbportfolio/import_export/resources/trades.py +1 -0
- wbportfolio/metric/backends/base.py +1 -0
- wbportfolio/metric/backends/portfolio_base.py +1 -0
- wbportfolio/metric/backends/portfolio_esg.py +1 -0
- wbportfolio/metric/tests/test_portfolio_base.py +1 -0
- wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +1 -131
- wbportfolio/migrations/0067_assetposition_unique_asset_position.py +1 -1
- wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +1 -1
- wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +407 -0
- wbportfolio/models/__init__.py +0 -5
- wbportfolio/models/adjustments.py +8 -2
- wbportfolio/models/asset.py +117 -98
- wbportfolio/models/graphs/portfolio.py +161 -0
- wbportfolio/models/graphs/utils.py +83 -0
- wbportfolio/models/indexes.py +2 -13
- wbportfolio/models/mixins/instruments.py +28 -8
- wbportfolio/models/portfolio.py +538 -332
- wbportfolio/models/portfolio_cash_flow.py +1 -0
- wbportfolio/models/portfolio_relationship.py +6 -2
- wbportfolio/models/product_groups.py +3 -2
- wbportfolio/models/products.py +3 -17
- wbportfolio/models/reconciliations/account_reconciliation_lines.py +1 -0
- wbportfolio/models/reconciliations/account_reconciliations.py +1 -0
- wbportfolio/models/registers.py +1 -0
- wbportfolio/models/transactions/__init__.py +1 -0
- wbportfolio/models/transactions/claim.py +8 -8
- wbportfolio/models/transactions/dividends.py +1 -0
- wbportfolio/models/transactions/fees.py +1 -0
- wbportfolio/models/transactions/rebalancing.py +153 -0
- wbportfolio/models/transactions/trade_proposals.py +153 -155
- wbportfolio/models/transactions/trades.py +48 -40
- wbportfolio/models/transactions/transactions.py +6 -12
- wbportfolio/models/utils.py +1 -0
- wbportfolio/pms/analytics/__init__.py +0 -0
- wbportfolio/pms/analytics/portfolio.py +28 -0
- wbportfolio/pms/trading/handler.py +13 -16
- wbportfolio/pms/typing.py +13 -29
- wbportfolio/rebalancing/__init__.py +0 -0
- wbportfolio/rebalancing/base.py +16 -0
- wbportfolio/rebalancing/decorators.py +17 -0
- wbportfolio/rebalancing/models/__init__.py +3 -0
- wbportfolio/rebalancing/models/composite.py +31 -0
- wbportfolio/rebalancing/models/equally_weighted.py +21 -0
- wbportfolio/rebalancing/models/model_portfolio.py +35 -0
- wbportfolio/reports/monthly_position_report.py +1 -1
- wbportfolio/risk_management/backends/accounts.py +7 -6
- wbportfolio/risk_management/backends/controversy_portfolio.py +1 -0
- wbportfolio/risk_management/backends/exposure_portfolio.py +1 -0
- wbportfolio/risk_management/backends/instrument_list_portfolio.py +1 -0
- wbportfolio/risk_management/backends/liquidity_risk.py +1 -0
- wbportfolio/risk_management/backends/liquidity_stress_instrument.py +1 -0
- wbportfolio/risk_management/backends/mixins.py +1 -0
- wbportfolio/risk_management/backends/product_integrity.py +6 -1
- wbportfolio/risk_management/backends/stop_loss_instrument.py +1 -0
- wbportfolio/risk_management/backends/stop_loss_portfolio.py +1 -0
- wbportfolio/risk_management/backends/ucits_portfolio.py +12 -5
- wbportfolio/risk_management/tests/test_accounts.py +1 -0
- wbportfolio/risk_management/tests/test_controversy_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_liquidity_risk.py +1 -0
- wbportfolio/risk_management/tests/test_product_integrity.py +1 -0
- wbportfolio/risk_management/tests/test_stop_loss_instrument.py +1 -0
- wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_ucits_portfolio.py +2 -1
- wbportfolio/serializers/__init__.py +5 -5
- wbportfolio/serializers/adjustments.py +1 -0
- wbportfolio/serializers/assets.py +18 -19
- wbportfolio/serializers/custodians.py +1 -0
- wbportfolio/serializers/portfolio_cash_flow.py +1 -0
- wbportfolio/serializers/portfolio_cash_targets.py +1 -0
- wbportfolio/serializers/portfolio_relationship.py +1 -0
- wbportfolio/serializers/portfolio_swing_pricing.py +1 -0
- wbportfolio/serializers/portfolios.py +61 -40
- wbportfolio/serializers/positions.py +1 -0
- wbportfolio/serializers/product_group.py +1 -0
- wbportfolio/serializers/products.py +4 -7
- wbportfolio/serializers/rebalancing.py +57 -0
- wbportfolio/serializers/reconciliations.py +2 -1
- wbportfolio/serializers/registers.py +1 -0
- wbportfolio/serializers/roles.py +1 -0
- wbportfolio/serializers/signals.py +10 -15
- wbportfolio/serializers/transactions/__init__.py +1 -1
- wbportfolio/serializers/transactions/claim.py +1 -0
- wbportfolio/serializers/transactions/fees.py +1 -0
- wbportfolio/serializers/transactions/trade_proposals.py +85 -0
- wbportfolio/serializers/transactions/trades.py +9 -51
- wbportfolio/serializers/transactions/transactions.py +4 -3
- wbportfolio/tasks.py +1 -78
- wbportfolio/tests/conftest.py +6 -13
- wbportfolio/tests/models/test_account_reconciliation.py +2 -0
- wbportfolio/tests/models/test_assets.py +27 -19
- wbportfolio/tests/models/test_customer_trades.py +1 -0
- wbportfolio/tests/models/test_imports.py +5 -1
- wbportfolio/tests/models/test_merge.py +5 -4
- wbportfolio/tests/models/test_portfolio_cash_flow.py +8 -6
- wbportfolio/tests/models/test_portfolios.py +619 -154
- wbportfolio/tests/models/test_product_groups.py +1 -0
- wbportfolio/tests/models/test_products.py +6 -3
- wbportfolio/tests/models/test_roles.py +1 -0
- wbportfolio/tests/models/test_splits.py +1 -0
- wbportfolio/tests/models/transactions/test_claim.py +1 -0
- wbportfolio/tests/models/transactions/test_fees.py +1 -0
- wbportfolio/tests/models/transactions/test_rebalancing.py +81 -0
- wbportfolio/tests/models/transactions/test_trades.py +1 -0
- wbportfolio/tests/models/utils.py +1 -0
- wbportfolio/tests/pms/__init__.py +0 -0
- wbportfolio/tests/pms/test_analytics.py +35 -0
- wbportfolio/tests/rebalancing/__init__.py +0 -0
- wbportfolio/tests/rebalancing/test_models.py +127 -0
- wbportfolio/tests/serializers/test_claims.py +1 -0
- wbportfolio/tests/signals.py +1 -7
- wbportfolio/tests/tests.py +2 -0
- wbportfolio/tests/viewsets/test_assets.py +1 -0
- wbportfolio/tests/viewsets/test_performances.py +1 -0
- wbportfolio/tests/viewsets/test_products.py +1 -0
- wbportfolio/tests/viewsets/transactions/test_claims.py +1 -0
- wbportfolio/urls.py +26 -12
- wbportfolio/viewsets/__init__.py +2 -5
- wbportfolio/viewsets/adjustments.py +1 -0
- wbportfolio/viewsets/assets.py +62 -51
- wbportfolio/viewsets/assets_and_net_new_money_progression.py +1 -0
- wbportfolio/viewsets/charts/assets.py +3 -1
- wbportfolio/viewsets/configs/buttons/__init__.py +1 -1
- wbportfolio/viewsets/configs/buttons/assets.py +1 -0
- wbportfolio/viewsets/configs/buttons/custodians.py +1 -0
- wbportfolio/viewsets/configs/buttons/mixins.py +1 -20
- wbportfolio/viewsets/configs/buttons/portfolios.py +90 -76
- wbportfolio/viewsets/configs/buttons/signals.py +1 -0
- wbportfolio/viewsets/configs/buttons/trades.py +1 -0
- wbportfolio/viewsets/configs/display/__init__.py +2 -1
- wbportfolio/viewsets/configs/display/adjustments.py +1 -0
- wbportfolio/viewsets/configs/display/assets.py +7 -6
- wbportfolio/viewsets/configs/display/claim.py +1 -0
- wbportfolio/viewsets/configs/display/portfolios.py +127 -79
- wbportfolio/viewsets/configs/display/product_performance.py +1 -0
- wbportfolio/viewsets/configs/display/rebalancing.py +27 -0
- wbportfolio/viewsets/configs/display/trade_proposals.py +7 -4
- wbportfolio/viewsets/configs/display/trades.py +75 -42
- wbportfolio/viewsets/configs/endpoints/__init__.py +3 -1
- wbportfolio/viewsets/configs/endpoints/assets.py +12 -0
- wbportfolio/viewsets/configs/endpoints/claim.py +1 -0
- wbportfolio/viewsets/configs/endpoints/portfolios.py +23 -7
- wbportfolio/viewsets/configs/endpoints/rebalancing.py +6 -0
- wbportfolio/viewsets/configs/endpoints/reconciliations.py +1 -0
- wbportfolio/viewsets/configs/endpoints/trade_proposals.py +1 -0
- wbportfolio/viewsets/configs/endpoints/trades.py +1 -0
- wbportfolio/viewsets/configs/menu/adjustments.py +1 -0
- wbportfolio/viewsets/configs/menu/assets.py +1 -0
- wbportfolio/viewsets/configs/menu/fees.py +1 -0
- wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +1 -0
- wbportfolio/viewsets/configs/menu/portfolios.py +4 -2
- wbportfolio/viewsets/configs/menu/positions.py +1 -0
- wbportfolio/viewsets/configs/menu/roles.py +1 -0
- wbportfolio/viewsets/configs/menu/transactions.py +1 -0
- wbportfolio/viewsets/configs/previews/portfolios.py +1 -6
- wbportfolio/viewsets/configs/titles/__init__.py +1 -1
- wbportfolio/viewsets/configs/titles/assets.py +1 -0
- wbportfolio/viewsets/configs/titles/fees.py +1 -0
- wbportfolio/viewsets/configs/titles/instrument_prices.py +1 -0
- wbportfolio/viewsets/configs/titles/portfolios.py +13 -11
- wbportfolio/viewsets/configs/titles/roles.py +1 -0
- wbportfolio/viewsets/configs/titles/trades.py +1 -0
- wbportfolio/viewsets/configs/titles/transactions.py +1 -0
- wbportfolio/viewsets/custodians.py +1 -0
- wbportfolio/viewsets/esg.py +1 -0
- wbportfolio/viewsets/mixins.py +1 -0
- wbportfolio/viewsets/portfolio_cash_flow.py +1 -0
- wbportfolio/viewsets/portfolio_cash_targets.py +1 -0
- wbportfolio/viewsets/portfolio_relationship.py +1 -0
- wbportfolio/viewsets/portfolio_swing_pricing.py +1 -0
- wbportfolio/viewsets/portfolios.py +228 -61
- wbportfolio/viewsets/positions.py +3 -2
- wbportfolio/viewsets/product_groups.py +1 -0
- wbportfolio/viewsets/product_performance.py +1 -0
- wbportfolio/viewsets/products.py +1 -0
- wbportfolio/viewsets/reconciliations.py +1 -0
- wbportfolio/viewsets/registers.py +1 -0
- wbportfolio/viewsets/roles.py +1 -0
- wbportfolio/viewsets/signals.py +1 -0
- wbportfolio/viewsets/transactions/__init__.py +1 -0
- wbportfolio/viewsets/transactions/claim.py +2 -1
- wbportfolio/viewsets/transactions/fees.py +1 -0
- wbportfolio/viewsets/transactions/mixins.py +1 -0
- wbportfolio/viewsets/transactions/rebalancing.py +31 -0
- wbportfolio/viewsets/transactions/trade_proposals.py +25 -5
- wbportfolio/viewsets/transactions/trades.py +16 -9
- wbportfolio/viewsets/transactions/transactions.py +1 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.1.dist-info}/METADATA +4 -1
- wbportfolio-1.45.1.dist-info/RECORD +521 -0
- wbportfolio/admin/synchronization/__init__.py +0 -2
- wbportfolio/admin/synchronization/admin.py +0 -114
- wbportfolio/admin/synchronization/portfolio_synchronization.py +0 -18
- wbportfolio/admin/synchronization/price_computation.py +0 -21
- wbportfolio/defaults/portfolio/default_rebalancing.py +0 -45
- wbportfolio/factories/pytest_utils.py +0 -121
- wbportfolio/factories/synchronization.py +0 -40
- wbportfolio/models/synchronization/__init__.py +0 -3
- wbportfolio/models/synchronization/portfolio_synchronization.py +0 -292
- wbportfolio/models/synchronization/price_computation.py +0 -200
- wbportfolio/models/synchronization/synchronization.py +0 -188
- wbportfolio/serializers/synchronization.py +0 -18
- wbportfolio/tests/models/test_synchronization.py +0 -617
- wbportfolio/viewsets/synchronization.py +0 -25
- wbportfolio-1.44.5.dist-info/RECORD +0 -508
- /wbportfolio/{defaults/portfolio → models/graphs}/__init__.py +0 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.1.dist-info}/WHEEL +0 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -11,6 +11,7 @@ from wbcore.contrib.directory.models import Entry
|
|
|
11
11
|
from wbcrm.models import Account
|
|
12
12
|
from wbfdm.models import Classification
|
|
13
13
|
from wbfdm.preferences import get_default_classification_group
|
|
14
|
+
|
|
14
15
|
from wbportfolio.analysis.claims import ConsolidatedTradeSummary
|
|
15
16
|
from wbportfolio.models import Product, ProductGroup
|
|
16
17
|
from wbportfolio.models.transactions.claim import Claim, ClaimGroupbyChoice
|
|
@@ -149,13 +150,13 @@ class RuleBackend(backend.AbstractRuleBackend):
|
|
|
149
150
|
}
|
|
150
151
|
color = "red" if percentage < 0 else "green"
|
|
151
152
|
if self.field == "AUM":
|
|
152
|
-
report_details[
|
|
153
|
-
"
|
|
154
|
-
|
|
153
|
+
report_details["AUM Change"] = (
|
|
154
|
+
f'<span style="color:{color}">{start_df.loc[breached_obj_id]:.0f} $ → {end_df.loc[breached_obj_id]:.0f} $</span>'
|
|
155
|
+
)
|
|
155
156
|
else:
|
|
156
|
-
report_details[
|
|
157
|
-
"
|
|
158
|
-
|
|
157
|
+
report_details["Shares Change"] = (
|
|
158
|
+
f"<span style='color:{color}'>{start_df.loc[breached_obj_id]:.0f} → {end_df.loc[breached_obj_id]:.0f}</span>"
|
|
159
|
+
)
|
|
159
160
|
report_details["Group By"] = self.group_by.value
|
|
160
161
|
yield backend.IncidentResult(
|
|
161
162
|
breached_object=breached_obj,
|
|
@@ -7,6 +7,7 @@ from wbcore import serializers as wb_serializers
|
|
|
7
7
|
from wbfdm.enums import ESGControveryFlag
|
|
8
8
|
from wbfdm.models import Instrument
|
|
9
9
|
from wbfdm.models.esg.controversies import Controversy
|
|
10
|
+
|
|
10
11
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
11
12
|
|
|
12
13
|
from .mixins import ActivePortfolioRelationshipMixin
|
|
@@ -8,6 +8,7 @@ from wbfdm.models import Instrument, InstrumentList, InstrumentListThroughModel
|
|
|
8
8
|
from wbfdm.serializers.instruments.instrument_lists import (
|
|
9
9
|
InstrumentListRepresentationSerializer,
|
|
10
10
|
)
|
|
11
|
+
|
|
11
12
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
12
13
|
|
|
13
14
|
from .mixins import ActivePortfolioRelationshipMixin
|
|
@@ -9,6 +9,7 @@ from wbcompliance.models.risk_management import backend
|
|
|
9
9
|
from wbcompliance.models.risk_management.dispatch import register
|
|
10
10
|
from wbcore import serializers as wb_serializers
|
|
11
11
|
from wbfdm.models import Instrument, InstrumentPrice
|
|
12
|
+
|
|
12
13
|
from wbportfolio.models import AssetPosition
|
|
13
14
|
|
|
14
15
|
|
|
@@ -6,6 +6,7 @@ from wbcompliance.models.risk_management.dispatch import register
|
|
|
6
6
|
from wbcore import serializers as wb_serializers
|
|
7
7
|
from wbcore.serializers.fields.number import percent_decorator
|
|
8
8
|
from wbfdm.models import Instrument
|
|
9
|
+
|
|
9
10
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
10
11
|
|
|
11
12
|
from .mixins import ActiveProductRelationshipMixin
|
|
@@ -7,6 +7,7 @@ from wbcompliance.models.risk_management import backend
|
|
|
7
7
|
from wbcompliance.models.risk_management.dispatch import register
|
|
8
8
|
from wbcore import serializers as wb_serializers
|
|
9
9
|
from wbfdm.models import InstrumentPrice
|
|
10
|
+
|
|
10
11
|
from wbportfolio.models import AssetPosition, Product
|
|
11
12
|
|
|
12
13
|
|
|
@@ -21,7 +22,11 @@ class RuleBackend(backend.AbstractRuleBackend):
|
|
|
21
22
|
product: Product
|
|
22
23
|
|
|
23
24
|
def is_passive_evaluation_valid(self) -> bool:
|
|
24
|
-
return
|
|
25
|
+
return (
|
|
26
|
+
self.product.is_active_at_date(self.evaluation_date)
|
|
27
|
+
and AssetPosition.objects.filter(is_estimated=False, portfolio=self.product.portfolio).exists()
|
|
28
|
+
and InstrumentPrice.objects.filter(calculated=False, instrument=self.product).exists()
|
|
29
|
+
)
|
|
25
30
|
|
|
26
31
|
@classmethod
|
|
27
32
|
def get_allowed_content_type(cls) -> "ContentType":
|
|
@@ -2,6 +2,7 @@ from typing import Generator
|
|
|
2
2
|
|
|
3
3
|
from wbcompliance.models.risk_management import backend
|
|
4
4
|
from wbcompliance.models.risk_management.dispatch import register
|
|
5
|
+
|
|
5
6
|
from wbportfolio.pms.typing import Valuation as ValuationDTO
|
|
6
7
|
|
|
7
8
|
from .mixins import ActiveProductRelationshipMixin, StopLossMixin
|
|
@@ -2,6 +2,7 @@ from typing import Generator
|
|
|
2
2
|
|
|
3
3
|
from wbcompliance.models.risk_management import backend
|
|
4
4
|
from wbcompliance.models.risk_management.dispatch import register
|
|
5
|
+
|
|
5
6
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
6
7
|
from wbportfolio.pms.typing import Valuation as ValuationDTO
|
|
7
8
|
|
|
@@ -7,6 +7,7 @@ from wbcompliance.models.risk_management.dispatch import register
|
|
|
7
7
|
from wbcore import serializers as wb_serializers
|
|
8
8
|
from wbcore.serializers.fields.number import percent_decorator
|
|
9
9
|
from wbfdm.models import Instrument
|
|
10
|
+
|
|
10
11
|
from wbportfolio.pms.typing import Portfolio as PortfolioDTO
|
|
11
12
|
|
|
12
13
|
from .mixins import ActivePortfolioRelationshipMixin
|
|
@@ -45,19 +46,25 @@ class RuleBackend(ActivePortfolioRelationshipMixin, backend.AbstractRuleBackend)
|
|
|
45
46
|
def _process_dto(self, portfolio: PortfolioDTO, **kwargs) -> Generator[backend.IncidentResult, None, None]:
|
|
46
47
|
if not (df := self._filter_df(pd.DataFrame(portfolio.to_df()).astype({"weighting": float}))).empty:
|
|
47
48
|
df = df[["underlying_instrument", "weighting"]].groupby("underlying_instrument").sum()
|
|
48
|
-
total_weight_threshold_1_2 = df
|
|
49
|
+
total_weight_threshold_1_2 = df["weighting"].sum()
|
|
49
50
|
highest_incident_type = RiskIncidentType.objects.order_by("-severity_order").first()
|
|
51
|
+
|
|
50
52
|
for id, row in df.to_dict("index").items():
|
|
51
53
|
if (row["weighting"] > self.threshold_2) or (total_weight_threshold_1_2 > self.threshold_3):
|
|
52
54
|
instrument = Instrument.objects.get(id=id)
|
|
55
|
+
breached_value = f"""
|
|
56
|
+
Sum >= {self.threshold_1:.2%}: {total_weight_threshold_1_2:+.2%}
|
|
57
|
+
"""
|
|
58
|
+
if row["weighting"] > self.threshold_2:
|
|
59
|
+
breached_value += f"<br>Instrument >= {self.threshold_2:.2%}: {instrument.name_repr}"
|
|
53
60
|
yield backend.IncidentResult(
|
|
54
61
|
breached_object=instrument,
|
|
55
62
|
breached_object_repr=str(instrument),
|
|
56
|
-
breached_value=
|
|
63
|
+
breached_value=breached_value,
|
|
57
64
|
report_details={
|
|
58
|
-
"Breach Thresholds": f"{self.threshold_1}|{self.threshold_2}|{self.threshold_3}",
|
|
59
|
-
"Weighting": f"{row['weighting']
|
|
60
|
-
f"Sum of positions
|
|
65
|
+
"Breach Thresholds": f"{self.threshold_1:.2%}|{self.threshold_2:.2%}|{self.threshold_3:.2%}",
|
|
66
|
+
"Weighting": f"{row['weighting']:+.2%}",
|
|
67
|
+
f"Sum of positions > {self.threshold_1:.2%}": f"{total_weight_threshold_1_2:+.2%}",
|
|
61
68
|
},
|
|
62
69
|
severity=highest_incident_type,
|
|
63
70
|
)
|
|
@@ -3,6 +3,7 @@ from faker import Faker
|
|
|
3
3
|
from pandas.tseries.offsets import BDay
|
|
4
4
|
from psycopg.types.range import NumericRange
|
|
5
5
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
6
|
+
|
|
6
7
|
from wbportfolio.models.transactions.claim import ClaimGroupbyChoice
|
|
7
8
|
from wbportfolio.risk_management.backends.accounts import (
|
|
8
9
|
RuleBackend as AccountRuleBackend,
|
|
@@ -4,6 +4,7 @@ import pytest
|
|
|
4
4
|
from faker import Faker
|
|
5
5
|
from psycopg.types.range import NumericRange
|
|
6
6
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
7
|
+
|
|
7
8
|
from wbportfolio.risk_management.backends.exposure_portfolio import (
|
|
8
9
|
RuleBackend as ExposurePortfolioRuleBackend,
|
|
9
10
|
)
|
|
@@ -2,6 +2,7 @@ import pytest
|
|
|
2
2
|
from faker import Faker
|
|
3
3
|
from psycopg.types.range import NumericRange
|
|
4
4
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
5
|
+
|
|
5
6
|
from wbportfolio.risk_management.backends.liquidity_risk import (
|
|
6
7
|
RuleBackend as LiquidityRiskRuleBackend,
|
|
7
8
|
)
|
|
@@ -3,6 +3,7 @@ from faker import Faker
|
|
|
3
3
|
from pandas.tseries.offsets import BDay
|
|
4
4
|
from psycopg.types.range import NumericRange
|
|
5
5
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
6
|
+
|
|
6
7
|
from wbportfolio.risk_management.backends.product_integrity import (
|
|
7
8
|
RuleBackend as ProductRuleBackend,
|
|
8
9
|
)
|
|
@@ -6,6 +6,7 @@ from faker import Faker
|
|
|
6
6
|
from psycopg.types.range import NumericRange
|
|
7
7
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
8
8
|
from wbfdm.models import RelatedInstrumentThroughModel
|
|
9
|
+
|
|
9
10
|
from wbportfolio.risk_management.backends.stop_loss_instrument import (
|
|
10
11
|
RuleBackend as StopLossInstrumentRuleBackend,
|
|
11
12
|
)
|
|
@@ -5,6 +5,7 @@ import pytest
|
|
|
5
5
|
from faker import Faker
|
|
6
6
|
from psycopg.types.range import NumericRange
|
|
7
7
|
from wbcompliance.factories.risk_management import RuleThresholdFactory
|
|
8
|
+
|
|
8
9
|
from wbportfolio.risk_management.backends.stop_loss_instrument import (
|
|
9
10
|
RuleBackend as StopLossInstrumentRuleBackend,
|
|
10
11
|
)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import pytest
|
|
2
2
|
from faker import Faker
|
|
3
|
+
|
|
3
4
|
from wbportfolio.risk_management.backends.ucits_portfolio import (
|
|
4
5
|
RuleBackend as UCITPortfolioRuleBackend,
|
|
5
6
|
)
|
|
@@ -18,7 +19,7 @@ class TestUcitsRuleModel(PortfolioTestMixin):
|
|
|
18
19
|
# Check No single asset can represent more than 10% of the fund's assets;
|
|
19
20
|
asset_position_factory.create(date=weekday, weighting=0.05, portfolio=portfolio)
|
|
20
21
|
asset_position_factory.create(date=weekday, weighting=0.05, portfolio=portfolio)
|
|
21
|
-
a3 = asset_position_factory.create(date=weekday, weighting=0.
|
|
22
|
+
a3 = asset_position_factory.create(date=weekday, weighting=0.15, portfolio=portfolio)
|
|
22
23
|
|
|
23
24
|
res = list(ucits_backend.check_rule())
|
|
24
25
|
assert len(res) == 1
|
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
from .rebalancing import (
|
|
2
|
+
RebalancingModelRepresentationSerializer,
|
|
3
|
+
RebalancerRepresentationSerializer,
|
|
4
|
+
RebalancerModelSerializer,
|
|
5
|
+
)
|
|
1
6
|
from .assets import (
|
|
2
7
|
AssetPositionInstrumentModelSerializer,
|
|
3
8
|
AssetPositionModelSerializer,
|
|
@@ -11,7 +16,6 @@ from .portfolio_relationship import (
|
|
|
11
16
|
InstrumentPortfolioThroughModelSerializer,
|
|
12
17
|
)
|
|
13
18
|
from .portfolios import (
|
|
14
|
-
ModelPortfolioModelSerializer,
|
|
15
19
|
PortfolioModelSerializer,
|
|
16
20
|
PortfolioPortfolioThroughModelSerializer,
|
|
17
21
|
PortfolioRepresentationSerializer,
|
|
@@ -22,10 +26,6 @@ from .positions import AggregatedAssetPositionModelSerializer
|
|
|
22
26
|
from .registers import RegisterModelSerializer, RegisterRepresentationSerializer
|
|
23
27
|
from .roles import PortfolioRoleModelSerializer, PortfolioRoleProjectModelSerializer
|
|
24
28
|
from .signals import *
|
|
25
|
-
from .synchronization import (
|
|
26
|
-
PortfolioSynchronizationRepresentationSerializer,
|
|
27
|
-
PriceComputationRepresentationSerializer,
|
|
28
|
-
)
|
|
29
29
|
from .transactions import *
|
|
30
30
|
from .products import (
|
|
31
31
|
ProductRepresentationSerializer,
|
|
@@ -2,18 +2,17 @@ from wbcore import serializers as wb_serializers
|
|
|
2
2
|
from wbcore.contrib.currency.serializers import CurrencyRepresentationSerializer
|
|
3
3
|
from wbfdm.serializers import InvestableInstrumentRepresentationSerializer
|
|
4
4
|
from wbfdm.serializers.exchanges import ExchangeRepresentationSerializer
|
|
5
|
+
|
|
5
6
|
from wbportfolio.models import AssetPosition, Portfolio
|
|
6
7
|
|
|
7
8
|
from .portfolios import PortfolioRepresentationSerializer
|
|
8
9
|
|
|
9
10
|
|
|
10
11
|
class AssetPositionModelSerializer(wb_serializers.ModelSerializer):
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
source="underlying_instrument", label_key="name"
|
|
16
|
-
)
|
|
12
|
+
underlying_quote_isin = wb_serializers.CharField(read_only=True)
|
|
13
|
+
underlying_quote_ticker = wb_serializers.CharField(read_only=True)
|
|
14
|
+
underlying_quote_name = wb_serializers.CharField(read_only=True)
|
|
15
|
+
_underlying_quote = InvestableInstrumentRepresentationSerializer(source="underlying_quote", label_key="name")
|
|
17
16
|
_currency = CurrencyRepresentationSerializer(source="currency")
|
|
18
17
|
_portfolio = PortfolioRepresentationSerializer(source="portfolio")
|
|
19
18
|
_exchange = ExchangeRepresentationSerializer(source="exchange")
|
|
@@ -70,11 +69,11 @@ class AssetPositionModelSerializer(wb_serializers.ModelSerializer):
|
|
|
70
69
|
"total_value_fx_portfolio",
|
|
71
70
|
"liquidity",
|
|
72
71
|
"is_estimated",
|
|
73
|
-
"
|
|
74
|
-
"
|
|
75
|
-
"
|
|
76
|
-
"
|
|
77
|
-
"
|
|
72
|
+
"underlying_quote_name",
|
|
73
|
+
"underlying_quote_isin",
|
|
74
|
+
"underlying_quote_ticker",
|
|
75
|
+
"underlying_quote",
|
|
76
|
+
"_underlying_quote",
|
|
78
77
|
"_portfolio",
|
|
79
78
|
"_portfolio_created",
|
|
80
79
|
"_exchange",
|
|
@@ -93,11 +92,11 @@ class AssetPositionPortfolioModelSerializer(AssetPositionModelSerializer):
|
|
|
93
92
|
fields = (
|
|
94
93
|
"id",
|
|
95
94
|
"is_estimated",
|
|
96
|
-
"
|
|
97
|
-
"
|
|
98
|
-
"
|
|
99
|
-
"
|
|
100
|
-
"
|
|
95
|
+
"underlying_quote_name",
|
|
96
|
+
"underlying_quote_isin",
|
|
97
|
+
"underlying_quote_ticker",
|
|
98
|
+
"underlying_quote",
|
|
99
|
+
"_underlying_quote",
|
|
101
100
|
"currency",
|
|
102
101
|
"_currency",
|
|
103
102
|
"exchange",
|
|
@@ -128,9 +127,9 @@ class AssetPositionAggregatedPortfolioModelSerializer(AssetPositionPortfolioMode
|
|
|
128
127
|
fields = (
|
|
129
128
|
"id",
|
|
130
129
|
"is_estimated",
|
|
131
|
-
"
|
|
132
|
-
"
|
|
133
|
-
"
|
|
130
|
+
"underlying_quote_isin",
|
|
131
|
+
"underlying_quote_ticker",
|
|
132
|
+
"underlying_quote_name",
|
|
134
133
|
"currency",
|
|
135
134
|
"price",
|
|
136
135
|
"shares",
|
|
@@ -2,6 +2,7 @@ from datetime import date, timedelta
|
|
|
2
2
|
|
|
3
3
|
from rest_framework.exceptions import ValidationError
|
|
4
4
|
from wbcore import serializers
|
|
5
|
+
|
|
5
6
|
from wbportfolio.models.portfolio_cash_flow import DailyPortfolioCashFlow
|
|
6
7
|
from wbportfolio.serializers.portfolios import PortfolioRepresentationSerializer
|
|
7
8
|
|
|
@@ -7,6 +7,7 @@ from wbfdm.serializers import (
|
|
|
7
7
|
from wbfdm.serializers.instruments.classifications import (
|
|
8
8
|
ClassificationGroupRepresentationSerializer,
|
|
9
9
|
)
|
|
10
|
+
|
|
10
11
|
from wbportfolio.models.portfolio_relationship import (
|
|
11
12
|
InstrumentPortfolioThroughModel,
|
|
12
13
|
PortfolioInstrumentPreferredClassificationThroughModel,
|
|
@@ -2,13 +2,15 @@ from rest_framework.reverse import reverse
|
|
|
2
2
|
from wbcore import serializers as wb_serializers
|
|
3
3
|
from wbcore.contrib.currency.serializers import CurrencyRepresentationSerializer
|
|
4
4
|
from wbcore.contrib.directory.models import BankingContact
|
|
5
|
+
|
|
5
6
|
from wbportfolio.models import Portfolio, PortfolioPortfolioThroughModel
|
|
6
|
-
from wbportfolio.serializers.
|
|
7
|
-
PortfolioSynchronizationRepresentationSerializer,
|
|
8
|
-
)
|
|
7
|
+
from wbportfolio.serializers.rebalancing import RebalancerRepresentationSerializer
|
|
9
8
|
|
|
10
9
|
|
|
11
10
|
class PortfolioRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
11
|
+
def get_filter_params(self, request):
|
|
12
|
+
return {"is_tracked": True}
|
|
13
|
+
|
|
12
14
|
_detail = wb_serializers.HyperlinkField(reverse_name="wbportfolio:portfolio-detail")
|
|
13
15
|
_detail_preview = wb_serializers.HyperlinkField(reverse_name="wbportfolio:portfolio-detail")
|
|
14
16
|
|
|
@@ -20,11 +22,17 @@ class PortfolioRepresentationSerializer(wb_serializers.RepresentationSerializer)
|
|
|
20
22
|
class PortfolioModelSerializer(wb_serializers.ModelSerializer):
|
|
21
23
|
_currency = CurrencyRepresentationSerializer(source="currency")
|
|
22
24
|
_depends_on = PortfolioRepresentationSerializer(source="depends_on", many=True)
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
)
|
|
27
|
-
|
|
25
|
+
automatic_rebalancer = wb_serializers.PrimaryKeyRelatedField(read_only=True)
|
|
26
|
+
_automatic_rebalancer = RebalancerRepresentationSerializer(source="automatic_rebalancer")
|
|
27
|
+
|
|
28
|
+
create_index = wb_serializers.BooleanField(write_only=True, default=False)
|
|
29
|
+
|
|
30
|
+
def create(self, validated_data):
|
|
31
|
+
create_index = validated_data.pop("create_index", False)
|
|
32
|
+
obj = super().create(validated_data)
|
|
33
|
+
if create_index:
|
|
34
|
+
obj.get_or_create_index()
|
|
35
|
+
return obj
|
|
28
36
|
|
|
29
37
|
@wb_serializers.register_only_instance_resource()
|
|
30
38
|
def cash_management(self, instance, request, user, **kwargs):
|
|
@@ -36,9 +44,9 @@ class PortfolioModelSerializer(wb_serializers.ModelSerializer):
|
|
|
36
44
|
b = BankingContact.objects.filter(wbportfolio_products__id__in=instance.instruments.all().values("id"))
|
|
37
45
|
if b.exists():
|
|
38
46
|
base_url = reverse("wbaccounting:futurecashflow-list", request=request)
|
|
39
|
-
additional_resources[
|
|
40
|
-
"
|
|
41
|
-
|
|
47
|
+
additional_resources["cash_flow"] = (
|
|
48
|
+
f'{base_url}?banking_contact={",".join([str(i) for i in b.distinct("id").values_list("id", flat=True)])}'
|
|
49
|
+
)
|
|
42
50
|
|
|
43
51
|
return additional_resources
|
|
44
52
|
|
|
@@ -67,22 +75,11 @@ class PortfolioModelSerializer(wb_serializers.ModelSerializer):
|
|
|
67
75
|
request=request,
|
|
68
76
|
)
|
|
69
77
|
|
|
70
|
-
if instance.portfolio_synchronization:
|
|
71
|
-
additional_resources["resynchronize"] = reverse(
|
|
72
|
-
"wbportfolio:portfolio-resynchronize",
|
|
73
|
-
args=[instance.id],
|
|
74
|
-
request=request,
|
|
75
|
-
)
|
|
76
78
|
additional_resources["dependencyportfolios"] = reverse(
|
|
77
79
|
"wbportfolio:portfolio-dependencyportfolio-list",
|
|
78
80
|
args=[instance.id],
|
|
79
81
|
request=request,
|
|
80
82
|
)
|
|
81
|
-
additional_resources["trade_proposals"] = reverse(
|
|
82
|
-
"wbportfolio:portfolio-tradeproposal-list",
|
|
83
|
-
args=[instance.id],
|
|
84
|
-
request=request,
|
|
85
|
-
)
|
|
86
83
|
|
|
87
84
|
additional_resources["preferredclassification"] = reverse(
|
|
88
85
|
"wbportfolio:portfolio-preferredclassification-list",
|
|
@@ -94,7 +91,38 @@ class PortfolioModelSerializer(wb_serializers.ModelSerializer):
|
|
|
94
91
|
args=[instance.id],
|
|
95
92
|
request=request,
|
|
96
93
|
)
|
|
97
|
-
|
|
94
|
+
additional_resources["trade_proposals"] = reverse(
|
|
95
|
+
"wbportfolio:portfolio-tradeproposal-list",
|
|
96
|
+
args=[instance.id],
|
|
97
|
+
request=request,
|
|
98
|
+
)
|
|
99
|
+
additional_resources["rebalance"] = reverse(
|
|
100
|
+
"wbportfolio:portfolio-rebalance",
|
|
101
|
+
args=[instance.id],
|
|
102
|
+
request=request,
|
|
103
|
+
)
|
|
104
|
+
if not getattr(instance, "automatic_rebalancer", None):
|
|
105
|
+
additional_resources["add_automatic_rebalancer"] = reverse(
|
|
106
|
+
"wbportfolio:portfolio-attachrebalancer",
|
|
107
|
+
args=[instance.id],
|
|
108
|
+
request=request,
|
|
109
|
+
)
|
|
110
|
+
if user.is_superuser and instance.is_lookthrough:
|
|
111
|
+
additional_resources["recompute_lookthrough"] = reverse(
|
|
112
|
+
"wbportfolio:portfolio-recomputelookthrough",
|
|
113
|
+
args=[instance.id],
|
|
114
|
+
request=request,
|
|
115
|
+
)
|
|
116
|
+
additional_resources["treegraphchart"] = reverse(
|
|
117
|
+
"wbportfolio:portfolio-treegraphchart-list",
|
|
118
|
+
args=[instance.id],
|
|
119
|
+
request=request,
|
|
120
|
+
)
|
|
121
|
+
additional_resources["topdowncomposition"] = reverse(
|
|
122
|
+
"wbportfolio:portfolio-topdowncomposition-list",
|
|
123
|
+
args=[instance.id],
|
|
124
|
+
request=request,
|
|
125
|
+
)
|
|
98
126
|
return additional_resources
|
|
99
127
|
|
|
100
128
|
class Meta:
|
|
@@ -102,31 +130,24 @@ class PortfolioModelSerializer(wb_serializers.ModelSerializer):
|
|
|
102
130
|
fields = (
|
|
103
131
|
"id",
|
|
104
132
|
"name",
|
|
105
|
-
"
|
|
133
|
+
"updated_at",
|
|
106
134
|
"_depends_on",
|
|
107
|
-
"_portfolio_synchronization",
|
|
108
135
|
"depends_on",
|
|
109
|
-
"portfolio_synchronization",
|
|
110
|
-
"_dependent_portfolios",
|
|
111
|
-
"dependent_portfolios",
|
|
112
136
|
"_currency",
|
|
113
137
|
"currency",
|
|
138
|
+
"automatic_rebalancer",
|
|
139
|
+
"_automatic_rebalancer",
|
|
140
|
+
"invested_timespan",
|
|
141
|
+
"is_manageable",
|
|
142
|
+
"is_tracked",
|
|
143
|
+
"only_weighting",
|
|
144
|
+
"is_lookthrough",
|
|
145
|
+
"is_composition",
|
|
114
146
|
"_additional_resources",
|
|
147
|
+
"create_index",
|
|
115
148
|
)
|
|
116
149
|
|
|
117
150
|
|
|
118
|
-
class ModelPortfolioModelSerializer(PortfolioModelSerializer):
|
|
119
|
-
@wb_serializers.register_only_instance_resource()
|
|
120
|
-
def rebalance(self, instance, request, user, **kwargs):
|
|
121
|
-
return {
|
|
122
|
-
"modelcomposition": reverse(
|
|
123
|
-
"wbportfolio:portfolio-modelcompositionpandas-list",
|
|
124
|
-
args=[instance.id],
|
|
125
|
-
request=request,
|
|
126
|
-
)
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
|
|
130
151
|
class PortfolioPortfolioThroughModelSerializer(wb_serializers.ModelSerializer):
|
|
131
152
|
_portfolio = PortfolioRepresentationSerializer(source="portfolio")
|
|
132
153
|
_dependency_portfolio = PortfolioRepresentationSerializer(source="dependency_portfolio")
|
|
@@ -3,6 +3,7 @@ from wbcore.contrib.directory.models import Company
|
|
|
3
3
|
from wbcore.contrib.directory.serializers import CompanyRepresentationSerializer
|
|
4
4
|
from wbcore.contrib.geography.serializers import GeographyRepresentationSerializer
|
|
5
5
|
from wbfdm.serializers.instruments import InstrumentModelSerializer
|
|
6
|
+
|
|
6
7
|
from wbportfolio.models import ProductGroup, ProductGroupRepresentant
|
|
7
8
|
from wbportfolio.serializers.portfolios import PortfolioRepresentationSerializer
|
|
8
9
|
|
|
@@ -11,11 +11,11 @@ from wbcore.contrib.directory.serializers import (
|
|
|
11
11
|
from wbcore.contrib.geography.serializers import GeographyRepresentationSerializer
|
|
12
12
|
from wbfdm.models import Instrument
|
|
13
13
|
from wbfdm.serializers.instruments.instruments import InstrumentModelSerializer
|
|
14
|
+
|
|
14
15
|
from wbportfolio.models import Portfolio, Product
|
|
15
16
|
from wbportfolio.serializers.portfolios import PortfolioRepresentationSerializer
|
|
16
17
|
|
|
17
18
|
from .product_group import ProductGroupRepresentationSerializer
|
|
18
|
-
from .synchronization import PriceComputationRepresentationSerializer
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
class ProductRepresentationSerializer(wb_serializers.RepresentationSerializer):
|
|
@@ -179,16 +179,15 @@ class ProductModelSerializer(ProductListModelSerializer):
|
|
|
179
179
|
is_next_factsheet_available = wb_serializers.BooleanField(default=False, read_only=True)
|
|
180
180
|
|
|
181
181
|
_portfolios = PortfolioRepresentationSerializer(source="portfolios", many=True)
|
|
182
|
-
_price_computation = PriceComputationRepresentationSerializer(source="price_computation")
|
|
183
182
|
|
|
184
183
|
@wb_serializers.register_resource()
|
|
185
184
|
def additional_resources(self, instance, request, user):
|
|
186
185
|
additional_resources = dict()
|
|
187
186
|
|
|
188
187
|
if user.profile.is_internal or user.is_superuser:
|
|
189
|
-
additional_resources[
|
|
190
|
-
"
|
|
191
|
-
|
|
188
|
+
additional_resources["aum"] = (
|
|
189
|
+
f'{reverse("wbportfolio:aumtable-list", args=[], request=request)}?product={instance.id}&group_by=ACCOUNT'
|
|
190
|
+
)
|
|
192
191
|
additional_resources["claims"] = reverse(
|
|
193
192
|
"wbportfolio:product-claim-list",
|
|
194
193
|
args=[instance.id],
|
|
@@ -248,8 +247,6 @@ class ProductModelSerializer(ProductListModelSerializer):
|
|
|
248
247
|
"_parent",
|
|
249
248
|
"_portfolios",
|
|
250
249
|
"portfolios",
|
|
251
|
-
"_price_computation",
|
|
252
|
-
"price_computation",
|
|
253
250
|
) + InstrumentModelSerializer.Meta.fields
|
|
254
251
|
|
|
255
252
|
|