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

Files changed (315) hide show
  1. wbportfolio/admin/__init__.py +1 -1
  2. wbportfolio/admin/asset.py +2 -1
  3. wbportfolio/admin/custodians.py +1 -0
  4. wbportfolio/admin/indexes.py +15 -0
  5. wbportfolio/admin/portfolio.py +12 -7
  6. wbportfolio/admin/portfolio_relationships.py +1 -0
  7. wbportfolio/admin/product_groups.py +2 -0
  8. wbportfolio/admin/products.py +2 -1
  9. wbportfolio/admin/reconciliations.py +1 -0
  10. wbportfolio/admin/registers.py +1 -0
  11. wbportfolio/admin/roles.py +1 -0
  12. wbportfolio/admin/transactions/__init__.py +1 -0
  13. wbportfolio/admin/transactions/claim.py +1 -0
  14. wbportfolio/admin/transactions/dividends.py +1 -0
  15. wbportfolio/admin/transactions/fees.py +1 -0
  16. wbportfolio/admin/transactions/rebalancing.py +26 -0
  17. wbportfolio/admin/transactions/trades.py +4 -3
  18. wbportfolio/admin/transactions/transactions.py +1 -0
  19. wbportfolio/analysis/claims.py +2 -1
  20. wbportfolio/contrib/company_portfolio/models.py +3 -6
  21. wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -12
  22. wbportfolio/contrib/company_portfolio/tests/test_models.py +1 -0
  23. wbportfolio/defaults/fees/default.py +1 -0
  24. wbportfolio/factories/__init__.py +1 -7
  25. wbportfolio/factories/adjustments.py +1 -0
  26. wbportfolio/factories/assets.py +13 -7
  27. wbportfolio/factories/claim.py +1 -0
  28. wbportfolio/factories/custodians.py +1 -0
  29. wbportfolio/factories/dividends.py +1 -0
  30. wbportfolio/factories/fees.py +1 -0
  31. wbportfolio/factories/indexes.py +1 -0
  32. wbportfolio/factories/portfolio_cash_flow.py +1 -0
  33. wbportfolio/factories/portfolio_cash_targets.py +1 -0
  34. wbportfolio/factories/portfolio_swing_pricings.py +1 -0
  35. wbportfolio/factories/portfolios.py +3 -0
  36. wbportfolio/factories/product_groups.py +1 -0
  37. wbportfolio/factories/products.py +1 -0
  38. wbportfolio/factories/rebalancing.py +23 -0
  39. wbportfolio/factories/reconciliations.py +1 -0
  40. wbportfolio/factories/roles.py +1 -0
  41. wbportfolio/factories/trades.py +1 -0
  42. wbportfolio/factories/transactions.py +1 -0
  43. wbportfolio/fdm/tasks.py +1 -0
  44. wbportfolio/filters/__init__.py +1 -1
  45. wbportfolio/filters/assets.py +8 -9
  46. wbportfolio/filters/assets_and_net_new_money_progression.py +1 -0
  47. wbportfolio/filters/custodians.py +1 -0
  48. wbportfolio/filters/esg.py +1 -0
  49. wbportfolio/filters/performances.py +7 -6
  50. wbportfolio/filters/portfolios.py +21 -1
  51. wbportfolio/filters/positions.py +1 -0
  52. wbportfolio/filters/products.py +1 -0
  53. wbportfolio/filters/roles.py +1 -0
  54. wbportfolio/filters/signals.py +1 -0
  55. wbportfolio/filters/transactions/claim.py +1 -0
  56. wbportfolio/filters/transactions/fees.py +1 -0
  57. wbportfolio/filters/transactions/trades.py +2 -1
  58. wbportfolio/filters/transactions/transactions.py +1 -0
  59. wbportfolio/import_export/backends/ubs/mixin.py +1 -0
  60. wbportfolio/import_export/backends/wbfdm/adjustment.py +1 -0
  61. wbportfolio/import_export/handlers/asset_position.py +11 -13
  62. wbportfolio/import_export/handlers/fees.py +1 -0
  63. wbportfolio/import_export/handlers/portfolio_cash_flow.py +1 -0
  64. wbportfolio/import_export/handlers/trade.py +1 -0
  65. wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +1 -0
  66. wbportfolio/import_export/parsers/jpmorgan/fees.py +1 -0
  67. wbportfolio/import_export/parsers/jpmorgan/strategy.py +5 -4
  68. wbportfolio/import_export/parsers/jpmorgan/valuation.py +1 -0
  69. wbportfolio/import_export/parsers/leonteq/customer_trade.py +1 -0
  70. wbportfolio/import_export/parsers/leonteq/equity.py +13 -12
  71. wbportfolio/import_export/parsers/leonteq/fees.py +1 -0
  72. wbportfolio/import_export/parsers/leonteq/trade.py +1 -0
  73. wbportfolio/import_export/parsers/leonteq/valuation.py +1 -0
  74. wbportfolio/import_export/parsers/natixis/customer_trade.py +1 -0
  75. wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +1 -0
  76. wbportfolio/import_export/parsers/natixis/d1_equity.py +3 -2
  77. wbportfolio/import_export/parsers/natixis/d1_fees.py +1 -0
  78. wbportfolio/import_export/parsers/natixis/d1_trade.py +1 -0
  79. wbportfolio/import_export/parsers/natixis/d1_valuation.py +1 -0
  80. wbportfolio/import_export/parsers/natixis/equity.py +5 -5
  81. wbportfolio/import_export/parsers/natixis/trade.py +1 -0
  82. wbportfolio/import_export/parsers/natixis/utils.py +8 -7
  83. wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +1 -0
  84. wbportfolio/import_export/parsers/sg_lux/customer_trade.py +1 -0
  85. wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +2 -1
  86. wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +2 -1
  87. wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +1 -0
  88. wbportfolio/import_export/parsers/sg_lux/equity.py +7 -8
  89. wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +1 -0
  90. wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +1 -0
  91. wbportfolio/import_export/parsers/sg_lux/registers.py +2 -1
  92. wbportfolio/import_export/parsers/societe_generale/customer_trade.py +1 -0
  93. wbportfolio/import_export/parsers/societe_generale/strategy.py +8 -9
  94. wbportfolio/import_export/parsers/societe_generale/valuation.py +1 -0
  95. wbportfolio/import_export/parsers/tellco/equity.py +5 -4
  96. wbportfolio/import_export/parsers/ubs/api/asset_position.py +15 -14
  97. wbportfolio/import_export/parsers/ubs/api/fees.py +1 -0
  98. wbportfolio/import_export/parsers/ubs/customer_trade.py +1 -0
  99. wbportfolio/import_export/parsers/ubs/equity.py +3 -2
  100. wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +1 -0
  101. wbportfolio/import_export/parsers/ubs/valuation.py +1 -0
  102. wbportfolio/import_export/parsers/vontobel/asset_position.py +19 -19
  103. wbportfolio/import_export/parsers/vontobel/customer_trade.py +1 -0
  104. wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +1 -0
  105. wbportfolio/import_export/parsers/vontobel/management_fees.py +1 -0
  106. wbportfolio/import_export/parsers/vontobel/performance_fees.py +1 -0
  107. wbportfolio/import_export/parsers/vontobel/trade.py +1 -0
  108. wbportfolio/import_export/parsers/vontobel/valuation_api.py +20 -0
  109. wbportfolio/import_export/resources/assets.py +4 -3
  110. wbportfolio/import_export/resources/trades.py +1 -0
  111. wbportfolio/metric/backends/base.py +1 -0
  112. wbportfolio/metric/backends/portfolio_base.py +1 -0
  113. wbportfolio/metric/backends/portfolio_esg.py +1 -0
  114. wbportfolio/metric/tests/test_portfolio_base.py +1 -0
  115. wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +1 -131
  116. wbportfolio/migrations/0067_assetposition_unique_asset_position.py +1 -1
  117. wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +1 -1
  118. wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +407 -0
  119. wbportfolio/models/__init__.py +0 -5
  120. wbportfolio/models/adjustments.py +8 -2
  121. wbportfolio/models/asset.py +117 -98
  122. wbportfolio/models/graphs/portfolio.py +144 -0
  123. wbportfolio/models/graphs/utils.py +83 -0
  124. wbportfolio/models/indexes.py +2 -13
  125. wbportfolio/models/mixins/instruments.py +28 -8
  126. wbportfolio/models/portfolio.py +538 -332
  127. wbportfolio/models/portfolio_cash_flow.py +1 -0
  128. wbportfolio/models/portfolio_relationship.py +6 -2
  129. wbportfolio/models/product_groups.py +3 -2
  130. wbportfolio/models/products.py +3 -17
  131. wbportfolio/models/reconciliations/account_reconciliation_lines.py +1 -0
  132. wbportfolio/models/reconciliations/account_reconciliations.py +1 -0
  133. wbportfolio/models/registers.py +1 -0
  134. wbportfolio/models/transactions/__init__.py +1 -0
  135. wbportfolio/models/transactions/claim.py +8 -8
  136. wbportfolio/models/transactions/dividends.py +1 -0
  137. wbportfolio/models/transactions/fees.py +1 -0
  138. wbportfolio/models/transactions/rebalancing.py +153 -0
  139. wbportfolio/models/transactions/trade_proposals.py +153 -155
  140. wbportfolio/models/transactions/trades.py +48 -40
  141. wbportfolio/models/transactions/transactions.py +6 -12
  142. wbportfolio/models/utils.py +1 -0
  143. wbportfolio/pms/analytics/__init__.py +0 -0
  144. wbportfolio/pms/analytics/portfolio.py +28 -0
  145. wbportfolio/pms/trading/handler.py +13 -16
  146. wbportfolio/pms/typing.py +13 -29
  147. wbportfolio/rebalancing/__init__.py +0 -0
  148. wbportfolio/rebalancing/base.py +16 -0
  149. wbportfolio/rebalancing/decorators.py +17 -0
  150. wbportfolio/rebalancing/models/__init__.py +3 -0
  151. wbportfolio/rebalancing/models/composite.py +31 -0
  152. wbportfolio/rebalancing/models/equally_weighted.py +21 -0
  153. wbportfolio/rebalancing/models/model_portfolio.py +35 -0
  154. wbportfolio/reports/monthly_position_report.py +1 -1
  155. wbportfolio/risk_management/backends/accounts.py +7 -6
  156. wbportfolio/risk_management/backends/controversy_portfolio.py +1 -0
  157. wbportfolio/risk_management/backends/exposure_portfolio.py +1 -0
  158. wbportfolio/risk_management/backends/instrument_list_portfolio.py +1 -0
  159. wbportfolio/risk_management/backends/liquidity_risk.py +1 -0
  160. wbportfolio/risk_management/backends/liquidity_stress_instrument.py +1 -0
  161. wbportfolio/risk_management/backends/mixins.py +1 -0
  162. wbportfolio/risk_management/backends/product_integrity.py +6 -1
  163. wbportfolio/risk_management/backends/stop_loss_instrument.py +1 -0
  164. wbportfolio/risk_management/backends/stop_loss_portfolio.py +1 -0
  165. wbportfolio/risk_management/backends/ucits_portfolio.py +1 -0
  166. wbportfolio/risk_management/tests/test_accounts.py +1 -0
  167. wbportfolio/risk_management/tests/test_controversy_portfolio.py +1 -0
  168. wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -0
  169. wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +1 -0
  170. wbportfolio/risk_management/tests/test_liquidity_risk.py +1 -0
  171. wbportfolio/risk_management/tests/test_product_integrity.py +1 -0
  172. wbportfolio/risk_management/tests/test_stop_loss_instrument.py +1 -0
  173. wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -0
  174. wbportfolio/risk_management/tests/test_ucits_portfolio.py +1 -0
  175. wbportfolio/serializers/__init__.py +5 -5
  176. wbportfolio/serializers/adjustments.py +1 -0
  177. wbportfolio/serializers/assets.py +18 -19
  178. wbportfolio/serializers/custodians.py +1 -0
  179. wbportfolio/serializers/portfolio_cash_flow.py +1 -0
  180. wbportfolio/serializers/portfolio_cash_targets.py +1 -0
  181. wbportfolio/serializers/portfolio_relationship.py +1 -0
  182. wbportfolio/serializers/portfolio_swing_pricing.py +1 -0
  183. wbportfolio/serializers/portfolios.py +61 -40
  184. wbportfolio/serializers/positions.py +1 -0
  185. wbportfolio/serializers/product_group.py +1 -0
  186. wbportfolio/serializers/products.py +4 -7
  187. wbportfolio/serializers/rebalancing.py +57 -0
  188. wbportfolio/serializers/reconciliations.py +2 -1
  189. wbportfolio/serializers/registers.py +1 -0
  190. wbportfolio/serializers/roles.py +1 -0
  191. wbportfolio/serializers/signals.py +10 -15
  192. wbportfolio/serializers/transactions/__init__.py +1 -1
  193. wbportfolio/serializers/transactions/claim.py +1 -0
  194. wbportfolio/serializers/transactions/fees.py +1 -0
  195. wbportfolio/serializers/transactions/trade_proposals.py +85 -0
  196. wbportfolio/serializers/transactions/trades.py +9 -51
  197. wbportfolio/serializers/transactions/transactions.py +4 -3
  198. wbportfolio/tasks.py +1 -78
  199. wbportfolio/tests/conftest.py +6 -13
  200. wbportfolio/tests/models/test_account_reconciliation.py +2 -0
  201. wbportfolio/tests/models/test_assets.py +27 -19
  202. wbportfolio/tests/models/test_customer_trades.py +1 -0
  203. wbportfolio/tests/models/test_imports.py +5 -1
  204. wbportfolio/tests/models/test_merge.py +5 -4
  205. wbportfolio/tests/models/test_portfolio_cash_flow.py +8 -6
  206. wbportfolio/tests/models/test_portfolios.py +594 -154
  207. wbportfolio/tests/models/test_product_groups.py +1 -0
  208. wbportfolio/tests/models/test_products.py +6 -3
  209. wbportfolio/tests/models/test_roles.py +1 -0
  210. wbportfolio/tests/models/test_splits.py +1 -0
  211. wbportfolio/tests/models/transactions/test_claim.py +1 -0
  212. wbportfolio/tests/models/transactions/test_fees.py +1 -0
  213. wbportfolio/tests/models/transactions/test_rebalancing.py +81 -0
  214. wbportfolio/tests/models/transactions/test_trades.py +1 -0
  215. wbportfolio/tests/models/utils.py +1 -0
  216. wbportfolio/tests/pms/__init__.py +0 -0
  217. wbportfolio/tests/pms/test_analytics.py +35 -0
  218. wbportfolio/tests/rebalancing/__init__.py +0 -0
  219. wbportfolio/tests/rebalancing/test_models.py +127 -0
  220. wbportfolio/tests/serializers/test_claims.py +1 -0
  221. wbportfolio/tests/signals.py +1 -7
  222. wbportfolio/tests/tests.py +2 -0
  223. wbportfolio/tests/viewsets/test_assets.py +1 -0
  224. wbportfolio/tests/viewsets/test_performances.py +1 -0
  225. wbportfolio/tests/viewsets/test_products.py +1 -0
  226. wbportfolio/tests/viewsets/transactions/test_claims.py +1 -0
  227. wbportfolio/urls.py +26 -12
  228. wbportfolio/viewsets/__init__.py +2 -5
  229. wbportfolio/viewsets/adjustments.py +1 -0
  230. wbportfolio/viewsets/assets.py +62 -51
  231. wbportfolio/viewsets/assets_and_net_new_money_progression.py +1 -0
  232. wbportfolio/viewsets/charts/assets.py +3 -1
  233. wbportfolio/viewsets/configs/buttons/__init__.py +1 -1
  234. wbportfolio/viewsets/configs/buttons/assets.py +1 -0
  235. wbportfolio/viewsets/configs/buttons/custodians.py +1 -0
  236. wbportfolio/viewsets/configs/buttons/mixins.py +1 -20
  237. wbportfolio/viewsets/configs/buttons/portfolios.py +90 -76
  238. wbportfolio/viewsets/configs/buttons/signals.py +1 -0
  239. wbportfolio/viewsets/configs/buttons/trades.py +1 -0
  240. wbportfolio/viewsets/configs/display/__init__.py +2 -1
  241. wbportfolio/viewsets/configs/display/adjustments.py +1 -0
  242. wbportfolio/viewsets/configs/display/assets.py +7 -6
  243. wbportfolio/viewsets/configs/display/claim.py +1 -0
  244. wbportfolio/viewsets/configs/display/portfolios.py +127 -79
  245. wbportfolio/viewsets/configs/display/product_performance.py +1 -0
  246. wbportfolio/viewsets/configs/display/rebalancing.py +27 -0
  247. wbportfolio/viewsets/configs/display/trade_proposals.py +7 -4
  248. wbportfolio/viewsets/configs/display/trades.py +75 -42
  249. wbportfolio/viewsets/configs/endpoints/__init__.py +3 -1
  250. wbportfolio/viewsets/configs/endpoints/claim.py +1 -0
  251. wbportfolio/viewsets/configs/endpoints/portfolios.py +23 -7
  252. wbportfolio/viewsets/configs/endpoints/rebalancing.py +6 -0
  253. wbportfolio/viewsets/configs/endpoints/reconciliations.py +1 -0
  254. wbportfolio/viewsets/configs/endpoints/trade_proposals.py +1 -0
  255. wbportfolio/viewsets/configs/endpoints/trades.py +1 -0
  256. wbportfolio/viewsets/configs/menu/adjustments.py +1 -0
  257. wbportfolio/viewsets/configs/menu/assets.py +1 -0
  258. wbportfolio/viewsets/configs/menu/fees.py +1 -0
  259. wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +1 -0
  260. wbportfolio/viewsets/configs/menu/portfolios.py +4 -2
  261. wbportfolio/viewsets/configs/menu/positions.py +1 -0
  262. wbportfolio/viewsets/configs/menu/roles.py +1 -0
  263. wbportfolio/viewsets/configs/menu/transactions.py +1 -0
  264. wbportfolio/viewsets/configs/previews/portfolios.py +1 -6
  265. wbportfolio/viewsets/configs/titles/__init__.py +1 -1
  266. wbportfolio/viewsets/configs/titles/assets.py +1 -0
  267. wbportfolio/viewsets/configs/titles/fees.py +1 -0
  268. wbportfolio/viewsets/configs/titles/instrument_prices.py +1 -0
  269. wbportfolio/viewsets/configs/titles/portfolios.py +13 -11
  270. wbportfolio/viewsets/configs/titles/roles.py +1 -0
  271. wbportfolio/viewsets/configs/titles/trades.py +1 -0
  272. wbportfolio/viewsets/configs/titles/transactions.py +1 -0
  273. wbportfolio/viewsets/custodians.py +1 -0
  274. wbportfolio/viewsets/esg.py +1 -0
  275. wbportfolio/viewsets/mixins.py +1 -0
  276. wbportfolio/viewsets/portfolio_cash_flow.py +1 -0
  277. wbportfolio/viewsets/portfolio_cash_targets.py +1 -0
  278. wbportfolio/viewsets/portfolio_relationship.py +1 -0
  279. wbportfolio/viewsets/portfolio_swing_pricing.py +1 -0
  280. wbportfolio/viewsets/portfolios.py +228 -61
  281. wbportfolio/viewsets/positions.py +3 -2
  282. wbportfolio/viewsets/product_groups.py +1 -0
  283. wbportfolio/viewsets/product_performance.py +1 -0
  284. wbportfolio/viewsets/products.py +1 -0
  285. wbportfolio/viewsets/reconciliations.py +1 -0
  286. wbportfolio/viewsets/registers.py +1 -0
  287. wbportfolio/viewsets/roles.py +1 -0
  288. wbportfolio/viewsets/signals.py +1 -0
  289. wbportfolio/viewsets/transactions/__init__.py +1 -0
  290. wbportfolio/viewsets/transactions/claim.py +2 -1
  291. wbportfolio/viewsets/transactions/fees.py +1 -0
  292. wbportfolio/viewsets/transactions/mixins.py +1 -0
  293. wbportfolio/viewsets/transactions/rebalancing.py +31 -0
  294. wbportfolio/viewsets/transactions/trade_proposals.py +25 -5
  295. wbportfolio/viewsets/transactions/trades.py +16 -9
  296. wbportfolio/viewsets/transactions/transactions.py +1 -0
  297. {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/METADATA +4 -1
  298. {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/RECORD +301 -288
  299. wbportfolio/admin/synchronization/__init__.py +0 -2
  300. wbportfolio/admin/synchronization/admin.py +0 -114
  301. wbportfolio/admin/synchronization/portfolio_synchronization.py +0 -18
  302. wbportfolio/admin/synchronization/price_computation.py +0 -21
  303. wbportfolio/defaults/portfolio/default_rebalancing.py +0 -45
  304. wbportfolio/factories/pytest_utils.py +0 -121
  305. wbportfolio/factories/synchronization.py +0 -40
  306. wbportfolio/models/synchronization/__init__.py +0 -3
  307. wbportfolio/models/synchronization/portfolio_synchronization.py +0 -292
  308. wbportfolio/models/synchronization/price_computation.py +0 -200
  309. wbportfolio/models/synchronization/synchronization.py +0 -188
  310. wbportfolio/serializers/synchronization.py +0 -18
  311. wbportfolio/tests/models/test_synchronization.py +0 -617
  312. wbportfolio/viewsets/synchronization.py +0 -25
  313. /wbportfolio/{defaults/portfolio → models/graphs}/__init__.py +0 -0
  314. {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/WHEEL +0 -0
  315. {wbportfolio-1.44.5.dist-info → wbportfolio-1.45.0.dist-info}/licenses/LICENSE +0 -0
@@ -10,12 +10,7 @@ class PortfolioPreviewConfig(PreviewViewConfig):
10
10
  def get_display(self) -> Display:
11
11
  return create_simple_display(
12
12
  [
13
- [
14
- "name",
15
- "name",
16
- "currency",
17
- ],
18
- [repeat_field(2, "portfolio_synchronization"), "last_synchronization"],
13
+ ["name", "currency", "updated_at"],
19
14
  [repeat_field(3, "depends_on")],
20
15
  ]
21
16
  )
@@ -38,7 +38,7 @@ from .instrument_prices import (
38
38
  NominalProductTitleConfig,
39
39
  )
40
40
 
41
- from .portfolios import ModelPortfolioTitleConfig, PortfolioTitleConfig, DailyPortfolioCashFlowTitleConfig
41
+ from .portfolios import PortfolioTitleConfig, DailyPortfolioCashFlowTitleConfig, PortfolioTreeGraphChartTitleConfig, TopDownPortfolioCompositionPandasTitleConfig
42
42
  from .positions import (
43
43
  AggregatedAssetPositionLiquidityTitleConfig,
44
44
  AssetPositionPandasTitleConfig,
@@ -1,5 +1,6 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
2
  from wbfdm.models import Instrument
3
+
3
4
  from wbportfolio.models import Portfolio
4
5
 
5
6
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbportfolio.models import Portfolio
3
4
 
4
5
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbportfolio.models import Product
3
4
 
4
5
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbportfolio.models.portfolio import Portfolio
3
4
 
4
5
 
@@ -13,20 +14,21 @@ class PortfolioTitleConfig(TitleViewConfig):
13
14
  return "New Portfolio"
14
15
 
15
16
 
16
- class ModelPortfolioTitleConfig(TitleViewConfig):
17
- def get_list_title(self):
18
- return "Model Portfolios"
19
-
20
- def get_instance_title(self):
21
- return "Model Portfolio: {{ name }}"
22
-
23
- def get_create_title(self):
24
- return "New Model Portfolio"
25
-
26
-
27
17
  class DailyPortfolioCashFlowTitleConfig(TitleViewConfig):
28
18
  def get_list_title(self):
29
19
  if portfolio_id := self.view.kwargs.get("portfolio_id", None):
30
20
  portfolio = Portfolio.objects.get(id=portfolio_id)
31
21
  return f"{portfolio}: Daily Portfolio Cash Flow"
32
22
  return "Daily Portfolio Cash Flow"
23
+
24
+
25
+ class PortfolioTreeGraphChartTitleConfig(TitleViewConfig):
26
+ def get_list_title(self):
27
+ portfolio = self.view.portfolio
28
+ return f"Tree Graph Chart for {portfolio}"
29
+
30
+
31
+ class TopDownPortfolioCompositionPandasTitleConfig(TitleViewConfig):
32
+ def get_list_title(self):
33
+ portfolio = self.view.portfolio
34
+ return f"Top-Down Composition for {portfolio}"
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbportfolio.models import Product
3
4
 
4
5
 
@@ -1,5 +1,6 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
2
  from wbfdm.models import Instrument
3
+
3
4
  from wbportfolio.models import Portfolio
4
5
 
5
6
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.titles import TitleViewConfig
2
+
2
3
  from wbportfolio.models import Portfolio
3
4
 
4
5
 
@@ -4,6 +4,7 @@ from rest_framework.decorators import action
4
4
  from rest_framework.response import Response
5
5
  from wbcore import viewsets
6
6
  from wbcore.permissions.permissions import InternalUserPermissionMixin
7
+
7
8
  from wbportfolio.filters import CustodianFilterSet
8
9
  from wbportfolio.models import Custodian
9
10
  from wbportfolio.serializers import (
@@ -11,6 +11,7 @@ from wbcore.utils.strings import format_number
11
11
  from wbfdm.analysis.esg.enums import AggregationMethod, ESGAggregation
12
12
  from wbfdm.analysis.esg.esg_analysis import DataLoader
13
13
  from wbfdm.models import Instrument
14
+
14
15
  from wbportfolio.filters import ESGMetricAggregationPortfolioPandasFilterSet
15
16
  from wbportfolio.models import AssetPosition
16
17
  from wbportfolio.viewsets.configs import (
@@ -1,6 +1,7 @@
1
1
  from django.shortcuts import get_object_or_404
2
2
  from django.utils.functional import cached_property
3
3
  from wbfdm.models import Instrument
4
+
4
5
  from wbportfolio.models import Portfolio, PortfolioRole
5
6
 
6
7
 
@@ -1,5 +1,6 @@
1
1
  from django.db.models import Case, F, Value, When
2
2
  from wbcore import viewsets
3
+
3
4
  from wbportfolio.models import DailyPortfolioCashFlow
4
5
  from wbportfolio.serializers import DailyPortfolioCashFlowModelSerializer
5
6
  from wbportfolio.viewsets.configs.display import DailyPortfolioCashFlowDisplayConfig
@@ -1,4 +1,5 @@
1
1
  from wbcore import viewsets
2
+
2
3
  from wbportfolio.models import PortfolioCashTarget
3
4
  from wbportfolio.serializers import PortfolioCashTargetModelSerializer
4
5
 
@@ -1,5 +1,6 @@
1
1
  from wbcore import viewsets
2
2
  from wbcore.permissions.permissions import InternalUserPermissionMixin
3
+
3
4
  from wbportfolio.models import (
4
5
  InstrumentPortfolioThroughModel,
5
6
  PortfolioInstrumentPreferredClassificationThroughModel,
@@ -1,4 +1,5 @@
1
1
  from wbcore import viewsets
2
+
2
3
  from wbportfolio.models.portfolio_swing_pricings import PortfolioSwingPricing
3
4
  from wbportfolio.serializers import PortfolioSwingPricingModelSerializer
4
5
 
@@ -1,34 +1,41 @@
1
- from datetime import datetime
1
+ from contextlib import suppress
2
+ from datetime import date, datetime
2
3
 
4
+ import pandas as pd
5
+ from django.db.models import Q
3
6
  from django.http import HttpResponse
4
7
  from django.shortcuts import get_object_or_404
8
+ from django.utils.dateparse import parse_date
9
+ from django.utils.functional import cached_property
5
10
  from rest_framework.decorators import action
11
+ from rest_framework.permissions import IsAdminUser
6
12
  from rest_framework.response import Response
13
+ from rest_framework.reverse import reverse
7
14
  from wbcore import viewsets
8
15
  from wbcore.contrib.currency.models import Currency
16
+ from wbcore.contrib.io.viewsets import ExportPandasAPIViewSet
17
+ from wbcore.pandas import fields as pf
9
18
  from wbcore.permissions.permissions import InternalUserPermissionMixin
10
- from wbcore.utils.date import get_date_interval_from_request
11
- from wbportfolio.filters import PortfolioFilterSet
19
+ from wbfdm.models import Instrument
20
+
21
+ from wbportfolio.filters import PortfolioFilterSet, PortfolioTreeGraphChartFilterSet
12
22
  from wbportfolio.models import (
23
+ AssetPosition,
13
24
  Portfolio,
14
25
  PortfolioPortfolioThroughModel,
15
- PortfolioSynchronization,
16
- PriceComputation,
26
+ Rebalancer,
27
+ RebalancingModel,
17
28
  TradeProposal,
18
29
  )
19
- from wbportfolio.models.portfolio import resynchronize_history_as_task
30
+ from wbportfolio.models.portfolio import batch_recompute_lookthrough_as_task
20
31
  from wbportfolio.serializers import (
21
- ModelPortfolioModelSerializer,
22
32
  PortfolioModelSerializer,
23
33
  PortfolioPortfolioThroughModelSerializer,
24
34
  PortfolioRepresentationSerializer,
25
35
  )
26
36
 
37
+ from ..models.graphs.portfolio import PortfolioGraph
27
38
  from .configs import (
28
- ModelPortfolioButtonConfig,
29
- ModelPortfolioDisplayConfig,
30
- ModelPortfolioEndpointConfig,
31
- ModelPortfolioTitleConfig,
32
39
  PortfolioButtonConfig,
33
40
  PortfolioDisplayConfig,
34
41
  PortfolioEndpointConfig,
@@ -36,6 +43,11 @@ from .configs import (
36
43
  PortfolioPortfolioThroughModelEndpointConfig,
37
44
  PortfolioPreviewConfig,
38
45
  PortfolioTitleConfig,
46
+ PortfolioTreeGraphChartEndpointConfig,
47
+ PortfolioTreeGraphChartTitleConfig,
48
+ TopDownPortfolioCompositionPandasDisplayConfig,
49
+ TopDownPortfolioCompositionPandasEndpointConfig,
50
+ TopDownPortfolioCompositionPandasTitleConfig,
39
51
  )
40
52
  from .mixins import UserPortfolioRequestPermissionMixin
41
53
 
@@ -70,75 +82,70 @@ class PortfolioModelViewSet(UserPortfolioRequestPermissionMixin, InternalUserPer
70
82
  .get_queryset()
71
83
  .select_related(
72
84
  "currency",
73
- "portfolio_synchronization",
74
85
  )
75
86
  .prefetch_related(
76
87
  "depends_on",
77
- "dependent_portfolios",
78
88
  )
79
89
  )
80
90
 
81
- @action(detail=True, methods=["PATCH"])
91
+ @action(detail=True, methods=["POST"])
82
92
  def rebalance(self, request, pk=None):
83
- if (date_str := request.POST.get("trade_date", None)) and (
84
- model_portfolio_id := request.POST.get("model_portfolio", None)
85
- ):
86
- TradeProposal.objects.create(
87
- portfolio=Portfolio.objects.get(id=pk),
88
- model_portfolio=Portfolio.objects.get(id=model_portfolio_id),
89
- trade_date=datetime.strptime(date_str, "%Y-%m-%d"),
93
+ if date_str := request.POST.get("trade_date", None):
94
+ trade_date = datetime.strptime(date_str, "%Y-%m-%d")
95
+ trade_proposal, _ = TradeProposal.objects.get_or_create(portfolio_id=pk, trade_date=trade_date)
96
+ trade_proposal.reset_trades()
97
+ return Response(
98
+ {"endpoint": reverse("wbportfolio:tradeproposal-detail", args=[trade_proposal.id], request=request)}
90
99
  )
91
- return Response({"send": True})
92
100
  raise HttpResponse("Bad Request", status=400)
93
101
 
94
- @action(detail=True, methods=["PATCH"])
95
- def resynchronize(self, request, pk=None):
96
- if request.user.has_perm("wbportfolio.administrate_instrument"):
97
- portfolio = get_object_or_404(Portfolio, pk=pk)
98
- instrument = request.GET.get("instrument", None)
99
- start, end = get_date_interval_from_request(request, request_type="POST")
100
- resynchronize_history_as_task.delay(portfolio.id, start, end, instrument_id=instrument)
101
- return Response({"send": True})
102
- return HttpResponse("Unauthorized", status=401)
103
-
104
-
105
- class ModelPortfolioModelViewSet(PortfolioModelViewSet):
106
- serializer_class = ModelPortfolioModelSerializer
107
- endpoint_config_class = ModelPortfolioEndpointConfig
108
- display_config_class = ModelPortfolioDisplayConfig
109
- title_config_class = ModelPortfolioTitleConfig
110
- button_config_class = ModelPortfolioButtonConfig
111
-
112
102
  @action(detail=False, methods=["POST"])
113
103
  def createmodelportfolio(self, request, pk=None):
114
104
  if self.is_portfolio_manager:
115
105
  name = request.POST["name"]
116
106
  currency_id = request.POST["currency"]
117
107
  currency = Currency.objects.get(id=currency_id)
118
- portfolio_synchronization_id = request.POST.get("portfolio_synchronization", None)
119
- price_computation_id = request.POST.get("price_computation", None)
120
- portfolio_synchronization = (
121
- PortfolioSynchronization.objects.get(id=portfolio_synchronization_id)
122
- if portfolio_synchronization_id
123
- else None
124
- )
125
- create_index = request.POST.get("create_index", "false") == "true"
126
108
  index_parameters = {}
127
- if create_index:
128
- index_parameters["price_computation"] = (
129
- PriceComputation.objects.get(id=price_computation_id) if price_computation_id else None
130
- )
131
- Portfolio.create_model_portfolio(
132
- name, currency, portfolio_synchronization=portfolio_synchronization, index_parameters=index_parameters
133
- )
109
+ Portfolio.create_model_portfolio(name, currency, index_parameters=index_parameters)
134
110
  return Response({"send": True})
135
111
  raise HttpResponse("Unauthorized", status=403)
136
112
 
137
- def get_queryset(self):
138
- model_portfolios = PortfolioPortfolioThroughModel.objects.filter(
139
- type=PortfolioPortfolioThroughModel.Type.MODEL
140
- ).values("dependency_portfolio")
141
- return super().get_queryset().filter(id__in=model_portfolios)
113
+ @action(detail=True, methods=["POST"])
114
+ def attachrebalancer(self, request, pk=None):
115
+ try:
116
+ activation_date = datetime.strptime(request.POST["activation_date"], "%Y-%m-%d")
117
+ rebalancing_model = get_object_or_404(RebalancingModel, pk=request.POST["rebalancing_model"])
118
+ frequency = request.POST["frequency"]
119
+ approve_trade_proposal_automatically = (
120
+ request.POST.get("approve_trade_proposal_automatically", "false") == "true"
121
+ )
122
+
123
+ rebalancer, _ = Rebalancer.objects.update_or_create(
124
+ portfolio=self.get_object(),
125
+ defaults={
126
+ "rebalancing_model": rebalancing_model,
127
+ "frequency": frequency,
128
+ "activation_date": activation_date,
129
+ "approve_trade_proposal_automatically": approve_trade_proposal_automatically,
130
+ },
131
+ )
132
+ return Response(
133
+ {"endpoint": reverse("wbportfolio:rebalancer-detail", args=[rebalancer.id], request=request)}
134
+ )
135
+ except KeyError:
136
+ return HttpResponse("Bad arguments", status=400)
137
+
138
+ @action(detail=True, methods=["POST"], permission_classes=[IsAdminUser])
139
+ def recomputelookthrough(self, request, pk=None):
140
+ portfolio = self.get_object()
141
+ if portfolio.is_lookthrough:
142
+ with suppress(KeyError):
143
+ start = datetime.strptime(request.POST["start"], "%Y-%m-%d")
144
+ end = datetime.strptime(request.POST["end"], "%Y-%m-%d")
145
+ batch_recompute_lookthrough_as_task.delay(portfolio.id, start, end)
146
+ return HttpResponse("Ok", status=200)
147
+
148
+ return HttpResponse("Bad arguments", status=400)
142
149
 
143
150
 
144
151
  class PortfolioPortfolioThroughModelViewSet(InternalUserPermissionMixin, viewsets.ModelViewSet):
@@ -151,4 +158,164 @@ class PortfolioPortfolioThroughModelViewSet(InternalUserPermissionMixin, viewset
151
158
  endpoint_config_class = PortfolioPortfolioThroughModelEndpointConfig
152
159
 
153
160
  def get_queryset(self):
154
- return super().get_queryset().filter(portfolio=self.kwargs["portfolio_id"])
161
+ return (
162
+ super()
163
+ .get_queryset()
164
+ .filter(Q(portfolio=self.kwargs["portfolio_id"]) | Q(dependency_portfolio=self.kwargs["portfolio_id"]))
165
+ )
166
+
167
+
168
+ class PortfolioTreeGraphChartViewSet(UserPortfolioRequestPermissionMixin, viewsets.HTMLViewSet):
169
+ filterset_class = PortfolioTreeGraphChartFilterSet
170
+ IDENTIFIER = "wbportfolio:portfolio-treegraphchart"
171
+ queryset = Portfolio.objects.all()
172
+
173
+ title_config_class = PortfolioTreeGraphChartTitleConfig
174
+ endpoint_config_class = PortfolioTreeGraphChartEndpointConfig
175
+
176
+ def get_queryset(self):
177
+ return super().get_queryset().filter(id=self.kwargs["portfolio_id"])
178
+
179
+ @cached_property
180
+ def val_date(self) -> date:
181
+ return parse_date(self.request.GET["date"])
182
+
183
+ def get_html(self, queryset) -> str:
184
+ portfolio_graph = PortfolioGraph(self.portfolio, self.val_date)
185
+ return portfolio_graph.to_svg()
186
+
187
+
188
+ class TopDownPortfolioCompositionPandasAPIView(UserPortfolioRequestPermissionMixin, ExportPandasAPIViewSet):
189
+ IDENTIFIER = "wbportfolio:topdowncomposition"
190
+ queryset = Portfolio.objects.all()
191
+
192
+ display_config_class = TopDownPortfolioCompositionPandasDisplayConfig
193
+ title_config_class = TopDownPortfolioCompositionPandasTitleConfig
194
+ endpoint_config_class = TopDownPortfolioCompositionPandasEndpointConfig
195
+
196
+ pandas_fields = pf.PandasFields(
197
+ fields=[
198
+ pf.PKField(key="id", label="ID"),
199
+ pf.CharField(key="_group_key", label="Group Key"),
200
+ pf.IntegerField(key="parent_row_id", label="Parent Row"),
201
+ pf.CharField(key="instrument", label="Instrument"),
202
+ pf.FloatField(key="effective_weights", label="Effective Weights", precision=2, percent=True),
203
+ pf.FloatField(key="rebalancing_weights", label="Rebalancing Weights", precision=2, percent=True),
204
+ ]
205
+ )
206
+
207
+ @cached_property
208
+ def composition_portfolio(self) -> Portfolio | None:
209
+ return self.portfolio.composition_portfolio or self.portfolio
210
+
211
+ @cached_property
212
+ def last_rebalancing_date(self) -> date | None:
213
+ if self.composition_portfolio:
214
+ with suppress(TradeProposal.DoesNotExist):
215
+ return (
216
+ self.composition_portfolio.trade_proposals.filter(trade_date__lte=self.last_effective_date)
217
+ .latest("trade_date")
218
+ .trade_date
219
+ )
220
+
221
+ @cached_property
222
+ def last_effective_date(self) -> date | None:
223
+ if self.composition_portfolio:
224
+ with suppress(AssetPosition.DoesNotExist):
225
+ return self.composition_portfolio.assets.latest("date").date
226
+
227
+ def get_dataframe(self, request, queryset, **kwargs):
228
+ df = pd.DataFrame(columns=["id", "parent_row_id", "instrument", "effective_weights", "rebalancing_weights"])
229
+
230
+ def _get_parent_instrument_id(portfolio):
231
+ with suppress(AttributeError):
232
+ return portfolio.instruments.first().id
233
+
234
+ if (
235
+ self.has_portfolio_access
236
+ and self.composition_portfolio
237
+ and self.last_rebalancing_date
238
+ and self.last_effective_date
239
+ ):
240
+ tree_positions_effective_date_df = (
241
+ pd.DataFrame(
242
+ map(
243
+ lambda x: {
244
+ "instrument": x.underlying_instrument.id,
245
+ "parent_instrument": _get_parent_instrument_id(
246
+ getattr(x, "parent_portfolio", "portfolio")
247
+ ),
248
+ "effective_weights": x.weighting,
249
+ },
250
+ self.composition_portfolio.get_positions(
251
+ self.last_effective_date, with_intermediary_position=True
252
+ ),
253
+ ),
254
+ columns=["instrument", "parent_instrument", "effective_weights"],
255
+ )
256
+ .groupby(["parent_instrument", "instrument"])
257
+ .sum()
258
+ )
259
+ tree_positions_rebalancing_date_df = (
260
+ pd.DataFrame(
261
+ map(
262
+ lambda x: {
263
+ "instrument": x.underlying_instrument.id,
264
+ "parent_instrument": _get_parent_instrument_id(
265
+ getattr(x, "parent_portfolio", "portfolio")
266
+ ),
267
+ "rebalancing_weights": x.weighting,
268
+ },
269
+ self.composition_portfolio.get_positions(
270
+ self.last_rebalancing_date, with_intermediary_position=True
271
+ ),
272
+ ),
273
+ columns=["instrument", "parent_instrument", "rebalancing_weights"],
274
+ )
275
+ .groupby(["parent_instrument", "instrument"])
276
+ .sum()
277
+ )
278
+
279
+ df = pd.concat(
280
+ [tree_positions_effective_date_df, tree_positions_rebalancing_date_df], axis=1
281
+ ).reset_index()
282
+
283
+ if not df["parent_instrument"].isnull().any():
284
+ df = pd.concat(
285
+ [
286
+ pd.DataFrame(
287
+ [
288
+ {
289
+ "instrument": self.portfolio.instruments.first().id,
290
+ "parent_instrument": None,
291
+ "effective_weights": 1.0,
292
+ "rebalancing_weights": 1.0,
293
+ }
294
+ ]
295
+ ),
296
+ df,
297
+ ],
298
+ ignore_index=True,
299
+ )
300
+
301
+ df = df.reset_index(names="id")
302
+
303
+ def _get_parent_id(x):
304
+ dff = df.loc[df["instrument"] == x, "id"]
305
+ if not dff.empty:
306
+ return dff.iloc[0]
307
+ return None
308
+
309
+ def _get_group_key(x):
310
+ return str(int(x)) if not df.loc[df["parent_row_id"] == x, :].empty else None
311
+
312
+ df["parent_row_id"] = df["parent_instrument"].apply(lambda x: _get_parent_id(x))
313
+ df["_group_key"] = df["id"].apply(lambda x: _get_group_key(x))
314
+ df = df.drop(columns=["parent_instrument"])
315
+ return df
316
+
317
+ def manipulate_dataframe(self, df):
318
+ df["instrument"] = df["instrument"].map(
319
+ dict(Instrument.objects.filter(id__in=df["instrument"]).values_list("id", "name_repr"))
320
+ )
321
+ return df
@@ -10,7 +10,8 @@ from wbcore.pandas import fields as pf
10
10
  from wbcore.permissions.permissions import InternalUserPermissionMixin
11
11
  from wbcore.serializers import decorator
12
12
  from wbcore.utils.strings import format_number
13
- from wbfdm.models import Classification, ClassificationGroup, Instrument
13
+ from wbfdm.models import Classification, ClassificationGroup, Instrument, InstrumentType
14
+
14
15
  from wbportfolio.filters import (
15
16
  AggregatedAssetPositionLiquidityFilter,
16
17
  AssetPositionPandasFilter,
@@ -212,7 +213,7 @@ class AggregatedAssetPositionLiquidityPandasView(InternalUserPermissionMixin, Ex
212
213
 
213
214
  # Take the liquidity query for the two dates.
214
215
  qs_assets = queryset.filter(
215
- underlying_security_instrument_type_key="equity",
216
+ underlying_instrument__instrument_type=InstrumentType.EQUITY,
216
217
  date__in=[historic_date, compared_date],
217
218
  ).values(
218
219
  "date",
@@ -1,5 +1,6 @@
1
1
  from wbcore import viewsets
2
2
  from wbfdm.viewsets.configs.buttons.instruments import InstrumentButtonViewConfig
3
+
3
4
  from wbportfolio.models import ProductGroup
4
5
  from wbportfolio.serializers import (
5
6
  ProductGroupModelSerializer,
@@ -24,6 +24,7 @@ from wbcore.permissions.permissions import InternalUserPermissionMixin
24
24
  from wbcore.utils.date import get_date_interval_from_request
25
25
  from wbcore.utils.strings import format_number
26
26
  from wbfdm.models import Instrument, InstrumentPrice, RelatedInstrumentThroughModel
27
+
27
28
  from wbportfolio.filters import (
28
29
  PerformanceComparisonFilter,
29
30
  PerformancePandasFilter,
@@ -36,6 +36,7 @@ from wbcore.utils.strings import format_number
36
36
  from wbfdm.contrib.metric.backends.performances import PERFORMANCE_METRIC
37
37
  from wbfdm.contrib.metric.viewsets.mixins import InstrumentMetricMixin
38
38
  from wbfdm.models import Instrument, InstrumentPrice
39
+
39
40
  from wbportfolio import serializers
40
41
  from wbportfolio.filters import (
41
42
  BaseProductFilterSet,
@@ -11,6 +11,7 @@ from rest_framework.response import Response
11
11
  from wbcore import viewsets
12
12
  from wbcore.contrib.notifications.dispatch import send_notification
13
13
  from wbcore.utils.strings import format_number
14
+
14
15
  from wbportfolio.models import AccountReconciliation, AccountReconciliationLine
15
16
  from wbportfolio.models.reconciliations.account_reconciliation_lines import (
16
17
  AccountReconciliationLineQuerySet,
@@ -1,5 +1,6 @@
1
1
  from wbcore import viewsets
2
2
  from wbcore.permissions.permissions import InternalUserPermissionMixin
3
+
3
4
  from wbportfolio.models import Register
4
5
  from wbportfolio.serializers import (
5
6
  RegisterModelSerializer,
@@ -1,5 +1,6 @@
1
1
  from wbcore import viewsets
2
2
  from wbcore.permissions.permissions import InternalUserPermissionMixin
3
+
3
4
  from wbportfolio.filters import PortfolioRoleFilterSet
4
5
  from wbportfolio.models import PortfolioRole
5
6
  from wbportfolio.serializers import (
@@ -6,6 +6,7 @@ from rest_framework.reverse import reverse
6
6
  from wbcore.contrib.icons import WBIcon
7
7
  from wbcore.metadata.configs import buttons as bt
8
8
  from wbcore.signals.instance_buttons import add_instance_button
9
+
9
10
  from wbportfolio.viewsets.products import ProductModelViewSet
10
11
 
11
12
 
@@ -17,6 +17,7 @@ from .fees import (
17
17
  FeesModelViewSet,
18
18
  FeesPortfolioModelViewSet,
19
19
  )
20
+ from .rebalancing import RebalancingModelRepresentationViewSet, RebalancerRepresentationViewSet, RebalancerModelViewSet
20
21
  from .trade_proposals import (
21
22
  TradeProposalModelViewSet,
22
23
  TradeProposalPortfolioModelViewSet,
@@ -43,6 +43,7 @@ from wbcore.utils.strings import format_number
43
43
  from wbcrm.models.accounts import Account
44
44
  from wbfdm.models import ClassificationGroup, InstrumentPrice
45
45
  from wbfdm.preferences import get_default_classification_group
46
+
46
47
  from wbportfolio.analysis.claims import ConsolidatedTradeSummary
47
48
  from wbportfolio.filters import (
48
49
  ClaimFilter,
@@ -51,9 +52,9 @@ from wbportfolio.filters import (
51
52
  CustomerAPIFilter,
52
53
  CustomerClaimFilter,
53
54
  CustomerClaimGroupByFilter,
55
+ DistributionNNMChartFilter,
54
56
  NegativeTermimalAccountPerProductFilterSet,
55
57
  ProfitAndLossPandasFilter,
56
- DistributionNNMChartFilter,
57
58
  )
58
59
  from wbportfolio.models import Product, Trade
59
60
  from wbportfolio.models.transactions.claim import Claim, ClaimGroupbyChoice
@@ -8,6 +8,7 @@ from wbcore.pandas import fields as pf
8
8
  from wbcore.permissions.permissions import InternalUserPermissionMixin
9
9
  from wbcore.serializers import decorator
10
10
  from wbcore.utils.strings import format_number
11
+
11
12
  from wbportfolio.filters import FeesAggregatedFilter, FeesFilter, FeesPortfolioFilterSet
12
13
  from wbportfolio.models import Fees
13
14
  from wbportfolio.serializers import FeesModelSerializer
@@ -2,6 +2,7 @@ from datetime import date, datetime
2
2
 
3
3
  from django.http import HttpRequest
4
4
  from django.utils.functional import cached_property
5
+
5
6
  from wbportfolio.models.transactions.claim import Claim
6
7
 
7
8