wbportfolio 1.47.1__tar.gz → 1.48.0__tar.gz

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 (526) hide show
  1. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/PKG-INFO +1 -1
  2. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/tasks.py +8 -4
  3. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/dynamic_preferences_registry.py +9 -0
  4. wbportfolio-1.48.0/wbportfolio/import_export/resources/trades.py +55 -0
  5. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/backends/base.py +3 -15
  6. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/__init__.py +1 -2
  7. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/asset.py +1 -1
  8. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/portfolio.py +12 -0
  9. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/products.py +50 -1
  10. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/trade_proposals.py +28 -20
  11. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/trades.py +18 -14
  12. wbportfolio-1.48.0/wbportfolio/preferences.py +11 -0
  13. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/accounts.py +14 -6
  14. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/exposure_portfolio.py +7 -5
  15. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/trade_proposals.py +2 -13
  16. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tasks.py +4 -1
  17. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/conftest.py +1 -1
  18. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_products.py +26 -0
  19. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/trade_proposals.py +21 -2
  20. wbportfolio-1.47.1/wbportfolio/import_export/resources/trades.py +0 -66
  21. wbportfolio-1.47.1/wbportfolio/preferences.py +0 -6
  22. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/.gitignore +0 -0
  23. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/LICENSE +0 -0
  24. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/pyproject.toml +0 -0
  25. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/__init__.py +0 -0
  26. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/__init__.py +0 -0
  27. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/asset.py +0 -0
  28. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/custodians.py +0 -0
  29. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/indexes.py +0 -0
  30. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/portfolio.py +0 -0
  31. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/portfolio_relationships.py +0 -0
  32. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/product_groups.py +0 -0
  33. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/products.py +0 -0
  34. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/reconciliations.py +0 -0
  35. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/registers.py +0 -0
  36. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/roles.py +0 -0
  37. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/__init__.py +0 -0
  38. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/claim.py +0 -0
  39. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/dividends.py +0 -0
  40. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/fees.py +0 -0
  41. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/rebalancing.py +0 -0
  42. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/trades.py +0 -0
  43. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/admin/transactions/transactions.py +0 -0
  44. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/analysis/__init__.py +0 -0
  45. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/analysis/claims.py +0 -0
  46. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/apps.py +0 -0
  47. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/__init__.py +0 -0
  48. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/__init__.py +0 -0
  49. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/admin.py +0 -0
  50. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/apps.py +0 -0
  51. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/configs/__init__.py +0 -0
  52. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/configs/display.py +0 -0
  53. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/configs/endpoints.py +0 -0
  54. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/configs/previews.py +0 -0
  55. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/constants.py +0 -0
  56. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/dynamic_preferences_registry.py +0 -0
  57. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/factories.py +0 -0
  58. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/filters.py +0 -0
  59. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/management.py +0 -0
  60. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/migrations/0001_initial.py +0 -0
  61. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/migrations/__init__.py +0 -0
  62. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/models.py +0 -0
  63. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/scripts.py +0 -0
  64. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/serializers.py +0 -0
  65. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/tests/__init__.py +0 -0
  66. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/tests/conftest.py +0 -0
  67. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/tests/test_models.py +0 -0
  68. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/urls.py +0 -0
  69. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/contrib/company_portfolio/viewsets.py +0 -0
  70. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/defaults/__init__.py +0 -0
  71. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/defaults/fees/__init__.py +0 -0
  72. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/defaults/fees/default.py +0 -0
  73. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/__init__.py +0 -0
  74. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/adjustments.py +0 -0
  75. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/assets.py +0 -0
  76. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/claim.py +0 -0
  77. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/custodians.py +0 -0
  78. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/dividends.py +0 -0
  79. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/fees.py +0 -0
  80. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/indexes.py +0 -0
  81. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/portfolio_cash_flow.py +0 -0
  82. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/portfolio_cash_targets.py +0 -0
  83. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/portfolio_swing_pricings.py +0 -0
  84. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/portfolios.py +0 -0
  85. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/product_groups.py +0 -0
  86. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/products.py +0 -0
  87. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/rebalancing.py +0 -0
  88. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/reconciliations.py +0 -0
  89. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/roles.py +0 -0
  90. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/trades.py +0 -0
  91. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/factories/transactions.py +0 -0
  92. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/fdm/__init__.py +0 -0
  93. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/fdm/tasks.py +0 -0
  94. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/__init__.py +0 -0
  95. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/assets.py +0 -0
  96. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/assets_and_net_new_money_progression.py +0 -0
  97. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/custodians.py +0 -0
  98. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/esg.py +0 -0
  99. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/performances.py +0 -0
  100. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/portfolios.py +0 -0
  101. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/positions.py +0 -0
  102. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/products.py +0 -0
  103. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/roles.py +0 -0
  104. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/signals.py +0 -0
  105. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/__init__.py +0 -0
  106. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/claim.py +0 -0
  107. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/fees.py +0 -0
  108. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/mixins.py +0 -0
  109. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/trades.py +0 -0
  110. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/filters/transactions/transactions.py +0 -0
  111. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/fixtures/product_factsheets.yaml +0 -0
  112. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/fixtures/wbportfolio.yaml.gz +0 -0
  113. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/fixtures/wbrisk_management.yaml.gz +0 -0
  114. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/__init__.py +0 -0
  115. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/__init__.py +0 -0
  116. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/refinitiv/adjustment.py +0 -0
  117. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/ubs/__init__.py +0 -0
  118. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/ubs/asset_position.py +0 -0
  119. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/ubs/fees.py +0 -0
  120. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/ubs/instrument_price.py +0 -0
  121. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/ubs/mixin.py +0 -0
  122. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/utils.py +0 -0
  123. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/wbfdm/__init__.py +0 -0
  124. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/wbfdm/adjustment.py +0 -0
  125. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/wbfdm/dividend.py +0 -0
  126. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/backends/wbfdm/mixin.py +0 -0
  127. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/__init__.py +0 -0
  128. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/adjustment.py +0 -0
  129. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/asset_position.py +0 -0
  130. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/dividend.py +0 -0
  131. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/fees.py +0 -0
  132. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/portfolio_cash_flow.py +0 -0
  133. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/register.py +0 -0
  134. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/handlers/trade.py +0 -0
  135. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/__init__.py +0 -0
  136. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/default_mapping.py +0 -0
  137. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/jpmorgan/__init__.py +0 -0
  138. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +0 -0
  139. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/jpmorgan/fees.py +0 -0
  140. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/jpmorgan/strategy.py +0 -0
  141. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/jpmorgan/valuation.py +0 -0
  142. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/__init__.py +0 -0
  143. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/customer_trade.py +0 -0
  144. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/equity.py +0 -0
  145. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/fees.py +0 -0
  146. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/trade.py +0 -0
  147. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/leonteq/valuation.py +0 -0
  148. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/__init__.py +0 -0
  149. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/customer_trade.py +0 -0
  150. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +0 -0
  151. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/d1_equity.py +0 -0
  152. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/d1_fees.py +0 -0
  153. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/d1_trade.py +0 -0
  154. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/d1_valuation.py +0 -0
  155. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/dividend.py +0 -0
  156. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/equity.py +0 -0
  157. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/fees.py +0 -0
  158. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/trade.py +0 -0
  159. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/utils.py +0 -0
  160. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/natixis/valuation.py +0 -0
  161. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/refinitiv/__init__.py +0 -0
  162. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/refinitiv/adjustment.py +0 -0
  163. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/__init__.py +0 -0
  164. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +0 -0
  165. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade.py +0 -0
  166. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +0 -0
  167. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +0 -0
  168. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +0 -0
  169. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/equity.py +0 -0
  170. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/fees.py +0 -0
  171. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/perf_fees.py +0 -0
  172. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +0 -0
  173. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +0 -0
  174. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/registers.py +0 -0
  175. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/sylk.py +0 -0
  176. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/utils.py +0 -0
  177. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/sg_lux/valuation.py +0 -0
  178. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/societe_generale/__init__.py +0 -0
  179. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/societe_generale/customer_trade.py +0 -0
  180. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/societe_generale/strategy.py +0 -0
  181. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/societe_generale/valuation.py +0 -0
  182. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/tellco/__init__.py +0 -0
  183. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/tellco/customer_trade.py +0 -0
  184. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/tellco/equity.py +0 -0
  185. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/tellco/valuation.py +0 -0
  186. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/__init__.py +0 -0
  187. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/api/__init__.py +0 -0
  188. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/api/asset_position.py +0 -0
  189. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/api/fees.py +0 -0
  190. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/api/instrument_price.py +0 -0
  191. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/api/utils.py +0 -0
  192. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/customer_trade.py +0 -0
  193. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/equity.py +0 -0
  194. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +0 -0
  195. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/ubs/valuation.py +0 -0
  196. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/__init__.py +0 -0
  197. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/asset_position.py +0 -0
  198. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/customer_trade.py +0 -0
  199. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -0
  200. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/instrument.py +0 -0
  201. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/management_fees.py +0 -0
  202. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/performance_fees.py +0 -0
  203. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/trade.py +0 -0
  204. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/utils.py +0 -0
  205. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/valuation.py +0 -0
  206. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/parsers/vontobel/valuation_api.py +0 -0
  207. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/resources/__init__.py +0 -0
  208. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/resources/assets.py +0 -0
  209. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/import_export/utils.py +0 -0
  210. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +0 -0
  211. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/kpi_handlers/nnm.py +0 -0
  212. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/__init__.py +0 -0
  213. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/backends/__init__.py +0 -0
  214. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/backends/constants.py +0 -0
  215. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/backends/portfolio_base.py +0 -0
  216. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/backends/portfolio_esg.py +0 -0
  217. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/tests/__init__.py +0 -0
  218. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/tests/conftest.py +0 -0
  219. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/tests/test_portfolio_base.py +0 -0
  220. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/metric/tests/test_portfolio_esg.py +0 -0
  221. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0001_initial_squashed.py +0 -0
  222. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0002_product_default_sub_account_squashed_0039_alter_assetallocation_company_and_more.py +0 -0
  223. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0040_instrument_financial_instrument.py +0 -0
  224. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0041_remove_listresearch_research_ptr_and_more.py +0 -0
  225. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0042_instrumentlist_instrumentlistthroughmodel_and_more.py +0 -0
  226. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0043_alter_instrumentlistthroughmodel_options_and_more.py +0 -0
  227. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0044_alter_instrumentlist_identifier.py +0 -0
  228. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0045_alter_instrument_financial_instrument.py +0 -0
  229. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0046_add_product_default_account.py +0 -0
  230. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0047_remove_product_default_sub_account.py +0 -0
  231. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0048_alter_trade_status.py +0 -0
  232. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0049_trade_claimed_shares.py +0 -0
  233. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0050_fees_fee_date_fees_wbportfolio_transac_1f7a29_idx.py +0 -0
  234. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0051_delete_macroreview.py +0 -0
  235. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +0 -0
  236. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0053_remove_product_group.py +0 -0
  237. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0054_portfolioinstrumentpreferredclassificationthroughmodel_and_more.py +0 -0
  238. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0055_remove_product__custom_management_rebates_and_more.py +0 -0
  239. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0056_remove_companyportfoliodata_assets_under_management_currency_and_more.py +0 -0
  240. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0057_alter_portfolio_preferred_instrument_classifications_and_more.py +0 -0
  241. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0058_pmsinstrument.py +0 -0
  242. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0059_fees_unique_fees.py +0 -0
  243. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0060_alter_portfolioportfoliothroughmodel_type.py +0 -0
  244. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0061_portfolio_bank_accounts_product_bank_account_and_more.py +0 -0
  245. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0062_alter_dailyportfoliocashflow_options.py +0 -0
  246. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0063_accountreconciliation_accountreconciliationline_and_more.py +0 -0
  247. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0064_alter_portfolio_managers_portfolio_is_tracked_and_more.py +0 -0
  248. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0065_alter_portfolio_managers_claim_as_shares_and_more.py +0 -0
  249. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0066_assetposition_initial_shares_at_custodian_and_more.py +0 -0
  250. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0067_assetposition_unique_asset_position.py +0 -0
  251. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0068_trade_internal_trade_trade_marked_as_internal_and_more.py +0 -0
  252. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0069_remove_portfolio_is_invested_and_more.py +0 -0
  253. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +0 -0
  254. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0071_alter_trade_options_alter_trade_order.py +0 -0
  255. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0072_trade_diff_shares.py +0 -0
  256. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0073_remove_product_price_computation_and_more.py +0 -0
  257. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/0074_alter_rebalancer_frequency_and_more.py +0 -0
  258. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/migrations/__init__.py +0 -0
  259. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/adjustments.py +0 -0
  260. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/custodians.py +0 -0
  261. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/exceptions.py +0 -0
  262. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/graphs/__init__.py +0 -0
  263. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/graphs/portfolio.py +0 -0
  264. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/graphs/utils.py +0 -0
  265. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/indexes.py +0 -0
  266. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/llm/wbcrm/analyze_relationship.py +0 -0
  267. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/mixins/__init__.py +0 -0
  268. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/mixins/instruments.py +0 -0
  269. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/mixins/liquidity_stress_test.py +0 -0
  270. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/portfolio_cash_flow.py +0 -0
  271. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/portfolio_cash_targets.py +0 -0
  272. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/portfolio_relationship.py +0 -0
  273. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/portfolio_swing_pricings.py +0 -0
  274. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/product_groups.py +0 -0
  275. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/reconciliations/__init__.py +0 -0
  276. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/reconciliations/account_reconciliation_lines.py +0 -0
  277. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/reconciliations/account_reconciliations.py +0 -0
  278. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/reconciliations/reconciliations.py +0 -0
  279. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/registers.py +0 -0
  280. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/roles.py +0 -0
  281. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/__init__.py +0 -0
  282. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/claim.py +0 -0
  283. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/dividends.py +0 -0
  284. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/expiry.py +0 -0
  285. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/fees.py +0 -0
  286. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/rebalancing.py +0 -0
  287. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/transactions/transactions.py +0 -0
  288. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/models/utils.py +0 -0
  289. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/permissions.py +0 -0
  290. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/__init__.py +0 -0
  291. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/analytics/__init__.py +0 -0
  292. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/analytics/portfolio.py +0 -0
  293. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/statistics/__init__.py +0 -0
  294. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/trading/__init__.py +0 -0
  295. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/trading/handler.py +0 -0
  296. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/pms/typing.py +0 -0
  297. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/__init__.py +0 -0
  298. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/base.py +0 -0
  299. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/decorators.py +0 -0
  300. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/models/__init__.py +0 -0
  301. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/models/composite.py +0 -0
  302. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/models/equally_weighted.py +0 -0
  303. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/models/market_capitalization_weighted.py +0 -0
  304. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/rebalancing/models/model_portfolio.py +0 -0
  305. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/reports/__init__.py +0 -0
  306. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/reports/monthly_position_report.py +0 -0
  307. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/__init__.py +0 -0
  308. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/__init__.py +0 -0
  309. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/controversy_portfolio.py +0 -0
  310. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/instrument_list_portfolio.py +0 -0
  311. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/liquidity_risk.py +0 -0
  312. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/liquidity_stress_instrument.py +0 -0
  313. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/mixins.py +0 -0
  314. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/product_integrity.py +0 -0
  315. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/stop_loss_instrument.py +0 -0
  316. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/stop_loss_portfolio.py +0 -0
  317. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/backends/ucits_portfolio.py +0 -0
  318. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/__init__.py +0 -0
  319. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/conftest.py +0 -0
  320. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_accounts.py +0 -0
  321. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_controversy_portfolio.py +0 -0
  322. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_exposure_portfolio.py +0 -0
  323. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +0 -0
  324. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_liquidity_risk.py +0 -0
  325. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_product_integrity.py +0 -0
  326. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_stop_loss_instrument.py +0 -0
  327. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +0 -0
  328. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/risk_management/tests/test_ucits_portfolio.py +0 -0
  329. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/__init__.py +0 -0
  330. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/adjustments.py +0 -0
  331. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/assets.py +0 -0
  332. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/custodians.py +0 -0
  333. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/portfolio_cash_flow.py +0 -0
  334. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/portfolio_cash_targets.py +0 -0
  335. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/portfolio_relationship.py +0 -0
  336. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/portfolio_swing_pricing.py +0 -0
  337. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/portfolios.py +0 -0
  338. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/positions.py +0 -0
  339. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/product_group.py +0 -0
  340. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/products.py +0 -0
  341. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/rebalancing.py +0 -0
  342. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/reconciliations.py +0 -0
  343. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/registers.py +0 -0
  344. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/roles.py +0 -0
  345. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/signals.py +0 -0
  346. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/__init__.py +0 -0
  347. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/claim.py +0 -0
  348. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/dividends.py +0 -0
  349. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/expiry.py +0 -0
  350. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/fees.py +0 -0
  351. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/trades.py +0 -0
  352. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/serializers/transactions/transactions.py +0 -0
  353. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/css/macro_review.css +0 -0
  354. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/account_holding_reconciliation.md +0 -0
  355. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/aggregate_asset_position_liquidity.md +0 -0
  356. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/company.md +0 -0
  357. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/earnings_instrument.md +0 -0
  358. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/financial_analysis_instrument_ratios.md +0 -0
  359. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/financial_statistics.md +0 -0
  360. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/static/wbportfolio/markdown/documentation/person.md +0 -0
  361. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/templates/portfolio/email/customer_report.html +0 -0
  362. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/templates/portfolio/email/customer_trade_notification.html +0 -0
  363. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/templates/portfolio/email/email_base_template.html +0 -0
  364. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/templates/portfolio/email/rebalancing_report.html +0 -0
  365. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/templates/portfolio/macro/macro_review.html +0 -0
  366. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/__init__.py +0 -0
  367. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/__init__.py +0 -0
  368. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_account_reconciliation.py +0 -0
  369. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_assets.py +0 -0
  370. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_custodians.py +0 -0
  371. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_customer_trades.py +0 -0
  372. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_dividends.py +0 -0
  373. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_imports.py +0 -0
  374. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_instrument_mixins.py +0 -0
  375. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_merge.py +0 -0
  376. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_portfolio_cash_flow.py +0 -0
  377. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_portfolio_cash_targets.py +0 -0
  378. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_portfolio_swing_pricings.py +0 -0
  379. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_portfolios.py +0 -0
  380. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_product_groups.py +0 -0
  381. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_roles.py +0 -0
  382. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/test_splits.py +0 -0
  383. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/transactions/__init__.py +0 -0
  384. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/transactions/test_claim.py +0 -0
  385. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/transactions/test_fees.py +0 -0
  386. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/transactions/test_rebalancing.py +0 -0
  387. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/transactions/test_trades.py +0 -0
  388. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/models/utils.py +0 -0
  389. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/pms/__init__.py +0 -0
  390. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/pms/test_analytics.py +0 -0
  391. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/rebalancing/__init__.py +0 -0
  392. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/rebalancing/test_models.py +0 -0
  393. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/serializers/__init__.py +0 -0
  394. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/serializers/test_claims.py +0 -0
  395. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/signals.py +0 -0
  396. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/tests.py +0 -0
  397. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/__init__.py +0 -0
  398. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/test_assets.py +0 -0
  399. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/test_performances.py +0 -0
  400. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/test_products.py +0 -0
  401. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/transactions/__init__.py +0 -0
  402. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/tests/viewsets/transactions/test_claims.py +0 -0
  403. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/urls.py +0 -0
  404. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/utils.py +0 -0
  405. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/__init__.py +0 -0
  406. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/adjustments.py +0 -0
  407. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/assets.py +0 -0
  408. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/assets_and_net_new_money_progression.py +0 -0
  409. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/charts/__init__.py +0 -0
  410. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/charts/assets.py +0 -0
  411. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/__init__.py +0 -0
  412. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/__init__.py +0 -0
  413. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/adjustments.py +0 -0
  414. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/assets.py +0 -0
  415. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/claims.py +0 -0
  416. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/custodians.py +0 -0
  417. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/fees.py +0 -0
  418. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/mixins.py +0 -0
  419. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/portfolios.py +0 -0
  420. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/products.py +0 -0
  421. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/reconciliations.py +0 -0
  422. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/registers.py +0 -0
  423. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/signals.py +0 -0
  424. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -0
  425. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/buttons/trades.py +0 -0
  426. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/__init__.py +0 -0
  427. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/adjustments.py +0 -0
  428. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/assets.py +0 -0
  429. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/claim.py +0 -0
  430. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/custodians.py +0 -0
  431. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/esg.py +0 -0
  432. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/fees.py +0 -0
  433. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/portfolio_cash_flow.py +0 -0
  434. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/portfolio_relationship.py +0 -0
  435. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/portfolios.py +0 -0
  436. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/positions.py +0 -0
  437. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/product_groups.py +0 -0
  438. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/product_performance.py +0 -0
  439. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/products.py +0 -0
  440. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/rebalancing.py +0 -0
  441. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/reconciliations.py +0 -0
  442. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/registers.py +0 -0
  443. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/roles.py +0 -0
  444. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/trade_proposals.py +0 -0
  445. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/trades.py +0 -0
  446. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/display/transactions.py +0 -0
  447. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/__init__.py +0 -0
  448. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/adjustments.py +0 -0
  449. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/assets.py +0 -0
  450. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/claim.py +0 -0
  451. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/custodians.py +0 -0
  452. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/esg.py +0 -0
  453. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/fees.py +0 -0
  454. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/portfolio_relationship.py +0 -0
  455. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/portfolios.py +0 -0
  456. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/positions.py +0 -0
  457. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/product_groups.py +0 -0
  458. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/product_performance.py +0 -0
  459. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/products.py +0 -0
  460. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/rebalancing.py +0 -0
  461. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/reconciliations.py +0 -0
  462. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/roles.py +0 -0
  463. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -0
  464. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/trades.py +0 -0
  465. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/endpoints/transactions.py +0 -0
  466. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/__init__.py +0 -0
  467. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/adjustments.py +0 -0
  468. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/assets.py +0 -0
  469. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/claim.py +0 -0
  470. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/custodians.py +0 -0
  471. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/fees.py +0 -0
  472. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/instrument_prices.py +0 -0
  473. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +0 -0
  474. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/portfolios.py +0 -0
  475. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/positions.py +0 -0
  476. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/product_groups.py +0 -0
  477. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/product_performance.py +0 -0
  478. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/products.py +0 -0
  479. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/reconciliations.py +0 -0
  480. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/registers.py +0 -0
  481. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/roles.py +0 -0
  482. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/trades.py +0 -0
  483. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/menu/transactions.py +0 -0
  484. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/previews/__init__.py +0 -0
  485. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/previews/portfolios.py +0 -0
  486. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/__init__.py +0 -0
  487. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/adjustments.py +0 -0
  488. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/assets.py +0 -0
  489. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/assets_and_net_new_money_progression.py +0 -0
  490. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/claim.py +0 -0
  491. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/custodians.py +0 -0
  492. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/esg.py +0 -0
  493. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/fees.py +0 -0
  494. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/instrument_prices.py +0 -0
  495. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/portfolios.py +0 -0
  496. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/positions.py +0 -0
  497. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/product_groups.py +0 -0
  498. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/product_performance.py +0 -0
  499. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/products.py +0 -0
  500. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/registers.py +0 -0
  501. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/roles.py +0 -0
  502. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/trades.py +0 -0
  503. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/configs/titles/transactions.py +0 -0
  504. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/custodians.py +0 -0
  505. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/esg.py +0 -0
  506. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/mixins.py +0 -0
  507. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/portfolio_cash_flow.py +0 -0
  508. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/portfolio_cash_targets.py +0 -0
  509. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/portfolio_relationship.py +0 -0
  510. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/portfolio_swing_pricing.py +0 -0
  511. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/portfolios.py +0 -0
  512. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/positions.py +0 -0
  513. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/product_groups.py +0 -0
  514. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/product_performance.py +0 -0
  515. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/products.py +0 -0
  516. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/reconciliations.py +0 -0
  517. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/registers.py +0 -0
  518. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/roles.py +0 -0
  519. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/signals.py +0 -0
  520. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/__init__.py +0 -0
  521. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/claim.py +0 -0
  522. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/fees.py +0 -0
  523. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/mixins.py +0 -0
  524. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/rebalancing.py +0 -0
  525. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/trades.py +0 -0
  526. {wbportfolio-1.47.1 → wbportfolio-1.48.0}/wbportfolio/viewsets/transactions/transactions.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.47.1
3
+ Version: 1.48.0
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -1,11 +1,13 @@
1
1
  from datetime import date
2
2
 
3
3
  from celery import shared_task
4
+ from django.db.models import Exists, OuterRef
4
5
  from tqdm import tqdm
5
6
  from wbcore.contrib.currency.models import CurrencyFXRates
6
- from wbcore.contrib.directory.models import Company, Entry
7
+ from wbcore.contrib.directory.models import Company
8
+ from wbcrm.models import Account
7
9
 
8
- from .models import Updater
10
+ from .models import CompanyPortfolioData, Updater
9
11
 
10
12
 
11
13
  @shared_task(queue="portfolio")
@@ -13,7 +15,9 @@ def update_all_portfolio_data(val_date: date | None = None):
13
15
  if not val_date:
14
16
  val_date = CurrencyFXRates.objects.latest("date").date
15
17
  updater = Updater(val_date)
16
- account_owners = Entry.objects.filter(accounts__isnull=False)
17
- qs = Company.objects.filter(id__in=account_owners)
18
+ qs = Company.objects.annotate(
19
+ has_account=Exists(Account.objects.filter(owner=OuterRef("pk"))),
20
+ has_portfolio_data=Exists(CompanyPortfolioData.objects.filter(company=OuterRef("pk"))),
21
+ )
18
22
  for company in tqdm(qs, total=qs.count()):
19
23
  updater.update_company_data(company)
@@ -56,3 +56,12 @@ class AccountHoldingReconciliationNotificationBodyUpdate(LongStringPreference):
56
56
  section = portfolio
57
57
  name = "account_holding_reconciliation_notification_body_update"
58
58
  default = """A reconcilation has been updated and requires your review. Please review the reconciliation for the account {account} on {reconciliation_date}."""
59
+
60
+
61
+ @global_preferences_registry.register
62
+ class ProductTerminationNoticePeriod(IntegerPreference):
63
+ section = portfolio
64
+ name = "product_termination_notice_period"
65
+ default = 6 * 30 # approx 6 months
66
+
67
+ verbose_name = "Product Termination notice period"
@@ -0,0 +1,55 @@
1
+ import rstr
2
+ from faker import Faker
3
+ from import_export import fields
4
+ from import_export.widgets import ForeignKeyWidget
5
+ from wbcore.contrib.io.resources import FilterModelResource
6
+ from wbfdm.models import Instrument
7
+
8
+ from wbportfolio.models import Trade
9
+
10
+ fake = Faker()
11
+
12
+
13
+ class TradeProposalTradeResource(FilterModelResource):
14
+ """
15
+ Trade Resource class to use to import trade from the trade proposal
16
+ """
17
+
18
+ DUMMY_FIELD_MAP = {
19
+ "underlying_instrument__isin": lambda: rstr.xeger("([A-Z]{2}[A-Z0-9]{9}[0-9]{1})"),
20
+ "underlying_instrument__ticker": "AAA",
21
+ "underlying_instrument__name": "stock name",
22
+ "weighting": 1.0,
23
+ "shares": 1000.2536,
24
+ "comment": lambda: fake.sentence(),
25
+ "order": 1,
26
+ }
27
+ underlying_instrument__isin = fields.Field(
28
+ column_name="underlying_instrument__isin",
29
+ attribute="underlying_instrument",
30
+ widget=ForeignKeyWidget(Instrument, field="isin"),
31
+ )
32
+ underlying_instrument__name = fields.Field(
33
+ column_name="underlying_instrument__name",
34
+ attribute="underlying_instrument",
35
+ widget=ForeignKeyWidget(Instrument, field="name"),
36
+ )
37
+ underlying_instrument__ticker = fields.Field(
38
+ column_name="underlying_instrument__ticker",
39
+ attribute="underlying_instrument",
40
+ widget=ForeignKeyWidget(Instrument, field="ticker"),
41
+ )
42
+
43
+ class Meta:
44
+ fields = (
45
+ "id",
46
+ "underlying_instrument__isin",
47
+ "underlying_instrument__name",
48
+ "underlying_instrument__ticker",
49
+ "weighting",
50
+ "shares",
51
+ "comment",
52
+ "order",
53
+ )
54
+ export_order = fields
55
+ model = Trade
@@ -2,12 +2,11 @@ from datetime import date
2
2
 
3
3
  import numpy as np
4
4
  import pandas as pd
5
- from django.db.models import Exists, OuterRef, QuerySet
5
+ from django.db.models import QuerySet
6
6
  from wbfdm.contrib.metric.backends.base import AbstractBackend, Metric
7
7
  from wbfdm.contrib.metric.exceptions import MetricInvalidParameterException
8
- from wbfdm.models import InstrumentType
9
8
 
10
- from wbportfolio.models import AssetPosition, InstrumentPortfolioThroughModel, Portfolio
9
+ from wbportfolio.models import AssetPosition, Portfolio
11
10
 
12
11
 
13
12
  class PortfolioMetricBaseBackend(AbstractBackend[Portfolio]):
@@ -66,18 +65,7 @@ class PortfolioMetricBaseBackend(AbstractBackend[Portfolio]):
66
65
  raise MetricInvalidParameterException()
67
66
 
68
67
  def get_queryset(self) -> QuerySet[Portfolio]:
69
- product_portfolios = (
70
- super()
71
- .get_queryset()
72
- .annotate(
73
- has_product=Exists(
74
- InstrumentPortfolioThroughModel.objects.filter(
75
- instrument__instrument_type=InstrumentType.PRODUCT, portfolio=OuterRef("pk")
76
- )
77
- )
78
- )
79
- .filter(has_product=True, is_active=True)
80
- )
68
+ product_portfolios = super().get_queryset().filter_active_and_tracked()
81
69
  try:
82
70
  last_position_date = (
83
71
  AssetPosition.objects.filter(portfolio__in=product_portfolios, is_estimated=False).latest("date").date
@@ -1,5 +1,5 @@
1
1
  # Import CRM relevant data
2
-
2
+ from .roles import PortfolioRole
3
3
  from .adjustments import Adjustment
4
4
  from .asset import AssetPosition, AssetPositionGroupBy
5
5
  from .custodians import Custodian
@@ -16,6 +16,5 @@ from .portfolio_cash_targets import PortfolioCashTarget
16
16
  from .portfolio_cash_flow import DailyPortfolioCashFlow
17
17
  from .portfolio_swing_pricings import PortfolioSwingPricing
18
18
  from .registers import Register
19
- from .roles import PortfolioRole
20
19
  from .transactions import *
21
20
  from .reconciliations import AccountReconciliation, AccountReconciliationLine
@@ -528,7 +528,7 @@ class AssetPosition(ImportMixin, models.Model):
528
528
  shares=self._shares,
529
529
  date=self.date,
530
530
  asset_valuation_date=self.asset_valuation_date,
531
- instrument_type=self.underlying_quote.instrument_type.id,
531
+ instrument_type=self.underlying_quote.security_instrument_type.id,
532
532
  currency=self.underlying_quote.currency.id,
533
533
  country=self.underlying_quote.country.id if self.underlying_quote.country else None,
534
534
  is_cash=self.underlying_quote.is_cash,
@@ -129,6 +129,15 @@ class DefaultPortfolioQueryset(QuerySet):
129
129
  & (Q(invested_timespan__endswith__gt=val_date) | Q(invested_timespan__endswith__isnull=True))
130
130
  )
131
131
 
132
+ def filter_active_and_tracked(self):
133
+ return self.annotate(
134
+ has_product=Exists(
135
+ InstrumentPortfolioThroughModel.objects.filter(
136
+ instrument__instrument_type=InstrumentType.PRODUCT, portfolio=OuterRef("pk")
137
+ )
138
+ )
139
+ ).filter((Q(has_product=True) | Q(is_manageable=True)) & Q(is_active=True) & Q(is_tracked=True))
140
+
132
141
  def to_dependency_iterator(self, val_date: date) -> Iterable["Portfolio"]:
133
142
  """
134
143
  A method to sort the given queryset to return undependable portfolio first. This is very useful if a routine needs to be applied sequentially on portfolios by order of dependence.
@@ -171,6 +180,9 @@ class DefaultPortfolioManager(ActiveObjectManager):
171
180
  def filter_invested_at_date(self, val_date: date):
172
181
  return self.get_queryset().filter_invested_at_date(val_date)
173
182
 
183
+ def filter_active_and_tracked(self):
184
+ return self.get_queryset().filter_active_and_tracked()
185
+
174
186
 
175
187
  class ActiveTrackedPortfolioManager(DefaultPortfolioManager):
176
188
  def get_queryset(self):
@@ -1,5 +1,5 @@
1
1
  from contextlib import suppress
2
- from datetime import date, datetime, time
2
+ from datetime import date, datetime, time, timedelta
3
3
  from decimal import Decimal
4
4
 
5
5
  from celery import shared_task
@@ -25,6 +25,9 @@ from pandas.tseries.offsets import BDay
25
25
  from wbcore.contrib.ai.llm.config import add_llm_prompt
26
26
  from wbcore.contrib.currency.models import CurrencyFXRates
27
27
  from wbcore.contrib.directory.models import Entry
28
+ from wbcore.contrib.notifications.dispatch import send_notification
29
+ from wbcore.contrib.notifications.utils import create_notification_type
30
+ from wbcore.permissions.shortcuts import get_internal_users
28
31
  from wbcore.signals import pre_merge
29
32
  from wbcore.utils.enum import ChoiceEnum
30
33
  from wbcrm.models.accounts import Account
@@ -34,6 +37,8 @@ from wbfdm.models.instruments.instruments import InstrumentManager, InstrumentTy
34
37
  from wbportfolio.models.llm.wbcrm.analyze_relationship import get_holding_prompt
35
38
  from wbportfolio.models.portfolio_relationship import InstrumentPortfolioThroughModel
36
39
 
40
+ from ..preferences import get_product_termination_notice_period
41
+ from . import PortfolioRole
37
42
  from .mixins.instruments import PMSInstrument, PMSInstrumentAbstractModel
38
43
 
39
44
 
@@ -316,6 +321,17 @@ class Product(PMSInstrumentAbstractModel):
316
321
  class Meta:
317
322
  verbose_name = "Product"
318
323
  verbose_name_plural = "Products"
324
+ notification_types = [
325
+ create_notification_type(
326
+ "wbportfolio.product.termination_notice",
327
+ "Product Termination Notice",
328
+ "Sends a notification when a product is expected termination in the near future",
329
+ True,
330
+ True,
331
+ True,
332
+ is_lock=True,
333
+ ),
334
+ ]
319
335
 
320
336
  def pre_save(self):
321
337
  super().pre_save()
@@ -341,6 +357,39 @@ class Product(PMSInstrumentAbstractModel):
341
357
  computed_str += f" ({self.isin})"
342
358
  return computed_str
343
359
 
360
+ def check_and_notify_product_termination_on_date(self, today: date) -> bool:
361
+ """
362
+ Checks if today is the expected notice date for product termination and sends notifications if applicable.
363
+
364
+ The expected notice date is calculated by subtracting the product termination notice period from the product's delisted date. Notifications are sent to users associated with the product's portfolio roles.
365
+
366
+ Args:
367
+ today (date): The date to check against the expected notice date.
368
+
369
+ Returns:
370
+ bool: True if termination is due, False otherwise.
371
+ """
372
+ if self.delisted_date:
373
+ product_termination_expected_notice_date = self.delisted_date - timedelta(
374
+ days=get_product_termination_notice_period()
375
+ )
376
+ if today == product_termination_expected_notice_date:
377
+ roles = PortfolioRole.objects.filter(
378
+ (models.Q(instrument=self) | models.Q(instrument__isnull=True))
379
+ & (models.Q(start__isnull=True) | models.Q(start__gte=today))
380
+ & (models.Q(end__isnull=True) | models.Q(end__lte=today))
381
+ & models.Q(person__user_account__isnull=False)
382
+ )
383
+ for user in get_internal_users().filter(is_active=True, id__in=roles.values("person__user_account")):
384
+ send_notification(
385
+ code="wbportfolio.product.termination_notice",
386
+ title="Product Termination Notice",
387
+ body=f"The product {self} will be terminated on the {self.delisted_date:%Y-%m-%d}",
388
+ user=user,
389
+ )
390
+ return True
391
+ return False
392
+
344
393
  @property
345
394
  def white_label_product(self):
346
395
  return self.white_label_customers.all().count() > 0
@@ -15,6 +15,7 @@ from wbcore.contrib.icons import WBIcon
15
15
  from wbcore.enums import RequestType
16
16
  from wbcore.metadata.configs.buttons import ActionButton
17
17
  from wbcore.models import WBModel
18
+ from wbcore.utils.models import CloneMixin
18
19
  from wbfdm.models.instruments.instruments import Instrument
19
20
 
20
21
  from wbportfolio.models.roles import PortfolioRole
@@ -30,7 +31,7 @@ logger = logging.getLogger("pms")
30
31
  SelfTradeProposal = TypeVar("SelfTradeProposal", bound="TradeProposal")
31
32
 
32
33
 
33
- class TradeProposal(RiskCheckMixin, WBModel):
34
+ class TradeProposal(CloneMixin, RiskCheckMixin, WBModel):
34
35
  trade_date = models.DateField(verbose_name="Trading Date")
35
36
 
36
37
  class Status(models.TextChoices):
@@ -76,17 +77,17 @@ class TradeProposal(RiskCheckMixin, WBModel):
76
77
  def save(self, *args, **kwargs):
77
78
  if not self.trade_date and self.portfolio.assets.exists():
78
79
  self.trade_date = (self.portfolio.assets.latest("date").date + BDay(1)).date()
79
- if not self.rebalancing_model and (rebalancer := getattr(self.portfolio, "automatic_rebalancer", None)):
80
- self.rebalancing_model = rebalancer.rebalancing_model
81
80
  super().save(*args, **kwargs)
82
81
  if self.status == TradeProposal.Status.APPROVED:
83
82
  self.portfolio.change_at_date(self.trade_date)
84
83
 
85
- def _get_checked_object_field_name(self) -> str:
86
- """
87
- Mandatory function from the Riskcheck mixin that returns the field (aka portfolio), representing the object to check the rules against.
88
- """
89
- return "portfolio"
84
+ @property
85
+ def checked_object(self):
86
+ return self.portfolio
87
+
88
+ @property
89
+ def check_evaluation_date(self):
90
+ return self.trade_date
90
91
 
91
92
  @cached_property
92
93
  def validated_trading_service(self) -> TradingService:
@@ -154,7 +155,7 @@ class TradeProposal(RiskCheckMixin, WBModel):
154
155
  )
155
156
 
156
157
  # Start tools methods
157
- def clone(self, **kwargs) -> SelfTradeProposal:
158
+ def _clone(self, **kwargs) -> SelfTradeProposal:
158
159
  """
159
160
  Method to clone self as a new trade proposal. It will automatically shift the trade date if a proposal already exists
160
161
  Args:
@@ -176,6 +177,11 @@ class TradeProposal(RiskCheckMixin, WBModel):
176
177
  portfolio=self.portfolio,
177
178
  creator=self.creator,
178
179
  )
180
+ for trade in self.trades.all():
181
+ trade.id = None
182
+ trade.trade_proposal = trade_proposal_clone
183
+ trade.save()
184
+
179
185
  return trade_proposal_clone
180
186
 
181
187
  def normalize_trades(self):
@@ -263,17 +269,19 @@ class TradeProposal(RiskCheckMixin, WBModel):
263
269
  last_trade_proposal.portfolio.assets.filter(
264
270
  date=last_trade_proposal.trade_date
265
271
  ).delete() # we delete the existing position and we reapply the trade proposal
266
- if not last_trade_proposal.portfolio.assets.filter(date=last_trade_proposal.trade_date).exists():
267
- if last_trade_proposal.status == TradeProposal.Status.APPROVED:
268
- logger.info("Reverting trade proposal ...")
269
- last_trade_proposal.revert()
270
- if last_trade_proposal.status == TradeProposal.Status.DRAFT:
271
- logger.info("Submitting trade proposal ...")
272
- last_trade_proposal.submit()
273
- if last_trade_proposal.status == TradeProposal.Status.SUBMIT:
274
- logger.info("Approving trade proposal ...")
275
- last_trade_proposal.approve()
276
- last_trade_proposal.save()
272
+ if last_trade_proposal.status == TradeProposal.Status.APPROVED:
273
+ logger.info("Reverting trade proposal ...")
274
+ last_trade_proposal.revert()
275
+ if last_trade_proposal.status == TradeProposal.Status.DRAFT:
276
+ if self.rebalancing_model: # if there is no position (for any reason) or we the trade proposal has a rebalancer model attached (trades are computed based on an aglo), we reapply this trade proposal
277
+ logger.info(f"Resetting trades from rebalancer model {self.rebalancing_model} ...")
278
+ self.reset_trades()
279
+ logger.info("Submitting trade proposal ...")
280
+ last_trade_proposal.submit()
281
+ if last_trade_proposal.status == TradeProposal.Status.SUBMIT:
282
+ logger.info("Approving trade proposal ...")
283
+ last_trade_proposal.approve()
284
+ last_trade_proposal.save()
277
285
  next_trade_proposal = last_trade_proposal.next_trade_proposal
278
286
  next_trade_date = (
279
287
  next_trade_proposal.trade_date - timedelta(days=1) if next_trade_proposal else date.today()
@@ -487,6 +487,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
487
487
  super().__init__(*args, **kwargs)
488
488
  if target_weight is not None: # if target weight is provided, we guess the corresponding weighting
489
489
  self.weighting = Decimal(target_weight) - self._effective_weight
490
+ self._set_transaction_subtype()
490
491
 
491
492
  def save(self, *args, **kwargs):
492
493
  if self.trade_proposal:
@@ -514,19 +515,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
514
515
 
515
516
  if self.transaction_subtype is None:
516
517
  # if subtype not provided, we extract it automatically from the existing data.
517
- if self.underlying_instrument.instrument_type.key == "product":
518
- if self.shares is not None:
519
- if self.shares > 0:
520
- self.transaction_subtype = Trade.Type.SUBSCRIPTION
521
- elif self.shares < 0:
522
- self.transaction_subtype = Trade.Type.REDEMPTION
523
- elif self.weighting is not None:
524
- if self.weighting > 0:
525
- self.transaction_subtype = Trade.Type.BUY
526
- elif self.weighting < 0:
527
- self.transaction_subtype = Trade.Type.SELL
528
- else:
529
- self.transaction_subtype = Trade.Type.REBALANCE
518
+ self._set_transaction_subtype()
530
519
  if self.id and hasattr(self, "claims"):
531
520
  self.claimed_shares = self.trade.claims.filter(status="APPROVED").aggregate(s=Sum("shares"))[
532
521
  "s"
@@ -535,6 +524,21 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
535
524
  self.marked_as_internal = True
536
525
  super().save(*args, **kwargs)
537
526
 
527
+ def _set_transaction_subtype(self):
528
+ if self.underlying_instrument.instrument_type.key == "product":
529
+ if self.shares is not None:
530
+ if self.shares > 0:
531
+ self.transaction_subtype = Trade.Type.SUBSCRIPTION
532
+ elif self.shares < 0:
533
+ self.transaction_subtype = Trade.Type.REDEMPTION
534
+ elif self.weighting is not None:
535
+ if self.weighting > 0:
536
+ self.transaction_subtype = Trade.Type.BUY
537
+ elif self.weighting < 0:
538
+ self.transaction_subtype = Trade.Type.SELL
539
+ else:
540
+ self.transaction_subtype = Trade.Type.REBALANCE
541
+
538
542
  def get_transaction_subtype(self) -> str:
539
543
  """
540
544
  Return the expected transaction subtype based n
@@ -560,7 +564,7 @@ class Trade(ShareMixin, Transaction, OrderedModel, WBModel):
560
564
  underlying_instrument=self.underlying_instrument.id,
561
565
  effective_weight=self._effective_weight,
562
566
  target_weight=self._target_weight,
563
- instrument_type=self.underlying_instrument.security_instrument_type,
567
+ instrument_type=self.underlying_instrument.security_instrument_type.id,
564
568
  currency=self.underlying_instrument.currency,
565
569
  date=self.transaction_date,
566
570
  )
@@ -0,0 +1,11 @@
1
+ from dynamic_preferences.registries import global_preferences_registry
2
+
3
+
4
+ def get_monthly_nnm_target(*args, **kwargs) -> int:
5
+ global_preferences = global_preferences_registry.manager()
6
+ return global_preferences["wbportfolio__monthly_nnm_target"]
7
+
8
+
9
+ def get_product_termination_notice_period(*args, **kwargs) -> int:
10
+ global_preferences = global_preferences_registry.manager()
11
+ return global_preferences["wbportfolio__product_termination_notice_period"]
@@ -3,6 +3,7 @@ from typing import Generator
3
3
 
4
4
  import pandas as pd
5
5
  from django.contrib.contenttypes.models import ContentType
6
+ from django.contrib.humanize.templatetags.humanize import intcomma
6
7
  from django.db import models
7
8
  from wbcompliance.models.risk_management import backend
8
9
  from wbcompliance.models.risk_management.dispatch import register
@@ -148,15 +149,22 @@ class RuleBackend(backend.AbstractRuleBackend):
148
149
  report_details = {
149
150
  "Period": f"{cts_generator.start_date:%d.%m.%Y} - {cts_generator.end_date:%d.%m.%Y}",
150
151
  }
152
+
153
+ # create report detail template
151
154
  color = "red" if percentage < 0 else "green"
155
+ number_prefix = ""
156
+
152
157
  if self.field == "AUM":
153
- report_details["AUM Change"] = (
154
- f'<span style="color:{color}">{start_df.loc[breached_obj_id]:.0f} $ → {end_df.loc[breached_obj_id]:.0f} $</span>'
155
- )
158
+ key = "AUM Change"
159
+ number_prefix = "$"
156
160
  else:
157
- report_details["Shares Change"] = (
158
- f"<span style='color:{color}'>{start_df.loc[breached_obj_id]:.0f} → {end_df.loc[breached_obj_id]:.0f}</span>"
159
- )
161
+ key = "Shares Change"
162
+
163
+ template = f'{number_prefix}{{}} → {number_prefix}{{}} <span style="color:{color}"><strong>Δ {number_prefix}{{}}</strong></span>'
164
+ start = intcomma(int(start_df.loc[breached_obj_id].round(0)))
165
+ end = intcomma(int(end_df.loc[breached_obj_id].round(0)))
166
+ diff = intcomma(int((end_df.loc[breached_obj_id] - start_df.loc[breached_obj_id]).round(0)))
167
+ report_details[key] = template.format(start, end, diff)
160
168
  report_details["Group By"] = self.group_by.value
161
169
  yield backend.IncidentResult(
162
170
  breached_object=breached_obj,
@@ -137,11 +137,12 @@ class RuleBackend(
137
137
  if not (df := self._filter_df(portfolio.to_df())).empty:
138
138
  df = df[[self.group_by.value, self.field.value]].groupby(self.group_by.value).sum().astype(float)
139
139
  for threshold in self.thresholds:
140
- dff = df.copy()
141
140
  numerical_range = threshold.numerical_range
142
- dff = dff[(dff[self.field.value] > numerical_range[0]) & (dff[self.field.value] < numerical_range[1])]
143
- if not dff.empty:
144
- for id, row in dff.to_dict("index").items():
141
+ incident_df = df[
142
+ (df[self.field.value] >= numerical_range[0]) & (df[self.field.value] < numerical_range[1])
143
+ ]
144
+ if not incident_df.empty:
145
+ for id, row in incident_df.to_dict("index").items():
145
146
  obj, obj_repr = self._get_obj_repr(id)
146
147
  severity: RiskIncidentType = threshold.severity
147
148
  if self.field == self.Field.WEIGHTING:
@@ -165,9 +166,9 @@ class RuleBackend(
165
166
  return df
166
167
  if self.is_cash is True or self.is_cash is False:
167
168
  df = df[df["is_cash"] == self.is_cash]
168
-
169
169
  if self.asset_classes:
170
170
  df = df[df["instrument_type"].isin(list(map(lambda o: o.id, self.asset_classes)))]
171
+
171
172
  if self.countries:
172
173
  df = df[(~df["country"].isnull() & df["country"].isin(list(map(lambda o: o.id, self.countries))))]
173
174
  if self.currencies:
@@ -179,6 +180,7 @@ class RuleBackend(
179
180
  & df["primary_classification"].isin(list(map(lambda o: o.id, self.classifications)))
180
181
  )
181
182
  ]
183
+
182
184
  return df
183
185
 
184
186
  def _get_obj_repr(self, pivot_object_id) -> tuple[models.Model | None, str]:
@@ -10,10 +10,7 @@ from .. import PortfolioRepresentationSerializer, RebalancingModelRepresentation
10
10
 
11
11
 
12
12
  class TradeProposalModelSerializer(wb_serializers.ModelSerializer):
13
- rebalancing_model = wb_serializers.PrimaryKeyRelatedField(
14
- queryset=RebalancingModel.objects.all(),
15
- default=DefaultFromView("portfolio.automatic_rebalancer.rebalancing_model"),
16
- )
13
+ rebalancing_model = wb_serializers.PrimaryKeyRelatedField(queryset=RebalancingModel.objects.all(), required=False)
17
14
  _rebalancing_model = RebalancingModelRepresentationSerializer(source="rebalancing_model")
18
15
  target_portfolio = wb_serializers.PrimaryKeyRelatedField(
19
16
  queryset=Portfolio.objects.all(), write_only=True, required=False, default=DefaultFromView("portfolio")
@@ -32,15 +29,7 @@ class TradeProposalModelSerializer(wb_serializers.ModelSerializer):
32
29
  obj = super().create(validated_data)
33
30
 
34
31
  target_portfolio_dto = None
35
- if (
36
- target_portfolio
37
- and not rebalancing_model
38
- and (
39
- last_effective_date := target_portfolio.get_latest_asset_position_date(
40
- obj.trade_date, with_estimated=True
41
- )
42
- )
43
- ):
32
+ if target_portfolio and not rebalancing_model and (last_effective_date := obj.last_effective_date):
44
33
  target_portfolio_dto = target_portfolio._build_dto(last_effective_date)
45
34
  try:
46
35
  obj.reset_trades(target_portfolio=target_portfolio_dto)
@@ -10,10 +10,13 @@ from .fdm.tasks import * # noqa
10
10
 
11
11
 
12
12
  @shared_task(queue="portfolio")
13
- def periodically_update_outstanding_shares_for_active_products():
13
+ def daily_active_product_task(today: date | None = None):
14
+ if not today:
15
+ today = date.today()
14
16
  qs = Product.active_objects.all()
15
17
  for product in tqdm(qs, total=qs.count()):
16
18
  update_outstanding_shares_as_task(product.id)
19
+ product.check_and_notify_product_termination_on_date(today)
17
20
 
18
21
 
19
22
  @shared_task(queue="portfolio")
@@ -117,7 +117,7 @@ register(ContinentFactory)
117
117
 
118
118
  register(CompanyFactory)
119
119
  register(PersonFactory)
120
- register(InternalUserFactory)
120
+ register(InternalUserFactory, "internal_user")
121
121
  register(EntryFactory)
122
122
  register(CustomerStatusFactory)
123
123
  register(CompanyTypeFactory)
@@ -1,5 +1,7 @@
1
1
  import datetime
2
+ from datetime import timedelta
2
3
  from decimal import Decimal
4
+ from unittest.mock import patch
3
5
 
4
6
  import pytest
5
7
  from faker import Faker
@@ -7,6 +9,7 @@ from wbfdm.models import Instrument
7
9
 
8
10
  from wbportfolio.models import Product, Trade
9
11
 
12
+ from ...preferences import get_product_termination_notice_period
10
13
  from .utils import PortfolioTestMixin
11
14
 
12
15
  fake = Faker()
@@ -188,3 +191,26 @@ class TestProductModel(PortfolioTestMixin):
188
191
  product.initial_high_water_mark = 400
189
192
  product.save()
190
193
  assert product.get_high_water_mark(p4.date) == 400
194
+
195
+ @patch("wbportfolio.models.products.send_notification")
196
+ def test_check_and_notify_product_termination_on_date(
197
+ self, mock_fct, weekday, product, manager_portfolio_role_factory, internal_user
198
+ ):
199
+ assert not product.check_and_notify_product_termination_on_date(weekday)
200
+
201
+ product.delisted_date = weekday + datetime.timedelta(days=get_product_termination_notice_period())
202
+ product.save()
203
+ assert product.check_and_notify_product_termination_on_date(weekday)
204
+ mock_fct.assert_not_called()
205
+ assert not product.check_and_notify_product_termination_on_date(
206
+ weekday + timedelta(days=1)
207
+ ) # one day later is not valid anymore
208
+
209
+ manager_portfolio_role_factory.create(person=internal_user.profile)
210
+ product.check_and_notify_product_termination_on_date(weekday)
211
+ mock_fct.assert_called_with(
212
+ code="wbportfolio.product.termination_notice",
213
+ title="Product Termination Notice",
214
+ body=f"The product {product} will be terminated on the {product.delisted_date:%Y-%m-%d}",
215
+ user=internal_user,
216
+ )