wbportfolio 1.56.1__py2.py3-none-any.whl → 1.56.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.
- wbportfolio/admin/orders/order_proposals.py +2 -0
- wbportfolio/admin/orders/orders.py +2 -0
- wbportfolio/models/orders/order_proposals.py +5 -7
- wbportfolio/models/orders/routing.py +3 -3
- wbportfolio/order_routing/adapters/ubs.py +4 -1
- wbportfolio/pms/typing.py +1 -22
- wbportfolio/serializers/orders/orders.py +2 -2
- wbportfolio/viewsets/orders/order_proposals.py +1 -1
- {wbportfolio-1.56.1.dist-info → wbportfolio-1.56.3.dist-info}/METADATA +1 -1
- {wbportfolio-1.56.1.dist-info → wbportfolio-1.56.3.dist-info}/RECORD +12 -12
- {wbportfolio-1.56.1.dist-info → wbportfolio-1.56.3.dist-info}/WHEEL +0 -0
- {wbportfolio-1.56.1.dist-info → wbportfolio-1.56.3.dist-info}/licenses/LICENSE +0 -0
|
@@ -12,3 +12,5 @@ class OrderProposalAdmin(admin.ModelAdmin):
|
|
|
12
12
|
list_display = ("portfolio", "rebalancing_model", "trade_date", "status")
|
|
13
13
|
autocomplete_fields = ["portfolio", "rebalancing_model"]
|
|
14
14
|
inlines = [OrderTabularInline]
|
|
15
|
+
|
|
16
|
+
raw_id_fields = ["portfolio", "creator", "approver"]
|
|
@@ -338,7 +338,9 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
338
338
|
def prepare_orders_for_execution(self) -> list[OrderDTO]:
|
|
339
339
|
executable_orders = []
|
|
340
340
|
for order in (
|
|
341
|
-
self.get_orders()
|
|
341
|
+
self.get_orders()
|
|
342
|
+
.exclude(models.Q(underlying_instrument__is_cash=True) | (models.Q(weighting=0) & models.Q(shares=0)))
|
|
343
|
+
.select_related("underlying_instrument")
|
|
342
344
|
):
|
|
343
345
|
instrument = order.underlying_instrument
|
|
344
346
|
# we support only the instrument type provided by the Order DTO class
|
|
@@ -459,7 +461,7 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
459
461
|
positions.append(
|
|
460
462
|
PositionDTO(
|
|
461
463
|
underlying_instrument=instrument.id,
|
|
462
|
-
instrument_type=instrument.
|
|
464
|
+
instrument_type=instrument.security_instrument_type.id,
|
|
463
465
|
weighting=weighting,
|
|
464
466
|
daily_return=daily_return if use_effective else Decimal("0"),
|
|
465
467
|
shares=row["shares"],
|
|
@@ -898,11 +900,7 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
898
900
|
|
|
899
901
|
Order.objects.bulk_update(orders, ["shares", "weighting", "desired_target_weight"])
|
|
900
902
|
|
|
901
|
-
|
|
902
|
-
estimated_cash_position = self.get_estimated_target_cash()
|
|
903
|
-
target_portfolio = self.validated_trading_service.trades_batch.convert_to_portfolio(
|
|
904
|
-
estimated_cash_position._build_dto()
|
|
905
|
-
)
|
|
903
|
+
target_portfolio = self.convert_to_portfolio()
|
|
906
904
|
self.evaluate_active_rules(self.trade_date, target_portfolio, asynchronously=True)
|
|
907
905
|
self.total_cash_weight = Decimal("1") - total_target_weight
|
|
908
906
|
return orders_validation_warnings
|
|
@@ -28,10 +28,10 @@ def execute_orders(order_proposal: "OrderProposal") -> tuple[ExecutionStatus, st
|
|
|
28
28
|
orders = order_proposal.prepare_orders_for_execution()
|
|
29
29
|
as_draft = _should_route_as_draft()
|
|
30
30
|
adapter = order_proposal.custodian_adapter
|
|
31
|
-
|
|
31
|
+
confirmed_orders, rebalancing_comment = adapter.submit_rebalancing(orders, as_draft=as_draft)
|
|
32
32
|
leftover_orders = order_proposal.orders.all()
|
|
33
33
|
|
|
34
|
-
for confirmed in
|
|
34
|
+
for confirmed in confirmed_orders:
|
|
35
35
|
with suppress(ObjectDoesNotExist):
|
|
36
36
|
order = leftover_orders.get(id=confirmed.id)
|
|
37
37
|
order.execution_confirmed = True
|
|
@@ -40,7 +40,7 @@ def execute_orders(order_proposal: "OrderProposal") -> tuple[ExecutionStatus, st
|
|
|
40
40
|
leftover_orders = leftover_orders.exclude(id=order.id)
|
|
41
41
|
|
|
42
42
|
# Orders without confirmation
|
|
43
|
-
leftover_orders.update(execution_confirmed=False, execution_comment="
|
|
43
|
+
leftover_orders.update(execution_confirmed=False, execution_comment="Execution ignored")
|
|
44
44
|
return ExecutionStatus.IN_DRAFT if as_draft else ExecutionStatus.PENDING, rebalancing_comment
|
|
45
45
|
|
|
46
46
|
|
|
@@ -10,7 +10,10 @@ from wbportfolio.pms.typing import Order
|
|
|
10
10
|
from .. import ExecutionStatus, RoutingException
|
|
11
11
|
from . import BaseCustodianAdapter
|
|
12
12
|
|
|
13
|
-
ASSET_CLASS_MAP = {
|
|
13
|
+
ASSET_CLASS_MAP = {
|
|
14
|
+
Order.AssetType.EQUITY: "EQUITY",
|
|
15
|
+
Order.AssetType.AMERICAN_DEPOSITORY_RECEIPT: "EQUITY",
|
|
16
|
+
} # API can support BOND, FUTURE, OPTION, and DYNAMIC_STRATEGY
|
|
14
17
|
ASSET_CLASS_MAP_INV = {
|
|
15
18
|
v: k for k, v in ASSET_CLASS_MAP.items()
|
|
16
19
|
} # API can support BOND, FUTURE, OPTION, and DYNAMIC_STRATEGY
|
wbportfolio/pms/typing.py
CHANGED
|
@@ -101,6 +101,7 @@ class Portfolio:
|
|
|
101
101
|
class Order:
|
|
102
102
|
class AssetType(enum.Enum):
|
|
103
103
|
EQUITY = "EQUITY"
|
|
104
|
+
AMERICAN_DEPOSITORY_RECEIPT = "AMERICAN_DEPOSITORY_RECEIPT"
|
|
104
105
|
|
|
105
106
|
id: int | str
|
|
106
107
|
trade_date: date
|
|
@@ -267,28 +268,6 @@ class TradeBatch:
|
|
|
267
268
|
if round(float(self.total_target_weight), 4) != 1: # we do that to remove decimal over precision
|
|
268
269
|
raise ValidationError(f"Total Weight cannot be different than 1 ({float(self.total_target_weight)})")
|
|
269
270
|
|
|
270
|
-
def convert_to_portfolio(self, use_effective: bool = False, *extra_positions):
|
|
271
|
-
positions = []
|
|
272
|
-
for trade in self.trades_map.values():
|
|
273
|
-
positions.append(
|
|
274
|
-
Position(
|
|
275
|
-
underlying_instrument=trade.underlying_instrument,
|
|
276
|
-
instrument_type=trade.instrument_type,
|
|
277
|
-
weighting=trade.target_weight if not use_effective else trade.previous_weight,
|
|
278
|
-
daily_return=trade.daily_return if use_effective else Decimal("0"),
|
|
279
|
-
shares=trade.target_shares,
|
|
280
|
-
currency=trade.currency,
|
|
281
|
-
date=trade.date,
|
|
282
|
-
is_cash=trade.is_cash,
|
|
283
|
-
price=trade.price,
|
|
284
|
-
currency_fx_rate=trade.currency_fx_rate,
|
|
285
|
-
)
|
|
286
|
-
)
|
|
287
|
-
for position in extra_positions:
|
|
288
|
-
if position.weighting:
|
|
289
|
-
positions.append(position)
|
|
290
|
-
return Portfolio(tuple(positions))
|
|
291
|
-
|
|
292
271
|
def normalize(self, total_target_weight: Decimal = Decimal("1.0")):
|
|
293
272
|
"""
|
|
294
273
|
Normalize the instantiate trades batch so that the target weight is 100%
|
|
@@ -89,7 +89,7 @@ class OrderOrderProposalListModelSerializer(wb_serializers.ModelSerializer):
|
|
|
89
89
|
) is not None and portfolio_value:
|
|
90
90
|
data["target_weight"] = target_total_value_fx_portfolio / portfolio_value
|
|
91
91
|
|
|
92
|
-
if data.get("weighting") or data.get("target_weight"):
|
|
92
|
+
if data.get("weighting") is not None or data.get("target_weight") is not None:
|
|
93
93
|
weighting = data.pop("weighting", None)
|
|
94
94
|
if (target_weight := data.pop("target_weight", None)) is not None:
|
|
95
95
|
weighting = target_weight - effective_weight
|
|
@@ -99,7 +99,7 @@ class OrderOrderProposalListModelSerializer(wb_serializers.ModelSerializer):
|
|
|
99
99
|
data.pop("shares", None)
|
|
100
100
|
data.pop("target_shares", None)
|
|
101
101
|
|
|
102
|
-
if data.get("shares") or data.get("target_shares"):
|
|
102
|
+
if data.get("shares") is not None or data.get("target_shares") is not None:
|
|
103
103
|
shares = data.pop("shares", None)
|
|
104
104
|
if (target_shares := data.pop("target_shares", None)) is not None:
|
|
105
105
|
shares = target_shares - effective_shares
|
|
@@ -96,7 +96,7 @@ class OrderProposalModelViewSet(CloneMixin, RiskCheckViewSetMixin, InternalUserP
|
|
|
96
96
|
)
|
|
97
97
|
if (
|
|
98
98
|
instance.execution_status in [ExecutionStatus.IN_DRAFT, ExecutionStatus.COMPLETED]
|
|
99
|
-
and instance.orders.filter(execution_confirmed=False).exists()
|
|
99
|
+
and instance.orders.exclude(shares=0, weighting=0).filter(execution_confirmed=False).exists()
|
|
100
100
|
):
|
|
101
101
|
warning(request, "Some orders failed confirmation. Check the list for further details.")
|
|
102
102
|
if instance.execution_status in [
|
|
@@ -20,8 +20,8 @@ wbportfolio/admin/reconciliations.py,sha256=s7aYxdJE6jX72bnKCrj-YdZBl9bFV_n44Bo2
|
|
|
20
20
|
wbportfolio/admin/registers.py,sha256=N5zcfFgxR9H37YEJxFIBif7v5uLN2mGNV3lf9c5OYnw,505
|
|
21
21
|
wbportfolio/admin/roles.py,sha256=h7d0aYBctghj1zFphWkMVHywnCjF8bewVbk8lq1IX8U,446
|
|
22
22
|
wbportfolio/admin/orders/__init__.py,sha256=m5iZgRJfsorMe7o-vt4qL3Jn1QMRJFXzJQSa1fljfvQ,87
|
|
23
|
-
wbportfolio/admin/orders/order_proposals.py,sha256=
|
|
24
|
-
wbportfolio/admin/orders/orders.py,sha256=
|
|
23
|
+
wbportfolio/admin/orders/order_proposals.py,sha256=RU5RpAtJUhhhvfLhALmCMm-RserVLYszdswjHa7FFII,480
|
|
24
|
+
wbportfolio/admin/orders/orders.py,sha256=FMHuBWRVft5jc_11bfVpINl8c4F1PXZNC_rfCdeNtxI,705
|
|
25
25
|
wbportfolio/admin/transactions/__init__.py,sha256=WJRFKwreNwFsQdSrjaK7HUZAzlnSeYNdciLyeoOzFRg,131
|
|
26
26
|
wbportfolio/admin/transactions/claim.py,sha256=DaE5vtmSlt_ya55bCAM75UD8smNisA5kl5jrAANm0yA,613
|
|
27
27
|
wbportfolio/admin/transactions/dividends.py,sha256=2Hx0yvcMp0VvzYfuO_jl-9KFrpq6RUd5S7NVrc10Rsg,1604
|
|
@@ -299,9 +299,9 @@ 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=I_pgJ3QVFBtq0SeljJerhtlrZESRDNAe4On6QfMHvXc,58834
|
|
301
301
|
wbportfolio/models/orders/__init__.py,sha256=EH9UacGR3npBMje5FGTeLOh1xqFBh9kc24WbGmBIA3g,69
|
|
302
|
-
wbportfolio/models/orders/order_proposals.py,sha256=
|
|
302
|
+
wbportfolio/models/orders/order_proposals.py,sha256=UYNuW5PguEjVD0h66vyGjagWlWqq46cpv80BORDiT3U,58281
|
|
303
303
|
wbportfolio/models/orders/orders.py,sha256=-bIle6Ftt_eRfP5R_J2Y4LEh9HqOUF0sbLUxQftd684,11588
|
|
304
|
-
wbportfolio/models/orders/routing.py,sha256=
|
|
304
|
+
wbportfolio/models/orders/routing.py,sha256=7nu7-3zmGsVA3tyymKK_ywY7V7RtKkGcXkyk2V8dXMw,2191
|
|
305
305
|
wbportfolio/models/reconciliations/__init__.py,sha256=MXH5fZIPGDRBgJkO6wVu_NLRs8fkP1im7G6d-h36lQY,127
|
|
306
306
|
wbportfolio/models/reconciliations/account_reconciliation_lines.py,sha256=QP6M7hMcyFbuXBa55Y-azui6Dl_WgbzMntEqWzQkbfM,7394
|
|
307
307
|
wbportfolio/models/reconciliations/account_reconciliations.py,sha256=rofSxetFfEJov6mPyoTvGxELA16HILyJZtQvm_kwYU0,4405
|
|
@@ -314,9 +314,9 @@ wbportfolio/models/transactions/trades.py,sha256=fzt52pD7GnvIhVGX8NuArFVzxKEQfPc
|
|
|
314
314
|
wbportfolio/models/transactions/transactions.py,sha256=X7vT0t6UNHFKVU_vCZsA_YQJuOpYisF1vVEeKaZD5CA,4245
|
|
315
315
|
wbportfolio/order_routing/__init__.py,sha256=kYloUGytPBNB8KVy5ysm9PlEEU_sGPk5c3ch46dXeJo,604
|
|
316
316
|
wbportfolio/order_routing/adapters/__init__.py,sha256=YiM5FFvLucDTBgIn3mCBjKNSRU7K2pokHdbWBoaZA94,1549
|
|
317
|
-
wbportfolio/order_routing/adapters/ubs.py,sha256=
|
|
317
|
+
wbportfolio/order_routing/adapters/ubs.py,sha256=RLBiZ98mWijuvtfI8e5C8xH7l4p7OckmpHy6KYjbiIQ,6394
|
|
318
318
|
wbportfolio/pms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
319
|
-
wbportfolio/pms/typing.py,sha256=
|
|
319
|
+
wbportfolio/pms/typing.py,sha256=6fog4ENENVMlv_4bpgCMSY9qWHZSaiEuPAMv4l3AcqM,9701
|
|
320
320
|
wbportfolio/pms/analytics/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
321
321
|
wbportfolio/pms/analytics/portfolio.py,sha256=u_S-e6HUQwAyq90gweDmxyTHWrIc5nd84sLuUF2iJzA,2031
|
|
322
322
|
wbportfolio/pms/analytics/utils.py,sha256=EfhKdo9B2ABaUPppb8DgZSqpNkSze8Rjej1xDjv-XcQ,282
|
|
@@ -376,7 +376,7 @@ wbportfolio/serializers/roles.py,sha256=T-9NqTldpvaEMFy-Bib5MB6MeboygEOqcMP61mzz
|
|
|
376
376
|
wbportfolio/serializers/signals.py,sha256=hD6R4oFtwhvnsJPteytPKy2JwEelmxrapdfoLSnluaE,7053
|
|
377
377
|
wbportfolio/serializers/orders/__init__.py,sha256=PKJRksA1pWsh8nVfGASoB0m3LyUzVRnq1m9VPp90J7k,271
|
|
378
378
|
wbportfolio/serializers/orders/order_proposals.py,sha256=Jxea2-Ze8Id5URv4UV-vTfCQGt11tjR27vRRfCs0gXU,4791
|
|
379
|
-
wbportfolio/serializers/orders/orders.py,sha256=
|
|
379
|
+
wbportfolio/serializers/orders/orders.py,sha256=sab4cGfo-zGPz_5W9DuwOqeo_ja0VobZGU01PjcZUHM,9521
|
|
380
380
|
wbportfolio/serializers/transactions/__init__.py,sha256=-7Pan4n7YI3iDvGXff6okzk4ycEURRxp5n_SHCY_g_I,493
|
|
381
381
|
wbportfolio/serializers/transactions/claim.py,sha256=mEt67F2v8HC6roemDT3S0dD0cZIVl1U9sASbLW3Vpyo,11611
|
|
382
382
|
wbportfolio/serializers/transactions/dividends.py,sha256=ADXf9cXe8rq55lC_a8vIzViGLmQ-yDXkgR54k2m-N0w,1814
|
|
@@ -548,7 +548,7 @@ wbportfolio/viewsets/configs/titles/registers.py,sha256=-C-YeGBhGva48oER6EIQ8CxW
|
|
|
548
548
|
wbportfolio/viewsets/configs/titles/roles.py,sha256=9LoJa3jgenXJ5UWRlIErTzdbjpSWMKsyJZtv-eDRTK4,739
|
|
549
549
|
wbportfolio/viewsets/configs/titles/trades.py,sha256=29XCLxvY0Xe3a2tjCno3tN2rRXCr9RWpbWnzurJfnYI,1986
|
|
550
550
|
wbportfolio/viewsets/orders/__init__.py,sha256=N8v9jdEXryOzrLlc7ML3iBCO2lmNXph9_TWoQ7PTvi4,195
|
|
551
|
-
wbportfolio/viewsets/orders/order_proposals.py,sha256=
|
|
551
|
+
wbportfolio/viewsets/orders/order_proposals.py,sha256=nWUlyVN4Ox54nVHyqN2ryHf_BPXuFjrW-FK5sp5WrHA,8333
|
|
552
552
|
wbportfolio/viewsets/orders/orders.py,sha256=O6Mo5t18FEGDLzAZZvgl8PY1STLiLgv1fyYVhupuSSY,11678
|
|
553
553
|
wbportfolio/viewsets/orders/configs/__init__.py,sha256=5MU57JXiKi32_PicHtiNr7YHmMN020FrlF5NFJf_Wds,94
|
|
554
554
|
wbportfolio/viewsets/orders/configs/buttons/__init__.py,sha256=EHzNmAfa0UQFITEF-wxj_s4wn3Y5DE3DCbEUmmvCTIs,106
|
|
@@ -567,7 +567,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
|
|
|
567
567
|
wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
|
|
568
568
|
wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
|
|
569
569
|
wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
|
|
570
|
-
wbportfolio-1.56.
|
|
571
|
-
wbportfolio-1.56.
|
|
572
|
-
wbportfolio-1.56.
|
|
573
|
-
wbportfolio-1.56.
|
|
570
|
+
wbportfolio-1.56.3.dist-info/METADATA,sha256=OBSV7sthodbAftQh-j9KrB9hzIFPcV1j5cLbX6tPwcE,751
|
|
571
|
+
wbportfolio-1.56.3.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
572
|
+
wbportfolio-1.56.3.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
573
|
+
wbportfolio-1.56.3.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|