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.

Files changed (273) hide show
  1. wbportfolio/admin/__init__.py +3 -1
  2. wbportfolio/admin/indexes.py +1 -1
  3. wbportfolio/admin/orders/__init__.py +2 -0
  4. wbportfolio/admin/orders/order_proposals.py +16 -0
  5. wbportfolio/admin/orders/orders.py +32 -0
  6. wbportfolio/admin/portfolio.py +11 -5
  7. wbportfolio/admin/product_groups.py +1 -1
  8. wbportfolio/admin/products.py +2 -1
  9. wbportfolio/admin/{transactions/rebalancing.py → rebalancing.py} +1 -1
  10. wbportfolio/admin/transactions/__init__.py +0 -2
  11. wbportfolio/admin/transactions/dividends.py +40 -4
  12. wbportfolio/admin/transactions/fees.py +24 -14
  13. wbportfolio/admin/transactions/trades.py +34 -27
  14. wbportfolio/analysis/claims.py +5 -6
  15. wbportfolio/api_clients/ubs.py +162 -0
  16. wbportfolio/constants.py +1 -0
  17. wbportfolio/contrib/company_portfolio/configs/display.py +22 -10
  18. wbportfolio/contrib/company_portfolio/configs/previews.py +3 -3
  19. wbportfolio/contrib/company_portfolio/filters.py +10 -10
  20. wbportfolio/contrib/company_portfolio/models.py +69 -39
  21. wbportfolio/contrib/company_portfolio/scripts.py +7 -2
  22. wbportfolio/contrib/company_portfolio/serializers.py +32 -22
  23. wbportfolio/contrib/company_portfolio/tasks.py +12 -1
  24. wbportfolio/contrib/company_portfolio/tests/conftest.py +2 -2
  25. wbportfolio/defaults/fees/default.py +7 -15
  26. wbportfolio/factories/__init__.py +2 -2
  27. wbportfolio/factories/assets.py +1 -1
  28. wbportfolio/factories/dividends.py +8 -3
  29. wbportfolio/factories/fees.py +8 -4
  30. wbportfolio/factories/orders/__init__.py +2 -0
  31. wbportfolio/factories/orders/order_proposals.py +21 -0
  32. wbportfolio/factories/orders/orders.py +34 -0
  33. wbportfolio/factories/portfolios.py +2 -1
  34. wbportfolio/factories/product_groups.py +3 -3
  35. wbportfolio/factories/products.py +3 -3
  36. wbportfolio/factories/rebalancing.py +1 -1
  37. wbportfolio/factories/trades.py +12 -16
  38. wbportfolio/filters/assets.py +18 -4
  39. wbportfolio/filters/orders/__init__.py +2 -0
  40. wbportfolio/filters/orders/order_proposals.py +55 -0
  41. wbportfolio/filters/orders/orders.py +11 -0
  42. wbportfolio/filters/portfolios.py +38 -1
  43. wbportfolio/filters/positions.py +0 -1
  44. wbportfolio/filters/transactions/__init__.py +1 -2
  45. wbportfolio/filters/transactions/fees.py +5 -12
  46. wbportfolio/filters/transactions/trades.py +16 -8
  47. wbportfolio/filters/transactions/utils.py +42 -0
  48. wbportfolio/import_export/backends/ubs/__init__.py +1 -0
  49. wbportfolio/import_export/backends/ubs/asset_position.py +6 -7
  50. wbportfolio/import_export/backends/ubs/fees.py +10 -20
  51. wbportfolio/import_export/backends/ubs/instrument_price.py +6 -6
  52. wbportfolio/import_export/backends/ubs/trade.py +48 -0
  53. wbportfolio/import_export/backends/utils.py +0 -17
  54. wbportfolio/import_export/handlers/asset_position.py +22 -10
  55. wbportfolio/import_export/handlers/dividend.py +8 -8
  56. wbportfolio/import_export/handlers/fees.py +13 -23
  57. wbportfolio/import_export/handlers/orders.py +71 -0
  58. wbportfolio/import_export/handlers/trade.py +53 -77
  59. wbportfolio/import_export/parsers/default_mapping.py +1 -1
  60. wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +2 -2
  61. wbportfolio/import_export/parsers/jpmorgan/fees.py +4 -4
  62. wbportfolio/import_export/parsers/jpmorgan/strategy.py +59 -85
  63. wbportfolio/import_export/parsers/jpmorgan/valuation.py +2 -2
  64. wbportfolio/import_export/parsers/leonteq/customer_trade.py +5 -5
  65. wbportfolio/import_export/parsers/leonteq/fees.py +11 -7
  66. wbportfolio/import_export/parsers/leonteq/trade.py +2 -6
  67. wbportfolio/import_export/parsers/natixis/d1_fees.py +2 -2
  68. wbportfolio/import_export/parsers/natixis/dividend.py +4 -9
  69. wbportfolio/import_export/parsers/natixis/equity.py +22 -4
  70. wbportfolio/import_export/parsers/natixis/fees.py +7 -9
  71. wbportfolio/import_export/parsers/natixis/utils.py +13 -19
  72. wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +1 -1
  73. wbportfolio/import_export/parsers/sg_lux/equity.py +10 -10
  74. wbportfolio/import_export/parsers/sg_lux/fees.py +2 -2
  75. wbportfolio/import_export/parsers/sg_lux/perf_fees.py +2 -2
  76. wbportfolio/import_export/parsers/sg_lux/sylk.py +12 -11
  77. wbportfolio/import_export/parsers/sg_lux/utils.py +2 -2
  78. wbportfolio/import_export/parsers/sg_lux/valuation.py +4 -2
  79. wbportfolio/import_export/parsers/societe_generale/strategy.py +5 -5
  80. wbportfolio/import_export/parsers/tellco/customer_trade.py +2 -1
  81. wbportfolio/import_export/parsers/tellco/valuation.py +4 -3
  82. wbportfolio/import_export/parsers/ubs/api/fees.py +2 -2
  83. wbportfolio/import_export/parsers/ubs/api/trade.py +39 -0
  84. wbportfolio/import_export/parsers/ubs/customer_trade.py +7 -5
  85. wbportfolio/import_export/parsers/ubs/equity.py +3 -2
  86. wbportfolio/import_export/parsers/ubs/valuation.py +2 -1
  87. wbportfolio/import_export/parsers/vontobel/customer_trade.py +2 -3
  88. wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -1
  89. wbportfolio/import_export/parsers/vontobel/management_fees.py +12 -20
  90. wbportfolio/import_export/parsers/vontobel/performance_fees.py +5 -8
  91. wbportfolio/import_export/parsers/vontobel/valuation_api.py +4 -1
  92. wbportfolio/import_export/resources/trades.py +3 -3
  93. wbportfolio/import_export/utils.py +3 -1
  94. wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +2 -2
  95. wbportfolio/metric/backends/base.py +2 -2
  96. wbportfolio/migrations/0059_fees_unique_fees.py +1 -1
  97. wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +622 -0
  98. wbportfolio/migrations/0078_trade_drift_factor.py +26 -0
  99. wbportfolio/migrations/0079_alter_trade_drift_factor.py +19 -0
  100. wbportfolio/migrations/0080_alter_trade_drift_factor_alter_trade_weighting.py +19 -0
  101. wbportfolio/migrations/0081_alter_trade_drift_factor.py +19 -0
  102. wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py +93 -0
  103. wbportfolio/migrations/0083_order_alter_trade_options_and_more.py +181 -0
  104. wbportfolio/migrations/0084_orderproposal_min_order_value.py +25 -0
  105. wbportfolio/migrations/0085_order_desired_target_weight.py +26 -0
  106. wbportfolio/migrations/0086_orderproposal_total_cash_weight.py +19 -0
  107. wbportfolio/migrations/0087_product_order_routing_custodian_adapter.py +94 -0
  108. wbportfolio/migrations/0088_orderproposal_total_effective_portfolio_contribution.py +19 -0
  109. wbportfolio/migrations/0089_orderproposal_min_weighting.py +71 -0
  110. wbportfolio/migrations/0090_dividendtransaction_price_fx_portfolio_and_more.py +44 -0
  111. wbportfolio/migrations/0091_remove_order_execution_confirmed_and_more.py +32 -0
  112. wbportfolio/migrations/0092_order_quantization_error_alter_orderproposal_status.py +49 -0
  113. wbportfolio/migrations/0093_remove_portfolioportfoliothroughmodel_unique_primary_and_more.py +35 -0
  114. wbportfolio/models/__init__.py +2 -0
  115. wbportfolio/models/adjustments.py +1 -1
  116. wbportfolio/models/asset.py +28 -170
  117. wbportfolio/models/builder.py +323 -0
  118. wbportfolio/models/custodians.py +3 -3
  119. wbportfolio/models/exceptions.py +1 -1
  120. wbportfolio/models/graphs/portfolio.py +1 -1
  121. wbportfolio/models/graphs/utils.py +11 -11
  122. wbportfolio/models/mixins/instruments.py +7 -0
  123. wbportfolio/models/mixins/liquidity_stress_test.py +4 -4
  124. wbportfolio/models/orders/__init__.py +2 -0
  125. wbportfolio/models/orders/order_proposals.py +1414 -0
  126. wbportfolio/models/orders/orders.py +410 -0
  127. wbportfolio/models/portfolio.py +311 -289
  128. wbportfolio/models/portfolio_relationship.py +6 -0
  129. wbportfolio/models/products.py +12 -0
  130. wbportfolio/models/{transactions/rebalancing.py → rebalancing.py} +40 -27
  131. wbportfolio/models/roles.py +4 -10
  132. wbportfolio/models/transactions/__init__.py +0 -4
  133. wbportfolio/models/transactions/claim.py +7 -6
  134. wbportfolio/models/transactions/dividends.py +42 -5
  135. wbportfolio/models/transactions/fees.py +55 -22
  136. wbportfolio/models/transactions/trades.py +121 -442
  137. wbportfolio/models/transactions/transactions.py +78 -158
  138. wbportfolio/models/utils.py +100 -1
  139. wbportfolio/order_routing/__init__.py +35 -0
  140. wbportfolio/order_routing/adapters/__init__.py +65 -0
  141. wbportfolio/order_routing/adapters/ubs.py +195 -0
  142. wbportfolio/order_routing/router.py +33 -0
  143. wbportfolio/order_routing/tests/__init__.py +0 -0
  144. wbportfolio/order_routing/tests/test_router.py +110 -0
  145. wbportfolio/permissions.py +7 -0
  146. wbportfolio/pms/analytics/portfolio.py +17 -9
  147. wbportfolio/pms/analytics/utils.py +9 -0
  148. wbportfolio/pms/trading/__init__.py +0 -1
  149. wbportfolio/pms/trading/optimizer.py +61 -0
  150. wbportfolio/pms/typing.py +198 -63
  151. wbportfolio/rebalancing/base.py +12 -1
  152. wbportfolio/rebalancing/decorators.py +1 -1
  153. wbportfolio/rebalancing/models/composite.py +4 -8
  154. wbportfolio/rebalancing/models/equally_weighted.py +13 -11
  155. wbportfolio/rebalancing/models/market_capitalization_weighted.py +21 -14
  156. wbportfolio/rebalancing/models/model_portfolio.py +14 -18
  157. wbportfolio/risk_management/backends/__init__.py +1 -0
  158. wbportfolio/risk_management/backends/controversy_portfolio.py +2 -2
  159. wbportfolio/risk_management/backends/esg_aggregation_portfolio.py +64 -0
  160. wbportfolio/risk_management/backends/exposure_portfolio.py +4 -4
  161. wbportfolio/risk_management/backends/instrument_list_portfolio.py +3 -3
  162. wbportfolio/risk_management/tests/test_esg_aggregation_portfolio.py +49 -0
  163. wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -1
  164. wbportfolio/risk_management/tests/test_stop_loss_instrument.py +2 -2
  165. wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -1
  166. wbportfolio/serializers/__init__.py +1 -0
  167. wbportfolio/serializers/orders/__init__.py +2 -0
  168. wbportfolio/serializers/orders/order_proposals.py +115 -0
  169. wbportfolio/serializers/orders/orders.py +283 -0
  170. wbportfolio/serializers/portfolios.py +7 -7
  171. wbportfolio/serializers/positions.py +2 -2
  172. wbportfolio/serializers/rebalancing.py +1 -1
  173. wbportfolio/serializers/signals.py +9 -12
  174. wbportfolio/serializers/transactions/__init__.py +1 -10
  175. wbportfolio/serializers/transactions/claim.py +2 -2
  176. wbportfolio/serializers/transactions/dividends.py +37 -9
  177. wbportfolio/serializers/transactions/fees.py +39 -10
  178. wbportfolio/serializers/transactions/trades.py +55 -157
  179. wbportfolio/tasks.py +43 -5
  180. wbportfolio/tests/analysis/__init__.py +0 -0
  181. wbportfolio/tests/analysis/test_claims.py +85 -0
  182. wbportfolio/tests/conftest.py +12 -12
  183. wbportfolio/tests/models/orders/__init__.py +0 -0
  184. wbportfolio/tests/models/orders/test_order_proposals.py +1046 -0
  185. wbportfolio/tests/models/test_assets.py +7 -3
  186. wbportfolio/tests/models/test_imports.py +9 -13
  187. wbportfolio/tests/models/test_portfolios.py +102 -95
  188. wbportfolio/tests/models/test_products.py +11 -0
  189. wbportfolio/tests/models/test_splits.py +1 -6
  190. wbportfolio/tests/models/test_utils.py +140 -0
  191. wbportfolio/tests/models/transactions/test_fees.py +7 -13
  192. wbportfolio/tests/models/transactions/test_rebalancing.py +5 -5
  193. wbportfolio/tests/models/transactions/test_trades.py +0 -20
  194. wbportfolio/tests/pms/test_analytics.py +22 -3
  195. wbportfolio/tests/rebalancing/test_models.py +51 -57
  196. wbportfolio/tests/signals.py +10 -20
  197. wbportfolio/tests/tests.py +3 -1
  198. wbportfolio/tests/viewsets/test_products.py +1 -0
  199. wbportfolio/urls.py +10 -13
  200. wbportfolio/viewsets/__init__.py +9 -4
  201. wbportfolio/viewsets/assets.py +3 -204
  202. wbportfolio/viewsets/charts/__init__.py +6 -1
  203. wbportfolio/viewsets/charts/assets.py +344 -154
  204. wbportfolio/viewsets/configs/buttons/__init__.py +2 -2
  205. wbportfolio/viewsets/configs/buttons/assets.py +1 -1
  206. wbportfolio/viewsets/configs/buttons/mixins.py +4 -4
  207. wbportfolio/viewsets/configs/buttons/portfolios.py +45 -1
  208. wbportfolio/viewsets/configs/buttons/products.py +32 -2
  209. wbportfolio/viewsets/configs/display/__init__.py +2 -5
  210. wbportfolio/viewsets/configs/display/assets.py +6 -19
  211. wbportfolio/viewsets/configs/display/fees.py +3 -3
  212. wbportfolio/viewsets/configs/display/portfolios.py +5 -5
  213. wbportfolio/viewsets/configs/display/products.py +1 -1
  214. wbportfolio/viewsets/configs/display/rebalancing.py +2 -2
  215. wbportfolio/viewsets/configs/display/reconciliations.py +4 -4
  216. wbportfolio/viewsets/configs/display/trades.py +1 -189
  217. wbportfolio/viewsets/configs/endpoints/__init__.py +3 -7
  218. wbportfolio/viewsets/configs/endpoints/fees.py +2 -2
  219. wbportfolio/viewsets/configs/endpoints/trades.py +0 -41
  220. wbportfolio/viewsets/configs/menu/__init__.py +1 -1
  221. wbportfolio/viewsets/configs/menu/orders.py +11 -0
  222. wbportfolio/viewsets/configs/titles/__init__.py +2 -3
  223. wbportfolio/viewsets/configs/titles/fees.py +4 -8
  224. wbportfolio/viewsets/esg.py +3 -5
  225. wbportfolio/viewsets/mixins.py +5 -1
  226. wbportfolio/viewsets/orders/__init__.py +6 -0
  227. wbportfolio/viewsets/orders/configs/__init__.py +4 -0
  228. wbportfolio/viewsets/orders/configs/buttons/__init__.py +2 -0
  229. wbportfolio/viewsets/orders/configs/buttons/order_proposals.py +188 -0
  230. wbportfolio/viewsets/orders/configs/buttons/orders.py +113 -0
  231. wbportfolio/viewsets/orders/configs/displays/__init__.py +2 -0
  232. wbportfolio/viewsets/orders/configs/displays/order_proposals.py +157 -0
  233. wbportfolio/viewsets/orders/configs/displays/orders.py +232 -0
  234. wbportfolio/viewsets/orders/configs/endpoints/__init__.py +2 -0
  235. wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py +21 -0
  236. wbportfolio/viewsets/orders/configs/endpoints/orders.py +28 -0
  237. wbportfolio/viewsets/orders/configs/titles/__init__.py +0 -0
  238. wbportfolio/viewsets/orders/configs/titles/orders.py +0 -0
  239. wbportfolio/viewsets/orders/order_proposals.py +252 -0
  240. wbportfolio/viewsets/orders/orders.py +277 -0
  241. wbportfolio/viewsets/portfolios.py +36 -12
  242. wbportfolio/viewsets/positions.py +3 -2
  243. wbportfolio/viewsets/products.py +6 -6
  244. wbportfolio/viewsets/{transactions/rebalancing.py → rebalancing.py} +2 -2
  245. wbportfolio/viewsets/transactions/__init__.py +3 -14
  246. wbportfolio/viewsets/transactions/fees.py +22 -22
  247. wbportfolio/viewsets/transactions/trades.py +1 -180
  248. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/METADATA +3 -1
  249. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/RECORD +252 -203
  250. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/WHEEL +1 -1
  251. wbportfolio/admin/transactions/transactions.py +0 -38
  252. wbportfolio/factories/transactions.py +0 -22
  253. wbportfolio/fdm/tasks.py +0 -13
  254. wbportfolio/filters/transactions/transactions.py +0 -99
  255. wbportfolio/models/transactions/expiry.py +0 -7
  256. wbportfolio/models/transactions/trade_proposals.py +0 -704
  257. wbportfolio/pms/trading/handler.py +0 -161
  258. wbportfolio/serializers/transactions/expiry.py +0 -18
  259. wbportfolio/serializers/transactions/trade_proposals.py +0 -76
  260. wbportfolio/serializers/transactions/transactions.py +0 -85
  261. wbportfolio/tests/models/transactions/test_trade_proposals.py +0 -410
  262. wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -66
  263. wbportfolio/viewsets/configs/display/trade_proposals.py +0 -100
  264. wbportfolio/viewsets/configs/display/transactions.py +0 -55
  265. wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -18
  266. wbportfolio/viewsets/configs/endpoints/transactions.py +0 -14
  267. wbportfolio/viewsets/configs/menu/transactions.py +0 -9
  268. wbportfolio/viewsets/configs/titles/transactions.py +0 -9
  269. wbportfolio/viewsets/signals.py +0 -43
  270. wbportfolio/viewsets/transactions/trade_proposals.py +0 -139
  271. wbportfolio/viewsets/transactions/transactions.py +0 -122
  272. /wbportfolio/{fdm → api_clients}/__init__.py +0 -0
  273. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/licenses/LICENSE +0 -0
@@ -2,7 +2,6 @@ from decimal import Decimal
2
2
 
3
3
  import pandas as pd
4
4
  import plotly.graph_objects as go
5
- from django.contrib.messages import error, warning
6
5
  from django.db.models import (
7
6
  BooleanField,
8
7
  Case,
@@ -16,16 +15,12 @@ from django.db.models import (
16
15
  When,
17
16
  )
18
17
  from django.db.models.functions import Coalesce
19
- from django.shortcuts import get_object_or_404
20
- from django.utils.functional import cached_property
21
18
  from django_filters.rest_framework import DjangoFilterBackend
22
19
  from wbcore import viewsets
23
20
  from wbcore.contrib.currency.models import CurrencyFXRates
24
21
  from wbcore.permissions.permissions import InternalUserPermissionMixin
25
22
  from wbcore.utils.strings import format_number
26
- from wbcore.viewsets.mixins import OrderableMixin
27
23
  from wbcrm.models import Account
28
- from wbfdm.models import Cash
29
24
 
30
25
  from wbportfolio.filters import (
31
26
  SubscriptionRedemptionFilterSet,
@@ -34,15 +29,11 @@ from wbportfolio.filters import (
34
29
  TradeInstrumentFilterSet,
35
30
  TradePortfolioFilter,
36
31
  )
37
- from wbportfolio.import_export.resources.trades import TradeProposalTradeResource
38
- from wbportfolio.models import Trade, TradeProposal
32
+ from wbportfolio.models import Trade
39
33
  from wbportfolio.models.transactions.claim import Claim
40
34
  from wbportfolio.serializers import (
41
- ReadOnlyTradeTradeProposalModelSerializer,
42
35
  TradeModelSerializer,
43
- TradeProposalRepresentationSerializer,
44
36
  TradeRepresentationSerializer,
45
- TradeTradeProposalModelSerializer,
46
37
  )
47
38
  from wbportfolio.viewsets.configs.titles.trades import (
48
39
  CustomerDistributionInstrumentTitleConfig,
@@ -64,18 +55,10 @@ from ..configs import (
64
55
  TradePortfolioEndpointConfig,
65
56
  TradePortfolioTitleConfig,
66
57
  TradeTitleConfig,
67
- TradeTradeProposalDisplayConfig,
68
- TradeTradeProposalEndpointConfig,
69
58
  )
70
59
  from ..mixins import UserPortfolioRequestPermissionMixin
71
60
 
72
61
 
73
- class TradeProposalRepresentationViewSet(InternalUserPermissionMixin, viewsets.RepresentationViewSet):
74
- IDENTIFIER = "wbportfolio:trade"
75
- queryset = TradeProposal.objects.all()
76
- serializer_class = TradeProposalRepresentationSerializer
77
-
78
-
79
62
  class TradeRepresentationViewSet(InternalUserPermissionMixin, viewsets.RepresentationViewSet):
80
63
  filterset_class = TradeFilter
81
64
 
@@ -357,165 +340,3 @@ class CustomerDistributionInstrumentChartViewSet(UserPortfolioRequestPermissionM
357
340
  )
358
341
  .filter(account_name__isnull=False)
359
342
  )
360
-
361
-
362
- class TradeTradeProposalModelViewSet(
363
- UserPortfolioRequestPermissionMixin, InternalUserPermissionMixin, OrderableMixin, viewsets.ModelViewSet
364
- ):
365
- IMPORT_ALLOWED = True
366
- ordering = (
367
- "trade_proposal",
368
- "order",
369
- )
370
- ordering_fields = (
371
- "underlying_instrument__name",
372
- "underlying_instrument_isin",
373
- "underlying_instrument_ticker",
374
- "underlying_instrument_refinitiv_identifier_code",
375
- "underlying_instrument_instrument_type",
376
- "target_weight",
377
- "effective_weight",
378
- "effective_shares",
379
- "target_shares",
380
- "shares",
381
- "weighting",
382
- )
383
- IDENTIFIER = "wbportfolio:tradeproposal"
384
- search_fields = ("underlying_instrument__name",)
385
- filterset_fields = {"status": ["exact"]}
386
- queryset = Trade.objects.all()
387
-
388
- display_config_class = TradeTradeProposalDisplayConfig
389
- endpoint_config_class = TradeTradeProposalEndpointConfig
390
- serializer_class = TradeTradeProposalModelSerializer
391
-
392
- @cached_property
393
- def trade_proposal(self):
394
- return get_object_or_404(TradeProposal, pk=self.kwargs["trade_proposal_id"])
395
-
396
- def has_import_permission(self, request) -> bool: # allow import only on draft trade proposal
397
- return super().has_import_permission(request) and self.trade_proposal.status == TradeProposal.Status.DRAFT
398
-
399
- def get_import_resource_kwargs(self):
400
- resource_kwargs = super().get_import_resource_kwargs()
401
- resource_kwargs["columns_mapping"] = {"underlying_instrument": "underlying_instrument__isin"}
402
- return resource_kwargs
403
-
404
- def get_resource_class(self):
405
- return TradeProposalTradeResource
406
-
407
- def get_aggregates(self, queryset, *args, **kwargs):
408
- agg = {}
409
- if queryset.exists():
410
- cash_target_position = self.trade_proposal.get_estimated_target_cash(
411
- self.trade_proposal.portfolio.currency
412
- )
413
- cash_target_cash_weight, cash_target_cash_shares = (
414
- cash_target_position.weighting,
415
- cash_target_position.initial_shares,
416
- )
417
- extra_existing_cash_components = Cash.objects.filter(
418
- id__in=self.trade_proposal.trades.filter(underlying_instrument__is_cash=True).values(
419
- "underlying_instrument"
420
- )
421
- ).exclude(currency=self.trade_proposal.portfolio.currency)
422
-
423
- for cash_component in extra_existing_cash_components:
424
- extra_cash_position = self.trade_proposal.get_estimated_target_cash(cash_component.currency)
425
- cash_target_cash_weight += extra_cash_position.weighting
426
- cash_target_cash_shares += extra_cash_position.initial_shares
427
- noncash_aggregates = queryset.filter(underlying_instrument__is_cash=False).aggregate(
428
- sum_target_weight=Sum(F("target_weight")),
429
- sum_effective_weight=Sum(F("effective_weight")),
430
- sum_target_shares=Sum(F("target_shares")),
431
- sum_effective_shares=Sum(F("effective_shares")),
432
- )
433
- cash_aggregates = queryset.filter(underlying_instrument__is_cash=True).aggregate(
434
- sum_effective_weight=Sum(F("effective_weight")),
435
- sum_effective_shares=Sum(F("effective_shares")),
436
- )
437
- # weights aggregates
438
- cash_sum_effective_weight = cash_aggregates["sum_effective_weight"] or Decimal(0)
439
- noncash_sum_effective_weight = noncash_aggregates["sum_effective_weight"] or Decimal(0)
440
- noncash_sum_target_weight = noncash_aggregates["sum_target_weight"] or Decimal(0)
441
- sum_buy_weight = queryset.filter(weighting__gte=0).aggregate(s=Sum(F("weighting")))["s"] or Decimal(0)
442
- sum_sell_weight = queryset.filter(weighting__lt=0).aggregate(s=Sum(F("weighting")))["s"] or Decimal(0)
443
-
444
- # shares aggregates
445
- cash_sum_effective_shares = cash_aggregates["sum_effective_shares"] or Decimal(0)
446
- noncash_sum_effective_shares = noncash_aggregates["sum_effective_shares"] or Decimal(0)
447
- noncash_sum_target_shares = noncash_aggregates["sum_target_shares"] or Decimal(0)
448
- sum_buy_shares = queryset.filter(shares__gte=0).aggregate(s=Sum(F("shares")))["s"] or Decimal(0)
449
- sum_sell_shares = queryset.filter(shares__lt=0).aggregate(s=Sum(F("shares")))["s"] or Decimal(0)
450
-
451
- agg = {
452
- "effective_weight": {
453
- "Cash": format_number(cash_sum_effective_weight, decimal=6),
454
- "Non-Cash": format_number(noncash_sum_effective_weight, decimal=6),
455
- "Total": format_number(noncash_sum_effective_weight + cash_sum_effective_weight, decimal=6),
456
- },
457
- "target_weight": {
458
- "Cash": format_number(cash_target_cash_weight, decimal=6),
459
- "Non-Cash": format_number(noncash_sum_target_weight, decimal=6),
460
- "Total": format_number(cash_target_cash_weight + noncash_sum_target_weight, decimal=6),
461
- },
462
- "effective_shares": {
463
- "Cash": format_number(cash_sum_effective_shares, decimal=6),
464
- "Non-Cash": format_number(noncash_sum_effective_shares, decimal=6),
465
- "Total": format_number(cash_sum_effective_shares + noncash_sum_effective_shares, decimal=6),
466
- },
467
- "target_shares": {
468
- "Cash": format_number(cash_target_cash_shares, decimal=6),
469
- "Non-Cash": format_number(noncash_sum_target_shares, decimal=6),
470
- "Total": format_number(cash_target_cash_shares + noncash_sum_target_shares, decimal=6),
471
- },
472
- "weighting": {
473
- "Cash Flow": format_number(cash_sum_effective_weight - cash_target_cash_weight, decimal=6),
474
- "Buy": format_number(sum_buy_weight, decimal=6),
475
- "Sell": format_number(sum_sell_weight, decimal=6),
476
- },
477
- "shares": {
478
- "Cash Flow": format_number(cash_sum_effective_shares - cash_target_cash_shares, decimal=6),
479
- "Buy": format_number(sum_buy_shares, decimal=6),
480
- "Sell": format_number(sum_sell_shares, decimal=6),
481
- },
482
- }
483
-
484
- return agg
485
-
486
- def get_serializer_class(self):
487
- if self.trade_proposal.status != TradeProposal.Status.DRAFT:
488
- return ReadOnlyTradeTradeProposalModelSerializer
489
- return TradeTradeProposalModelSerializer
490
-
491
- def add_messages(self, request, queryset=None, paginated_queryset=None, instance=None, initial=False):
492
- if queryset is not None and queryset.exists() and self.trade_proposal.status != TradeProposal.Status.APPROVED:
493
- total_target_weight = queryset.aggregate(c=Sum(F("target_weight")))["c"] or Decimal(0)
494
- if round(total_target_weight, 3) != 1:
495
- warning(
496
- request,
497
- "The total target weight does not equal 1. To avoid automatic cash allocation, please adjust the trade weights to sum up to 1. Otherwise, a cash component will be added when this trade proposal is submitted.",
498
- )
499
- if queryset.filter(status=Trade.Status.FAILED):
500
- error(
501
- request,
502
- "Some trades failed preparation. To resolve this, please revert the trade proposal to draft, review and correct the trades, and then resubmit.",
503
- )
504
-
505
- def get_queryset(self):
506
- if self.is_portfolio_manager:
507
- qs = super().get_queryset().filter(trade_proposal=self.kwargs["trade_proposal_id"]).annotate_base_info()
508
- else:
509
- qs = TradeProposal.objects.none()
510
- return qs.annotate(
511
- underlying_instrument_isin=F("underlying_instrument__isin"),
512
- underlying_instrument_ticker=F("underlying_instrument__ticker"),
513
- underlying_instrument_refinitiv_identifier_code=F("underlying_instrument__refinitiv_identifier_code"),
514
- underlying_instrument_instrument_type=Case(
515
- When(
516
- underlying_instrument__parent__is_security=True,
517
- then=F("underlying_instrument__parent__instrument_type__short_name"),
518
- ),
519
- default=F("underlying_instrument__instrument_type__short_name"),
520
- ),
521
- )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.52.0
3
+ Version: 1.59.4
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -19,6 +19,8 @@ Requires-Dist: wbcompliance
19
19
  Requires-Dist: wbcore
20
20
  Requires-Dist: wbcrm
21
21
  Requires-Dist: wbfdm
22
+ Requires-Dist: wbmailing
22
23
  Requires-Dist: wbnews
24
+ Requires-Dist: wbreport
23
25
  Requires-Dist: xlrd==2.*
24
26
  Requires-Dist: xlsxwriter==3.*