wbportfolio 1.54.7__py2.py3-none-any.whl → 1.54.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.

@@ -158,9 +158,13 @@ class TradeImportHandler(ImportExportHandler):
158
158
  self.import_source.log += "\nNo trade was successfully matched."
159
159
 
160
160
  def _get_history(self, history: Dict[str, Any]) -> models.QuerySet:
161
+ from wbportfolio.models.transactions.trade_proposals import TradeProposal
162
+
161
163
  if trade_proposal_id := history.get("trade_proposal_id"):
162
164
  # if a trade proposal is provided, we delete the existing history first as otherwise, it would mess with the target weight computation
163
- self.model.objects.filter(trade_proposal_id=trade_proposal_id).delete()
165
+ trade_proposal = TradeProposal.objects.get(id=trade_proposal_id)
166
+ trade_proposal.trades.all().delete()
167
+ trade_proposal.reset_trades()
164
168
  trades = self.model.objects.none()
165
169
  else:
166
170
  trades = self.model.objects.filter(
@@ -94,22 +94,19 @@ def get_returns(
94
94
  df = pd.DataFrame(Instrument.objects.filter(id__in=instrument_ids).dl.market_data(**kwargs))
95
95
  if df.empty:
96
96
  raise InvalidAnalyticPortfolio()
97
- fx_rate_df = df[["instrument_id", "fx_rate", "valuation_date"]].pivot(
98
- index="valuation_date", columns="instrument_id", values="fx_rate"
97
+ df = df[["instrument_id", "fx_rate", "close", "valuation_date"]].pivot(
98
+ index="valuation_date", columns="instrument_id", values=["fx_rate", "close"]
99
99
  )
100
-
101
- prices_df = df[["instrument_id", "close", "valuation_date"]].pivot(
102
- index="valuation_date", columns="instrument_id", values="close"
103
- )
104
- price_fx_portfolio_df = fx_rate_df * prices_df
105
-
106
- ts = pd.bdate_range(price_fx_portfolio_df.index.min(), price_fx_portfolio_df.index.max(), freq="B")
107
- price_fx_portfolio_df = price_fx_portfolio_df.reindex(ts)
100
+ ts = pd.bdate_range(df.index.min(), df.index.max(), freq="B")
101
+ df = df.reindex(ts)
108
102
  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(
103
+ df = df.ffill()
104
+ df.index = pd.to_datetime(df.index)
105
+
106
+ prices_df = df["close"]
107
+ fx_rate_df = df["fx_rate"]
108
+ returns = prices_to_returns(fx_rate_df * prices_df, drop_inceptions_nan=False, fill_nan=ffill_returns)
109
+ return {ts.date(): row for ts, row in prices_df.replace(np.nan, None).to_dict("index").items()}, returns.replace(
113
110
  [np.inf, -np.inf, np.nan], 0
114
111
  )
115
112
 
@@ -1095,6 +1092,7 @@ class Portfolio(DeleteToDisableMixin, WBModel):
1095
1092
  )
1096
1093
  if broadcast_changes_at_date:
1097
1094
  for update_date, changed_weights in positions.get_weights().items():
1095
+ kwargs.pop("changed_weights", None)
1098
1096
  self.change_at_date(update_date, changed_weights=changed_weights, **kwargs)
1099
1097
 
1100
1098
  @classmethod
@@ -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(2025, 1, 1)
1138
- v2 = date(2025, 1, 2)
1139
- v3 = date(2025, 1, 3)
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
- i13 = instrument_price_factory.create(date=v3, instrument=i1)
1147
- asset_position_factory.create(date=v1, portfolio=portfolio, underlying_instrument=i1)
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
- i13.refresh_from_db()
1152
- _, returns = get_returns([i1.id, i2.id], from_date=v1, to_date=v3)
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], [i13.net_value / i12.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):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.54.7
3
+ Version: 1.54.9
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -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=t-iezNZN6s834EsszGh_5sHnFGgLb3MZpcHrF2pWMG8,12533
116
+ wbportfolio/import_export/handlers/trade.py,sha256=oLYNEAFyDeInvHjuAbB4pe60q6VmHX0wGcyuEGofbKM,12700
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=8cnnvIWKsBIp1WSfhFHaSB4OLCuFZ3lwJ9koZxIY40s,58080
260
+ wbportfolio/models/portfolio.py,sha256=9gbT3tuo73SfhBn4_HIes71feyjTXnZnn9lX2KL_1pQ,57861
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
@@ -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=oSlB1KdSHdR5lXm6G7wpjMjRgM79OrHM2FY_PHhna58,53570
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
@@ -522,7 +522,7 @@ wbportfolio/viewsets/transactions/mixins.py,sha256=WipvJoi5hylkpD0y9VATe30WAcwIH
522
522
  wbportfolio/viewsets/transactions/rebalancing.py,sha256=6rIrdK0rtKL1afJ-tYfAGdQVTN2MH1kG_yCeVkmyK8k,1263
523
523
  wbportfolio/viewsets/transactions/trade_proposals.py,sha256=kQCojTNKBEyn2NcenL3a9auzBH4sIgLEx8rLAYCGLGg,6161
524
524
  wbportfolio/viewsets/transactions/trades.py,sha256=GHOw5jtcqoaHiRrxxxL29c9405QiPisEn4coGELKDrE,22146
525
- wbportfolio-1.54.7.dist-info/METADATA,sha256=3cBCW9p4yeH2L3_e9ruCBUDkvWkzcOnj4-SQeK6fUi0,702
526
- wbportfolio-1.54.7.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
527
- wbportfolio-1.54.7.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
528
- wbportfolio-1.54.7.dist-info/RECORD,,
525
+ wbportfolio-1.54.9.dist-info/METADATA,sha256=SL5iDKkrof3J3-X4ykL9jJslbUo8ltmEwJzni_emoXY,702
526
+ wbportfolio-1.54.9.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
527
+ wbportfolio-1.54.9.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
528
+ wbportfolio-1.54.9.dist-info/RECORD,,