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

@@ -5,7 +5,6 @@ from unittest.mock import patch
5
5
 
6
6
  import pandas as pd
7
7
  import pytest
8
- from django.contrib.contenttypes.models import ContentType
9
8
  from django.db.models import F, Sum
10
9
  from django.forms.models import model_to_dict
11
10
  from faker import Faker
@@ -20,9 +19,8 @@ from wbportfolio.models import (
20
19
  PortfolioPortfolioThroughModel,
21
20
  Trade,
22
21
  )
23
- from wbportfolio.models.asset import AssetPositionIterator
24
22
 
25
- from ...models.portfolio import get_returns, update_portfolio_after_investable_universe
23
+ from ...models.portfolio import update_portfolio_after_investable_universe
26
24
  from .utils import PortfolioTestMixin
27
25
 
28
26
  fake = Faker()
@@ -264,7 +262,9 @@ class TestPortfolioModel(PortfolioTestMixin):
264
262
  for pos in AssetPosition.objects.all():
265
263
  assert float(pos.weighting) == pytest.approx(float(pos.total_value_fx_portfolio / total_value), rel=1e-2)
266
264
 
267
- mock_estimate_net_asset_values.assert_called_once_with(portfolio, (weekday + BDay(1)).date(), weights=None)
265
+ mock_estimate_net_asset_values.assert_called_once_with(
266
+ portfolio, (weekday + BDay(1)).date(), analytic_portfolio=None
267
+ )
268
268
 
269
269
  @patch.object(Portfolio, "compute_lookthrough", autospec=True)
270
270
  def test_change_at_date_with_dependent_portfolio(
@@ -285,9 +285,6 @@ class TestPortfolioModel(PortfolioTestMixin):
285
285
  mock_compute_lookthrough.assert_called_once_with(
286
286
  dependent_portfolio,
287
287
  weekday,
288
- recompute_weighting=False,
289
- force_recompute_weighting=False,
290
- changed_weights=None,
291
288
  )
292
289
 
293
290
  def test_is_active_at_date(
@@ -1005,12 +1002,10 @@ class TestPortfolioModel(PortfolioTestMixin):
1005
1002
  fx_instrument = currency_fx_rates_factory.create(currency=instrument.currency, date=weekday)
1006
1003
  instrument_id: int = instrument.id
1007
1004
  weights = {instrument_id: random.random()}
1008
- positions = AssetPositionIterator(
1009
- portfolio, prices={weekday: {instrument_id: p.net_value}}, infer_underlying_quote_price=False
1010
- )
1011
- positions.add((weekday, weights))
1005
+ portfolio.builder.set_prices({weekday: {instrument_id: p.net_value}})
1006
+ portfolio.builder.add((weekday, weights), infer_underlying_quote_price=False)
1012
1007
 
1013
- res = list(positions)
1008
+ res = list(portfolio.builder.get_positions())
1014
1009
  a = res[0]
1015
1010
  assert len(res) == 1
1016
1011
  assert a.date == weekday
@@ -1053,35 +1048,34 @@ class TestPortfolioModel(PortfolioTestMixin):
1053
1048
  asset_position_factory.create(date=weekday, portfolio=portfolio, underlying_instrument=i2, weighting=0.3)
1054
1049
 
1055
1050
  rebalancer_factory.create(portfolio=portfolio, frequency="RRULE:FREQ=DAILY;", activation_date=rebalancing_date)
1056
- positions, rebalancing_order_proposal = portfolio.drift_weights(
1057
- weekday, (rebalancing_date + BDay(1)).date(), stop_at_rebalancing=True
1058
- )
1059
- assert rebalancing_order_proposal.trade_date == rebalancing_date
1060
- assert rebalancing_order_proposal.status == "SUBMIT"
1061
- assert set(positions.get_weights().keys()) == {
1062
- middle_date,
1063
- }, "Drifting weight with a non automatic rebalancer stops the iteration"
1064
-
1065
- # we expect a equally rebalancing (default) so both orders needs to be created
1066
- orders = rebalancing_order_proposal.get_orders()
1067
- t1 = orders.get(value_date=rebalancing_date, underlying_instrument=i1)
1068
- t2 = orders.get(value_date=rebalancing_date, underlying_instrument=i2)
1069
- assert t1._target_weight == Decimal("0.5")
1070
- assert t2._target_weight == Decimal("0.5")
1071
-
1072
- # we approve the rebalancing order proposal
1073
- assert rebalancing_order_proposal.status == "SUBMIT"
1074
- rebalancing_order_proposal.approve(replay=False)
1075
- rebalancing_order_proposal.save()
1051
+ portfolio.load_builder_returns(weekday, rebalancing_date)
1052
+ gen = portfolio.drift_weights(weekday, (rebalancing_date + BDay(1)).date(), stop_at_rebalancing=True)
1053
+ assert next(gen)[0] == middle_date, "Drifting weight with a non automatic rebalancer stops the iteration"
1054
+ try:
1055
+ next(gen)
1056
+ assert False, "the next iteration should stop and return the rebalancing"
1057
+ except StopIteration as e:
1058
+ rebalancing_order_proposal = e.value
1059
+ assert rebalancing_order_proposal.trade_date == rebalancing_date
1060
+ assert rebalancing_order_proposal.status == "SUBMIT"
1061
+
1062
+ # we expect a equally rebalancing (default) so both orders needs to be created
1063
+ orders = rebalancing_order_proposal.get_orders()
1064
+ t1 = orders.get(value_date=rebalancing_date, underlying_instrument=i1)
1065
+ t2 = orders.get(value_date=rebalancing_date, underlying_instrument=i2)
1066
+ assert t1._target_weight == Decimal("0.5")
1067
+ assert t2._target_weight == Decimal("0.5")
1068
+
1069
+ # we approve the rebalancing order proposal
1070
+ assert rebalancing_order_proposal.status == "SUBMIT"
1071
+ rebalancing_order_proposal.approve(replay=False)
1072
+ rebalancing_order_proposal.save()
1076
1073
 
1077
1074
  # check that the rebalancing was applied and position reflect that
1078
1075
  assert portfolio.assets.get(date=rebalancing_date, underlying_instrument=i1).weighting == Decimal("0.5")
1079
1076
  assert portfolio.assets.get(date=rebalancing_date, underlying_instrument=i2).weighting == Decimal("0.5")
1080
1077
 
1081
- @patch("wbportfolio.models.portfolio.compute_metrics_as_task.delay")
1082
- def test_bulk_create_positions(
1083
- self, mock_compute_metrics, portfolio, weekday, asset_position_factory, instrument_factory
1084
- ):
1078
+ def test_bulk_create_positions(self, portfolio, weekday, asset_position_factory, instrument_factory):
1085
1079
  portfolio.is_manageable = False
1086
1080
  portfolio.save()
1087
1081
  i1 = instrument_factory.create()
@@ -1090,21 +1084,17 @@ class TestPortfolioModel(PortfolioTestMixin):
1090
1084
  a1 = asset_position_factory.build(date=weekday, portfolio=portfolio, underlying_instrument=i1)
1091
1085
 
1092
1086
  # check initial creation
1093
- portfolio.bulk_create_positions(AssetPositionIterator(portfolio).add([a1]), compute_metrics=True)
1087
+ portfolio.builder.add([a1]).bulk_create_positions(compute_metrics=True)
1094
1088
  assert AssetPosition.objects.get(portfolio=portfolio, date=weekday).weighting == a1.weighting
1095
1089
  assert AssetPosition.objects.get(portfolio=portfolio, date=weekday).underlying_instrument == i1
1096
1090
 
1097
- mock_compute_metrics.assert_called_once_with(
1098
- weekday, basket_id=portfolio.id, basket_content_type_id=ContentType.objects.get_for_model(Portfolio).id
1099
- )
1100
-
1101
1091
  # check that if we change key value, an already exising position will be updated accordingly
1102
1092
  a1.weighting = Decimal(0.5)
1103
- portfolio.bulk_create_positions(AssetPositionIterator(portfolio).add([a1]))
1093
+ portfolio.builder.add([a1]).bulk_create_positions()
1104
1094
  assert AssetPosition.objects.get(portfolio=portfolio, date=weekday).weighting == Decimal(0.5)
1105
1095
 
1106
1096
  a2 = asset_position_factory.build(date=weekday, portfolio=portfolio, underlying_instrument=i2)
1107
- portfolio.bulk_create_positions(AssetPositionIterator(portfolio).add([a2]))
1097
+ portfolio.builder.add([a2]).bulk_create_positions()
1108
1098
  assert (
1109
1099
  AssetPosition.objects.get(portfolio=portfolio, date=weekday, underlying_instrument=i1).weighting
1110
1100
  == a1.weighting
@@ -1115,7 +1105,7 @@ class TestPortfolioModel(PortfolioTestMixin):
1115
1105
  )
1116
1106
 
1117
1107
  a3 = asset_position_factory.build(date=weekday, portfolio=portfolio, underlying_instrument=i3)
1118
- portfolio.bulk_create_positions(AssetPositionIterator(portfolio).add([a3]), delete_leftovers=True)
1108
+ portfolio.builder.add([a3]).bulk_create_positions(delete_leftovers=True)
1119
1109
  assert AssetPosition.objects.get(portfolio=portfolio, date=weekday).weighting == a3.weighting
1120
1110
  assert AssetPosition.objects.get(portfolio=portfolio, date=weekday).underlying_instrument == i3
1121
1111
 
@@ -1134,83 +1124,6 @@ class TestPortfolioModel(PortfolioTestMixin):
1134
1124
  res = list(Portfolio.objects.all().to_dependency_iterator(weekday))
1135
1125
  assert res == [index_portfolio, dependency_portfolio, dependant_portfolio, undependant_portfolio]
1136
1126
 
1137
- def test_get_returns(self, instrument_factory, instrument_price_factory, asset_position_factory, portfolio):
1138
- v1 = date(2024, 12, 31)
1139
- v2 = date(2025, 1, 1)
1140
- v3 = date(2025, 1, 2)
1141
- v4 = date(2025, 1, 3)
1142
-
1143
- i1 = instrument_factory.create()
1144
- i2 = instrument_factory.create()
1145
-
1146
- i11 = instrument_price_factory.create(date=v1, instrument=i1)
1147
- i12 = instrument_price_factory.create(date=v2, instrument=i1)
1148
- i14 = instrument_price_factory.create(date=v4, instrument=i1)
1149
- i21 = instrument_price_factory.create(date=v1, instrument=i2)
1150
- i11.refresh_from_db()
1151
- i12.refresh_from_db()
1152
- i14.refresh_from_db()
1153
- prices, returns = get_returns([i1.id, i2.id], from_date=v1, to_date=v4)
1154
-
1155
- expected_returns = pd.DataFrame(
1156
- [[i12.net_value / i11.net_value - 1, 0.0], [0.0, 0.0], [i14.net_value / i12.net_value - 1, 0.0]],
1157
- index=[v2, v3, v4],
1158
- columns=[i1.id, i2.id],
1159
- dtype="float64",
1160
- )
1161
- expected_returns.index = pd.to_datetime(expected_returns.index)
1162
- pd.testing.assert_frame_equal(returns, expected_returns, check_names=False, check_freq=False, atol=1e-6)
1163
- assert prices[v1][i1.id] == float(i11.net_value)
1164
- assert prices[v2][i1.id] == float(i12.net_value)
1165
- assert prices[v3][i1.id] == float(i12.net_value)
1166
- assert prices[v4][i1.id] == float(i14.net_value)
1167
- # test that the returned price are ffill
1168
- assert prices[v1][i2.id] == float(i21.net_value)
1169
- assert prices[v2][i2.id] == float(i21.net_value)
1170
- assert prices[v3][i2.id] == float(i21.net_value)
1171
- assert prices[v4][i2.id] == float(i21.net_value)
1172
-
1173
- def test_get_returns_fix_forex_on_holiday(
1174
- self, instrument, instrument_price_factory, currency_fx_rates_factory, currency_factory
1175
- ):
1176
- v1 = date(2024, 12, 31)
1177
- v2 = date(2025, 1, 1)
1178
- v3 = date(2025, 1, 2)
1179
-
1180
- target_currency = currency_factory.create()
1181
- fx_target1 = currency_fx_rates_factory.create(currency=target_currency, date=v1)
1182
- fx_target2 = currency_fx_rates_factory.create(currency=target_currency, date=v2) # noqa
1183
- fx_target3 = currency_fx_rates_factory.create(currency=target_currency, date=v3)
1184
-
1185
- fx1 = currency_fx_rates_factory.create(currency=instrument.currency, date=v1)
1186
- fx2 = currency_fx_rates_factory.create(currency=instrument.currency, date=v2) # noqa
1187
- fx3 = currency_fx_rates_factory.create(currency=instrument.currency, date=v3)
1188
-
1189
- i1 = instrument_price_factory.create(net_value=Decimal("100"), date=v1, instrument=instrument)
1190
- i2 = instrument_price_factory.create(net_value=Decimal("100"), date=v2, instrument=instrument, calculated=True)
1191
- i3 = instrument_price_factory.create(net_value=Decimal("200"), date=v3, instrument=instrument)
1192
-
1193
- prices, returns = get_returns([instrument.id], from_date=v1, to_date=v3, to_currency=target_currency)
1194
- returns.index = pd.to_datetime(returns.index)
1195
- assert prices[v1][instrument.id] == float(i1.net_value)
1196
- assert prices[v2][instrument.id] == float(i2.net_value)
1197
- assert prices[v3][instrument.id] == float(i3.net_value)
1198
-
1199
- assert returns.loc[pd.Timestamp(v2), instrument.id] == pytest.approx(
1200
- float(
1201
- (i2.net_value * fx_target1.value / fx1.value) / (i1.net_value * fx_target1.value / fx1.value)
1202
- - Decimal("1")
1203
- ),
1204
- abs=10e-8,
1205
- ) # as v2 as a calculated price, the forex won't apply to it
1206
- assert returns.loc[pd.Timestamp(v3), instrument.id] == pytest.approx(
1207
- float(
1208
- (i3.net_value * fx_target3.value / fx3.value) / (i2.net_value * fx_target1.value / fx1.value)
1209
- - Decimal("1")
1210
- ),
1211
- abs=10e-8,
1212
- )
1213
-
1214
1127
  @patch.object(Portfolio, "compute_lookthrough", autospec=True)
1215
1128
  def test_handle_controlling_portfolio_change_at_date(self, mock_compute_lookthrough, weekday, portfolio_factory):
1216
1129
  primary_portfolio = portfolio_factory.create(only_weighting=True)
@@ -15,6 +15,7 @@ class OrderProposalDisplayConfig(DisplayViewConfig):
15
15
  return dp.ListDisplay(
16
16
  fields=[
17
17
  dp.Field(key="trade_date", label="Order Date"),
18
+ dp.Field(key="rebalancing_model", label="Rebalancing Model"),
18
19
  dp.Field(key="comment", label="Comment"),
19
20
  ],
20
21
  legends=[
@@ -86,12 +87,12 @@ class OrderProposalDisplayConfig(DisplayViewConfig):
86
87
  layouts={
87
88
  default(): Layout(
88
89
  grid_template_areas=[
89
- ["status", "status"],
90
- ["trade_date", "total_cash_weight"],
91
- ["rebalancing_model", "target_portfolio"]
90
+ ["status", "status", "status"],
91
+ ["trade_date", "total_cash_weight", "min_order_value"],
92
+ ["rebalancing_model", "target_portfolio", "target_portfolio"]
92
93
  if self.view.new_mode
93
- else ["rebalancing_model", "rebalancing_model"],
94
- ["comment", "comment"],
94
+ else ["rebalancing_model", "rebalancing_model", "rebalancing_model"],
95
+ ["comment", "comment", "comment"],
95
96
  ],
96
97
  ),
97
98
  },
@@ -150,7 +150,7 @@ class OrderOrderProposalModelViewSet(
150
150
  },
151
151
  "weighting": {
152
152
  "Cash Flow": format_number(
153
- cash_sum_target_cash_weight - cash_sum_effective_weight,
153
+ sum_sell_weight + sum_buy_weight,
154
154
  decimal=Order.ORDER_WEIGHTING_PRECISION,
155
155
  ),
156
156
  "Buy": format_number(sum_buy_weight, decimal=Order.ORDER_WEIGHTING_PRECISION),
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.54.20
3
+ Version: 1.54.21
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -262,14 +262,17 @@ wbportfolio/migrations/0080_alter_trade_drift_factor_alter_trade_weighting.py,sh
262
262
  wbportfolio/migrations/0081_alter_trade_drift_factor.py,sha256=rF3HA1MQJ0hltr0dExJAx47w8XxUCWRbDUyxQLoQB2I,656
263
263
  wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py,sha256=DZBKD0LG1aXQ2bR7UwYwdVobiCCtKDBMLHDZRmFQRKQ,4108
264
264
  wbportfolio/migrations/0083_order_alter_trade_options_and_more.py,sha256=oFYG2cVf2CFKFJX84eUSmGJdK1BHY_QcVm_hmAIbVNg,9952
265
+ wbportfolio/migrations/0084_orderproposal_min_order_value.py,sha256=bJPpPX7PQmlWAIyLzZ6ca6K0paGTRbzS8AkyOHDoGMc,925
266
+ wbportfolio/migrations/0085_order_desired_target_weight.py,sha256=L8p5t4PqjWIwqwiqt-ofdfGkBhm-7dtbg52cIkxNnDs,803
265
267
  wbportfolio/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
266
268
  wbportfolio/models/__init__.py,sha256=qU4e7HKyh8NL_0Mg92PcbHTewCv7Ya2gei1DMGe1LWE,980
267
269
  wbportfolio/models/adjustments.py,sha256=osXWkJZOiansPWYPyHtl7Z121zDWi7u1YMtrBQtbHVo,10272
268
- wbportfolio/models/asset.py,sha256=b0vPt4LwNrxcMiK7UmBKViYnbNNlZzPTagvU5vFuyrc,45685
270
+ wbportfolio/models/asset.py,sha256=PwL16w2Rw_rJL73e0vCWMlRqsCxKW4zA9bf1EgTzD60,39574
271
+ wbportfolio/models/builder.py,sha256=n4__dW8L3hiM8U2_xhUPmR3Gt67pDI0vv5fejzoqah8,11536
269
272
  wbportfolio/models/custodians.py,sha256=owTiS2Vm5CRKzh9M_P9GOVg-s-ndQ9UvRmw3yZP7cw0,3815
270
273
  wbportfolio/models/exceptions.py,sha256=3ix0tWUO-O6jpz8f07XIwycw2x3JFRoWzjwil8FVA2Q,52
271
274
  wbportfolio/models/indexes.py,sha256=gvW4K9U9Bj8BmVCqFYdWiXvDWhjHINRON8XhNsZUiQY,639
272
- wbportfolio/models/portfolio.py,sha256=b0YL4dytrEeHRt7VLn1uJYb_47vRKFYiq9Y_6JLrIJU,58419
275
+ wbportfolio/models/portfolio.py,sha256=XIRR2r0yDgE1zdZ5WZUeaas0ZdRGOm0Ps6bvkgg7fQc,53046
273
276
  wbportfolio/models/portfolio_cash_flow.py,sha256=uElG7IJUBY8qvtrXftOoskX6EA-dKgEG1JJdvHeWV7g,7336
274
277
  wbportfolio/models/portfolio_cash_targets.py,sha256=WmgG-etPisZsh2yaFQpz7EkpvAudKBEzqPsO715w52U,1498
275
278
  wbportfolio/models/portfolio_relationship.py,sha256=ZGECiPZiLdlk4uSamOrEfuzO0hduK6OMKJLUSnh5_kc,5190
@@ -289,8 +292,8 @@ wbportfolio/models/mixins/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJW
289
292
  wbportfolio/models/mixins/instruments.py,sha256=SgBreTpa_X3uyCWo7t8B0VaTtl49IjmBMe4Pab6TjAM,6796
290
293
  wbportfolio/models/mixins/liquidity_stress_test.py,sha256=iQVzT3QM7VtHnqfj9gT6KUIe4wC4MJXery-AXJHUYns,58820
291
294
  wbportfolio/models/orders/__init__.py,sha256=EH9UacGR3npBMje5FGTeLOh1xqFBh9kc24WbGmBIA3g,69
292
- wbportfolio/models/orders/order_proposals.py,sha256=uAOPhCUPcCBkAwGPCS0b9JEpwLfnGdJfXM6z8btfzvg,39882
293
- wbportfolio/models/orders/orders.py,sha256=5XKU5NNLlrB0ydQtVGm_woDagt_Qo7IMZhc7GcrQ_lI,9481
295
+ wbportfolio/models/orders/order_proposals.py,sha256=nKzeHPcSQav4KkaUXUBWJVxd8ku3GmG5KQKyQ3cvIUM,40467
296
+ wbportfolio/models/orders/orders.py,sha256=8vYyAV1S2ATVD3Ve_Cjtms_mj564yu5pvfK6wtqQx3A,9664
294
297
  wbportfolio/models/reconciliations/__init__.py,sha256=MXH5fZIPGDRBgJkO6wVu_NLRs8fkP1im7G6d-h36lQY,127
295
298
  wbportfolio/models/reconciliations/account_reconciliation_lines.py,sha256=QP6M7hMcyFbuXBa55Y-azui6Dl_WgbzMntEqWzQkbfM,7394
296
299
  wbportfolio/models/reconciliations/account_reconciliations.py,sha256=rofSxetFfEJov6mPyoTvGxELA16HILyJZtQvm_kwYU0,4405
@@ -361,7 +364,7 @@ wbportfolio/serializers/registers.py,sha256=zhdKH_mHEBE0VOhm6xpY54bTMtcSaY5BskEa
361
364
  wbportfolio/serializers/roles.py,sha256=T-9NqTldpvaEMFy-Bib5MB6MeboygEOqcMP61mzzD3Q,2146
362
365
  wbportfolio/serializers/signals.py,sha256=hD6R4oFtwhvnsJPteytPKy2JwEelmxrapdfoLSnluaE,7053
363
366
  wbportfolio/serializers/orders/__init__.py,sha256=PKJRksA1pWsh8nVfGASoB0m3LyUzVRnq1m9VPp90J7k,271
364
- wbportfolio/serializers/orders/order_proposals.py,sha256=FegiVe1d1AZoLtOuNOUfLN7HwGy4mKGrdYHKDwuUjPY,4430
367
+ wbportfolio/serializers/orders/order_proposals.py,sha256=MmL8noS2qqyKKXiYLLPRS4_Cz1RhlfdFwkCKZiqRyxQ,4461
365
368
  wbportfolio/serializers/orders/orders.py,sha256=pAKjJLRANOo1iMlcv18twuQ0aAVDVKYt-pPx6avnWRQ,7464
366
369
  wbportfolio/serializers/transactions/__init__.py,sha256=-7Pan4n7YI3iDvGXff6okzk4ycEURRxp5n_SHCY_g_I,493
367
370
  wbportfolio/serializers/transactions/claim.py,sha256=kC4E2RZRrpd9i8tGfoiV-gpWDk3ikR5F1Wf0v_IGIvw,11599
@@ -397,14 +400,14 @@ wbportfolio/tests/models/test_merge.py,sha256=sdsjiZsmR6vsUKwTa5kkvL6QTeAZqtd_EP
397
400
  wbportfolio/tests/models/test_portfolio_cash_flow.py,sha256=X8dsXexsb1b0lBiuGzu40ps_Az_1UmmKT0eo1vbXH94,5792
398
401
  wbportfolio/tests/models/test_portfolio_cash_targets.py,sha256=q8QWAwt-kKRkLC0E05GyRhF_TTQXIi8bdHjXVU0fCV0,965
399
402
  wbportfolio/tests/models/test_portfolio_swing_pricings.py,sha256=kr2AOcQkyg2pX3ULjU-o9ye-NVpjMrrfoe-DVbYCbjs,1656
400
- wbportfolio/tests/models/test_portfolios.py,sha256=yh5CgeDH15zFxgnV1KzPl_YQTfaH3hRIG3mXLs9GfRU,56156
403
+ wbportfolio/tests/models/test_portfolios.py,sha256=VdfkblwSow1w-HLFto8wssuBTjSqaCBpE1_Tf6wb0R0,51878
401
404
  wbportfolio/tests/models/test_product_groups.py,sha256=AcdxhurV-n_bBuUsfD1GqVtwLFcs7VI2CRrwzsIUWbU,3337
402
405
  wbportfolio/tests/models/test_products.py,sha256=IcBzw9hrGiWFMRwPBTMukCMWrhqnjOVA2hhb90xYOW8,9580
403
406
  wbportfolio/tests/models/test_roles.py,sha256=4Cn7WyrA2ztJNeWLk5cy9kYo5XLWMbFSvo1O-9JYxeA,3323
404
407
  wbportfolio/tests/models/test_splits.py,sha256=ytKcHsI_90kj1L4s8It-KEcc24rkDcElxwQ8q0QxEvk,9689
405
408
  wbportfolio/tests/models/utils.py,sha256=ORNJq6NMo1Za22jGZXfTfKeNEnTRlfEt_8SJ6xLaQWg,325
406
409
  wbportfolio/tests/models/orders/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
407
- wbportfolio/tests/models/orders/test_order_proposals.py,sha256=FJCP2Gj1eRQb1X7pqiWxGJk4a1qOdVTzE-aRL71fOYk,30773
410
+ wbportfolio/tests/models/orders/test_order_proposals.py,sha256=T0vo7D65E0Cyqhwq3QK_Fd6RlCzCJRZSbA0PSZft0k4,31316
408
411
  wbportfolio/tests/models/transactions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
409
412
  wbportfolio/tests/models/transactions/test_claim.py,sha256=NG3BKB-FVcIDgHSJHCjImxgMM3ISVUMl24xUPmEcPec,5570
410
413
  wbportfolio/tests/models/transactions/test_fees.py,sha256=tAp18x2wCNQr11LUnLtHNbBDbbX0v1DZnmW7i-cEi5Q,2423
@@ -533,13 +536,13 @@ wbportfolio/viewsets/configs/titles/roles.py,sha256=9LoJa3jgenXJ5UWRlIErTzdbjpSW
533
536
  wbportfolio/viewsets/configs/titles/trades.py,sha256=29XCLxvY0Xe3a2tjCno3tN2rRXCr9RWpbWnzurJfnYI,1986
534
537
  wbportfolio/viewsets/orders/__init__.py,sha256=N8v9jdEXryOzrLlc7ML3iBCO2lmNXph9_TWoQ7PTvi4,195
535
538
  wbportfolio/viewsets/orders/order_proposals.py,sha256=mw385zzU52nCq8p6xgionh43xLmOn5aX-2BPlCHnqlE,6214
536
- wbportfolio/viewsets/orders/orders.py,sha256=uqEE22CZkcatSWtZgoqskK_7tV8m_-rTfH75_jFb5Lc,10874
539
+ wbportfolio/viewsets/orders/orders.py,sha256=u3tRqio-oCnmqhC5jmn_EDKoNrF1xXMgOu2c2BfqNS8,10851
537
540
  wbportfolio/viewsets/orders/configs/__init__.py,sha256=5MU57JXiKi32_PicHtiNr7YHmMN020FrlF5NFJf_Wds,94
538
541
  wbportfolio/viewsets/orders/configs/buttons/__init__.py,sha256=EHzNmAfa0UQFITEF-wxj_s4wn3Y5DE3DCbEUmmvCTIs,106
539
542
  wbportfolio/viewsets/orders/configs/buttons/order_proposals.py,sha256=Q_7LrsuLzjSXCIoscFQXMMHl8cuCporDNM5k735W7d8,3584
540
543
  wbportfolio/viewsets/orders/configs/buttons/orders.py,sha256=GDO4Y33wkjhDxzpf7B1d_rKzAixegLv5rHam1DV3WkM,290
541
544
  wbportfolio/viewsets/orders/configs/displays/__init__.py,sha256=__YJBbz_ZnKpE8WMMDR2PC9Nng-EVlRpGTEQucdrhRA,108
542
- wbportfolio/viewsets/orders/configs/displays/order_proposals.py,sha256=UL6yaNh9DuUFSSwur4brMBPyjKGxxtZg-W8iZxuB3Y0,4826
545
+ wbportfolio/viewsets/orders/configs/displays/order_proposals.py,sha256=Iy195FwD2KGxxNWYspAj7CKQ0assL_wtQx0hN7KMz9o,4985
543
546
  wbportfolio/viewsets/orders/configs/displays/orders.py,sha256=8YW5Sncmowl5eLbnuUkD5xQXnP4P3vM6aBXNvolFG1s,7007
544
547
  wbportfolio/viewsets/orders/configs/endpoints/__init__.py,sha256=IB8GEadiEtBDclhkgpcJGXWfCF6qRK_42hxJ4pcdZDU,148
545
548
  wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py,sha256=fY3y2YWR9nY-KE8k078NszDsnwOgqOIjHUgLvQjDivU,822
@@ -551,7 +554,7 @@ wbportfolio/viewsets/transactions/claim.py,sha256=Pb1WftoO-w-ZSTbLRhmQubhy7hgd68
551
554
  wbportfolio/viewsets/transactions/fees.py,sha256=WT2bWWfgozz4_rpyTKX7dgBBTXD-gu0nlsd2Nk2Zh1Q,7028
552
555
  wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIHUIroVkK10FYw7k,636
553
556
  wbportfolio/viewsets/transactions/trades.py,sha256=xBgOGaJ8aEg-2RxEJ4FDaBs4SGwuLasun3nhpis0WQY,12363
554
- wbportfolio-1.54.20.dist-info/METADATA,sha256=btEl2kgx_48zUSM1dteAkvv7d9dhxE7CC7bIN1idLl0,703
555
- wbportfolio-1.54.20.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
556
- wbportfolio-1.54.20.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
557
- wbportfolio-1.54.20.dist-info/RECORD,,
557
+ wbportfolio-1.54.21.dist-info/METADATA,sha256=5NHNRB4-w5pyBzzP936g_zkFz86kNs3OXQBj7qBTNa8,703
558
+ wbportfolio-1.54.21.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
559
+ wbportfolio-1.54.21.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
560
+ wbportfolio-1.54.21.dist-info/RECORD,,