wbportfolio 1.44.4__py2.py3-none-any.whl → 1.45.0__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 +20 -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 +144 -0
- wbportfolio/models/graphs/utils.py +83 -0
- wbportfolio/models/indexes.py +2 -13
- wbportfolio/models/mixins/instruments.py +30 -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 +1 -0
- 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 +1 -0
- 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 +594 -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/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.4.dist-info → wbportfolio-1.45.0.dist-info}/METADATA +4 -1
- {wbportfolio-1.44.4.dist-info → wbportfolio-1.45.0.dist-info}/RECORD +301 -288
- 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/{defaults/portfolio → models/graphs}/__init__.py +0 -0
- {wbportfolio-1.44.4.dist-info → wbportfolio-1.45.0.dist-info}/WHEEL +0 -0
- {wbportfolio-1.44.4.dist-info → wbportfolio-1.45.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,9 +2,11 @@ from typing import Optional
|
|
|
2
2
|
|
|
3
3
|
from django.utils.translation import gettext_lazy as _
|
|
4
4
|
from wbcore.metadata.configs import display as dp
|
|
5
|
+
from wbcore.metadata.configs.display import Layout, Page, default
|
|
5
6
|
from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
6
7
|
Display,
|
|
7
8
|
create_simple_display,
|
|
9
|
+
create_simple_page_with_inline,
|
|
8
10
|
create_simple_section,
|
|
9
11
|
)
|
|
10
12
|
from wbcore.metadata.configs.display.instance_display.utils import repeat_field
|
|
@@ -17,109 +19,155 @@ class PortfolioDisplayConfig(DisplayViewConfig):
|
|
|
17
19
|
fields=[
|
|
18
20
|
dp.Field(key="name", label="Name"),
|
|
19
21
|
dp.Field(key="currency", label="Currency"),
|
|
20
|
-
dp.Field(key="
|
|
21
|
-
dp.Field(key="last_synchronization", label="Last Synchronization"),
|
|
22
|
+
dp.Field(key="updated_at", label="Updated At"),
|
|
22
23
|
dp.Field(key="depends_on", label="Depends on"),
|
|
24
|
+
dp.Field(key="automatic_rebalancer", label="Rebalancer"),
|
|
25
|
+
dp.Field(key="invested_timespan", label="Invested"),
|
|
26
|
+
dp.Field(key="is_manageable", label="Managed"),
|
|
27
|
+
dp.Field(key="is_tracked", label="Tracked"),
|
|
28
|
+
dp.Field(key="only_weighting", label="Only-Weight"),
|
|
29
|
+
dp.Field(key="is_lookthrough", label="Lookthrough"),
|
|
30
|
+
dp.Field(key="is_composition", label="Composition"),
|
|
23
31
|
]
|
|
24
32
|
)
|
|
25
33
|
|
|
26
34
|
def get_instance_display(self) -> Display:
|
|
27
|
-
return
|
|
28
|
-
[
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
35
|
+
return Display(
|
|
36
|
+
pages=[
|
|
37
|
+
Page(
|
|
38
|
+
title="Main Information",
|
|
39
|
+
layouts={
|
|
40
|
+
default(): Layout(
|
|
41
|
+
grid_template_areas=[
|
|
42
|
+
["name", "name", "currency", "is_manageable"],
|
|
43
|
+
["invested_timespan", "invested_timespan", "create_index", "."]
|
|
44
|
+
if self.new_mode
|
|
45
|
+
else [
|
|
46
|
+
"invested_timespan",
|
|
47
|
+
"invested_timespan",
|
|
48
|
+
"automatic_rebalancer",
|
|
49
|
+
"automatic_rebalancer",
|
|
50
|
+
],
|
|
51
|
+
["is_tracked", "is_lookthrough", "only_weighting", "is_composition"],
|
|
52
|
+
[repeat_field(4, "instruments_section")],
|
|
53
|
+
[repeat_field(4, "dependencyportfolios_section")],
|
|
54
|
+
[repeat_field(4, "preferredclassification_section")],
|
|
55
|
+
],
|
|
56
|
+
# grid_template_rows=["min-content"] * 3 + ["1fr", "446px"],
|
|
57
|
+
# grid_template_columns=[repeat(4, "183px"), "1fr", "1fr"],
|
|
58
|
+
sections=[
|
|
59
|
+
create_simple_section(
|
|
60
|
+
"instruments_section",
|
|
61
|
+
_("Linked Instruments"),
|
|
62
|
+
[["instruments"]],
|
|
63
|
+
"instruments",
|
|
64
|
+
collapsed=True,
|
|
65
|
+
),
|
|
66
|
+
create_simple_section(
|
|
67
|
+
"dependencyportfolios_section",
|
|
68
|
+
_("Dependency Portfolios"),
|
|
69
|
+
[["dependencyportfolios"]],
|
|
70
|
+
"dependencyportfolios",
|
|
71
|
+
collapsed=True,
|
|
72
|
+
),
|
|
73
|
+
create_simple_section(
|
|
74
|
+
"preferredclassification_section",
|
|
75
|
+
_("Preferred Classification"),
|
|
76
|
+
[["preferredclassification"]],
|
|
77
|
+
"preferredclassification",
|
|
78
|
+
collapsed=True,
|
|
79
|
+
),
|
|
80
|
+
],
|
|
81
|
+
),
|
|
82
|
+
},
|
|
44
83
|
),
|
|
45
|
-
|
|
46
|
-
"
|
|
84
|
+
Page(
|
|
85
|
+
title="Trade",
|
|
86
|
+
layouts={
|
|
87
|
+
default(): dp.Layout(
|
|
88
|
+
grid_template_areas=[
|
|
89
|
+
["trade_proposals"],
|
|
90
|
+
],
|
|
91
|
+
grid_template_rows=["auto"],
|
|
92
|
+
inlines=[
|
|
93
|
+
dp.Inline(key="trade_proposals", endpoint="trade_proposals"),
|
|
94
|
+
],
|
|
95
|
+
)
|
|
96
|
+
},
|
|
47
97
|
),
|
|
48
|
-
|
|
49
|
-
"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
98
|
+
Page(
|
|
99
|
+
title="Composition",
|
|
100
|
+
display=Display(
|
|
101
|
+
navigation_type=dp.NavigationType.PANEL,
|
|
102
|
+
pages=[
|
|
103
|
+
create_simple_page_with_inline("Assets", "assets"),
|
|
104
|
+
create_simple_page_with_inline("Top-Down Composition", "topdowncomposition"),
|
|
105
|
+
create_simple_page_with_inline("Contributor", "contributor"),
|
|
106
|
+
create_simple_page_with_inline("Distribution Table", "distribution_table"),
|
|
107
|
+
create_simple_page_with_inline("Distribution Chart", "distribution_chart"),
|
|
108
|
+
# Page(
|
|
109
|
+
# title="Distribution",
|
|
110
|
+
# layouts={
|
|
111
|
+
# default(): Layout(
|
|
112
|
+
# grid_template_areas=[["distribution_table", "distribution_chart"]],
|
|
113
|
+
# grid_template_rows=["auto"],
|
|
114
|
+
# grid_template_columns=["2fr", "1fr"],
|
|
115
|
+
# inlines=[
|
|
116
|
+
# Inline(
|
|
117
|
+
# key="distribution_table", endpoint="distribution_table", title="Table"
|
|
118
|
+
# ),
|
|
119
|
+
# Inline(
|
|
120
|
+
# key="distribution_chart", endpoint="distribution_chart", title="Chart"
|
|
121
|
+
# ),
|
|
122
|
+
# ],
|
|
123
|
+
# ),
|
|
124
|
+
# },
|
|
125
|
+
# ),
|
|
126
|
+
create_simple_page_with_inline(
|
|
127
|
+
"Portfolio Composition vs. Dependant Portfolios", "modelcomposition"
|
|
128
|
+
),
|
|
129
|
+
],
|
|
130
|
+
),
|
|
54
131
|
),
|
|
55
|
-
|
|
56
|
-
"preferredclassification_section",
|
|
57
|
-
_("Preferred Classification"),
|
|
58
|
-
[["preferredclassification"]],
|
|
59
|
-
"preferredclassification",
|
|
60
|
-
collapsed=True,
|
|
61
|
-
),
|
|
62
|
-
],
|
|
132
|
+
]
|
|
63
133
|
)
|
|
64
134
|
|
|
65
135
|
|
|
66
|
-
class
|
|
136
|
+
class PortfolioPortfolioThroughModelDisplayConfig(DisplayViewConfig):
|
|
67
137
|
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
68
138
|
return dp.ListDisplay(
|
|
69
139
|
fields=[
|
|
70
|
-
dp.Field(key="
|
|
71
|
-
dp.Field(key="
|
|
72
|
-
dp.Field(key="
|
|
73
|
-
dp.Field(key="last_synchronization", label="Last Synchronization"),
|
|
74
|
-
dp.Field(key="depends_on", label="Depends on"),
|
|
140
|
+
dp.Field(key="dependency_portfolio", label="Dependency Portfolio"),
|
|
141
|
+
dp.Field(key="portfolio", label="Dependant Portfolio"),
|
|
142
|
+
dp.Field(key="type", label="Type"),
|
|
75
143
|
]
|
|
76
144
|
)
|
|
77
145
|
|
|
78
146
|
def get_instance_display(self) -> Display:
|
|
79
147
|
return create_simple_display(
|
|
80
148
|
[
|
|
81
|
-
["
|
|
82
|
-
|
|
83
|
-
[repeat_field(2, "dependent_portfolios")],
|
|
84
|
-
[repeat_field(2, "trade_proposals_section")],
|
|
85
|
-
[repeat_field(2, "instruments_section")],
|
|
86
|
-
[repeat_field(2, "dependencyportfolios_section")],
|
|
87
|
-
[repeat_field(2, "preferredclassification_section")],
|
|
88
|
-
],
|
|
89
|
-
[
|
|
90
|
-
create_simple_section(
|
|
91
|
-
"trade_proposals_section",
|
|
92
|
-
_("Trade Proposals"),
|
|
93
|
-
[["trade_proposals"]],
|
|
94
|
-
"trade_proposals",
|
|
95
|
-
collapsed=True,
|
|
96
|
-
),
|
|
97
|
-
create_simple_section(
|
|
98
|
-
"instruments_section", _("Linked Instruments"), [["instruments"]], "instruments", collapsed=True
|
|
99
|
-
),
|
|
100
|
-
create_simple_section(
|
|
101
|
-
"dependencyportfolios_section",
|
|
102
|
-
_("Dependency Portfolios"),
|
|
103
|
-
[["dependencyportfolios"]],
|
|
104
|
-
"dependencyportfolios",
|
|
105
|
-
collapsed=True,
|
|
106
|
-
),
|
|
107
|
-
create_simple_section(
|
|
108
|
-
"preferredclassification_section",
|
|
109
|
-
_("Preferred Classification"),
|
|
110
|
-
[["preferredclassification"]],
|
|
111
|
-
"preferredclassification",
|
|
112
|
-
collapsed=True,
|
|
113
|
-
),
|
|
114
|
-
],
|
|
149
|
+
["dependency_portfolio", "type"],
|
|
150
|
+
]
|
|
115
151
|
)
|
|
116
152
|
|
|
117
153
|
|
|
118
|
-
class
|
|
154
|
+
class TopDownPortfolioCompositionPandasDisplayConfig(DisplayViewConfig):
|
|
119
155
|
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
156
|
+
rebalancing_column_label = "Last Rebalancing"
|
|
157
|
+
effective_column_label = "Actual"
|
|
158
|
+
if self.view.last_rebalancing_date:
|
|
159
|
+
rebalancing_column_label += f" ({self.view.last_rebalancing_date:%Y-ok, %m-%d})"
|
|
160
|
+
if self.view.last_effective_date:
|
|
161
|
+
effective_column_label += f" ({self.view.last_effective_date:%Y-%m-%d})"
|
|
120
162
|
return dp.ListDisplay(
|
|
121
163
|
fields=[
|
|
122
|
-
dp.Field(key="
|
|
123
|
-
dp.Field(key="
|
|
124
|
-
|
|
164
|
+
dp.Field(key="instrument", label="Instrument"),
|
|
165
|
+
dp.Field(key="effective_weights", label=rebalancing_column_label),
|
|
166
|
+
dp.Field(key="rebalancing_weights", label=effective_column_label),
|
|
167
|
+
],
|
|
168
|
+
tree=True,
|
|
169
|
+
tree_group_pinned="left",
|
|
170
|
+
tree_group_field="instrument",
|
|
171
|
+
tree_group_label="Instrument",
|
|
172
|
+
tree_group_parent_pointer="parent_row_id",
|
|
125
173
|
)
|
|
@@ -4,6 +4,7 @@ from wbcore.contrib.color.enums import WBColor
|
|
|
4
4
|
from wbcore.enums import Unit
|
|
5
5
|
from wbcore.metadata.configs import display as dp
|
|
6
6
|
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
7
|
+
|
|
7
8
|
from wbportfolio.filters.performances import PerformancePandasFilter
|
|
8
9
|
|
|
9
10
|
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
|
|
3
|
+
from wbcore.metadata.configs import display as dp
|
|
4
|
+
from wbcore.metadata.configs.display import Display, create_simple_display
|
|
5
|
+
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class RebalancerDisplayConfig(DisplayViewConfig):
|
|
9
|
+
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
10
|
+
return dp.ListDisplay(
|
|
11
|
+
fields=[
|
|
12
|
+
dp.Field(key="portfolio", label="Portfolio"),
|
|
13
|
+
dp.Field(key="rebalancing_model", label="Rebalancing Model"),
|
|
14
|
+
dp.Field(key="approve_trade_proposal_automatically", label="Approve automatically"),
|
|
15
|
+
dp.Field(key="frequency_repr", label="Frequency"),
|
|
16
|
+
dp.Field(key="activation_date", label="Activation Date"),
|
|
17
|
+
],
|
|
18
|
+
)
|
|
19
|
+
|
|
20
|
+
def get_instance_display(self) -> Display:
|
|
21
|
+
return create_simple_display(
|
|
22
|
+
[
|
|
23
|
+
["rebalancing_model", "approve_trade_proposal_automatically"],
|
|
24
|
+
["frequency", "activation_date"],
|
|
25
|
+
["rebalancing_dates", "rebalancing_dates"],
|
|
26
|
+
]
|
|
27
|
+
)
|
|
@@ -6,6 +6,7 @@ from wbcore.metadata.configs.display.instance_display import Inline, Layout, Pag
|
|
|
6
6
|
from wbcore.metadata.configs.display.instance_display.operators import default
|
|
7
7
|
from wbcore.metadata.configs.display.instance_display.shortcuts import Display
|
|
8
8
|
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
9
|
+
|
|
9
10
|
from wbportfolio.models import TradeProposal
|
|
10
11
|
|
|
11
12
|
|
|
@@ -76,9 +77,11 @@ class TradeProposalDisplayConfig(DisplayViewConfig):
|
|
|
76
77
|
layouts={
|
|
77
78
|
default(): Layout(
|
|
78
79
|
grid_template_areas=[
|
|
79
|
-
["status", "status"],
|
|
80
|
-
["trade_date", "
|
|
81
|
-
|
|
80
|
+
["status", "status", "status"],
|
|
81
|
+
["trade_date", "rebalancing_model", "target_portfolio"]
|
|
82
|
+
if self.view.new_mode
|
|
83
|
+
else ["trade_date", "rebalancing_model", "rebalancing_model"],
|
|
84
|
+
["comment", "comment", "comment"],
|
|
82
85
|
],
|
|
83
86
|
),
|
|
84
87
|
},
|
|
@@ -88,7 +91,7 @@ class TradeProposalDisplayConfig(DisplayViewConfig):
|
|
|
88
91
|
layouts={
|
|
89
92
|
default(): Layout(
|
|
90
93
|
grid_template_areas=[["trades"]],
|
|
91
|
-
grid_template_rows=["
|
|
94
|
+
grid_template_rows=["1fr"],
|
|
92
95
|
inlines=[Inline(key="trades", endpoint="trades")],
|
|
93
96
|
),
|
|
94
97
|
},
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from typing import Optional
|
|
2
2
|
|
|
3
|
+
from django.shortcuts import get_object_or_404
|
|
3
4
|
from wbcore.contrib.color.enums import WBColor
|
|
4
5
|
from wbcore.contrib.icons import WBIcon
|
|
5
6
|
from wbcore.enums import Unit
|
|
@@ -10,7 +11,8 @@ from wbcore.metadata.configs.display.instance_display.shortcuts import (
|
|
|
10
11
|
)
|
|
11
12
|
from wbcore.metadata.configs.display.instance_display.utils import repeat_field
|
|
12
13
|
from wbcore.metadata.configs.display.view_config import DisplayViewConfig
|
|
13
|
-
|
|
14
|
+
|
|
15
|
+
from wbportfolio.models import Trade, TradeProposal
|
|
14
16
|
|
|
15
17
|
NEGATIVE_RED_FORMATTING = [
|
|
16
18
|
dp.FormattingRule(
|
|
@@ -38,6 +40,11 @@ SHARE_FORMATTING = dp.Formatting(
|
|
|
38
40
|
TRADE_STATUS_LEGENDS = dp.Legend(
|
|
39
41
|
key="status",
|
|
40
42
|
items=[
|
|
43
|
+
dp.LegendItem(
|
|
44
|
+
icon=WBColor.RED_LIGHT.value,
|
|
45
|
+
label=Trade.Status.FAILED.label,
|
|
46
|
+
value=Trade.Status.FAILED.value,
|
|
47
|
+
),
|
|
41
48
|
dp.LegendItem(
|
|
42
49
|
icon=WBColor.BLUE_LIGHT.value,
|
|
43
50
|
label=Trade.Status.DRAFT.label,
|
|
@@ -64,6 +71,10 @@ TRADE_STATUS_LEGENDS = dp.Legend(
|
|
|
64
71
|
TRADE_STATUS_FORMATTING = dp.Formatting(
|
|
65
72
|
column="status",
|
|
66
73
|
formatting_rules=[
|
|
74
|
+
dp.FormattingRule(
|
|
75
|
+
style={"backgroundColor": WBColor.RED_LIGHT.value},
|
|
76
|
+
condition=("==", Trade.Status.FAILED.value),
|
|
77
|
+
),
|
|
67
78
|
dp.FormattingRule(
|
|
68
79
|
style={"backgroundColor": WBColor.BLUE_LIGHT.value},
|
|
69
80
|
condition=("==", Trade.Status.DRAFT.value),
|
|
@@ -287,19 +298,45 @@ class TradePortfolioDisplayConfig(TradeDisplayConfig):
|
|
|
287
298
|
|
|
288
299
|
class TradeTradeProposalDisplayConfig(DisplayViewConfig):
|
|
289
300
|
def get_list_display(self) -> Optional[dp.ListDisplay]:
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
301
|
+
trade_proposal = get_object_or_404(TradeProposal, pk=self.view.kwargs.get("trade_proposal_id", None))
|
|
302
|
+
fields = [
|
|
303
|
+
dp.Field(key="underlying_instrument", label="Instrument"),
|
|
304
|
+
dp.Field(
|
|
305
|
+
label="Weight",
|
|
306
|
+
open_by_default=False,
|
|
307
|
+
key=None,
|
|
308
|
+
children=[
|
|
309
|
+
dp.Field(key="effective_weight", label="Effective Weight", show="open"),
|
|
310
|
+
dp.Field(key="target_weight", label="Target Weight", show="open"),
|
|
311
|
+
dp.Field(
|
|
312
|
+
key="weighting",
|
|
313
|
+
label="Delta Weight",
|
|
314
|
+
formatting_rules=[
|
|
315
|
+
dp.FormattingRule(
|
|
316
|
+
style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
|
|
317
|
+
condition=("<", 0),
|
|
318
|
+
),
|
|
319
|
+
dp.FormattingRule(
|
|
320
|
+
style={"color": WBColor.GREEN_DARK.value, "fontWeight": "bold"},
|
|
321
|
+
condition=(">", 0),
|
|
322
|
+
),
|
|
323
|
+
],
|
|
324
|
+
),
|
|
325
|
+
],
|
|
326
|
+
),
|
|
327
|
+
]
|
|
328
|
+
if not trade_proposal.portfolio.only_weighting:
|
|
329
|
+
fields.append(
|
|
293
330
|
dp.Field(
|
|
294
|
-
label="
|
|
331
|
+
label="Shares",
|
|
295
332
|
open_by_default=False,
|
|
296
333
|
key=None,
|
|
297
334
|
children=[
|
|
298
|
-
dp.Field(key="
|
|
299
|
-
dp.Field(key="
|
|
335
|
+
dp.Field(key="effective_shares", label="Effective Shares", show="open"),
|
|
336
|
+
dp.Field(key="target_shares", label="Target Shares", show="open"),
|
|
300
337
|
dp.Field(
|
|
301
|
-
key="
|
|
302
|
-
label="
|
|
338
|
+
key="shares",
|
|
339
|
+
label="Shares",
|
|
303
340
|
formatting_rules=[
|
|
304
341
|
dp.FormattingRule(
|
|
305
342
|
style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
|
|
@@ -312,39 +349,35 @@ class TradeTradeProposalDisplayConfig(DisplayViewConfig):
|
|
|
312
349
|
],
|
|
313
350
|
),
|
|
314
351
|
],
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
dp.Field(key="order", label="Order", show="open"),
|
|
345
|
-
],
|
|
346
|
-
),
|
|
347
|
-
],
|
|
352
|
+
)
|
|
353
|
+
)
|
|
354
|
+
fields.append(
|
|
355
|
+
dp.Field(
|
|
356
|
+
label="Information",
|
|
357
|
+
open_by_default=False,
|
|
358
|
+
key=None,
|
|
359
|
+
children=[
|
|
360
|
+
dp.Field(
|
|
361
|
+
key="transaction_subtype",
|
|
362
|
+
label="Direction",
|
|
363
|
+
formatting_rules=[
|
|
364
|
+
dp.FormattingRule(
|
|
365
|
+
style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
|
|
366
|
+
condition=("==", Trade.Type.SELL.name),
|
|
367
|
+
),
|
|
368
|
+
dp.FormattingRule(
|
|
369
|
+
style={"color": WBColor.GREEN_DARK.value, "fontWeight": "bold"},
|
|
370
|
+
condition=("==", Trade.Type.BUY.name),
|
|
371
|
+
),
|
|
372
|
+
],
|
|
373
|
+
),
|
|
374
|
+
dp.Field(key="comment", label="Comment"),
|
|
375
|
+
dp.Field(key="order", label="Order", show="open"),
|
|
376
|
+
],
|
|
377
|
+
)
|
|
378
|
+
)
|
|
379
|
+
return dp.ListDisplay(
|
|
380
|
+
fields=fields,
|
|
348
381
|
legends=[TRADE_STATUS_LEGENDS],
|
|
349
382
|
formatting=[SHARE_FORMATTING, TRADE_STATUS_FORMATTING],
|
|
350
383
|
)
|
|
@@ -34,9 +34,10 @@ from .fees import (
|
|
|
34
34
|
from .fees import FeesAggregatedPortfolioPandasEndpointConfig, FeesPortfolioEndpointConfig, FeeEndpointConfig
|
|
35
35
|
|
|
36
36
|
from .portfolios import (
|
|
37
|
-
ModelPortfolioEndpointConfig,
|
|
38
37
|
PortfolioEndpointConfig,
|
|
39
38
|
PortfolioPortfolioThroughModelEndpointConfig,
|
|
39
|
+
PortfolioTreeGraphChartEndpointConfig,
|
|
40
|
+
TopDownPortfolioCompositionPandasEndpointConfig
|
|
40
41
|
)
|
|
41
42
|
from .positions import (
|
|
42
43
|
AggregatedAssetPositionLiquidityEndpointConfig,
|
|
@@ -73,3 +74,4 @@ from .portfolio_relationship import (
|
|
|
73
74
|
)
|
|
74
75
|
from .esg import ESGMetricAggregationPortfolioPandasEndpointConfig
|
|
75
76
|
from .reconciliations import AccountReconciliationLineEndpointViewConfig, AccountReconciliationEndpointViewConfig
|
|
77
|
+
from .rebalancing import RebalancerEndpointConfig
|
|
@@ -6,18 +6,16 @@ class PortfolioEndpointConfig(EndpointViewConfig):
|
|
|
6
6
|
def get_endpoint(self, **kwargs):
|
|
7
7
|
return super().get_endpoint()
|
|
8
8
|
|
|
9
|
-
def
|
|
9
|
+
def get_update_endpoint(self, **kwargs):
|
|
10
10
|
if self.view.is_portfolio_manager:
|
|
11
11
|
return self.get_endpoint(**kwargs)
|
|
12
12
|
return None
|
|
13
13
|
|
|
14
|
-
def
|
|
15
|
-
return
|
|
16
|
-
|
|
14
|
+
def get_delete_endpoint(self, **kwargs):
|
|
15
|
+
return self.get_update_endpoint(**kwargs)
|
|
17
16
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return reverse("wbportfolio:modelportfolio-list", request=self.request)
|
|
17
|
+
def get_create_endpoint(self, **kwargs):
|
|
18
|
+
return self.get_update_endpoint(**kwargs)
|
|
21
19
|
|
|
22
20
|
|
|
23
21
|
class PortfolioPortfolioThroughModelEndpointConfig(EndpointViewConfig):
|
|
@@ -41,3 +39,21 @@ class PortfolioPortfolioThroughModelEndpointConfig(EndpointViewConfig):
|
|
|
41
39
|
if self.request.user.is_superuser:
|
|
42
40
|
return self.get_list_endpoint(**kwargs)
|
|
43
41
|
return None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class PortfolioTreeGraphChartEndpointConfig(EndpointViewConfig):
|
|
45
|
+
def get_list_endpoint(self, **kwargs):
|
|
46
|
+
return reverse(
|
|
47
|
+
"wbportfolio:portfolio-treegraphchart-list",
|
|
48
|
+
args=[self.view.kwargs["portfolio_id"]],
|
|
49
|
+
request=self.request,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class TopDownPortfolioCompositionPandasEndpointConfig(EndpointViewConfig):
|
|
54
|
+
def get_list_endpoint(self, **kwargs):
|
|
55
|
+
return reverse(
|
|
56
|
+
"wbportfolio:portfolio-topdowncomposition-list",
|
|
57
|
+
args=[self.view.kwargs["portfolio_id"]],
|
|
58
|
+
request=self.request,
|
|
59
|
+
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from wbcore.menus import ItemPermission, MenuItem
|
|
2
|
+
|
|
2
3
|
from wbportfolio.permissions import is_portfolio_manager
|
|
3
4
|
|
|
4
5
|
PortfolioMenuItem = MenuItem(
|
|
@@ -9,7 +10,8 @@ PortfolioMenuItem = MenuItem(
|
|
|
9
10
|
|
|
10
11
|
|
|
11
12
|
ModelPortfolioMenuItem = MenuItem(
|
|
12
|
-
label="
|
|
13
|
-
endpoint="wbportfolio:
|
|
13
|
+
label="Managed Portfolios",
|
|
14
|
+
endpoint="wbportfolio:portfolio-list",
|
|
15
|
+
endpoint_get_parameters={"is_manageable": True},
|
|
14
16
|
permission=ItemPermission(method=is_portfolio_manager, permissions=["wbportfolio.view_portfolio"]),
|
|
15
17
|
)
|