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

@@ -99,7 +99,7 @@ class TradeImportHandler(ImportExportHandler):
99
99
  if history.exists():
100
100
  queryset = history
101
101
  else:
102
- queryset = self.model.objects.filter(marked_for_deletion=False)
102
+ queryset = self.model.objects.filter(marked_for_deletion=False).exclude(id__in=self.processed_ids)
103
103
 
104
104
  queryset = queryset.filter(
105
105
  models.Q(underlying_instrument=data["underlying_instrument"]) & models.Q(**dates_lookup)
@@ -116,7 +116,6 @@ class TradeImportHandler(ImportExportHandler):
116
116
  if external_id_queryset.count() == 1:
117
117
  self.import_source.log += f"External ID {external_id} provided -> Load CustomerTrade"
118
118
  return external_id_queryset.first()
119
-
120
119
  if portfolio := data.get("portfolio", None):
121
120
  queryset = queryset.filter(portfolio=portfolio)
122
121
  if queryset.exists():
@@ -142,6 +141,7 @@ class TradeImportHandler(ImportExportHandler):
142
141
  if queryset.exists():
143
142
  # We try to filter by price as well
144
143
  trade = queryset.first()
144
+
145
145
  if queryset.count() == 1:
146
146
  self.import_source.log += f"\nOne Trade found: {trade}"
147
147
  if queryset.count() > 1:
@@ -3,15 +3,15 @@ from typing import Dict
3
3
 
4
4
  import numpy as np
5
5
  import pandas as pd
6
- from wbcore.contrib.io.models import ImportSource
6
+ from slugify import slugify
7
7
 
8
8
  from wbportfolio.models import Trade
9
9
 
10
10
 
11
- def parse_row(obj: Dict, import_source: ImportSource) -> Dict:
11
+ def parse_row(obj: Dict, negate_shares: bool = False) -> Dict:
12
12
  isin = obj["underlying_instrument__isin"]
13
13
  shares = obj["shares"]
14
- if import_source.source.import_parameters.get("negate_shares", False):
14
+ if negate_shares:
15
15
  shares = -1 * shares
16
16
  return {
17
17
  "underlying_instrument": {"isin": isin, "instrument_type": "product"},
@@ -30,6 +30,9 @@ def parse(import_source):
30
30
  xx, yy = np.where(df == "Trade Date")
31
31
  df = df.iloc[xx[0] :, yy[0] :]
32
32
  df = df.rename(columns=df.iloc[0]).drop(df.index[0]).dropna(how="all")
33
+ negate_shares = "net-quantity" in list(
34
+ map(lambda c: slugify(c), df.columns)
35
+ ) # we slugified the column to be more robust
33
36
  df = df.rename(columns=lambda x: x.lower())
34
37
  df = df.rename(
35
38
  columns={
@@ -50,6 +53,5 @@ def parse(import_source):
50
53
  df.loc[df["custodian"].isnull(), "custodian"] = "N/A"
51
54
  data = list()
52
55
  for d in df.to_dict("records"):
53
- data.append(parse_row(d, import_source))
54
-
56
+ data.append(parse_row(d, negate_shares=negate_shares))
55
57
  return {"data": data}
@@ -319,7 +319,9 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
319
319
 
320
320
  def prepare_orders_for_execution(self) -> list[OrderDTO]:
321
321
  executable_orders = []
322
- for order in self.get_orders().select_related("underlying_instrument"):
322
+ for order in (
323
+ self.get_orders().exclude(underlying_instrument__is_cash=True).select_related("underlying_instrument")
324
+ ):
323
325
  instrument = order.underlying_instrument
324
326
  # we support only the instrument type provided by the Order DTO class
325
327
  asset_class = instrument.get_security_ancestor().instrument_type.key.upper()
@@ -344,7 +346,7 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
344
346
  order.execution_confirmed = False
345
347
  order.execution_comment = "Underlying instrument does not have a valid identifier."
346
348
  order.save()
347
- except AttributeError:
349
+ except (AttributeError, KeyError):
348
350
  order.execution_confirmed = False
349
351
  order.execution_comment = f"Unsupported asset class {asset_class.title()}."
350
352
  order.save()
@@ -669,7 +669,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
669
669
  def fix_quantization(self, val_date: date):
670
670
  assets = self.assets.filter(date=val_date)
671
671
  total_weighting = assets.aggregate(s=Sum("weighting"))["s"]
672
- if quantization_error := Decimal("1") - total_weighting:
672
+ if total_weighting and (quantization_error := Decimal("1") - total_weighting):
673
673
  cash = self.cash_component
674
674
  try:
675
675
  cash_pos = assets.get(underlying_quote=cash)
@@ -31,16 +31,15 @@ class TestImportMixinModel:
31
31
 
32
32
  trade = trade_factory.build()
33
33
  data = {"data": [serialize(trade)]}
34
- handler = TradeImportHandler(import_source)
35
34
 
36
35
  # Import non existing data
37
- handler.process(data)
36
+ TradeImportHandler(import_source).process(data)
38
37
  assert Trade.objects.count() == 1
39
38
 
40
39
  # Import already existing data
41
40
  # import_source.data['data'][0]['shares'] *= 2
42
41
 
43
- handler.process(data)
42
+ TradeImportHandler(import_source).process(data)
44
43
  assert Trade.objects.count() == 1
45
44
 
46
45
  def test_import_price(self, import_source, product, instrument_price_factory, instrument):
@@ -87,14 +87,13 @@ class OrderProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
87
87
 
88
88
  def add_messages(self, request, instance: OrderProposal | None = None, **kwargs):
89
89
  if instance:
90
- if instance.status == OrderProposal.Status.PENDING:
91
- if not instance.portfolio.is_manageable:
92
- info(request, "This order proposal cannot be approved the portfolio is considered unmanaged.")
93
- if instance.has_non_successful_checks:
94
- warning(
95
- request,
96
- "This order proposal cannot be approved because there is unsuccessful pre-trade checks. Please rectify accordingly and resubmit a valid order proposal",
97
- )
90
+ if instance.status == OrderProposal.Status.APPROVED and not instance.portfolio.is_manageable:
91
+ info(request, "This order proposal cannot be approved the portfolio is considered unmanaged.")
92
+ if instance.status == OrderProposal.Status.PENDING and instance.has_non_successful_checks:
93
+ warning(
94
+ request,
95
+ "This order proposal cannot be approved because there is unsuccessful pre-trade checks. Please rectify accordingly and resubmit a valid order proposal",
96
+ )
98
97
  if (
99
98
  instance.execution_status in [ExecutionStatus.IN_DRAFT, ExecutionStatus.COMPLETED]
100
99
  and instance.orders.filter(execution_confirmed=False).exists()
@@ -1,6 +1,6 @@
1
1
  from decimal import Decimal
2
2
 
3
- from django.contrib.messages import error, warning
3
+ from django.contrib.messages import error, info
4
4
  from django.db.models import (
5
5
  Case,
6
6
  F,
@@ -184,7 +184,7 @@ class OrderOrderProposalModelViewSet(
184
184
  ]:
185
185
  total_target_weight = self.orders.aggregate(c=Sum(F("target_weight")))["c"] or Decimal(0)
186
186
  if round(total_target_weight, 8) != 1:
187
- warning(
187
+ info(
188
188
  request,
189
189
  "The total target weight does not equal 1. To avoid automatic cash allocation, please adjust the order weights to sum up to 1. Otherwise, a cash component will be added when this order proposal is submitted.",
190
190
  )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.55.0
3
+ Version: 1.55.2
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -126,7 +126,7 @@ wbportfolio/import_export/handlers/fees.py,sha256=BOFHAvSTlvVLaxnm6KD_fcza1TlPc0
126
126
  wbportfolio/import_export/handlers/orders.py,sha256=GU3_tIy-tAw9aU-ifsnmMZPBB9sqfkFC_S1d9VziTwg,3136
127
127
  wbportfolio/import_export/handlers/portfolio_cash_flow.py,sha256=W7QPNqEvvsq0RS016EAFBp1ezvc6G9Rk-hviRZh8o6Y,2737
128
128
  wbportfolio/import_export/handlers/register.py,sha256=sYyXkE8b1DPZ5monxylZn0kjxLVdNYYZR-p61dwEoDM,2271
129
- wbportfolio/import_export/handlers/trade.py,sha256=g2jAYYeuhZv_DuvM6zlROcq6rUlSbGaQ3tO4u6wkSRU,11140
129
+ wbportfolio/import_export/handlers/trade.py,sha256=xHg_4LMuMFRN49vEguIBDujM7vZxuhnEYMj95ZJ3s0E,11175
130
130
  wbportfolio/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
131
131
  wbportfolio/import_export/parsers/default_mapping.py,sha256=KrO-X5CvQCeQoBYzFDxavoQGriyUSeI2QDx5ar_zo7A,1405
132
132
  wbportfolio/import_export/parsers/jpmorgan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -179,7 +179,7 @@ wbportfolio/import_export/parsers/tellco/customer_trade.py,sha256=U04YVJHxQLWxpN
179
179
  wbportfolio/import_export/parsers/tellco/equity.py,sha256=3mPqh-kridsNCy5K4sa43SRsZIzNnRCr_3qGYlm356Q,3353
180
180
  wbportfolio/import_export/parsers/tellco/valuation.py,sha256=QM8fYYOESGocACSbJnqD-1TtSYxOXOkkT7oLY6XY10Y,1642
181
181
  wbportfolio/import_export/parsers/ubs/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
182
- wbportfolio/import_export/parsers/ubs/customer_trade.py,sha256=ZLWYLGO8BveXb5mTFfg53LgXXLGvztDgUaqIDa-qkJ0,2010
182
+ wbportfolio/import_export/parsers/ubs/customer_trade.py,sha256=PYXVZRBoI0B6NJGhHoTboBzfA-U16hrIDDdPu--RLNs,2089
183
183
  wbportfolio/import_export/parsers/ubs/equity.py,sha256=a3Hv6kjE__VUSdkE2TJ4NBCyVvnt34bPO-uZPR7pcEM,3471
184
184
  wbportfolio/import_export/parsers/ubs/historical_customer_trade.py,sha256=1IggU7Ogg8-gdwLqBtz-FZ6l-UKsjbtM-KomM8u6QpA,1746
185
185
  wbportfolio/import_export/parsers/ubs/valuation.py,sha256=6P71APM4xGoAadCywO6DBz42xL1bClacf242pb25w_s,1597
@@ -279,7 +279,7 @@ wbportfolio/models/builder.py,sha256=txZE_gEDgkPgSxSF0AlvZiRyhRQixD4Ame0wEF6Fjoo
279
279
  wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
280
280
  wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
281
281
  wbportfolio/models/indexes.py,sha256=gvW4K9U9Bj8BmVCqFYdWiXvDWhjHINRON8XhNsZUiQY,639
282
- wbportfolio/models/portfolio.py,sha256=Lrtxa-jItT9HCBQxfUClnXdaLPTf4CKZEXwAEmkhNtE,54618
282
+ wbportfolio/models/portfolio.py,sha256=fuYvHx4D3GqHjO0cBqe09M-t-t6jUzuOMh2ikTbykMo,54640
283
283
  wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
284
284
  wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
285
285
  wbportfolio/models/portfolio_relationship.py,sha256=ZGECiPZiLdlk4uSamOrEfuzO0hduK6OMKJLUSnh5_kc,5190
@@ -299,7 +299,7 @@ wbportfolio/models/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
299
299
  wbportfolio/models/mixins/instruments.py,sha256=SuMPquQ93D4pZMK-4hQbJtV58_NOyf3wVOctQq7LNXQ,7054
300
300
  wbportfolio/models/mixins/liquidity_stress_test.py,sha256=iQVzT3QM7VtHnqfj9gT6KUIe4wC4MJXery-AXJHUYns,58820
301
301
  wbportfolio/models/orders/__init__.py,sha256=EH9UacGR3npBMje5FGTeLOh1xqFBh9kc24WbGmBIA3g,69
302
- wbportfolio/models/orders/order_proposals.py,sha256=RYiQRo93RoXRy-QKl9shIGb4OfueiUT6we9uoQXokQk,57039
302
+ wbportfolio/models/orders/order_proposals.py,sha256=1ce97DXjzZ4MsUAgA_GlnofnztAf0Y6zR1etZs-LrFI,57120
303
303
  wbportfolio/models/orders/orders.py,sha256=kiVmVeW2D1bAuT983nSeIug6uoZ78IZovuAgls-CO8w,10150
304
304
  wbportfolio/models/orders/routing.py,sha256=OpeP-rfMm1UN7a3vbNxBEQxqtGfE57AeGWnbTZa1fRQ,2223
305
305
  wbportfolio/models/reconciliations/__init__.py,sha256=MXH5fZIPGDRBgJkO6wVu_NLRs8fkP1im7G6d-h36lQY,127
@@ -405,7 +405,7 @@ wbportfolio/tests/models/test_assets.py,sha256=N8OP2ZTPdq0lGonFRB0q_ruwF8QYpOGLk
405
405
  wbportfolio/tests/models/test_custodians.py,sha256=WnFA4R-deVL7DSKufGE0mcFUdU05otNfGvmG4psiIh4,340
406
406
  wbportfolio/tests/models/test_customer_trades.py,sha256=50By281j-nJ43jwRWK_KxNQGv6SuimT9e_ejgu6b19o,4942
407
407
  wbportfolio/tests/models/test_dividends.py,sha256=SVkIW3OqN4-9tq1HIvJm8_8rOyNTHbJKFiN075DeGGc,162
408
- wbportfolio/tests/models/test_imports.py,sha256=byqRJlnWqkkLdb8CkaX0cPGqfICOkuZ2_6tBk2YR3D0,7857
408
+ wbportfolio/tests/models/test_imports.py,sha256=GktsJAlFnNTwYVXxeWcYFx4-kSI3A-JvhmvFwJsh-sE,7857
409
409
  wbportfolio/tests/models/test_instrument_mixins.py,sha256=avX7a7Ovdzm_2v8JpSmrzqPo52qmIEa33c074D5KFCU,2206
410
410
  wbportfolio/tests/models/test_merge.py,sha256=sdsjiZsmR6vsUKwTa5kkvL6QTeAZqtd_EPWPI11FKGY,6497
411
411
  wbportfolio/tests/models/test_portfolio_cash_flow.py,sha256=X8dsXexsb1b0lBiuGzu40ps_Az_1UmmKT0eo1vbXH94,5792
@@ -546,8 +546,8 @@ wbportfolio/viewsets/configs/titles/registers.py,sha256=-C-YeGBhGva48oER6EIQ8CxW
546
546
  wbportfolio/viewsets/configs/titles/roles.py,sha256=9LoJa3jgenXJ5UWRlIErTzdbjpSWMKsyJZtv-eDRTK4,739
547
547
  wbportfolio/viewsets/configs/titles/trades.py,sha256=29XCLxvY0Xe3a2tjCno3tN2rRXCr9RWpbWnzurJfnYI,1986
548
548
  wbportfolio/viewsets/orders/__init__.py,sha256=N8v9jdEXryOzrLlc7ML3iBCO2lmNXph9_TWoQ7PTvi4,195
549
- wbportfolio/viewsets/orders/order_proposals.py,sha256=-VmvLEtL6-lhqT3WuyZlwnH1XFHpzuT9JBQclhRlNkY,8289
550
- wbportfolio/viewsets/orders/orders.py,sha256=ENFcW4feaazV1FupeI5UiE4W9wv0k8b57ypDB7gr1KA,10928
549
+ wbportfolio/viewsets/orders/order_proposals.py,sha256=IMiRh7kFqzmHjC34k-FjV21NSxkWVBi5NTEtUysN9qg,8302
550
+ wbportfolio/viewsets/orders/orders.py,sha256=bSJ8na5XO5HcmrDdLkD6gH1G6J90nLa3bOTe89IWoAI,10922
551
551
  wbportfolio/viewsets/orders/configs/__init__.py,sha256=5MU57JXiKi32_PicHtiNr7YHmMN020FrlF5NFJf_Wds,94
552
552
  wbportfolio/viewsets/orders/configs/buttons/__init__.py,sha256=EHzNmAfa0UQFITEF-wxj_s4wn3Y5DE3DCbEUmmvCTIs,106
553
553
  wbportfolio/viewsets/orders/configs/buttons/order_proposals.py,sha256=1BPkIYv0-K2DDGa4Gua2_Pxsx7fNurTZ2tYNdL66On0,6495
@@ -565,7 +565,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
565
565
  wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
566
566
  wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
567
567
  wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
568
- wbportfolio-1.55.0.dist-info/METADATA,sha256=s1b7Uq_ApxcCUFeHjg2DpMT-MGVZjDLzo_8TRrGPTao,751
569
- wbportfolio-1.55.0.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
570
- wbportfolio-1.55.0.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
571
- wbportfolio-1.55.0.dist-info/RECORD,,
568
+ wbportfolio-1.55.2.dist-info/METADATA,sha256=keGWSdz-FLt0PsvSwjvhtyKIfOxmS_OM53oSOX41_o8,751
569
+ wbportfolio-1.55.2.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
570
+ wbportfolio-1.55.2.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
571
+ wbportfolio-1.55.2.dist-info/RECORD,,