wbportfolio 1.54.8__py2.py3-none-any.whl → 1.54.10__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/import_export/handlers/trade.py +7 -1
- wbportfolio/models/portfolio.py +19 -15
- wbportfolio/models/transactions/trade_proposals.py +3 -4
- wbportfolio/models/transactions/trades.py +6 -7
- wbportfolio/tests/models/test_portfolios.py +19 -10
- wbportfolio/viewsets/transactions/trades.py +18 -9
- {wbportfolio-1.54.8.dist-info → wbportfolio-1.54.10.dist-info}/METADATA +1 -1
- {wbportfolio-1.54.8.dist-info → wbportfolio-1.54.10.dist-info}/RECORD +10 -10
- {wbportfolio-1.54.8.dist-info → wbportfolio-1.54.10.dist-info}/WHEEL +0 -0
- {wbportfolio-1.54.8.dist-info → wbportfolio-1.54.10.dist-info}/licenses/LICENSE +0 -0
|
@@ -88,6 +88,8 @@ class TradeImportHandler(ImportExportHandler):
|
|
|
88
88
|
1 / (math.pow(10, 4))
|
|
89
89
|
) # we need that convertion mechanism otherwise there is floating point approximation error while casting to decimal and get_instance does not work as expected
|
|
90
90
|
data[field.name] = Decimal(value).quantize(Decimal(str(q)))
|
|
91
|
+
if (target_weight := data.pop("target_weight", None)) is not None:
|
|
92
|
+
data["_target_weight"] = target_weight
|
|
91
93
|
|
|
92
94
|
def _create_instance(self, data: Dict[str, Any], **kwargs) -> models.Model:
|
|
93
95
|
if "transaction_date" not in data: # we might get only book date and not transaction date
|
|
@@ -158,9 +160,13 @@ class TradeImportHandler(ImportExportHandler):
|
|
|
158
160
|
self.import_source.log += "\nNo trade was successfully matched."
|
|
159
161
|
|
|
160
162
|
def _get_history(self, history: Dict[str, Any]) -> models.QuerySet:
|
|
163
|
+
from wbportfolio.models.transactions.trade_proposals import TradeProposal
|
|
164
|
+
|
|
161
165
|
if trade_proposal_id := history.get("trade_proposal_id"):
|
|
162
166
|
# if a trade proposal is provided, we delete the existing history first as otherwise, it would mess with the target weight computation
|
|
163
|
-
|
|
167
|
+
trade_proposal = TradeProposal.objects.get(id=trade_proposal_id)
|
|
168
|
+
trade_proposal.trades.all().delete()
|
|
169
|
+
trade_proposal.reset_trades()
|
|
164
170
|
trades = self.model.objects.none()
|
|
165
171
|
else:
|
|
166
172
|
trades = self.model.objects.filter(
|
wbportfolio/models/portfolio.py
CHANGED
|
@@ -54,6 +54,8 @@ logger = logging.getLogger("pms")
|
|
|
54
54
|
if TYPE_CHECKING:
|
|
55
55
|
from wbportfolio.models.transactions.trade_proposals import TradeProposal
|
|
56
56
|
|
|
57
|
+
MARKET_HOLIDAY_MAX_DURATION = 15
|
|
58
|
+
|
|
57
59
|
|
|
58
60
|
def get_returns(
|
|
59
61
|
instrument_ids: list[int],
|
|
@@ -94,22 +96,20 @@ def get_returns(
|
|
|
94
96
|
df = pd.DataFrame(Instrument.objects.filter(id__in=instrument_ids).dl.market_data(**kwargs))
|
|
95
97
|
if df.empty:
|
|
96
98
|
raise InvalidAnalyticPortfolio()
|
|
97
|
-
|
|
98
|
-
index="valuation_date", columns="instrument_id", values="fx_rate"
|
|
99
|
+
df = df[["instrument_id", "fx_rate", "close", "valuation_date"]].pivot(
|
|
100
|
+
index="valuation_date", columns="instrument_id", values=["fx_rate", "close"]
|
|
99
101
|
)
|
|
102
|
+
ts = pd.bdate_range(df.index.min(), df.index.max(), freq="B")
|
|
103
|
+
df = df.reindex(ts)
|
|
104
|
+
if ffill_returns:
|
|
105
|
+
df = df.ffill()
|
|
106
|
+
df.index = pd.to_datetime(df.index)
|
|
100
107
|
|
|
101
|
-
prices_df = df[
|
|
102
|
-
|
|
103
|
-
)
|
|
104
|
-
price_fx_portfolio_df = fx_rate_df * prices_df
|
|
108
|
+
prices_df = df["close"]
|
|
109
|
+
fx_rate_df = df["fx_rate"]
|
|
105
110
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
if ffill_returns:
|
|
109
|
-
price_fx_portfolio_df = price_fx_portfolio_df.ffill()
|
|
110
|
-
price_fx_portfolio_df.index = pd.to_datetime(price_fx_portfolio_df.index)
|
|
111
|
-
returns = prices_to_returns(price_fx_portfolio_df, drop_inceptions_nan=False, fill_nan=ffill_returns)
|
|
112
|
-
return {dt: row for dt, row in prices_df.replace(np.nan, None).to_dict("index").items()}, returns.replace(
|
|
111
|
+
returns = prices_to_returns(fx_rate_df * prices_df, drop_inceptions_nan=False, fill_nan=ffill_returns)
|
|
112
|
+
return {ts.date(): row for ts, row in prices_df.replace(np.nan, None).to_dict("index").items()}, returns.replace(
|
|
113
113
|
[np.inf, -np.inf, np.nan], 0
|
|
114
114
|
)
|
|
115
115
|
|
|
@@ -403,7 +403,11 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
403
403
|
weights = self.get_weights(val_date)
|
|
404
404
|
return_date = (val_date + BDay(1)).date()
|
|
405
405
|
_, returns = get_returns(
|
|
406
|
-
list(weights.keys()),
|
|
406
|
+
list(weights.keys()),
|
|
407
|
+
(val_date - BDay(MARKET_HOLIDAY_MAX_DURATION)).date(),
|
|
408
|
+
return_date,
|
|
409
|
+
to_currency=self.currency,
|
|
410
|
+
**kwargs,
|
|
407
411
|
)
|
|
408
412
|
if pd.Timestamp(return_date) not in returns.index:
|
|
409
413
|
raise InvalidAnalyticPortfolio()
|
|
@@ -825,7 +829,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
|
|
|
825
829
|
|
|
826
830
|
prices, returns = get_returns(
|
|
827
831
|
instrument_ids,
|
|
828
|
-
(start_date - BDay(
|
|
832
|
+
(start_date - BDay(MARKET_HOLIDAY_MAX_DURATION)).date(),
|
|
829
833
|
end_date,
|
|
830
834
|
to_currency=self.currency,
|
|
831
835
|
ffill_returns=True,
|
|
@@ -397,7 +397,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
397
397
|
if approve_automatically and self.portfolio.can_be_rebalanced:
|
|
398
398
|
self.approve(replay=False, broadcast_changes_at_date=broadcast_changes_at_date)
|
|
399
399
|
|
|
400
|
-
def replay(self,
|
|
400
|
+
def replay(self, broadcast_changes_at_date: bool = True):
|
|
401
401
|
last_trade_proposal = self
|
|
402
402
|
last_trade_proposal_created = False
|
|
403
403
|
while last_trade_proposal and last_trade_proposal.status == TradeProposal.Status.APPROVED:
|
|
@@ -405,7 +405,7 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
405
405
|
logger.info(f"Replaying trade proposal {last_trade_proposal}")
|
|
406
406
|
last_trade_proposal.approve_workflow(
|
|
407
407
|
silent_exception=True,
|
|
408
|
-
force_reset_trade=
|
|
408
|
+
force_reset_trade=True,
|
|
409
409
|
broadcast_changes_at_date=broadcast_changes_at_date,
|
|
410
410
|
)
|
|
411
411
|
last_trade_proposal.save()
|
|
@@ -803,9 +803,8 @@ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
|
|
|
803
803
|
) # we delete the existing portfolio as it has been reverted
|
|
804
804
|
for trade in self.trades.all():
|
|
805
805
|
trade.status = Trade.Status.DRAFT
|
|
806
|
-
trade.drift_factor = Decimal("1")
|
|
807
806
|
trades.append(trade)
|
|
808
|
-
Trade.objects.bulk_update(trades, ["status"
|
|
807
|
+
Trade.objects.bulk_update(trades, ["status"])
|
|
809
808
|
|
|
810
809
|
def can_revert(self):
|
|
811
810
|
errors = dict()
|
|
@@ -439,7 +439,7 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
439
439
|
method=RequestType.PATCH,
|
|
440
440
|
identifiers=("wbportfolio:trade",),
|
|
441
441
|
icon=WBIcon.UNDO.icon,
|
|
442
|
-
key="
|
|
442
|
+
key="revert",
|
|
443
443
|
label="Revert",
|
|
444
444
|
action_label="revert",
|
|
445
445
|
# description_fields="<p>Start: {{start}}</p><p>End: {{end}}</p><p>Title: {{title}}</p>",
|
|
@@ -518,6 +518,11 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
518
518
|
self, "target_weight", round(self._effective_weight + self.weighting, self.TRADE_WEIGHTING_PRECISION)
|
|
519
519
|
)
|
|
520
520
|
|
|
521
|
+
@_target_weight.setter
|
|
522
|
+
def _target_weight(self, target_weight):
|
|
523
|
+
self.weighting = Decimal(target_weight) - self._effective_weight
|
|
524
|
+
self._set_type()
|
|
525
|
+
|
|
521
526
|
@property
|
|
522
527
|
@admin.display(description="Target Shares")
|
|
523
528
|
def _target_shares(self) -> Decimal:
|
|
@@ -558,12 +563,6 @@ class Trade(TransactionMixin, ImportMixin, OrderedModel, models.Model):
|
|
|
558
563
|
]
|
|
559
564
|
# notification_email_template = "portfolio/email/trade_notification.html"
|
|
560
565
|
|
|
561
|
-
def __init__(self, *args, target_weight: Decimal | None = None, **kwargs):
|
|
562
|
-
super().__init__(*args, **kwargs)
|
|
563
|
-
if target_weight is not None: # if target weight is provided, we guess the corresponding weighting
|
|
564
|
-
self.weighting = Decimal(target_weight) - self._effective_weight
|
|
565
|
-
self._set_type()
|
|
566
|
-
|
|
567
566
|
def save(self, *args, **kwargs):
|
|
568
567
|
if abs(self.weighting) < 10e-6:
|
|
569
568
|
self.weighting = Decimal("0")
|
|
@@ -1134,31 +1134,40 @@ class TestPortfolioModel(PortfolioTestMixin):
|
|
|
1134
1134
|
assert res == [index_portfolio, dependency_portfolio, dependant_portfolio, undependant_portfolio]
|
|
1135
1135
|
|
|
1136
1136
|
def test_get_returns(self, instrument_factory, instrument_price_factory, asset_position_factory, portfolio):
|
|
1137
|
-
v1 = date(
|
|
1138
|
-
v2 = date(2025, 1,
|
|
1139
|
-
v3 = date(2025, 1,
|
|
1137
|
+
v1 = date(2024, 12, 31)
|
|
1138
|
+
v2 = date(2025, 1, 1)
|
|
1139
|
+
v3 = date(2025, 1, 2)
|
|
1140
|
+
v4 = date(2025, 1, 3)
|
|
1140
1141
|
|
|
1141
1142
|
i1 = instrument_factory.create()
|
|
1142
1143
|
i2 = instrument_factory.create()
|
|
1143
1144
|
|
|
1144
1145
|
i11 = instrument_price_factory.create(date=v1, instrument=i1)
|
|
1145
1146
|
i12 = instrument_price_factory.create(date=v2, instrument=i1)
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
asset_position_factory.create(date=v3, portfolio=portfolio, underlying_instrument=i2)
|
|
1147
|
+
i14 = instrument_price_factory.create(date=v4, instrument=i1)
|
|
1148
|
+
i21 = instrument_price_factory.create(date=v1, instrument=i2)
|
|
1149
1149
|
i11.refresh_from_db()
|
|
1150
1150
|
i12.refresh_from_db()
|
|
1151
|
-
|
|
1152
|
-
|
|
1151
|
+
i14.refresh_from_db()
|
|
1152
|
+
prices, returns = get_returns([i1.id, i2.id], from_date=v1, to_date=v4)
|
|
1153
1153
|
|
|
1154
1154
|
expected_returns = pd.DataFrame(
|
|
1155
|
-
[[i12.net_value / i11.net_value - 1, 0.0], [
|
|
1156
|
-
index=[v2, v3],
|
|
1155
|
+
[[i12.net_value / i11.net_value - 1, 0.0], [0.0, 0.0], [i14.net_value / i12.net_value - 1, 0.0]],
|
|
1156
|
+
index=[v2, v3, v4],
|
|
1157
1157
|
columns=[i1.id, i2.id],
|
|
1158
1158
|
dtype="float64",
|
|
1159
1159
|
)
|
|
1160
1160
|
expected_returns.index = pd.to_datetime(expected_returns.index)
|
|
1161
1161
|
pd.testing.assert_frame_equal(returns, expected_returns, check_names=False, check_freq=False, atol=1e-6)
|
|
1162
|
+
assert prices[v1][i1.id] == float(i11.net_value)
|
|
1163
|
+
assert prices[v2][i1.id] == float(i12.net_value)
|
|
1164
|
+
assert prices[v3][i1.id] == float(i12.net_value)
|
|
1165
|
+
assert prices[v4][i1.id] == float(i14.net_value)
|
|
1166
|
+
# test that the returned price are ffill
|
|
1167
|
+
assert prices[v1][i2.id] == float(i21.net_value)
|
|
1168
|
+
assert prices[v2][i2.id] == float(i21.net_value)
|
|
1169
|
+
assert prices[v3][i2.id] == float(i21.net_value)
|
|
1170
|
+
assert prices[v4][i2.id] == float(i21.net_value)
|
|
1162
1171
|
|
|
1163
1172
|
@patch.object(Portfolio, "compute_lookthrough", autospec=True)
|
|
1164
1173
|
def test_handle_controlling_portfolio_change_at_date(self, mock_compute_lookthrough, weekday, portfolio_factory):
|
|
@@ -445,14 +445,20 @@ class TradeTradeProposalModelViewSet(
|
|
|
445
445
|
|
|
446
446
|
agg = {
|
|
447
447
|
"effective_weight": {
|
|
448
|
-
"Cash": format_number(cash_sum_effective_weight, decimal=
|
|
449
|
-
"Non-Cash": format_number(noncash_sum_effective_weight, decimal=
|
|
450
|
-
"Total": format_number(
|
|
448
|
+
"Cash": format_number(cash_sum_effective_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
449
|
+
"Non-Cash": format_number(noncash_sum_effective_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
450
|
+
"Total": format_number(
|
|
451
|
+
noncash_sum_effective_weight + cash_sum_effective_weight,
|
|
452
|
+
decimal=Trade.TRADE_WEIGHTING_PRECISION,
|
|
453
|
+
),
|
|
451
454
|
},
|
|
452
455
|
"target_weight": {
|
|
453
|
-
"Cash": format_number(cash_sum_target_cash_weight, decimal=
|
|
454
|
-
"Non-Cash": format_number(noncash_sum_target_weight, decimal=
|
|
455
|
-
"Total": format_number(
|
|
456
|
+
"Cash": format_number(cash_sum_target_cash_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
457
|
+
"Non-Cash": format_number(noncash_sum_target_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
458
|
+
"Total": format_number(
|
|
459
|
+
cash_sum_target_cash_weight + noncash_sum_target_weight,
|
|
460
|
+
decimal=Trade.TRADE_WEIGHTING_PRECISION,
|
|
461
|
+
),
|
|
456
462
|
},
|
|
457
463
|
"effective_total_value_fx_portfolio": {
|
|
458
464
|
"Cash": format_number(cash_sum_effective_total_value_fx_portfolio, decimal=6),
|
|
@@ -471,9 +477,12 @@ class TradeTradeProposalModelViewSet(
|
|
|
471
477
|
),
|
|
472
478
|
},
|
|
473
479
|
"weighting": {
|
|
474
|
-
"Cash Flow": format_number(
|
|
475
|
-
|
|
476
|
-
|
|
480
|
+
"Cash Flow": format_number(
|
|
481
|
+
cash_sum_target_cash_weight - cash_sum_effective_weight,
|
|
482
|
+
decimal=Trade.TRADE_WEIGHTING_PRECISION,
|
|
483
|
+
),
|
|
484
|
+
"Buy": format_number(sum_buy_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
485
|
+
"Sell": format_number(sum_sell_weight, decimal=Trade.TRADE_WEIGHTING_PRECISION),
|
|
477
486
|
},
|
|
478
487
|
"total_value_fx_portfolio": {
|
|
479
488
|
"Cash Flow": format_number(
|
|
@@ -113,7 +113,7 @@ wbportfolio/import_export/handlers/dividend.py,sha256=F0oLfNt2B_QQAjHBCRpxa5HSkf
|
|
|
113
113
|
wbportfolio/import_export/handlers/fees.py,sha256=BOFHAvSTlvVLaxnm6KD_fcza1TlPc02HOR9J0_jjswI,2495
|
|
114
114
|
wbportfolio/import_export/handlers/portfolio_cash_flow.py,sha256=W7QPNqEvvsq0RS016EAFBp1ezvc6G9Rk-hviRZh8o6Y,2737
|
|
115
115
|
wbportfolio/import_export/handlers/register.py,sha256=sYyXkE8b1DPZ5monxylZn0kjxLVdNYYZR-p61dwEoDM,2271
|
|
116
|
-
wbportfolio/import_export/handlers/trade.py,sha256=
|
|
116
|
+
wbportfolio/import_export/handlers/trade.py,sha256=_-P1ImDX6jfObm1WKiLtzz7RXEnXjtARAw7cxoHReCM,12826
|
|
117
117
|
wbportfolio/import_export/parsers/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
118
118
|
wbportfolio/import_export/parsers/default_mapping.py,sha256=KrO-X5CvQCeQoBYzFDxavoQGriyUSeI2QDx5ar_zo7A,1405
|
|
119
119
|
wbportfolio/import_export/parsers/jpmorgan/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
@@ -257,7 +257,7 @@ wbportfolio/models/asset.py,sha256=b0vPt4LwNrxcMiK7UmBKViYnbNNlZzPTagvU5vFuyrc,4
|
|
|
257
257
|
wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
|
|
258
258
|
wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
|
|
259
259
|
wbportfolio/models/indexes.py,sha256=gvW4K9U9Bj8BmVCqFYdWiXvDWhjHINRON8XhNsZUiQY,639
|
|
260
|
-
wbportfolio/models/portfolio.py,sha256=
|
|
260
|
+
wbportfolio/models/portfolio.py,sha256=2m35YgEsF1gkt_JN5O4UlOtNLAqSfKi8JUp0G-1HPmQ,57997
|
|
261
261
|
wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
|
|
262
262
|
wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
|
|
263
263
|
wbportfolio/models/portfolio_relationship.py,sha256=ZGECiPZiLdlk4uSamOrEfuzO0hduK6OMKJLUSnh5_kc,5190
|
|
@@ -284,8 +284,8 @@ wbportfolio/models/transactions/claim.py,sha256=SF2FlwG6SRVmA_hT0NbXah5-fYejccWK
|
|
|
284
284
|
wbportfolio/models/transactions/dividends.py,sha256=mmOdGWR35yndUMoCuG24Y6BdtxDhSk2gMQ-8LVguqzg,1890
|
|
285
285
|
wbportfolio/models/transactions/fees.py,sha256=wJtlzbBCAq1UHvv0wqWTE2BEjCF5RMtoaSDS3kODFRo,7112
|
|
286
286
|
wbportfolio/models/transactions/rebalancing.py,sha256=rwePcmTZOYgfSWnBQcBrZ3DQHRJ3w17hdO_hgrRbbhI,7696
|
|
287
|
-
wbportfolio/models/transactions/trade_proposals.py,sha256=
|
|
288
|
-
wbportfolio/models/transactions/trades.py,sha256=
|
|
287
|
+
wbportfolio/models/transactions/trade_proposals.py,sha256=UYhV2pjQE4V-k0tVTBeZgPPK0C-tBeY345iroDzulfg,38106
|
|
288
|
+
wbportfolio/models/transactions/trades.py,sha256=oAUWCPPdBcMf5bcYI6BwvnrFKK588ZLRHPyPr65h-0U,33966
|
|
289
289
|
wbportfolio/models/transactions/transactions.py,sha256=XTcUeMUfkf5XTSZaR2UAyGqCVkOhQYk03_vzHLIgf8Q,3807
|
|
290
290
|
wbportfolio/pms/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
291
291
|
wbportfolio/pms/typing.py,sha256=BV4dzazNHdfpfLV99bLVyYGcETmbQSnFV6ipc4fNKfg,8470
|
|
@@ -380,7 +380,7 @@ wbportfolio/tests/models/test_merge.py,sha256=sdsjiZsmR6vsUKwTa5kkvL6QTeAZqtd_EP
|
|
|
380
380
|
wbportfolio/tests/models/test_portfolio_cash_flow.py,sha256=X8dsXexsb1b0lBiuGzu40ps_Az_1UmmKT0eo1vbXH94,5792
|
|
381
381
|
wbportfolio/tests/models/test_portfolio_cash_targets.py,sha256=q8QWAwt-kKRkLC0E05GyRhF_TTQXIi8bdHjXVU0fCV0,965
|
|
382
382
|
wbportfolio/tests/models/test_portfolio_swing_pricings.py,sha256=kr2AOcQkyg2pX3ULjU-o9ye-NVpjMrrfoe-DVbYCbjs,1656
|
|
383
|
-
wbportfolio/tests/models/test_portfolios.py,sha256=
|
|
383
|
+
wbportfolio/tests/models/test_portfolios.py,sha256=sWbt9NE8Cludu7hUhxxnIJwOSQ_U_yC6UPFPkbpV8Qk,54010
|
|
384
384
|
wbportfolio/tests/models/test_product_groups.py,sha256=AcdxhurV-n_bBuUsfD1GqVtwLFcs7VI2CRrwzsIUWbU,3337
|
|
385
385
|
wbportfolio/tests/models/test_products.py,sha256=IcBzw9hrGiWFMRwPBTMukCMWrhqnjOVA2hhb90xYOW8,9580
|
|
386
386
|
wbportfolio/tests/models/test_roles.py,sha256=4Cn7WyrA2ztJNeWLk5cy9kYo5XLWMbFSvo1O-9JYxeA,3323
|
|
@@ -521,8 +521,8 @@ wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0
|
|
|
521
521
|
wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
|
|
522
522
|
wbportfolio/viewsets/transactions/rebalancing.py,sha256=6rIrdK0rtKL1afJ-tYfAGdQVTN2MH1kG_yCeVkmyK8k,1263
|
|
523
523
|
wbportfolio/viewsets/transactions/trade_proposals.py,sha256=kQCojTNKBEyn2NcenL3a9auzBH4sIgLEx8rLAYCGLGg,6161
|
|
524
|
-
wbportfolio/viewsets/transactions/trades.py,sha256=
|
|
525
|
-
wbportfolio-1.54.
|
|
526
|
-
wbportfolio-1.54.
|
|
527
|
-
wbportfolio-1.54.
|
|
528
|
-
wbportfolio-1.54.
|
|
524
|
+
wbportfolio/viewsets/transactions/trades.py,sha256=Y8v2cM0vpspHysaAvu8qqhzt86dNtb2Q3puo4HCJsTI,22629
|
|
525
|
+
wbportfolio-1.54.10.dist-info/METADATA,sha256=uKqFJps-zs7857cq_8X_JmogU7gB5LG3RaZORctTI-k,703
|
|
526
|
+
wbportfolio-1.54.10.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
|
|
527
|
+
wbportfolio-1.54.10.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
|
|
528
|
+
wbportfolio-1.54.10.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|