wbportfolio 1.44.4__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 +30 -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.4.dist-info → wbportfolio-1.45.0.dist-info}/METADATA +4 -1
  298. {wbportfolio-1.44.4.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.4.dist-info → wbportfolio-1.45.0.dist-info}/WHEEL +0 -0
  315. {wbportfolio-1.44.4.dist-info → wbportfolio-1.45.0.dist-info}/licenses/LICENSE +0 -0
@@ -2,9 +2,11 @@ from typing import Optional
2
2
 
3
3
  from django.utils.translation import gettext_lazy as _
4
4
  from wbcore.metadata.configs import display as dp
5
+ from wbcore.metadata.configs.display import Layout, Page, default
5
6
  from wbcore.metadata.configs.display.instance_display.shortcuts import (
6
7
  Display,
7
8
  create_simple_display,
9
+ create_simple_page_with_inline,
8
10
  create_simple_section,
9
11
  )
10
12
  from wbcore.metadata.configs.display.instance_display.utils import repeat_field
@@ -17,109 +19,155 @@ class PortfolioDisplayConfig(DisplayViewConfig):
17
19
  fields=[
18
20
  dp.Field(key="name", label="Name"),
19
21
  dp.Field(key="currency", label="Currency"),
20
- dp.Field(key="portfolio_synchronization", label="Synchronization Method"),
21
- dp.Field(key="last_synchronization", label="Last Synchronization"),
22
+ dp.Field(key="updated_at", label="Updated At"),
22
23
  dp.Field(key="depends_on", label="Depends on"),
24
+ dp.Field(key="automatic_rebalancer", label="Rebalancer"),
25
+ dp.Field(key="invested_timespan", label="Invested"),
26
+ dp.Field(key="is_manageable", label="Managed"),
27
+ dp.Field(key="is_tracked", label="Tracked"),
28
+ dp.Field(key="only_weighting", label="Only-Weight"),
29
+ dp.Field(key="is_lookthrough", label="Lookthrough"),
30
+ dp.Field(key="is_composition", label="Composition"),
23
31
  ]
24
32
  )
25
33
 
26
34
  def get_instance_display(self) -> Display:
27
- return create_simple_display(
28
- [
29
- ["name", "currency"],
30
- ["portfolio_synchronization", "portfolio_synchronization"],
31
- [repeat_field(2, "dependent_portfolios")],
32
- [repeat_field(2, "trade_proposals_section")],
33
- [repeat_field(2, "instruments_section")],
34
- [repeat_field(2, "dependencyportfolios_section")],
35
- [repeat_field(2, "preferredclassification_section")],
36
- ],
37
- [
38
- create_simple_section(
39
- "trade_proposals_section",
40
- _("Trade Proposals"),
41
- [["trade_proposals"]],
42
- "trade_proposals",
43
- collapsed=True,
35
+ return Display(
36
+ pages=[
37
+ Page(
38
+ title="Main Information",
39
+ layouts={
40
+ default(): Layout(
41
+ grid_template_areas=[
42
+ ["name", "name", "currency", "is_manageable"],
43
+ ["invested_timespan", "invested_timespan", "create_index", "."]
44
+ if self.new_mode
45
+ else [
46
+ "invested_timespan",
47
+ "invested_timespan",
48
+ "automatic_rebalancer",
49
+ "automatic_rebalancer",
50
+ ],
51
+ ["is_tracked", "is_lookthrough", "only_weighting", "is_composition"],
52
+ [repeat_field(4, "instruments_section")],
53
+ [repeat_field(4, "dependencyportfolios_section")],
54
+ [repeat_field(4, "preferredclassification_section")],
55
+ ],
56
+ # grid_template_rows=["min-content"] * 3 + ["1fr", "446px"],
57
+ # grid_template_columns=[repeat(4, "183px"), "1fr", "1fr"],
58
+ sections=[
59
+ create_simple_section(
60
+ "instruments_section",
61
+ _("Linked Instruments"),
62
+ [["instruments"]],
63
+ "instruments",
64
+ collapsed=True,
65
+ ),
66
+ create_simple_section(
67
+ "dependencyportfolios_section",
68
+ _("Dependency Portfolios"),
69
+ [["dependencyportfolios"]],
70
+ "dependencyportfolios",
71
+ collapsed=True,
72
+ ),
73
+ create_simple_section(
74
+ "preferredclassification_section",
75
+ _("Preferred Classification"),
76
+ [["preferredclassification"]],
77
+ "preferredclassification",
78
+ collapsed=True,
79
+ ),
80
+ ],
81
+ ),
82
+ },
44
83
  ),
45
- create_simple_section(
46
- "instruments_section", _("Linked Instruments"), [["instruments"]], "instruments", collapsed=True
84
+ Page(
85
+ title="Trade",
86
+ layouts={
87
+ default(): dp.Layout(
88
+ grid_template_areas=[
89
+ ["trade_proposals"],
90
+ ],
91
+ grid_template_rows=["auto"],
92
+ inlines=[
93
+ dp.Inline(key="trade_proposals", endpoint="trade_proposals"),
94
+ ],
95
+ )
96
+ },
47
97
  ),
48
- create_simple_section(
49
- "dependencyportfolios_section",
50
- _("Dependency Portfolios"),
51
- [["dependencyportfolios"]],
52
- "dependencyportfolios",
53
- collapsed=True,
98
+ Page(
99
+ title="Composition",
100
+ display=Display(
101
+ navigation_type=dp.NavigationType.PANEL,
102
+ pages=[
103
+ create_simple_page_with_inline("Assets", "assets"),
104
+ create_simple_page_with_inline("Top-Down Composition", "topdowncomposition"),
105
+ create_simple_page_with_inline("Contributor", "contributor"),
106
+ create_simple_page_with_inline("Distribution Table", "distribution_table"),
107
+ create_simple_page_with_inline("Distribution Chart", "distribution_chart"),
108
+ # Page(
109
+ # title="Distribution",
110
+ # layouts={
111
+ # default(): Layout(
112
+ # grid_template_areas=[["distribution_table", "distribution_chart"]],
113
+ # grid_template_rows=["auto"],
114
+ # grid_template_columns=["2fr", "1fr"],
115
+ # inlines=[
116
+ # Inline(
117
+ # key="distribution_table", endpoint="distribution_table", title="Table"
118
+ # ),
119
+ # Inline(
120
+ # key="distribution_chart", endpoint="distribution_chart", title="Chart"
121
+ # ),
122
+ # ],
123
+ # ),
124
+ # },
125
+ # ),
126
+ create_simple_page_with_inline(
127
+ "Portfolio Composition vs. Dependant Portfolios", "modelcomposition"
128
+ ),
129
+ ],
130
+ ),
54
131
  ),
55
- create_simple_section(
56
- "preferredclassification_section",
57
- _("Preferred Classification"),
58
- [["preferredclassification"]],
59
- "preferredclassification",
60
- collapsed=True,
61
- ),
62
- ],
132
+ ]
63
133
  )
64
134
 
65
135
 
66
- class ModelPortfolioDisplayConfig(PortfolioDisplayConfig):
136
+ class PortfolioPortfolioThroughModelDisplayConfig(DisplayViewConfig):
67
137
  def get_list_display(self) -> Optional[dp.ListDisplay]:
68
138
  return dp.ListDisplay(
69
139
  fields=[
70
- dp.Field(key="name", label="Name"),
71
- dp.Field(key="currency", label="Currency"),
72
- dp.Field(key="portfolio_synchronization", label="Synchronization Method"),
73
- dp.Field(key="last_synchronization", label="Last Synchronization"),
74
- dp.Field(key="depends_on", label="Depends on"),
140
+ dp.Field(key="dependency_portfolio", label="Dependency Portfolio"),
141
+ dp.Field(key="portfolio", label="Dependant Portfolio"),
142
+ dp.Field(key="type", label="Type"),
75
143
  ]
76
144
  )
77
145
 
78
146
  def get_instance_display(self) -> Display:
79
147
  return create_simple_display(
80
148
  [
81
- ["name", "currency"],
82
- [repeat_field(2, "portfolio_synchronization")],
83
- [repeat_field(2, "dependent_portfolios")],
84
- [repeat_field(2, "trade_proposals_section")],
85
- [repeat_field(2, "instruments_section")],
86
- [repeat_field(2, "dependencyportfolios_section")],
87
- [repeat_field(2, "preferredclassification_section")],
88
- ],
89
- [
90
- create_simple_section(
91
- "trade_proposals_section",
92
- _("Trade Proposals"),
93
- [["trade_proposals"]],
94
- "trade_proposals",
95
- collapsed=True,
96
- ),
97
- create_simple_section(
98
- "instruments_section", _("Linked Instruments"), [["instruments"]], "instruments", collapsed=True
99
- ),
100
- create_simple_section(
101
- "dependencyportfolios_section",
102
- _("Dependency Portfolios"),
103
- [["dependencyportfolios"]],
104
- "dependencyportfolios",
105
- collapsed=True,
106
- ),
107
- create_simple_section(
108
- "preferredclassification_section",
109
- _("Preferred Classification"),
110
- [["preferredclassification"]],
111
- "preferredclassification",
112
- collapsed=True,
113
- ),
114
- ],
149
+ ["dependency_portfolio", "type"],
150
+ ]
115
151
  )
116
152
 
117
153
 
118
- class PortfolioPortfolioThroughModelDisplayConfig(DisplayViewConfig):
154
+ class TopDownPortfolioCompositionPandasDisplayConfig(DisplayViewConfig):
119
155
  def get_list_display(self) -> Optional[dp.ListDisplay]:
156
+ rebalancing_column_label = "Last Rebalancing"
157
+ effective_column_label = "Actual"
158
+ if self.view.last_rebalancing_date:
159
+ rebalancing_column_label += f" ({self.view.last_rebalancing_date:%Y-ok, %m-%d})"
160
+ if self.view.last_effective_date:
161
+ effective_column_label += f" ({self.view.last_effective_date:%Y-%m-%d})"
120
162
  return dp.ListDisplay(
121
163
  fields=[
122
- dp.Field(key="dependency_portfolio", label="Dependency Portfolio"),
123
- dp.Field(key="type", label="Type"),
124
- ]
164
+ dp.Field(key="instrument", label="Instrument"),
165
+ dp.Field(key="effective_weights", label=rebalancing_column_label),
166
+ dp.Field(key="rebalancing_weights", label=effective_column_label),
167
+ ],
168
+ tree=True,
169
+ tree_group_pinned="left",
170
+ tree_group_field="instrument",
171
+ tree_group_label="Instrument",
172
+ tree_group_parent_pointer="parent_row_id",
125
173
  )
@@ -4,6 +4,7 @@ from wbcore.contrib.color.enums import WBColor
4
4
  from wbcore.enums import Unit
5
5
  from wbcore.metadata.configs import display as dp
6
6
  from wbcore.metadata.configs.display.view_config import DisplayViewConfig
7
+
7
8
  from wbportfolio.filters.performances import PerformancePandasFilter
8
9
 
9
10
 
@@ -0,0 +1,27 @@
1
+ from typing import Optional
2
+
3
+ from wbcore.metadata.configs import display as dp
4
+ from wbcore.metadata.configs.display import Display, create_simple_display
5
+ from wbcore.metadata.configs.display.view_config import DisplayViewConfig
6
+
7
+
8
+ class RebalancerDisplayConfig(DisplayViewConfig):
9
+ def get_list_display(self) -> Optional[dp.ListDisplay]:
10
+ return dp.ListDisplay(
11
+ fields=[
12
+ dp.Field(key="portfolio", label="Portfolio"),
13
+ dp.Field(key="rebalancing_model", label="Rebalancing Model"),
14
+ dp.Field(key="approve_trade_proposal_automatically", label="Approve automatically"),
15
+ dp.Field(key="frequency_repr", label="Frequency"),
16
+ dp.Field(key="activation_date", label="Activation Date"),
17
+ ],
18
+ )
19
+
20
+ def get_instance_display(self) -> Display:
21
+ return create_simple_display(
22
+ [
23
+ ["rebalancing_model", "approve_trade_proposal_automatically"],
24
+ ["frequency", "activation_date"],
25
+ ["rebalancing_dates", "rebalancing_dates"],
26
+ ]
27
+ )
@@ -6,6 +6,7 @@ from wbcore.metadata.configs.display.instance_display import Inline, Layout, Pag
6
6
  from wbcore.metadata.configs.display.instance_display.operators import default
7
7
  from wbcore.metadata.configs.display.instance_display.shortcuts import Display
8
8
  from wbcore.metadata.configs.display.view_config import DisplayViewConfig
9
+
9
10
  from wbportfolio.models import TradeProposal
10
11
 
11
12
 
@@ -76,9 +77,11 @@ class TradeProposalDisplayConfig(DisplayViewConfig):
76
77
  layouts={
77
78
  default(): Layout(
78
79
  grid_template_areas=[
79
- ["status", "status"],
80
- ["trade_date", "model_portfolio"],
81
- ["comment", "comment"],
80
+ ["status", "status", "status"],
81
+ ["trade_date", "rebalancing_model", "target_portfolio"]
82
+ if self.view.new_mode
83
+ else ["trade_date", "rebalancing_model", "rebalancing_model"],
84
+ ["comment", "comment", "comment"],
82
85
  ],
83
86
  ),
84
87
  },
@@ -88,7 +91,7 @@ class TradeProposalDisplayConfig(DisplayViewConfig):
88
91
  layouts={
89
92
  default(): Layout(
90
93
  grid_template_areas=[["trades"]],
91
- grid_template_rows=["minmax(700px, 100%)"],
94
+ grid_template_rows=["1fr"],
92
95
  inlines=[Inline(key="trades", endpoint="trades")],
93
96
  ),
94
97
  },
@@ -1,5 +1,6 @@
1
1
  from typing import Optional
2
2
 
3
+ from django.shortcuts import get_object_or_404
3
4
  from wbcore.contrib.color.enums import WBColor
4
5
  from wbcore.contrib.icons import WBIcon
5
6
  from wbcore.enums import Unit
@@ -10,7 +11,8 @@ from wbcore.metadata.configs.display.instance_display.shortcuts import (
10
11
  )
11
12
  from wbcore.metadata.configs.display.instance_display.utils import repeat_field
12
13
  from wbcore.metadata.configs.display.view_config import DisplayViewConfig
13
- from wbportfolio.models import Trade
14
+
15
+ from wbportfolio.models import Trade, TradeProposal
14
16
 
15
17
  NEGATIVE_RED_FORMATTING = [
16
18
  dp.FormattingRule(
@@ -38,6 +40,11 @@ SHARE_FORMATTING = dp.Formatting(
38
40
  TRADE_STATUS_LEGENDS = dp.Legend(
39
41
  key="status",
40
42
  items=[
43
+ dp.LegendItem(
44
+ icon=WBColor.RED_LIGHT.value,
45
+ label=Trade.Status.FAILED.label,
46
+ value=Trade.Status.FAILED.value,
47
+ ),
41
48
  dp.LegendItem(
42
49
  icon=WBColor.BLUE_LIGHT.value,
43
50
  label=Trade.Status.DRAFT.label,
@@ -64,6 +71,10 @@ TRADE_STATUS_LEGENDS = dp.Legend(
64
71
  TRADE_STATUS_FORMATTING = dp.Formatting(
65
72
  column="status",
66
73
  formatting_rules=[
74
+ dp.FormattingRule(
75
+ style={"backgroundColor": WBColor.RED_LIGHT.value},
76
+ condition=("==", Trade.Status.FAILED.value),
77
+ ),
67
78
  dp.FormattingRule(
68
79
  style={"backgroundColor": WBColor.BLUE_LIGHT.value},
69
80
  condition=("==", Trade.Status.DRAFT.value),
@@ -287,19 +298,45 @@ class TradePortfolioDisplayConfig(TradeDisplayConfig):
287
298
 
288
299
  class TradeTradeProposalDisplayConfig(DisplayViewConfig):
289
300
  def get_list_display(self) -> Optional[dp.ListDisplay]:
290
- return dp.ListDisplay(
291
- fields=[
292
- dp.Field(key="underlying_instrument", label="Instrument"),
301
+ trade_proposal = get_object_or_404(TradeProposal, pk=self.view.kwargs.get("trade_proposal_id", None))
302
+ fields = [
303
+ dp.Field(key="underlying_instrument", label="Instrument"),
304
+ dp.Field(
305
+ label="Weight",
306
+ open_by_default=False,
307
+ key=None,
308
+ children=[
309
+ dp.Field(key="effective_weight", label="Effective Weight", show="open"),
310
+ dp.Field(key="target_weight", label="Target Weight", show="open"),
311
+ dp.Field(
312
+ key="weighting",
313
+ label="Delta Weight",
314
+ formatting_rules=[
315
+ dp.FormattingRule(
316
+ style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
317
+ condition=("<", 0),
318
+ ),
319
+ dp.FormattingRule(
320
+ style={"color": WBColor.GREEN_DARK.value, "fontWeight": "bold"},
321
+ condition=(">", 0),
322
+ ),
323
+ ],
324
+ ),
325
+ ],
326
+ ),
327
+ ]
328
+ if not trade_proposal.portfolio.only_weighting:
329
+ fields.append(
293
330
  dp.Field(
294
- label="Weight",
331
+ label="Shares",
295
332
  open_by_default=False,
296
333
  key=None,
297
334
  children=[
298
- dp.Field(key="effective_weight", label="Effective Weight"),
299
- dp.Field(key="target_weight", label="Target Weight"),
335
+ dp.Field(key="effective_shares", label="Effective Shares", show="open"),
336
+ dp.Field(key="target_shares", label="Target Shares", show="open"),
300
337
  dp.Field(
301
- key="weighting",
302
- label="Delta Weight",
338
+ key="shares",
339
+ label="Shares",
303
340
  formatting_rules=[
304
341
  dp.FormattingRule(
305
342
  style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
@@ -312,39 +349,35 @@ class TradeTradeProposalDisplayConfig(DisplayViewConfig):
312
349
  ],
313
350
  ),
314
351
  ],
315
- ),
316
- dp.Field(
317
- label="Shares",
318
- open_by_default=False,
319
- key=None,
320
- children=[
321
- dp.Field(
322
- key="transaction_subtype",
323
- label="Direction",
324
- formatting_rules=[
325
- dp.FormattingRule(
326
- style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
327
- condition=("==", Trade.Type.SELL.name),
328
- ),
329
- dp.FormattingRule(
330
- style={"color": WBColor.GREEN_DARK.value, "fontWeight": "bold"},
331
- condition=("==", Trade.Type.BUY.name),
332
- ),
333
- ],
334
- ),
335
- dp.Field(key="shares", label="Shares", show="open"),
336
- ],
337
- ),
338
- dp.Field(
339
- label="Information",
340
- open_by_default=False,
341
- key=None,
342
- children=[
343
- dp.Field(key="comment", label="Comment"),
344
- dp.Field(key="order", label="Order", show="open"),
345
- ],
346
- ),
347
- ],
352
+ )
353
+ )
354
+ fields.append(
355
+ dp.Field(
356
+ label="Information",
357
+ open_by_default=False,
358
+ key=None,
359
+ children=[
360
+ dp.Field(
361
+ key="transaction_subtype",
362
+ label="Direction",
363
+ formatting_rules=[
364
+ dp.FormattingRule(
365
+ style={"color": WBColor.RED_DARK.value, "fontWeight": "bold"},
366
+ condition=("==", Trade.Type.SELL.name),
367
+ ),
368
+ dp.FormattingRule(
369
+ style={"color": WBColor.GREEN_DARK.value, "fontWeight": "bold"},
370
+ condition=("==", Trade.Type.BUY.name),
371
+ ),
372
+ ],
373
+ ),
374
+ dp.Field(key="comment", label="Comment"),
375
+ dp.Field(key="order", label="Order", show="open"),
376
+ ],
377
+ )
378
+ )
379
+ return dp.ListDisplay(
380
+ fields=fields,
348
381
  legends=[TRADE_STATUS_LEGENDS],
349
382
  formatting=[SHARE_FORMATTING, TRADE_STATUS_FORMATTING],
350
383
  )
@@ -34,9 +34,10 @@ from .fees import (
34
34
  from .fees import FeesAggregatedPortfolioPandasEndpointConfig, FeesPortfolioEndpointConfig, FeeEndpointConfig
35
35
 
36
36
  from .portfolios import (
37
- ModelPortfolioEndpointConfig,
38
37
  PortfolioEndpointConfig,
39
38
  PortfolioPortfolioThroughModelEndpointConfig,
39
+ PortfolioTreeGraphChartEndpointConfig,
40
+ TopDownPortfolioCompositionPandasEndpointConfig
40
41
  )
41
42
  from .positions import (
42
43
  AggregatedAssetPositionLiquidityEndpointConfig,
@@ -73,3 +74,4 @@ from .portfolio_relationship import (
73
74
  )
74
75
  from .esg import ESGMetricAggregationPortfolioPandasEndpointConfig
75
76
  from .reconciliations import AccountReconciliationLineEndpointViewConfig, AccountReconciliationEndpointViewConfig
77
+ from .rebalancing import RebalancerEndpointConfig
@@ -1,5 +1,6 @@
1
1
  from rest_framework.reverse import reverse
2
2
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
3
+
3
4
  from wbportfolio.models.transactions.claim import Claim
4
5
 
5
6
 
@@ -6,18 +6,16 @@ class PortfolioEndpointConfig(EndpointViewConfig):
6
6
  def get_endpoint(self, **kwargs):
7
7
  return super().get_endpoint()
8
8
 
9
- def get_delete_endpoint(self, **kwargs):
9
+ def get_update_endpoint(self, **kwargs):
10
10
  if self.view.is_portfolio_manager:
11
11
  return self.get_endpoint(**kwargs)
12
12
  return None
13
13
 
14
- def get_create_endpoint(self, **kwargs):
15
- return None
16
-
14
+ def get_delete_endpoint(self, **kwargs):
15
+ return self.get_update_endpoint(**kwargs)
17
16
 
18
- class ModelPortfolioEndpointConfig(PortfolioEndpointConfig):
19
- def get_endpoint(self, **kwargs):
20
- return reverse("wbportfolio:modelportfolio-list", request=self.request)
17
+ def get_create_endpoint(self, **kwargs):
18
+ return self.get_update_endpoint(**kwargs)
21
19
 
22
20
 
23
21
  class PortfolioPortfolioThroughModelEndpointConfig(EndpointViewConfig):
@@ -41,3 +39,21 @@ class PortfolioPortfolioThroughModelEndpointConfig(EndpointViewConfig):
41
39
  if self.request.user.is_superuser:
42
40
  return self.get_list_endpoint(**kwargs)
43
41
  return None
42
+
43
+
44
+ class PortfolioTreeGraphChartEndpointConfig(EndpointViewConfig):
45
+ def get_list_endpoint(self, **kwargs):
46
+ return reverse(
47
+ "wbportfolio:portfolio-treegraphchart-list",
48
+ args=[self.view.kwargs["portfolio_id"]],
49
+ request=self.request,
50
+ )
51
+
52
+
53
+ class TopDownPortfolioCompositionPandasEndpointConfig(EndpointViewConfig):
54
+ def get_list_endpoint(self, **kwargs):
55
+ return reverse(
56
+ "wbportfolio:portfolio-topdowncomposition-list",
57
+ args=[self.view.kwargs["portfolio_id"]],
58
+ request=self.request,
59
+ )
@@ -0,0 +1,6 @@
1
+ from wbcore.metadata.configs.endpoints import EndpointViewConfig
2
+
3
+
4
+ class RebalancerEndpointConfig(EndpointViewConfig):
5
+ def get_endpoint(self, **kwargs):
6
+ return super().get_endpoint()
@@ -1,4 +1,5 @@
1
1
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
2
+
2
3
  from wbportfolio.models.reconciliations.account_reconciliations import (
3
4
  AccountReconciliation,
4
5
  )
@@ -1,5 +1,6 @@
1
1
  from rest_framework.reverse import reverse
2
2
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
3
+
3
4
  from wbportfolio.models import TradeProposal
4
5
 
5
6
 
@@ -1,6 +1,7 @@
1
1
  from django.shortcuts import get_object_or_404
2
2
  from rest_framework.reverse import reverse
3
3
  from wbcore.metadata.configs.endpoints import EndpointViewConfig
4
+
4
5
  from wbportfolio.models import TradeProposal
5
6
 
6
7
 
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_portfolio_manager
3
4
 
4
5
  ADJUSTMENT_MENUITEM = MenuItem(
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_portfolio_manager
3
4
 
4
5
  EQUITYCASHPOSITION_MENUITEM = MenuItem(
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_manager
3
4
 
4
5
  GAIN_MENUITEM = MenuItem(
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_portfolio_manager
3
4
 
4
5
  PORTFOLIO_DAILY_CASH_FLOW = MenuItem(
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_portfolio_manager
3
4
 
4
5
  PortfolioMenuItem = MenuItem(
@@ -9,7 +10,8 @@ PortfolioMenuItem = MenuItem(
9
10
 
10
11
 
11
12
  ModelPortfolioMenuItem = MenuItem(
12
- label="Model Portfolios",
13
- endpoint="wbportfolio:modelportfolio-list",
13
+ label="Managed Portfolios",
14
+ endpoint="wbportfolio:portfolio-list",
15
+ endpoint_get_parameters={"is_manageable": True},
14
16
  permission=ItemPermission(method=is_portfolio_manager, permissions=["wbportfolio.view_portfolio"]),
15
17
  )
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_analyst, is_portfolio_manager
3
4
 
4
5
  ASSETPOSITION_MENUITEM = MenuItem(
@@ -1,5 +1,6 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
2
  from wbcore.permissions.shortcuts import is_internal_user
3
+
3
4
  from wbportfolio.permissions import is_manager
4
5
 
5
6
  PORTFOLIOROLE_MENUITEM = MenuItem(
@@ -1,4 +1,5 @@
1
1
  from wbcore.menus import ItemPermission, MenuItem
2
+
2
3
  from wbportfolio.permissions import is_manager
3
4
 
4
5
  TRANSACTION_MENUITEM = MenuItem(