wbportfolio 1.54.13__py2.py3-none-any.whl → 1.54.15__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 (86) hide show
  1. wbportfolio/admin/__init__.py +2 -0
  2. wbportfolio/admin/orders/__init__.py +2 -0
  3. wbportfolio/admin/orders/order_proposals.py +14 -0
  4. wbportfolio/admin/orders/orders.py +30 -0
  5. wbportfolio/admin/{transactions/rebalancing.py → rebalancing.py} +1 -1
  6. wbportfolio/admin/transactions/__init__.py +0 -1
  7. wbportfolio/admin/transactions/trades.py +2 -17
  8. wbportfolio/contrib/company_portfolio/tests/conftest.py +2 -2
  9. wbportfolio/factories/__init__.py +2 -1
  10. wbportfolio/factories/orders/__init__.py +2 -0
  11. wbportfolio/factories/orders/order_proposals.py +17 -0
  12. wbportfolio/factories/orders/orders.py +21 -0
  13. wbportfolio/factories/rebalancing.py +1 -1
  14. wbportfolio/factories/trades.py +2 -13
  15. wbportfolio/filters/orders/__init__.py +1 -0
  16. wbportfolio/filters/orders/orders.py +11 -0
  17. wbportfolio/import_export/handlers/trade.py +20 -20
  18. wbportfolio/import_export/resources/trades.py +2 -2
  19. wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py +93 -0
  20. wbportfolio/migrations/0083_order_alter_trade_options_and_more.py +181 -0
  21. wbportfolio/models/__init__.py +2 -0
  22. wbportfolio/models/orders/__init__.py +2 -0
  23. wbportfolio/models/{transactions/trade_proposals.py → orders/order_proposals.py} +289 -245
  24. wbportfolio/models/orders/orders.py +243 -0
  25. wbportfolio/models/portfolio.py +17 -20
  26. wbportfolio/models/{transactions/rebalancing.py → rebalancing.py} +18 -18
  27. wbportfolio/models/transactions/__init__.py +0 -2
  28. wbportfolio/models/transactions/trades.py +10 -450
  29. wbportfolio/pms/analytics/portfolio.py +10 -6
  30. wbportfolio/pms/analytics/utils.py +9 -0
  31. wbportfolio/pms/trading/handler.py +6 -4
  32. wbportfolio/pms/typing.py +18 -7
  33. wbportfolio/rebalancing/decorators.py +1 -1
  34. wbportfolio/rebalancing/models/composite.py +3 -7
  35. wbportfolio/rebalancing/models/market_capitalization_weighted.py +3 -1
  36. wbportfolio/serializers/__init__.py +1 -0
  37. wbportfolio/serializers/orders/__init__.py +2 -0
  38. wbportfolio/serializers/{transactions/trade_proposals.py → orders/order_proposals.py} +23 -15
  39. wbportfolio/serializers/orders/orders.py +187 -0
  40. wbportfolio/serializers/portfolios.py +7 -7
  41. wbportfolio/serializers/rebalancing.py +1 -1
  42. wbportfolio/serializers/transactions/__init__.py +1 -5
  43. wbportfolio/serializers/transactions/trades.py +1 -182
  44. wbportfolio/tests/conftest.py +4 -2
  45. wbportfolio/tests/models/orders/__init__.py +0 -0
  46. wbportfolio/tests/models/{transactions/test_trade_proposals.py → orders/test_order_proposals.py} +218 -246
  47. wbportfolio/tests/models/test_portfolios.py +11 -10
  48. wbportfolio/tests/models/transactions/test_rebalancing.py +5 -5
  49. wbportfolio/tests/models/transactions/test_trades.py +0 -20
  50. wbportfolio/tests/rebalancing/test_models.py +24 -28
  51. wbportfolio/tests/signals.py +10 -10
  52. wbportfolio/tests/tests.py +1 -1
  53. wbportfolio/urls.py +7 -7
  54. wbportfolio/viewsets/__init__.py +2 -0
  55. wbportfolio/viewsets/configs/buttons/__init__.py +2 -3
  56. wbportfolio/viewsets/configs/buttons/trades.py +0 -8
  57. wbportfolio/viewsets/configs/display/__init__.py +0 -2
  58. wbportfolio/viewsets/configs/display/portfolios.py +5 -5
  59. wbportfolio/viewsets/configs/display/rebalancing.py +2 -2
  60. wbportfolio/viewsets/configs/display/trades.py +1 -225
  61. wbportfolio/viewsets/configs/endpoints/__init__.py +0 -3
  62. wbportfolio/viewsets/configs/endpoints/trades.py +0 -41
  63. wbportfolio/viewsets/orders/__init__.py +6 -0
  64. wbportfolio/viewsets/orders/configs/__init__.py +4 -0
  65. wbportfolio/viewsets/orders/configs/buttons/__init__.py +2 -0
  66. wbportfolio/viewsets/{configs/buttons/trade_proposals.py → orders/configs/buttons/order_proposals.py} +22 -21
  67. wbportfolio/viewsets/orders/configs/buttons/orders.py +9 -0
  68. wbportfolio/viewsets/orders/configs/displays/__init__.py +2 -0
  69. wbportfolio/viewsets/{configs/display/trade_proposals.py → orders/configs/displays/order_proposals.py} +21 -21
  70. wbportfolio/viewsets/orders/configs/displays/orders.py +180 -0
  71. wbportfolio/viewsets/orders/configs/endpoints/__init__.py +2 -0
  72. wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py +21 -0
  73. wbportfolio/viewsets/orders/configs/endpoints/orders.py +26 -0
  74. wbportfolio/viewsets/orders/configs/titles/__init__.py +0 -0
  75. wbportfolio/viewsets/orders/configs/titles/orders.py +0 -0
  76. wbportfolio/viewsets/{transactions/trade_proposals.py → orders/order_proposals.py} +46 -45
  77. wbportfolio/viewsets/orders/orders.py +219 -0
  78. wbportfolio/viewsets/portfolios.py +12 -12
  79. wbportfolio/viewsets/{transactions/rebalancing.py → rebalancing.py} +2 -2
  80. wbportfolio/viewsets/transactions/__init__.py +1 -7
  81. wbportfolio/viewsets/transactions/trades.py +1 -199
  82. {wbportfolio-1.54.13.dist-info → wbportfolio-1.54.15.dist-info}/METADATA +1 -1
  83. {wbportfolio-1.54.13.dist-info → wbportfolio-1.54.15.dist-info}/RECORD +85 -58
  84. wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -18
  85. {wbportfolio-1.54.13.dist-info → wbportfolio-1.54.15.dist-info}/WHEEL +0 -0
  86. {wbportfolio-1.54.13.dist-info → wbportfolio-1.54.15.dist-info}/licenses/LICENSE +0 -0
@@ -1,20 +1,14 @@
1
1
  from datetime import timedelta
2
2
  from decimal import Decimal
3
3
 
4
- from rest_framework import serializers
5
4
  from rest_framework.reverse import reverse
6
5
  from wbcore import serializers as wb_serializers
7
6
  from wbcore.contrib.currency.serializers import CurrencyRepresentationSerializer
8
- from wbcore.metadata.configs.display.list_display import BaseTreeGroupLevelOption
9
- from wbfdm.models import Instrument
10
- from wbfdm.serializers import InvestableInstrumentRepresentationSerializer
11
7
  from wbfdm.serializers.instruments.instruments import (
12
- CompanyRepresentationSerializer,
13
8
  InvestableUniverseRepresentationSerializer,
14
- SecurityRepresentationSerializer,
15
9
  )
16
10
 
17
- from wbportfolio.models import PortfolioRole, Trade, TradeProposal
11
+ from wbportfolio.models import PortfolioRole, Trade
18
12
  from wbportfolio.models.transactions.claim import Claim
19
13
  from wbportfolio.serializers.custodians import CustodianRepresentationSerializer
20
14
  from wbportfolio.serializers.registers import RegisterRepresentationSerializer
@@ -41,14 +35,6 @@ class CopyClaimRepresentationSerializer(wb_serializers.RepresentationSerializer)
41
35
  )
42
36
 
43
37
 
44
- class TradeProposalRepresentationSerializer(wb_serializers.RepresentationSerializer):
45
- _detail = wb_serializers.HyperlinkField(reverse_name="wbportfolio:tradeproposal-detail")
46
-
47
- class Meta:
48
- model = TradeProposal
49
- fields = ("id", "trade_date", "status", "_detail")
50
-
51
-
52
38
  class TradeRepresentationSerializer(wb_serializers.RepresentationSerializer):
53
39
  _detail = wb_serializers.HyperlinkField(reverse_name="wbportfolio:trade-detail")
54
40
  diff_shares = wb_serializers.DecimalField(max_digits=15, decimal_places=4, read_only=True)
@@ -253,170 +239,3 @@ class TradeModelSerializer(wb_serializers.ModelSerializer):
253
239
  "_internal_trade",
254
240
  "_additional_resources",
255
241
  )
256
-
257
-
258
- class GetSecurityDefault:
259
- requires_context = True
260
-
261
- def __call__(self, serializer_instance):
262
- try:
263
- instance = serializer_instance.view.get_object()
264
- return instance.underlying_instrument.parent or instance.underlying_instrument
265
- except Exception:
266
- return None
267
-
268
-
269
- class GetCompanyDefault:
270
- requires_context = True
271
-
272
- def __call__(self, serializer_instance):
273
- try:
274
- instance = serializer_instance.view.get_object()
275
- security = instance.underlying_instrument.parent or instance.underlying_instrument
276
- return security.parent or security
277
- except Exception:
278
- return None
279
-
280
-
281
- class TradeTradeProposalModelSerializer(TradeModelSerializer):
282
- underlying_instrument_isin = wb_serializers.CharField(read_only=True)
283
- underlying_instrument_ticker = wb_serializers.CharField(read_only=True)
284
- underlying_instrument_refinitiv_identifier_code = wb_serializers.CharField(read_only=True)
285
- underlying_instrument_instrument_type = wb_serializers.CharField(read_only=True)
286
-
287
- company = wb_serializers.PrimaryKeyRelatedField(
288
- queryset=Instrument.objects.filter(level=0),
289
- required=False,
290
- read_only=lambda view: not view.new_mode,
291
- default=GetCompanyDefault(),
292
- )
293
- _company = CompanyRepresentationSerializer(source="company", required=False)
294
-
295
- security = wb_serializers.PrimaryKeyRelatedField(
296
- queryset=Instrument.objects.filter(is_security=True),
297
- required=False,
298
- read_only=lambda view: not view.new_mode,
299
- default=GetSecurityDefault(),
300
- )
301
- _security = SecurityRepresentationSerializer(
302
- source="security",
303
- optional_get_parameters={"company": "parent"},
304
- depends_on=[{"field": "company", "options": {}}],
305
- required=False,
306
- )
307
- underlying_instrument = wb_serializers.PrimaryKeyRelatedField(
308
- queryset=Instrument.objects.all(), label="Quote", read_only=lambda view: not view.new_mode
309
- )
310
- _underlying_instrument = InvestableInstrumentRepresentationSerializer(
311
- source="underlying_instrument",
312
- optional_get_parameters={"security": "parent"},
313
- depends_on=[{"field": "security", "options": {}}],
314
- tree_config=BaseTreeGroupLevelOption(clear_filter=True, filter_key="parent"),
315
- )
316
-
317
- status = wb_serializers.ChoiceField(default=Trade.Status.DRAFT, choices=Trade.Status.choices)
318
-
319
- target_weight = wb_serializers.DecimalField(
320
- max_digits=Trade.TRADE_WEIGHTING_PRECISION + 1,
321
- decimal_places=Trade.TRADE_WEIGHTING_PRECISION,
322
- required=False,
323
- default=0,
324
- )
325
- effective_weight = wb_serializers.DecimalField(
326
- read_only=True,
327
- max_digits=Trade.TRADE_WEIGHTING_PRECISION + 1,
328
- decimal_places=Trade.TRADE_WEIGHTING_PRECISION,
329
- default=0,
330
- )
331
-
332
- effective_shares = wb_serializers.DecimalField(read_only=True, max_digits=16, decimal_places=6, default=0)
333
- target_shares = wb_serializers.DecimalField(read_only=True, max_digits=16, decimal_places=6, default=0)
334
-
335
- total_value_fx_portfolio = wb_serializers.DecimalField(read_only=True, max_digits=16, decimal_places=2, default=0)
336
- effective_total_value_fx_portfolio = wb_serializers.DecimalField(
337
- read_only=True, max_digits=16, decimal_places=2, default=0
338
- )
339
- target_total_value_fx_portfolio = wb_serializers.DecimalField(
340
- read_only=True, max_digits=16, decimal_places=2, default=0
341
- )
342
-
343
- portfolio_currency = wb_serializers.CharField(read_only=True)
344
-
345
- def validate(self, data):
346
- data.pop("company", None)
347
- data.pop("security", None)
348
- if self.instance and "underlying_instrument" in data:
349
- raise serializers.ValidationError(
350
- {
351
- "underlying_instrument": "You cannot modify the underlying instrument other than creating a new entry"
352
- }
353
- )
354
- effective_weight = self.instance._effective_weight if self.instance else Decimal(0.0)
355
- weighting = data.get("weighting", self.instance.weighting if self.instance else Decimal(0.0))
356
- if (target_weight := data.pop("target_weight", None)) is not None:
357
- weighting = target_weight - effective_weight
358
- if (target_weight := data.pop("target_weight", None)) is not None:
359
- weighting = target_weight - effective_weight
360
- if weighting >= 0:
361
- data["transaction_subtype"] = "BUY"
362
- else:
363
- data["transaction_subtype"] = "SELL"
364
- data["weighting"] = weighting
365
- return super().validate(data)
366
-
367
- class Meta:
368
- model = Trade
369
- percent_fields = ["effective_weight", "target_weight", "weighting"]
370
- decorators = {
371
- "total_value_fx_portfolio": wb_serializers.decorator(
372
- decorator_type="text", position="left", value="{{portfolio_currency}}"
373
- ),
374
- "effective_total_value_fx_portfolio": wb_serializers.decorator(
375
- decorator_type="text", position="left", value="{{portfolio_currency}}"
376
- ),
377
- "target_total_value_fx_portfolio": wb_serializers.decorator(
378
- decorator_type="text", position="left", value="{{portfolio_currency}}"
379
- ),
380
- }
381
- read_only_fields = (
382
- "transaction_subtype",
383
- "shares",
384
- "effective_shares",
385
- "target_shares",
386
- "total_value_fx_portfolio",
387
- "effective_total_value_fx_portfolio",
388
- "target_total_value_fx_portfolio",
389
- )
390
- fields = (
391
- "id",
392
- "shares",
393
- "underlying_instrument_isin",
394
- "underlying_instrument_ticker",
395
- "underlying_instrument_refinitiv_identifier_code",
396
- "underlying_instrument_instrument_type",
397
- "company",
398
- "_company",
399
- "security",
400
- "_security",
401
- "underlying_instrument",
402
- "_underlying_instrument",
403
- "transaction_subtype",
404
- "status",
405
- "comment",
406
- "effective_weight",
407
- "target_weight",
408
- "weighting",
409
- "trade_proposal",
410
- "order",
411
- "effective_shares",
412
- "target_shares",
413
- "total_value_fx_portfolio",
414
- "effective_total_value_fx_portfolio",
415
- "target_total_value_fx_portfolio",
416
- "portfolio_currency",
417
- )
418
-
419
-
420
- class ReadOnlyTradeTradeProposalModelSerializer(TradeTradeProposalModelSerializer):
421
- class Meta(TradeTradeProposalModelSerializer.Meta):
422
- read_only_fields = TradeTradeProposalModelSerializer.Meta.fields
@@ -64,7 +64,8 @@ from wbportfolio.factories import (
64
64
  ProductGroupRepresentantFactory,
65
65
  ProductPortfolioRoleFactory,
66
66
  TradeFactory,
67
- TradeProposalFactory,
67
+ OrderFactory,
68
+ OrderProposalFactory,
68
69
  WhiteLabelProductFactory,
69
70
  RebalancerFactory,
70
71
  RebalancingModelFactory
@@ -92,7 +93,8 @@ register(ModelPortfolioFactory)
92
93
  register(ModelPortfolioWithBaseProductFactory, "model_portfolio_with_base_product")
93
94
  register(TradeFactory)
94
95
  register(CustomerTradeFactory)
95
- register(TradeProposalFactory)
96
+ register(OrderProposalFactory)
97
+ register(OrderFactory)
96
98
  register(DividendTransactionsFactory)
97
99
  register(FeesFactory)
98
100
  register(WhiteLabelProductFactory, "white_label_product")
File without changes