wbportfolio 1.52.5__tar.gz → 1.53.0__tar.gz
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-1.52.5 → wbportfolio-1.53.0}/PKG-INFO +1 -1
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/portfolios.py +1 -0
- wbportfolio-1.53.0/wbportfolio/migrations/0078_trade_drift_factor.py +26 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/asset.py +3 -2
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/portfolio.py +17 -2
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/trade_proposals.py +80 -71
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/trades.py +66 -32
- wbportfolio-1.53.0/wbportfolio/pms/trading/handler.py +210 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/typing.py +63 -20
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/models/model_portfolio.py +11 -14
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/trade_proposals.py +18 -1
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/trades.py +33 -5
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_portfolios.py +10 -9
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/test_trade_proposals.py +230 -13
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/rebalancing/test_models.py +10 -16
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/trade_proposals.py +9 -1
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/trade_proposals.py +5 -4
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/trades.py +36 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/trade_proposals.py +3 -1
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/trades.py +53 -45
- wbportfolio-1.52.5/wbportfolio/pms/trading/handler.py +0 -161
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/.gitignore +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/LICENSE +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/pyproject.toml +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/asset.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/indexes.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/portfolio_relationships.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/dividends.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/admin/transactions/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/analysis/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/analysis/claims.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/apps.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/admin.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/apps.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/configs/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/configs/display.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/configs/endpoints.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/configs/previews.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/constants.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/dynamic_preferences_registry.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/factories.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/filters.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/management.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/migrations/0001_initial.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/migrations/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/models.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/scripts.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/serializers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/tasks.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/tests/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/tests/test_models.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/urls.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/contrib/company_portfolio/viewsets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/defaults/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/defaults/fees/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/defaults/fees/default.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/dynamic_preferences_registry.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/dividends.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/indexes.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/factories/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/fdm/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/fdm/tasks.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/performances.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/filters/transactions/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/fixtures/product_factsheets.yaml +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/fixtures/wbportfolio.yaml.gz +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/fixtures/wbrisk_management.yaml.gz +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/refinitiv/adjustment.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/ubs/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/ubs/asset_position.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/ubs/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/ubs/instrument_price.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/ubs/mixin.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/wbfdm/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/wbfdm/adjustment.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/wbfdm/dividend.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/backends/wbfdm/mixin.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/adjustment.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/asset_position.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/dividend.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/register.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/handlers/trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/default_mapping.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/jpmorgan/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/jpmorgan/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/jpmorgan/strategy.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/jpmorgan/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/leonteq/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/d1_equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/d1_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/d1_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/d1_valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/dividend.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/natixis/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/refinitiv/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/refinitiv/adjustment.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/perf_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/sylk.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/sg_lux/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/societe_generale/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/societe_generale/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/societe_generale/strategy.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/societe_generale/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/tellco/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/tellco/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/tellco/equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/tellco/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/api/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/api/asset_position.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/api/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/api/instrument_price.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/api/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/equity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/ubs/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/asset_position.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/management_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/performance_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/trade.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/valuation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/parsers/vontobel/valuation_api.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/resources/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/resources/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/resources/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/import_export/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/kpi_handlers/nnm.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/de/LC_MESSAGES/django.mo +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/de/LC_MESSAGES/django.po +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/en/LC_MESSAGES/django.mo +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/en/LC_MESSAGES/django.po +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/fr/LC_MESSAGES/django.mo +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/locale/fr/LC_MESSAGES/django.po +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/backends/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/backends/base.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/backends/constants.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/backends/portfolio_base.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/backends/portfolio_esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/tests/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/tests/conftest.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/tests/test_portfolio_base.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/metric/tests/test_portfolio_esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0001_initial_squashed.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0002_product_default_sub_account_squashed_0039_alter_assetallocation_company_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0040_instrument_financial_instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0041_remove_listresearch_research_ptr_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0042_instrumentlist_instrumentlistthroughmodel_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0043_alter_instrumentlistthroughmodel_options_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0044_alter_instrumentlist_identifier.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0045_alter_instrument_financial_instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0046_add_product_default_account.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0047_remove_product_default_sub_account.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0048_alter_trade_status.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0049_trade_claimed_shares.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0050_fees_fee_date_fees_wbportfolio_transac_1f7a29_idx.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0051_delete_macroreview.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0053_remove_product_group.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0054_portfolioinstrumentpreferredclassificationthroughmodel_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0055_remove_product__custom_management_rebates_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0056_remove_companyportfoliodata_assets_under_management_currency_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0057_alter_portfolio_preferred_instrument_classifications_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0058_pmsinstrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0059_fees_unique_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0060_alter_portfolioportfoliothroughmodel_type.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0061_portfolio_bank_accounts_product_bank_account_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0062_alter_dailyportfoliocashflow_options.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0063_accountreconciliation_accountreconciliationline_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0064_alter_portfolio_managers_portfolio_is_tracked_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0065_alter_portfolio_managers_claim_as_shares_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0066_assetposition_initial_shares_at_custodian_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0067_assetposition_unique_asset_position.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0068_trade_internal_trade_trade_marked_as_internal_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0069_remove_portfolio_is_invested_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0071_alter_trade_options_alter_trade_order.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0072_trade_diff_shares.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0074_alter_rebalancer_frequency_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0075_portfolio_initial_position_date_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0076_alter_dividendtransaction_price_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/migrations/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/exceptions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/graphs/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/graphs/portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/graphs/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/indexes.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/llm/wbcrm/analyze_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/mixins/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/mixins/instruments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/mixins/liquidity_stress_test.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/portfolio_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/reconciliations/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/reconciliations/account_reconciliation_lines.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/reconciliations/account_reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/reconciliations/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/dividends.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/transactions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/permissions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/analytics/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/analytics/portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/statistics/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/pms/trading/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/preferences.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/base.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/decorators.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/models/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/models/composite.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/models/equally_weighted.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/rebalancing/models/market_capitalization_weighted.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/reports/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/reports/monthly_position_report.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/accounts.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/controversy_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/exposure_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/instrument_list_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/liquidity_risk.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/liquidity_stress_instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/product_integrity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/stop_loss_instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/stop_loss_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/backends/ucits_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/conftest.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_accounts.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_controversy_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_exposure_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_liquidity_risk.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_product_integrity.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_stop_loss_instrument.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/risk_management/tests/test_ucits_portfolio.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/portfolio_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/portfolio_swing_pricing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/product_group.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/dividends.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/serializers/transactions/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/css/macro_review.css +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/account_holding_reconciliation.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/aggregate_asset_position_liquidity.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/company.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/earnings_instrument.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/financial_analysis_instrument_ratios.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/financial_statistics.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/static/wbportfolio/markdown/documentation/person.md +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tasks.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/templates/portfolio/email/customer_report.html +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/templates/portfolio/email/customer_trade_notification.html +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/templates/portfolio/email/email_base_template.html +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/templates/portfolio/email/rebalancing_report.html +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/templates/portfolio/macro/macro_review.html +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/conftest.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_account_reconciliation.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_customer_trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_dividends.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_imports.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_instrument_mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_merge.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_portfolio_cash_targets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/test_splits.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/test_claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/test_fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/test_rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/transactions/test_trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/models/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/pms/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/pms/test_analytics.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/rebalancing/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/serializers/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/serializers/test_claims.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/tests.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/test_assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/test_performances.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/test_products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/tests/viewsets/transactions/test_claims.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/urls.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/utils.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/charts/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/charts/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/claims.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/buttons/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/portfolio_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/product_performance.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/display/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/portfolio_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/product_performance.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/rebalancing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/endpoints/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/instrument_prices.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/product_performance.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/menu/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/previews/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/previews/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/adjustments.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/assets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/instrument_prices.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/product_performance.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/configs/titles/trades.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/custodians.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/esg.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/portfolio_relationship.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/portfolio_swing_pricing.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/portfolios.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/positions.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/product_groups.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/product_performance.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/products.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/reconciliations.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/registers.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/roles.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/signals.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/__init__.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/claim.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/fees.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/mixins.py +0 -0
- {wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/viewsets/transactions/rebalancing.py +0 -0
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Generated by Django 5.0.14 on 2025-07-02 13:10
|
|
2
|
+
|
|
3
|
+
from decimal import Decimal
|
|
4
|
+
from django.db import migrations, models
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class Migration(migrations.Migration):
|
|
8
|
+
|
|
9
|
+
dependencies = [
|
|
10
|
+
('wbportfolio', '0077_remove_transaction_currency_and_more'),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AddField(
|
|
15
|
+
model_name='trade',
|
|
16
|
+
name='drift_factor',
|
|
17
|
+
field=models.DecimalField(decimal_places=6, default=Decimal('1'), help_text='Drift factor to be applied to the previous portfolio weight to get the actual effective weight including daily return', max_digits=16, verbose_name='Drift Factor'),
|
|
18
|
+
),
|
|
19
|
+
migrations.AlterField(
|
|
20
|
+
model_name='trade',
|
|
21
|
+
name='weighting',
|
|
22
|
+
field=models.DecimalField(decimal_places=8, default=Decimal('0'),
|
|
23
|
+
help_text='The weight to be multiplied against the target', max_digits=9,
|
|
24
|
+
verbose_name='Weight'),
|
|
25
|
+
),
|
|
26
|
+
]
|
|
@@ -693,7 +693,7 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
693
693
|
def get_portfolio_total_asset_value(self) -> Decimal:
|
|
694
694
|
return self.portfolio.get_total_asset_value(self.date)
|
|
695
695
|
|
|
696
|
-
def _build_dto(self, new_weight: Decimal = None) -> PositionDTO:
|
|
696
|
+
def _build_dto(self, new_weight: Decimal = None, **kwargs) -> PositionDTO:
|
|
697
697
|
"""
|
|
698
698
|
Data Transfer Object
|
|
699
699
|
Returns:
|
|
@@ -708,7 +708,7 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
708
708
|
instrument_type=self.underlying_quote.security_instrument_type.id,
|
|
709
709
|
currency=self.underlying_quote.currency.id,
|
|
710
710
|
country=self.underlying_quote.country.id if self.underlying_quote.country else None,
|
|
711
|
-
is_cash=self.underlying_quote.is_cash,
|
|
711
|
+
is_cash=self.underlying_quote.is_cash or self.underlying_quote.is_cash_equivalent,
|
|
712
712
|
primary_classification=(
|
|
713
713
|
self.underlying_quote.primary_classification.id
|
|
714
714
|
if self.underlying_quote.primary_classification
|
|
@@ -726,6 +726,7 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
726
726
|
price=self._price,
|
|
727
727
|
currency_fx_rate=self._currency_fx_rate,
|
|
728
728
|
portfolio_created=self.portfolio_created.id if self.portfolio_created else None,
|
|
729
|
+
**kwargs,
|
|
729
730
|
)
|
|
730
731
|
|
|
731
732
|
@cached_property
|
|
@@ -355,8 +355,23 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
355
355
|
|
|
356
356
|
def _build_dto(self, val_date: date, **extra_kwargs) -> PortfolioDTO:
|
|
357
357
|
"returns the dto representation of this portfolio at the specified date"
|
|
358
|
+
assets = self.assets.filter(date=val_date, **extra_kwargs)
|
|
359
|
+
try:
|
|
360
|
+
drifted_weights = self.get_analytic_portfolio(val_date).get_next_weights()
|
|
361
|
+
except InvalidAnalyticPortfolio:
|
|
362
|
+
drifted_weights = {}
|
|
358
363
|
return PortfolioDTO(
|
|
359
|
-
tuple(
|
|
364
|
+
tuple(
|
|
365
|
+
[
|
|
366
|
+
pos._build_dto(
|
|
367
|
+
drift_factor=drifted_weights.get(pos.underlying_quote.id, float(pos.weighting))
|
|
368
|
+
/ float(pos.weighting)
|
|
369
|
+
if pos.weighting
|
|
370
|
+
else Decimal(1.0)
|
|
371
|
+
)
|
|
372
|
+
for pos in assets
|
|
373
|
+
]
|
|
374
|
+
),
|
|
360
375
|
)
|
|
361
376
|
|
|
362
377
|
def get_weights(self, val_date: date) -> dict[int, float]:
|
|
@@ -926,7 +941,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
926
941
|
if self.is_composition:
|
|
927
942
|
assets = list(self.get_lookthrough_positions(val_date, **kwargs))
|
|
928
943
|
else:
|
|
929
|
-
assets = self.assets.filter(date=val_date)
|
|
944
|
+
assets = list(self.assets.filter(date=val_date))
|
|
930
945
|
return assets
|
|
931
946
|
|
|
932
947
|
def compute_lookthrough(self, from_date: date, to_date: date | None = None):
|
{wbportfolio-1.52.5 → wbportfolio-1.53.0}/wbportfolio/models/transactions/trade_proposals.py
RENAMED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
import math
|
|
2
3
|
from contextlib import suppress
|
|
3
4
|
from datetime import date, timedelta
|
|
4
5
|
from decimal import Decimal
|
|
5
|
-
from typing import TypeVar
|
|
6
|
+
from typing import Any, TypeVar
|
|
6
7
|
|
|
7
8
|
from celery import shared_task
|
|
8
|
-
from django.contrib.messages import error, info
|
|
9
9
|
from django.core.exceptions import ValidationError
|
|
10
10
|
from django.db import models
|
|
11
11
|
from django.utils.functional import cached_property
|
|
@@ -92,14 +92,14 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
92
92
|
)
|
|
93
93
|
super().save(*args, **kwargs)
|
|
94
94
|
|
|
95
|
-
@property
|
|
96
|
-
def checked_object(self):
|
|
97
|
-
return self.portfolio
|
|
98
|
-
|
|
99
95
|
@property
|
|
100
96
|
def check_evaluation_date(self):
|
|
101
97
|
return self.trade_date
|
|
102
98
|
|
|
99
|
+
@property
|
|
100
|
+
def checked_object(self) -> Any:
|
|
101
|
+
return self.portfolio
|
|
102
|
+
|
|
103
103
|
@cached_property
|
|
104
104
|
def portfolio_total_asset_value(self) -> Decimal:
|
|
105
105
|
return self.portfolio.get_total_asset_value(self.last_effective_date)
|
|
@@ -109,10 +109,13 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
109
109
|
"""
|
|
110
110
|
This property holds the validated trading services and cache it.This property expect to be set only if is_valid return True
|
|
111
111
|
"""
|
|
112
|
+
target_portfolio = self._build_dto().convert_to_portfolio()
|
|
113
|
+
|
|
112
114
|
return TradingService(
|
|
113
115
|
self.trade_date,
|
|
114
|
-
effective_portfolio=self.
|
|
115
|
-
target_portfolio=
|
|
116
|
+
effective_portfolio=self._get_default_effective_portfolio(),
|
|
117
|
+
target_portfolio=target_portfolio,
|
|
118
|
+
total_target_weight=target_portfolio.total_weight,
|
|
116
119
|
)
|
|
117
120
|
|
|
118
121
|
@cached_property
|
|
@@ -197,25 +200,30 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
197
200
|
|
|
198
201
|
return trade_proposal_clone
|
|
199
202
|
|
|
200
|
-
def normalize_trades(self):
|
|
203
|
+
def normalize_trades(self, total_target_weight: Decimal = Decimal("1.0")):
|
|
201
204
|
"""
|
|
202
205
|
Call the trading service with the existing trades and normalize them in order to obtain a total sum target weight of 100%
|
|
203
206
|
The existing trade will be modified directly with the given normalization factor
|
|
204
207
|
"""
|
|
205
|
-
service = TradingService(
|
|
206
|
-
|
|
208
|
+
service = TradingService(
|
|
209
|
+
self.trade_date,
|
|
210
|
+
effective_portfolio=self._get_default_effective_portfolio(),
|
|
211
|
+
target_portfolio=self._build_dto().convert_to_portfolio(),
|
|
212
|
+
total_target_weight=total_target_weight,
|
|
213
|
+
)
|
|
207
214
|
leftovers_trades = self.trades.all()
|
|
208
|
-
total_target_weight = Decimal("0.0")
|
|
209
215
|
for underlying_instrument_id, trade_dto in service.trades_batch.trades_map.items():
|
|
210
216
|
with suppress(Trade.DoesNotExist):
|
|
211
217
|
trade = self.trades.get(underlying_instrument_id=underlying_instrument_id)
|
|
212
218
|
trade.weighting = round(trade_dto.delta_weight, 6)
|
|
213
219
|
trade.save()
|
|
214
|
-
total_target_weight += trade._target_weight
|
|
215
220
|
leftovers_trades = leftovers_trades.exclude(id=trade.id)
|
|
216
221
|
leftovers_trades.delete()
|
|
222
|
+
t_weight = self.trades.all().annotate_base_info().aggregate(models.Sum("target_weight"))[
|
|
223
|
+
"target_weight__sum"
|
|
224
|
+
] or Decimal("0.0")
|
|
217
225
|
# we handle quantization error due to the decimal max digits. In that case, we take the biggest trade (highest weight) and we remove the quantization error
|
|
218
|
-
if quantize_error := (
|
|
226
|
+
if quantize_error := (t_weight - total_target_weight):
|
|
219
227
|
biggest_trade = self.trades.latest("weighting")
|
|
220
228
|
biggest_trade.weighting -= quantize_error
|
|
221
229
|
biggest_trade.save()
|
|
@@ -232,23 +240,31 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
232
240
|
if self.trades.exists():
|
|
233
241
|
return self._build_dto().convert_to_portfolio()
|
|
234
242
|
# Return the current portfolio by default
|
|
243
|
+
return self._get_default_effective_portfolio()
|
|
244
|
+
|
|
245
|
+
def _get_default_effective_portfolio(self):
|
|
235
246
|
return self.portfolio._build_dto(self.last_effective_date)
|
|
236
247
|
|
|
237
|
-
def reset_trades(
|
|
248
|
+
def reset_trades(
|
|
249
|
+
self,
|
|
250
|
+
target_portfolio: PortfolioDTO | None = None,
|
|
251
|
+
validate_trade: bool = True,
|
|
252
|
+
total_target_weight: Decimal = Decimal("1.0"),
|
|
253
|
+
):
|
|
238
254
|
"""
|
|
239
255
|
Will delete all existing trades and recreate them from the method `create_or_update_trades`
|
|
240
256
|
"""
|
|
241
257
|
# delete all existing trades
|
|
242
258
|
last_effective_date = self.last_effective_date
|
|
243
259
|
# Get effective and target portfolio
|
|
244
|
-
effective_portfolio = self.portfolio._build_dto(last_effective_date)
|
|
245
260
|
if not target_portfolio:
|
|
246
261
|
target_portfolio = self._get_default_target_portfolio()
|
|
247
262
|
if target_portfolio:
|
|
248
263
|
service = TradingService(
|
|
249
264
|
self.trade_date,
|
|
250
|
-
effective_portfolio=
|
|
265
|
+
effective_portfolio=self._get_default_effective_portfolio(),
|
|
251
266
|
target_portfolio=target_portfolio,
|
|
267
|
+
total_target_weight=total_target_weight,
|
|
252
268
|
)
|
|
253
269
|
if validate_trade:
|
|
254
270
|
service.is_valid()
|
|
@@ -262,11 +278,13 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
262
278
|
)
|
|
263
279
|
# we cannot do a bulk-create because Trade is a multi table inheritance
|
|
264
280
|
weighting = round(trade_dto.delta_weight, 6)
|
|
281
|
+
drift_factor = trade_dto.drift_factor
|
|
265
282
|
try:
|
|
266
283
|
trade = self.trades.get(underlying_instrument=instrument)
|
|
267
284
|
trade.weighting = weighting
|
|
268
285
|
trade.currency_fx_rate = currency_fx_rate
|
|
269
286
|
trade.status = Trade.Status.DRAFT
|
|
287
|
+
trade.drift_factor = drift_factor
|
|
270
288
|
except Trade.DoesNotExist:
|
|
271
289
|
trade = Trade(
|
|
272
290
|
underlying_instrument=instrument,
|
|
@@ -276,9 +294,15 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
276
294
|
trade_proposal=self,
|
|
277
295
|
portfolio=self.portfolio,
|
|
278
296
|
weighting=weighting,
|
|
297
|
+
drift_factor=drift_factor,
|
|
279
298
|
status=Trade.Status.DRAFT,
|
|
280
299
|
currency_fx_rate=currency_fx_rate,
|
|
281
300
|
)
|
|
301
|
+
trade.price = trade.get_price()
|
|
302
|
+
# if we cannot automatically find a price, we consider the stock is invalid and we sell it
|
|
303
|
+
if trade.price is None:
|
|
304
|
+
trade.price = Decimal("0.0")
|
|
305
|
+
trade.weighting = -trade_dto.effective_weight
|
|
282
306
|
trade.save()
|
|
283
307
|
|
|
284
308
|
def replay(self):
|
|
@@ -329,7 +353,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
329
353
|
last_trade_proposal_created = False
|
|
330
354
|
last_trade_proposal = next_trade_proposal
|
|
331
355
|
|
|
332
|
-
def get_estimated_shares(self, weight: Decimal, underlying_quote: Instrument) -> Decimal:
|
|
356
|
+
def get_estimated_shares(self, weight: Decimal, underlying_quote: Instrument, quote_price: Decimal) -> Decimal:
|
|
333
357
|
"""
|
|
334
358
|
Estimates the number of shares for a trade based on the given weight and underlying quote.
|
|
335
359
|
|
|
@@ -342,23 +366,29 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
342
366
|
Returns:
|
|
343
367
|
Decimal | None: The estimated number of shares or None if the calculation fails.
|
|
344
368
|
"""
|
|
345
|
-
|
|
346
|
-
# Retrieve the price of the underlying quote on the trade date TODO: this is very slow and probably due to the to_date argument to the dl which slowdown drastically the query
|
|
347
|
-
quote_price = Decimal(underlying_quote.get_price(self.trade_date))
|
|
369
|
+
# Retrieve the price of the underlying quote on the trade date TODO: this is very slow and probably due to the to_date argument to the dl which slowdown drastically the query
|
|
348
370
|
|
|
349
|
-
|
|
350
|
-
|
|
371
|
+
# Calculate the trade's total value in the portfolio's currency
|
|
372
|
+
trade_total_value_fx_portfolio = self.portfolio_total_asset_value * weight
|
|
351
373
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
374
|
+
# Convert the quote price to the portfolio's currency
|
|
375
|
+
price_fx_portfolio = quote_price * underlying_quote.currency.convert(
|
|
376
|
+
self.trade_date, self.portfolio.currency, exact_lookup=False
|
|
377
|
+
)
|
|
378
|
+
|
|
379
|
+
# If the price is valid, calculate and return the estimated shares
|
|
380
|
+
if price_fx_portfolio:
|
|
381
|
+
return trade_total_value_fx_portfolio / price_fx_portfolio
|
|
356
382
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
383
|
+
def get_round_lot_size(self, shares: Decimal, underlying_quote: Instrument) -> Decimal:
|
|
384
|
+
if (round_lot_size := underlying_quote.round_lot_size) != 1 and (
|
|
385
|
+
not underlying_quote.exchange or underlying_quote.exchange.apply_round_lot_size
|
|
386
|
+
):
|
|
387
|
+
if shares > 0:
|
|
388
|
+
shares = math.ceil(shares / round_lot_size) * round_lot_size
|
|
389
|
+
elif abs(shares) > round_lot_size:
|
|
390
|
+
shares = math.floor(shares / round_lot_size) * round_lot_size
|
|
391
|
+
return shares
|
|
362
392
|
|
|
363
393
|
def get_estimated_target_cash(self, currency: Currency) -> AssetPosition:
|
|
364
394
|
"""
|
|
@@ -399,7 +429,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
399
429
|
|
|
400
430
|
# Estimate the target shares for the cash component
|
|
401
431
|
with suppress(ValueError):
|
|
402
|
-
total_target_shares = self.get_estimated_shares(target_cash_weight, cash_component)
|
|
432
|
+
total_target_shares = self.get_estimated_shares(target_cash_weight, cash_component, Decimal("1.0"))
|
|
403
433
|
|
|
404
434
|
cash_component = Cash.objects.get_or_create(
|
|
405
435
|
currency=self.portfolio.currency, defaults={"name": self.portfolio.currency.title}
|
|
@@ -447,46 +477,25 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
447
477
|
},
|
|
448
478
|
)
|
|
449
479
|
def submit(self, by=None, description=None, **kwargs):
|
|
450
|
-
self.reset_trades(target_portfolio=self._build_dto().convert_to_portfolio())
|
|
451
480
|
trades = []
|
|
452
|
-
|
|
481
|
+
trades_validation_warnings = []
|
|
453
482
|
for trade in self.trades.all():
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
)
|
|
459
|
-
else:
|
|
460
|
-
trade.status = Trade.Status.SUBMIT
|
|
483
|
+
trade_warnings = trade.submit(
|
|
484
|
+
by=by, description=description, portfolio_total_asset_value=self.portfolio_total_asset_value, **kwargs
|
|
485
|
+
)
|
|
486
|
+
if trade_warnings:
|
|
487
|
+
trades_validation_warnings.extend(trade_warnings)
|
|
461
488
|
trades.append(trade)
|
|
462
489
|
|
|
463
|
-
Trade.objects.bulk_update(trades, ["status"])
|
|
490
|
+
Trade.objects.bulk_update(trades, ["status", "shares", "weighting"])
|
|
464
491
|
|
|
465
492
|
# If we estimate cash on this trade proposal, we make sure to create the corresponding cash component
|
|
466
493
|
estimated_cash_position = self.get_estimated_target_cash(self.portfolio.currency)
|
|
467
|
-
target_portfolio = self.validated_trading_service.
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
estimated_cash_position.underlying_quote.id
|
|
471
|
-
):
|
|
472
|
-
existing_cash_position += estimated_cash_position
|
|
473
|
-
else:
|
|
474
|
-
target_portfolio.positions_map[estimated_cash_position.underlying_quote.id] = (
|
|
475
|
-
estimated_cash_position._build_dto()
|
|
476
|
-
)
|
|
477
|
-
target_portfolio = PortfolioDTO(positions=tuple(target_portfolio.positions_map.values()))
|
|
494
|
+
target_portfolio = self.validated_trading_service.trades_batch.convert_to_portfolio(
|
|
495
|
+
estimated_cash_position._build_dto()
|
|
496
|
+
)
|
|
478
497
|
self.evaluate_active_rules(self.trade_date, target_portfolio, asynchronously=True)
|
|
479
|
-
|
|
480
|
-
if (
|
|
481
|
-
trades_validation_errors
|
|
482
|
-
and (fsm_context := getattr(self, "fsm_context", None))
|
|
483
|
-
and (request := fsm_context.get("request", None))
|
|
484
|
-
):
|
|
485
|
-
msg = f"""The reason for the failed trades are: <ul>
|
|
486
|
-
{''.join(map(lambda o: '<li>' + o + '</li>', trades_validation_errors))}
|
|
487
|
-
</ul>
|
|
488
|
-
"""
|
|
489
|
-
error(request, msg, extra_tags="auto_close=0")
|
|
498
|
+
return trades_validation_warnings
|
|
490
499
|
|
|
491
500
|
def can_submit(self):
|
|
492
501
|
errors = dict()
|
|
@@ -496,7 +505,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
496
505
|
service = self.validated_trading_service
|
|
497
506
|
try:
|
|
498
507
|
service.is_valid(ignore_error=True)
|
|
499
|
-
# if service.trades_batch.
|
|
508
|
+
# if service.trades_batch.total_abs_delta_weight == 0:
|
|
500
509
|
# errors_list.append(
|
|
501
510
|
# "There is no change detected in this trade proposal. Please submit at last one valid trade"
|
|
502
511
|
# )
|
|
@@ -542,6 +551,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
542
551
|
raise ValueError("Non-Rebalanceable portfolio cannot be traded manually.")
|
|
543
552
|
trades = []
|
|
544
553
|
assets = []
|
|
554
|
+
warnings = []
|
|
545
555
|
# We do not want to create the estimated cash position if there is not trades in the trade proposal (shouldn't be possible anyway)
|
|
546
556
|
estimated_cash_position = self.get_estimated_target_cash(self.portfolio.currency)
|
|
547
557
|
|
|
@@ -556,13 +566,11 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
556
566
|
|
|
557
567
|
# if there is cash leftover, we create an extra asset position to hold the cash component
|
|
558
568
|
if estimated_cash_position.weighting and len(trades) > 0:
|
|
569
|
+
warnings.append(
|
|
570
|
+
f"We created automatically a cash position of weight {estimated_cash_position.weighting:.2%}"
|
|
571
|
+
)
|
|
559
572
|
estimated_cash_position.pre_save()
|
|
560
573
|
assets.append(estimated_cash_position)
|
|
561
|
-
if (fsm_context := getattr(self, "fsm_context", None)) and (request := fsm_context.get("request", None)):
|
|
562
|
-
info(
|
|
563
|
-
request,
|
|
564
|
-
f"We created automatically a cash position of weight {estimated_cash_position.weighting:.2%}",
|
|
565
|
-
)
|
|
566
574
|
|
|
567
575
|
Trade.objects.bulk_update(trades, ["status"])
|
|
568
576
|
self.portfolio.bulk_create_positions(
|
|
@@ -570,6 +578,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
570
578
|
)
|
|
571
579
|
if replay and self.portfolio.is_manageable:
|
|
572
580
|
replay_as_task.delay(self.id, user_id=by.id if by else None)
|
|
581
|
+
return warnings
|
|
573
582
|
|
|
574
583
|
def can_approve(self):
|
|
575
584
|
errors = dict()
|
|
@@ -53,7 +53,7 @@ class TradeQueryset(OrderedModelQuerySet):
|
|
|
53
53
|
.order_by("-date")
|
|
54
54
|
.values("date")[:1]
|
|
55
55
|
),
|
|
56
|
-
|
|
56
|
+
_previous_weight=Coalesce(
|
|
57
57
|
Subquery(
|
|
58
58
|
AssetPosition.unannotated_objects.filter(
|
|
59
59
|
underlying_quote=OuterRef("underlying_instrument"),
|
|
@@ -66,6 +66,7 @@ class TradeQueryset(OrderedModelQuerySet):
|
|
|
66
66
|
),
|
|
67
67
|
Decimal(0),
|
|
68
68
|
),
|
|
69
|
+
effective_weight=F("_previous_weight") * F("drift_factor"),
|
|
69
70
|
target_weight=F("effective_weight") + F("weighting"),
|
|
70
71
|
effective_shares=Coalesce(
|
|
71
72
|
Subquery(
|
|
@@ -163,8 +164,8 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
163
164
|
)
|
|
164
165
|
|
|
165
166
|
weighting = models.DecimalField(
|
|
166
|
-
max_digits=
|
|
167
|
-
decimal_places=
|
|
167
|
+
max_digits=9,
|
|
168
|
+
decimal_places=8,
|
|
168
169
|
default=Decimal(0),
|
|
169
170
|
help_text="The weight to be multiplied against the target",
|
|
170
171
|
verbose_name="Weight",
|
|
@@ -223,7 +224,13 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
223
224
|
on_delete=models.CASCADE,
|
|
224
225
|
help_text="The Trade Proposal this trade is coming from",
|
|
225
226
|
)
|
|
226
|
-
|
|
227
|
+
drift_factor = models.DecimalField(
|
|
228
|
+
max_digits=16,
|
|
229
|
+
decimal_places=6,
|
|
230
|
+
default=Decimal(1.0),
|
|
231
|
+
verbose_name="Drift Factor",
|
|
232
|
+
help_text="Drift factor to be applied to the previous portfolio weight to get the actual effective weight including daily return",
|
|
233
|
+
)
|
|
227
234
|
external_id = models.CharField(
|
|
228
235
|
max_length=255,
|
|
229
236
|
null=True,
|
|
@@ -249,9 +256,7 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
249
256
|
field=status,
|
|
250
257
|
source=Status.DRAFT,
|
|
251
258
|
target=GET_STATE(
|
|
252
|
-
lambda self, **kwargs: (
|
|
253
|
-
self.Status.SUBMIT if self.last_underlying_quote_price is not None else self.Status.FAILED
|
|
254
|
-
),
|
|
259
|
+
lambda self, **kwargs: (self.Status.SUBMIT if self.price else self.Status.FAILED),
|
|
255
260
|
states=[Status.SUBMIT, Status.FAILED],
|
|
256
261
|
),
|
|
257
262
|
permission=lambda instance, user: PortfolioRole.is_portfolio_manager(
|
|
@@ -270,8 +275,27 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
270
275
|
},
|
|
271
276
|
on_error="FAILED",
|
|
272
277
|
)
|
|
273
|
-
def submit(self, by=None, description=None, **kwargs):
|
|
274
|
-
|
|
278
|
+
def submit(self, by=None, description=None, portfolio_total_asset_value=None, **kwargs):
|
|
279
|
+
warnings = []
|
|
280
|
+
# if shares is defined and the underlying instrument defines a round lot size different than 1 and exchange allows its application, we round the share accordingly
|
|
281
|
+
if self.trade_proposal and not self.portfolio.only_weighting:
|
|
282
|
+
shares = self.trade_proposal.get_round_lot_size(self.shares, self.underlying_instrument)
|
|
283
|
+
if shares != self.shares:
|
|
284
|
+
warnings.append(
|
|
285
|
+
f"{self.underlying_instrument.computed_str} has a round lot size of {self.underlying_instrument.round_lot_size}: shares were rounded from {self.shares} to {shares}"
|
|
286
|
+
)
|
|
287
|
+
shares = round(shares) # ensure fractional shares are converted into integer
|
|
288
|
+
# we need to recompute the delta weight has we changed the number of shares
|
|
289
|
+
if shares != self.shares:
|
|
290
|
+
self.shares = shares
|
|
291
|
+
if portfolio_total_asset_value:
|
|
292
|
+
self.weighting = self.shares * self.price * self.currency_fx_rate / portfolio_total_asset_value
|
|
293
|
+
|
|
294
|
+
if not self.price:
|
|
295
|
+
warnings.append(
|
|
296
|
+
f"Trade failed because no price is found for {self.underlying_instrument.computed_str} on {self.transaction_date:%Y-%m-%d}"
|
|
297
|
+
)
|
|
298
|
+
return warnings
|
|
275
299
|
|
|
276
300
|
def can_submit(self):
|
|
277
301
|
pass
|
|
@@ -287,6 +311,7 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
287
311
|
def fail(self, **kwargs):
|
|
288
312
|
pass
|
|
289
313
|
|
|
314
|
+
# TODO To be removed
|
|
290
315
|
@cached_property
|
|
291
316
|
def last_underlying_quote_price(self) -> InstrumentPrice | None:
|
|
292
317
|
try:
|
|
@@ -343,7 +368,7 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
343
368
|
)
|
|
344
369
|
|
|
345
370
|
def can_execute(self):
|
|
346
|
-
if not self.
|
|
371
|
+
if not self.price:
|
|
347
372
|
return {"underlying_instrument": [_("Cannot execute a trade without a valid quote price")]}
|
|
348
373
|
if not self.portfolio.is_manageable:
|
|
349
374
|
return {
|
|
@@ -453,16 +478,14 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
453
478
|
@property
|
|
454
479
|
@admin.display(description="Effective Weight")
|
|
455
480
|
def _effective_weight(self) -> Decimal:
|
|
456
|
-
|
|
457
|
-
self
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
or Decimal(0),
|
|
465
|
-
)
|
|
481
|
+
if hasattr(self, "effective_weight"):
|
|
482
|
+
return self.effective_weight
|
|
483
|
+
previous_weight = AssetPosition.unannotated_objects.filter(
|
|
484
|
+
underlying_quote=self.underlying_instrument,
|
|
485
|
+
date=self._last_effective_date,
|
|
486
|
+
portfolio=self.portfolio,
|
|
487
|
+
).aggregate(s=Sum("weighting"))["s"] or Decimal(0)
|
|
488
|
+
return previous_weight * self.drift_factor
|
|
466
489
|
|
|
467
490
|
@property
|
|
468
491
|
@admin.display(description="Effective Shares")
|
|
@@ -531,19 +554,24 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
531
554
|
|
|
532
555
|
def save(self, *args, **kwargs):
|
|
533
556
|
if self.trade_proposal:
|
|
557
|
+
if not self.underlying_instrument.is_investable_universe:
|
|
558
|
+
self.underlying_instrument.is_investable_universe = True
|
|
559
|
+
self.underlying_instrument.save()
|
|
534
560
|
self.portfolio = self.trade_proposal.portfolio
|
|
535
561
|
self.transaction_date = self.trade_proposal.trade_date
|
|
536
562
|
self.value_date = self.trade_proposal.last_effective_date
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
563
|
+
if self.price is None:
|
|
564
|
+
# we try to get the price if not provided directly from the underlying instrument
|
|
565
|
+
self.price = self.get_price()
|
|
566
|
+
if self.trade_proposal and not self.portfolio.only_weighting:
|
|
567
|
+
estimated_shares = self.trade_proposal.get_estimated_shares(
|
|
568
|
+
self.weighting, self.underlying_instrument, self.price
|
|
569
|
+
)
|
|
570
|
+
if estimated_shares:
|
|
571
|
+
self.shares = estimated_shares
|
|
540
572
|
|
|
541
573
|
if not self.custodian and self.bank:
|
|
542
574
|
self.custodian = Custodian.get_by_mapping(self.bank)
|
|
543
|
-
if self.price is None:
|
|
544
|
-
# we try to get the price if not provided directly from the underlying instrument
|
|
545
|
-
with suppress(Exception):
|
|
546
|
-
self.price = self.underlying_instrument.get_price(self.value_date)
|
|
547
575
|
|
|
548
576
|
if self.transaction_subtype is None or self.trade_proposal:
|
|
549
577
|
# if subtype not provided, we extract it automatically from the existing data.
|
|
@@ -588,9 +616,6 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
588
616
|
"""
|
|
589
617
|
|
|
590
618
|
def get_asset(self) -> AssetPosition:
|
|
591
|
-
last_underlying_quote_price = self.last_underlying_quote_price
|
|
592
|
-
if not last_underlying_quote_price:
|
|
593
|
-
raise ValueError("No price found")
|
|
594
619
|
asset = AssetPosition(
|
|
595
620
|
underlying_quote=self.underlying_instrument,
|
|
596
621
|
portfolio_created=None,
|
|
@@ -598,9 +623,8 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
598
623
|
date=self.transaction_date,
|
|
599
624
|
initial_currency_fx_rate=self.currency_fx_rate,
|
|
600
625
|
weighting=self._target_weight,
|
|
601
|
-
initial_price=self.
|
|
626
|
+
initial_price=self.price,
|
|
602
627
|
initial_shares=None,
|
|
603
|
-
underlying_quote_price=self.last_underlying_quote_price,
|
|
604
628
|
asset_valuation_date=self.transaction_date,
|
|
605
629
|
currency=self.currency,
|
|
606
630
|
is_estimated=False,
|
|
@@ -609,6 +633,11 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
609
633
|
asset.pre_save()
|
|
610
634
|
return asset
|
|
611
635
|
|
|
636
|
+
def get_price(self) -> Decimal | None:
|
|
637
|
+
if self.value_date:
|
|
638
|
+
with suppress(ValueError):
|
|
639
|
+
return Decimal(self.underlying_instrument.get_price(self.value_date))
|
|
640
|
+
|
|
612
641
|
def delete(self, **kwargs):
|
|
613
642
|
pre_collection.send(sender=self.__class__, instance=self)
|
|
614
643
|
super().delete(**kwargs)
|
|
@@ -628,9 +657,14 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
628
657
|
underlying_instrument=self.underlying_instrument.id,
|
|
629
658
|
effective_weight=self._effective_weight,
|
|
630
659
|
target_weight=self._target_weight,
|
|
660
|
+
effective_shares=self._effective_shares,
|
|
661
|
+
target_shares=self._target_shares,
|
|
662
|
+
currency_fx_rate=self.currency_fx_rate,
|
|
663
|
+
price=self.price,
|
|
631
664
|
instrument_type=self.underlying_instrument.security_instrument_type.id,
|
|
632
665
|
currency=self.underlying_instrument.currency,
|
|
633
666
|
date=self.transaction_date,
|
|
667
|
+
is_cash=self.underlying_instrument.is_cash or self.underlying_instrument.is_cash_equivalent,
|
|
634
668
|
)
|
|
635
669
|
|
|
636
670
|
def get_alternative_valid_trades(self, share_delta: float = 0):
|