wbportfolio 1.46.5__py2.py3-none-any.whl → 1.46.6__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.

@@ -144,7 +144,9 @@ class TradeImportHandler(ImportExportHandler):
144
144
 
145
145
  def _get_history(self, history: Dict[str, Any]) -> models.QuerySet:
146
146
  if trade_proposal_id := history.get("trade_proposal_id"):
147
- trades = self.model.objects.filter(trade_proposal_id=trade_proposal_id)
147
+ # if a trade proposal is provided, we delete the existing history first as otherwise, it would mess with the target weight computation
148
+ self.model.objects.filter(trade_proposal_id=trade_proposal_id).delete()
149
+ trades = self.model.objects.none()
148
150
  else:
149
151
  trades = self.model.objects.filter(
150
152
  exclude_from_history=False,
@@ -184,14 +184,21 @@ class TradeProposal(RiskCheckMixin, WBModel):
184
184
  service = TradingService(self.trade_date, trades_batch=self._build_dto())
185
185
  service.normalize()
186
186
  leftovers_trades = self.trades.all()
187
- for _, trade in service.trades_batch.trades_map.items():
187
+ total_target_weight = Decimal("0.0")
188
+ for underlying_instrument_id, trade_dto in service.trades_batch.trades_map.items():
188
189
  with suppress(Trade.DoesNotExist):
189
- trade = Trade.objects.get(id=trade.id)
190
- trade.weighting = trade.delta_weight
190
+ trade = self.trades.get(underlying_instrument_id=underlying_instrument_id)
191
+ trade.weighting = round(trade_dto.delta_weight, 6)
191
192
  trade.shares = self.estimate_shares(trade)
192
193
  trade.save()
194
+ total_target_weight += trade._target_weight
193
195
  leftovers_trades = leftovers_trades.exclude(id=trade.id)
194
196
  leftovers_trades.delete()
197
+ # we handle quantization error due to the decimal max digits. In that case, we take the biggest trade (highest weight) and we remove the quantization error
198
+ if quantize_error := (total_target_weight - Decimal("1.0")):
199
+ biggest_trade = self.trades.latest("weighting")
200
+ biggest_trade.weighting -= quantize_error
201
+ biggest_trade.save()
195
202
 
196
203
  def _get_target_portfolio(self, **kwargs) -> PortfolioDTO:
197
204
  if self.rebalancing_model:
@@ -406,7 +406,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
406
406
  except Product.DoesNotExist:
407
407
  return None
408
408
 
409
- @cached_property
409
+ @property
410
410
  @admin.display(description="Last Effective Date")
411
411
  def _last_effective_date(self) -> date:
412
412
  if hasattr(self, "last_effective_date"):
@@ -420,7 +420,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
420
420
  ).exists():
421
421
  return assets.latest("date").date
422
422
 
423
- @cached_property
423
+ @property
424
424
  @admin.display(description="Effective Weight")
425
425
  def _effective_weight(self) -> Decimal:
426
426
  return getattr(
@@ -434,7 +434,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
434
434
  or Decimal(0),
435
435
  )
436
436
 
437
- @cached_property
437
+ @property
438
438
  @admin.display(description="Effective Shares")
439
439
  def _effective_shares(self) -> Decimal:
440
440
  return getattr(
@@ -448,12 +448,12 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
448
448
  or Decimal(0),
449
449
  )
450
450
 
451
- @cached_property
451
+ @property
452
452
  @admin.display(description="Target Weight")
453
453
  def _target_weight(self) -> Decimal:
454
454
  return getattr(self, "target_weight", self._effective_weight + self.weighting)
455
455
 
456
- @cached_property
456
+ @property
457
457
  @admin.display(description="Target Shares")
458
458
  def _target_shares(self) -> Decimal:
459
459
  return getattr(self, "target_shares", self._effective_shares + self.shares)
@@ -483,6 +483,11 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
483
483
  ]
484
484
  # notification_email_template = "portfolio/email/trade_notification.html"
485
485
 
486
+ def __init__(self, *args, target_weight: Decimal | None = None, **kwargs):
487
+ super().__init__(*args, **kwargs)
488
+ if target_weight is not None: # if target weight is provided, we guess the corresponding weighting
489
+ self.weighting = Decimal(target_weight) - self._effective_weight
490
+
486
491
  def save(self, *args, **kwargs):
487
492
  if self.trade_proposal:
488
493
  self.portfolio = self.trade_proposal.portfolio
wbportfolio/pms/typing.py CHANGED
@@ -4,7 +4,6 @@ from decimal import Decimal
4
4
 
5
5
  import pandas as pd
6
6
  from django.core.exceptions import ValidationError
7
- from django.utils.functional import cached_property
8
7
 
9
8
 
10
9
  @dataclass(frozen=True)
@@ -60,11 +59,11 @@ class Portfolio:
60
59
  positions_map[pos.underlying_instrument] = pos
61
60
  object.__setattr__(self, "positions_map", positions_map)
62
61
 
63
- @cached_property
62
+ @property
64
63
  def total_weight(self):
65
64
  return round(sum([pos.weighting for pos in self.positions]), 6)
66
65
 
67
- @cached_property
66
+ @property
68
67
  def total_shares(self):
69
68
  return sum([pos.target_shares for pos in self.positions if pos.target_shares is not None])
70
69
 
@@ -108,7 +107,7 @@ class Trade:
108
107
  },
109
108
  )
110
109
 
111
- @cached_property
110
+ @property
112
111
  def delta_weight(self) -> Decimal:
113
112
  return self.target_weight - self.effective_weight
114
113
 
@@ -141,15 +140,15 @@ class TradeBatch:
141
140
  trade_map[trade.underlying_instrument] = trade
142
141
  object.__setattr__(self, "trades_map", trade_map)
143
142
 
144
- @cached_property
143
+ @property
145
144
  def total_target_weight(self) -> Decimal:
146
145
  return round(sum([trade.target_weight for trade in self.trades]), 6)
147
146
 
148
- @cached_property
147
+ @property
149
148
  def total_effective_weight(self) -> Decimal:
150
149
  return round(sum([trade.effective_weight for trade in self.trades]), 6)
151
150
 
152
- @cached_property
151
+ @property
153
152
  def totat_abs_delta_weight(self) -> Decimal:
154
153
  return sum([abs(trade.delta_weight) for trade in self.trades])
155
154
 
@@ -56,6 +56,8 @@ class TradeProposalModelSerializer(wb_serializers.ModelSerializer):
56
56
  res["replay"] = reverse("wbportfolio:tradeproposal-replay", args=[instance.id], request=request)
57
57
  if instance.status == TradeProposal.Status.DRAFT:
58
58
  res["reset"] = reverse("wbportfolio:tradeproposal-reset", args=[instance.id], request=request)
59
+ res["normalize"] = reverse("wbportfolio:tradeproposal-normalize", args=[instance.id], request=request)
60
+ res["deleteall"] = reverse("wbportfolio:tradeproposal-deleteall", args=[instance.id], request=request)
59
61
  res["trades"] = reverse(
60
62
  "wbportfolio:tradeproposal-trade-list",
61
63
  args=[instance.id],
@@ -546,7 +546,7 @@ class CompositionModelPortfolioPandasView(
546
546
  )
547
547
  )
548
548
  )
549
- df = pd.DataFrame(rows)
549
+ df = pd.DataFrame(rows, columns=["underlying_instrument", "weighting", "shares", "portfolio"])
550
550
  df = df.pivot_table(
551
551
  index="underlying_instrument",
552
552
  columns=["portfolio"],
@@ -16,8 +16,7 @@ from .registers import RegisterButtonConfig
16
16
  from .trades import (
17
17
  TradeButtonConfig,
18
18
  TradeInstrumentButtonConfig,
19
- TradeProposalButtonConfig,
20
- TradeTradeProposalButtonConfig,
21
19
  )
20
+ from .trade_proposals import TradeProposalButtonConfig
22
21
  from .reconciliations import AccountReconciliationButtonViewConfig, AccountReconciliationLineButtonViewConfig
23
22
  from .signals import *
@@ -7,18 +7,59 @@ from wbcore.metadata.configs.buttons.view_config import ButtonViewConfig
7
7
  class TradeProposalButtonConfig(ButtonViewConfig):
8
8
  def get_custom_list_instance_buttons(self):
9
9
  return {
10
- bt.ActionButton(
11
- method=RequestType.PATCH,
12
- identifiers=("wbportfolio:tradeproposal",),
13
- key="replay",
14
- icon=WBIcon.SYNCHRONIZE.icon,
15
- label="Replay Trades",
16
- description_fields="""
17
- <p>Replay Trades. It will recompute all assets positions until next trade proposal day (or today otherwise) </p>
18
- """,
19
- action_label="Replay Trade",
20
- title="Replay Trade",
21
- )
10
+ bt.DropDownButton(
11
+ label="Tools",
12
+ buttons=(
13
+ bt.ActionButton(
14
+ method=RequestType.PATCH,
15
+ identifiers=("wbportfolio:tradeproposal",),
16
+ key="replay",
17
+ icon=WBIcon.SYNCHRONIZE.icon,
18
+ label="Replay Trades",
19
+ description_fields="""
20
+ <p>Replay Trades. It will recompute all assets positions until next trade proposal day (or today otherwise) </p>
21
+ """,
22
+ action_label="Replay Trade",
23
+ title="Replay Trade",
24
+ ),
25
+ bt.ActionButton(
26
+ method=RequestType.PATCH,
27
+ identifiers=("wbportfolio:tradeproposal",),
28
+ key="reset",
29
+ icon=WBIcon.REGENERATE.icon,
30
+ label="Reset Trades",
31
+ description_fields="""
32
+ <p>Delete and recreate initial trades to from its associated model portfolio</p>
33
+ """,
34
+ action_label="Reset Trades",
35
+ title="Reset Trades",
36
+ ),
37
+ bt.ActionButton(
38
+ method=RequestType.PATCH,
39
+ identifiers=("wbportfolio:tradeproposal",),
40
+ key="normalize",
41
+ icon=WBIcon.EDIT.icon,
42
+ label="Normalize Trades",
43
+ description_fields="""
44
+ <p>Make sure all trades normalize to a total target weight of 100%</p>
45
+ """,
46
+ action_label="Normalize Trades",
47
+ title="Normalize Trades",
48
+ ),
49
+ bt.ActionButton(
50
+ method=RequestType.PATCH,
51
+ identifiers=("wbportfolio:tradeproposal",),
52
+ key="deleteall",
53
+ icon=WBIcon.DELETE.icon,
54
+ label="Delete All Trades",
55
+ description_fields="""
56
+ <p>Delete all trades from this trade proposal?</p>
57
+ """,
58
+ action_label="Delete All Trades",
59
+ title="Delete All Trades",
60
+ ),
61
+ ),
62
+ ),
22
63
  }
23
64
 
24
65
  def get_custom_instance_buttons(self):
@@ -1,12 +1,9 @@
1
1
  from rest_framework.reverse import reverse
2
2
  from wbcore.contrib.icons import WBIcon
3
- from wbcore.enums import RequestType
4
3
  from wbcore.metadata.configs import buttons as bt
5
4
  from wbcore.metadata.configs.buttons.view_config import ButtonViewConfig
6
5
  from wbfdm.models import Instrument
7
6
 
8
- from wbportfolio.models import TradeProposal
9
-
10
7
 
11
8
  class TradeButtonConfig(ButtonViewConfig):
12
9
  def get_custom_list_instance_buttons(self):
@@ -61,85 +58,3 @@ class TradeInstrumentButtonConfig(TradeButtonConfig):
61
58
  )
62
59
  )
63
60
  return res
64
-
65
-
66
- class TradeTradeProposalButtonConfig(ButtonViewConfig):
67
- def get_custom_buttons(self):
68
- if trade_proposal_id := self.view.kwargs.get("trade_proposal_id", None):
69
- trade_proposal = TradeProposal.objects.get(id=trade_proposal_id)
70
- if trade_proposal.status == TradeProposal.Status.DRAFT:
71
- return {
72
- bt.DropDownButton(
73
- label="Tools",
74
- buttons=(
75
- bt.ActionButton(
76
- method=RequestType.PATCH,
77
- identifiers=("wbportfolio:tradeproposal",),
78
- endpoint=reverse(
79
- "wbportfolio:tradeproposal-reset", args=[trade_proposal_id], request=self.request
80
- ),
81
- icon=WBIcon.REGENERATE.icon,
82
- label="Reset Trade",
83
- description_fields="""
84
- <p>Delete and recreate initial trades to from its associated model portfolio</p>
85
- """,
86
- action_label="Reset Trade",
87
- title="Reset Trade",
88
- ),
89
- bt.ActionButton(
90
- method=RequestType.PATCH,
91
- identifiers=("wbportfolio:tradeproposal",),
92
- endpoint=reverse(
93
- "wbportfolio:tradeproposal-normalize",
94
- args=[trade_proposal_id],
95
- request=self.request,
96
- ),
97
- icon=WBIcon.EDIT.icon,
98
- label="Normalize Trades",
99
- description_fields="""
100
- <p>Make sure all trades normalize to a total target weight of 100%</p>
101
- """,
102
- action_label="Normalize Trades",
103
- title="Normalize Trades",
104
- ),
105
- bt.ActionButton(
106
- method=RequestType.PATCH,
107
- identifiers=("wbportfolio:tradeproposal",),
108
- endpoint=reverse(
109
- "wbportfolio:tradeproposal-deleteall",
110
- args=[trade_proposal_id],
111
- request=self.request,
112
- ),
113
- icon=WBIcon.DELETE.icon,
114
- label="Delete All Trades",
115
- description_fields="""
116
- <p>Delete all trades from this trade proposal?</p>
117
- """,
118
- action_label="Delete All Trades",
119
- title="Delete All Trades",
120
- ),
121
- ),
122
- )
123
- }
124
- return {}
125
-
126
-
127
- class TradeProposalButtonConfig(ButtonViewConfig):
128
- def get_custom_list_instance_buttons(self):
129
- return {
130
- bt.ActionButton(
131
- method=RequestType.PATCH,
132
- identifiers=("wbportfolio:tradeproposal",),
133
- key="replay",
134
- icon=WBIcon.SYNCHRONIZE.icon,
135
- label="Replay Trades",
136
- description_fields="""
137
- <p>Replay Trades. It will recompute all assets positions until next trade proposal day (or today otherwise) </p>
138
- """,
139
- action_label="Replay Trade",
140
- title="Replay Trade",
141
- )
142
- }
143
-
144
- def get_custom_instance_buttons(self):
145
- return self.get_custom_list_instance_buttons()
@@ -4,6 +4,7 @@ from datetime import date
4
4
  from django.shortcuts import get_object_or_404
5
5
  from django.utils.functional import cached_property
6
6
  from pandas._libs.tslibs.offsets import BDay
7
+ from rest_framework import status
7
8
  from rest_framework.decorators import action
8
9
  from rest_framework.response import Response
9
10
  from wbcompliance.viewsets.risk_management.mixins import RiskCheckViewSetMixin
@@ -78,6 +79,7 @@ class TradeProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
78
79
  if trade_proposal.status == TradeProposal.Status.DRAFT:
79
80
  trade_proposal.reset_trades()
80
81
  return Response({"send": True})
82
+ return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
81
83
 
82
84
  @action(detail=True, methods=["PATCH"])
83
85
  def normalize(self, request, pk=None):
@@ -85,6 +87,7 @@ class TradeProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
85
87
  if trade_proposal.status == TradeProposal.Status.DRAFT:
86
88
  trade_proposal.normalize_trades()
87
89
  return Response({"send": True})
90
+ return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
88
91
 
89
92
  @action(detail=True, methods=["PATCH"])
90
93
  def replay(self, request, pk=None):
@@ -92,6 +95,7 @@ class TradeProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
92
95
  if trade_proposal.portfolio.is_manageable:
93
96
  replay_as_task.delay(trade_proposal.id)
94
97
  return Response({"send": True})
98
+ return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
95
99
 
96
100
  @action(detail=True, methods=["PATCH"])
97
101
  def deleteall(self, request, pk=None):
@@ -99,6 +103,7 @@ class TradeProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
99
103
  if trade_proposal.status == TradeProposal.Status.DRAFT:
100
104
  trade_proposal.trades.all().delete()
101
105
  return Response({"send": True})
106
+ return Response({"status": "Trade proposal is not Draft"}, status=status.HTTP_400_BAD_REQUEST)
102
107
 
103
108
 
104
109
  class TradeProposalPortfolioModelViewSet(UserPortfolioRequestPermissionMixin, TradeProposalModelViewSet):
@@ -63,7 +63,6 @@ from ..configs import (
63
63
  TradePortfolioEndpointConfig,
64
64
  TradePortfolioTitleConfig,
65
65
  TradeTitleConfig,
66
- TradeTradeProposalButtonConfig,
67
66
  TradeTradeProposalDisplayConfig,
68
67
  TradeTradeProposalEndpointConfig,
69
68
  )
@@ -376,7 +375,6 @@ class TradeTradeProposalModelViewSet(
376
375
  display_config_class = TradeTradeProposalDisplayConfig
377
376
  endpoint_config_class = TradeTradeProposalEndpointConfig
378
377
  serializer_class = TradeTradeProposalModelSerializer
379
- button_config_class = TradeTradeProposalButtonConfig
380
378
 
381
379
  @cached_property
382
380
  def trade_proposal(self):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.46.5
3
+ Version: 1.46.6
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -115,7 +115,7 @@ wbportfolio/import_export/handlers/dividend.py,sha256=tftdVdAzNpKSSvouOtvJfzWL36
115
115
  wbportfolio/import_export/handlers/fees.py,sha256=XYH752IkNGYhhhwatp8nYa1zG1-YZFDkYW15dyQgOIg,2824
116
116
  wbportfolio/import_export/handlers/portfolio_cash_flow.py,sha256=2ODaquuC83RfmNwmQ-8TdhiASObfIems_B1g0yqaYTs,2733
117
117
  wbportfolio/import_export/handlers/register.py,sha256=sYyXkE8b1DPZ5monxylZn0kjxLVdNYYZR-p61dwEoDM,2271
118
- wbportfolio/import_export/handlers/trade.py,sha256=Wvj7aFzc4UXYU5dZSxqBkA9hBozHiKzwGSmF6g2-Zss,10635
118
+ wbportfolio/import_export/handlers/trade.py,sha256=DArRPXWjH2YhqPGtbZw7Nyt3JjQNEltx1RyQ3-4FzKs,10829
119
119
  wbportfolio/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
120
120
  wbportfolio/import_export/parsers/default_mapping.py,sha256=KrO-X5CvQCeQoBYzFDxavoQGriyUSeI2QDx5ar_zo7A,1405
121
121
  wbportfolio/import_export/parsers/jpmorgan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -273,11 +273,11 @@ wbportfolio/models/transactions/dividends.py,sha256=naL5xeDQfUBf5KyGt7y-tTcHL22n
273
273
  wbportfolio/models/transactions/expiry.py,sha256=vnNHdcC1hf2HP4rAbmoGgOfagBYKNFytqOwzOI0MlVI,144
274
274
  wbportfolio/models/transactions/fees.py,sha256=ffvqo8I4A0l5rLi00jJ6sGot0jmnkoxaNsbDzdPLwCg,5712
275
275
  wbportfolio/models/transactions/rebalancing.py,sha256=vEYdYhog9jiPw_xQd_XQunNzcpHZ8Zk18kQhsN4HuhA,6596
276
- wbportfolio/models/transactions/trade_proposals.py,sha256=tpxg6EJ8Z6sB7VJ39GVLH-sBVJ9_ypUOqaUE0T5Rvhk,20804
277
- wbportfolio/models/transactions/trades.py,sha256=7IAC9eDx-ouKGn1RPR_Ggd5XjLgr3rE4xBn_ub0o1TE,27589
276
+ wbportfolio/models/transactions/trade_proposals.py,sha256=gsvgEI5yqmFb_bCN4FsgfyQqslMXLQlzTe3G7odwTCA,21366
277
+ wbportfolio/models/transactions/trades.py,sha256=gbXvxiyh8bvg6ldyd8qBwRPv4t0Tf5cbZXBnZXPIomc,27861
278
278
  wbportfolio/models/transactions/transactions.py,sha256=4THsE4xqdigZAwWKYfTNRLPJlkmAmsgE70Ribp9Lnrk,7127
279
279
  wbportfolio/pms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
280
- wbportfolio/pms/typing.py,sha256=lRWh9alcstZzwA04hFSPZfOFbCjaVPWtUpWnurnsh8c,6014
280
+ wbportfolio/pms/typing.py,sha256=WKP5tYyYt7DbMo25VM99V4IAM9oDSIPZyR3yXCzeZEA,5920
281
281
  wbportfolio/pms/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
282
282
  wbportfolio/pms/analytics/portfolio.py,sha256=93hcHEuBOPi534El2HVCIyjs9MBQMX7dIZ97JIpNV1c,1535
283
283
  wbportfolio/pms/statistics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -339,7 +339,7 @@ wbportfolio/serializers/transactions/claim.py,sha256=kC4E2RZRrpd9i8tGfoiV-gpWDk3
339
339
  wbportfolio/serializers/transactions/dividends.py,sha256=EULwKDumHBv4r2HsdEGZMZGFaye4dRUNNyXg6-wZXzc,520
340
340
  wbportfolio/serializers/transactions/expiry.py,sha256=K3XOSbCyef-xRzOjCr4Qg_YFJ_JuuiJ9u6tDS86l0hg,477
341
341
  wbportfolio/serializers/transactions/fees.py,sha256=uPmSWuCeoV2bwVS6RmEz3a0VRBWJHIQr0WhklYc1UAI,1068
342
- wbportfolio/serializers/transactions/trade_proposals.py,sha256=h8Ub69YPEhds1fC0dcbvXmSmpszor0WWxsodUeJmPVY,3414
342
+ wbportfolio/serializers/transactions/trade_proposals.py,sha256=2-GLD70swYlLVEIiWWTNcgN83EbPtLyFSO9wKBwjUm4,3644
343
343
  wbportfolio/serializers/transactions/trades.py,sha256=pONV5NSqrXUnoTEoAxovnnQqu37cZGuB33TYvIOK3rE,10009
344
344
  wbportfolio/serializers/transactions/transactions.py,sha256=O137zeCndK-nxIWSRLEj7bXbBZDGa4d6qK6pJIIYK3g,4170
345
345
  wbportfolio/static/wbportfolio/css/macro_review.css,sha256=FAVVO8nModxwPXcTKpcfzVxBGPZGJVK1Xn-0dkSfGyc,233
@@ -396,7 +396,7 @@ wbportfolio/tests/viewsets/transactions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5J
396
396
  wbportfolio/tests/viewsets/transactions/test_claims.py,sha256=QEZfMAW07dyoZ63t2umSwGOqvaTULfYfbN_F4ZoSAcw,6368
397
397
  wbportfolio/viewsets/__init__.py,sha256=3kUaQ66ybvROwejd3bEcSt4XKzfOlPDaeoStMvlz7qY,2294
398
398
  wbportfolio/viewsets/adjustments.py,sha256=5hWCjxSgUIsrPOmJKoDYK3gywdMTI0aYDorEj1FXRVc,1429
399
- wbportfolio/viewsets/assets.py,sha256=ac_hAyTiRLE_4FHCPvemgZaeEH10s7J2ZLfXykKDY1o,22663
399
+ wbportfolio/viewsets/assets.py,sha256=vwfrJaws7aVOUd-4FTlZVahpiMGgIEt1rcUumvWIKss,22734
400
400
  wbportfolio/viewsets/assets_and_net_new_money_progression.py,sha256=Jl4vEQP4N2OFL5IGBXoKcj-0qaPviU0I8npvQLw4Io0,4464
401
401
  wbportfolio/viewsets/custodians.py,sha256=CTFqkqVP1R3AV7lhdvcdICxB5DfwDYCyikNSI5kbYEo,2322
402
402
  wbportfolio/viewsets/esg.py,sha256=27MxxdXQH3Cq_1UEYmcrF7htUOg6i81fUpbVQXAAKJI,6985
@@ -417,7 +417,7 @@ wbportfolio/viewsets/signals.py,sha256=URxNz-7tKNBgvaFIE3FItfao3Md0dKQN_eVFwxxiE
417
417
  wbportfolio/viewsets/charts/__init__.py,sha256=mNSpDrsqK-afRxGBfEsfgupUc20xU-JW08FpxIyudok,71
418
418
  wbportfolio/viewsets/charts/assets.py,sha256=rZM4Ul0ZXVr7uz3SU44J5IYU7-FivjDgR1it_4ewk2o,10547
419
419
  wbportfolio/viewsets/configs/__init__.py,sha256=K5opfVQvgGwSyw3XwDGkv3lo5i9jBxOJXYhLqyCdfeQ,137
420
- wbportfolio/viewsets/configs/buttons/__init__.py,sha256=eqcRU3oH_iaQlCH_meJhG35-q6ZOGBGWPHNZ2ElsJb8,858
420
+ wbportfolio/viewsets/configs/buttons/__init__.py,sha256=99WAr_tftIXJbQPINkwy8xKI509d1zlatDeGu0zHMjU,846
421
421
  wbportfolio/viewsets/configs/buttons/adjustments.py,sha256=sUY_3vxqP0kuqs8i5hklfboZI6QiAOrmu30eb29Xupo,492
422
422
  wbportfolio/viewsets/configs/buttons/assets.py,sha256=6HqSyUpczK66iL0Jg8BbvAJuci3jm8OsB9p9Nt_o14Q,5680
423
423
  wbportfolio/viewsets/configs/buttons/claims.py,sha256=G1GFK1jQyR9M0dyXthYA6krG2JFvHhc3D7pFh6IUQ30,3684
@@ -429,8 +429,8 @@ wbportfolio/viewsets/configs/buttons/products.py,sha256=HfMQjpgGAgvTDLEFQRwbHE82
429
429
  wbportfolio/viewsets/configs/buttons/reconciliations.py,sha256=lw4r22GHpqKPUF1MrB6P9dOkL-FHe5iiBJ0--f8D74E,3145
430
430
  wbportfolio/viewsets/configs/buttons/registers.py,sha256=aS89TsYHql83k-NHojOrLDqtBpnpsUUO8x63PiMfrXM,445
431
431
  wbportfolio/viewsets/configs/buttons/signals.py,sha256=6sKBQI_eDvZuZR5bUUwvur5R67A3oChAGxPfayWUelE,2739
432
- wbportfolio/viewsets/configs/buttons/trade_proposals.py,sha256=6fOFeDQYp_vgc9-bEw5POMTg7-_MUiaUP2hQv5vMC9s,959
433
- wbportfolio/viewsets/configs/buttons/trades.py,sha256=bM-TKxFJ05zBRRRItx6b42pwTFRB8qlPoFwjOYIJK4M,6404
432
+ wbportfolio/viewsets/configs/buttons/trade_proposals.py,sha256=eZBfYk5ZhancCVcu7bvRKPGBKTl_tGlgz6BZrGPpPxQ,2953
433
+ wbportfolio/viewsets/configs/buttons/trades.py,sha256=X2B1l0iEIdHb3ZMf9rLVoiX_H8lSyLD12wopgumOIX4,2318
434
434
  wbportfolio/viewsets/configs/display/__init__.py,sha256=SmazY-YEp-Xf8G08Uz1-CzePZRCRtHrziRMIYYIGpCk,2176
435
435
  wbportfolio/viewsets/configs/display/adjustments.py,sha256=jIOEc23OCYBguLaZRlZxC916kocYT35ZV9Jsiocs9nk,3334
436
436
  wbportfolio/viewsets/configs/display/assets.py,sha256=8yLAXyrZLl7L1m1rhBnkh4uaqVpSQJhRVkcM7_AHBsc,10943
@@ -514,10 +514,10 @@ wbportfolio/viewsets/transactions/claim.py,sha256=m_Fy4J_QZSve1VlR_sPQrVBDopgCqq
514
514
  wbportfolio/viewsets/transactions/fees.py,sha256=7VUXIogmRrXCz_D9tvDiiTae0t5j09W9zPUzxXzBGTE,7031
515
515
  wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
516
516
  wbportfolio/viewsets/transactions/rebalancing.py,sha256=6rIrdK0rtKL1afJ-tYfAGdQVTN2MH1kG_yCeVkmyK8k,1263
517
- wbportfolio/viewsets/transactions/trade_proposals.py,sha256=fYTvvRk7k5xsBzbIgJvU4I4OrllF0VkhlrekD4GVgDk,4296
518
- wbportfolio/viewsets/transactions/trades.py,sha256=wdtEWN1V5wsmesR3mRxPmTJUIAmDmqaNsfIhOB57kqY,16330
517
+ wbportfolio/viewsets/transactions/trade_proposals.py,sha256=gXdJJ00D6UavZfBczvZQb5cYPQlU6-xOg_-TnMBzEO0,4742
518
+ wbportfolio/viewsets/transactions/trades.py,sha256=mo5b1wFm0twvGVp-CYnzpGLYMqPcHN8GjH4G_WwFFwc,16237
519
519
  wbportfolio/viewsets/transactions/transactions.py,sha256=ixDp-nsNA8t_A06rBCT19hOMJHy0iRmdz1XKdV1OwAs,4450
520
- wbportfolio-1.46.5.dist-info/METADATA,sha256=uhGKIh1jRNfdf699MnvWNcKT4X5XUDkk8e3NWtmf91o,734
521
- wbportfolio-1.46.5.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
522
- wbportfolio-1.46.5.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
523
- wbportfolio-1.46.5.dist-info/RECORD,,
520
+ wbportfolio-1.46.6.dist-info/METADATA,sha256=bPhihbH1kVhFD5f6_2c6whVYANHDhZ8zBnuNHJt6n1c,734
521
+ wbportfolio-1.46.6.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
522
+ wbportfolio-1.46.6.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
523
+ wbportfolio-1.46.6.dist-info/RECORD,,