wbportfolio 1.46.9__tar.gz → 1.46.11__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.46.9 → wbportfolio-1.46.11}/PKG-INFO +1 -1
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/asset.py +12 -7
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/mixins/instruments.py +3 -1
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/portfolio.py +149 -120
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/rebalancing.py +9 -4
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/trade_proposals.py +2 -3
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/analytics/portfolio.py +4 -8
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/trading/handler.py +1 -1
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/models/market_capitalization_weighted.py +10 -9
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/trade_proposals.py +1 -1
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_portfolios.py +17 -14
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/pms/test_analytics.py +2 -2
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/rebalancing/test_models.py +4 -4
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/.gitignore +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/LICENSE +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/pyproject.toml +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/asset.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/indexes.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/portfolio_relationships.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/dividends.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/admin/transactions/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/analysis/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/analysis/claims.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/apps.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/admin.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/apps.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/configs/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/configs/display.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/configs/endpoints.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/configs/previews.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/constants.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/dynamic_preferences_registry.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/factories.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/filters.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/management.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/migrations/0001_initial.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/migrations/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/models.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/scripts.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/serializers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/tasks.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/tests/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/tests/test_models.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/urls.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/contrib/company_portfolio/viewsets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/defaults/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/defaults/fees/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/defaults/fees/default.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/dynamic_preferences_registry.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/dividends.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/indexes.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/factories/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/fdm/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/fdm/tasks.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/performances.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/signals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/filters/transactions/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/fixtures/product_factsheets.yaml +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/fixtures/wbportfolio.yaml.gz +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/fixtures/wbrisk_management.yaml.gz +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/refinitiv/adjustment.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/ubs/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/ubs/asset_position.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/ubs/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/ubs/instrument_price.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/ubs/mixin.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/wbfdm/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/wbfdm/adjustment.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/wbfdm/dividend.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/backends/wbfdm/mixin.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/adjustment.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/asset_position.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/dividend.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/register.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/handlers/trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/default_mapping.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/jpmorgan/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/jpmorgan/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/jpmorgan/strategy.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/jpmorgan/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/leonteq/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/d1_equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/d1_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/d1_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/d1_valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/dividend.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/natixis/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/refinitiv/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/refinitiv/adjustment.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/perf_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/sylk.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/sg_lux/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/societe_generale/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/societe_generale/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/societe_generale/strategy.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/societe_generale/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/tellco/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/tellco/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/tellco/equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/tellco/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/api/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/api/asset_position.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/api/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/api/instrument_price.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/api/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/equity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/ubs/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/asset_position.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/management_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/performance_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/trade.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/valuation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/parsers/vontobel/valuation_api.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/resources/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/resources/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/resources/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/import_export/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/kpi_handlers/nnm.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/backends/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/backends/base.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/backends/constants.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/backends/portfolio_base.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/backends/portfolio_esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/tests/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/tests/conftest.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/tests/test_portfolio_base.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/metric/tests/test_portfolio_esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0001_initial_squashed.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0002_product_default_sub_account_squashed_0039_alter_assetallocation_company_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0040_instrument_financial_instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0041_remove_listresearch_research_ptr_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0042_instrumentlist_instrumentlistthroughmodel_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0043_alter_instrumentlistthroughmodel_options_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0044_alter_instrumentlist_identifier.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0045_alter_instrument_financial_instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0046_add_product_default_account.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0047_remove_product_default_sub_account.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0048_alter_trade_status.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0049_trade_claimed_shares.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0050_fees_fee_date_fees_wbportfolio_transac_1f7a29_idx.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0051_delete_macroreview.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0053_remove_product_group.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0054_portfolioinstrumentpreferredclassificationthroughmodel_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0055_remove_product__custom_management_rebates_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0056_remove_companyportfoliodata_assets_under_management_currency_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0057_alter_portfolio_preferred_instrument_classifications_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0058_pmsinstrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0059_fees_unique_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0060_alter_portfolioportfoliothroughmodel_type.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0061_portfolio_bank_accounts_product_bank_account_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0062_alter_dailyportfoliocashflow_options.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0063_accountreconciliation_accountreconciliationline_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0064_alter_portfolio_managers_portfolio_is_tracked_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0065_alter_portfolio_managers_claim_as_shares_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0066_assetposition_initial_shares_at_custodian_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0067_assetposition_unique_asset_position.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0068_trade_internal_trade_trade_marked_as_internal_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0069_remove_portfolio_is_invested_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0071_alter_trade_options_alter_trade_order.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0072_trade_diff_shares.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/0074_alter_rebalancer_frequency_and_more.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/migrations/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/graphs/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/graphs/portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/graphs/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/indexes.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/llm/wbcrm/analyze_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/mixins/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/mixins/liquidity_stress_test.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/portfolio_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/reconciliations/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/reconciliations/account_reconciliation_lines.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/reconciliations/account_reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/reconciliations/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/dividends.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/expiry.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/permissions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/analytics/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/statistics/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/trading/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/pms/typing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/preferences.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/base.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/decorators.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/models/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/models/composite.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/models/equally_weighted.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/rebalancing/models/model_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/reports/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/reports/monthly_position_report.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/accounts.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/controversy_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/exposure_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/instrument_list_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/liquidity_risk.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/liquidity_stress_instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/product_integrity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/stop_loss_instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/stop_loss_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/backends/ucits_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/conftest.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_accounts.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_controversy_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_exposure_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_liquidity_risk.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_product_integrity.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_stop_loss_instrument.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/risk_management/tests/test_ucits_portfolio.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/portfolio_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/portfolio_swing_pricing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/product_group.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/signals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/dividends.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/expiry.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/css/macro_review.css +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/account_holding_reconciliation.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/aggregate_asset_position_liquidity.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/company.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/earnings_instrument.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/financial_analysis_instrument_ratios.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/financial_statistics.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/static/wbportfolio/markdown/documentation/person.md +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tasks.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/templates/portfolio/email/customer_report.html +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/templates/portfolio/email/customer_trade_notification.html +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/templates/portfolio/email/email_base_template.html +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/templates/portfolio/email/rebalancing_report.html +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/templates/portfolio/macro/macro_review.html +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/conftest.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_account_reconciliation.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_customer_trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_dividends.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_imports.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_instrument_mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_merge.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_portfolio_cash_targets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_portfolio_swing_pricings.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/test_splits.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/transactions/test_claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/transactions/test_fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/transactions/test_rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/transactions/test_trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/models/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/pms/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/rebalancing/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/serializers/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/serializers/test_claims.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/signals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/tests.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/test_assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/test_performances.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/test_products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/tests/viewsets/transactions/test_claims.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/urls.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/utils.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/charts/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/charts/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/claims.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/signals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/buttons/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/portfolio_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/product_performance.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/trade_proposals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/display/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/portfolio_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/product_performance.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/endpoints/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/instrument_prices.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/product_performance.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/menu/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/previews/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/previews/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/adjustments.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/assets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/assets_and_net_new_money_progression.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/instrument_prices.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/product_performance.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/configs/titles/transactions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/custodians.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/esg.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/portfolio_cash_flow.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/portfolio_cash_targets.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/portfolio_relationship.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/portfolio_swing_pricing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/portfolios.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/positions.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/product_groups.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/product_performance.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/products.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/reconciliations.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/registers.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/roles.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/signals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/__init__.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/claim.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/fees.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/mixins.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/rebalancing.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/trade_proposals.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/trades.py +0 -0
- {wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/viewsets/transactions/transactions.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
from contextlib import suppress
|
|
2
2
|
from datetime import date
|
|
3
|
-
from decimal import Decimal
|
|
3
|
+
from decimal import Decimal, InvalidOperation
|
|
4
4
|
|
|
5
5
|
from django.contrib import admin
|
|
6
6
|
from django.db import models
|
|
@@ -393,7 +393,9 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
393
393
|
analytical_objects = AnalyticalAssetPositionManager()
|
|
394
394
|
unannotated_objects = models.Manager()
|
|
395
395
|
|
|
396
|
-
def pre_save(
|
|
396
|
+
def pre_save(
|
|
397
|
+
self, create_underlying_quote_price_if_missing: bool = False, infer_underlying_quote_price: bool = True
|
|
398
|
+
):
|
|
397
399
|
if not self.asset_valuation_date:
|
|
398
400
|
self.asset_valuation_date = self.date
|
|
399
401
|
|
|
@@ -417,10 +419,10 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
417
419
|
|
|
418
420
|
if not getattr(self, "currency", None):
|
|
419
421
|
self.currency = self.underlying_quote.currency
|
|
420
|
-
if not self.underlying_quote_price:
|
|
422
|
+
if not self.underlying_quote_price and infer_underlying_quote_price:
|
|
421
423
|
try:
|
|
422
424
|
# We get only the instrument price (and don't create it) because we don't want to create product instrument price on asset position propagation
|
|
423
|
-
# Instead, we
|
|
425
|
+
# Instead, we decided to opt for a post_save based system that will assign the missing position price when a price is created
|
|
424
426
|
self.underlying_quote_price = InstrumentPrice.objects.get(
|
|
425
427
|
calculated=False, instrument=self.underlying_quote, date=self.asset_valuation_date
|
|
426
428
|
)
|
|
@@ -468,9 +470,12 @@ class AssetPosition(ImportMixin, models.Model):
|
|
|
468
470
|
if self.initial_currency_fx_rate is None:
|
|
469
471
|
self.initial_currency_fx_rate = Decimal(1.0)
|
|
470
472
|
if self.currency_fx_rate_portfolio_to_usd and self.currency_fx_rate_instrument_to_usd:
|
|
471
|
-
|
|
472
|
-
self.
|
|
473
|
-
|
|
473
|
+
try:
|
|
474
|
+
self.initial_currency_fx_rate = (
|
|
475
|
+
self.currency_fx_rate_portfolio_to_usd.value / self.currency_fx_rate_instrument_to_usd.value
|
|
476
|
+
)
|
|
477
|
+
except InvalidOperation:
|
|
478
|
+
self.initial_currency_fx_rate = Decimal(0.0)
|
|
474
479
|
|
|
475
480
|
def save(self, *args, create_underlying_quote_price_if_missing: bool = False, **kwargs):
|
|
476
481
|
self.pre_save(create_underlying_quote_price_if_missing=create_underlying_quote_price_if_missing)
|
|
@@ -65,7 +65,9 @@ class PMSInstrument(Instrument):
|
|
|
65
65
|
try:
|
|
66
66
|
return InstrumentPrice.objects.filter_only_valid_prices().get(instrument=self, date=val_date)
|
|
67
67
|
except InstrumentPrice.DoesNotExist:
|
|
68
|
-
if not self.inception_date or not self.prices.filter(
|
|
68
|
+
if (not self.inception_date or self.inception_date == val_date) and not self.prices.filter(
|
|
69
|
+
date__lte=val_date
|
|
70
|
+
).exists():
|
|
69
71
|
return InstrumentPrice.objects.get_or_create(
|
|
70
72
|
instrument=self, date=val_date, defaults={"calculated": False, "net_value": self.issue_price}
|
|
71
73
|
)[0]
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import logging
|
|
2
|
+
from collections import defaultdict
|
|
2
3
|
from contextlib import suppress
|
|
3
4
|
from datetime import date, timedelta
|
|
4
5
|
from decimal import Decimal
|
|
@@ -26,6 +27,7 @@ from django.db.models import (
|
|
|
26
27
|
from django.db.models.signals import post_save
|
|
27
28
|
from django.dispatch import receiver
|
|
28
29
|
from django.utils import timezone
|
|
30
|
+
from django.utils.functional import cached_property
|
|
29
31
|
from pandas._libs.tslibs.offsets import BDay
|
|
30
32
|
from psycopg.types.range import DateRange
|
|
31
33
|
from skfolio.preprocessing import prices_to_returns
|
|
@@ -54,6 +56,63 @@ from . import ProductGroup
|
|
|
54
56
|
logger = logging.getLogger("pms")
|
|
55
57
|
|
|
56
58
|
|
|
59
|
+
class PositionDictConverter:
|
|
60
|
+
"""Utility class to load a dictionary of dictionary (dictionary of instrument_id and float per date) into a iterable of assetposition"""
|
|
61
|
+
|
|
62
|
+
def __init__(self, portfolio, prices: pd.DataFrame, infer_underlying_quote_price=False):
|
|
63
|
+
self.portfolio = portfolio
|
|
64
|
+
self.instruments = {}
|
|
65
|
+
self.fx_rates = defaultdict(dict)
|
|
66
|
+
self.prices = prices
|
|
67
|
+
self.infer_underlying_quote_price = infer_underlying_quote_price
|
|
68
|
+
|
|
69
|
+
def _get_instrument(self, instrument_id: int) -> Instrument:
|
|
70
|
+
try:
|
|
71
|
+
return self.instruments[instrument_id]
|
|
72
|
+
except KeyError:
|
|
73
|
+
instrument = Instrument.objects.get(id=instrument_id)
|
|
74
|
+
self.instruments[instrument_id] = instrument
|
|
75
|
+
return instrument
|
|
76
|
+
|
|
77
|
+
def _get_fx_rate(self, val_date: date, currency) -> CurrencyFXRates:
|
|
78
|
+
try:
|
|
79
|
+
return self.fx_rates[currency][val_date]
|
|
80
|
+
except KeyError:
|
|
81
|
+
fx_rate = CurrencyFXRates.objects.get_or_create(
|
|
82
|
+
currency=currency, date=val_date, defaults={"value": Decimal(0)}
|
|
83
|
+
)[0] # we create a fx rate anyway to not fail the position. The fx rate expect to be there later on
|
|
84
|
+
self.fx_rates[currency][val_date] = fx_rate
|
|
85
|
+
return fx_rate
|
|
86
|
+
|
|
87
|
+
def dict_to_model(self, val_date: date, instrument_id: int, weighting: float) -> AssetPosition:
|
|
88
|
+
underlying_quote = self._get_instrument(instrument_id)
|
|
89
|
+
currency_fx_rate_portfolio_to_usd = self._get_fx_rate(val_date, self.portfolio.currency)
|
|
90
|
+
currency_fx_rate_instrument_to_usd = self._get_fx_rate(val_date, underlying_quote.currency)
|
|
91
|
+
position = AssetPosition(
|
|
92
|
+
underlying_quote=underlying_quote,
|
|
93
|
+
weighting=weighting,
|
|
94
|
+
date=val_date,
|
|
95
|
+
asset_valuation_date=val_date,
|
|
96
|
+
is_estimated=True,
|
|
97
|
+
portfolio=self.portfolio,
|
|
98
|
+
currency=underlying_quote.currency,
|
|
99
|
+
initial_price=self.prices.loc[pd.Timestamp(val_date), instrument_id],
|
|
100
|
+
currency_fx_rate_portfolio_to_usd=currency_fx_rate_portfolio_to_usd,
|
|
101
|
+
currency_fx_rate_instrument_to_usd=currency_fx_rate_instrument_to_usd,
|
|
102
|
+
initial_currency_fx_rate=None,
|
|
103
|
+
underlying_quote_price=None,
|
|
104
|
+
underlying_instrument=None,
|
|
105
|
+
)
|
|
106
|
+
position.pre_save(
|
|
107
|
+
infer_underlying_quote_price=self.infer_underlying_quote_price
|
|
108
|
+
) # inferring underlying quote price is potentially very slow for big dataset of positions, it's not very needed for model portfolio so we disable it
|
|
109
|
+
return position
|
|
110
|
+
|
|
111
|
+
def convert(self, positions: dict[date, dict[int, float]]) -> Iterable[AssetPosition]:
|
|
112
|
+
for val_date, weights in positions.items():
|
|
113
|
+
yield from map(lambda row: self.dict_to_model(val_date, row[0], row[1]), weights.items())
|
|
114
|
+
|
|
115
|
+
|
|
57
116
|
class DefaultPortfolioQueryset(QuerySet):
|
|
58
117
|
def filter_invested_at_date(self, val_date: date) -> QuerySet:
|
|
59
118
|
"""
|
|
@@ -253,11 +312,12 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
253
312
|
def imported_assets(self):
|
|
254
313
|
return self.assets.filter(is_estimated=False)
|
|
255
314
|
|
|
256
|
-
@
|
|
315
|
+
@cached_property
|
|
257
316
|
def pms_instruments(self):
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
317
|
+
instruments = [i for i in Product.objects.filter(portfolios=self)]
|
|
318
|
+
instruments.extend([i for i in ProductGroup.objects.filter(portfolios=self)])
|
|
319
|
+
instruments.extend([i for i in Index.objects.filter(portfolios=self)])
|
|
320
|
+
return instruments
|
|
261
321
|
|
|
262
322
|
@property
|
|
263
323
|
def can_be_rebalanced(self):
|
|
@@ -298,31 +358,28 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
298
358
|
)
|
|
299
359
|
)
|
|
300
360
|
|
|
301
|
-
def get_analytic_portfolio(self, val_date: date,
|
|
361
|
+
def get_analytic_portfolio(self, val_date: date, **kwargs) -> tuple[AnalyticPortfolio, pd.DataFrame]:
|
|
302
362
|
"""
|
|
303
363
|
Return the analytic portfolio associated with this portfolio at the given date
|
|
304
364
|
|
|
305
365
|
the analytic portfolio inherit from SKFolio Portfolio and can be used to access all this library methods
|
|
306
366
|
Args:
|
|
307
367
|
val_date: the date to calculate the portfolio for
|
|
308
|
-
with_previous_weights: If true, excludes the previous weights into the analytic portfolio (might be necessary for some metrics)
|
|
309
368
|
|
|
310
369
|
Returns:
|
|
311
370
|
The instantiated analytic portfolio
|
|
312
371
|
"""
|
|
313
372
|
weights = self.get_weights(val_date)
|
|
314
373
|
instrument_ids = weights.keys()
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
if previous_date := self.get_latest_asset_position_date(val_date - timedelta(days=1)):
|
|
318
|
-
previous_weights = self.get_weights(previous_date)
|
|
319
|
-
instrument_ids = previous_weights.keys()
|
|
320
|
-
returns = self.get_returns(instrument_ids, (val_date - BDay(3)).date(), val_date)[0]
|
|
374
|
+
return_date = (val_date + BDay(1)).date()
|
|
375
|
+
returns, prices = self.get_returns(instrument_ids, (val_date - BDay(2)).date(), return_date, **kwargs)
|
|
321
376
|
returns = returns.fillna(0) # not sure this is what we want
|
|
322
|
-
return
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
377
|
+
return (
|
|
378
|
+
AnalyticPortfolio(
|
|
379
|
+
X=returns,
|
|
380
|
+
weights=weights,
|
|
381
|
+
),
|
|
382
|
+
prices,
|
|
326
383
|
)
|
|
327
384
|
|
|
328
385
|
def is_invested_at_date(self, val_date: date) -> bool:
|
|
@@ -567,10 +624,11 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
567
624
|
|
|
568
625
|
def get_child_portfolios(self, val_date: date) -> set["Portfolio"]:
|
|
569
626
|
child_portfolios = set()
|
|
570
|
-
|
|
627
|
+
instrument_rel = InstrumentPortfolioThroughModel.objects.filter(portfolio=self)
|
|
628
|
+
if instrument_rel.exists():
|
|
571
629
|
for parent_portfolio in Portfolio.objects.filter(
|
|
572
630
|
id__in=AssetPosition.unannotated_objects.filter(
|
|
573
|
-
date=val_date, underlying_quote__in=
|
|
631
|
+
date=val_date, underlying_quote__in=instrument_rel.values("instrument")
|
|
574
632
|
).values("portfolio")
|
|
575
633
|
):
|
|
576
634
|
child_portfolios.add(parent_portfolio)
|
|
@@ -592,27 +650,32 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
592
650
|
evaluate_rebalancer: bool = True,
|
|
593
651
|
):
|
|
594
652
|
logger.info(f"change at date for {self} at {val_date}")
|
|
595
|
-
qs = self.assets.filter(date=val_date).filter(
|
|
596
|
-
Q(total_value_fx_portfolio__isnull=False) | Q(weighting__isnull=False)
|
|
597
|
-
)
|
|
598
653
|
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if
|
|
605
|
-
|
|
606
|
-
#
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
654
|
+
if recompute_weighting:
|
|
655
|
+
# We normalize weight across the portfolio for a given date
|
|
656
|
+
qs = self.assets.filter(date=val_date).filter(
|
|
657
|
+
Q(total_value_fx_portfolio__isnull=False) | Q(weighting__isnull=False)
|
|
658
|
+
)
|
|
659
|
+
if (self.is_lookthrough or self.is_manageable or force_recompute_weighting) and qs.exists():
|
|
660
|
+
total_weighting = qs.aggregate(s=Sum("weighting"))["s"]
|
|
661
|
+
# We check if this actually necessary
|
|
662
|
+
# (i.e. if the weight is already summed to 100%, it is already normalized)
|
|
663
|
+
if (
|
|
664
|
+
not total_weighting
|
|
665
|
+
or not isclose(total_weighting, Decimal(1.0), abs_tol=0.001)
|
|
666
|
+
or force_recompute_weighting
|
|
667
|
+
):
|
|
668
|
+
total_value = qs.aggregate(s=Sum("total_value_fx_portfolio"))["s"]
|
|
669
|
+
# TODO we change this because postgres doesn't support join statement in update (and total_value_fx_portfolio is a joined annoted field)
|
|
670
|
+
for asset in qs:
|
|
671
|
+
if total_value:
|
|
672
|
+
asset.weighting = asset._total_value_fx_portfolio / total_value
|
|
673
|
+
elif total_weighting:
|
|
674
|
+
asset.weighting = asset.weighting / total_weighting
|
|
675
|
+
asset.save()
|
|
613
676
|
|
|
614
677
|
# We check if there is an instrument attached to the portfolio with calculated NAV and price computation method
|
|
615
|
-
self.estimate_net_asset_values(val_date)
|
|
678
|
+
self.estimate_net_asset_values((val_date + BDay(1)).date()) # updating weighting in t0 influence nav in t+1
|
|
616
679
|
if evaluate_rebalancer:
|
|
617
680
|
self.evaluate_rebalancing(val_date)
|
|
618
681
|
|
|
@@ -641,17 +704,21 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
641
704
|
dependent_portfolio.handle_controlling_portfolio_change_at_date(val_date)
|
|
642
705
|
|
|
643
706
|
def evaluate_rebalancing(self, val_date: date):
|
|
644
|
-
# if the portfolio has an automatic rebalancer and the next business day is suitable with the rebalancer, we create a trade proposal automatically
|
|
645
|
-
next_business_date = (val_date + BDay(1)).date()
|
|
646
|
-
|
|
647
707
|
if hasattr(self, "automatic_rebalancer"):
|
|
648
|
-
|
|
708
|
+
# if the portfolio has an automatic rebalancer and the next business day is suitable with the rebalancer, we create a trade proposal automatically
|
|
709
|
+
next_business_date = (val_date + BDay(1)).date()
|
|
710
|
+
if self.automatic_rebalancer.is_valid(val_date): # we evaluate the rebalancer in t0 and t+1
|
|
711
|
+
logger.info(f"Evaluate Rebalancing for {self} at {val_date}")
|
|
712
|
+
self.automatic_rebalancer.evaluate_rebalancing(val_date)
|
|
649
713
|
if self.automatic_rebalancer.is_valid(next_business_date):
|
|
714
|
+
logger.info(f"Evaluate Rebalancing for {self} at {next_business_date}")
|
|
650
715
|
self.automatic_rebalancer.evaluate_rebalancing(next_business_date)
|
|
651
716
|
|
|
652
717
|
def estimate_net_asset_values(self, val_date: date):
|
|
653
718
|
for instrument in self.pms_instruments:
|
|
654
|
-
if
|
|
719
|
+
if instrument.is_active_at_date(val_date) and (
|
|
720
|
+
net_asset_value_computation_method_path := instrument.net_asset_value_computation_method_path
|
|
721
|
+
):
|
|
655
722
|
logger.info(f"Estimate NAV of {val_date:%Y-%m-%d} for instrument {instrument}")
|
|
656
723
|
net_asset_value_computation_method = import_from_dotted_path(net_asset_value_computation_method_path)
|
|
657
724
|
estimated_net_asset_value = net_asset_value_computation_method(val_date, instrument)
|
|
@@ -671,76 +738,32 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
671
738
|
instrument.update_last_valuation_date()
|
|
672
739
|
instrument.update_last_valuation_date()
|
|
673
740
|
|
|
674
|
-
def get_estimated_portfolio_from_weights(
|
|
675
|
-
self, val_date: date, weights: dict[int, float], prices: dict[int, Decimal] | None = None
|
|
676
|
-
) -> Iterable[AssetPosition]:
|
|
677
|
-
"""
|
|
678
|
-
Given weights and the corresponding instrument price, instantiate asset positions (as AssetPosition object)
|
|
679
|
-
|
|
680
|
-
Args:
|
|
681
|
-
val_date: The positions valuation date
|
|
682
|
-
weights: The positions weights as dictionary (Instrument IDS as key and weights as values)
|
|
683
|
-
prices: The prices associated with each position
|
|
684
|
-
|
|
685
|
-
Returns:
|
|
686
|
-
Yield AssetPosition objects.
|
|
687
|
-
"""
|
|
688
|
-
if prices is None:
|
|
689
|
-
prices = dict()
|
|
690
|
-
try:
|
|
691
|
-
currency_fx_rate_portfolio_to_usd = CurrencyFXRates.objects.get(date=val_date, currency=self.currency)
|
|
692
|
-
except CurrencyFXRates.DoesNotExist:
|
|
693
|
-
currency_fx_rate_portfolio_to_usd = None
|
|
694
|
-
for underlying_quote_id, next_weight in weights.items():
|
|
695
|
-
underlying_quote = Instrument.objects.get(id=underlying_quote_id)
|
|
696
|
-
position = AssetPosition(
|
|
697
|
-
underlying_quote=underlying_quote,
|
|
698
|
-
weighting=next_weight,
|
|
699
|
-
date=val_date,
|
|
700
|
-
asset_valuation_date=val_date,
|
|
701
|
-
is_estimated=True,
|
|
702
|
-
portfolio=self,
|
|
703
|
-
currency=underlying_quote.currency,
|
|
704
|
-
currency_fx_rate_portfolio_to_usd=currency_fx_rate_portfolio_to_usd,
|
|
705
|
-
initial_price=prices.get(underlying_quote_id, None),
|
|
706
|
-
initial_currency_fx_rate=None,
|
|
707
|
-
currency_fx_rate_instrument_to_usd=None,
|
|
708
|
-
underlying_quote_price=None,
|
|
709
|
-
underlying_instrument=None,
|
|
710
|
-
)
|
|
711
|
-
position.pre_save()
|
|
712
|
-
yield position
|
|
713
|
-
|
|
714
741
|
def batch_portfolio(self, start_date: date, end_date: date):
|
|
715
742
|
"""
|
|
716
743
|
Create the cumulative portfolios between the two given dates and stop at the first rebalancing (if any)
|
|
717
744
|
|
|
718
745
|
Returns: The trade proposal generated by the rebalancing, if any (otherwise None)
|
|
719
746
|
"""
|
|
720
|
-
analytic_portfolio = self.get_analytic_portfolio(start_date)
|
|
721
747
|
rebalancer = getattr(self, "automatic_rebalancer", None)
|
|
722
|
-
|
|
723
|
-
|
|
748
|
+
|
|
749
|
+
weights = self.get_weights(start_date) # initial weights
|
|
750
|
+
positions = dict()
|
|
724
751
|
next_trade_proposal = None
|
|
725
752
|
rebalancing_date = None
|
|
726
753
|
logger.info(f"compute next weights in batch for {self} from {start_date:%Y-%m-%d} to {end_date:%Y-%m-%d}")
|
|
727
|
-
returns, prices = self.get_returns(
|
|
754
|
+
returns, prices = self.get_returns(weights.keys(), (start_date - BDay(3)).date(), end_date, ffill_returns=True)
|
|
728
755
|
for to_date_ts in pd.date_range(start_date + timedelta(days=1), end_date, freq="B"):
|
|
729
756
|
to_date = to_date_ts.date()
|
|
730
757
|
logger.info(f"Processing {to_date:%Y-%m-%d}")
|
|
731
758
|
if rebalancer and rebalancer.is_valid(to_date):
|
|
732
759
|
rebalancing_date = to_date
|
|
733
760
|
break
|
|
734
|
-
# with suppress(IndexError):
|
|
735
761
|
last_returns = returns.loc[[to_date_ts], :]
|
|
736
|
-
|
|
737
|
-
positions.
|
|
738
|
-
self.get_estimated_portfolio_from_weights(
|
|
739
|
-
to_date, next_weights, prices.loc[to_date_ts, :].dropna().to_dict()
|
|
740
|
-
)
|
|
741
|
-
)
|
|
742
|
-
analytic_portfolio = AnalyticPortfolio(X=last_returns, weights=next_weights)
|
|
762
|
+
analytic_portfolio = AnalyticPortfolio(weights=weights, X=last_returns)
|
|
763
|
+
positions[to_date] = analytic_portfolio.get_next_weights()
|
|
743
764
|
|
|
765
|
+
positions_generator = PositionDictConverter(self, prices)
|
|
766
|
+
positions = list(positions_generator.convert(positions))
|
|
744
767
|
self.bulk_create_positions(positions, delete_leftovers=True, compute_metrics=False, evaluate_rebalancer=False)
|
|
745
768
|
if rebalancing_date:
|
|
746
769
|
next_trade_proposal = rebalancer.evaluate_rebalancing(rebalancing_date)
|
|
@@ -774,18 +797,13 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
774
797
|
self.is_tracked and not self.is_lookthrough and not is_target_portfolio_imported and from_is_active
|
|
775
798
|
): # we cannot propagate a new portfolio for untracked, or look-through or already imported or inactive portfolios
|
|
776
799
|
logger.info(f"computing next weight for {self} from {from_date:%Y-%m-%d} to {to_date:%Y-%m-%d}")
|
|
777
|
-
analytic_portfolio = self.get_analytic_portfolio(from_date)
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
self.get_estimated_portfolio_from_weights(
|
|
785
|
-
to_date, weights, prices.iloc[-1, :].T.dropna().to_dict()
|
|
786
|
-
),
|
|
787
|
-
)
|
|
788
|
-
)
|
|
800
|
+
analytic_portfolio, to_prices = self.get_analytic_portfolio(from_date)
|
|
801
|
+
if not to_prices.empty:
|
|
802
|
+
weights = analytic_portfolio.get_next_weights()
|
|
803
|
+
positions_generator = PositionDictConverter(
|
|
804
|
+
self, to_prices, infer_underlying_quote_price=True
|
|
805
|
+
).convert({to_date: weights})
|
|
806
|
+
positions = list(map(lambda a: _parse_position(a), positions_generator))
|
|
789
807
|
self.bulk_create_positions(positions, delete_leftovers=True, compute_metrics=True)
|
|
790
808
|
|
|
791
809
|
def get_lookthrough_positions(
|
|
@@ -932,8 +950,11 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
932
950
|
for position in positions:
|
|
933
951
|
position.portfolio = self
|
|
934
952
|
update_dates.add(position.date)
|
|
935
|
-
self.assets.filter(date__in=update_dates, is_estimated=True).delete()
|
|
936
|
-
|
|
953
|
+
# self.assets.filter(date__in=update_dates, is_estimated=True).delete()
|
|
954
|
+
leftover_positions_ids = list(
|
|
955
|
+
self.assets.filter(date__in=update_dates).values_list("id", flat=True)
|
|
956
|
+
) # we need to get the ids otherwise the queryset is reevaluated later
|
|
957
|
+
logger.info(f"bulk saving {len(positions)} positions ({len(leftover_positions_ids)} leftovers) ...")
|
|
937
958
|
objs = AssetPosition.unannotated_objects.bulk_create(
|
|
938
959
|
positions,
|
|
939
960
|
update_fields=[
|
|
@@ -951,11 +972,13 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
951
972
|
],
|
|
952
973
|
unique_fields=["portfolio", "date", "underlying_quote", "portfolio_created"],
|
|
953
974
|
update_conflicts=True,
|
|
975
|
+
batch_size=10000,
|
|
954
976
|
)
|
|
955
977
|
if delete_leftovers:
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
978
|
+
objs_ids = list(map(lambda x: x.id, objs))
|
|
979
|
+
leftover_positions_ids = list(filter(lambda i: i not in objs_ids, leftover_positions_ids))
|
|
980
|
+
logger.info(f"deleting {len(leftover_positions_ids)} leftover positions..")
|
|
981
|
+
AssetPosition.objects.filter(id__in=leftover_positions_ids).delete()
|
|
959
982
|
for update_date in sorted(update_dates):
|
|
960
983
|
self.change_at_date(update_date, **kwargs)
|
|
961
984
|
|
|
@@ -972,7 +995,12 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
972
995
|
return self.assets.filter(Q(date=val_date) & ~Q(initial_shares=F("initial_shares_at_custodian"))).exists()
|
|
973
996
|
|
|
974
997
|
def get_returns(
|
|
975
|
-
self,
|
|
998
|
+
self,
|
|
999
|
+
instruments: Iterable,
|
|
1000
|
+
from_date: date,
|
|
1001
|
+
to_date: date,
|
|
1002
|
+
ffill_returns: bool = True,
|
|
1003
|
+
convert_to_portfolio_currency: bool = True,
|
|
976
1004
|
) -> tuple[pd.DataFrame, pd.DataFrame]:
|
|
977
1005
|
"""
|
|
978
1006
|
Utility methods to get instrument returns for a given date range
|
|
@@ -988,8 +1016,10 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
988
1016
|
prices = InstrumentPrice.objects.filter(
|
|
989
1017
|
instrument__in=instruments, date__gte=from_date, date__lte=to_date
|
|
990
1018
|
).annotate(
|
|
991
|
-
|
|
992
|
-
|
|
1019
|
+
fx_rate=CurrencyFXRates.get_fx_rates_subquery_for_two_currencies(
|
|
1020
|
+
"date", "instrument__currency", self.currency
|
|
1021
|
+
),
|
|
1022
|
+
price_fx_portfolio=F("net_value") * F("fx_rate") if convert_to_portfolio_currency else F("net_value"),
|
|
993
1023
|
)
|
|
994
1024
|
prices_df = (
|
|
995
1025
|
pd.DataFrame(
|
|
@@ -1187,13 +1217,12 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
1187
1217
|
|
|
1188
1218
|
def default_estimate_net_value(val_date: date, instrument: Instrument) -> float | None:
|
|
1189
1219
|
portfolio = instrument.portfolio
|
|
1190
|
-
if (
|
|
1191
|
-
|
|
1192
|
-
)
|
|
1193
|
-
|
|
1194
|
-
|
|
1195
|
-
|
|
1196
|
-
return analytic_portfolio.get_estimate_net_value(float(last_price.net_value))
|
|
1220
|
+
if (previous_date := portfolio.get_latest_asset_position_date(val_date - BDay(1), with_estimated=True)) and (
|
|
1221
|
+
last_price := instrument.get_latest_price(previous_date)
|
|
1222
|
+
):
|
|
1223
|
+
with suppress(IndexError): # we silent any indexerror introduced by no returns for the past days
|
|
1224
|
+
analytic_portfolio, _ = portfolio.get_analytic_portfolio(previous_date)
|
|
1225
|
+
return analytic_portfolio.get_estimate_net_value(float(last_price.net_value))
|
|
1197
1226
|
|
|
1198
1227
|
|
|
1199
1228
|
@receiver(post_save, sender="wbportfolio.Product")
|
|
@@ -99,11 +99,16 @@ class Rebalancer(ComplexToStringMixin, models.Model):
|
|
|
99
99
|
return pivot_date
|
|
100
100
|
|
|
101
101
|
def is_valid(self, trade_date: date) -> bool:
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
if TradeProposal.objects.filter(
|
|
103
|
+
portfolio=self.portfolio, status=TradeProposal.Status.APPROVED, trade_date=trade_date
|
|
104
|
+
).exists(): # if a already approved trade proposal exists, we do not allow a re-evaluatioon of the rebalancing (only possible if "replayed")
|
|
105
|
+
return False
|
|
106
|
+
for initial_valid_datetime in self.get_rrule(trade_date):
|
|
107
|
+
initial_valid_date = initial_valid_datetime.date()
|
|
108
|
+
alternative_valid_date = self._get_next_valid_date(initial_valid_date)
|
|
109
|
+
if trade_date in [alternative_valid_date, initial_valid_date]:
|
|
105
110
|
return True
|
|
106
|
-
if
|
|
111
|
+
if alternative_valid_date > trade_date:
|
|
107
112
|
break
|
|
108
113
|
return False
|
|
109
114
|
|
{wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/models/transactions/trade_proposals.py
RENAMED
|
@@ -79,6 +79,8 @@ class TradeProposal(RiskCheckMixin, WBModel):
|
|
|
79
79
|
if not self.rebalancing_model and (rebalancer := getattr(self.portfolio, "automatic_rebalancer", None)):
|
|
80
80
|
self.rebalancing_model = rebalancer.rebalancing_model
|
|
81
81
|
super().save(*args, **kwargs)
|
|
82
|
+
if self.status == TradeProposal.Status.APPROVED:
|
|
83
|
+
self.portfolio.change_at_date(self.trade_date)
|
|
82
84
|
|
|
83
85
|
def _get_checked_object_field_name(self) -> str:
|
|
84
86
|
"""
|
|
@@ -234,7 +236,6 @@ class TradeProposal(RiskCheckMixin, WBModel):
|
|
|
234
236
|
)
|
|
235
237
|
service.normalize()
|
|
236
238
|
service.is_valid()
|
|
237
|
-
|
|
238
239
|
for trade_dto in service.validated_trades:
|
|
239
240
|
instrument = Instrument.objects.get(id=trade_dto.underlying_instrument)
|
|
240
241
|
currency_fx_rate = instrument.currency.convert(
|
|
@@ -378,8 +379,6 @@ class TradeProposal(RiskCheckMixin, WBModel):
|
|
|
378
379
|
for trade in self.trades.all():
|
|
379
380
|
trade.execute()
|
|
380
381
|
trade.save()
|
|
381
|
-
self.portfolio.change_at_date(self.trade_date)
|
|
382
|
-
# replay_as_task.delay(self.id)
|
|
383
382
|
|
|
384
383
|
def can_approve(self):
|
|
385
384
|
errors = dict()
|
|
@@ -16,16 +16,14 @@ class Portfolio(BasePortfolio):
|
|
|
16
16
|
)
|
|
17
17
|
return df
|
|
18
18
|
|
|
19
|
-
def get_next_weights(self
|
|
19
|
+
def get_next_weights(self) -> dict[int, float]:
|
|
20
20
|
"""
|
|
21
|
-
Given the next returns, compute the
|
|
22
|
-
|
|
23
|
-
Args:
|
|
24
|
-
returns: The returns for the next day as a pandas series
|
|
21
|
+
Given the next returns, compute the drifted weights of this portfolio
|
|
25
22
|
|
|
26
23
|
Returns:
|
|
27
24
|
A dictionary of weights (instrument ids as keys and weights as values)
|
|
28
25
|
"""
|
|
26
|
+
returns = self.X.iloc[-1, :].T
|
|
29
27
|
weights = self.all_weights_per_observation.iloc[-1, :].T
|
|
30
28
|
if weights.sum() != 0:
|
|
31
29
|
weights /= weights.sum()
|
|
@@ -35,7 +33,5 @@ class Portfolio(BasePortfolio):
|
|
|
35
33
|
return contribution.dropna().to_dict()
|
|
36
34
|
|
|
37
35
|
def get_estimate_net_value(self, previous_net_asset_value: float) -> float:
|
|
38
|
-
|
|
39
|
-
raise ValueError("No previous weights available")
|
|
40
|
-
expected_returns = self.previous_weights @ self.X.iloc[-1, :].T
|
|
36
|
+
expected_returns = self.weights @ self.X.iloc[-1, :].T
|
|
41
37
|
return previous_net_asset_value * (1.0 + expected_returns)
|
|
@@ -97,7 +97,7 @@ class TradingService:
|
|
|
97
97
|
effective_shares = 0
|
|
98
98
|
instrument_type = currency = None
|
|
99
99
|
if effective_pos := effective_portfolio.positions_map.get(instrument, None):
|
|
100
|
-
effective_weight =
|
|
100
|
+
effective_weight = effective_pos.weighting
|
|
101
101
|
effective_shares = effective_pos.shares
|
|
102
102
|
instrument_type, currency = effective_pos.instrument_type, effective_pos.currency
|
|
103
103
|
if target_pos := target_portfolio.positions_map.get(instrument, None):
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
from decimal import Decimal
|
|
2
2
|
|
|
3
|
+
import numpy as np
|
|
3
4
|
import pandas as pd
|
|
4
5
|
from django.db.models import Q, QuerySet
|
|
5
6
|
from wbfdm.enums import MarketData
|
|
@@ -26,7 +27,7 @@ class MarketCapitalizationRebalancing(AbstractRebalancingModel):
|
|
|
26
27
|
self.market_cap_df = pd.DataFrame(
|
|
27
28
|
instruments.dl.market_data(
|
|
28
29
|
values=[MarketData.MARKET_CAPITALIZATION],
|
|
29
|
-
exact_date=self.
|
|
30
|
+
exact_date=self.trade_date,
|
|
30
31
|
target_currency=self.TARGET_CURRENCY,
|
|
31
32
|
)
|
|
32
33
|
)
|
|
@@ -80,9 +81,7 @@ class MarketCapitalizationRebalancing(AbstractRebalancingModel):
|
|
|
80
81
|
|
|
81
82
|
if not instrument_ids:
|
|
82
83
|
instrument_ids = list(
|
|
83
|
-
self.portfolio.assets.filter(date=self.
|
|
84
|
-
"underlying_instrument", flat=True
|
|
85
|
-
)
|
|
84
|
+
self.portfolio.assets.filter(date=self.trade_date).values_list("underlying_instrument", flat=True)
|
|
86
85
|
)
|
|
87
86
|
|
|
88
87
|
return Instrument.objects.filter(id__in=instrument_ids).filter(
|
|
@@ -107,14 +106,16 @@ class MarketCapitalizationRebalancing(AbstractRebalancingModel):
|
|
|
107
106
|
|
|
108
107
|
def get_target_portfolio(self) -> Portfolio:
|
|
109
108
|
positions = []
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
total_market_cap = self.market_cap_df.dropna().sum()
|
|
110
|
+
for underlying_instrument, market_cap in self.market_cap_df.to_dict().items():
|
|
111
|
+
if np.isnan(market_cap):
|
|
112
|
+
weighting = Decimal(0)
|
|
113
|
+
else:
|
|
114
|
+
weighting = Decimal(market_cap / total_market_cap)
|
|
114
115
|
positions.append(
|
|
115
116
|
Position(
|
|
116
117
|
underlying_instrument=underlying_instrument,
|
|
117
|
-
weighting=
|
|
118
|
+
weighting=weighting,
|
|
118
119
|
date=self.trade_date,
|
|
119
120
|
)
|
|
120
121
|
)
|
{wbportfolio-1.46.9 → wbportfolio-1.46.11}/wbportfolio/serializers/transactions/trade_proposals.py
RENAMED
|
@@ -46,7 +46,7 @@ class TradeProposalModelSerializer(wb_serializers.ModelSerializer):
|
|
|
46
46
|
obj.reset_trades(target_portfolio=target_portfolio_dto)
|
|
47
47
|
except ValidationError as e:
|
|
48
48
|
if request := self.context.get("request"):
|
|
49
|
-
warning(request, str(e))
|
|
49
|
+
warning(request, str(e), extra_tags="auto_close=0")
|
|
50
50
|
return obj
|
|
51
51
|
|
|
52
52
|
@wb_serializers.register_only_instance_resource()
|