wbportfolio 1.44.5__py2.py3-none-any.whl → 1.45.0__py2.py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of wbportfolio might be problematic. Click here for more details.
- wbportfolio/admin/__init__.py +1 -1
- wbportfolio/admin/asset.py +2 -1
- wbportfolio/admin/custodians.py +1 -0
- wbportfolio/admin/indexes.py +15 -0
- wbportfolio/admin/portfolio.py +12 -7
- wbportfolio/admin/portfolio_relationships.py +1 -0
- wbportfolio/admin/product_groups.py +2 -0
- wbportfolio/admin/products.py +2 -1
- wbportfolio/admin/reconciliations.py +1 -0
- wbportfolio/admin/registers.py +1 -0
- wbportfolio/admin/roles.py +1 -0
- wbportfolio/admin/transactions/__init__.py +1 -0
- wbportfolio/admin/transactions/claim.py +1 -0
- wbportfolio/admin/transactions/dividends.py +1 -0
- wbportfolio/admin/transactions/fees.py +1 -0
- wbportfolio/admin/transactions/rebalancing.py +26 -0
- wbportfolio/admin/transactions/trades.py +4 -3
- wbportfolio/admin/transactions/transactions.py +1 -0
- wbportfolio/analysis/claims.py +2 -1
- wbportfolio/contrib/company_portfolio/models.py +3 -6
- wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -12
- wbportfolio/contrib/company_portfolio/tests/test_models.py +1 -0
- wbportfolio/defaults/fees/default.py +1 -0
- wbportfolio/factories/__init__.py +1 -7
- wbportfolio/factories/adjustments.py +1 -0
- wbportfolio/factories/assets.py +13 -7
- wbportfolio/factories/claim.py +1 -0
- wbportfolio/factories/custodians.py +1 -0
- wbportfolio/factories/dividends.py +1 -0
- wbportfolio/factories/fees.py +1 -0
- wbportfolio/factories/indexes.py +1 -0
- wbportfolio/factories/portfolio_cash_flow.py +1 -0
- wbportfolio/factories/portfolio_cash_targets.py +1 -0
- wbportfolio/factories/portfolio_swing_pricings.py +1 -0
- wbportfolio/factories/portfolios.py +3 -0
- wbportfolio/factories/product_groups.py +1 -0
- wbportfolio/factories/products.py +1 -0
- wbportfolio/factories/rebalancing.py +23 -0
- wbportfolio/factories/reconciliations.py +1 -0
- wbportfolio/factories/roles.py +1 -0
- wbportfolio/factories/trades.py +1 -0
- wbportfolio/factories/transactions.py +1 -0
- wbportfolio/fdm/tasks.py +1 -0
- wbportfolio/filters/__init__.py +1 -1
- wbportfolio/filters/assets.py +8 -9
- wbportfolio/filters/assets_and_net_new_money_progression.py +1 -0
- wbportfolio/filters/custodians.py +1 -0
- wbportfolio/filters/esg.py +1 -0
- wbportfolio/filters/performances.py +7 -6
- wbportfolio/filters/portfolios.py +21 -1
- wbportfolio/filters/positions.py +1 -0
- wbportfolio/filters/products.py +1 -0
- wbportfolio/filters/roles.py +1 -0
- wbportfolio/filters/signals.py +1 -0
- wbportfolio/filters/transactions/claim.py +1 -0
- wbportfolio/filters/transactions/fees.py +1 -0
- wbportfolio/filters/transactions/trades.py +2 -1
- wbportfolio/filters/transactions/transactions.py +1 -0
- wbportfolio/import_export/backends/ubs/mixin.py +1 -0
- wbportfolio/import_export/backends/wbfdm/adjustment.py +1 -0
- wbportfolio/import_export/handlers/asset_position.py +11 -13
- wbportfolio/import_export/handlers/fees.py +1 -0
- wbportfolio/import_export/handlers/portfolio_cash_flow.py +1 -0
- wbportfolio/import_export/handlers/trade.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/fees.py +1 -0
- wbportfolio/import_export/parsers/jpmorgan/strategy.py +5 -4
- wbportfolio/import_export/parsers/jpmorgan/valuation.py +1 -0
- wbportfolio/import_export/parsers/leonteq/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/leonteq/equity.py +13 -12
- wbportfolio/import_export/parsers/leonteq/fees.py +1 -0
- wbportfolio/import_export/parsers/leonteq/trade.py +1 -0
- wbportfolio/import_export/parsers/leonteq/valuation.py +1 -0
- wbportfolio/import_export/parsers/natixis/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_equity.py +3 -2
- wbportfolio/import_export/parsers/natixis/d1_fees.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/d1_valuation.py +1 -0
- wbportfolio/import_export/parsers/natixis/equity.py +5 -5
- wbportfolio/import_export/parsers/natixis/trade.py +1 -0
- wbportfolio/import_export/parsers/natixis/utils.py +8 -7
- wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +2 -1
- wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +2 -1
- wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/equity.py +7 -8
- wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +1 -0
- wbportfolio/import_export/parsers/sg_lux/registers.py +2 -1
- wbportfolio/import_export/parsers/societe_generale/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/societe_generale/strategy.py +8 -9
- wbportfolio/import_export/parsers/societe_generale/valuation.py +1 -0
- wbportfolio/import_export/parsers/tellco/equity.py +5 -4
- wbportfolio/import_export/parsers/ubs/api/asset_position.py +15 -14
- wbportfolio/import_export/parsers/ubs/api/fees.py +1 -0
- wbportfolio/import_export/parsers/ubs/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/ubs/equity.py +3 -2
- wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/ubs/valuation.py +1 -0
- wbportfolio/import_export/parsers/vontobel/asset_position.py +19 -19
- wbportfolio/import_export/parsers/vontobel/customer_trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/management_fees.py +1 -0
- wbportfolio/import_export/parsers/vontobel/performance_fees.py +1 -0
- wbportfolio/import_export/parsers/vontobel/trade.py +1 -0
- wbportfolio/import_export/parsers/vontobel/valuation_api.py +20 -0
- wbportfolio/import_export/resources/assets.py +4 -3
- wbportfolio/import_export/resources/trades.py +1 -0
- wbportfolio/metric/backends/base.py +1 -0
- wbportfolio/metric/backends/portfolio_base.py +1 -0
- wbportfolio/metric/backends/portfolio_esg.py +1 -0
- wbportfolio/metric/tests/test_portfolio_base.py +1 -0
- wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +1 -131
- wbportfolio/migrations/0067_assetposition_unique_asset_position.py +1 -1
- wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +1 -1
- wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +407 -0
- wbportfolio/models/__init__.py +0 -5
- wbportfolio/models/adjustments.py +8 -2
- wbportfolio/models/asset.py +117 -98
- wbportfolio/models/graphs/portfolio.py +144 -0
- wbportfolio/models/graphs/utils.py +83 -0
- wbportfolio/models/indexes.py +2 -13
- wbportfolio/models/mixins/instruments.py +28 -8
- wbportfolio/models/portfolio.py +538 -332
- wbportfolio/models/portfolio_cash_flow.py +1 -0
- wbportfolio/models/portfolio_relationship.py +6 -2
- wbportfolio/models/product_groups.py +3 -2
- wbportfolio/models/products.py +3 -17
- wbportfolio/models/reconciliations/account_reconciliation_lines.py +1 -0
- wbportfolio/models/reconciliations/account_reconciliations.py +1 -0
- wbportfolio/models/registers.py +1 -0
- wbportfolio/models/transactions/__init__.py +1 -0
- wbportfolio/models/transactions/claim.py +8 -8
- wbportfolio/models/transactions/dividends.py +1 -0
- wbportfolio/models/transactions/fees.py +1 -0
- wbportfolio/models/transactions/rebalancing.py +153 -0
- wbportfolio/models/transactions/trade_proposals.py +153 -155
- wbportfolio/models/transactions/trades.py +48 -40
- wbportfolio/models/transactions/transactions.py +6 -12
- wbportfolio/models/utils.py +1 -0
- wbportfolio/pms/analytics/__init__.py +0 -0
- wbportfolio/pms/analytics/portfolio.py +28 -0
- wbportfolio/pms/trading/handler.py +13 -16
- wbportfolio/pms/typing.py +13 -29
- wbportfolio/rebalancing/__init__.py +0 -0
- wbportfolio/rebalancing/base.py +16 -0
- wbportfolio/rebalancing/decorators.py +17 -0
- wbportfolio/rebalancing/models/__init__.py +3 -0
- wbportfolio/rebalancing/models/composite.py +31 -0
- wbportfolio/rebalancing/models/equally_weighted.py +21 -0
- wbportfolio/rebalancing/models/model_portfolio.py +35 -0
- wbportfolio/reports/monthly_position_report.py +1 -1
- wbportfolio/risk_management/backends/accounts.py +7 -6
- wbportfolio/risk_management/backends/controversy_portfolio.py +1 -0
- wbportfolio/risk_management/backends/exposure_portfolio.py +1 -0
- wbportfolio/risk_management/backends/instrument_list_portfolio.py +1 -0
- wbportfolio/risk_management/backends/liquidity_risk.py +1 -0
- wbportfolio/risk_management/backends/liquidity_stress_instrument.py +1 -0
- wbportfolio/risk_management/backends/mixins.py +1 -0
- wbportfolio/risk_management/backends/product_integrity.py +6 -1
- wbportfolio/risk_management/backends/stop_loss_instrument.py +1 -0
- wbportfolio/risk_management/backends/stop_loss_portfolio.py +1 -0
- wbportfolio/risk_management/backends/ucits_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_accounts.py +1 -0
- wbportfolio/risk_management/tests/test_controversy_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_liquidity_risk.py +1 -0
- wbportfolio/risk_management/tests/test_product_integrity.py +1 -0
- wbportfolio/risk_management/tests/test_stop_loss_instrument.py +1 -0
- wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -0
- wbportfolio/risk_management/tests/test_ucits_portfolio.py +1 -0
- wbportfolio/serializers/__init__.py +5 -5
- wbportfolio/serializers/adjustments.py +1 -0
- wbportfolio/serializers/assets.py +18 -19
- wbportfolio/serializers/custodians.py +1 -0
- wbportfolio/serializers/portfolio_cash_flow.py +1 -0
- wbportfolio/serializers/portfolio_cash_targets.py +1 -0
- wbportfolio/serializers/portfolio_relationship.py +1 -0
- wbportfolio/serializers/portfolio_swing_pricing.py +1 -0
- wbportfolio/serializers/portfolios.py +61 -40
- wbportfolio/serializers/positions.py +1 -0
- wbportfolio/serializers/product_group.py +1 -0
- wbportfolio/serializers/products.py +4 -7
- wbportfolio/serializers/rebalancing.py +57 -0
- wbportfolio/serializers/reconciliations.py +2 -1
- wbportfolio/serializers/registers.py +1 -0
- wbportfolio/serializers/roles.py +1 -0
- wbportfolio/serializers/signals.py +10 -15
- wbportfolio/serializers/transactions/__init__.py +1 -1
- wbportfolio/serializers/transactions/claim.py +1 -0
- wbportfolio/serializers/transactions/fees.py +1 -0
- wbportfolio/serializers/transactions/trade_proposals.py +85 -0
- wbportfolio/serializers/transactions/trades.py +9 -51
- wbportfolio/serializers/transactions/transactions.py +4 -3
- wbportfolio/tasks.py +1 -78
- wbportfolio/tests/conftest.py +6 -13
- wbportfolio/tests/models/test_account_reconciliation.py +2 -0
- wbportfolio/tests/models/test_assets.py +27 -19
- wbportfolio/tests/models/test_customer_trades.py +1 -0
- wbportfolio/tests/models/test_imports.py +5 -1
- wbportfolio/tests/models/test_merge.py +5 -4
- wbportfolio/tests/models/test_portfolio_cash_flow.py +8 -6
- wbportfolio/tests/models/test_portfolios.py +594 -154
- wbportfolio/tests/models/test_product_groups.py +1 -0
- wbportfolio/tests/models/test_products.py +6 -3
- wbportfolio/tests/models/test_roles.py +1 -0
- wbportfolio/tests/models/test_splits.py +1 -0
- wbportfolio/tests/models/transactions/test_claim.py +1 -0
- wbportfolio/tests/models/transactions/test_fees.py +1 -0
- wbportfolio/tests/models/transactions/test_rebalancing.py +81 -0
- wbportfolio/tests/models/transactions/test_trades.py +1 -0
- wbportfolio/tests/models/utils.py +1 -0
- wbportfolio/tests/pms/__init__.py +0 -0
- wbportfolio/tests/pms/test_analytics.py +35 -0
- wbportfolio/tests/rebalancing/__init__.py +0 -0
- wbportfolio/tests/rebalancing/test_models.py +127 -0
- wbportfolio/tests/serializers/test_claims.py +1 -0
- wbportfolio/tests/signals.py +1 -7
- wbportfolio/tests/tests.py +2 -0
- wbportfolio/tests/viewsets/test_assets.py +1 -0
- wbportfolio/tests/viewsets/test_performances.py +1 -0
- wbportfolio/tests/viewsets/test_products.py +1 -0
- wbportfolio/tests/viewsets/transactions/test_claims.py +1 -0
- wbportfolio/urls.py +26 -12
- wbportfolio/viewsets/__init__.py +2 -5
- wbportfolio/viewsets/adjustments.py +1 -0
- wbportfolio/viewsets/assets.py +62 -51
- wbportfolio/viewsets/assets_and_net_new_money_progression.py +1 -0
- wbportfolio/viewsets/charts/assets.py +3 -1
- wbportfolio/viewsets/configs/buttons/__init__.py +1 -1
- wbportfolio/viewsets/configs/buttons/assets.py +1 -0
- wbportfolio/viewsets/configs/buttons/custodians.py +1 -0
- wbportfolio/viewsets/configs/buttons/mixins.py +1 -20
- wbportfolio/viewsets/configs/buttons/portfolios.py +90 -76
- wbportfolio/viewsets/configs/buttons/signals.py +1 -0
- wbportfolio/viewsets/configs/buttons/trades.py +1 -0
- wbportfolio/viewsets/configs/display/__init__.py +2 -1
- wbportfolio/viewsets/configs/display/adjustments.py +1 -0
- wbportfolio/viewsets/configs/display/assets.py +7 -6
- wbportfolio/viewsets/configs/display/claim.py +1 -0
- wbportfolio/viewsets/configs/display/portfolios.py +127 -79
- wbportfolio/viewsets/configs/display/product_performance.py +1 -0
- wbportfolio/viewsets/configs/display/rebalancing.py +27 -0
- wbportfolio/viewsets/configs/display/trade_proposals.py +7 -4
- wbportfolio/viewsets/configs/display/trades.py +75 -42
- wbportfolio/viewsets/configs/endpoints/__init__.py +3 -1
- wbportfolio/viewsets/configs/endpoints/claim.py +1 -0
- wbportfolio/viewsets/configs/endpoints/portfolios.py +23 -7
- wbportfolio/viewsets/configs/endpoints/rebalancing.py +6 -0
- wbportfolio/viewsets/configs/endpoints/reconciliations.py +1 -0
- wbportfolio/viewsets/configs/endpoints/trade_proposals.py +1 -0
- wbportfolio/viewsets/configs/endpoints/trades.py +1 -0
- wbportfolio/viewsets/configs/menu/adjustments.py +1 -0
- wbportfolio/viewsets/configs/menu/assets.py +1 -0
- wbportfolio/viewsets/configs/menu/fees.py +1 -0
- wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +1 -0
- wbportfolio/viewsets/configs/menu/portfolios.py +4 -2
- wbportfolio/viewsets/configs/menu/positions.py +1 -0
- wbportfolio/viewsets/configs/menu/roles.py +1 -0
- wbportfolio/viewsets/configs/menu/transactions.py +1 -0
- wbportfolio/viewsets/configs/previews/portfolios.py +1 -6
- wbportfolio/viewsets/configs/titles/__init__.py +1 -1
- wbportfolio/viewsets/configs/titles/assets.py +1 -0
- wbportfolio/viewsets/configs/titles/fees.py +1 -0
- wbportfolio/viewsets/configs/titles/instrument_prices.py +1 -0
- wbportfolio/viewsets/configs/titles/portfolios.py +13 -11
- wbportfolio/viewsets/configs/titles/roles.py +1 -0
- wbportfolio/viewsets/configs/titles/trades.py +1 -0
- wbportfolio/viewsets/configs/titles/transactions.py +1 -0
- wbportfolio/viewsets/custodians.py +1 -0
- wbportfolio/viewsets/esg.py +1 -0
- wbportfolio/viewsets/mixins.py +1 -0
- wbportfolio/viewsets/portfolio_cash_flow.py +1 -0
- wbportfolio/viewsets/portfolio_cash_targets.py +1 -0
- wbportfolio/viewsets/portfolio_relationship.py +1 -0
- wbportfolio/viewsets/portfolio_swing_pricing.py +1 -0
- wbportfolio/viewsets/portfolios.py +228 -61
- wbportfolio/viewsets/positions.py +3 -2
- wbportfolio/viewsets/product_groups.py +1 -0
- wbportfolio/viewsets/product_performance.py +1 -0
- wbportfolio/viewsets/products.py +1 -0
- wbportfolio/viewsets/reconciliations.py +1 -0
- wbportfolio/viewsets/registers.py +1 -0
- wbportfolio/viewsets/roles.py +1 -0
- wbportfolio/viewsets/signals.py +1 -0
- wbportfolio/viewsets/transactions/__init__.py +1 -0
- wbportfolio/viewsets/transactions/claim.py +2 -1
- wbportfolio/viewsets/transactions/fees.py +1 -0
- wbportfolio/viewsets/transactions/mixins.py +1 -0
- wbportfolio/viewsets/transactions/rebalancing.py +31 -0
- wbportfolio/viewsets/transactions/trade_proposals.py +25 -5
- wbportfolio/viewsets/transactions/trades.py +16 -9
- wbportfolio/viewsets/transactions/transactions.py +1 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/METADATA +4 -1
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/RECORD +301 -288
- wbportfolio/admin/synchronization/__init__.py +0 -2
- wbportfolio/admin/synchronization/admin.py +0 -114
- wbportfolio/admin/synchronization/portfolio_synchronization.py +0 -18
- wbportfolio/admin/synchronization/price_computation.py +0 -21
- wbportfolio/defaults/portfolio/default_rebalancing.py +0 -45
- wbportfolio/factories/pytest_utils.py +0 -121
- wbportfolio/factories/synchronization.py +0 -40
- wbportfolio/models/synchronization/__init__.py +0 -3
- wbportfolio/models/synchronization/portfolio_synchronization.py +0 -292
- wbportfolio/models/synchronization/price_computation.py +0 -200
- wbportfolio/models/synchronization/synchronization.py +0 -188
- wbportfolio/serializers/synchronization.py +0 -18
- wbportfolio/tests/models/test_synchronization.py +0 -617
- wbportfolio/viewsets/synchronization.py +0 -25
- /wbportfolio/{defaults/portfolio → models/graphs}/__init__.py +0 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/WHEEL +0 -0
- {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/licenses/LICENSE +0 -0
wbportfolio/filters/esg.py
CHANGED
|
@@ -5,6 +5,7 @@ from wbcore.pandas.filterset import PandasFilterSetMixin
|
|
|
5
5
|
from wbcore.utils.date import current_financial_month
|
|
6
6
|
from wbfdm.filters.utils import last_period_date_range
|
|
7
7
|
from wbfdm.models import Instrument
|
|
8
|
+
|
|
8
9
|
from wbportfolio.models import Product
|
|
9
10
|
|
|
10
11
|
from .products import BaseProductFilterSet
|
|
@@ -38,9 +39,9 @@ class PerformancePandasFilter(PandasFilterSetMixin, BaseProductFilterSet):
|
|
|
38
39
|
clearable=False,
|
|
39
40
|
required=True,
|
|
40
41
|
)
|
|
41
|
-
white_label_customers = (
|
|
42
|
-
|
|
43
|
-
) =
|
|
42
|
+
white_label_customers = classifications = classifications_neq = unclassified = invested = portfolio = (
|
|
43
|
+
content_type
|
|
44
|
+
) = tags = None
|
|
44
45
|
|
|
45
46
|
class Meta:
|
|
46
47
|
model = Product
|
|
@@ -136,9 +137,9 @@ class ProductPerformanceNetNewMoneyFilter(PandasFilterSetMixin, BaseProductFilte
|
|
|
136
137
|
|
|
137
138
|
return queryset
|
|
138
139
|
|
|
139
|
-
white_label_customers = (
|
|
140
|
-
|
|
141
|
-
) =
|
|
140
|
+
white_label_customers = classifications = classifications_neq = unclassified = invested = portfolio = (
|
|
141
|
+
content_type
|
|
142
|
+
) = tags = None
|
|
142
143
|
|
|
143
144
|
class Meta:
|
|
144
145
|
model = Product
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
from wbcore import filters as wb_filters
|
|
2
2
|
from wbfdm.models import Instrument
|
|
3
|
+
|
|
4
|
+
from wbportfolio.filters.assets import get_latest_asset_position
|
|
3
5
|
from wbportfolio.models import Portfolio
|
|
4
6
|
|
|
5
7
|
|
|
6
8
|
class PortfolioFilterSet(wb_filters.FilterSet):
|
|
9
|
+
is_tracked = wb_filters.BooleanFilter(default=True, label="Is tracked")
|
|
7
10
|
instrument = wb_filters.ModelChoiceFilter(
|
|
8
11
|
label="Instrument",
|
|
9
12
|
queryset=Instrument.objects.all(),
|
|
@@ -21,4 +24,21 @@ class PortfolioFilterSet(wb_filters.FilterSet):
|
|
|
21
24
|
|
|
22
25
|
class Meta:
|
|
23
26
|
model = Portfolio
|
|
24
|
-
fields = {
|
|
27
|
+
fields = {
|
|
28
|
+
"currency": ["exact"],
|
|
29
|
+
"hedged_currency": ["exact"],
|
|
30
|
+
"is_manageable": ["exact"],
|
|
31
|
+
"only_weighting": ["exact"],
|
|
32
|
+
"is_lookthrough": ["exact"],
|
|
33
|
+
"is_composition": ["exact"],
|
|
34
|
+
"bank_accounts": ["exact"],
|
|
35
|
+
"depends_on": ["exact"],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class PortfolioTreeGraphChartFilterSet(wb_filters.FilterSet):
|
|
40
|
+
date = wb_filters.DateFilter(method="fake_filter", default=get_latest_asset_position, required=True)
|
|
41
|
+
|
|
42
|
+
class Meta:
|
|
43
|
+
model = Portfolio
|
|
44
|
+
fields = {}
|
wbportfolio/filters/positions.py
CHANGED
|
@@ -6,6 +6,7 @@ from wbcore import filters as wb_filters
|
|
|
6
6
|
from wbcore.contrib.currency.models import CurrencyFXRates
|
|
7
7
|
from wbcore.pandas.filterset import PandasFilterSetMixin
|
|
8
8
|
from wbcore.utils.date import current_financial_month
|
|
9
|
+
|
|
9
10
|
from wbportfolio.filters.assets import (
|
|
10
11
|
DateFilterMixin,
|
|
11
12
|
get_latest_end_quarter_date_asset_position,
|
wbportfolio/filters/products.py
CHANGED
|
@@ -4,6 +4,7 @@ from wbcore.contrib.directory.models import Company, Entry
|
|
|
4
4
|
from wbfdm.filters.instruments import InstrumentFilterSet
|
|
5
5
|
from wbfdm.filters.utils import last_period_date_range
|
|
6
6
|
from wbfdm.models import Classification
|
|
7
|
+
|
|
7
8
|
from wbportfolio.models import Product, ProductGroup
|
|
8
9
|
|
|
9
10
|
|
wbportfolio/filters/roles.py
CHANGED
wbportfolio/filters/signals.py
CHANGED
|
@@ -6,6 +6,7 @@ from wbcore import filters as wb_filters
|
|
|
6
6
|
from wbcore.signals.filters import add_filters
|
|
7
7
|
from wbfdm.filters import BaseClassifiedInstrumentFilterSet, ClassificationFilter
|
|
8
8
|
from wbfdm.models import InstrumentClassificationThroughModel
|
|
9
|
+
|
|
9
10
|
from wbportfolio.models import AssetPosition, Portfolio
|
|
10
11
|
|
|
11
12
|
|
|
@@ -7,6 +7,7 @@ from wbcore.utils.date import current_financial_quarter
|
|
|
7
7
|
from wbcrm.models.accounts import Account, AccountRole
|
|
8
8
|
from wbfdm.models import Classification, ClassificationGroup
|
|
9
9
|
from wbfdm.preferences import get_default_classification_group
|
|
10
|
+
|
|
10
11
|
from wbportfolio.filters.transactions.mixins import OppositeSharesFieldMethodMixin
|
|
11
12
|
from wbportfolio.models import Product, ProductGroup
|
|
12
13
|
from wbportfolio.models.transactions.claim import Claim, ClaimGroupbyChoice
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from wbcore import filters as wb_filters
|
|
2
2
|
from wbcore.filters.defaults import current_quarter_date_range
|
|
3
3
|
from wbcore.pandas.filterset import PandasFilterSetMixin
|
|
4
|
+
|
|
4
5
|
from wbportfolio.models import Fees
|
|
5
6
|
|
|
6
7
|
from .transactions import TransactionFilterSet, get_transaction_default_date_range
|
|
@@ -4,10 +4,11 @@ from django.db.models import Count, OuterRef, Subquery
|
|
|
4
4
|
from wbcore import filters as wb_filters
|
|
5
5
|
from wbcrm.models.accounts import Account
|
|
6
6
|
from wbfdm.models import Instrument
|
|
7
|
+
|
|
7
8
|
from wbportfolio.models import Product, Trade
|
|
8
9
|
from wbportfolio.models.transactions.claim import Claim
|
|
9
|
-
from .mixins import OppositeSharesFieldMethodMixin
|
|
10
10
|
|
|
11
|
+
from .mixins import OppositeSharesFieldMethodMixin
|
|
11
12
|
from .transactions import TransactionFilterSet
|
|
12
13
|
|
|
13
14
|
|
|
@@ -6,6 +6,7 @@ from django.core.serializers.json import DjangoJSONEncoder
|
|
|
6
6
|
from pandas.tseries.offsets import BDay
|
|
7
7
|
from wbcore.contrib.io.backends import AbstractDataBackend, register
|
|
8
8
|
from wbfdm.models import Instrument
|
|
9
|
+
|
|
9
10
|
from wbportfolio.import_export.backends.utils import (
|
|
10
11
|
get_timedelta_import_instrument_price,
|
|
11
12
|
)
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
from collections import defaultdict
|
|
2
|
+
from contextlib import suppress
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
from decimal import Decimal
|
|
4
5
|
from itertools import chain
|
|
@@ -6,8 +7,6 @@ from typing import Any, Dict, List, Optional
|
|
|
6
7
|
|
|
7
8
|
from django.core.exceptions import ObjectDoesNotExist
|
|
8
9
|
from django.db import models
|
|
9
|
-
from contextlib import suppress
|
|
10
|
-
|
|
11
10
|
from wbcore.contrib.authentication.authentication import User
|
|
12
11
|
from wbcore.contrib.currency.import_export.handlers import CurrencyImportHandler
|
|
13
12
|
from wbcore.contrib.io.exceptions import DeserializationError
|
|
@@ -16,6 +15,7 @@ from wbcore.contrib.notifications.dispatch import send_notification
|
|
|
16
15
|
from wbfdm.import_export.handlers.instrument import InstrumentImportHandler
|
|
17
16
|
from wbfdm.import_export.handlers.instrument_price import InstrumentPriceImportHandler
|
|
18
17
|
from wbfdm.models.exchanges import Exchange
|
|
18
|
+
|
|
19
19
|
from wbportfolio.models.roles import PortfolioRole
|
|
20
20
|
|
|
21
21
|
|
|
@@ -34,7 +34,7 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
34
34
|
from wbportfolio.models import Portfolio
|
|
35
35
|
|
|
36
36
|
portfolio_data = data.pop("portfolio", None)
|
|
37
|
-
|
|
37
|
+
underlying_quote_data = data.pop("underlying_quote", data.pop("underlying_instrument", None))
|
|
38
38
|
if "currency" in data:
|
|
39
39
|
data["currency"] = self.currency_handler.process_object(data["currency"], read_only=True)[0]
|
|
40
40
|
data["date"] = datetime.strptime(data["date"], "%Y-%m-%d").date()
|
|
@@ -49,8 +49,8 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
49
49
|
data["exchange"] = Exchange.dict_to_model(sanitized_dict)
|
|
50
50
|
|
|
51
51
|
data["portfolio"] = Portfolio._get_or_create_portfolio(self.instrument_handler, portfolio_data)
|
|
52
|
-
data["
|
|
53
|
-
|
|
52
|
+
data["underlying_quote"] = self.instrument_handler.process_object(
|
|
53
|
+
underlying_quote_data, only_security=False, read_only=True
|
|
54
54
|
)[0]
|
|
55
55
|
|
|
56
56
|
# number type deserialization and sanitization
|
|
@@ -69,13 +69,13 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
69
69
|
# if the initial price is not provided, we try to get it directly from the dataloader
|
|
70
70
|
if data.get("initial_price") is None:
|
|
71
71
|
try:
|
|
72
|
-
data["initial_price"] = data["
|
|
72
|
+
data["initial_price"] = data["underlying_quote"].get_price(
|
|
73
73
|
data["date"], price_date_timedelta=self.PRICE_DATE_TIMEDELTA
|
|
74
74
|
)
|
|
75
75
|
except ValueError:
|
|
76
76
|
# If we cannot find a price with the default timedelta, we try with a bigger range (in case the instrument stopped trading for some time for instance)
|
|
77
77
|
try:
|
|
78
|
-
data["initial_price"] = data["
|
|
78
|
+
data["initial_price"] = data["underlying_quote"].get_price(
|
|
79
79
|
data["date"], price_date_timedelta=self.MAX_PRICE_DATE_TIMEDELTA
|
|
80
80
|
)
|
|
81
81
|
except ValueError:
|
|
@@ -88,9 +88,7 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
88
88
|
|
|
89
89
|
def _get_instance(self, data: Dict[str, Any], history: Optional[models.QuerySet] = None, **kwargs) -> models.Model:
|
|
90
90
|
self.import_source.log += "\nTrying to get asset position instance"
|
|
91
|
-
position = data["portfolio"].assets.filter(
|
|
92
|
-
date=data["date"], underlying_instrument=data["underlying_instrument"]
|
|
93
|
-
)
|
|
91
|
+
position = data["portfolio"].assets.filter(date=data["date"], underlying_quote=data["underlying_quote"])
|
|
94
92
|
if position.exists():
|
|
95
93
|
self.import_source.log += "\nAsset Position found."
|
|
96
94
|
if position.count() > 1:
|
|
@@ -104,7 +102,7 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
104
102
|
def _create_instance(self, data: Dict[str, Any], **kwargs) -> models.Model:
|
|
105
103
|
instance = self.model(
|
|
106
104
|
portfolio=data["portfolio"],
|
|
107
|
-
|
|
105
|
+
underlying_quote=data["underlying_quote"],
|
|
108
106
|
date=data["date"],
|
|
109
107
|
asset_valuation_date=data["asset_valuation_date"],
|
|
110
108
|
weighting=data.get("weighting", None),
|
|
@@ -118,10 +116,10 @@ class AssetPositionImportHandler(ImportExportHandler):
|
|
|
118
116
|
return self._save_object(instance, **kwargs)
|
|
119
117
|
|
|
120
118
|
def _save_object(self, _object, **kwargs):
|
|
121
|
-
_object.
|
|
119
|
+
_object.underlying_quote_price = (
|
|
122
120
|
None # detech possibly already attached instrument price to retrigger the save mechanism
|
|
123
121
|
)
|
|
124
|
-
_object.save(
|
|
122
|
+
_object.save(create_underlying_quote_price_if_missing=True)
|
|
125
123
|
return _object
|
|
126
124
|
|
|
127
125
|
def _post_processing_objects(
|
|
@@ -3,6 +3,7 @@ from datetime import datetime
|
|
|
3
3
|
from wbcore.contrib.currency.import_export.handlers import CurrencyImportHandler
|
|
4
4
|
from wbcore.contrib.io.imports import ImportExportHandler
|
|
5
5
|
from wbfdm.models.instruments import Cash
|
|
6
|
+
|
|
6
7
|
from wbportfolio.models.products import Product
|
|
7
8
|
|
|
8
9
|
|
|
@@ -7,6 +7,7 @@ from django.contrib.auth import get_user_model
|
|
|
7
7
|
from django.db.models import Q
|
|
8
8
|
from wbcore.contrib.io.imports import ImportExportHandler
|
|
9
9
|
from wbcore.contrib.notifications.dispatch import send_notification
|
|
10
|
+
|
|
10
11
|
from wbportfolio.models import Portfolio
|
|
11
12
|
|
|
12
13
|
if TYPE_CHECKING:
|
|
@@ -9,6 +9,7 @@ from wbcore.contrib.io.exceptions import DeserializationError
|
|
|
9
9
|
from wbcore.contrib.io.imports import ImportExportHandler
|
|
10
10
|
from wbfdm.import_export.handlers.instrument import InstrumentImportHandler
|
|
11
11
|
from wbfdm.models import InstrumentType
|
|
12
|
+
|
|
12
13
|
from wbportfolio.models.portfolio import Portfolio
|
|
13
14
|
from wbportfolio.models.products import update_outstanding_shares_as_task
|
|
14
15
|
from wbportfolio.utils import string_matching
|
|
@@ -4,6 +4,7 @@ import re
|
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
|
+
|
|
7
8
|
from wbportfolio.import_export.utils import convert_string_to_number
|
|
8
9
|
|
|
9
10
|
logger = logging.getLogger("importers.parsers.jp_morgan.strategy")
|
|
@@ -30,7 +31,7 @@ def manually_create_100_position(parent_strategies, valuation_date):
|
|
|
30
31
|
last_price = float(valuations.latest("date").net_value)
|
|
31
32
|
data.append(
|
|
32
33
|
{
|
|
33
|
-
"
|
|
34
|
+
"underlying_quote": index.id,
|
|
34
35
|
"portfolio": {"instrument_type": "product", "id": product.id},
|
|
35
36
|
"currency__key": index.currency.key,
|
|
36
37
|
"initial_currency_fx_rate": 1.0,
|
|
@@ -84,7 +85,7 @@ def parse(import_source):
|
|
|
84
85
|
weighting = convert_string_to_number(strategy_data["Weight In Percent"].replace("%", "")) / 100
|
|
85
86
|
except Exception:
|
|
86
87
|
weighting = 0.0
|
|
87
|
-
|
|
88
|
+
underlying_quote = {
|
|
88
89
|
"ticker": ticker,
|
|
89
90
|
"exchange": exchange,
|
|
90
91
|
"isin": isin,
|
|
@@ -93,10 +94,10 @@ def parse(import_source):
|
|
|
93
94
|
"instrument_type": instrument_type.lower(),
|
|
94
95
|
}
|
|
95
96
|
if isin:
|
|
96
|
-
|
|
97
|
+
underlying_quote["isin"] = isin
|
|
97
98
|
data.append(
|
|
98
99
|
{
|
|
99
|
-
"
|
|
100
|
+
"underlying_quote": underlying_quote,
|
|
100
101
|
"portfolio": {
|
|
101
102
|
"instrument_type": "index",
|
|
102
103
|
"ticker": strategy,
|
|
@@ -4,6 +4,7 @@ from io import BytesIO
|
|
|
4
4
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
|
+
|
|
7
8
|
from wbportfolio.models import Product
|
|
8
9
|
|
|
9
10
|
FIELD_MAP = {
|
|
@@ -11,9 +12,9 @@ FIELD_MAP = {
|
|
|
11
12
|
"CURRENT PRICE": "initial_price",
|
|
12
13
|
"FX": "initial_currency_fx_rate",
|
|
13
14
|
"TOTAL UNITS": "initial_shares",
|
|
14
|
-
"TYPE": "
|
|
15
|
-
"NAME": "
|
|
16
|
-
"ISIN": "
|
|
15
|
+
"TYPE": "underlying_quote__instrument_type",
|
|
16
|
+
"NAME": "underlying_quote__name",
|
|
17
|
+
"ISIN": "underlying_quote__isin",
|
|
17
18
|
"WEIGHT (%)": "weighting",
|
|
18
19
|
}
|
|
19
20
|
|
|
@@ -34,11 +35,11 @@ def parse(import_source):
|
|
|
34
35
|
df = df.rename(columns=df.iloc[0]).drop(df.index[0]).dropna(how="all").rename(columns=FIELD_MAP)
|
|
35
36
|
|
|
36
37
|
df = df[
|
|
37
|
-
(df["
|
|
38
|
+
(df["underlying_quote__instrument_type"].isin(["CASH", "SHARE"]))
|
|
38
39
|
& (df["N"].astype("str").str.isnumeric())
|
|
39
40
|
]
|
|
40
41
|
|
|
41
|
-
equities_index = df["
|
|
42
|
+
equities_index = df["underlying_quote__instrument_type"] == "SHARE"
|
|
42
43
|
df.loc[~equities_index, "initial_shares"] = df.loc[~equities_index, "TOTAL VALUE"]
|
|
43
44
|
df.loc[~equities_index, "initial_price"] = 1.0
|
|
44
45
|
df.initial_currency_fx_rate = df.initial_currency_fx_rate.fillna(1.0)
|
|
@@ -46,25 +47,25 @@ def parse(import_source):
|
|
|
46
47
|
# df["weighting"] = df.weighting / df.weighting.sum()
|
|
47
48
|
product = Product.objects.get(isin=sheet_name)
|
|
48
49
|
for position in df.to_dict("records"):
|
|
49
|
-
if position["
|
|
50
|
+
if position["underlying_quote__instrument_type"] == "CASH":
|
|
50
51
|
ticker = exchange = "CASH"
|
|
51
52
|
else:
|
|
52
53
|
ticker, exchange, _ = str(position["BBG TICKER / IDENTIFIER"]).split(" ")
|
|
53
54
|
|
|
54
|
-
if position["
|
|
55
|
-
|
|
55
|
+
if position["underlying_quote__instrument_type"] == "SHARE":
|
|
56
|
+
underlying_quote = {
|
|
56
57
|
"ticker": ticker,
|
|
57
58
|
"exchange": {"bbg_exchange_codes": exchange},
|
|
58
|
-
"name": position["
|
|
59
|
+
"name": position["underlying_quote__name"],
|
|
59
60
|
"currency__key": position["currency__key"],
|
|
60
61
|
"instrument_type": "equity",
|
|
61
|
-
"isin": position["
|
|
62
|
+
"isin": position["underlying_quote__isin"],
|
|
62
63
|
}
|
|
63
64
|
else:
|
|
64
|
-
|
|
65
|
+
underlying_quote = {"currency__key": position["currency__key"], "instrument_type": "cash"}
|
|
65
66
|
data.append(
|
|
66
67
|
{
|
|
67
|
-
"
|
|
68
|
+
"underlying_quote": underlying_quote,
|
|
68
69
|
"currency__key": position["currency__key"],
|
|
69
70
|
"is_estimated": False,
|
|
70
71
|
"date": valuation_date.strftime("%Y-%m-%d"),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import xlrd
|
|
2
|
+
|
|
2
3
|
from wbportfolio.models import Product
|
|
3
4
|
|
|
4
5
|
|
|
@@ -45,7 +46,7 @@ def parse(import_source):
|
|
|
45
46
|
|
|
46
47
|
data.append(
|
|
47
48
|
{
|
|
48
|
-
"
|
|
49
|
+
"underlying_quote": {"instrument_type": "product", "ticker": ticker},
|
|
49
50
|
"currency__key": currency_key,
|
|
50
51
|
"date": valuation_date.strftime("%Y-%m-%d"),
|
|
51
52
|
"asset_valuation_date": valuation_date.strftime("%Y-%m-%d"),
|
|
@@ -58,7 +59,7 @@ def parse(import_source):
|
|
|
58
59
|
|
|
59
60
|
data.append(
|
|
60
61
|
{
|
|
61
|
-
"
|
|
62
|
+
"underlying_quote": {
|
|
62
63
|
"instrument_type": "cash",
|
|
63
64
|
"ticker": "CASH",
|
|
64
65
|
"name": f"1 {product.currency.key} AMC",
|
|
@@ -10,7 +10,7 @@ FIELD_MAP = {
|
|
|
10
10
|
"Valuation Date": "asset_valuation_date",
|
|
11
11
|
"Quoted Crncy": "currency__key",
|
|
12
12
|
"exchange": "exchange",
|
|
13
|
-
"
|
|
13
|
+
"underlying_quote": "underlying_quote",
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
|
|
@@ -20,7 +20,7 @@ def _apply_adjusting_factor(row):
|
|
|
20
20
|
|
|
21
21
|
No idea why though
|
|
22
22
|
"""
|
|
23
|
-
if row["
|
|
23
|
+
if row["underlying_quote"]["instrument_type"] == "product":
|
|
24
24
|
return pd.Series([row["initial_price"], row["initial_shares"] * row["Quotity/Adj. factor"]])
|
|
25
25
|
else:
|
|
26
26
|
return pd.Series([row["initial_price"] * row["Quotity/Adj. factor"], row["initial_shares"]])
|
|
@@ -39,14 +39,14 @@ def parse(import_source):
|
|
|
39
39
|
df = df.rename(columns=FIELD_MAP)
|
|
40
40
|
df = df.dropna(subset=["initial_price"])
|
|
41
41
|
df["initial_price"] = df["initial_price"].astype("str").str.replace(" ", "").astype("float")
|
|
42
|
-
df["
|
|
42
|
+
df["underlying_quote"] = df[["Ticker", "Name", "currency__key"]].apply(
|
|
43
43
|
lambda x: _get_underlying_instrument(*x), axis=1
|
|
44
44
|
)
|
|
45
45
|
df["initial_price"] = df["initial_price"].replace(0, np.nan).fillna(1.0)
|
|
46
46
|
df[["initial_price", "initial_shares"]] = df[
|
|
47
|
-
["initial_price", "initial_shares", "Quotity/Adj. factor", "
|
|
47
|
+
["initial_price", "initial_shares", "Quotity/Adj. factor", "underlying_quote"]
|
|
48
48
|
].apply(lambda x: _apply_adjusting_factor(x), axis=1)
|
|
49
|
-
df["exchange"] = df.
|
|
49
|
+
df["exchange"] = df.underlying_quote.apply(lambda x: x.get("exchange", None))
|
|
50
50
|
df = df.drop(columns=df.columns.difference(FIELD_MAP.values()))
|
|
51
51
|
|
|
52
52
|
df["portfolio__instrument_type"] = "product"
|
|
@@ -2,6 +2,7 @@ import datetime
|
|
|
2
2
|
import re
|
|
3
3
|
|
|
4
4
|
from django.db.models import Q
|
|
5
|
+
|
|
5
6
|
from wbportfolio.models import Product
|
|
6
7
|
|
|
7
8
|
INSTRUMENT_MAP_NAME = {"EDA23_AtonRa Z class": Product.objects.get(isin="LU2170995018")}
|
|
@@ -28,9 +29,9 @@ def _get_underlying_instrument(bbg_code, name, currency, instrument_type="equity
|
|
|
28
29
|
|
|
29
30
|
cash_position = cash_position or "CASH" == bbg_code or len(re.findall("(CASH [A-Z]{3})", bbg_code)) > 0
|
|
30
31
|
if cash_position:
|
|
31
|
-
|
|
32
|
+
underlying_quote = {"instrument_type": "cash", "currency__key": currency}
|
|
32
33
|
else:
|
|
33
|
-
|
|
34
|
+
underlying_quote = {
|
|
34
35
|
"exchange": {"bbg_exchange_codes": exchange},
|
|
35
36
|
"currency__key": currency,
|
|
36
37
|
"name": name.split(" @")[0].split("/")[
|
|
@@ -44,13 +45,13 @@ def _get_underlying_instrument(bbg_code, name, currency, instrument_type="equity
|
|
|
44
45
|
if len(isin_re) > 0:
|
|
45
46
|
isin = isin_re[0]
|
|
46
47
|
# Natixis gives us ISIN as ticker for product. in that case, we registered the isin but we remove the ticker
|
|
47
|
-
|
|
48
|
-
del
|
|
48
|
+
underlying_quote["instrument_type"] = "product"
|
|
49
|
+
del underlying_quote["ticker"]
|
|
49
50
|
elif Product.objects.filter(ticker=ticker).exists():
|
|
50
|
-
|
|
51
|
+
underlying_quote["instrument_type"] = "product"
|
|
51
52
|
if isin:
|
|
52
|
-
|
|
53
|
-
return
|
|
53
|
+
underlying_quote["isin"] = isin
|
|
54
|
+
return underlying_quote
|
|
54
55
|
|
|
55
56
|
|
|
56
57
|
def file_name_parse(file_name):
|
|
@@ -5,9 +5,10 @@ from io import StringIO
|
|
|
5
5
|
import numpy as np
|
|
6
6
|
import pandas as pd
|
|
7
7
|
from wbfdm.models import InstrumentPrice
|
|
8
|
-
from wbportfolio.models import Product, Register, Trade
|
|
9
8
|
from xlrd import xldate_as_datetime
|
|
10
9
|
|
|
10
|
+
from wbportfolio.models import Product, Register, Trade
|
|
11
|
+
|
|
11
12
|
from .sylk import SYLK
|
|
12
13
|
from .utils import assemble_transaction_reference, get_portfolio_id
|
|
13
14
|
|