wbportfolio 1.55.8__py2.py3-none-any.whl → 1.55.9__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/portfolio.py +11 -5
- wbportfolio/migrations/0089_orderproposal_min_weighting.py +71 -0
- wbportfolio/models/orders/order_proposals.py +18 -0
- wbportfolio/models/orders/orders.py +6 -0
- wbportfolio/models/portfolio.py +20 -0
- wbportfolio/serializers/orders/order_proposals.py +1 -0
- wbportfolio/tasks.py +42 -4
- wbportfolio/tests/models/orders/test_order_proposals.py +32 -0
- wbportfolio/viewsets/orders/configs/displays/order_proposals.py +5 -5
- {wbportfolio-1.55.8.dist-info → wbportfolio-1.55.9.dist-info}/METADATA +1 -1
- {wbportfolio-1.55.8.dist-info → wbportfolio-1.55.9.dist-info}/RECORD +13 -14
- wbportfolio/fdm/__init__.py +0 -0
- wbportfolio/fdm/tasks.py +0 -42
- {wbportfolio-1.55.8.dist-info → wbportfolio-1.55.9.dist-info}/WHEEL +0 -0
- {wbportfolio-1.55.8.dist-info → wbportfolio-1.55.9.dist-info}/licenses/LICENSE +0 -0
wbportfolio/admin/portfolio.py
CHANGED
|
@@ -10,10 +10,6 @@ from wbportfolio.models import (
|
|
|
10
10
|
PortfolioSwingPricing,
|
|
11
11
|
)
|
|
12
12
|
|
|
13
|
-
from .portfolio_relationships import (
|
|
14
|
-
PortfolioInstrumentPreferredClassificationThroughInlineModelAdmin,
|
|
15
|
-
)
|
|
16
|
-
|
|
17
13
|
|
|
18
14
|
@admin.register(PortfolioBankAccountThroughModel)
|
|
19
15
|
class PortfolioBankAccountThroughModelModelAdmin(admin.ModelAdmin):
|
|
@@ -64,6 +60,16 @@ class PortfolioModelAdmin(admin.ModelAdmin):
|
|
|
64
60
|
)
|
|
65
61
|
},
|
|
66
62
|
),
|
|
63
|
+
(
|
|
64
|
+
"OMS",
|
|
65
|
+
{
|
|
66
|
+
"fields": (
|
|
67
|
+
"default_order_proposal_min_order_value",
|
|
68
|
+
"default_order_proposal_min_weighting",
|
|
69
|
+
"default_order_proposal_total_cash_weight",
|
|
70
|
+
)
|
|
71
|
+
},
|
|
72
|
+
),
|
|
67
73
|
)
|
|
68
74
|
readonly_fields = ["updated_at"]
|
|
69
75
|
list_display = (
|
|
@@ -78,7 +84,7 @@ class PortfolioModelAdmin(admin.ModelAdmin):
|
|
|
78
84
|
inlines = [
|
|
79
85
|
PortfolioBankAccountThroughModelAdmin,
|
|
80
86
|
InstrumentPortfolioThroughModelAdmin,
|
|
81
|
-
PortfolioInstrumentPreferredClassificationThroughInlineModelAdmin,
|
|
87
|
+
# PortfolioInstrumentPreferredClassificationThroughInlineModelAdmin,
|
|
82
88
|
PortfolioPortfolioThroughModelInlineAdmin,
|
|
83
89
|
]
|
|
84
90
|
raw_id_fields = [
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# Generated by Django 5.0.12 on 2025-09-15 13:45
|
|
2
|
+
|
|
3
|
+
import django.core.validators
|
|
4
|
+
from decimal import Decimal
|
|
5
|
+
from django.db import migrations, models
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
|
|
10
|
+
dependencies = [
|
|
11
|
+
('wbportfolio', '0088_orderproposal_total_effective_portfolio_contribution'),
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
operations = [
|
|
15
|
+
migrations.AddField(
|
|
16
|
+
model_name='orderproposal',
|
|
17
|
+
name='min_weighting',
|
|
18
|
+
field=models.DecimalField(decimal_places=8, default=Decimal('0'), help_text='The minimum weight allowed for this order proposal ', max_digits=9, verbose_name='Minimum Weight'),
|
|
19
|
+
),
|
|
20
|
+
migrations.AddField(
|
|
21
|
+
model_name='portfolio',
|
|
22
|
+
name='default_order_proposal_min_order_value',
|
|
23
|
+
field=models.IntegerField(default=0, verbose_name='Default Order Proposal Minimum Order Value'),
|
|
24
|
+
),
|
|
25
|
+
migrations.AddField(
|
|
26
|
+
model_name='portfolio',
|
|
27
|
+
name='default_order_proposal_min_weighting',
|
|
28
|
+
field=models.DecimalField(decimal_places=8, default=Decimal('0'), max_digits=9,
|
|
29
|
+
verbose_name='Default Order Proposal Minimum Weight'),
|
|
30
|
+
),
|
|
31
|
+
migrations.AddField(
|
|
32
|
+
model_name='portfolio',
|
|
33
|
+
name='default_order_proposal_total_cash_weight',
|
|
34
|
+
field=models.DecimalField(decimal_places=4, default=Decimal('0'), max_digits=5,
|
|
35
|
+
verbose_name='Default Order Proposal Total Cash Weight'),
|
|
36
|
+
),
|
|
37
|
+
migrations.AlterField(
|
|
38
|
+
model_name='orderproposal',
|
|
39
|
+
name='min_weighting',
|
|
40
|
+
field=models.DecimalField(decimal_places=8, default=Decimal('0'),
|
|
41
|
+
help_text='The minimum weight allowed for this order proposal ', max_digits=9,
|
|
42
|
+
validators=[django.core.validators.MinValueValidator(Decimal('0')),
|
|
43
|
+
django.core.validators.MaxValueValidator(Decimal('1'))],
|
|
44
|
+
verbose_name='Minimum Weight'),
|
|
45
|
+
),
|
|
46
|
+
migrations.AlterField(
|
|
47
|
+
model_name='orderproposal',
|
|
48
|
+
name='total_cash_weight',
|
|
49
|
+
field=models.DecimalField(decimal_places=4, default=Decimal('0'),
|
|
50
|
+
help_text='The desired percentage for the cash component. The remaining percentage (100% minus this value) will be allocated to total target weighting. Default is 0%.',
|
|
51
|
+
max_digits=5, validators=[django.core.validators.MinValueValidator(Decimal('0')),
|
|
52
|
+
django.core.validators.MaxValueValidator(Decimal('1'))],
|
|
53
|
+
verbose_name='Total Cash Weight'),
|
|
54
|
+
),
|
|
55
|
+
migrations.AlterField(
|
|
56
|
+
model_name='portfolio',
|
|
57
|
+
name='default_order_proposal_min_weighting',
|
|
58
|
+
field=models.DecimalField(decimal_places=8, default=Decimal('0'), max_digits=9,
|
|
59
|
+
validators=[django.core.validators.MinValueValidator(Decimal('0')),
|
|
60
|
+
django.core.validators.MaxValueValidator(Decimal('1'))],
|
|
61
|
+
verbose_name='Default Order Proposal Minimum Weight'),
|
|
62
|
+
),
|
|
63
|
+
migrations.AlterField(
|
|
64
|
+
model_name='portfolio',
|
|
65
|
+
name='default_order_proposal_total_cash_weight',
|
|
66
|
+
field=models.DecimalField(decimal_places=4, default=Decimal('0'), max_digits=5,
|
|
67
|
+
validators=[django.core.validators.MinValueValidator(Decimal('0')),
|
|
68
|
+
django.core.validators.MaxValueValidator(Decimal('1'))],
|
|
69
|
+
verbose_name='Default Order Proposal Total Cash Weight'),
|
|
70
|
+
),
|
|
71
|
+
]
|
|
@@ -7,6 +7,7 @@ from typing import Any, TypeVar
|
|
|
7
7
|
|
|
8
8
|
from celery import shared_task
|
|
9
9
|
from django.core.exceptions import ValidationError
|
|
10
|
+
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
10
11
|
from django.db import DatabaseError, models
|
|
11
12
|
from django.db.models import (
|
|
12
13
|
F,
|
|
@@ -96,12 +97,22 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
96
97
|
min_order_value = models.IntegerField(
|
|
97
98
|
default=0, verbose_name="Minimum Order Value", help_text="Minimum Order Value in the Portfolio currency"
|
|
98
99
|
)
|
|
100
|
+
min_weighting = models.DecimalField(
|
|
101
|
+
max_digits=9,
|
|
102
|
+
decimal_places=Order.ORDER_WEIGHTING_PRECISION,
|
|
103
|
+
default=Decimal(0),
|
|
104
|
+
help_text="The minimum weight allowed for this order proposal ",
|
|
105
|
+
verbose_name="Minimum Weight",
|
|
106
|
+
validators=[MinValueValidator(Decimal("0")), MaxValueValidator(Decimal("1"))],
|
|
107
|
+
)
|
|
108
|
+
|
|
99
109
|
total_cash_weight = models.DecimalField(
|
|
100
110
|
default=Decimal("0"),
|
|
101
111
|
decimal_places=4,
|
|
102
112
|
max_digits=5,
|
|
103
113
|
verbose_name="Total Cash Weight",
|
|
104
114
|
help_text="The desired percentage for the cash component. The remaining percentage (100% minus this value) will be allocated to total target weighting. Default is 0%.",
|
|
115
|
+
validators=[MinValueValidator(Decimal("0")), MaxValueValidator(Decimal("1"))],
|
|
105
116
|
)
|
|
106
117
|
total_effective_portfolio_contribution = models.DecimalField(
|
|
107
118
|
default=Decimal("1"),
|
|
@@ -136,6 +147,13 @@ class OrderProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
136
147
|
]
|
|
137
148
|
|
|
138
149
|
def save(self, *args, **kwargs):
|
|
150
|
+
# if the order proposal is created, we default these fields with the portfolio default value for automatic value assignement
|
|
151
|
+
if not self.id and not self.min_order_value:
|
|
152
|
+
self.min_order_value = self.portfolio.default_order_proposal_min_order_value
|
|
153
|
+
if not self.id and not self.min_weighting:
|
|
154
|
+
self.min_weighting = self.portfolio.default_order_proposal_min_weighting
|
|
155
|
+
if not self.id and not self.total_cash_weight:
|
|
156
|
+
self.total_cash_weight = self.portfolio.default_order_proposal_total_cash_weight
|
|
139
157
|
# if a order proposal is created before the existing earliest order proposal, we automatically shift the linked instruments inception date to allow automatic NAV computation since the new inception date
|
|
140
158
|
if not self.portfolio.order_proposals.filter(trade_date__lt=self.trade_date).exists():
|
|
141
159
|
# we need to set the inception date as the first order proposal trade date (and thus, the first position date). We expect a NAV at 100 then
|
|
@@ -87,6 +87,12 @@ class Order(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
87
87
|
self.shares = shares
|
|
88
88
|
if portfolio_total_asset_value:
|
|
89
89
|
self.weighting = self.shares * self.price * self.currency_fx_rate / portfolio_total_asset_value
|
|
90
|
+
if abs(self.weighting) < self.order_proposal.min_weighting:
|
|
91
|
+
warnings.append(
|
|
92
|
+
f"Weighting for order {self.underlying_instrument.computed_str} ({self.weighting}) is bellow the allowed Minimum Weighting ({self.order_proposal.min_weighting})"
|
|
93
|
+
)
|
|
94
|
+
self.shares = Decimal("0")
|
|
95
|
+
self.weighting = Decimal("0")
|
|
90
96
|
if self.shares and abs(self.total_value_fx_portfolio) < self.order_proposal.min_order_value:
|
|
91
97
|
warnings.append(
|
|
92
98
|
f"Total Value for order {self.underlying_instrument.computed_str} ({self.total_value_fx_portfolio}) is bellow the allowed Minimum Order Value ({self.order_proposal.min_order_value})"
|
wbportfolio/models/portfolio.py
CHANGED
|
@@ -9,6 +9,7 @@ import pandas as pd
|
|
|
9
9
|
from celery import shared_task
|
|
10
10
|
from django.contrib.postgres.fields import DateRangeField
|
|
11
11
|
from django.core.exceptions import ObjectDoesNotExist
|
|
12
|
+
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
12
13
|
from django.db import models
|
|
13
14
|
from django.db.models import Exists, F, OuterRef, Q, QuerySet, Sum
|
|
14
15
|
from django.db.models.signals import post_save
|
|
@@ -233,6 +234,25 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
233
234
|
blank=True,
|
|
234
235
|
)
|
|
235
236
|
|
|
237
|
+
# OMS default parameters. Used to seed order proposal default value upon creation
|
|
238
|
+
default_order_proposal_min_order_value = models.IntegerField(
|
|
239
|
+
default=0, verbose_name="Default Order Proposal Minimum Order Value"
|
|
240
|
+
)
|
|
241
|
+
default_order_proposal_min_weighting = models.DecimalField(
|
|
242
|
+
max_digits=9,
|
|
243
|
+
decimal_places=8,
|
|
244
|
+
default=Decimal(0),
|
|
245
|
+
verbose_name="Default Order Proposal Minimum Weight",
|
|
246
|
+
validators=[MinValueValidator(Decimal("0")), MaxValueValidator(Decimal("1"))],
|
|
247
|
+
)
|
|
248
|
+
default_order_proposal_total_cash_weight = models.DecimalField(
|
|
249
|
+
default=Decimal("0"),
|
|
250
|
+
decimal_places=4,
|
|
251
|
+
max_digits=5,
|
|
252
|
+
verbose_name="Default Order Proposal Total Cash Weight",
|
|
253
|
+
validators=[MinValueValidator(Decimal("0")), MaxValueValidator(Decimal("1"))],
|
|
254
|
+
)
|
|
255
|
+
|
|
236
256
|
objects = DefaultPortfolioManager()
|
|
237
257
|
tracked_objects = ActiveTrackedPortfolioManager()
|
|
238
258
|
|
wbportfolio/tasks.py
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
from contextlib import suppress
|
|
2
2
|
from datetime import date, timedelta
|
|
3
3
|
|
|
4
|
+
from celery import shared_task
|
|
4
5
|
from django.db.models import ProtectedError, Q
|
|
6
|
+
from tqdm import tqdm
|
|
7
|
+
from wbfdm.models import Controversy, Instrument
|
|
5
8
|
|
|
6
|
-
from wbportfolio.models import Portfolio, Trade
|
|
7
|
-
from wbportfolio.models.products import Product
|
|
8
|
-
|
|
9
|
-
from .fdm.tasks import * # noqa
|
|
9
|
+
from wbportfolio.models import AssetPosition, Portfolio, Product, Trade
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@shared_task(queue="portfolio")
|
|
@@ -49,3 +49,41 @@ def update_preferred_classification_per_instrument_and_portfolio_as_task():
|
|
|
49
49
|
# - propagate (or update) t-2 asset positions into t-1
|
|
50
50
|
# - Synchronize wbportfolio at t-1
|
|
51
51
|
# - Compute Instrument Price estimate at t-1
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
@shared_task(queue="portfolio")
|
|
55
|
+
def synchronize_portfolio_controversies():
|
|
56
|
+
active_portfolios = Portfolio.objects.filter_active_and_tracked()
|
|
57
|
+
qs = (
|
|
58
|
+
AssetPosition.objects.filter(portfolio__in=active_portfolios)
|
|
59
|
+
.values("underlying_instrument")
|
|
60
|
+
.distinct("underlying_instrument")
|
|
61
|
+
)
|
|
62
|
+
objs = {}
|
|
63
|
+
securities = Instrument.objects.filter(id__in=qs.values("underlying_instrument"))
|
|
64
|
+
securities_mapping = {security.id: security.get_root() for security in securities}
|
|
65
|
+
for controversy in securities.dl.esg_controversies():
|
|
66
|
+
instrument = securities_mapping[controversy["instrument_id"]]
|
|
67
|
+
obj = Controversy.dict_to_model(controversy, instrument)
|
|
68
|
+
objs[obj.external_id] = obj
|
|
69
|
+
|
|
70
|
+
Controversy.objects.bulk_create(
|
|
71
|
+
objs.values(),
|
|
72
|
+
update_fields=[
|
|
73
|
+
"instrument",
|
|
74
|
+
"headline",
|
|
75
|
+
"description",
|
|
76
|
+
"source",
|
|
77
|
+
"direct_involvement",
|
|
78
|
+
"company_response",
|
|
79
|
+
"review",
|
|
80
|
+
"initiated",
|
|
81
|
+
"flag",
|
|
82
|
+
"status",
|
|
83
|
+
"type",
|
|
84
|
+
"severity",
|
|
85
|
+
],
|
|
86
|
+
unique_fields=["external_id"],
|
|
87
|
+
update_conflicts=True,
|
|
88
|
+
batch_size=10000,
|
|
89
|
+
)
|
|
@@ -695,6 +695,38 @@ class TestOrderProposal:
|
|
|
695
695
|
assert order.shares == Decimal(0)
|
|
696
696
|
assert order.weighting == Decimal(0)
|
|
697
697
|
|
|
698
|
+
def test_order_submit_bellow_minimum_weighting(self, order_factory, order_proposal):
|
|
699
|
+
o1 = order_factory.create(order_proposal=order_proposal, price=Decimal(1), weighting=Decimal("0.8"))
|
|
700
|
+
o2 = order_factory.create(order_proposal=order_proposal, price=Decimal(1), weighting=Decimal("0.2"))
|
|
701
|
+
order_proposal.submit()
|
|
702
|
+
order_proposal.save()
|
|
703
|
+
|
|
704
|
+
o1.refresh_from_db()
|
|
705
|
+
o2.refresh_from_db()
|
|
706
|
+
assert o1.weighting == Decimal("0.8")
|
|
707
|
+
assert o2.weighting == Decimal("0.2")
|
|
708
|
+
|
|
709
|
+
order_proposal.min_weighting = Decimal("0.21")
|
|
710
|
+
order_proposal.backtodraft()
|
|
711
|
+
order_proposal.submit()
|
|
712
|
+
order_proposal.save()
|
|
713
|
+
|
|
714
|
+
o1.refresh_from_db()
|
|
715
|
+
o2.refresh_from_db()
|
|
716
|
+
assert o1.weighting == Decimal("0.8")
|
|
717
|
+
assert o2.weighting == Decimal("0")
|
|
718
|
+
|
|
719
|
+
order_proposal.approve()
|
|
720
|
+
order_proposal.apply()
|
|
721
|
+
order_proposal.save()
|
|
722
|
+
|
|
723
|
+
assert order_proposal.portfolio.assets.get(
|
|
724
|
+
date=order_proposal.trade_date, underlying_quote=o1.underlying_instrument
|
|
725
|
+
).weighting == Decimal("0.8")
|
|
726
|
+
assert order_proposal.portfolio.assets.get(
|
|
727
|
+
date=order_proposal.trade_date, underlying_quote=order_proposal.cash_component
|
|
728
|
+
).weighting == Decimal("0.2")
|
|
729
|
+
|
|
698
730
|
def test_reset_order_use_desired_target_weight(self, order_proposal, order_factory):
|
|
699
731
|
order1 = order_factory.create(
|
|
700
732
|
order_proposal=order_proposal, weighting=Decimal("0.5"), desired_target_weight=Decimal("0.7")
|
|
@@ -132,12 +132,12 @@ class OrderProposalDisplayConfig(DisplayViewConfig):
|
|
|
132
132
|
layouts={
|
|
133
133
|
default(): Layout(
|
|
134
134
|
grid_template_areas=[
|
|
135
|
-
["status", "status", "status"],
|
|
136
|
-
["trade_date", "total_cash_weight", "min_order_value"],
|
|
137
|
-
["rebalancing_model", "target_portfolio", "target_portfolio"]
|
|
135
|
+
["status", "status", "status", "status"],
|
|
136
|
+
["trade_date", "total_cash_weight", "min_order_value", "min_weighting"],
|
|
137
|
+
["rebalancing_model", "rebalancing_model", "target_portfolio", "target_portfolio"]
|
|
138
138
|
if self.view.new_mode
|
|
139
|
-
else ["rebalancing_model", "creator", "approver"],
|
|
140
|
-
["comment", "comment", "comment"],
|
|
139
|
+
else ["rebalancing_model", "rebalancing_model", "creator", "approver"],
|
|
140
|
+
["comment", "comment", "comment", "comment"],
|
|
141
141
|
],
|
|
142
142
|
),
|
|
143
143
|
},
|
|
@@ -4,14 +4,14 @@ wbportfolio/constants.py,sha256=86bfJ-xAyJQGv8DDxhVP_BM7Jr_lxQMhe4SkrxpfN_c,119
|
|
|
4
4
|
wbportfolio/dynamic_preferences_registry.py,sha256=SV-4JWBZBYhXt5cNMglx-yRJhxpejP_jo157ghjq2q0,2294
|
|
5
5
|
wbportfolio/permissions.py,sha256=F147DXfitbw6IdMQGEFfymCJkiG5YGkWKsLdVVliPyw,320
|
|
6
6
|
wbportfolio/preferences.py,sha256=JpowIFTrnjfomogJNrYmmfv7V35bRZNNGL_zooKzEhc,465
|
|
7
|
-
wbportfolio/tasks.py,sha256=
|
|
7
|
+
wbportfolio/tasks.py,sha256=fjmG0FrCkwoHKDk7re6-vjKpI0q_HFtYLF8cddZHvnw,3243
|
|
8
8
|
wbportfolio/urls.py,sha256=PE9UwW2RR8FEUnPc3foaDIW7T49vTwO1TyBPYaSorw0,10539
|
|
9
9
|
wbportfolio/utils.py,sha256=QZ4t0j2NwKYmgWJM77yvXSp-8wVcZmFvNi5_v7YA3ac,750
|
|
10
10
|
wbportfolio/admin/__init__.py,sha256=oTmHrq_4H4OyEna3R_3tIh7pyCyNYVsMDD8y06IYMfQ,675
|
|
11
11
|
wbportfolio/admin/asset.py,sha256=Nukw4axCnctQFlAtPkPJyalEga7RtTp7jr138MOdWSM,1254
|
|
12
12
|
wbportfolio/admin/custodians.py,sha256=rJ9wFdiFM5t3WrmAfNXWzjxDAWrbnlSstfNjQxSmTNE,332
|
|
13
13
|
wbportfolio/admin/indexes.py,sha256=XPiVGBRDD7SV7YvSDv9pAo513IjIbEOBS_pcvVP_UfQ,440
|
|
14
|
-
wbportfolio/admin/portfolio.py,sha256=
|
|
14
|
+
wbportfolio/admin/portfolio.py,sha256=OiUFpxqK7V0iL8dO6LxE_LOepvr20b2CIDRiKPkdEns,4063
|
|
15
15
|
wbportfolio/admin/portfolio_relationships.py,sha256=mLRQUvezcUQfEls0p6pe0P1qVf335zD5pX4eRVf119M,711
|
|
16
16
|
wbportfolio/admin/product_groups.py,sha256=0iXpoj-gGwLeF6BmCohX7d5qrVhCgIxNWUQmJcM67q0,1391
|
|
17
17
|
wbportfolio/admin/products.py,sha256=vEtUpSlnCLLCs4SXkI5UFO7iPsXhRUk7PsNvfD7FS40,2550
|
|
@@ -79,8 +79,6 @@ wbportfolio/factories/trades.py,sha256=ZHfj20KjeTu57sNaZzfSw2JqCoI9q4BjfPp5qRMVs
|
|
|
79
79
|
wbportfolio/factories/orders/__init__.py,sha256=QG7on_F9GiuJgvGbM0BNDVdfGwwBz_WGbmCFNbKPZzc,83
|
|
80
80
|
wbportfolio/factories/orders/order_proposals.py,sha256=3QGG6eI2sWYGJenn17gz37A2PJgjZLlPqAsqci1lFXI,702
|
|
81
81
|
wbportfolio/factories/orders/orders.py,sha256=tTw2U-xvUsFpG4zad3KCHZPQx1FVg-zPjwEN73XEOjg,907
|
|
82
|
-
wbportfolio/fdm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
83
|
-
wbportfolio/fdm/tasks.py,sha256=v7UmrQhHAgJOQ3AC3VRvJ4YIKveqsqyWnvM33UQOUDI,1367
|
|
84
82
|
wbportfolio/filters/__init__.py,sha256=m44CdyYMtku8rMGyiX8KSmMdvyqaElKW4UMkEqOC1VM,1374
|
|
85
83
|
wbportfolio/filters/assets.py,sha256=rvBNtQ8OcvYXSmaVdgjH7IITvaBZ558Y9sCj0B_WDpw,18866
|
|
86
84
|
wbportfolio/filters/assets_and_net_new_money_progression.py,sha256=IYl_qMFO9QKhXhCTtz2JrOjlAKdEkykNlu4DO_H7HkQ,1403
|
|
@@ -271,6 +269,7 @@ wbportfolio/migrations/0085_order_desired_target_weight.py,sha256=L8p5t4PqjWIwqw
|
|
|
271
269
|
wbportfolio/migrations/0086_orderproposal_total_cash_weight.py,sha256=IE65OYYBOSQjj6znl9jmsMalxDmKdnHV1DbVz_ZX_M4,689
|
|
272
270
|
wbportfolio/migrations/0087_product_order_routing_custodian_adapter.py,sha256=4OHTjdXNwJ-My8EgUGYWM_vRBccjYgghjN4fLV0n1yQ,4564
|
|
273
271
|
wbportfolio/migrations/0088_orderproposal_total_effective_portfolio_contribution.py,sha256=6Q41GSbWg_L8r6FUcQ9MrdpRazOdUlc7tD8_bmg8a3Y,521
|
|
272
|
+
wbportfolio/migrations/0089_orderproposal_min_weighting.py,sha256=DgJdIRka1eZSrEZqkUBHiVPpCfOvChWPrWdx-ZExO6Q,3906
|
|
274
273
|
wbportfolio/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
275
274
|
wbportfolio/models/__init__.py,sha256=qU4e7HKyh8NL_0Mg92PcbHTewCv7Ya2gei1DMGe1LWE,980
|
|
276
275
|
wbportfolio/models/adjustments.py,sha256=osXWkJZOiansPWYPyHtl7Z121zDWi7u1YMtrBQtbHVo,10272
|
|
@@ -279,7 +278,7 @@ wbportfolio/models/builder.py,sha256=txZE_gEDgkPgSxSF0AlvZiRyhRQixD4Ame0wEF6Fjoo
|
|
|
279
278
|
wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
|
|
280
279
|
wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
|
|
281
280
|
wbportfolio/models/indexes.py,sha256=gvW4K9U9Bj8BmVCqFYdWiXvDWhjHINRON8XhNsZUiQY,639
|
|
282
|
-
wbportfolio/models/portfolio.py,sha256=
|
|
281
|
+
wbportfolio/models/portfolio.py,sha256=zgismDA7dXSvX7b_1h9jOdYeilg9qv5mI0mQcy7aRW0,55547
|
|
283
282
|
wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
|
|
284
283
|
wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
|
|
285
284
|
wbportfolio/models/portfolio_relationship.py,sha256=ZGECiPZiLdlk4uSamOrEfuzO0hduK6OMKJLUSnh5_kc,5190
|
|
@@ -299,8 +298,8 @@ wbportfolio/models/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
|
|
|
299
298
|
wbportfolio/models/mixins/instruments.py,sha256=SuMPquQ93D4pZMK-4hQbJtV58_NOyf3wVOctQq7LNXQ,7054
|
|
300
299
|
wbportfolio/models/mixins/liquidity_stress_test.py,sha256=iQVzT3QM7VtHnqfj9gT6KUIe4wC4MJXery-AXJHUYns,58820
|
|
301
300
|
wbportfolio/models/orders/__init__.py,sha256=EH9UacGR3npBMje5FGTeLOh1xqFBh9kc24WbGmBIA3g,69
|
|
302
|
-
wbportfolio/models/orders/order_proposals.py,sha256=
|
|
303
|
-
wbportfolio/models/orders/orders.py,sha256=
|
|
301
|
+
wbportfolio/models/orders/order_proposals.py,sha256=u-RNtSw-psb8BGeE7Lkbet5UQnCL_hacyhX3he0PxZQ,58191
|
|
302
|
+
wbportfolio/models/orders/orders.py,sha256=OpUbKzY2g6XA3n8hyU-FTauEQE5UKLEdOPQkdi4rktU,10520
|
|
304
303
|
wbportfolio/models/orders/routing.py,sha256=OpeP-rfMm1UN7a3vbNxBEQxqtGfE57AeGWnbTZa1fRQ,2223
|
|
305
304
|
wbportfolio/models/reconciliations/__init__.py,sha256=MXH5fZIPGDRBgJkO6wVu_NLRs8fkP1im7G6d-h36lQY,127
|
|
306
305
|
wbportfolio/models/reconciliations/account_reconciliation_lines.py,sha256=QP6M7hMcyFbuXBa55Y-azui6Dl_WgbzMntEqWzQkbfM,7394
|
|
@@ -375,7 +374,7 @@ wbportfolio/serializers/registers.py,sha256=zhdKH_mHEBE0VOhm6xpY54bTMtcSaY5BskEa
|
|
|
375
374
|
wbportfolio/serializers/roles.py,sha256=T-9NqTldpvaEMFy-Bib5MB6MeboygEOqcMP61mzzD3Q,2146
|
|
376
375
|
wbportfolio/serializers/signals.py,sha256=hD6R4oFtwhvnsJPteytPKy2JwEelmxrapdfoLSnluaE,7053
|
|
377
376
|
wbportfolio/serializers/orders/__init__.py,sha256=PKJRksA1pWsh8nVfGASoB0m3LyUzVRnq1m9VPp90J7k,271
|
|
378
|
-
wbportfolio/serializers/orders/order_proposals.py,sha256=
|
|
377
|
+
wbportfolio/serializers/orders/order_proposals.py,sha256=Jxea2-Ze8Id5URv4UV-vTfCQGt11tjR27vRRfCs0gXU,4791
|
|
379
378
|
wbportfolio/serializers/orders/orders.py,sha256=7zIl5lwt7RatSVcrmNmLpWX2r2VkND33HQOUkryGjYo,7582
|
|
380
379
|
wbportfolio/serializers/transactions/__init__.py,sha256=-7Pan4n7YI3iDvGXff6okzk4ycEURRxp5n_SHCY_g_I,493
|
|
381
380
|
wbportfolio/serializers/transactions/claim.py,sha256=kC4E2RZRrpd9i8tGfoiV-gpWDk3ikR5F1Wf0v_IGIvw,11599
|
|
@@ -420,7 +419,7 @@ wbportfolio/tests/models/test_roles.py,sha256=4Cn7WyrA2ztJNeWLk5cy9kYo5XLWMbFSvo
|
|
|
420
419
|
wbportfolio/tests/models/test_splits.py,sha256=ytKcHsI_90kj1L4s8It-KEcc24rkDcElxwQ8q0QxEvk,9689
|
|
421
420
|
wbportfolio/tests/models/utils.py,sha256=ORNJq6NMo1Za22jGZXfTfKeNEnTRlfEt_8SJ6xLaQWg,325
|
|
422
421
|
wbportfolio/tests/models/orders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
423
|
-
wbportfolio/tests/models/orders/test_order_proposals.py,sha256=
|
|
422
|
+
wbportfolio/tests/models/orders/test_order_proposals.py,sha256=N_l7wgFgd-1uFCE6ZbWCzXEOmOgWaiee-w1VCqKxLnw,35401
|
|
424
423
|
wbportfolio/tests/models/transactions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
425
424
|
wbportfolio/tests/models/transactions/test_claim.py,sha256=NG3BKB-FVcIDgHSJHCjImxgMM3ISVUMl24xUPmEcPec,5570
|
|
426
425
|
wbportfolio/tests/models/transactions/test_fees.py,sha256=tAp18x2wCNQr11LUnLtHNbBDbbX0v1DZnmW7i-cEi5Q,2423
|
|
@@ -555,7 +554,7 @@ wbportfolio/viewsets/orders/configs/buttons/__init__.py,sha256=EHzNmAfa0UQFITEF-
|
|
|
555
554
|
wbportfolio/viewsets/orders/configs/buttons/order_proposals.py,sha256=1BPkIYv0-K2DDGa4Gua2_Pxsx7fNurTZ2tYNdL66On0,6495
|
|
556
555
|
wbportfolio/viewsets/orders/configs/buttons/orders.py,sha256=GDO4Y33wkjhDxzpf7B1d_rKzAixegLv5rHam1DV3WkM,290
|
|
557
556
|
wbportfolio/viewsets/orders/configs/displays/__init__.py,sha256=__YJBbz_ZnKpE8WMMDR2PC9Nng-EVlRpGTEQucdrhRA,108
|
|
558
|
-
wbportfolio/viewsets/orders/configs/displays/order_proposals.py,sha256=
|
|
557
|
+
wbportfolio/viewsets/orders/configs/displays/order_proposals.py,sha256=zLoLEw4N1i_LD0e3hJnxzO8ORN2byFZoCxWnAz8DBx0,7362
|
|
559
558
|
wbportfolio/viewsets/orders/configs/displays/orders.py,sha256=R1oaDTGosL430xnYZpJz7ihnCOCO6eAFhDQz-wGYT24,7611
|
|
560
559
|
wbportfolio/viewsets/orders/configs/endpoints/__init__.py,sha256=IB8GEadiEtBDclhkgpcJGXWfCF6qRK_42hxJ4pcdZDU,148
|
|
561
560
|
wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py,sha256=fY3y2YWR9nY-KE8k078NszDsnwOgqOIjHUgLvQjDivU,822
|
|
@@ -567,7 +566,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
|
|
|
567
566
|
wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
|
|
568
567
|
wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
|
|
569
568
|
wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
|
|
570
|
-
wbportfolio-1.55.
|
|
571
|
-
wbportfolio-1.55.
|
|
572
|
-
wbportfolio-1.55.
|
|
573
|
-
wbportfolio-1.55.
|
|
569
|
+
wbportfolio-1.55.9.dist-info/METADATA,sha256=n1wrT55caQrYOtnWIcc_-bZdvHAjIDCO0rDr92VeroM,751
|
|
570
|
+
wbportfolio-1.55.9.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
571
|
+
wbportfolio-1.55.9.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
572
|
+
wbportfolio-1.55.9.dist-info/RECORD,,
|
wbportfolio/fdm/__init__.py
DELETED
|
File without changes
|
wbportfolio/fdm/tasks.py
DELETED
|
@@ -1,42 +0,0 @@
|
|
|
1
|
-
from celery import shared_task
|
|
2
|
-
from wbfdm.models import Controversy, Instrument
|
|
3
|
-
|
|
4
|
-
from wbportfolio.models import AssetPosition, Portfolio
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@shared_task(queue="portfolio")
|
|
8
|
-
def synchronize_portfolio_controversies():
|
|
9
|
-
active_portfolios = Portfolio.objects.filter_active_and_tracked()
|
|
10
|
-
qs = (
|
|
11
|
-
AssetPosition.objects.filter(portfolio__in=active_portfolios)
|
|
12
|
-
.values("underlying_instrument")
|
|
13
|
-
.distinct("underlying_instrument")
|
|
14
|
-
)
|
|
15
|
-
objs = {}
|
|
16
|
-
securities = Instrument.objects.filter(id__in=qs.values("underlying_instrument"))
|
|
17
|
-
securities_mapping = {security.id: security.get_root() for security in securities}
|
|
18
|
-
for controversy in securities.dl.esg_controversies():
|
|
19
|
-
instrument = securities_mapping[controversy["instrument_id"]]
|
|
20
|
-
obj = Controversy.dict_to_model(controversy, instrument)
|
|
21
|
-
objs[obj.external_id] = obj
|
|
22
|
-
|
|
23
|
-
Controversy.objects.bulk_create(
|
|
24
|
-
objs.values(),
|
|
25
|
-
update_fields=[
|
|
26
|
-
"instrument",
|
|
27
|
-
"headline",
|
|
28
|
-
"description",
|
|
29
|
-
"source",
|
|
30
|
-
"direct_involvement",
|
|
31
|
-
"company_response",
|
|
32
|
-
"review",
|
|
33
|
-
"initiated",
|
|
34
|
-
"flag",
|
|
35
|
-
"status",
|
|
36
|
-
"type",
|
|
37
|
-
"severity",
|
|
38
|
-
],
|
|
39
|
-
unique_fields=["external_id"],
|
|
40
|
-
update_conflicts=True,
|
|
41
|
-
batch_size=10000,
|
|
42
|
-
)
|
|
File without changes
|
|
File without changes
|