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

@@ -854,7 +854,9 @@ class Portfolio(DeleteToDisableMixin, WBModel):
854
854
  not self.is_lookthrough and not is_target_portfolio_imported and self.is_active_at_date(from_date)
855
855
  ): # we cannot propagate a new portfolio for untracked, or look-through or already imported or inactive portfolios
856
856
  positions, _ = self.drift_weights(from_date, to_date)
857
- self.bulk_create_positions(positions, delete_leftovers=True, compute_metrics=True)
857
+ self.bulk_create_positions(
858
+ positions, delete_leftovers=True, compute_metrics=True, evaluate_rebalancer=False
859
+ )
858
860
 
859
861
  def get_lookthrough_positions(
860
862
  self,
@@ -260,9 +260,10 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
260
260
  last_effective_date, self.portfolio.currency, exact_lookup=True
261
261
  )
262
262
  # we cannot do a bulk-create because Trade is a multi table inheritance
263
+ weighting = round(trade_dto.delta_weight, 6)
263
264
  try:
264
265
  trade = self.trades.get(underlying_instrument=instrument)
265
- trade.weighting = trade_dto.delta_weight
266
+ trade.weighting = weighting
266
267
  trade.currency_fx_rate = currency_fx_rate
267
268
  trade.status = Trade.Status.DRAFT
268
269
  except Trade.DoesNotExist:
@@ -273,7 +274,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
273
274
  transaction_date=self.trade_date,
274
275
  trade_proposal=self,
275
276
  portfolio=self.portfolio,
276
- weighting=trade_dto.delta_weight,
277
+ weighting=weighting,
277
278
  status=Trade.Status.DRAFT,
278
279
  currency_fx_rate=currency_fx_rate,
279
280
  )
@@ -4,7 +4,9 @@ from decimal import Decimal
4
4
  from rest_framework import serializers
5
5
  from rest_framework.reverse import reverse
6
6
  from wbcore import serializers as wb_serializers
7
+ from wbfdm.models import Instrument
7
8
  from wbfdm.serializers import InvestableInstrumentRepresentationSerializer
9
+ from wbfdm.serializers.instruments.instruments import CompanyRepresentationSerializer, SecurityRepresentationSerializer
8
10
 
9
11
  from wbportfolio.models import PortfolioRole, Trade, TradeProposal
10
12
  from wbportfolio.models.transactions.claim import Claim
@@ -212,13 +214,62 @@ class TradeModelSerializer(TransactionModelSerializer):
212
214
  )
213
215
 
214
216
 
217
+ class GetSecurityDefault:
218
+ requires_context = True
219
+
220
+ def __call__(self, serializer_instance):
221
+ try:
222
+ instance = serializer_instance.view.get_object()
223
+ return instance.underlying_instrument.parent or instance.underlying_instrument
224
+ except Exception:
225
+ return None
226
+
227
+
228
+ class GetCompanyDefault:
229
+ requires_context = True
230
+
231
+ def __call__(self, serializer_instance):
232
+ try:
233
+ instance = serializer_instance.view.get_object()
234
+ security = instance.underlying_instrument.parent or instance.underlying_instrument
235
+ return security.parent or security
236
+ except Exception:
237
+ return None
238
+
239
+
215
240
  class TradeTradeProposalModelSerializer(TradeModelSerializer):
216
241
  underlying_instrument_isin = wb_serializers.CharField(read_only=True)
217
242
  underlying_instrument_ticker = wb_serializers.CharField(read_only=True)
218
243
  underlying_instrument_refinitiv_identifier_code = wb_serializers.CharField(read_only=True)
219
244
  underlying_instrument_instrument_type = wb_serializers.CharField(read_only=True)
245
+
246
+ company = wb_serializers.PrimaryKeyRelatedField(
247
+ queryset=Instrument.objects.filter(level=0),
248
+ required=False,
249
+ read_only=lambda view: not view.new_mode,
250
+ default=GetCompanyDefault(),
251
+ )
252
+ _company = CompanyRepresentationSerializer(source="company", required=False)
253
+
254
+ security = wb_serializers.PrimaryKeyRelatedField(
255
+ queryset=Instrument.objects.filter(is_security=True),
256
+ required=False,
257
+ read_only=lambda view: not view.new_mode,
258
+ default=GetSecurityDefault(),
259
+ )
260
+ _security = SecurityRepresentationSerializer(
261
+ source="security",
262
+ optional_get_parameters={"company": "parent"},
263
+ depends_on=[{"field": "company", "options": {}}],
264
+ required=False,
265
+ )
266
+ underlying_instrument = wb_serializers.PrimaryKeyRelatedField(
267
+ queryset=Instrument.objects.all(), label="Quote", read_only=lambda view: not view.new_mode
268
+ )
220
269
  _underlying_instrument = InvestableInstrumentRepresentationSerializer(
221
- source="underlying_instrument", label_key="name"
270
+ source="underlying_instrument",
271
+ optional_get_parameters={"security": "parent"},
272
+ depends_on=[{"field": "security", "options": {}}],
222
273
  )
223
274
 
224
275
  status = wb_serializers.ChoiceField(default=Trade.Status.DRAFT, choices=Trade.Status.choices)
@@ -228,6 +279,8 @@ class TradeTradeProposalModelSerializer(TradeModelSerializer):
228
279
  target_shares = wb_serializers.DecimalField(read_only=True, max_digits=16, decimal_places=6, default=0)
229
280
 
230
281
  def validate(self, data):
282
+ data.pop("company", None)
283
+ data.pop("security", None)
231
284
  if self.instance and "underlying_instrument" in data:
232
285
  raise serializers.ValidationError(
233
286
  {
@@ -235,13 +288,15 @@ class TradeTradeProposalModelSerializer(TradeModelSerializer):
235
288
  }
236
289
  )
237
290
  effective_weight = self.instance._effective_weight if self.instance else Decimal(0.0)
291
+ weighting = data.get("weighting", self.instance.weighting if self.instance else Decimal(0.0))
238
292
  if (target_weight := data.pop("target_weight", None)) is not None:
239
- data["weighting"] = target_weight - effective_weight
240
- if data["weighting"] >= 0:
293
+ weighting = target_weight - effective_weight
294
+ if weighting >= 0:
241
295
  data["transaction_subtype"] = "BUY"
242
296
  else:
243
297
  data["transaction_subtype"] = "SELL"
244
- return data
298
+ data["weighting"] = weighting
299
+ return super().validate(data)
245
300
 
246
301
  class Meta:
247
302
  model = Trade
@@ -262,6 +317,10 @@ class TradeTradeProposalModelSerializer(TradeModelSerializer):
262
317
  "underlying_instrument_ticker",
263
318
  "underlying_instrument_refinitiv_identifier_code",
264
319
  "underlying_instrument_instrument_type",
320
+ "company",
321
+ "_company",
322
+ "security",
323
+ "_security",
265
324
  "underlying_instrument",
266
325
  "_underlying_instrument",
267
326
  "transaction_subtype",
@@ -390,10 +390,13 @@ class TradeTradeProposalDisplayConfig(DisplayViewConfig):
390
390
  )
391
391
 
392
392
  def get_instance_display(self) -> Display:
393
- return create_simple_display(
394
- [
395
- ["underlying_instrument", "target_weight", "weighting"],
396
- ["effective_weight", "transaction_subtype", "shares"],
397
- [repeat_field(3, "comment")],
398
- ]
399
- )
393
+ trade_proposal = get_object_or_404(TradeProposal, pk=self.view.kwargs.get("trade_proposal_id", None))
394
+
395
+ fields = [
396
+ ["company", "security", "underlying_instrument"],
397
+ ["effective_weight", "target_weight", "weighting"],
398
+ ]
399
+ if not trade_proposal.portfolio.only_weighting:
400
+ fields.append(["effective_shares", "target_shares", "shares"])
401
+ fields.append([repeat_field(3, "comment")])
402
+ return create_simple_display(fields)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.50.1
3
+ Version: 1.50.3
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -249,7 +249,7 @@ wbportfolio/models/asset.py,sha256=wwAWW2vl21nJS7RVswjvB1PAZRjJ1VzCyLF4fb7R0Gw,4
249
249
  wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
250
250
  wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
251
251
  wbportfolio/models/indexes.py,sha256=iLYF2gzNzX4GLj_Nh3fybUcAQ1TslnT0wgQ6mN164QI,728
252
- wbportfolio/models/portfolio.py,sha256=Rq9ih9aPhLC1RukrIF_wrmtRQm0-3w4i9NEtWJGZ02g,55742
252
+ wbportfolio/models/portfolio.py,sha256=l7YsGpei9a4yhTBPZsWk0W9YNO3WoC1EoraQFzSa79Q,55799
253
253
  wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
254
254
  wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
255
255
  wbportfolio/models/portfolio_relationship.py,sha256=mMb18UMRWg9kx_9uIPkMktwORuXXLjKdgRPQQvB6fVE,5486
@@ -276,7 +276,7 @@ wbportfolio/models/transactions/dividends.py,sha256=92-jG8bZN9nU9oDubpu-UDH43Ri7
276
276
  wbportfolio/models/transactions/expiry.py,sha256=vnNHdcC1hf2HP4rAbmoGgOfagBYKNFytqOwzOI0MlVI,144
277
277
  wbportfolio/models/transactions/fees.py,sha256=ffvqo8I4A0l5rLi00jJ6sGot0jmnkoxaNsbDzdPLwCg,5712
278
278
  wbportfolio/models/transactions/rebalancing.py,sha256=obzgewWKOD4kJbCoF5fhtfDk502QkbrjPKh8T9KDGew,7355
279
- wbportfolio/models/transactions/trade_proposals.py,sha256=qUuCftA7iPLprSVSM7Opkf4hgWxhE-WivRkVWIaFzBw,30541
279
+ wbportfolio/models/transactions/trade_proposals.py,sha256=ppSiF8y8mzK2BREETVODTJ8iBhHwuUso_5Meculmb_o,30576
280
280
  wbportfolio/models/transactions/trades.py,sha256=4qA0cEff_hcV3kMnmJKXr0wSThpKhhm0HbzHbspBuxw,28919
281
281
  wbportfolio/models/transactions/transactions.py,sha256=fWoDf0TSV0L0gLUDOQpCRLzjMt1H4MUvUHGEaMsilCc,7027
282
282
  wbportfolio/pms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -343,7 +343,7 @@ wbportfolio/serializers/transactions/dividends.py,sha256=EULwKDumHBv4r2HsdEGZMZG
343
343
  wbportfolio/serializers/transactions/expiry.py,sha256=K3XOSbCyef-xRzOjCr4Qg_YFJ_JuuiJ9u6tDS86l0hg,477
344
344
  wbportfolio/serializers/transactions/fees.py,sha256=uPmSWuCeoV2bwVS6RmEz3a0VRBWJHIQr0WhklYc1UAI,1068
345
345
  wbportfolio/serializers/transactions/trade_proposals.py,sha256=fiGpL6za5ERLtdbud5wrciCVXHX6-3SjeF8Zaa6Zhzg,3410
346
- wbportfolio/serializers/transactions/trades.py,sha256=nqldVcwcWFQaBVZE46VWo_hJ3mSPrDJ3ZaihpmvVXZE,10755
346
+ wbportfolio/serializers/transactions/trades.py,sha256=OCm33pxy-d3YeEue3lIdEXt1utpx8ZLks4Am4XcP708,12932
347
347
  wbportfolio/serializers/transactions/transactions.py,sha256=O137zeCndK-nxIWSRLEj7bXbBZDGa4d6qK6pJIIYK3g,4170
348
348
  wbportfolio/static/wbportfolio/css/macro_review.css,sha256=FAVVO8nModxwPXcTKpcfzVxBGPZGJVK1Xn-0dkSfGyc,233
349
349
  wbportfolio/static/wbportfolio/markdown/documentation/account_holding_reconciliation.md,sha256=MabxOvOne8s5gl6osDoow6-3ghaXLAYg9THWpvy6G5I,921
@@ -454,7 +454,7 @@ wbportfolio/viewsets/configs/display/reconciliations.py,sha256=YvMAuwmpX0HExvGsu
454
454
  wbportfolio/viewsets/configs/display/registers.py,sha256=1np75exIk5rfct6UkVN_RnfJ9ozvIkcWJgFV4_4rJns,3182
455
455
  wbportfolio/viewsets/configs/display/roles.py,sha256=SFUyCdxSlHZ3NsMrJmpVBSlg-XKGaEFteV89nyLMMAQ,1815
456
456
  wbportfolio/viewsets/configs/display/trade_proposals.py,sha256=sRLSUjKlarBhnTwg7tX_Juldor3beswJlyvZfFPvNEk,4315
457
- wbportfolio/viewsets/configs/display/trades.py,sha256=3rvIYMCe3IOyDw5HTrXcPvstdDg6Zt13oskh1yKQyRY,16613
457
+ wbportfolio/viewsets/configs/display/trades.py,sha256=tn7kpkzwd5AwzPznsIlRlQjjCoK1qVlTt4gtw6VHPpg,16841
458
458
  wbportfolio/viewsets/configs/display/transactions.py,sha256=DOM3eV1DxBwX6Iiw3C2sJamWh6A_3ZSYC9447Jc3Wmo,2586
459
459
  wbportfolio/viewsets/configs/endpoints/__init__.py,sha256=E13AYY3CIW4CZtmqwBVMPDYA5zNyKJeRZtiXKtad68Y,2871
460
460
  wbportfolio/viewsets/configs/endpoints/adjustments.py,sha256=9CcnfNuFcxsZ8YvfUitSeyCvpLxY-jU-gIw3GG0mIp4,697
@@ -521,7 +521,7 @@ wbportfolio/viewsets/transactions/rebalancing.py,sha256=6rIrdK0rtKL1afJ-tYfAGdQV
521
521
  wbportfolio/viewsets/transactions/trade_proposals.py,sha256=iQpC_Thbj56SmM05vPRsF1JZguGBDaTUH3I-_iCHCV0,5958
522
522
  wbportfolio/viewsets/transactions/trades.py,sha256=-yJ4j8NJTu2VWyhCq5BXGNND_925Ietoxx9k07SLVh0,21634
523
523
  wbportfolio/viewsets/transactions/transactions.py,sha256=ixDp-nsNA8t_A06rBCT19hOMJHy0iRmdz1XKdV1OwAs,4450
524
- wbportfolio-1.50.1.dist-info/METADATA,sha256=Yi-dunYxBzs9RvSKEaW9q4m6NkFz9WvbeNf9gWUSJfY,734
525
- wbportfolio-1.50.1.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
526
- wbportfolio-1.50.1.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
527
- wbportfolio-1.50.1.dist-info/RECORD,,
524
+ wbportfolio-1.50.3.dist-info/METADATA,sha256=9kA5ZvtgfVeY2HJ-IZ4aVZqUK9Heq7Zg4aLlImhOAXA,734
525
+ wbportfolio-1.50.3.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
526
+ wbportfolio-1.50.3.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
527
+ wbportfolio-1.50.3.dist-info/RECORD,,