wbportfolio 1.52.0__py2.py3-none-any.whl → 1.59.4__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/__init__.py +3 -1
- wbportfolio/admin/indexes.py +1 -1
- wbportfolio/admin/orders/__init__.py +2 -0
- wbportfolio/admin/orders/order_proposals.py +16 -0
- wbportfolio/admin/orders/orders.py +32 -0
- wbportfolio/admin/portfolio.py +11 -5
- wbportfolio/admin/product_groups.py +1 -1
- wbportfolio/admin/products.py +2 -1
- wbportfolio/admin/{transactions/rebalancing.py → rebalancing.py} +1 -1
- wbportfolio/admin/transactions/__init__.py +0 -2
- wbportfolio/admin/transactions/dividends.py +40 -4
- wbportfolio/admin/transactions/fees.py +24 -14
- wbportfolio/admin/transactions/trades.py +34 -27
- wbportfolio/analysis/claims.py +5 -6
- wbportfolio/api_clients/ubs.py +162 -0
- wbportfolio/constants.py +1 -0
- wbportfolio/contrib/company_portfolio/configs/display.py +22 -10
- wbportfolio/contrib/company_portfolio/configs/previews.py +3 -3
- wbportfolio/contrib/company_portfolio/filters.py +10 -10
- wbportfolio/contrib/company_portfolio/models.py +69 -39
- wbportfolio/contrib/company_portfolio/scripts.py +7 -2
- wbportfolio/contrib/company_portfolio/serializers.py +32 -22
- wbportfolio/contrib/company_portfolio/tasks.py +12 -1
- wbportfolio/contrib/company_portfolio/tests/conftest.py +2 -2
- wbportfolio/defaults/fees/default.py +7 -15
- wbportfolio/factories/__init__.py +2 -2
- wbportfolio/factories/assets.py +1 -1
- wbportfolio/factories/dividends.py +8 -3
- wbportfolio/factories/fees.py +8 -4
- wbportfolio/factories/orders/__init__.py +2 -0
- wbportfolio/factories/orders/order_proposals.py +21 -0
- wbportfolio/factories/orders/orders.py +34 -0
- wbportfolio/factories/portfolios.py +2 -1
- wbportfolio/factories/product_groups.py +3 -3
- wbportfolio/factories/products.py +3 -3
- wbportfolio/factories/rebalancing.py +1 -1
- wbportfolio/factories/trades.py +12 -16
- wbportfolio/filters/assets.py +18 -4
- wbportfolio/filters/orders/__init__.py +2 -0
- wbportfolio/filters/orders/order_proposals.py +55 -0
- wbportfolio/filters/orders/orders.py +11 -0
- wbportfolio/filters/portfolios.py +38 -1
- wbportfolio/filters/positions.py +0 -1
- wbportfolio/filters/transactions/__init__.py +1 -2
- wbportfolio/filters/transactions/fees.py +5 -12
- wbportfolio/filters/transactions/trades.py +16 -8
- wbportfolio/filters/transactions/utils.py +42 -0
- wbportfolio/import_export/backends/ubs/__init__.py +1 -0
- wbportfolio/import_export/backends/ubs/asset_position.py +6 -7
- wbportfolio/import_export/backends/ubs/fees.py +10 -20
- wbportfolio/import_export/backends/ubs/instrument_price.py +6 -6
- wbportfolio/import_export/backends/ubs/trade.py +48 -0
- wbportfolio/import_export/backends/utils.py +0 -17
- wbportfolio/import_export/handlers/asset_position.py +22 -10
- wbportfolio/import_export/handlers/dividend.py +8 -8
- wbportfolio/import_export/handlers/fees.py +13 -23
- wbportfolio/import_export/handlers/orders.py +71 -0
- wbportfolio/import_export/handlers/trade.py +53 -77
- wbportfolio/import_export/parsers/default_mapping.py +1 -1
- wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +2 -2
- wbportfolio/import_export/parsers/jpmorgan/fees.py +4 -4
- wbportfolio/import_export/parsers/jpmorgan/strategy.py +59 -85
- wbportfolio/import_export/parsers/jpmorgan/valuation.py +2 -2
- wbportfolio/import_export/parsers/leonteq/customer_trade.py +5 -5
- wbportfolio/import_export/parsers/leonteq/fees.py +11 -7
- wbportfolio/import_export/parsers/leonteq/trade.py +2 -6
- wbportfolio/import_export/parsers/natixis/d1_fees.py +2 -2
- wbportfolio/import_export/parsers/natixis/dividend.py +4 -9
- wbportfolio/import_export/parsers/natixis/equity.py +22 -4
- wbportfolio/import_export/parsers/natixis/fees.py +7 -9
- wbportfolio/import_export/parsers/natixis/utils.py +13 -19
- wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +1 -1
- wbportfolio/import_export/parsers/sg_lux/equity.py +10 -10
- wbportfolio/import_export/parsers/sg_lux/fees.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/perf_fees.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/sylk.py +12 -11
- wbportfolio/import_export/parsers/sg_lux/utils.py +2 -2
- wbportfolio/import_export/parsers/sg_lux/valuation.py +4 -2
- wbportfolio/import_export/parsers/societe_generale/strategy.py +5 -5
- wbportfolio/import_export/parsers/tellco/customer_trade.py +2 -1
- wbportfolio/import_export/parsers/tellco/valuation.py +4 -3
- wbportfolio/import_export/parsers/ubs/api/fees.py +2 -2
- wbportfolio/import_export/parsers/ubs/api/trade.py +39 -0
- wbportfolio/import_export/parsers/ubs/customer_trade.py +7 -5
- wbportfolio/import_export/parsers/ubs/equity.py +3 -2
- wbportfolio/import_export/parsers/ubs/valuation.py +2 -1
- wbportfolio/import_export/parsers/vontobel/customer_trade.py +2 -3
- wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -1
- wbportfolio/import_export/parsers/vontobel/management_fees.py +12 -20
- wbportfolio/import_export/parsers/vontobel/performance_fees.py +5 -8
- wbportfolio/import_export/parsers/vontobel/valuation_api.py +4 -1
- wbportfolio/import_export/resources/trades.py +3 -3
- wbportfolio/import_export/utils.py +3 -1
- wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +2 -2
- wbportfolio/metric/backends/base.py +2 -2
- wbportfolio/migrations/0059_fees_unique_fees.py +1 -1
- wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +622 -0
- wbportfolio/migrations/0078_trade_drift_factor.py +26 -0
- wbportfolio/migrations/0079_alter_trade_drift_factor.py +19 -0
- wbportfolio/migrations/0080_alter_trade_drift_factor_alter_trade_weighting.py +19 -0
- wbportfolio/migrations/0081_alter_trade_drift_factor.py +19 -0
- wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py +93 -0
- wbportfolio/migrations/0083_order_alter_trade_options_and_more.py +181 -0
- wbportfolio/migrations/0084_orderproposal_min_order_value.py +25 -0
- wbportfolio/migrations/0085_order_desired_target_weight.py +26 -0
- wbportfolio/migrations/0086_orderproposal_total_cash_weight.py +19 -0
- wbportfolio/migrations/0087_product_order_routing_custodian_adapter.py +94 -0
- wbportfolio/migrations/0088_orderproposal_total_effective_portfolio_contribution.py +19 -0
- wbportfolio/migrations/0089_orderproposal_min_weighting.py +71 -0
- wbportfolio/migrations/0090_dividendtransaction_price_fx_portfolio_and_more.py +44 -0
- wbportfolio/migrations/0091_remove_order_execution_confirmed_and_more.py +32 -0
- wbportfolio/migrations/0092_order_quantization_error_alter_orderproposal_status.py +49 -0
- wbportfolio/migrations/0093_remove_portfolioportfoliothroughmodel_unique_primary_and_more.py +35 -0
- wbportfolio/models/__init__.py +2 -0
- wbportfolio/models/adjustments.py +1 -1
- wbportfolio/models/asset.py +28 -170
- wbportfolio/models/builder.py +323 -0
- wbportfolio/models/custodians.py +3 -3
- wbportfolio/models/exceptions.py +1 -1
- wbportfolio/models/graphs/portfolio.py +1 -1
- wbportfolio/models/graphs/utils.py +11 -11
- wbportfolio/models/mixins/instruments.py +7 -0
- wbportfolio/models/mixins/liquidity_stress_test.py +4 -4
- wbportfolio/models/orders/__init__.py +2 -0
- wbportfolio/models/orders/order_proposals.py +1414 -0
- wbportfolio/models/orders/orders.py +410 -0
- wbportfolio/models/portfolio.py +311 -289
- wbportfolio/models/portfolio_relationship.py +6 -0
- wbportfolio/models/products.py +12 -0
- wbportfolio/models/{transactions/rebalancing.py → rebalancing.py} +40 -27
- wbportfolio/models/roles.py +4 -10
- wbportfolio/models/transactions/__init__.py +0 -4
- wbportfolio/models/transactions/claim.py +7 -6
- wbportfolio/models/transactions/dividends.py +42 -5
- wbportfolio/models/transactions/fees.py +55 -22
- wbportfolio/models/transactions/trades.py +121 -442
- wbportfolio/models/transactions/transactions.py +78 -158
- wbportfolio/models/utils.py +100 -1
- wbportfolio/order_routing/__init__.py +35 -0
- wbportfolio/order_routing/adapters/__init__.py +65 -0
- wbportfolio/order_routing/adapters/ubs.py +195 -0
- wbportfolio/order_routing/router.py +33 -0
- wbportfolio/order_routing/tests/__init__.py +0 -0
- wbportfolio/order_routing/tests/test_router.py +110 -0
- wbportfolio/permissions.py +7 -0
- wbportfolio/pms/analytics/portfolio.py +17 -9
- wbportfolio/pms/analytics/utils.py +9 -0
- wbportfolio/pms/trading/__init__.py +0 -1
- wbportfolio/pms/trading/optimizer.py +61 -0
- wbportfolio/pms/typing.py +198 -63
- wbportfolio/rebalancing/base.py +12 -1
- wbportfolio/rebalancing/decorators.py +1 -1
- wbportfolio/rebalancing/models/composite.py +4 -8
- wbportfolio/rebalancing/models/equally_weighted.py +13 -11
- wbportfolio/rebalancing/models/market_capitalization_weighted.py +21 -14
- wbportfolio/rebalancing/models/model_portfolio.py +14 -18
- wbportfolio/risk_management/backends/__init__.py +1 -0
- wbportfolio/risk_management/backends/controversy_portfolio.py +2 -2
- wbportfolio/risk_management/backends/esg_aggregation_portfolio.py +64 -0
- wbportfolio/risk_management/backends/exposure_portfolio.py +4 -4
- wbportfolio/risk_management/backends/instrument_list_portfolio.py +3 -3
- wbportfolio/risk_management/tests/test_esg_aggregation_portfolio.py +49 -0
- wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -1
- wbportfolio/risk_management/tests/test_stop_loss_instrument.py +2 -2
- wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -1
- wbportfolio/serializers/__init__.py +1 -0
- wbportfolio/serializers/orders/__init__.py +2 -0
- wbportfolio/serializers/orders/order_proposals.py +115 -0
- wbportfolio/serializers/orders/orders.py +283 -0
- wbportfolio/serializers/portfolios.py +7 -7
- wbportfolio/serializers/positions.py +2 -2
- wbportfolio/serializers/rebalancing.py +1 -1
- wbportfolio/serializers/signals.py +9 -12
- wbportfolio/serializers/transactions/__init__.py +1 -10
- wbportfolio/serializers/transactions/claim.py +2 -2
- wbportfolio/serializers/transactions/dividends.py +37 -9
- wbportfolio/serializers/transactions/fees.py +39 -10
- wbportfolio/serializers/transactions/trades.py +55 -157
- wbportfolio/tasks.py +43 -5
- wbportfolio/tests/analysis/__init__.py +0 -0
- wbportfolio/tests/analysis/test_claims.py +85 -0
- wbportfolio/tests/conftest.py +12 -12
- wbportfolio/tests/models/orders/__init__.py +0 -0
- wbportfolio/tests/models/orders/test_order_proposals.py +1046 -0
- wbportfolio/tests/models/test_assets.py +7 -3
- wbportfolio/tests/models/test_imports.py +9 -13
- wbportfolio/tests/models/test_portfolios.py +102 -95
- wbportfolio/tests/models/test_products.py +11 -0
- wbportfolio/tests/models/test_splits.py +1 -6
- wbportfolio/tests/models/test_utils.py +140 -0
- wbportfolio/tests/models/transactions/test_fees.py +7 -13
- wbportfolio/tests/models/transactions/test_rebalancing.py +5 -5
- wbportfolio/tests/models/transactions/test_trades.py +0 -20
- wbportfolio/tests/pms/test_analytics.py +22 -3
- wbportfolio/tests/rebalancing/test_models.py +51 -57
- wbportfolio/tests/signals.py +10 -20
- wbportfolio/tests/tests.py +3 -1
- wbportfolio/tests/viewsets/test_products.py +1 -0
- wbportfolio/urls.py +10 -13
- wbportfolio/viewsets/__init__.py +9 -4
- wbportfolio/viewsets/assets.py +3 -204
- wbportfolio/viewsets/charts/__init__.py +6 -1
- wbportfolio/viewsets/charts/assets.py +344 -154
- wbportfolio/viewsets/configs/buttons/__init__.py +2 -2
- wbportfolio/viewsets/configs/buttons/assets.py +1 -1
- wbportfolio/viewsets/configs/buttons/mixins.py +4 -4
- wbportfolio/viewsets/configs/buttons/portfolios.py +45 -1
- wbportfolio/viewsets/configs/buttons/products.py +32 -2
- wbportfolio/viewsets/configs/display/__init__.py +2 -5
- wbportfolio/viewsets/configs/display/assets.py +6 -19
- wbportfolio/viewsets/configs/display/fees.py +3 -3
- wbportfolio/viewsets/configs/display/portfolios.py +5 -5
- wbportfolio/viewsets/configs/display/products.py +1 -1
- wbportfolio/viewsets/configs/display/rebalancing.py +2 -2
- wbportfolio/viewsets/configs/display/reconciliations.py +4 -4
- wbportfolio/viewsets/configs/display/trades.py +1 -189
- wbportfolio/viewsets/configs/endpoints/__init__.py +3 -7
- wbportfolio/viewsets/configs/endpoints/fees.py +2 -2
- wbportfolio/viewsets/configs/endpoints/trades.py +0 -41
- wbportfolio/viewsets/configs/menu/__init__.py +1 -1
- wbportfolio/viewsets/configs/menu/orders.py +11 -0
- wbportfolio/viewsets/configs/titles/__init__.py +2 -3
- wbportfolio/viewsets/configs/titles/fees.py +4 -8
- wbportfolio/viewsets/esg.py +3 -5
- wbportfolio/viewsets/mixins.py +5 -1
- wbportfolio/viewsets/orders/__init__.py +6 -0
- wbportfolio/viewsets/orders/configs/__init__.py +4 -0
- wbportfolio/viewsets/orders/configs/buttons/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/buttons/order_proposals.py +188 -0
- wbportfolio/viewsets/orders/configs/buttons/orders.py +113 -0
- wbportfolio/viewsets/orders/configs/displays/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/displays/order_proposals.py +157 -0
- wbportfolio/viewsets/orders/configs/displays/orders.py +232 -0
- wbportfolio/viewsets/orders/configs/endpoints/__init__.py +2 -0
- wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py +21 -0
- wbportfolio/viewsets/orders/configs/endpoints/orders.py +28 -0
- wbportfolio/viewsets/orders/configs/titles/__init__.py +0 -0
- wbportfolio/viewsets/orders/configs/titles/orders.py +0 -0
- wbportfolio/viewsets/orders/order_proposals.py +252 -0
- wbportfolio/viewsets/orders/orders.py +277 -0
- wbportfolio/viewsets/portfolios.py +36 -12
- wbportfolio/viewsets/positions.py +3 -2
- wbportfolio/viewsets/products.py +6 -6
- wbportfolio/viewsets/{transactions/rebalancing.py → rebalancing.py} +2 -2
- wbportfolio/viewsets/transactions/__init__.py +3 -14
- wbportfolio/viewsets/transactions/fees.py +22 -22
- wbportfolio/viewsets/transactions/trades.py +1 -180
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/METADATA +3 -1
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/RECORD +252 -203
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/WHEEL +1 -1
- wbportfolio/admin/transactions/transactions.py +0 -38
- wbportfolio/factories/transactions.py +0 -22
- wbportfolio/fdm/tasks.py +0 -13
- wbportfolio/filters/transactions/transactions.py +0 -99
- wbportfolio/models/transactions/expiry.py +0 -7
- wbportfolio/models/transactions/trade_proposals.py +0 -704
- wbportfolio/pms/trading/handler.py +0 -161
- wbportfolio/serializers/transactions/expiry.py +0 -18
- wbportfolio/serializers/transactions/trade_proposals.py +0 -76
- wbportfolio/serializers/transactions/transactions.py +0 -85
- wbportfolio/tests/models/transactions/test_trade_proposals.py +0 -410
- wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -66
- wbportfolio/viewsets/configs/display/trade_proposals.py +0 -100
- wbportfolio/viewsets/configs/display/transactions.py +0 -55
- wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -18
- wbportfolio/viewsets/configs/endpoints/transactions.py +0 -14
- wbportfolio/viewsets/configs/menu/transactions.py +0 -9
- wbportfolio/viewsets/configs/titles/transactions.py +0 -9
- wbportfolio/viewsets/signals.py +0 -43
- wbportfolio/viewsets/transactions/trade_proposals.py +0 -139
- wbportfolio/viewsets/transactions/transactions.py +0 -122
- /wbportfolio/{fdm → api_clients}/__init__.py +0 -0
- {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/licenses/LICENSE +0 -0
|
@@ -6,7 +6,7 @@ import pytest
|
|
|
6
6
|
from django.core.exceptions import ValidationError
|
|
7
7
|
from pandas._libs.tslibs.offsets import BDay
|
|
8
8
|
|
|
9
|
-
from wbportfolio.models import AssetPosition,
|
|
9
|
+
from wbportfolio.models import AssetPosition, OrderProposal
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
@pytest.mark.django_db
|
|
@@ -47,7 +47,7 @@ class TestRebalancer:
|
|
|
47
47
|
def test_evaluate_rebalancing(
|
|
48
48
|
self, weekday, rebalancer_factory, asset_position_factory, instrument_factory, instrument_price_factory
|
|
49
49
|
):
|
|
50
|
-
rebalancer = rebalancer_factory.create(
|
|
50
|
+
rebalancer = rebalancer_factory.create(apply_order_proposal_automatically=True)
|
|
51
51
|
trade_date = (weekday + BDay(1)).date()
|
|
52
52
|
|
|
53
53
|
i1 = instrument_factory.create()
|
|
@@ -63,9 +63,9 @@ class TestRebalancer:
|
|
|
63
63
|
a2 = asset_position_factory.create(
|
|
64
64
|
portfolio=rebalancer.portfolio, date=weekday, weighting=0.3, underlying_instrument=i2
|
|
65
65
|
)
|
|
66
|
-
|
|
67
|
-
assert
|
|
68
|
-
assert
|
|
66
|
+
order_proposal = rebalancer.evaluate_rebalancing(trade_date)
|
|
67
|
+
assert order_proposal.orders.count() == 2
|
|
68
|
+
assert order_proposal.status == OrderProposal.Status.CONFIRMED
|
|
69
69
|
assert AssetPosition.objects.get(
|
|
70
70
|
portfolio=rebalancer.portfolio, date=trade_date, underlying_quote=a1.underlying_instrument
|
|
71
71
|
).weighting == Decimal(0.5)
|
|
@@ -3,7 +3,6 @@ from decimal import Decimal
|
|
|
3
3
|
|
|
4
4
|
import pytest
|
|
5
5
|
from faker import Faker
|
|
6
|
-
from pandas._libs.tslibs.offsets import BDay
|
|
7
6
|
|
|
8
7
|
from wbportfolio.models import Product, Trade
|
|
9
8
|
|
|
@@ -103,12 +102,6 @@ class TestTradeModel:
|
|
|
103
102
|
assert customer_trade.claimed_shares == c2.shares
|
|
104
103
|
|
|
105
104
|
|
|
106
|
-
@pytest.mark.django_db
|
|
107
|
-
class TestTradeProposalModel:
|
|
108
|
-
def test_init(self, trade_proposal):
|
|
109
|
-
assert trade_proposal.id is not None
|
|
110
|
-
|
|
111
|
-
|
|
112
105
|
@pytest.mark.django_db
|
|
113
106
|
class TestTradeInstrumentPrice:
|
|
114
107
|
def test_shares(self, portfolio, product_factory, trade_factory, instrument_price_factory):
|
|
@@ -204,16 +197,3 @@ class TestTradeInstrumentPrice:
|
|
|
204
197
|
subscription_trade1.refresh_from_db()
|
|
205
198
|
assert subscription_trade1.internal_trade == internal_trade
|
|
206
199
|
assert subscription_trade1.marked_as_internal is True
|
|
207
|
-
|
|
208
|
-
def test_last_underlying_quote_price(self, weekday, trade_factory, instrument_price_factory):
|
|
209
|
-
trade = trade_factory.create(transaction_date=weekday, value_date=(weekday - BDay(1)).date())
|
|
210
|
-
assert trade.last_underlying_quote_price is None
|
|
211
|
-
del trade.last_underlying_quote_price
|
|
212
|
-
|
|
213
|
-
# test that underlying quote price returns any price found at transaction_date, or then at value_date (in that order)
|
|
214
|
-
p0 = instrument_price_factory.create(instrument=trade.underlying_instrument, date=trade.value_date)
|
|
215
|
-
assert trade.last_underlying_quote_price == p0
|
|
216
|
-
del trade.last_underlying_quote_price
|
|
217
|
-
|
|
218
|
-
p1 = instrument_price_factory.create(instrument=trade.underlying_instrument, date=trade.transaction_date)
|
|
219
|
-
assert trade.last_underlying_quote_price == p1
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import pandas as pd
|
|
2
|
+
import pytest
|
|
2
3
|
|
|
3
4
|
from wbportfolio.pms.analytics.portfolio import Portfolio
|
|
4
5
|
|
|
@@ -15,9 +16,27 @@ def test_get_next_weights():
|
|
|
15
16
|
portfolio = Portfolio(X=pd.DataFrame([returns]), weights=pd.Series(weights))
|
|
16
17
|
next_weights = portfolio.get_next_weights()
|
|
17
18
|
|
|
18
|
-
assert next_weights[0] == w0 * (r0 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1))
|
|
19
|
-
assert next_weights[1] == w1 * (r1 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1))
|
|
20
|
-
assert next_weights[2] == w2 * (r2 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1))
|
|
19
|
+
assert next_weights[0] == pytest.approx(w0 * (r0 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1)), abs=10e-8)
|
|
20
|
+
assert next_weights[1] == pytest.approx(w1 * (r1 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1)), abs=10e-8)
|
|
21
|
+
assert next_weights[2] == pytest.approx(w2 * (r2 + 1) / (w0 * (r0 + 1) + w1 * (r1 + 1) + w2 * (r2 + 1)), abs=10e-8)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def test_get_next_weights_solve_quantization_error():
|
|
25
|
+
w0 = 0.33333334
|
|
26
|
+
w1 = 0.33333333
|
|
27
|
+
w2 = 0.33333333
|
|
28
|
+
weights = [w0, w1, w2]
|
|
29
|
+
returns = [1.0, 1.0, 1.0] # no returns
|
|
30
|
+
portfolio = Portfolio(X=pd.DataFrame([returns]), weights=pd.Series(weights))
|
|
31
|
+
next_weights = portfolio.get_next_weights(round_precision=8) # no rounding as number are all 8 decimals
|
|
32
|
+
assert sum(next_weights.values()) == 1.0
|
|
33
|
+
next_weights = portfolio.get_next_weights(
|
|
34
|
+
round_precision=7
|
|
35
|
+
) # we expect the weight to be rounded to 6 decimals, which would lead to a total sum of 0.999999
|
|
36
|
+
|
|
37
|
+
assert next_weights[0] == 0.3333334
|
|
38
|
+
assert next_weights[1] == 0.3333333
|
|
39
|
+
assert next_weights[2] == 0.3333333
|
|
21
40
|
|
|
22
41
|
|
|
23
42
|
def test_get_estimate_net_value():
|
|
@@ -4,28 +4,34 @@ import pytest
|
|
|
4
4
|
from pandas._libs.tslibs.offsets import BDay
|
|
5
5
|
from wbfdm.models import InstrumentPrice
|
|
6
6
|
|
|
7
|
-
from wbportfolio.factories import
|
|
8
|
-
from wbportfolio.models import
|
|
7
|
+
from wbportfolio.factories import OrderFactory, OrderProposalFactory, PortfolioFactory
|
|
8
|
+
from wbportfolio.models import Order, OrderProposal, PortfolioPortfolioThroughModel
|
|
9
9
|
|
|
10
10
|
|
|
11
11
|
@pytest.mark.django_db
|
|
12
12
|
class TestEquallyWeightedRebalancing:
|
|
13
|
-
|
|
14
|
-
def model(self, portfolio, weekday):
|
|
13
|
+
def test_is_valid(self, portfolio, weekday, asset_position_factory, instrument_price_factory):
|
|
15
14
|
from wbportfolio.rebalancing.models import EquallyWeightedRebalancing
|
|
16
15
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
def test_is_valid(self, portfolio, weekday, model, asset_position_factory, instrument_price_factory):
|
|
16
|
+
trade_date = (weekday + BDay(1)).date()
|
|
17
|
+
model = EquallyWeightedRebalancing(portfolio, trade_date, weekday)
|
|
20
18
|
assert not model.is_valid()
|
|
21
|
-
|
|
19
|
+
|
|
20
|
+
a = asset_position_factory.create(portfolio=portfolio, date=weekday)
|
|
21
|
+
model = EquallyWeightedRebalancing(portfolio, trade_date, weekday)
|
|
22
22
|
assert not model.is_valid()
|
|
23
|
-
|
|
23
|
+
|
|
24
|
+
instrument_price_factory.create(instrument=a.underlying_quote, date=trade_date)
|
|
25
|
+
model = EquallyWeightedRebalancing(portfolio, trade_date, weekday)
|
|
24
26
|
assert model.is_valid()
|
|
25
27
|
|
|
26
|
-
def test_get_target_portfolio(self, portfolio, weekday,
|
|
27
|
-
|
|
28
|
-
|
|
28
|
+
def test_get_target_portfolio(self, portfolio, weekday, asset_position_factory):
|
|
29
|
+
from wbportfolio.rebalancing.models import EquallyWeightedRebalancing
|
|
30
|
+
|
|
31
|
+
a1 = asset_position_factory(weighting=0.7, portfolio=portfolio, date=weekday)
|
|
32
|
+
a2 = asset_position_factory(weighting=0.3, portfolio=portfolio, date=weekday)
|
|
33
|
+
model = EquallyWeightedRebalancing(portfolio, (weekday + BDay(1)).date(), weekday)
|
|
34
|
+
|
|
29
35
|
target_portfolio = model.get_target_portfolio()
|
|
30
36
|
target_positions = target_portfolio.positions_map
|
|
31
37
|
assert target_positions[a1.underlying_instrument.id].weighting == Decimal(0.5)
|
|
@@ -38,30 +44,22 @@ class TestModelPortfolioRebalancing:
|
|
|
38
44
|
def model(self, portfolio, weekday):
|
|
39
45
|
from wbportfolio.rebalancing.models import ModelPortfolioRebalancing
|
|
40
46
|
|
|
47
|
+
PortfolioPortfolioThroughModel.objects.create(
|
|
48
|
+
portfolio=portfolio,
|
|
49
|
+
dependency_portfolio=PortfolioFactory.create(),
|
|
50
|
+
type=PortfolioPortfolioThroughModel.Type.MODEL,
|
|
51
|
+
)
|
|
41
52
|
return ModelPortfolioRebalancing(portfolio, (weekday + BDay(1)).date(), weekday)
|
|
42
53
|
|
|
43
54
|
def test_is_valid(self, portfolio, weekday, model, asset_position_factory, instrument_price_factory):
|
|
44
55
|
assert not model.is_valid()
|
|
45
56
|
asset_position_factory.create(portfolio=model.portfolio, date=model.last_effective_date)
|
|
46
57
|
assert not model.is_valid()
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
portfolio=model.portfolio,
|
|
50
|
-
dependency_portfolio=model_portfolio,
|
|
51
|
-
type=PortfolioPortfolioThroughModel.Type.MODEL,
|
|
52
|
-
)
|
|
53
|
-
a = asset_position_factory.create(portfolio=model.model_portfolio, date=model.last_effective_date)
|
|
54
|
-
assert not model.is_valid()
|
|
55
|
-
instrument_price_factory.create(instrument=a.underlying_quote, date=model.trade_date)
|
|
58
|
+
|
|
59
|
+
asset_position_factory.create(portfolio=model.model_portfolio, date=model.last_effective_date)
|
|
56
60
|
assert model.is_valid()
|
|
57
61
|
|
|
58
62
|
def test_get_target_portfolio(self, portfolio, weekday, model, asset_position_factory):
|
|
59
|
-
model_portfolio = PortfolioFactory.create()
|
|
60
|
-
PortfolioPortfolioThroughModel.objects.create(
|
|
61
|
-
portfolio=model.portfolio,
|
|
62
|
-
dependency_portfolio=model_portfolio,
|
|
63
|
-
type=PortfolioPortfolioThroughModel.Type.MODEL,
|
|
64
|
-
)
|
|
65
63
|
asset_position_factory(portfolio=portfolio, date=model.last_effective_date) # noise
|
|
66
64
|
asset_position_factory(portfolio=portfolio, date=model.last_effective_date) # noise
|
|
67
65
|
a1 = asset_position_factory(weighting=0.8, portfolio=portfolio.model_portfolio, date=model.last_effective_date)
|
|
@@ -83,50 +81,46 @@ class TestCompositeRebalancing:
|
|
|
83
81
|
def test_is_valid(self, portfolio, weekday, model, asset_position_factory, instrument_price_factory):
|
|
84
82
|
assert not model.is_valid()
|
|
85
83
|
|
|
86
|
-
|
|
87
|
-
portfolio=model.portfolio, trade_date=model.last_effective_date, status=
|
|
84
|
+
order_proposal = OrderProposalFactory.create(
|
|
85
|
+
portfolio=model.portfolio, trade_date=model.last_effective_date, status=OrderProposal.Status.CONFIRMED
|
|
88
86
|
)
|
|
89
|
-
t1 =
|
|
87
|
+
t1 = OrderFactory.create(
|
|
90
88
|
portfolio=model.portfolio,
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
weighting=0.7,
|
|
95
|
-
status=Trade.Status.EXECUTED,
|
|
89
|
+
value_date=model.last_effective_date,
|
|
90
|
+
order_type=Order.Type.BUY,
|
|
91
|
+
order_proposal=order_proposal,
|
|
92
|
+
weighting=Decimal(0.7),
|
|
96
93
|
)
|
|
97
|
-
|
|
94
|
+
OrderFactory.create(
|
|
98
95
|
portfolio=model.portfolio,
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
weighting=0.3,
|
|
103
|
-
status=Trade.Status.EXECUTED,
|
|
96
|
+
value_date=model.last_effective_date,
|
|
97
|
+
order_type=Order.Type.BUY,
|
|
98
|
+
order_proposal=order_proposal,
|
|
99
|
+
weighting=Decimal(0.3),
|
|
104
100
|
)
|
|
105
101
|
assert not model.is_valid()
|
|
106
102
|
instrument_price_factory.create(instrument=t1.underlying_instrument, date=model.trade_date)
|
|
107
103
|
assert model.is_valid()
|
|
108
104
|
|
|
109
105
|
def test_get_target_portfolio(self, portfolio, weekday, model, asset_position_factory):
|
|
110
|
-
|
|
111
|
-
portfolio=model.portfolio, trade_date=model.last_effective_date, status=
|
|
106
|
+
order_proposal = OrderProposalFactory.create(
|
|
107
|
+
portfolio=model.portfolio, trade_date=model.last_effective_date, status=OrderProposal.Status.CONFIRMED
|
|
112
108
|
)
|
|
113
109
|
asset_position_factory(portfolio=portfolio, date=model.last_effective_date) # noise
|
|
114
110
|
asset_position_factory(portfolio=portfolio, date=model.last_effective_date) # noise
|
|
115
|
-
t1 =
|
|
111
|
+
t1 = OrderFactory.create(
|
|
116
112
|
portfolio=model.portfolio,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
weighting=0.8,
|
|
121
|
-
status=Trade.Status.EXECUTED,
|
|
113
|
+
value_date=model.last_effective_date,
|
|
114
|
+
order_type=Order.Type.BUY,
|
|
115
|
+
order_proposal=order_proposal,
|
|
116
|
+
weighting=Decimal(0.8),
|
|
122
117
|
)
|
|
123
|
-
t2 =
|
|
118
|
+
t2 = OrderFactory.create(
|
|
124
119
|
portfolio=model.portfolio,
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
weighting=0.2,
|
|
129
|
-
status=Trade.Status.EXECUTED,
|
|
120
|
+
value_date=model.last_effective_date,
|
|
121
|
+
order_type=Order.Type.BUY,
|
|
122
|
+
order_proposal=order_proposal,
|
|
123
|
+
weighting=Decimal(0.2),
|
|
130
124
|
)
|
|
131
125
|
target_portfolio = model.get_target_portfolio()
|
|
132
126
|
target_positions = target_portfolio.positions_map
|
|
@@ -162,5 +156,5 @@ class TestMarketCapitalizationRebalancing:
|
|
|
162
156
|
|
|
163
157
|
target_portfolio = model.get_target_portfolio()
|
|
164
158
|
target_positions = target_portfolio.positions_map
|
|
165
|
-
assert target_positions[i1].weighting == mkt12 / (mkt12 + mkt21)
|
|
166
|
-
assert target_positions[i2].weighting == mkt21 / (mkt12 + mkt21)
|
|
159
|
+
assert target_positions[i1].weighting == pytest.approx(Decimal(mkt12 / (mkt12 + mkt21)), abs=Decimal(1e-8))
|
|
160
|
+
assert target_positions[i2].weighting == pytest.approx(Decimal(mkt21 / (mkt12 + mkt21)), abs=Decimal(1e-8))
|
wbportfolio/tests/signals.py
CHANGED
|
@@ -6,9 +6,9 @@ from wbfdm.factories import InstrumentPriceFactory
|
|
|
6
6
|
|
|
7
7
|
from wbportfolio.factories import (
|
|
8
8
|
CustomerTradeFactory,
|
|
9
|
+
OrderProposalFactory,
|
|
9
10
|
ProductFactory,
|
|
10
11
|
ProductPortfolioRoleFactory,
|
|
11
|
-
TradeProposalFactory,
|
|
12
12
|
)
|
|
13
13
|
from wbportfolio.viewsets import (
|
|
14
14
|
AssetPositionInstrumentModelViewSet,
|
|
@@ -17,17 +17,15 @@ from wbportfolio.viewsets import (
|
|
|
17
17
|
ClaimEntryModelViewSet,
|
|
18
18
|
CustodianDistributionInstrumentChartViewSet,
|
|
19
19
|
CustomerDistributionInstrumentChartViewSet,
|
|
20
|
-
DistributionChartViewSet,
|
|
21
|
-
DistributionTableViewSet,
|
|
22
20
|
NominalProductChartView,
|
|
21
|
+
OrderOrderProposalModelViewSet,
|
|
22
|
+
OrderProposalPortfolioModelViewSet,
|
|
23
23
|
PortfolioRoleInstrumentModelViewSet,
|
|
24
24
|
ProductCustomerModelViewSet,
|
|
25
25
|
ProductPerformanceFeesModelViewSet,
|
|
26
26
|
SubscriptionRedemptionInstrumentModelViewSet,
|
|
27
27
|
SubscriptionRedemptionModelViewSet,
|
|
28
28
|
TradeInstrumentModelViewSet,
|
|
29
|
-
TradeProposalPortfolioModelViewSet,
|
|
30
|
-
TradeTradeProposalModelViewSet,
|
|
31
29
|
)
|
|
32
30
|
|
|
33
31
|
# =================================================================================================================
|
|
@@ -54,18 +52,18 @@ def receive_factory_product_portfolio_role(sender, *args, **kwargs):
|
|
|
54
52
|
# =================================================================================================================
|
|
55
53
|
# UPDATE KWARGS
|
|
56
54
|
# =================================================================================================================
|
|
57
|
-
@receiver(custom_update_kwargs, sender=
|
|
58
|
-
def
|
|
55
|
+
@receiver(custom_update_kwargs, sender=OrderOrderProposalModelViewSet)
|
|
56
|
+
def receive_kwargs_trade_order_proposal_product(sender, *args, **kwargs):
|
|
59
57
|
if obj := kwargs.get("obj_factory"):
|
|
60
|
-
|
|
61
|
-
obj.
|
|
58
|
+
order_proposal = OrderProposalFactory.create()
|
|
59
|
+
obj.order_proposal = order_proposal
|
|
62
60
|
obj.save()
|
|
63
|
-
return {"
|
|
61
|
+
return {"order_proposal_id": order_proposal.id}
|
|
64
62
|
return {}
|
|
65
63
|
|
|
66
64
|
|
|
67
|
-
@receiver(custom_update_kwargs, sender=
|
|
68
|
-
def
|
|
65
|
+
@receiver(custom_update_kwargs, sender=OrderProposalPortfolioModelViewSet)
|
|
66
|
+
def receive_kwargs_trade_order_proposal_portfolio(sender, *args, **kwargs):
|
|
69
67
|
if obj := kwargs.get("obj_factory"):
|
|
70
68
|
return {"portfolio_id": obj.portfolio.id}
|
|
71
69
|
return {}
|
|
@@ -96,14 +94,6 @@ def receive_kwargs_portfolio_role_instrument(sender, *args, **kwargs):
|
|
|
96
94
|
return {}
|
|
97
95
|
|
|
98
96
|
|
|
99
|
-
@receiver(custom_update_kwargs, sender=DistributionChartViewSet)
|
|
100
|
-
@receiver(custom_update_kwargs, sender=DistributionTableViewSet)
|
|
101
|
-
def receive_kwargs_distribution_chart_instrument_id(sender, *args, **kwargs):
|
|
102
|
-
if instrument_id := kwargs.get("underlying_instrument_id"):
|
|
103
|
-
return {"instrument_id": instrument_id}
|
|
104
|
-
return {}
|
|
105
|
-
|
|
106
|
-
|
|
107
97
|
@receiver(custom_update_kwargs, sender=ProductPerformanceFeesModelViewSet)
|
|
108
98
|
def receive_kwargs_product_performance_fees(sender, *args, **kwargs):
|
|
109
99
|
CurrencyFXRatesFactory()
|
wbportfolio/tests/tests.py
CHANGED
|
@@ -9,7 +9,7 @@ for key, value in default_config.items():
|
|
|
9
9
|
and x.__name__
|
|
10
10
|
not in [
|
|
11
11
|
"AggregatedAssetPositionLiquidityPandasView",
|
|
12
|
-
"
|
|
12
|
+
"OrderOrderProposalModelViewSet",
|
|
13
13
|
"PortfolioSwingPricing",
|
|
14
14
|
"PortfolioCashTarget",
|
|
15
15
|
"PortfolioSwingPricingModelViewSet",
|
|
@@ -19,6 +19,8 @@ for key, value in default_config.items():
|
|
|
19
19
|
"AccountReconciliationLine",
|
|
20
20
|
"TopDownPortfolioCompositionPandasAPIView",
|
|
21
21
|
"CompositionModelPortfolioPandasView",
|
|
22
|
+
"DistributionChartViewSet",
|
|
23
|
+
"DistributionTableViewSet",
|
|
22
24
|
# "ClaimModelViewSet",
|
|
23
25
|
# "ClaimModelSerializer",
|
|
24
26
|
],
|
|
@@ -23,6 +23,7 @@ class TestProductModelViewSet:
|
|
|
23
23
|
portfolio_factory.create_batch(4, invested_timespan=DateRange(date.min, date.max))
|
|
24
24
|
+ portfolio_factory.create_batch(2, invested_timespan=DateRange(date.min, date.max)),
|
|
25
25
|
product_factory.create_batch(6),
|
|
26
|
+
strict=False,
|
|
26
27
|
):
|
|
27
28
|
InstrumentPortfolioThroughModel.objects.update_or_create(
|
|
28
29
|
instrument=product, defaults={"portfolio": portfolio}
|
wbportfolio/urls.py
CHANGED
|
@@ -30,7 +30,6 @@ router.register(
|
|
|
30
30
|
router.register(r"portfoliorole", viewsets.PortfolioRoleModelViewSet, basename="portfoliorole")
|
|
31
31
|
|
|
32
32
|
|
|
33
|
-
router.register(r"transaction", viewsets.TransactionModelViewSet, basename="transaction")
|
|
34
33
|
router.register(r"fees", viewsets.FeesModelViewSet, basename="fees")
|
|
35
34
|
router.register(r"trade", viewsets.TradeModelViewSet, basename="trade")
|
|
36
35
|
router.register(
|
|
@@ -39,7 +38,7 @@ router.register(
|
|
|
39
38
|
|
|
40
39
|
router.register(r"traderepresentation", viewsets.TradeRepresentationViewSet, basename="traderepresentation")
|
|
41
40
|
router.register(
|
|
42
|
-
r"
|
|
41
|
+
r"orderproposalrepresentation", viewsets.OrderProposalRepresentationViewSet, basename="orderproposalrepresentation"
|
|
43
42
|
)
|
|
44
43
|
router.register(
|
|
45
44
|
r"rebalancingmodelrepresentation",
|
|
@@ -63,7 +62,7 @@ router.register(r"aumchart", viewsets.InstrumentPriceAUMDataChartView, basename=
|
|
|
63
62
|
|
|
64
63
|
router.register(r"custodian", viewsets.CustodianModelViewSet, basename="custodian")
|
|
65
64
|
|
|
66
|
-
router.register(r"
|
|
65
|
+
router.register(r"orderproposal", viewsets.OrderProposalModelViewSet, basename="orderproposal")
|
|
67
66
|
|
|
68
67
|
router.register(
|
|
69
68
|
r"assetandnetnewmoneyprogression",
|
|
@@ -79,8 +78,6 @@ portfolio_router.register(
|
|
|
79
78
|
)
|
|
80
79
|
portfolio_router.register(r"asset", viewsets.AssetPositionPortfolioModelViewSet, basename="portfolio-asset")
|
|
81
80
|
portfolio_router.register(r"contributor", viewsets.ContributorPortfolioChartView, basename="portfolio-contributor")
|
|
82
|
-
portfolio_router.register(r"fees", viewsets.FeesPortfolioModelViewSet, basename="portfolio-fees")
|
|
83
|
-
portfolio_router.register(r"transaction", viewsets.TransactionPortfolioModelViewSet, basename="portfolio-transaction")
|
|
84
81
|
portfolio_router.register(r"trade", viewsets.TradePortfolioModelViewSet, basename="portfolio-trade")
|
|
85
82
|
portfolio_router.register(
|
|
86
83
|
r"instrument", viewsets.InstrumentPortfolioThroughPortfolioModelViewSet, basename="portfolio-instrument"
|
|
@@ -91,7 +88,7 @@ portfolio_router.register(
|
|
|
91
88
|
basename="portfolio-preferredclassification",
|
|
92
89
|
)
|
|
93
90
|
portfolio_router.register(
|
|
94
|
-
r"
|
|
91
|
+
r"orderproposal", viewsets.OrderProposalPortfolioModelViewSet, basename="portfolio-orderproposal"
|
|
95
92
|
)
|
|
96
93
|
portfolio_router.register(
|
|
97
94
|
r"dependencyportfolio", viewsets.PortfolioPortfolioThroughModelViewSet, basename="portfolio-dependencyportfolio"
|
|
@@ -101,9 +98,7 @@ portfolio_router.register(
|
|
|
101
98
|
viewsets.CompositionModelPortfolioPandasView,
|
|
102
99
|
basename="portfolio-modelcompositionpandas",
|
|
103
100
|
)
|
|
104
|
-
|
|
105
|
-
r"feesaggregated", viewsets.FeesAggregatedPortfolioPandasView, basename="portfolio-feesaggregated"
|
|
106
|
-
)
|
|
101
|
+
|
|
107
102
|
portfolio_router.register(
|
|
108
103
|
r"distributionchart",
|
|
109
104
|
viewsets.DistributionChartViewSet,
|
|
@@ -139,10 +134,12 @@ product_router = WBCoreRouter()
|
|
|
139
134
|
product_router.register(r"nominalchart", viewsets.NominalProductChartView, basename="product-nominalchart")
|
|
140
135
|
product_router.register(r"aumchart", viewsets.AUMProductChartView, basename="product-aumchart")
|
|
141
136
|
product_router.register(r"claim", viewsets.ClaimProductModelViewSet, basename="product-claim")
|
|
137
|
+
product_router.register(r"feesaggregated", viewsets.FeesAggregatedProductPandasView, basename="product-feesaggregated")
|
|
138
|
+
product_router.register(r"fees", viewsets.FeesProductModelViewSet, basename="product-fees")
|
|
142
139
|
|
|
143
|
-
# Subrouter for
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
# Subrouter for Order Proposal
|
|
141
|
+
order_proposal_router = WBCoreRouter()
|
|
142
|
+
order_proposal_router.register(r"order", viewsets.OrderOrderProposalModelViewSet, basename="orderproposal-order")
|
|
146
143
|
|
|
147
144
|
trade_router = WBCoreRouter()
|
|
148
145
|
trade_router.register(r"claim", viewsets.ClaimTradeModelViewSet, basename="trade-claim")
|
|
@@ -253,7 +250,7 @@ urlpatterns = [
|
|
|
253
250
|
path("product/<int:product_id>/", include(product_router.urls)),
|
|
254
251
|
path("trade/<int:trade_id>/", include(trade_router.urls)),
|
|
255
252
|
path("portfolio/<int:portfolio_id>/", include(portfolio_router.urls)),
|
|
256
|
-
path("
|
|
253
|
+
path("orderproposal/<int:order_proposal_id>/", include(order_proposal_router.urls)),
|
|
257
254
|
path("instrument/<int:instrument_id>/", include(instrument_router.urls)),
|
|
258
255
|
path("account/<int:account_id>/", include(account_router.urls)),
|
|
259
256
|
path("entry/<int:entry_id>/", include(entry_router.urls)),
|
wbportfolio/viewsets/__init__.py
CHANGED
|
@@ -2,12 +2,16 @@ from .assets import (
|
|
|
2
2
|
AssetPositionInstrumentModelViewSet,
|
|
3
3
|
AssetPositionModelViewSet,
|
|
4
4
|
AssetPositionPortfolioModelViewSet,
|
|
5
|
-
AssetPositionUnderlyingInstrumentChartViewSet,
|
|
6
5
|
CashPositionPortfolioPandasAPIView,
|
|
7
6
|
CompositionModelPortfolioPandasView,
|
|
8
|
-
ContributorPortfolioChartView,
|
|
9
7
|
)
|
|
10
|
-
from .charts import
|
|
8
|
+
from .charts import (
|
|
9
|
+
DistributionChartViewSet,
|
|
10
|
+
DistributionTableViewSet,
|
|
11
|
+
AssetPositionUnderlyingInstrumentChartViewSet,
|
|
12
|
+
ContributorPortfolioChartView
|
|
13
|
+
|
|
14
|
+
)
|
|
11
15
|
from .custodians import CustodianModelViewSet, CustodianRepresentationViewSet
|
|
12
16
|
from .portfolio_relationship import InstrumentPreferedClassificationThroughProductModelViewSet
|
|
13
17
|
from .portfolios import (
|
|
@@ -23,8 +27,9 @@ from .positions import (
|
|
|
23
27
|
)
|
|
24
28
|
from .registers import RegisterModelViewSet, RegisterRepresentationViewSet
|
|
25
29
|
from .roles import PortfolioRoleInstrumentModelViewSet, PortfolioRoleModelViewSet
|
|
26
|
-
from .
|
|
30
|
+
from .rebalancing import RebalancingModelRepresentationViewSet, RebalancerRepresentationViewSet, RebalancerModelViewSet
|
|
27
31
|
from .transactions import *
|
|
32
|
+
from .orders import *
|
|
28
33
|
from .adjustments import AdjustmentEquityModelViewSet, AdjustmentModelViewSet
|
|
29
34
|
from .product_groups import ProductGroupModelViewSet, ProductGroupRepresentationViewSet
|
|
30
35
|
from .product_performance import (
|