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
|
@@ -10,12 +10,7 @@ class PortfolioPreviewConfig(PreviewViewConfig):
|
|
|
10
10
|
def get_display(self) -> Display:
|
|
11
11
|
return create_simple_display(
|
|
12
12
|
[
|
|
13
|
-
[
|
|
14
|
-
"name",
|
|
15
|
-
"name",
|
|
16
|
-
"currency",
|
|
17
|
-
],
|
|
18
|
-
[repeat_field(2, "portfolio_synchronization"), "last_synchronization"],
|
|
13
|
+
["name", "currency", "updated_at"],
|
|
19
14
|
[repeat_field(3, "depends_on")],
|
|
20
15
|
]
|
|
21
16
|
)
|
|
@@ -38,7 +38,7 @@ from .instrument_prices import (
|
|
|
38
38
|
NominalProductTitleConfig,
|
|
39
39
|
)
|
|
40
40
|
|
|
41
|
-
from .portfolios import
|
|
41
|
+
from .portfolios import PortfolioTitleConfig, DailyPortfolioCashFlowTitleConfig, PortfolioTreeGraphChartTitleConfig, TopDownPortfolioCompositionPandasTitleConfig
|
|
42
42
|
from .positions import (
|
|
43
43
|
AggregatedAssetPositionLiquidityTitleConfig,
|
|
44
44
|
AssetPositionPandasTitleConfig,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from wbcore.metadata.configs.titles import TitleViewConfig
|
|
2
|
+
|
|
2
3
|
from wbportfolio.models.portfolio import Portfolio
|
|
3
4
|
|
|
4
5
|
|
|
@@ -13,20 +14,21 @@ class PortfolioTitleConfig(TitleViewConfig):
|
|
|
13
14
|
return "New Portfolio"
|
|
14
15
|
|
|
15
16
|
|
|
16
|
-
class ModelPortfolioTitleConfig(TitleViewConfig):
|
|
17
|
-
def get_list_title(self):
|
|
18
|
-
return "Model Portfolios"
|
|
19
|
-
|
|
20
|
-
def get_instance_title(self):
|
|
21
|
-
return "Model Portfolio: {{ name }}"
|
|
22
|
-
|
|
23
|
-
def get_create_title(self):
|
|
24
|
-
return "New Model Portfolio"
|
|
25
|
-
|
|
26
|
-
|
|
27
17
|
class DailyPortfolioCashFlowTitleConfig(TitleViewConfig):
|
|
28
18
|
def get_list_title(self):
|
|
29
19
|
if portfolio_id := self.view.kwargs.get("portfolio_id", None):
|
|
30
20
|
portfolio = Portfolio.objects.get(id=portfolio_id)
|
|
31
21
|
return f"{portfolio}: Daily Portfolio Cash Flow"
|
|
32
22
|
return "Daily Portfolio Cash Flow"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class PortfolioTreeGraphChartTitleConfig(TitleViewConfig):
|
|
26
|
+
def get_list_title(self):
|
|
27
|
+
portfolio = self.view.portfolio
|
|
28
|
+
return f"Tree Graph Chart for {portfolio}"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TopDownPortfolioCompositionPandasTitleConfig(TitleViewConfig):
|
|
32
|
+
def get_list_title(self):
|
|
33
|
+
portfolio = self.view.portfolio
|
|
34
|
+
return f"Top-Down Composition for {portfolio}"
|
|
@@ -4,6 +4,7 @@ from rest_framework.decorators import action
|
|
|
4
4
|
from rest_framework.response import Response
|
|
5
5
|
from wbcore import viewsets
|
|
6
6
|
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
7
|
+
|
|
7
8
|
from wbportfolio.filters import CustodianFilterSet
|
|
8
9
|
from wbportfolio.models import Custodian
|
|
9
10
|
from wbportfolio.serializers import (
|
wbportfolio/viewsets/esg.py
CHANGED
|
@@ -11,6 +11,7 @@ from wbcore.utils.strings import format_number
|
|
|
11
11
|
from wbfdm.analysis.esg.enums import AggregationMethod, ESGAggregation
|
|
12
12
|
from wbfdm.analysis.esg.esg_analysis import DataLoader
|
|
13
13
|
from wbfdm.models import Instrument
|
|
14
|
+
|
|
14
15
|
from wbportfolio.filters import ESGMetricAggregationPortfolioPandasFilterSet
|
|
15
16
|
from wbportfolio.models import AssetPosition
|
|
16
17
|
from wbportfolio.viewsets.configs import (
|
wbportfolio/viewsets/mixins.py
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from django.db.models import Case, F, Value, When
|
|
2
2
|
from wbcore import viewsets
|
|
3
|
+
|
|
3
4
|
from wbportfolio.models import DailyPortfolioCashFlow
|
|
4
5
|
from wbportfolio.serializers import DailyPortfolioCashFlowModelSerializer
|
|
5
6
|
from wbportfolio.viewsets.configs.display import DailyPortfolioCashFlowDisplayConfig
|
|
@@ -1,34 +1,41 @@
|
|
|
1
|
-
from
|
|
1
|
+
from contextlib import suppress
|
|
2
|
+
from datetime import date, datetime
|
|
2
3
|
|
|
4
|
+
import pandas as pd
|
|
5
|
+
from django.db.models import Q
|
|
3
6
|
from django.http import HttpResponse
|
|
4
7
|
from django.shortcuts import get_object_or_404
|
|
8
|
+
from django.utils.dateparse import parse_date
|
|
9
|
+
from django.utils.functional import cached_property
|
|
5
10
|
from rest_framework.decorators import action
|
|
11
|
+
from rest_framework.permissions import IsAdminUser
|
|
6
12
|
from rest_framework.response import Response
|
|
13
|
+
from rest_framework.reverse import reverse
|
|
7
14
|
from wbcore import viewsets
|
|
8
15
|
from wbcore.contrib.currency.models import Currency
|
|
16
|
+
from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
|
|
17
|
+
from wbcore.pandas import fields as pf
|
|
9
18
|
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
10
|
-
from
|
|
11
|
-
|
|
19
|
+
from wbfdm.models import Instrument
|
|
20
|
+
|
|
21
|
+
from wbportfolio.filters import PortfolioFilterSet, PortfolioTreeGraphChartFilterSet
|
|
12
22
|
from wbportfolio.models import (
|
|
23
|
+
AssetPosition,
|
|
13
24
|
Portfolio,
|
|
14
25
|
PortfolioPortfolioThroughModel,
|
|
15
|
-
|
|
16
|
-
|
|
26
|
+
Rebalancer,
|
|
27
|
+
RebalancingModel,
|
|
17
28
|
TradeProposal,
|
|
18
29
|
)
|
|
19
|
-
from wbportfolio.models.portfolio import
|
|
30
|
+
from wbportfolio.models.portfolio import batch_recompute_lookthrough_as_task
|
|
20
31
|
from wbportfolio.serializers import (
|
|
21
|
-
ModelPortfolioModelSerializer,
|
|
22
32
|
PortfolioModelSerializer,
|
|
23
33
|
PortfolioPortfolioThroughModelSerializer,
|
|
24
34
|
PortfolioRepresentationSerializer,
|
|
25
35
|
)
|
|
26
36
|
|
|
37
|
+
from ..models.graphs.portfolio import PortfolioGraph
|
|
27
38
|
from .configs import (
|
|
28
|
-
ModelPortfolioButtonConfig,
|
|
29
|
-
ModelPortfolioDisplayConfig,
|
|
30
|
-
ModelPortfolioEndpointConfig,
|
|
31
|
-
ModelPortfolioTitleConfig,
|
|
32
39
|
PortfolioButtonConfig,
|
|
33
40
|
PortfolioDisplayConfig,
|
|
34
41
|
PortfolioEndpointConfig,
|
|
@@ -36,6 +43,11 @@ from .configs import (
|
|
|
36
43
|
PortfolioPortfolioThroughModelEndpointConfig,
|
|
37
44
|
PortfolioPreviewConfig,
|
|
38
45
|
PortfolioTitleConfig,
|
|
46
|
+
PortfolioTreeGraphChartEndpointConfig,
|
|
47
|
+
PortfolioTreeGraphChartTitleConfig,
|
|
48
|
+
TopDownPortfolioCompositionPandasDisplayConfig,
|
|
49
|
+
TopDownPortfolioCompositionPandasEndpointConfig,
|
|
50
|
+
TopDownPortfolioCompositionPandasTitleConfig,
|
|
39
51
|
)
|
|
40
52
|
from .mixins import UserPortfolioRequestPermissionMixin
|
|
41
53
|
|
|
@@ -70,75 +82,70 @@ class PortfolioModelViewSet(UserPortfolioRequestPermissionMixin, InternalUserPer
|
|
|
70
82
|
.get_queryset()
|
|
71
83
|
.select_related(
|
|
72
84
|
"currency",
|
|
73
|
-
"portfolio_synchronization",
|
|
74
85
|
)
|
|
75
86
|
.prefetch_related(
|
|
76
87
|
"depends_on",
|
|
77
|
-
"dependent_portfolios",
|
|
78
88
|
)
|
|
79
89
|
)
|
|
80
90
|
|
|
81
|
-
@action(detail=True, methods=["
|
|
91
|
+
@action(detail=True, methods=["POST"])
|
|
82
92
|
def rebalance(self, request, pk=None):
|
|
83
|
-
if
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
trade_date=datetime.strptime(date_str, "%Y-%m-%d"),
|
|
93
|
+
if date_str := request.POST.get("trade_date", None):
|
|
94
|
+
trade_date = datetime.strptime(date_str, "%Y-%m-%d")
|
|
95
|
+
trade_proposal, _ = TradeProposal.objects.get_or_create(portfolio_id=pk, trade_date=trade_date)
|
|
96
|
+
trade_proposal.reset_trades()
|
|
97
|
+
return Response(
|
|
98
|
+
{"endpoint": reverse("wbportfolio:tradeproposal-detail", args=[trade_proposal.id], request=request)}
|
|
90
99
|
)
|
|
91
|
-
return Response({"send": True})
|
|
92
100
|
raise HttpResponse("Bad Request", status=400)
|
|
93
101
|
|
|
94
|
-
@action(detail=True, methods=["PATCH"])
|
|
95
|
-
def resynchronize(self, request, pk=None):
|
|
96
|
-
if request.user.has_perm("wbportfolio.administrate_instrument"):
|
|
97
|
-
portfolio = get_object_or_404(Portfolio, pk=pk)
|
|
98
|
-
instrument = request.GET.get("instrument", None)
|
|
99
|
-
start, end = get_date_interval_from_request(request, request_type="POST")
|
|
100
|
-
resynchronize_history_as_task.delay(portfolio.id, start, end, instrument_id=instrument)
|
|
101
|
-
return Response({"send": True})
|
|
102
|
-
return HttpResponse("Unauthorized", status=401)
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
class ModelPortfolioModelViewSet(PortfolioModelViewSet):
|
|
106
|
-
serializer_class = ModelPortfolioModelSerializer
|
|
107
|
-
endpoint_config_class = ModelPortfolioEndpointConfig
|
|
108
|
-
display_config_class = ModelPortfolioDisplayConfig
|
|
109
|
-
title_config_class = ModelPortfolioTitleConfig
|
|
110
|
-
button_config_class = ModelPortfolioButtonConfig
|
|
111
|
-
|
|
112
102
|
@action(detail=False, methods=["POST"])
|
|
113
103
|
def createmodelportfolio(self, request, pk=None):
|
|
114
104
|
if self.is_portfolio_manager:
|
|
115
105
|
name = request.POST["name"]
|
|
116
106
|
currency_id = request.POST["currency"]
|
|
117
107
|
currency = Currency.objects.get(id=currency_id)
|
|
118
|
-
portfolio_synchronization_id = request.POST.get("portfolio_synchronization", None)
|
|
119
|
-
price_computation_id = request.POST.get("price_computation", None)
|
|
120
|
-
portfolio_synchronization = (
|
|
121
|
-
PortfolioSynchronization.objects.get(id=portfolio_synchronization_id)
|
|
122
|
-
if portfolio_synchronization_id
|
|
123
|
-
else None
|
|
124
|
-
)
|
|
125
|
-
create_index = request.POST.get("create_index", "false") == "true"
|
|
126
108
|
index_parameters = {}
|
|
127
|
-
|
|
128
|
-
index_parameters["price_computation"] = (
|
|
129
|
-
PriceComputation.objects.get(id=price_computation_id) if price_computation_id else None
|
|
130
|
-
)
|
|
131
|
-
Portfolio.create_model_portfolio(
|
|
132
|
-
name, currency, portfolio_synchronization=portfolio_synchronization, index_parameters=index_parameters
|
|
133
|
-
)
|
|
109
|
+
Portfolio.create_model_portfolio(name, currency, index_parameters=index_parameters)
|
|
134
110
|
return Response({"send": True})
|
|
135
111
|
raise HttpResponse("Unauthorized", status=403)
|
|
136
112
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
113
|
+
@action(detail=True, methods=["POST"])
|
|
114
|
+
def attachrebalancer(self, request, pk=None):
|
|
115
|
+
try:
|
|
116
|
+
activation_date = datetime.strptime(request.POST["activation_date"], "%Y-%m-%d")
|
|
117
|
+
rebalancing_model = get_object_or_404(RebalancingModel, pk=request.POST["rebalancing_model"])
|
|
118
|
+
frequency = request.POST["frequency"]
|
|
119
|
+
approve_trade_proposal_automatically = (
|
|
120
|
+
request.POST.get("approve_trade_proposal_automatically", "false") == "true"
|
|
121
|
+
)
|
|
122
|
+
|
|
123
|
+
rebalancer, _ = Rebalancer.objects.update_or_create(
|
|
124
|
+
portfolio=self.get_object(),
|
|
125
|
+
defaults={
|
|
126
|
+
"rebalancing_model": rebalancing_model,
|
|
127
|
+
"frequency": frequency,
|
|
128
|
+
"activation_date": activation_date,
|
|
129
|
+
"approve_trade_proposal_automatically": approve_trade_proposal_automatically,
|
|
130
|
+
},
|
|
131
|
+
)
|
|
132
|
+
return Response(
|
|
133
|
+
{"endpoint": reverse("wbportfolio:rebalancer-detail", args=[rebalancer.id], request=request)}
|
|
134
|
+
)
|
|
135
|
+
except KeyError:
|
|
136
|
+
return HttpResponse("Bad arguments", status=400)
|
|
137
|
+
|
|
138
|
+
@action(detail=True, methods=["POST"], permission_classes=[IsAdminUser])
|
|
139
|
+
def recomputelookthrough(self, request, pk=None):
|
|
140
|
+
portfolio = self.get_object()
|
|
141
|
+
if portfolio.is_lookthrough:
|
|
142
|
+
with suppress(KeyError):
|
|
143
|
+
start = datetime.strptime(request.POST["start"], "%Y-%m-%d")
|
|
144
|
+
end = datetime.strptime(request.POST["end"], "%Y-%m-%d")
|
|
145
|
+
batch_recompute_lookthrough_as_task.delay(portfolio.id, start, end)
|
|
146
|
+
return HttpResponse("Ok", status=200)
|
|
147
|
+
|
|
148
|
+
return HttpResponse("Bad arguments", status=400)
|
|
142
149
|
|
|
143
150
|
|
|
144
151
|
class PortfolioPortfolioThroughModelViewSet(InternalUserPermissionMixin, viewsets.ModelViewSet):
|
|
@@ -151,4 +158,164 @@ class PortfolioPortfolioThroughModelViewSet(InternalUserPermissionMixin, viewset
|
|
|
151
158
|
endpoint_config_class = PortfolioPortfolioThroughModelEndpointConfig
|
|
152
159
|
|
|
153
160
|
def get_queryset(self):
|
|
154
|
-
return
|
|
161
|
+
return (
|
|
162
|
+
super()
|
|
163
|
+
.get_queryset()
|
|
164
|
+
.filter(Q(portfolio=self.kwargs["portfolio_id"]) | Q(dependency_portfolio=self.kwargs["portfolio_id"]))
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
class PortfolioTreeGraphChartViewSet(UserPortfolioRequestPermissionMixin, viewsets.HTMLViewSet):
|
|
169
|
+
filterset_class = PortfolioTreeGraphChartFilterSet
|
|
170
|
+
IDENTIFIER = "wbportfolio:portfolio-treegraphchart"
|
|
171
|
+
queryset = Portfolio.objects.all()
|
|
172
|
+
|
|
173
|
+
title_config_class = PortfolioTreeGraphChartTitleConfig
|
|
174
|
+
endpoint_config_class = PortfolioTreeGraphChartEndpointConfig
|
|
175
|
+
|
|
176
|
+
def get_queryset(self):
|
|
177
|
+
return super().get_queryset().filter(id=self.kwargs["portfolio_id"])
|
|
178
|
+
|
|
179
|
+
@cached_property
|
|
180
|
+
def val_date(self) -> date:
|
|
181
|
+
return parse_date(self.request.GET["date"])
|
|
182
|
+
|
|
183
|
+
def get_html(self, queryset) -> str:
|
|
184
|
+
portfolio_graph = PortfolioGraph(self.portfolio, self.val_date, rankdir="LR", size="20,11")
|
|
185
|
+
return portfolio_graph.to_svg()
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
class TopDownPortfolioCompositionPandasAPIView(UserPortfolioRequestPermissionMixin, ExportPandasAPIViewSet):
|
|
189
|
+
IDENTIFIER = "wbportfolio:topdowncomposition"
|
|
190
|
+
queryset = Portfolio.objects.all()
|
|
191
|
+
|
|
192
|
+
display_config_class = TopDownPortfolioCompositionPandasDisplayConfig
|
|
193
|
+
title_config_class = TopDownPortfolioCompositionPandasTitleConfig
|
|
194
|
+
endpoint_config_class = TopDownPortfolioCompositionPandasEndpointConfig
|
|
195
|
+
|
|
196
|
+
pandas_fields = pf.PandasFields(
|
|
197
|
+
fields=[
|
|
198
|
+
pf.PKField(key="id", label="ID"),
|
|
199
|
+
pf.CharField(key="_group_key", label="Group Key"),
|
|
200
|
+
pf.IntegerField(key="parent_row_id", label="Parent Row"),
|
|
201
|
+
pf.CharField(key="instrument", label="Instrument"),
|
|
202
|
+
pf.FloatField(key="effective_weights", label="Effective Weights", precision=2, percent=True),
|
|
203
|
+
pf.FloatField(key="rebalancing_weights", label="Rebalancing Weights", precision=2, percent=True),
|
|
204
|
+
]
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
@cached_property
|
|
208
|
+
def composition_portfolio(self) -> Portfolio | None:
|
|
209
|
+
return self.portfolio.composition_portfolio or self.portfolio
|
|
210
|
+
|
|
211
|
+
@cached_property
|
|
212
|
+
def last_rebalancing_date(self) -> date | None:
|
|
213
|
+
if self.composition_portfolio:
|
|
214
|
+
with suppress(TradeProposal.DoesNotExist):
|
|
215
|
+
return (
|
|
216
|
+
self.composition_portfolio.trade_proposals.filter(trade_date__lte=self.last_effective_date)
|
|
217
|
+
.latest("trade_date")
|
|
218
|
+
.trade_date
|
|
219
|
+
)
|
|
220
|
+
|
|
221
|
+
@cached_property
|
|
222
|
+
def last_effective_date(self) -> date | None:
|
|
223
|
+
if self.composition_portfolio:
|
|
224
|
+
with suppress(AssetPosition.DoesNotExist):
|
|
225
|
+
return self.composition_portfolio.assets.latest("date").date
|
|
226
|
+
|
|
227
|
+
def get_dataframe(self, request, queryset, **kwargs):
|
|
228
|
+
df = pd.DataFrame(columns=["id", "parent_row_id", "instrument", "effective_weights", "rebalancing_weights"])
|
|
229
|
+
|
|
230
|
+
def _get_parent_instrument_id(portfolio):
|
|
231
|
+
with suppress(AttributeError):
|
|
232
|
+
return portfolio.instruments.first().id
|
|
233
|
+
|
|
234
|
+
if (
|
|
235
|
+
self.has_portfolio_access
|
|
236
|
+
and self.composition_portfolio
|
|
237
|
+
and self.last_rebalancing_date
|
|
238
|
+
and self.last_effective_date
|
|
239
|
+
):
|
|
240
|
+
tree_positions_effective_date_df = (
|
|
241
|
+
pd.DataFrame(
|
|
242
|
+
map(
|
|
243
|
+
lambda x: {
|
|
244
|
+
"instrument": x.underlying_instrument.id,
|
|
245
|
+
"parent_instrument": _get_parent_instrument_id(
|
|
246
|
+
getattr(x, "parent_portfolio", "portfolio")
|
|
247
|
+
),
|
|
248
|
+
"effective_weights": x.weighting,
|
|
249
|
+
},
|
|
250
|
+
self.composition_portfolio.get_positions(
|
|
251
|
+
self.last_effective_date, with_intermediary_position=True
|
|
252
|
+
),
|
|
253
|
+
),
|
|
254
|
+
columns=["instrument", "parent_instrument", "effective_weights"],
|
|
255
|
+
)
|
|
256
|
+
.groupby(["parent_instrument", "instrument"])
|
|
257
|
+
.sum()
|
|
258
|
+
)
|
|
259
|
+
tree_positions_rebalancing_date_df = (
|
|
260
|
+
pd.DataFrame(
|
|
261
|
+
map(
|
|
262
|
+
lambda x: {
|
|
263
|
+
"instrument": x.underlying_instrument.id,
|
|
264
|
+
"parent_instrument": _get_parent_instrument_id(
|
|
265
|
+
getattr(x, "parent_portfolio", "portfolio")
|
|
266
|
+
),
|
|
267
|
+
"rebalancing_weights": x.weighting,
|
|
268
|
+
},
|
|
269
|
+
self.composition_portfolio.get_positions(
|
|
270
|
+
self.last_rebalancing_date, with_intermediary_position=True
|
|
271
|
+
),
|
|
272
|
+
),
|
|
273
|
+
columns=["instrument", "parent_instrument", "rebalancing_weights"],
|
|
274
|
+
)
|
|
275
|
+
.groupby(["parent_instrument", "instrument"])
|
|
276
|
+
.sum()
|
|
277
|
+
)
|
|
278
|
+
|
|
279
|
+
df = pd.concat(
|
|
280
|
+
[tree_positions_effective_date_df, tree_positions_rebalancing_date_df], axis=1
|
|
281
|
+
).reset_index()
|
|
282
|
+
|
|
283
|
+
if not df["parent_instrument"].isnull().any():
|
|
284
|
+
df = pd.concat(
|
|
285
|
+
[
|
|
286
|
+
pd.DataFrame(
|
|
287
|
+
[
|
|
288
|
+
{
|
|
289
|
+
"instrument": self.portfolio.instruments.first().id,
|
|
290
|
+
"parent_instrument": None,
|
|
291
|
+
"effective_weights": 1.0,
|
|
292
|
+
"rebalancing_weights": 1.0,
|
|
293
|
+
}
|
|
294
|
+
]
|
|
295
|
+
),
|
|
296
|
+
df,
|
|
297
|
+
],
|
|
298
|
+
ignore_index=True,
|
|
299
|
+
)
|
|
300
|
+
|
|
301
|
+
df = df.reset_index(names="id")
|
|
302
|
+
|
|
303
|
+
def _get_parent_id(x):
|
|
304
|
+
dff = df.loc[df["instrument"] == x, "id"]
|
|
305
|
+
if not dff.empty:
|
|
306
|
+
return dff.iloc[0]
|
|
307
|
+
return None
|
|
308
|
+
|
|
309
|
+
def _get_group_key(x):
|
|
310
|
+
return str(int(x)) if not df.loc[df["parent_row_id"] == x, :].empty else None
|
|
311
|
+
|
|
312
|
+
df["parent_row_id"] = df["parent_instrument"].apply(lambda x: _get_parent_id(x))
|
|
313
|
+
df["_group_key"] = df["id"].apply(lambda x: _get_group_key(x))
|
|
314
|
+
df = df.drop(columns=["parent_instrument"])
|
|
315
|
+
return df
|
|
316
|
+
|
|
317
|
+
def manipulate_dataframe(self, df):
|
|
318
|
+
df["instrument"] = df["instrument"].map(
|
|
319
|
+
dict(Instrument.objects.filter(id__in=df["instrument"]).values_list("id", "name_repr"))
|
|
320
|
+
)
|
|
321
|
+
return df
|
|
@@ -10,7 +10,8 @@ from wbcore.pandas import fields as pf
|
|
|
10
10
|
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
11
11
|
from wbcore.serializers import decorator
|
|
12
12
|
from wbcore.utils.strings import format_number
|
|
13
|
-
from wbfdm.models import Classification, ClassificationGroup, Instrument
|
|
13
|
+
from wbfdm.models import Classification, ClassificationGroup, Instrument, InstrumentType
|
|
14
|
+
|
|
14
15
|
from wbportfolio.filters import (
|
|
15
16
|
AggregatedAssetPositionLiquidityFilter,
|
|
16
17
|
AssetPositionPandasFilter,
|
|
@@ -212,7 +213,7 @@ class AggregatedAssetPositionLiquidityPandasView(InternalUserPermissionMixin, Ex
|
|
|
212
213
|
|
|
213
214
|
# Take the liquidity query for the two dates.
|
|
214
215
|
qs_assets = queryset.filter(
|
|
215
|
-
|
|
216
|
+
underlying_instrument__instrument_type=InstrumentType.EQUITY,
|
|
216
217
|
date__in=[historic_date, compared_date],
|
|
217
218
|
).values(
|
|
218
219
|
"date",
|
|
@@ -24,6 +24,7 @@ from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
|
24
24
|
from wbcore.utils.date import get_date_interval_from_request
|
|
25
25
|
from wbcore.utils.strings import format_number
|
|
26
26
|
from wbfdm.models import Instrument, InstrumentPrice, RelatedInstrumentThroughModel
|
|
27
|
+
|
|
27
28
|
from wbportfolio.filters import (
|
|
28
29
|
PerformanceComparisonFilter,
|
|
29
30
|
PerformancePandasFilter,
|
wbportfolio/viewsets/products.py
CHANGED
|
@@ -36,6 +36,7 @@ from wbcore.utils.strings import format_number
|
|
|
36
36
|
from wbfdm.contrib.metric.backends.performances import PERFORMANCE_METRIC
|
|
37
37
|
from wbfdm.contrib.metric.viewsets.mixins import InstrumentMetricMixin
|
|
38
38
|
from wbfdm.models import Instrument, InstrumentPrice
|
|
39
|
+
|
|
39
40
|
from wbportfolio import serializers
|
|
40
41
|
from wbportfolio.filters import (
|
|
41
42
|
BaseProductFilterSet,
|
|
@@ -11,6 +11,7 @@ from rest_framework.response import Response
|
|
|
11
11
|
from wbcore import viewsets
|
|
12
12
|
from wbcore.contrib.notifications.dispatch import send_notification
|
|
13
13
|
from wbcore.utils.strings import format_number
|
|
14
|
+
|
|
14
15
|
from wbportfolio.models import AccountReconciliation, AccountReconciliationLine
|
|
15
16
|
from wbportfolio.models.reconciliations.account_reconciliation_lines import (
|
|
16
17
|
AccountReconciliationLineQuerySet,
|
wbportfolio/viewsets/roles.py
CHANGED
wbportfolio/viewsets/signals.py
CHANGED
|
@@ -6,6 +6,7 @@ from rest_framework.reverse import reverse
|
|
|
6
6
|
from wbcore.contrib.icons import WBIcon
|
|
7
7
|
from wbcore.metadata.configs import buttons as bt
|
|
8
8
|
from wbcore.signals.instance_buttons import add_instance_button
|
|
9
|
+
|
|
9
10
|
from wbportfolio.viewsets.products import ProductModelViewSet
|
|
10
11
|
|
|
11
12
|
|
|
@@ -17,6 +17,7 @@ from .fees import (
|
|
|
17
17
|
FeesModelViewSet,
|
|
18
18
|
FeesPortfolioModelViewSet,
|
|
19
19
|
)
|
|
20
|
+
from .rebalancing import RebalancingModelRepresentationViewSet, RebalancerRepresentationViewSet, RebalancerModelViewSet
|
|
20
21
|
from .trade_proposals import (
|
|
21
22
|
TradeProposalModelViewSet,
|
|
22
23
|
TradeProposalPortfolioModelViewSet,
|
|
@@ -43,6 +43,7 @@ from wbcore.utils.strings import format_number
|
|
|
43
43
|
from wbcrm.models.accounts import Account
|
|
44
44
|
from wbfdm.models import ClassificationGroup, InstrumentPrice
|
|
45
45
|
from wbfdm.preferences import get_default_classification_group
|
|
46
|
+
|
|
46
47
|
from wbportfolio.analysis.claims import ConsolidatedTradeSummary
|
|
47
48
|
from wbportfolio.filters import (
|
|
48
49
|
ClaimFilter,
|
|
@@ -51,9 +52,9 @@ from wbportfolio.filters import (
|
|
|
51
52
|
CustomerAPIFilter,
|
|
52
53
|
CustomerClaimFilter,
|
|
53
54
|
CustomerClaimGroupByFilter,
|
|
55
|
+
DistributionNNMChartFilter,
|
|
54
56
|
NegativeTermimalAccountPerProductFilterSet,
|
|
55
57
|
ProfitAndLossPandasFilter,
|
|
56
|
-
DistributionNNMChartFilter,
|
|
57
58
|
)
|
|
58
59
|
from wbportfolio.models import Product, Trade
|
|
59
60
|
from wbportfolio.models.transactions.claim import Claim, ClaimGroupbyChoice
|
|
@@ -8,6 +8,7 @@ from wbcore.pandas import fields as pf
|
|
|
8
8
|
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
9
9
|
from wbcore.serializers import decorator
|
|
10
10
|
from wbcore.utils.strings import format_number
|
|
11
|
+
|
|
11
12
|
from wbportfolio.filters import FeesAggregatedFilter, FeesFilter, FeesPortfolioFilterSet
|
|
12
13
|
from wbportfolio.models import Fees
|
|
13
14
|
from wbportfolio.serializers import FeesModelSerializer
|