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.
- wbportfolio/models/portfolio.py +3 -1
- wbportfolio/models/transactions/trade_proposals.py +3 -2
- wbportfolio/serializers/transactions/trades.py +63 -4
- wbportfolio/viewsets/configs/display/trades.py +10 -7
- {wbportfolio-1.50.1.dist-info → wbportfolio-1.50.3.dist-info}/METADATA +1 -1
- {wbportfolio-1.50.1.dist-info → wbportfolio-1.50.3.dist-info}/RECORD +8 -8
- {wbportfolio-1.50.1.dist-info → wbportfolio-1.50.3.dist-info}/WHEEL +0 -0
- {wbportfolio-1.50.1.dist-info → wbportfolio-1.50.3.dist-info}/licenses/LICENSE +0 -0
wbportfolio/models/portfolio.py
CHANGED
|
@@ -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(
|
|
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 =
|
|
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=
|
|
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",
|
|
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
|
-
|
|
240
|
-
if
|
|
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
|
-
|
|
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
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
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)
|
|
@@ -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=
|
|
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=
|
|
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=
|
|
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=
|
|
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.
|
|
525
|
-
wbportfolio-1.50.
|
|
526
|
-
wbportfolio-1.50.
|
|
527
|
-
wbportfolio-1.50.
|
|
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,,
|
|
File without changes
|
|
File without changes
|