wbportfolio 1.52.0__py2.py3-none-any.whl → 1.59.4__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 +3 -1
- wbportfolio/admin/indexes.py +1 -1
- wbportfolio/admin/orders/__init__.py +2 -0
- wbportfolio/admin/orders/order_proposals.py +16 -0
- wbportfolio/admin/orders/orders.py +32 -0
- wbportfolio/admin/portfolio.py +11 -5
- wbportfolio/admin/product_groups.py +1 -1
- wbportfolio/admin/products.py +2 -1
- wbportfolio/admin/{transactions/rebalancing.py → rebalancing.py} +1 -1
- wbportfolio/admin/transactions/__init__.py +0 -2
- wbportfolio/admin/transactions/dividends.py +40 -4
- wbportfolio/admin/transactions/fees.py +24 -14
- wbportfolio/admin/transactions/trades.py +34 -27
- wbportfolio/analysis/claims.py +5 -6
- wbportfolio/api_clients/ubs.py +162 -0
- wbportfolio/constants.py +1 -0
- wbportfolio/contrib/company_portfolio/configs/display.py +22 -10
- wbportfolio/contrib/company_portfolio/configs/previews.py +3 -3
- wbportfolio/contrib/company_portfolio/filters.py +10 -10
- wbportfolio/contrib/company_portfolio/models.py +69 -39
- wbportfolio/contrib/company_portfolio/scripts.py +7 -2
- wbportfolio/contrib/company_portfolio/serializers.py +32 -22
- wbportfolio/contrib/company_portfolio/tasks.py +12 -1
- wbportfolio/contrib/company_portfolio/tests/conftest.py +2 -2
- wbportfolio/defaults/fees/default.py +7 -15
- wbportfolio/factories/__init__.py +2 -2
- wbportfolio/factories/assets.py +1 -1
- wbportfolio/factories/dividends.py +8 -3
- wbportfolio/factories/fees.py +8 -4
- wbportfolio/factories/orders/__init__.py +2 -0
- wbportfolio/factories/orders/order_proposals.py +21 -0
- wbportfolio/factories/orders/orders.py +34 -0
- wbportfolio/factories/portfolios.py +2 -1
- wbportfolio/factories/product_groups.py +3 -3
- wbportfolio/factories/products.py +3 -3
- wbportfolio/factories/rebalancing.py +1 -1
- wbportfolio/factories/trades.py +12 -16
- wbportfolio/filters/assets.py +18 -4
- wbportfolio/filters/orders/__init__.py +2 -0
- wbportfolio/filters/orders/order_proposals.py +55 -0
- wbportfolio/filters/orders/orders.py +11 -0
- wbportfolio/filters/portfolios.py +38 -1
- wbportfolio/filters/positions.py +0 -1
- wbportfolio/filters/transactions/__init__.py +1 -2
- wbportfolio/filters/transactions/fees.py +5 -12
- wbportfolio/filters/transactions/trades.py +16 -8
- wbportfolio/filters/transactions/utils.py +42 -0
- wbportfolio/import_export/backends/ubs/__init__.py +1 -0
- wbportfolio/import_export/backends/ubs/asset_position.py +6 -7
- wbportfolio/import_export/backends/ubs/fees.py +10 -20
- wbportfolio/import_export/backends/ubs/instrument_price.py +6 -6
- wbportfolio/import_export/backends/ubs/trade.py +48 -0
- wbportfolio/import_export/backends/utils.py +0 -17
- wbportfolio/import_export/handlers/asset_position.py +22 -10
- wbportfolio/import_export/handlers/dividend.py +8 -8
- wbportfolio/import_export/handlers/fees.py +13 -23
- wbportfolio/import_export/handlers/orders.py +71 -0
- wbportfolio/import_export/handlers/trade.py +53 -77
- wbportfolio/import_export/parsers/default_mapping.py +1 -1
- wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +2 -2
- wbportfolio/import_export/parsers/jpmorgan/fees.py +4 -4
- wbportfolio/import_export/parsers/jpmorgan/strategy.py +59 -85
- wbportfolio/import_export/parsers/jpmorgan/valuation.py +2 -2
- wbportfolio/import_export/parsers/leonteq/customer_trade.py +5 -5
- wbportfolio/import_export/parsers/leonteq/fees.py +11 -7
- wbportfolio/import_export/parsers/leonteq/trade.py +2 -6
- wbportfolio/import_export/parsers/natixis/d1_fees.py +2 -2
- wbportfolio/import_export/parsers/natixis/dividend.py +4 -9
- wbportfolio/import_export/parsers/natixis/equity.py +22 -4
- wbportfolio/import_export/parsers/natixis/fees.py +7 -9
- wbportfolio/import_export/parsers/natixis/utils.py +13 -19
- wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +1 -1
- wbportfolio/import_export/parsers/sg_lux/equity.py +10 -10
- wbportfolio/import_export/parsers/sg_lux/fees.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/perf_fees.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/sylk.py +12 -11
- wbportfolio/import_export/parsers/sg_lux/utils.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/valuation.py +4 -2
- wbportfolio/import_export/parsers/societe_generale/strategy.py +5 -5
- wbportfolio/import_export/parsers/tellco/customer_trade.py +2 -1
- wbportfolio/import_export/parsers/tellco/valuation.py +4 -3
- wbportfolio/import_export/parsers/ubs/api/fees.py +2 -2
- wbportfolio/import_export/parsers/ubs/api/trade.py +39 -0
- wbportfolio/import_export/parsers/ubs/customer_trade.py +7 -5
- wbportfolio/import_export/parsers/ubs/equity.py +3 -2
- wbportfolio/import_export/parsers/ubs/valuation.py +2 -1
- wbportfolio/import_export/parsers/vontobel/customer_trade.py +2 -3
- wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -1
- wbportfolio/import_export/parsers/vontobel/management_fees.py +12 -20
- wbportfolio/import_export/parsers/vontobel/performance_fees.py +5 -8
- wbportfolio/import_export/parsers/vontobel/valuation_api.py +4 -1
- wbportfolio/import_export/resources/trades.py +3 -3
- wbportfolio/import_export/utils.py +3 -1
- wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +2 -2
- wbportfolio/metric/backends/base.py +2 -2
- wbportfolio/migrations/0059_fees_unique_fees.py +1 -1
- wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +622 -0
- wbportfolio/migrations/0078_trade_drift_factor.py +26 -0
- wbportfolio/migrations/0079_alter_trade_drift_factor.py +19 -0
- wbportfolio/migrations/0080_alter_trade_drift_factor_alter_trade_weighting.py +19 -0
- wbportfolio/migrations/0081_alter_trade_drift_factor.py +19 -0
- wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py +93 -0
- wbportfolio/migrations/0083_order_alter_trade_options_and_more.py +181 -0
- wbportfolio/migrations/0084_orderproposal_min_order_value.py +25 -0
- wbportfolio/migrations/0085_order_desired_target_weight.py +26 -0
- wbportfolio/migrations/0086_orderproposal_total_cash_weight.py +19 -0
- wbportfolio/migrations/0087_product_order_routing_custodian_adapter.py +94 -0
- wbportfolio/migrations/0088_orderproposal_total_effective_portfolio_contribution.py +19 -0
- wbportfolio/migrations/0089_orderproposal_min_weighting.py +71 -0
- wbportfolio/migrations/0090_dividendtransaction_price_fx_portfolio_and_more.py +44 -0
- wbportfolio/migrations/0091_remove_order_execution_confirmed_and_more.py +32 -0
- wbportfolio/migrations/0092_order_quantization_error_alter_orderproposal_status.py +49 -0
- wbportfolio/migrations/0093_remove_portfolioportfoliothroughmodel_unique_primary_and_more.py +35 -0
- wbportfolio/models/__init__.py +2 -0
- wbportfolio/models/adjustments.py +1 -1
- wbportfolio/models/asset.py +28 -170
- wbportfolio/models/builder.py +323 -0
- wbportfolio/models/custodians.py +3 -3
- wbportfolio/models/exceptions.py +1 -1
- wbportfolio/models/graphs/portfolio.py +1 -1
- wbportfolio/models/graphs/utils.py +11 -11
- wbportfolio/models/mixins/instruments.py +7 -0
- wbportfolio/models/mixins/liquidity_stress_test.py +4 -4
- wbportfolio/models/orders/__init__.py +2 -0
- wbportfolio/models/orders/order_proposals.py +1414 -0
- wbportfolio/models/orders/orders.py +410 -0
- wbportfolio/models/portfolio.py +311 -289
- wbportfolio/models/portfolio_relationship.py +6 -0
- wbportfolio/models/products.py +12 -0
- wbportfolio/models/{transactions/rebalancing.py → rebalancing.py} +40 -27
- wbportfolio/models/roles.py +4 -10
- wbportfolio/models/transactions/__init__.py +0 -4
- wbportfolio/models/transactions/claim.py +7 -6
- wbportfolio/models/transactions/dividends.py +42 -5
- wbportfolio/models/transactions/fees.py +55 -22
- wbportfolio/models/transactions/trades.py +121 -442
- wbportfolio/models/transactions/transactions.py +78 -158
- wbportfolio/models/utils.py +100 -1
- wbportfolio/order_routing/__init__.py +35 -0
- wbportfolio/order_routing/adapters/__init__.py +65 -0
- wbportfolio/order_routing/adapters/ubs.py +195 -0
- wbportfolio/order_routing/router.py +33 -0
- wbportfolio/order_routing/tests/__init__.py +0 -0
- wbportfolio/order_routing/tests/test_router.py +110 -0
- wbportfolio/permissions.py +7 -0
- wbportfolio/pms/analytics/portfolio.py +17 -9
- wbportfolio/pms/analytics/utils.py +9 -0
- wbportfolio/pms/trading/__init__.py +0 -1
- wbportfolio/pms/trading/optimizer.py +61 -0
- wbportfolio/pms/typing.py +198 -63
- wbportfolio/rebalancing/base.py +12 -1
- wbportfolio/rebalancing/decorators.py +1 -1
- wbportfolio/rebalancing/models/composite.py +4 -8
- wbportfolio/rebalancing/models/equally_weighted.py +13 -11
- wbportfolio/rebalancing/models/market_capitalization_weighted.py +21 -14
- wbportfolio/rebalancing/models/model_portfolio.py +14 -18
- wbportfolio/risk_management/backends/__init__.py +1 -0
- wbportfolio/risk_management/backends/controversy_portfolio.py +2 -2
- wbportfolio/risk_management/backends/esg_aggregation_portfolio.py +64 -0
- wbportfolio/risk_management/backends/exposure_portfolio.py +4 -4
- wbportfolio/risk_management/backends/instrument_list_portfolio.py +3 -3
- wbportfolio/risk_management/tests/test_esg_aggregation_portfolio.py +49 -0
- wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -1
- wbportfolio/risk_management/tests/test_stop_loss_instrument.py +2 -2
- wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -1
- wbportfolio/serializers/__init__.py +1 -0
- wbportfolio/serializers/orders/__init__.py +2 -0
- wbportfolio/serializers/orders/order_proposals.py +115 -0
- wbportfolio/serializers/orders/orders.py +283 -0
- wbportfolio/serializers/portfolios.py +7 -7
- wbportfolio/serializers/positions.py +2 -2
- wbportfolio/serializers/rebalancing.py +1 -1
- wbportfolio/serializers/signals.py +9 -12
- wbportfolio/serializers/transactions/__init__.py +1 -10
- wbportfolio/serializers/transactions/claim.py +2 -2
- wbportfolio/serializers/transactions/dividends.py +37 -9
- wbportfolio/serializers/transactions/fees.py +39 -10
- wbportfolio/serializers/transactions/trades.py +55 -157
- wbportfolio/tasks.py +43 -5
- wbportfolio/tests/analysis/__init__.py +0 -0
- wbportfolio/tests/analysis/test_claims.py +85 -0
- wbportfolio/tests/conftest.py +12 -12
- wbportfolio/tests/models/orders/__init__.py +0 -0
- wbportfolio/tests/models/orders/test_order_proposals.py +1046 -0
- wbportfolio/tests/models/test_assets.py +7 -3
- wbportfolio/tests/models/test_imports.py +9 -13
- wbportfolio/tests/models/test_portfolios.py +102 -95
- wbportfolio/tests/models/test_products.py +11 -0
- wbportfolio/tests/models/test_splits.py +1 -6
- wbportfolio/tests/models/test_utils.py +140 -0
- wbportfolio/tests/models/transactions/test_fees.py +7 -13
- wbportfolio/tests/models/transactions/test_rebalancing.py +5 -5
- wbportfolio/tests/models/transactions/test_trades.py +0 -20
- wbportfolio/tests/pms/test_analytics.py +22 -3
- wbportfolio/tests/rebalancing/test_models.py +51 -57
- wbportfolio/tests/signals.py +10 -20
- wbportfolio/tests/tests.py +3 -1
- wbportfolio/tests/viewsets/test_products.py +1 -0
- wbportfolio/urls.py +10 -13
- wbportfolio/viewsets/__init__.py +9 -4
- wbportfolio/viewsets/assets.py +3 -204
- wbportfolio/viewsets/charts/__init__.py +6 -1
- wbportfolio/viewsets/charts/assets.py +344 -154
- wbportfolio/viewsets/configs/buttons/__init__.py +2 -2
- wbportfolio/viewsets/configs/buttons/assets.py +1 -1
- wbportfolio/viewsets/configs/buttons/mixins.py +4 -4
- wbportfolio/viewsets/configs/buttons/portfolios.py +45 -1
- wbportfolio/viewsets/configs/buttons/products.py +32 -2
- wbportfolio/viewsets/configs/display/__init__.py +2 -5
- wbportfolio/viewsets/configs/display/assets.py +6 -19
- wbportfolio/viewsets/configs/display/fees.py +3 -3
- wbportfolio/viewsets/configs/display/portfolios.py +5 -5
- wbportfolio/viewsets/configs/display/products.py +1 -1
- wbportfolio/viewsets/configs/display/rebalancing.py +2 -2
- wbportfolio/viewsets/configs/display/reconciliations.py +4 -4
- wbportfolio/viewsets/configs/display/trades.py +1 -189
- wbportfolio/viewsets/configs/endpoints/__init__.py +3 -7
- wbportfolio/viewsets/configs/endpoints/fees.py +2 -2
- wbportfolio/viewsets/configs/endpoints/trades.py +0 -41
- wbportfolio/viewsets/configs/menu/__init__.py +1 -1
- wbportfolio/viewsets/configs/menu/orders.py +11 -0
- wbportfolio/viewsets/configs/titles/__init__.py +2 -3
- wbportfolio/viewsets/configs/titles/fees.py +4 -8
- wbportfolio/viewsets/esg.py +3 -5
- wbportfolio/viewsets/mixins.py +5 -1
- wbportfolio/viewsets/orders/__init__.py +6 -0
- wbportfolio/viewsets/orders/configs/__init__.py +4 -0
- wbportfolio/viewsets/orders/configs/buttons/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/buttons/order_proposals.py +188 -0
- wbportfolio/viewsets/orders/configs/buttons/orders.py +113 -0
- wbportfolio/viewsets/orders/configs/displays/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/displays/order_proposals.py +157 -0
- wbportfolio/viewsets/orders/configs/displays/orders.py +232 -0
- wbportfolio/viewsets/orders/configs/endpoints/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py +21 -0
- wbportfolio/viewsets/orders/configs/endpoints/orders.py +28 -0
- wbportfolio/viewsets/orders/configs/titles/__init__.py +0 -0
- wbportfolio/viewsets/orders/configs/titles/orders.py +0 -0
- wbportfolio/viewsets/orders/order_proposals.py +252 -0
- wbportfolio/viewsets/orders/orders.py +277 -0
- wbportfolio/viewsets/portfolios.py +36 -12
- wbportfolio/viewsets/positions.py +3 -2
- wbportfolio/viewsets/products.py +6 -6
- wbportfolio/viewsets/{transactions/rebalancing.py → rebalancing.py} +2 -2
- wbportfolio/viewsets/transactions/__init__.py +3 -14
- wbportfolio/viewsets/transactions/fees.py +22 -22
- wbportfolio/viewsets/transactions/trades.py +1 -180
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/METADATA +3 -1
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/RECORD +252 -203
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/WHEEL +1 -1
- wbportfolio/admin/transactions/transactions.py +0 -38
- wbportfolio/factories/transactions.py +0 -22
- wbportfolio/fdm/tasks.py +0 -13
- wbportfolio/filters/transactions/transactions.py +0 -99
- wbportfolio/models/transactions/expiry.py +0 -7
- wbportfolio/models/transactions/trade_proposals.py +0 -704
- wbportfolio/pms/trading/handler.py +0 -161
- wbportfolio/serializers/transactions/expiry.py +0 -18
- wbportfolio/serializers/transactions/trade_proposals.py +0 -76
- wbportfolio/serializers/transactions/transactions.py +0 -85
- wbportfolio/tests/models/transactions/test_trade_proposals.py +0 -410
- wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -66
- wbportfolio/viewsets/configs/display/trade_proposals.py +0 -100
- wbportfolio/viewsets/configs/display/transactions.py +0 -55
- wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -18
- wbportfolio/viewsets/configs/endpoints/transactions.py +0 -14
- wbportfolio/viewsets/configs/menu/transactions.py +0 -9
- wbportfolio/viewsets/configs/titles/transactions.py +0 -9
- wbportfolio/viewsets/signals.py +0 -43
- wbportfolio/viewsets/transactions/trade_proposals.py +0 -139
- wbportfolio/viewsets/transactions/transactions.py +0 -122
- /wbportfolio/{fdm → api_clients}/__init__.py +0 -0
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
from wbcore.metadata.configs.titles import TitleViewConfig
|
|
2
|
-
|
|
3
|
-
from wbportfolio.models import Portfolio
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class TransactionPortfolioTitleConfig(TitleViewConfig):
|
|
7
|
-
def get_list_title(self):
|
|
8
|
-
portfolio = Portfolio.objects.get(id=self.view.kwargs["portfolio_id"])
|
|
9
|
-
return f"Transactions for Product {str(portfolio)}"
|
wbportfolio/viewsets/signals.py
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
from django.apps import apps
|
|
2
|
-
from django.contrib.contenttypes.models import ContentType
|
|
3
|
-
from django.db.models import Q
|
|
4
|
-
from django.dispatch import receiver
|
|
5
|
-
from rest_framework.reverse import reverse
|
|
6
|
-
from wbcore.contrib.icons import WBIcon
|
|
7
|
-
from wbcore.metadata.configs import buttons as bt
|
|
8
|
-
from wbcore.signals.instance_buttons import add_instance_button
|
|
9
|
-
|
|
10
|
-
from wbportfolio.viewsets.products import ProductModelViewSet
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
@receiver(add_instance_button, sender=ProductModelViewSet)
|
|
14
|
-
def add_report_buttons(sender, many, *args, request=None, **kwargs):
|
|
15
|
-
report_buttons = []
|
|
16
|
-
try:
|
|
17
|
-
if instrument_id := kwargs.get("pk", None):
|
|
18
|
-
content_type_product = ContentType.objects.get(app_label="wbportfolio", model="product")
|
|
19
|
-
content_type_instrument = ContentType.objects.get(app_label="wbfdm", model="instrument")
|
|
20
|
-
Report = apps.get_model("wbreport", "Report")
|
|
21
|
-
for report in Report.objects.filter(object_id=instrument_id, is_active=True).filter(
|
|
22
|
-
Q(content_type=content_type_product) | Q(content_type=content_type_instrument)
|
|
23
|
-
):
|
|
24
|
-
if primary_version := report.primary_version:
|
|
25
|
-
report_buttons.append(
|
|
26
|
-
bt.HyperlinkButton(
|
|
27
|
-
label=f"{report.title} Report",
|
|
28
|
-
endpoint=reverse(
|
|
29
|
-
"public_report:report_version", args=[primary_version.lookup], request=request
|
|
30
|
-
),
|
|
31
|
-
),
|
|
32
|
-
)
|
|
33
|
-
if request.user.profile.is_internal or request.user.is_superuser:
|
|
34
|
-
report_buttons.append(
|
|
35
|
-
bt.HyperlinkButton(
|
|
36
|
-
label=f"{report.title} Widget",
|
|
37
|
-
endpoint=reverse("wbreport:report-detail", args=[report.id], request=request),
|
|
38
|
-
),
|
|
39
|
-
)
|
|
40
|
-
except LookupError:
|
|
41
|
-
pass
|
|
42
|
-
if report_buttons:
|
|
43
|
-
return bt.DropDownButton(label="Reports", buttons=tuple(report_buttons), icon=WBIcon.NOTEBOOK.icon)
|
|
@@ -1,139 +0,0 @@
|
|
|
1
|
-
from contextlib import suppress
|
|
2
|
-
from datetime import date
|
|
3
|
-
|
|
4
|
-
from django.contrib.messages import info, warning
|
|
5
|
-
from django.shortcuts import get_object_or_404
|
|
6
|
-
from django.utils.functional import cached_property
|
|
7
|
-
from pandas._libs.tslibs.offsets import BDay
|
|
8
|
-
from rest_framework import status
|
|
9
|
-
from rest_framework.decorators import action
|
|
10
|
-
from rest_framework.response import Response
|
|
11
|
-
from wbcompliance.viewsets.risk_management.mixins import RiskCheckViewSetMixin
|
|
12
|
-
from wbcore import serializers as wb_serializers
|
|
13
|
-
from wbcore import viewsets
|
|
14
|
-
from wbcore.metadata.configs.display.instance_display import (
|
|
15
|
-
Display,
|
|
16
|
-
create_simple_display,
|
|
17
|
-
)
|
|
18
|
-
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
19
|
-
from wbcore.utils.views import CloneMixin
|
|
20
|
-
|
|
21
|
-
from wbportfolio.models import AssetPosition, TradeProposal
|
|
22
|
-
from wbportfolio.models.transactions.trade_proposals import (
|
|
23
|
-
replay_as_task,
|
|
24
|
-
)
|
|
25
|
-
from wbportfolio.serializers import (
|
|
26
|
-
ReadOnlyTradeProposalModelSerializer,
|
|
27
|
-
TradeProposalModelSerializer,
|
|
28
|
-
TradeProposalRepresentationSerializer,
|
|
29
|
-
)
|
|
30
|
-
|
|
31
|
-
from ..configs import (
|
|
32
|
-
TradeProposalButtonConfig,
|
|
33
|
-
TradeProposalDisplayConfig,
|
|
34
|
-
TradeProposalEndpointConfig,
|
|
35
|
-
TradeProposalPortfolioEndpointConfig,
|
|
36
|
-
)
|
|
37
|
-
from ..mixins import UserPortfolioRequestPermissionMixin
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
class TradeProposalRepresentationViewSet(InternalUserPermissionMixin, viewsets.RepresentationViewSet):
|
|
41
|
-
IDENTIFIER = "wbportfolio:trade"
|
|
42
|
-
queryset = TradeProposal.objects.all()
|
|
43
|
-
serializer_class = TradeProposalRepresentationSerializer
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
class TradeProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserPermissionMixin, viewsets.ModelViewSet):
|
|
47
|
-
ordering_fields = ("trade_date",)
|
|
48
|
-
ordering = ("-trade_date",)
|
|
49
|
-
search_fields = ("comment",)
|
|
50
|
-
filterset_fields = {"trade_date": ["exact", "gte", "lte"], "status": ["exact"]}
|
|
51
|
-
|
|
52
|
-
queryset = TradeProposal.objects.select_related("rebalancing_model", "portfolio")
|
|
53
|
-
serializer_class = TradeProposalModelSerializer
|
|
54
|
-
display_config_class = TradeProposalDisplayConfig
|
|
55
|
-
button_config_class = TradeProposalButtonConfig
|
|
56
|
-
endpoint_config_class = TradeProposalEndpointConfig
|
|
57
|
-
|
|
58
|
-
def get_serializer_class(self):
|
|
59
|
-
if self.new_mode or (
|
|
60
|
-
"pk" in self.kwargs and (obj := self.get_object()) and obj.status == TradeProposal.Status.DRAFT
|
|
61
|
-
):
|
|
62
|
-
return TradeProposalModelSerializer
|
|
63
|
-
return ReadOnlyTradeProposalModelSerializer
|
|
64
|
-
|
|
65
|
-
# 2 methods to parametrize the clone button functionality
|
|
66
|
-
def get_clone_button_serializer_class(self, instance):
|
|
67
|
-
class CloneSerializer(wb_serializers.Serializer):
|
|
68
|
-
clone_date = wb_serializers.DateField(
|
|
69
|
-
default=(instance.trade_date + BDay(1)).date(), label="Trade Date"
|
|
70
|
-
) # we need to change the field name from the trade proposa fields, otherwise fontend conflicts
|
|
71
|
-
clone_comment = wb_serializers.TextField(label="Comment")
|
|
72
|
-
|
|
73
|
-
return CloneSerializer
|
|
74
|
-
|
|
75
|
-
def get_clone_button_instance_display(self) -> Display:
|
|
76
|
-
return create_simple_display(
|
|
77
|
-
[
|
|
78
|
-
["clone_comment"],
|
|
79
|
-
["clone_date"],
|
|
80
|
-
]
|
|
81
|
-
)
|
|
82
|
-
|
|
83
|
-
def add_messages(self, request, instance=None, **kwargs):
|
|
84
|
-
if instance and instance.status == TradeProposal.Status.SUBMIT:
|
|
85
|
-
if not instance.portfolio.is_manageable:
|
|
86
|
-
info(request, "This trade proposal cannot be approved the portfolio is considered unmanaged.")
|
|
87
|
-
if instance.has_non_successful_checks:
|
|
88
|
-
warning(
|
|
89
|
-
request,
|
|
90
|
-
"This trade proposal cannot be approved because there is unsuccessful pre-trade checks. Please rectify accordingly and resubmit a valid trade proposal",
|
|
91
|
-
)
|
|
92
|
-
|
|
93
|
-
@classmethod
|
|
94
|
-
def _get_risk_checks_button_title(cls) -> str:
|
|
95
|
-
return "Pre-Trade Checks"
|
|
96
|
-
|
|
97
|
-
@action(detail=True, methods=["PATCH"])
|
|
98
|
-
def reset(self, request, pk=None):
|
|
99
|
-
trade_proposal = get_object_or_404(TradeProposal, pk=pk)
|
|
100
|
-
if trade_proposal.status == TradeProposal.Status.DRAFT:
|
|
101
|
-
trade_proposal.reset_trades()
|
|
102
|
-
return Response({"send": True})
|
|
103
|
-
return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
|
|
104
|
-
|
|
105
|
-
@action(detail=True, methods=["PATCH"])
|
|
106
|
-
def normalize(self, request, pk=None):
|
|
107
|
-
trade_proposal = get_object_or_404(TradeProposal, pk=pk)
|
|
108
|
-
if trade_proposal.status == TradeProposal.Status.DRAFT:
|
|
109
|
-
trade_proposal.normalize_trades()
|
|
110
|
-
return Response({"send": True})
|
|
111
|
-
return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
|
|
112
|
-
|
|
113
|
-
@action(detail=True, methods=["PATCH"])
|
|
114
|
-
def replay(self, request, pk=None):
|
|
115
|
-
trade_proposal = get_object_or_404(TradeProposal, pk=pk)
|
|
116
|
-
if trade_proposal.portfolio.is_manageable:
|
|
117
|
-
replay_as_task.delay(trade_proposal.id, user_id=self.request.user.id)
|
|
118
|
-
return Response({"send": True})
|
|
119
|
-
return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
|
|
120
|
-
|
|
121
|
-
@action(detail=True, methods=["PATCH"])
|
|
122
|
-
def deleteall(self, request, pk=None):
|
|
123
|
-
trade_proposal = get_object_or_404(TradeProposal, pk=pk)
|
|
124
|
-
if trade_proposal.status == TradeProposal.Status.DRAFT:
|
|
125
|
-
trade_proposal.trades.all().delete()
|
|
126
|
-
return Response({"send": True})
|
|
127
|
-
return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
class TradeProposalPortfolioModelViewSet(UserPortfolioRequestPermissionMixin, TradeProposalModelViewSet):
|
|
131
|
-
endpoint_config_class = TradeProposalPortfolioEndpointConfig
|
|
132
|
-
|
|
133
|
-
@cached_property
|
|
134
|
-
def default_trade_date(self) -> date | None:
|
|
135
|
-
with suppress(AssetPosition.DoesNotExist):
|
|
136
|
-
return (self.portfolio.assets.latest("date").date + BDay(1)).date()
|
|
137
|
-
|
|
138
|
-
def get_queryset(self):
|
|
139
|
-
return TradeProposal.objects.filter(portfolio=self.kwargs["portfolio_id"])
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
from decimal import Decimal
|
|
2
|
-
|
|
3
|
-
from django.db.models import (
|
|
4
|
-
Case,
|
|
5
|
-
DecimalField,
|
|
6
|
-
ExpressionWrapper,
|
|
7
|
-
F,
|
|
8
|
-
OuterRef,
|
|
9
|
-
Subquery,
|
|
10
|
-
Sum,
|
|
11
|
-
When,
|
|
12
|
-
)
|
|
13
|
-
from wbcore import viewsets
|
|
14
|
-
from wbcore.contrib.currency.models import CurrencyFXRates
|
|
15
|
-
from wbcore.permissions.permissions import InternalUserPermissionMixin
|
|
16
|
-
from wbcore.utils.strings import format_number
|
|
17
|
-
|
|
18
|
-
from wbportfolio.filters import TransactionFilterSet, TransactionPortfolioFilterSet
|
|
19
|
-
from wbportfolio.models import Fees, Trade, Transaction
|
|
20
|
-
from wbportfolio.serializers import (
|
|
21
|
-
TransactionModelSerializer,
|
|
22
|
-
TransactionRepresentationSerializer,
|
|
23
|
-
)
|
|
24
|
-
|
|
25
|
-
from ..configs import (
|
|
26
|
-
TransactionDisplayConfig,
|
|
27
|
-
TransactionEndpointConfig,
|
|
28
|
-
TransactionPortfolioDisplayConfig,
|
|
29
|
-
TransactionPortfolioEndpointConfig,
|
|
30
|
-
TransactionPortfolioTitleConfig,
|
|
31
|
-
)
|
|
32
|
-
from ..mixins import UserPortfolioRequestPermissionMixin
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
class TransactionRepresentationViewSet(InternalUserPermissionMixin, viewsets.RepresentationViewSet):
|
|
36
|
-
IDENTIFIER = "wbportfolio:transaction"
|
|
37
|
-
filterset_class = TransactionFilterSet
|
|
38
|
-
search_fields = ("portfolio__name", "underlying_instrument__name", "comment")
|
|
39
|
-
ordering_fields = (
|
|
40
|
-
"transaction_date",
|
|
41
|
-
"currency__key",
|
|
42
|
-
"underlying_instrument__name",
|
|
43
|
-
"portfolio__name",
|
|
44
|
-
"transaction_type",
|
|
45
|
-
"book_date",
|
|
46
|
-
"value_date",
|
|
47
|
-
"currency_fx_rate",
|
|
48
|
-
"total_value",
|
|
49
|
-
"total_value_fx_portfolio",
|
|
50
|
-
"total_value_gross",
|
|
51
|
-
"total_value_gross_fx_portfolio",
|
|
52
|
-
)
|
|
53
|
-
ordering = ["-transaction_date"]
|
|
54
|
-
|
|
55
|
-
serializer_class = TransactionRepresentationSerializer
|
|
56
|
-
queryset = Transaction.objects.all()
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
class TransactionModelViewSet(UserPortfolioRequestPermissionMixin, InternalUserPermissionMixin, viewsets.ModelViewSet):
|
|
60
|
-
IDENTIFIER = "wbportfolio:transaction"
|
|
61
|
-
|
|
62
|
-
serializer_class = TransactionModelSerializer
|
|
63
|
-
|
|
64
|
-
filterset_class = TransactionFilterSet
|
|
65
|
-
ordering_fields = TransactionRepresentationViewSet.ordering_fields
|
|
66
|
-
search_fields = TransactionRepresentationViewSet.search_fields
|
|
67
|
-
ordering = TransactionRepresentationViewSet.ordering
|
|
68
|
-
|
|
69
|
-
queryset = Transaction.objects.all()
|
|
70
|
-
display_config_class = TransactionDisplayConfig
|
|
71
|
-
endpoint_config_class = TransactionEndpointConfig
|
|
72
|
-
|
|
73
|
-
def get_queryset(self):
|
|
74
|
-
return (
|
|
75
|
-
super()
|
|
76
|
-
.get_queryset()
|
|
77
|
-
.annotate(
|
|
78
|
-
fx_rate=CurrencyFXRates.get_fx_rates_subquery(
|
|
79
|
-
"transaction_date", currency="currency", lookup_expr="exact"
|
|
80
|
-
),
|
|
81
|
-
total_value_usd=ExpressionWrapper(F("total_value"), output_field=DecimalField()),
|
|
82
|
-
total_value_gross_usd=ExpressionWrapper(F("total_value_gross"), output_field=DecimalField()),
|
|
83
|
-
transaction_underlying_type_trade=Subquery(
|
|
84
|
-
Trade.objects.filter(id=OuterRef("pk")).values("transaction_subtype")[:1]
|
|
85
|
-
),
|
|
86
|
-
transaction_underlying_type_fees=Subquery(
|
|
87
|
-
Fees.objects.filter(id=OuterRef("pk")).values("transaction_subtype")[:1]
|
|
88
|
-
),
|
|
89
|
-
transaction_underlying_type=Case(
|
|
90
|
-
When(
|
|
91
|
-
transaction_underlying_type_trade__isnull=False,
|
|
92
|
-
then=F("transaction_underlying_type_trade"),
|
|
93
|
-
),
|
|
94
|
-
When(transaction_underlying_type_fees__isnull=False, then=F("transaction_underlying_type_fees")),
|
|
95
|
-
),
|
|
96
|
-
)
|
|
97
|
-
.select_related("underlying_instrument")
|
|
98
|
-
.select_related("portfolio")
|
|
99
|
-
.select_related("currency")
|
|
100
|
-
)
|
|
101
|
-
|
|
102
|
-
def get_aggregates(self, queryset, paginated_queryset):
|
|
103
|
-
return {
|
|
104
|
-
"total_value_usd": {
|
|
105
|
-
"Σ": format_number(queryset.aggregate(s=Sum("total_value_usd"))["s"] or Decimal(0)),
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
class TransactionPortfolioModelViewSet(TransactionModelViewSet):
|
|
111
|
-
IDENTIFIER = "wbportfolio:transaction"
|
|
112
|
-
|
|
113
|
-
filterset_class = TransactionPortfolioFilterSet
|
|
114
|
-
display_config_class = TransactionPortfolioDisplayConfig
|
|
115
|
-
endpoint_config_class = TransactionPortfolioEndpointConfig
|
|
116
|
-
title_config_class = TransactionPortfolioTitleConfig
|
|
117
|
-
|
|
118
|
-
def get_queryset(self):
|
|
119
|
-
qs = super().get_queryset().filter(portfolio=self.portfolio)
|
|
120
|
-
if self.is_portfolio_manager:
|
|
121
|
-
return qs
|
|
122
|
-
return qs.exclude(transaction_type=Transaction.Type.FEES)
|
|
File without changes
|
|
File without changes
|