wbportfolio 1.43.1__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 (506) hide show
  1. wbportfolio/__init__.py +1 -0
  2. wbportfolio/admin/__init__.py +12 -0
  3. wbportfolio/admin/asset.py +47 -0
  4. wbportfolio/admin/custodians.py +9 -0
  5. wbportfolio/admin/portfolio.py +127 -0
  6. wbportfolio/admin/portfolio_relationships.py +22 -0
  7. wbportfolio/admin/product_groups.py +42 -0
  8. wbportfolio/admin/products.py +80 -0
  9. wbportfolio/admin/reconciliations.py +14 -0
  10. wbportfolio/admin/registers.py +17 -0
  11. wbportfolio/admin/roles.py +19 -0
  12. wbportfolio/admin/synchronization/__init__.py +2 -0
  13. wbportfolio/admin/synchronization/admin.py +114 -0
  14. wbportfolio/admin/synchronization/portfolio_synchronization.py +18 -0
  15. wbportfolio/admin/synchronization/price_computation.py +21 -0
  16. wbportfolio/admin/transactions/__init__.py +5 -0
  17. wbportfolio/admin/transactions/claim.py +16 -0
  18. wbportfolio/admin/transactions/dividends.py +14 -0
  19. wbportfolio/admin/transactions/fees.py +35 -0
  20. wbportfolio/admin/transactions/trades.py +49 -0
  21. wbportfolio/admin/transactions/transactions.py +37 -0
  22. wbportfolio/analysis/__init__.py +0 -0
  23. wbportfolio/analysis/claims.py +235 -0
  24. wbportfolio/apps.py +5 -0
  25. wbportfolio/contrib/__init__.py +0 -0
  26. wbportfolio/contrib/company_portfolio/__init__.py +0 -0
  27. wbportfolio/contrib/company_portfolio/admin.py +28 -0
  28. wbportfolio/contrib/company_portfolio/apps.py +29 -0
  29. wbportfolio/contrib/company_portfolio/configs/__init__.py +3 -0
  30. wbportfolio/contrib/company_portfolio/configs/display.py +182 -0
  31. wbportfolio/contrib/company_portfolio/configs/endpoints.py +34 -0
  32. wbportfolio/contrib/company_portfolio/configs/previews.py +37 -0
  33. wbportfolio/contrib/company_portfolio/constants.py +1 -0
  34. wbportfolio/contrib/company_portfolio/dynamic_preferences_registry.py +87 -0
  35. wbportfolio/contrib/company_portfolio/factories.py +32 -0
  36. wbportfolio/contrib/company_portfolio/filters.py +127 -0
  37. wbportfolio/contrib/company_portfolio/management.py +19 -0
  38. wbportfolio/contrib/company_portfolio/migrations/0001_initial.py +214 -0
  39. wbportfolio/contrib/company_portfolio/migrations/__init__.py +0 -0
  40. wbportfolio/contrib/company_portfolio/models.py +334 -0
  41. wbportfolio/contrib/company_portfolio/scripts.py +76 -0
  42. wbportfolio/contrib/company_portfolio/serializers.py +303 -0
  43. wbportfolio/contrib/company_portfolio/tasks.py +19 -0
  44. wbportfolio/contrib/company_portfolio/tests/__init__.py +0 -0
  45. wbportfolio/contrib/company_portfolio/tests/conftest.py +161 -0
  46. wbportfolio/contrib/company_portfolio/tests/test_models.py +161 -0
  47. wbportfolio/contrib/company_portfolio/urls.py +29 -0
  48. wbportfolio/contrib/company_portfolio/viewsets.py +195 -0
  49. wbportfolio/defaults/__init__.py +0 -0
  50. wbportfolio/defaults/fees/__init__.py +0 -0
  51. wbportfolio/defaults/fees/default.py +92 -0
  52. wbportfolio/defaults/portfolio/__init__.py +0 -0
  53. wbportfolio/defaults/portfolio/default_rebalancing.py +45 -0
  54. wbportfolio/dynamic_preferences_registry.py +58 -0
  55. wbportfolio/factories/__init__.py +35 -0
  56. wbportfolio/factories/adjustments.py +17 -0
  57. wbportfolio/factories/assets.py +75 -0
  58. wbportfolio/factories/claim.py +39 -0
  59. wbportfolio/factories/custodians.py +11 -0
  60. wbportfolio/factories/dividends.py +14 -0
  61. wbportfolio/factories/fees.py +15 -0
  62. wbportfolio/factories/indexes.py +17 -0
  63. wbportfolio/factories/portfolio_cash_flow.py +20 -0
  64. wbportfolio/factories/portfolio_cash_targets.py +15 -0
  65. wbportfolio/factories/portfolio_swing_pricings.py +15 -0
  66. wbportfolio/factories/portfolios.py +59 -0
  67. wbportfolio/factories/product_groups.py +28 -0
  68. wbportfolio/factories/products.py +56 -0
  69. wbportfolio/factories/pytest_utils.py +121 -0
  70. wbportfolio/factories/reconciliations.py +23 -0
  71. wbportfolio/factories/roles.py +20 -0
  72. wbportfolio/factories/synchronization.py +40 -0
  73. wbportfolio/factories/trades.py +35 -0
  74. wbportfolio/factories/transactions.py +21 -0
  75. wbportfolio/fdm/__init__.py +0 -0
  76. wbportfolio/fdm/tasks.py +12 -0
  77. wbportfolio/filters/__init__.py +32 -0
  78. wbportfolio/filters/assets.py +485 -0
  79. wbportfolio/filters/assets_and_net_new_money_progression.py +42 -0
  80. wbportfolio/filters/custodians.py +10 -0
  81. wbportfolio/filters/esg.py +22 -0
  82. wbportfolio/filters/performances.py +171 -0
  83. wbportfolio/filters/portfolios.py +24 -0
  84. wbportfolio/filters/positions.py +178 -0
  85. wbportfolio/filters/products.py +153 -0
  86. wbportfolio/filters/roles.py +26 -0
  87. wbportfolio/filters/signals.py +92 -0
  88. wbportfolio/filters/transactions/__init__.py +20 -0
  89. wbportfolio/filters/transactions/claim.py +394 -0
  90. wbportfolio/filters/transactions/fees.py +66 -0
  91. wbportfolio/filters/transactions/trades.py +248 -0
  92. wbportfolio/filters/transactions/transactions.py +98 -0
  93. wbportfolio/fixtures/product_factsheets.yaml +1 -0
  94. wbportfolio/fixtures/wbportfolio.yaml.gz +0 -0
  95. wbportfolio/fixtures/wbrisk_management.yaml.gz +0 -0
  96. wbportfolio/import_export/__init__.py +0 -0
  97. wbportfolio/import_export/backends/__init__.py +2 -0
  98. wbportfolio/import_export/backends/refinitiv/adjustment.py +40 -0
  99. wbportfolio/import_export/backends/ubs/__init__.py +3 -0
  100. wbportfolio/import_export/backends/ubs/asset_position.py +45 -0
  101. wbportfolio/import_export/backends/ubs/fees.py +63 -0
  102. wbportfolio/import_export/backends/ubs/instrument_price.py +44 -0
  103. wbportfolio/import_export/backends/ubs/mixin.py +15 -0
  104. wbportfolio/import_export/backends/utils.py +58 -0
  105. wbportfolio/import_export/backends/wbfdm/__init__.py +2 -0
  106. wbportfolio/import_export/backends/wbfdm/adjustment.py +50 -0
  107. wbportfolio/import_export/backends/wbfdm/dividend.py +16 -0
  108. wbportfolio/import_export/backends/wbfdm/mixin.py +15 -0
  109. wbportfolio/import_export/handlers/__init__.py +0 -0
  110. wbportfolio/import_export/handlers/adjustment.py +39 -0
  111. wbportfolio/import_export/handlers/asset_position.py +167 -0
  112. wbportfolio/import_export/handlers/dividend.py +80 -0
  113. wbportfolio/import_export/handlers/fees.py +58 -0
  114. wbportfolio/import_export/handlers/portfolio_cash_flow.py +57 -0
  115. wbportfolio/import_export/handlers/register.py +43 -0
  116. wbportfolio/import_export/handlers/trade.py +191 -0
  117. wbportfolio/import_export/parsers/__init__.py +0 -0
  118. wbportfolio/import_export/parsers/default_mapping.py +30 -0
  119. wbportfolio/import_export/parsers/jpmorgan/__init__.py +0 -0
  120. wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +63 -0
  121. wbportfolio/import_export/parsers/jpmorgan/fees.py +64 -0
  122. wbportfolio/import_export/parsers/jpmorgan/strategy.py +116 -0
  123. wbportfolio/import_export/parsers/jpmorgan/valuation.py +41 -0
  124. wbportfolio/import_export/parsers/leonteq/__init__.py +0 -0
  125. wbportfolio/import_export/parsers/leonteq/customer_trade.py +47 -0
  126. wbportfolio/import_export/parsers/leonteq/equity.py +81 -0
  127. wbportfolio/import_export/parsers/leonteq/fees.py +70 -0
  128. wbportfolio/import_export/parsers/leonteq/trade.py +94 -0
  129. wbportfolio/import_export/parsers/leonteq/valuation.py +39 -0
  130. wbportfolio/import_export/parsers/natixis/__init__.py +0 -0
  131. wbportfolio/import_export/parsers/natixis/customer_trade.py +62 -0
  132. wbportfolio/import_export/parsers/natixis/d1_customer_trade.py +66 -0
  133. wbportfolio/import_export/parsers/natixis/d1_equity.py +80 -0
  134. wbportfolio/import_export/parsers/natixis/d1_fees.py +58 -0
  135. wbportfolio/import_export/parsers/natixis/d1_trade.py +70 -0
  136. wbportfolio/import_export/parsers/natixis/d1_valuation.py +41 -0
  137. wbportfolio/import_export/parsers/natixis/dividend.py +53 -0
  138. wbportfolio/import_export/parsers/natixis/equity.py +60 -0
  139. wbportfolio/import_export/parsers/natixis/fees.py +53 -0
  140. wbportfolio/import_export/parsers/natixis/trade.py +63 -0
  141. wbportfolio/import_export/parsers/natixis/utils.py +76 -0
  142. wbportfolio/import_export/parsers/natixis/valuation.py +46 -0
  143. wbportfolio/import_export/parsers/refinitiv/__init__.py +0 -0
  144. wbportfolio/import_export/parsers/refinitiv/adjustment.py +24 -0
  145. wbportfolio/import_export/parsers/sg_lux/__init__.py +0 -0
  146. wbportfolio/import_export/parsers/sg_lux/custodian_positions.py +70 -0
  147. wbportfolio/import_export/parsers/sg_lux/customer_trade.py +75 -0
  148. wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +140 -0
  149. wbportfolio/import_export/parsers/sg_lux/customer_trade_slk.py +80 -0
  150. wbportfolio/import_export/parsers/sg_lux/customer_trade_without_pw.py +57 -0
  151. wbportfolio/import_export/parsers/sg_lux/equity.py +161 -0
  152. wbportfolio/import_export/parsers/sg_lux/fees.py +56 -0
  153. wbportfolio/import_export/parsers/sg_lux/perf_fees.py +51 -0
  154. wbportfolio/import_export/parsers/sg_lux/portfolio_cash_flow.py +29 -0
  155. wbportfolio/import_export/parsers/sg_lux/portfolio_future_cash_flow.py +36 -0
  156. wbportfolio/import_export/parsers/sg_lux/registers.py +210 -0
  157. wbportfolio/import_export/parsers/sg_lux/sylk.py +248 -0
  158. wbportfolio/import_export/parsers/sg_lux/utils.py +36 -0
  159. wbportfolio/import_export/parsers/sg_lux/valuation.py +53 -0
  160. wbportfolio/import_export/parsers/societe_generale/__init__.py +0 -0
  161. wbportfolio/import_export/parsers/societe_generale/customer_trade.py +54 -0
  162. wbportfolio/import_export/parsers/societe_generale/strategy.py +94 -0
  163. wbportfolio/import_export/parsers/societe_generale/valuation.py +37 -0
  164. wbportfolio/import_export/parsers/tellco/__init__.py +0 -0
  165. wbportfolio/import_export/parsers/tellco/customer_trade.py +64 -0
  166. wbportfolio/import_export/parsers/tellco/equity.py +86 -0
  167. wbportfolio/import_export/parsers/tellco/valuation.py +52 -0
  168. wbportfolio/import_export/parsers/ubs/__init__.py +0 -0
  169. wbportfolio/import_export/parsers/ubs/api/__init__.py +0 -0
  170. wbportfolio/import_export/parsers/ubs/api/asset_position.py +106 -0
  171. wbportfolio/import_export/parsers/ubs/api/fees.py +31 -0
  172. wbportfolio/import_export/parsers/ubs/api/instrument_price.py +20 -0
  173. wbportfolio/import_export/parsers/ubs/api/utils.py +0 -0
  174. wbportfolio/import_export/parsers/ubs/customer_trade.py +60 -0
  175. wbportfolio/import_export/parsers/ubs/equity.py +97 -0
  176. wbportfolio/import_export/parsers/ubs/historical_customer_trade.py +67 -0
  177. wbportfolio/import_export/parsers/ubs/valuation.py +52 -0
  178. wbportfolio/import_export/parsers/vontobel/__init__.py +0 -0
  179. wbportfolio/import_export/parsers/vontobel/asset_position.py +97 -0
  180. wbportfolio/import_export/parsers/vontobel/customer_trade.py +54 -0
  181. wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +40 -0
  182. wbportfolio/import_export/parsers/vontobel/instrument.py +34 -0
  183. wbportfolio/import_export/parsers/vontobel/management_fees.py +86 -0
  184. wbportfolio/import_export/parsers/vontobel/performance_fees.py +35 -0
  185. wbportfolio/import_export/parsers/vontobel/trade.py +38 -0
  186. wbportfolio/import_export/parsers/vontobel/utils.py +17 -0
  187. wbportfolio/import_export/parsers/vontobel/valuation.py +29 -0
  188. wbportfolio/import_export/resources/__init__.py +0 -0
  189. wbportfolio/import_export/resources/assets.py +68 -0
  190. wbportfolio/import_export/resources/trades.py +41 -0
  191. wbportfolio/import_export/utils.py +42 -0
  192. wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +119 -0
  193. wbportfolio/kpi_handlers/nnm.py +163 -0
  194. wbportfolio/metric/__init__.py +0 -0
  195. wbportfolio/metric/backends/__init__.py +2 -0
  196. wbportfolio/metric/backends/base.py +86 -0
  197. wbportfolio/metric/backends/constants.py +222 -0
  198. wbportfolio/metric/backends/portfolio_base.py +255 -0
  199. wbportfolio/metric/backends/portfolio_esg.py +66 -0
  200. wbportfolio/metric/tests/__init__.py +0 -0
  201. wbportfolio/metric/tests/conftest.py +4 -0
  202. wbportfolio/metric/tests/test_portfolio_base.py +135 -0
  203. wbportfolio/metric/tests/test_portfolio_esg.py +69 -0
  204. wbportfolio/migrations/0001_initial_squashed.py +13848 -0
  205. wbportfolio/migrations/0002_product_default_sub_account_squashed_0039_alter_assetallocation_company_and_more.py +3836 -0
  206. wbportfolio/migrations/0040_instrument_financial_instrument.py +26 -0
  207. wbportfolio/migrations/0041_remove_listresearch_research_ptr_and_more.py +129 -0
  208. wbportfolio/migrations/0042_instrumentlist_instrumentlistthroughmodel_and_more.py +71 -0
  209. wbportfolio/migrations/0043_alter_instrumentlistthroughmodel_options_and_more.py +238 -0
  210. wbportfolio/migrations/0044_alter_instrumentlist_identifier.py +35 -0
  211. wbportfolio/migrations/0045_alter_instrument_financial_instrument.py +26 -0
  212. wbportfolio/migrations/0046_add_product_default_account.py +166 -0
  213. wbportfolio/migrations/0047_remove_product_default_sub_account.py +14 -0
  214. wbportfolio/migrations/0048_alter_trade_status.py +29 -0
  215. wbportfolio/migrations/0049_trade_claimed_shares.py +25 -0
  216. wbportfolio/migrations/0050_fees_fee_date_fees_wbportfolio_transac_1f7a29_idx.py +44 -0
  217. wbportfolio/migrations/0051_delete_macroreview.py +11 -0
  218. wbportfolio/migrations/0052_remove_cash_instrument_ptr_and_more.py +888 -0
  219. wbportfolio/migrations/0053_remove_product_group.py +132 -0
  220. wbportfolio/migrations/0054_portfolioinstrumentpreferredclassificationthroughmodel_and_more.py +270 -0
  221. wbportfolio/migrations/0055_remove_product__custom_management_rebates_and_more.py +139 -0
  222. wbportfolio/migrations/0056_remove_companyportfoliodata_assets_under_management_currency_and_more.py +56 -0
  223. wbportfolio/migrations/0057_alter_portfolio_preferred_instrument_classifications_and_more.py +36 -0
  224. wbportfolio/migrations/0058_pmsinstrument.py +23 -0
  225. wbportfolio/migrations/0059_fees_unique_fees.py +51 -0
  226. wbportfolio/migrations/0060_alter_portfolioportfoliothroughmodel_type.py +21 -0
  227. wbportfolio/migrations/0061_portfolio_bank_accounts_product_bank_account_and_more.py +175 -0
  228. wbportfolio/migrations/0062_alter_dailyportfoliocashflow_options.py +20 -0
  229. wbportfolio/migrations/0063_accountreconciliation_accountreconciliationline_and_more.py +133 -0
  230. wbportfolio/migrations/0064_alter_portfolio_managers_portfolio_is_tracked_and_more.py +40 -0
  231. wbportfolio/migrations/0065_alter_portfolio_managers_claim_as_shares_and_more.py +73 -0
  232. wbportfolio/migrations/0066_assetposition_initial_shares_at_custodian_and_more.py +108 -0
  233. wbportfolio/migrations/0067_assetposition_unique_asset_position.py +77 -0
  234. wbportfolio/migrations/0068_trade_internal_trade_trade_marked_as_internal_and_more.py +59 -0
  235. wbportfolio/migrations/0069_remove_portfolio_is_invested_and_more.py +56 -0
  236. wbportfolio/migrations/0070_remove_assetposition_unique_asset_position_and_more.py +82 -0
  237. wbportfolio/migrations/0071_alter_trade_options_alter_trade_order.py +22 -0
  238. wbportfolio/migrations/__init__.py +0 -0
  239. wbportfolio/models/__init__.py +26 -0
  240. wbportfolio/models/adjustments.py +246 -0
  241. wbportfolio/models/asset.py +869 -0
  242. wbportfolio/models/custodians.py +101 -0
  243. wbportfolio/models/indexes.py +33 -0
  244. wbportfolio/models/llm/wbcrm/analyze_relationship.py +58 -0
  245. wbportfolio/models/mixins/__init__.py +0 -0
  246. wbportfolio/models/mixins/instruments.py +127 -0
  247. wbportfolio/models/mixins/liquidity_stress_test.py +1307 -0
  248. wbportfolio/models/portfolio.py +1039 -0
  249. wbportfolio/models/portfolio_cash_flow.py +167 -0
  250. wbportfolio/models/portfolio_cash_targets.py +46 -0
  251. wbportfolio/models/portfolio_relationship.py +135 -0
  252. wbportfolio/models/portfolio_swing_pricings.py +51 -0
  253. wbportfolio/models/product_groups.py +230 -0
  254. wbportfolio/models/products.py +569 -0
  255. wbportfolio/models/reconciliations/__init__.py +2 -0
  256. wbportfolio/models/reconciliations/account_reconciliation_lines.py +192 -0
  257. wbportfolio/models/reconciliations/account_reconciliations.py +102 -0
  258. wbportfolio/models/reconciliations/reconciliations.py +25 -0
  259. wbportfolio/models/registers.py +132 -0
  260. wbportfolio/models/roles.py +208 -0
  261. wbportfolio/models/synchronization/__init__.py +3 -0
  262. wbportfolio/models/synchronization/portfolio_synchronization.py +292 -0
  263. wbportfolio/models/synchronization/price_computation.py +200 -0
  264. wbportfolio/models/synchronization/synchronization.py +188 -0
  265. wbportfolio/models/transactions/__init__.py +7 -0
  266. wbportfolio/models/transactions/claim.py +634 -0
  267. wbportfolio/models/transactions/dividends.py +31 -0
  268. wbportfolio/models/transactions/expiry.py +7 -0
  269. wbportfolio/models/transactions/fees.py +153 -0
  270. wbportfolio/models/transactions/trade_proposals.py +502 -0
  271. wbportfolio/models/transactions/trades.py +704 -0
  272. wbportfolio/models/transactions/transactions.py +211 -0
  273. wbportfolio/models/utils.py +12 -0
  274. wbportfolio/permissions.py +13 -0
  275. wbportfolio/pms/__init__.py +0 -0
  276. wbportfolio/pms/statistics/__init__.py +0 -0
  277. wbportfolio/pms/trading/__init__.py +1 -0
  278. wbportfolio/pms/trading/handler.py +164 -0
  279. wbportfolio/pms/typing.py +194 -0
  280. wbportfolio/preferences.py +6 -0
  281. wbportfolio/reports/__init__.py +0 -0
  282. wbportfolio/reports/monthly_position_report.py +74 -0
  283. wbportfolio/risk_management/__init__.py +0 -0
  284. wbportfolio/risk_management/backends/__init__.py +11 -0
  285. wbportfolio/risk_management/backends/accounts.py +166 -0
  286. wbportfolio/risk_management/backends/controversy_portfolio.py +63 -0
  287. wbportfolio/risk_management/backends/exposure_portfolio.py +203 -0
  288. wbportfolio/risk_management/backends/instrument_list_portfolio.py +89 -0
  289. wbportfolio/risk_management/backends/liquidity_risk.py +86 -0
  290. wbportfolio/risk_management/backends/liquidity_stress_instrument.py +86 -0
  291. wbportfolio/risk_management/backends/mixins.py +220 -0
  292. wbportfolio/risk_management/backends/product_integrity.py +111 -0
  293. wbportfolio/risk_management/backends/stop_loss_instrument.py +24 -0
  294. wbportfolio/risk_management/backends/stop_loss_portfolio.py +36 -0
  295. wbportfolio/risk_management/backends/ucits_portfolio.py +63 -0
  296. wbportfolio/risk_management/tests/__init__.py +0 -0
  297. wbportfolio/risk_management/tests/conftest.py +15 -0
  298. wbportfolio/risk_management/tests/test_accounts.py +98 -0
  299. wbportfolio/risk_management/tests/test_controversy_portfolio.py +33 -0
  300. wbportfolio/risk_management/tests/test_exposure_portfolio.py +94 -0
  301. wbportfolio/risk_management/tests/test_instrument_list_portfolio.py +60 -0
  302. wbportfolio/risk_management/tests/test_liquidity_risk.py +47 -0
  303. wbportfolio/risk_management/tests/test_product_integrity.py +55 -0
  304. wbportfolio/risk_management/tests/test_stop_loss_instrument.py +110 -0
  305. wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +119 -0
  306. wbportfolio/risk_management/tests/test_ucits_portfolio.py +39 -0
  307. wbportfolio/serializers/__init__.py +42 -0
  308. wbportfolio/serializers/adjustments.py +24 -0
  309. wbportfolio/serializers/assets.py +166 -0
  310. wbportfolio/serializers/custodians.py +26 -0
  311. wbportfolio/serializers/portfolio_cash_flow.py +48 -0
  312. wbportfolio/serializers/portfolio_cash_targets.py +20 -0
  313. wbportfolio/serializers/portfolio_relationship.py +53 -0
  314. wbportfolio/serializers/portfolio_swing_pricing.py +20 -0
  315. wbportfolio/serializers/portfolios.py +143 -0
  316. wbportfolio/serializers/positions.py +76 -0
  317. wbportfolio/serializers/product_group.py +88 -0
  318. wbportfolio/serializers/products.py +331 -0
  319. wbportfolio/serializers/reconciliations.py +173 -0
  320. wbportfolio/serializers/registers.py +72 -0
  321. wbportfolio/serializers/roles.py +60 -0
  322. wbportfolio/serializers/signals.py +157 -0
  323. wbportfolio/serializers/synchronization.py +18 -0
  324. wbportfolio/serializers/transactions/__init__.py +24 -0
  325. wbportfolio/serializers/transactions/claim.py +310 -0
  326. wbportfolio/serializers/transactions/dividends.py +18 -0
  327. wbportfolio/serializers/transactions/expiry.py +18 -0
  328. wbportfolio/serializers/transactions/fees.py +32 -0
  329. wbportfolio/serializers/transactions/trades.py +315 -0
  330. wbportfolio/serializers/transactions/transactions.py +84 -0
  331. wbportfolio/static/wbportfolio/css/macro_review.css +17 -0
  332. wbportfolio/static/wbportfolio/markdown/documentation/account_holding_reconciliation.md +16 -0
  333. wbportfolio/static/wbportfolio/markdown/documentation/aggregate_asset_position_liquidity.md +25 -0
  334. wbportfolio/static/wbportfolio/markdown/documentation/company.md +78 -0
  335. wbportfolio/static/wbportfolio/markdown/documentation/earnings_instrument.md +14 -0
  336. wbportfolio/static/wbportfolio/markdown/documentation/financial_analysis_instrument_ratios.md +94 -0
  337. wbportfolio/static/wbportfolio/markdown/documentation/financial_statistics.md +44 -0
  338. wbportfolio/static/wbportfolio/markdown/documentation/person.md +70 -0
  339. wbportfolio/tasks.py +125 -0
  340. wbportfolio/templates/portfolio/email/customer_report.html +6 -0
  341. wbportfolio/templates/portfolio/email/customer_trade_notification.html +26 -0
  342. wbportfolio/templates/portfolio/email/email_base_template.html +420 -0
  343. wbportfolio/templates/portfolio/email/rebalancing_report.html +34 -0
  344. wbportfolio/templates/portfolio/macro/macro_review.html +88 -0
  345. wbportfolio/tests/__init__.py +0 -0
  346. wbportfolio/tests/conftest.py +164 -0
  347. wbportfolio/tests/models/__init__.py +0 -0
  348. wbportfolio/tests/models/test_account_reconciliation.py +191 -0
  349. wbportfolio/tests/models/test_assets.py +193 -0
  350. wbportfolio/tests/models/test_custodians.py +12 -0
  351. wbportfolio/tests/models/test_customer_trades.py +113 -0
  352. wbportfolio/tests/models/test_dividends.py +7 -0
  353. wbportfolio/tests/models/test_imports.py +192 -0
  354. wbportfolio/tests/models/test_instrument_mixins.py +48 -0
  355. wbportfolio/tests/models/test_merge.py +133 -0
  356. wbportfolio/tests/models/test_portfolio_cash_flow.py +112 -0
  357. wbportfolio/tests/models/test_portfolio_cash_targets.py +27 -0
  358. wbportfolio/tests/models/test_portfolio_swing_pricings.py +42 -0
  359. wbportfolio/tests/models/test_portfolios.py +676 -0
  360. wbportfolio/tests/models/test_product_groups.py +80 -0
  361. wbportfolio/tests/models/test_products.py +187 -0
  362. wbportfolio/tests/models/test_roles.py +82 -0
  363. wbportfolio/tests/models/test_splits.py +233 -0
  364. wbportfolio/tests/models/test_synchronization.py +617 -0
  365. wbportfolio/tests/models/transactions/__init__.py +0 -0
  366. wbportfolio/tests/models/transactions/test_claim.py +129 -0
  367. wbportfolio/tests/models/transactions/test_fees.py +65 -0
  368. wbportfolio/tests/models/transactions/test_trades.py +204 -0
  369. wbportfolio/tests/models/utils.py +13 -0
  370. wbportfolio/tests/serializers/__init__.py +0 -0
  371. wbportfolio/tests/serializers/test_claims.py +21 -0
  372. wbportfolio/tests/signals.py +151 -0
  373. wbportfolio/tests/tests.py +31 -0
  374. wbportfolio/tests/viewsets/__init__.py +0 -0
  375. wbportfolio/tests/viewsets/test_assets.py +67 -0
  376. wbportfolio/tests/viewsets/test_performances.py +72 -0
  377. wbportfolio/tests/viewsets/test_products.py +92 -0
  378. wbportfolio/tests/viewsets/transactions/__init__.py +0 -0
  379. wbportfolio/tests/viewsets/transactions/test_claims.py +146 -0
  380. wbportfolio/urls.py +247 -0
  381. wbportfolio/utils.py +30 -0
  382. wbportfolio/viewsets/__init__.py +57 -0
  383. wbportfolio/viewsets/adjustments.py +46 -0
  384. wbportfolio/viewsets/assets.py +562 -0
  385. wbportfolio/viewsets/assets_and_net_new_money_progression.py +117 -0
  386. wbportfolio/viewsets/charts/__init__.py +1 -0
  387. wbportfolio/viewsets/charts/assets.py +247 -0
  388. wbportfolio/viewsets/configs/__init__.py +6 -0
  389. wbportfolio/viewsets/configs/buttons/__init__.py +23 -0
  390. wbportfolio/viewsets/configs/buttons/adjustments.py +13 -0
  391. wbportfolio/viewsets/configs/buttons/assets.py +145 -0
  392. wbportfolio/viewsets/configs/buttons/claims.py +83 -0
  393. wbportfolio/viewsets/configs/buttons/custodians.py +76 -0
  394. wbportfolio/viewsets/configs/buttons/fees.py +14 -0
  395. wbportfolio/viewsets/configs/buttons/mixins.py +88 -0
  396. wbportfolio/viewsets/configs/buttons/portfolios.py +115 -0
  397. wbportfolio/viewsets/configs/buttons/products.py +41 -0
  398. wbportfolio/viewsets/configs/buttons/reconciliations.py +65 -0
  399. wbportfolio/viewsets/configs/buttons/registers.py +11 -0
  400. wbportfolio/viewsets/configs/buttons/signals.py +68 -0
  401. wbportfolio/viewsets/configs/buttons/trade_proposals.py +25 -0
  402. wbportfolio/viewsets/configs/buttons/trades.py +144 -0
  403. wbportfolio/viewsets/configs/display/__init__.py +61 -0
  404. wbportfolio/viewsets/configs/display/adjustments.py +81 -0
  405. wbportfolio/viewsets/configs/display/assets.py +265 -0
  406. wbportfolio/viewsets/configs/display/claim.py +299 -0
  407. wbportfolio/viewsets/configs/display/custodians.py +24 -0
  408. wbportfolio/viewsets/configs/display/esg.py +88 -0
  409. wbportfolio/viewsets/configs/display/fees.py +133 -0
  410. wbportfolio/viewsets/configs/display/portfolio_cash_flow.py +103 -0
  411. wbportfolio/viewsets/configs/display/portfolio_relationship.py +38 -0
  412. wbportfolio/viewsets/configs/display/portfolios.py +125 -0
  413. wbportfolio/viewsets/configs/display/positions.py +75 -0
  414. wbportfolio/viewsets/configs/display/product_groups.py +54 -0
  415. wbportfolio/viewsets/configs/display/product_performance.py +241 -0
  416. wbportfolio/viewsets/configs/display/products.py +249 -0
  417. wbportfolio/viewsets/configs/display/reconciliations.py +151 -0
  418. wbportfolio/viewsets/configs/display/registers.py +71 -0
  419. wbportfolio/viewsets/configs/display/roles.py +49 -0
  420. wbportfolio/viewsets/configs/display/trade_proposals.py +97 -0
  421. wbportfolio/viewsets/configs/display/trades.py +359 -0
  422. wbportfolio/viewsets/configs/display/transactions.py +55 -0
  423. wbportfolio/viewsets/configs/endpoints/__init__.py +75 -0
  424. wbportfolio/viewsets/configs/endpoints/adjustments.py +17 -0
  425. wbportfolio/viewsets/configs/endpoints/assets.py +115 -0
  426. wbportfolio/viewsets/configs/endpoints/claim.py +106 -0
  427. wbportfolio/viewsets/configs/endpoints/custodians.py +6 -0
  428. wbportfolio/viewsets/configs/endpoints/esg.py +14 -0
  429. wbportfolio/viewsets/configs/endpoints/fees.py +26 -0
  430. wbportfolio/viewsets/configs/endpoints/portfolio_relationship.py +23 -0
  431. wbportfolio/viewsets/configs/endpoints/portfolios.py +43 -0
  432. wbportfolio/viewsets/configs/endpoints/positions.py +18 -0
  433. wbportfolio/viewsets/configs/endpoints/product_groups.py +11 -0
  434. wbportfolio/viewsets/configs/endpoints/product_performance.py +29 -0
  435. wbportfolio/viewsets/configs/endpoints/products.py +37 -0
  436. wbportfolio/viewsets/configs/endpoints/reconciliations.py +31 -0
  437. wbportfolio/viewsets/configs/endpoints/roles.py +9 -0
  438. wbportfolio/viewsets/configs/endpoints/trade_proposals.py +17 -0
  439. wbportfolio/viewsets/configs/endpoints/trades.py +82 -0
  440. wbportfolio/viewsets/configs/endpoints/transactions.py +17 -0
  441. wbportfolio/viewsets/configs/menu/__init__.py +30 -0
  442. wbportfolio/viewsets/configs/menu/adjustments.py +8 -0
  443. wbportfolio/viewsets/configs/menu/assets.py +8 -0
  444. wbportfolio/viewsets/configs/menu/claim.py +41 -0
  445. wbportfolio/viewsets/configs/menu/custodians.py +11 -0
  446. wbportfolio/viewsets/configs/menu/fees.py +13 -0
  447. wbportfolio/viewsets/configs/menu/instrument_prices.py +10 -0
  448. wbportfolio/viewsets/configs/menu/portfolio_cash_flow.py +8 -0
  449. wbportfolio/viewsets/configs/menu/portfolios.py +15 -0
  450. wbportfolio/viewsets/configs/menu/positions.py +14 -0
  451. wbportfolio/viewsets/configs/menu/product_groups.py +10 -0
  452. wbportfolio/viewsets/configs/menu/product_performance.py +25 -0
  453. wbportfolio/viewsets/configs/menu/products.py +15 -0
  454. wbportfolio/viewsets/configs/menu/reconciliations.py +7 -0
  455. wbportfolio/viewsets/configs/menu/registers.py +10 -0
  456. wbportfolio/viewsets/configs/menu/roles.py +16 -0
  457. wbportfolio/viewsets/configs/menu/trades.py +18 -0
  458. wbportfolio/viewsets/configs/menu/transactions.py +8 -0
  459. wbportfolio/viewsets/configs/previews/__init__.py +1 -0
  460. wbportfolio/viewsets/configs/previews/portfolios.py +21 -0
  461. wbportfolio/viewsets/configs/titles/__init__.py +65 -0
  462. wbportfolio/viewsets/configs/titles/adjustments.py +19 -0
  463. wbportfolio/viewsets/configs/titles/assets.py +57 -0
  464. wbportfolio/viewsets/configs/titles/assets_and_net_new_money_progression.py +6 -0
  465. wbportfolio/viewsets/configs/titles/claim.py +81 -0
  466. wbportfolio/viewsets/configs/titles/custodians.py +12 -0
  467. wbportfolio/viewsets/configs/titles/esg.py +10 -0
  468. wbportfolio/viewsets/configs/titles/fees.py +25 -0
  469. wbportfolio/viewsets/configs/titles/instrument_prices.py +20 -0
  470. wbportfolio/viewsets/configs/titles/portfolios.py +32 -0
  471. wbportfolio/viewsets/configs/titles/positions.py +11 -0
  472. wbportfolio/viewsets/configs/titles/product_groups.py +12 -0
  473. wbportfolio/viewsets/configs/titles/product_performance.py +16 -0
  474. wbportfolio/viewsets/configs/titles/products.py +6 -0
  475. wbportfolio/viewsets/configs/titles/registers.py +12 -0
  476. wbportfolio/viewsets/configs/titles/roles.py +23 -0
  477. wbportfolio/viewsets/configs/titles/trades.py +51 -0
  478. wbportfolio/viewsets/configs/titles/transactions.py +8 -0
  479. wbportfolio/viewsets/custodians.py +66 -0
  480. wbportfolio/viewsets/esg.py +165 -0
  481. wbportfolio/viewsets/mixins.py +48 -0
  482. wbportfolio/viewsets/portfolio_cash_flow.py +31 -0
  483. wbportfolio/viewsets/portfolio_cash_targets.py +8 -0
  484. wbportfolio/viewsets/portfolio_relationship.py +46 -0
  485. wbportfolio/viewsets/portfolio_swing_pricing.py +8 -0
  486. wbportfolio/viewsets/portfolios.py +154 -0
  487. wbportfolio/viewsets/positions.py +292 -0
  488. wbportfolio/viewsets/product_groups.py +84 -0
  489. wbportfolio/viewsets/product_performance.py +646 -0
  490. wbportfolio/viewsets/products.py +529 -0
  491. wbportfolio/viewsets/reconciliations.py +160 -0
  492. wbportfolio/viewsets/registers.py +75 -0
  493. wbportfolio/viewsets/roles.py +44 -0
  494. wbportfolio/viewsets/signals.py +42 -0
  495. wbportfolio/viewsets/synchronization.py +25 -0
  496. wbportfolio/viewsets/transactions/__init__.py +40 -0
  497. wbportfolio/viewsets/transactions/claim.py +933 -0
  498. wbportfolio/viewsets/transactions/fees.py +190 -0
  499. wbportfolio/viewsets/transactions/mixins.py +19 -0
  500. wbportfolio/viewsets/transactions/trade_proposals.py +93 -0
  501. wbportfolio/viewsets/transactions/trades.py +395 -0
  502. wbportfolio/viewsets/transactions/transactions.py +123 -0
  503. wbportfolio-1.43.1.dist-info/METADATA +22 -0
  504. wbportfolio-1.43.1.dist-info/RECORD +506 -0
  505. wbportfolio-1.43.1.dist-info/WHEEL +5 -0
  506. wbportfolio-1.43.1.dist-info/licenses/LICENSE +4 -0
@@ -0,0 +1,248 @@
1
+ # Author: Skip Montanaro (skip@mojam.com)
2
+ # Version: 0.1
3
+ # https://github.com/smontanaro/python-bits/blob/master/sylk.py
4
+
5
+ """Read SYLK files
6
+
7
+ Caveat emptor! This module has only been tested with SYLK files generated
8
+ by AppleWorks 5.0! It almost certainly needs work to be able to process
9
+ files generated by other spreadsheets.
10
+ """
11
+
12
+ import re
13
+
14
+
15
+ class Table:
16
+ """
17
+ Table of rows used to store sylk parsed datas
18
+
19
+ rows are compound of a various amount of datas (different length)
20
+ """
21
+
22
+ def __init__(self):
23
+ self.rows = []
24
+
25
+ def __setitem__(self, xy_tuple, val):
26
+ """
27
+ Setitem method to set datas in this grid
28
+
29
+ :param tuple xy_tuple: The x,y coordinates as 2-uple
30
+ :param str val: The value to store in the grid
31
+
32
+ Handle the completion of a row to ensure the grid's row is wide enough
33
+ to set the value
34
+ """
35
+ (x, y) = xy_tuple
36
+ ox = x - 1
37
+ oy = y - 1
38
+ # Ensure the table is long enough to store the val
39
+ while len(self.rows) < y:
40
+ new_row = [" "] * x
41
+ self.rows.append(new_row)
42
+
43
+ row = self.rows[oy]
44
+ if val not in ("", " "):
45
+ # Ensure the row is large enough to store the val
46
+ if len(row) < x:
47
+ self._extend_row(row, x - len(row))
48
+ self.rows[oy][ox] = val
49
+
50
+ def _extend_row(self, row, missing):
51
+ """
52
+ Extend a row adding void values
53
+
54
+ :param list row: a list of datas
55
+ :param int missing: The number of void items to add
56
+ """
57
+ row.extend([" "] * missing)
58
+ return row
59
+
60
+ def __iter__(self):
61
+ for row in self.rows:
62
+ yield row
63
+
64
+
65
+ class SYLK:
66
+ """class to read SYLK files and dump to CSV"""
67
+
68
+ # when time began
69
+ # different computers use different core dates and store dates as offsets
70
+ # this makes SYLK inherently unportable, but we fudge that by
71
+ # using the ID field to guess at the creating platform
72
+ # note that PCs apparently can't properly decode SYLK files generated
73
+ # on Macs using Appleworks/Clarisworks because they don't take this into
74
+ # account
75
+ unixepoch = (1970, 1, 1, 0, 0, 0, 0, 0, 0)
76
+ macepoch = (1904, 1, 1, 0, 0, 0, 0, 0, 0)
77
+ # this is pure fiction...
78
+ pcepoch = (1900, 1, 1, 0, 0, 0, 0, 0, 0)
79
+
80
+ # map SYLK format strings into data types
81
+ knownformats = {
82
+ "General": "string",
83
+ "0": "int",
84
+ "0.00": "float",
85
+ "#,##0": "int",
86
+ "#,##0.00": "float",
87
+ r'"$"#,##0\ ;;\("$"#,##0\,': "float",
88
+ r'"$"#,##0.00\ ;;\("$"#,##0.00\,': "float",
89
+ "0%": "float",
90
+ "0.00%": "float",
91
+ "0.00E+00": "float",
92
+ "m/d/yy": "date",
93
+ "d-mmm-yy": "date",
94
+ "d-mmm": "date",
95
+ "mmm-yy": "date",
96
+ "h:mm AM/PM": "time",
97
+ "h:mm:ss AM/PM": "time",
98
+ "h:mm": "time",
99
+ "h:mm:ss": "time",
100
+ "hh:mm AM/PM": "time",
101
+ "hh:mm:ss AM/PM": "time",
102
+ "m/d/yy h:mm": "datetime",
103
+ "m-dd-yy": "date",
104
+ "m-dd": "date",
105
+ '"$"#,##0 ;;[Red]("$"#,##0,': "float",
106
+ '"$"#,##0.00 ;;[Red]("$"#,##0.00,': "float",
107
+ "mmm d, yyyy": "date",
108
+ "mmmm d, yyyy": "date",
109
+ "ddd, mmm d, yyyy": "date",
110
+ "dddd, mmmm d, yyyy": "date",
111
+ "d, mmmm yyyy": "date",
112
+ }
113
+
114
+ date_output = "%d/%m/%Y"
115
+
116
+ def __init__(self):
117
+ self.datebase = self.unixepoch
118
+ self.printformats = []
119
+ self.currentformat = self.currenttype = ""
120
+ self.curx = self.cury = 0
121
+ self.data = Table()
122
+ self.unknown = {}
123
+
124
+ def escape(self, s):
125
+ """
126
+ Escape a string
127
+ """
128
+ if s[0:1] == '"':
129
+ return '"' + re.sub('"', '\\"\\"', s[1:-1]) + '"'
130
+ return s
131
+
132
+ def parse(self, stream):
133
+ """
134
+ Parse the given stream
135
+ """
136
+ lines = re.sub("[\r\n]+", "\n", stream.read()).split("\n")
137
+ for line in lines:
138
+ self.parseline(line)
139
+
140
+ def stream_rows(self):
141
+ """
142
+ Stream the rows (to be used to write a csv file for example)
143
+ """
144
+ return self.data
145
+
146
+ def addunknown(self, fld, subfld):
147
+ self.unknown[fld] = self.unknown.get(fld, {})
148
+ self.unknown[fld][subfld] = 1
149
+
150
+ def writeunknown(self, stream):
151
+ if self.unknown:
152
+ stream.write("Unrecognized fields (subfields):\n")
153
+ for key in list(self.unknown.keys()):
154
+ stream.write("%s (%s)\n" % (key, repr(list(self.unknown[key].keys()))))
155
+ else:
156
+ stream.write("No unrecognized fields\n")
157
+ stream.flush()
158
+
159
+ def _id_field(self, fields):
160
+ if fields[1][:6] in ("PClari", "PApple", "P Sage"):
161
+ self.datebase = self.macepoch
162
+
163
+ def _f_field(self, fields):
164
+ for f in fields[1:]:
165
+ ftd = f[0]
166
+ val = f[1:]
167
+ if ftd == "X":
168
+ self.curx = int(val)
169
+ elif ftd == "Y":
170
+ self.cury = int(val)
171
+ elif ftd == "P":
172
+ # references print format for the next cell
173
+ self.currentformat, self.currenttype = self.printformats[int(val)]
174
+ else:
175
+ self.addunknown("F", ftd)
176
+
177
+ def _c_field(self, fields):
178
+ for f in fields[1:]:
179
+ ftd = f[0]
180
+ val = f[1:]
181
+ if ftd == "X":
182
+ self.curx = int(val)
183
+
184
+ elif ftd == "Y":
185
+ self.cury = int(val)
186
+
187
+ elif ftd == "K":
188
+ val = eval(self.escape(val))
189
+ # if type(val) == int:
190
+ # if self.currenttype == "date":
191
+ # # value is offset in days from datebase
192
+ # date = time.localtime(
193
+ # time.mktime(self.datebase) +
194
+ # float(val) * 24 * 60 * 60
195
+ # )
196
+
197
+ # val = time.strftime(self.date_output, date)
198
+ self.data[(self.curx, self.cury)] = "%s" % val
199
+
200
+ else:
201
+ self.addunknown("C", ftd)
202
+
203
+ def _p_fields(self, fields):
204
+ if fields[1][0] == "P":
205
+ # print formats imply data types?
206
+ format = fields[1][1:].replace("\\", "")
207
+ if format in self.knownformats:
208
+ self.printformats.append((format, self.knownformats[format]))
209
+ else:
210
+ # hack to guess type...
211
+ hasY = "y" in format
212
+ hasD = "d" in format
213
+ hasH = "h" in format
214
+ hasZ = "0" in format
215
+ hasP = "." in format
216
+ if (hasD or hasY) and hasH:
217
+ dtype = "datetime"
218
+ elif hasD or hasY:
219
+ dtype = "date"
220
+ elif hasH:
221
+ dtype = "time"
222
+ elif hasP and hasZ:
223
+ dtype = "float"
224
+ elif hasZ:
225
+ dtype = "int"
226
+ else:
227
+ dtype = "string"
228
+ self.printformats.append((format, dtype))
229
+ else:
230
+ self.addunknown("P", fields[1][0])
231
+
232
+ def parseline(self, line):
233
+ fields = re.split("(?i);(?=[a-z])", line)
234
+ if fields[0] == "ID":
235
+ self._id_field(fields)
236
+ if fields[0] == "F":
237
+ self._f_field(fields)
238
+ elif fields[0] == "C":
239
+ self._c_field(fields)
240
+ elif fields[0] == "P":
241
+ self._p_fields(fields)
242
+ else:
243
+ fld = fields[0]
244
+ for f in fields[1:]:
245
+ self.addunknown(fld, f)
246
+
247
+ def __iter__(self):
248
+ return self.data.__iter__()
@@ -0,0 +1,36 @@
1
+ import re
2
+ from typing import Any, Dict
3
+
4
+ from wbportfolio.models import Product, Register, Trade
5
+
6
+
7
+ def get_portfolio_id(x):
8
+ product = Product.objects.get(id=x)
9
+ portfolio = product.primary_portfolio
10
+ return portfolio.id
11
+
12
+
13
+ def parse_transaction_reference(trans_ref: str) -> tuple[str, str, bool]:
14
+ pattern = r"([0-9]{7})([0-9]{8})([CD]{1})"
15
+ transaction_id, outlet_id, credit_debit = re.findall(pattern, trans_ref)[0]
16
+ return transaction_id, outlet_id, credit_debit == "C"
17
+
18
+
19
+ def assemble_transaction_reference(data: Dict[str, Any]) -> str:
20
+ transaction_ref = data["external_identifier2"]
21
+ register_reference = data["register__register_reference"]
22
+ if data.get("TRANSFER_REGISTER", None):
23
+ register_reference = data["TRANSFER_REGISTER"]
24
+
25
+ outlet = Register.objects.get(register_reference=register_reference).outlet_reference
26
+ credit_debit = "C" if data["shares"] > 0 else "D"
27
+
28
+ return f"{int(transaction_ref):07}{int(outlet):08}{credit_debit}"
29
+
30
+
31
+ def create_transaction_reference(customer_trade: "Trade") -> str:
32
+ transaction_id = customer_trade.external_identifier2
33
+ outlet_id = customer_trade.register.clearing_reference
34
+ credit_debit = "C" if customer_trade.initial_shares > 0 else "D"
35
+
36
+ return f"{transaction_id:07}{outlet_id:08}{credit_debit}"
@@ -0,0 +1,53 @@
1
+ import codecs
2
+ import csv
3
+ import datetime
4
+ import re
5
+
6
+ from wbportfolio.import_export.utils import convert_string_to_number
7
+ from wbportfolio.models import Product
8
+
9
+
10
+ def file_name_parse(file_name):
11
+ dates = re.findall(r"([0-9]{4}-[0-9]{2}-[0-9]{2})", file_name)
12
+ isin = re.findall(r"\.([a-zA-Z0-9]*)_", file_name)
13
+
14
+ assert len(dates) == 2, "Not 2 dates found in the filename"
15
+ assert len(isin) == 1, "Not exactly 1 isin found in the filename"
16
+
17
+ return {
18
+ "isin": isin[0],
19
+ "valuation_date": datetime.datetime.strptime(dates[0], "%Y-%m-%d").date(),
20
+ "generation_date": datetime.datetime.strptime(dates[1], "%Y-%m-%d").date(),
21
+ }
22
+
23
+
24
+ def parse(import_source):
25
+ # Load file into a CSV DictReader
26
+ csv_file = import_source.file.open()
27
+ # csv_file_type = type(csv_file.read())
28
+
29
+ # # If the file is a byte string, then we need to convert it.
30
+ # if csv_file_type is bytes:
31
+ csv_file = codecs.iterdecode(csv_file, "latin1")
32
+
33
+ # # Read file into a CSV Dict Reader
34
+ csv_reader = csv.DictReader(csv_file, delimiter=",")
35
+
36
+ # # Iterate through the CSV File and parse the data into a list
37
+ data = list()
38
+
39
+ for valuation in csv_reader:
40
+ valuation_date = datetime.datetime.strptime(valuation["NAV Date"], "%Y/%m/%d").date()
41
+ product = Product.objects.get(isin=valuation["ISIN Code"])
42
+ if valuation_date.weekday() not in [5, 6] and product.currency.key == valuation["Ccy"]:
43
+ data.append(
44
+ {
45
+ "instrument": {"instrument_type": "product", "id": product.id},
46
+ "date": valuation_date.strftime("%Y-%m-%d"),
47
+ "net_value": round(convert_string_to_number(valuation["NAV per share"]), 6),
48
+ "calculated": False,
49
+ }
50
+ )
51
+
52
+ csv_file.close()
53
+ return {"data": data}
@@ -0,0 +1,54 @@
1
+ import datetime
2
+ import re
3
+ from io import BytesIO
4
+
5
+ import pandas as pd
6
+ from wbportfolio.models import Product, Trade
7
+
8
+
9
+ def parse(import_source):
10
+ df_dict = pd.read_excel(BytesIO(import_source.file.read()), engine="openpyxl", sheet_name=None)
11
+
12
+ data = list()
13
+ products = list()
14
+ max_date = datetime.date(1900, 1, 1)
15
+
16
+ for sheet_name, df in df_dict.items():
17
+ if "prices" not in sheet_name:
18
+ isin = re.findall("([A-Z]{2}[A-Z0-9]{9}[0-9]{1})", sheet_name)
19
+ product = Product.objects.get(isin=isin[0])
20
+ products.append(product.id)
21
+ df = df.rename(
22
+ columns={
23
+ "Trade Date": "transaction_date",
24
+ "Price": "price",
25
+ "Nominal": "nominal",
26
+ "Market CP": "bank",
27
+ "Way": "way",
28
+ }
29
+ )
30
+ df["transaction_date"] = pd.to_datetime(
31
+ df["transaction_date"],
32
+ )
33
+ for trade in df.to_dict("records"):
34
+ max_date = max(trade["transaction_date"].date(), max_date)
35
+
36
+ shares = trade["nominal"] if trade["way"] == "S" else trade["nominal"] * -1
37
+ shares = shares / product.share_price
38
+ portfolio = product.primary_portfolio
39
+ data.append(
40
+ {
41
+ "underlying_instrument": {"id": product.id, "instrument_type": "product"},
42
+ "currency__key": product.currency.key,
43
+ "portfolio": portfolio.id,
44
+ "transaction_date": trade["transaction_date"].strftime("%Y-%m-%d"),
45
+ "shares": shares,
46
+ "transaction_subtype": Trade.Type.REDEMPTION if shares < 0 else Trade.Type.SUBSCRIPTION,
47
+ "bank": trade["bank"],
48
+ "price": round(trade["price"] / 10, 6),
49
+ }
50
+ )
51
+ return {
52
+ "data": data,
53
+ "history": {"underlying_instruments": products, "transaction_date": max_date.strftime("%Y-%m-%d")},
54
+ }
@@ -0,0 +1,94 @@
1
+ import datetime
2
+ import logging
3
+ import re
4
+ from io import BytesIO
5
+
6
+ import numpy as np
7
+ import pandas as pd
8
+ from wbportfolio.import_export.utils import extract_exchange_ticker
9
+
10
+ logger = logging.getLogger("importers.parsers.jp_morgan.strategy")
11
+
12
+
13
+ def file_name_parse(file_name):
14
+ dates = re.findall("([0-9]{8})", file_name)
15
+
16
+ assert len(dates) == 1, "Not exactly 1 date found in the filename"
17
+
18
+ return {"valuation_date": datetime.datetime.strptime(dates[0], "%Y%m%d").date()}
19
+
20
+
21
+ def parse(import_source):
22
+ data = list()
23
+ prices = list()
24
+ df_dict = pd.read_excel(BytesIO(import_source.file.read()), engine="openpyxl", sheet_name=None)
25
+ for sheet_name, df in df_dict.items():
26
+ xx, yy = np.where(df == "Ticker")
27
+ if len(xx) == 1 and len(yy) == 1:
28
+ df_info = df.iloc[: xx[0] - 1, :].transpose()
29
+ df_info = df_info.rename(columns=df_info.iloc[0]).drop(df_info.index[0]).dropna(how="all")
30
+
31
+ strategy_ticker = df_info.loc[:, df_info.columns.str.contains("Ticker")].iloc[0, 0]
32
+ strategy_currency = df_info.loc[:, df_info.columns.str.contains("CCY")].iloc[0, 0]
33
+ valuation_date = df_info.loc[:, df_info.columns.str.contains("Date")].iloc[0, 0]
34
+ valuation_date = datetime.datetime.strptime(valuation_date, "%Y-%m-%d")
35
+ strategy_close = df_info.loc[:, df_info.columns.str.contains("Level")].iloc[0, 0]
36
+
37
+ df_positions = df.iloc[xx[0] :, yy[0] :]
38
+ df_positions = (
39
+ df_positions.rename(columns=df_positions.iloc[0]).drop(df_positions.index[0]).dropna(how="all")
40
+ )
41
+ df_positions = df_positions.rename(
42
+ columns={
43
+ df_positions.columns[df_positions.columns.str.contains("Forex")][0]: "initial_currency_fx_rate",
44
+ df_positions.columns[df_positions.columns.str.contains("Currency")][0]: "currency__key",
45
+ df_positions.columns[df_positions.columns.str.contains("Weight")][0]: "weighting",
46
+ df_positions.columns[df_positions.columns.str.contains("Level")][0]: "initial_price",
47
+ df_positions.columns[df_positions.columns.str.contains("Ticker")][
48
+ 0
49
+ ]: "underlying_instrument__ticker",
50
+ df_positions.columns[df_positions.columns.str.contains("ISIN")][0]: "underlying_instrument__isin",
51
+ df_positions.columns[df_positions.columns.str.contains("Name")][0]: "underlying_instrument__name",
52
+ }
53
+ )
54
+ for position in df_positions.to_dict("records"):
55
+ ticker, exchange = extract_exchange_ticker(position["underlying_instrument__ticker"])
56
+ if exchange:
57
+ exchange = {"bbg_exchange_codes": exchange}
58
+ data.append(
59
+ {
60
+ "underlying_instrument": {
61
+ "instrument_type": "equity",
62
+ "ticker": ticker,
63
+ "isin": position["underlying_instrument__isin"],
64
+ "name": position["underlying_instrument__name"],
65
+ "currency__key": position["currency__key"],
66
+ "exchange": exchange,
67
+ },
68
+ "portfolio": {
69
+ "instrument_type": "index",
70
+ "ticker": strategy_ticker,
71
+ "currency__key": strategy_currency,
72
+ },
73
+ "is_estimated": False,
74
+ "exchange": exchange,
75
+ "asset_type": "equity",
76
+ "currency__key": position["currency__key"],
77
+ "initial_currency_fx_rate": round(position["initial_currency_fx_rate"], 6),
78
+ "weighting": round(position["weighting"], 6),
79
+ "initial_price": round(position["initial_price"], 6),
80
+ "date": valuation_date.strftime("%Y-%m-%d"),
81
+ }
82
+ )
83
+ prices.append(
84
+ {
85
+ "instrument": {
86
+ "instrument_type": "index",
87
+ "ticker": strategy_ticker,
88
+ "currency__key": strategy_currency,
89
+ },
90
+ "date": valuation_date.strftime("%Y-%m-%d"),
91
+ "net_value": strategy_close,
92
+ }
93
+ )
94
+ return {"data": data, "prices": prices}
@@ -0,0 +1,37 @@
1
+ from io import BytesIO
2
+
3
+ import numpy as np
4
+ import pandas as pd
5
+ from wbportfolio.import_export.utils import get_file_extension
6
+ from wbportfolio.models import Product
7
+
8
+
9
+ def parse(import_source):
10
+ if get_file_extension(import_source.file) == ".xlsx":
11
+ df = pd.read_excel(BytesIO(import_source.file.read()), engine="openpyxl", sheet_name="Position").dropna(
12
+ how="all"
13
+ )
14
+ elif get_file_extension(import_source.file) == ".xls":
15
+ df = pd.read_excel(BytesIO(import_source.file.read()), sheet_name="Position").dropna(how="all")
16
+ else:
17
+ raise Exception("File not supported")
18
+
19
+ xx, yy = np.where(df == "ISIN Code")
20
+ df = df.iloc[xx[0] :, yy[0] :]
21
+ df = df.rename(columns=df.iloc[0]).drop(df.index[0]).dropna(how="all")
22
+
23
+ df["Valuation Date"] = pd.to_datetime(df["Valuation Date"])
24
+
25
+ data = list()
26
+ for valuation in df.to_dict("records"):
27
+ product = Product.objects.get(isin=valuation["ISIN Code"])
28
+ data.append(
29
+ {
30
+ "instrument": {"instrument_type": "product", "id": product.id},
31
+ "date": valuation["Valuation Date"].strftime("%Y-%m-%d"),
32
+ "net_value": round(valuation["Bid"], 6),
33
+ "calculated": False,
34
+ }
35
+ )
36
+
37
+ return {"data": data}
File without changes
@@ -0,0 +1,64 @@
1
+ import codecs
2
+ import csv
3
+ import datetime
4
+ import re
5
+
6
+ from wbportfolio.import_export.utils import convert_string_to_number
7
+ from wbportfolio.models import Product, Trade
8
+
9
+ product_mapping = {
10
+ "2304": {
11
+ "A": "CH0442615701",
12
+ "B": "CH0442770316",
13
+ },
14
+ "2316": {
15
+ "A": "CH0583763534",
16
+ "B": "CH0583763542",
17
+ },
18
+ }
19
+
20
+
21
+ def file_name_parse(file_name):
22
+ identifier = re.findall("([0-9]{4}).*", file_name)
23
+ assert len(identifier) == 1, "Not exactly one identifier was found."
24
+ return identifier[0]
25
+
26
+
27
+ def parse(import_source):
28
+ # Get the identifier from the file name to know which product group it is
29
+ identifier = file_name_parse(import_source.file.name)
30
+
31
+ # Load file into a CSV DictReader
32
+ csv_file = import_source.file.open()
33
+ csv_file_type = type(csv_file.read())
34
+
35
+ # If the file is a byte string, then we need to convert it.
36
+ if csv_file_type is bytes:
37
+ csv_file = codecs.iterdecode(csv_file, "latin1")
38
+
39
+ # Read file into a CSV Dict Reader
40
+ csv_reader = csv.DictReader(csv_file, delimiter=";")
41
+
42
+ # Iterate through the CSV File and parse the data into a list
43
+ data = list()
44
+ for customer_trade in csv_reader:
45
+ product = Product.objects.get(isin=product_mapping[identifier][customer_trade["Anteilklasse"].strip()])
46
+
47
+ transaction_date = datetime.datetime.strptime(customer_trade["Datum"], "%Y%m%d").date()
48
+ shares = round(convert_string_to_number(customer_trade["Saldo - Anzahl"]), 4)
49
+ portfolio = product.primary_portfolio
50
+ data.append(
51
+ {
52
+ "underlying_instrument": {"id": product.id, "instrument_type": "product"},
53
+ "portfolio": portfolio.id,
54
+ "currency__key": product.currency.key,
55
+ "transaction_date": transaction_date.strftime("%Y-%m-%d"),
56
+ "value_date": transaction_date.strftime("%Y-%m-%d"),
57
+ "shares": shares,
58
+ "bank": "Tellco Trade",
59
+ "transaction_subtype": Trade.Type.REDEMPTION if shares < 0 else Trade.Type.SUBSCRIPTION,
60
+ "price": round(convert_string_to_number(customer_trade["NIW"]), 4),
61
+ }
62
+ )
63
+ csv_file.close()
64
+ return {"data": data}
@@ -0,0 +1,86 @@
1
+ import codecs
2
+ import csv
3
+ import datetime
4
+
5
+ import pandas as pd
6
+ from wbcore.contrib.currency.models import Currency
7
+ from wbportfolio.import_export.utils import convert_string_to_number
8
+ from wbportfolio.models import ProductGroup
9
+
10
+
11
+ def parse(import_source):
12
+ # Load file into a CSV DictReader and convert the encoding to latin1 due to hyphonation
13
+ csv_file = import_source.file.open()
14
+ csv_file = codecs.iterdecode(csv_file, "latin1")
15
+
16
+ # Read file into a CSV Dict Reader
17
+ csv_reader = csv.DictReader(csv_file, delimiter=";")
18
+
19
+ # Iterate through the CSV File and parse the data into a list
20
+ data = list()
21
+ for basket in csv_reader:
22
+ if basket["Assetart"] == "CPON" or (
23
+ basket["Assetart"] == "TRES" and "Sichtguthaben" not in basket["Assetbezeichnung"]
24
+ ):
25
+ continue
26
+ product_group = ProductGroup.objects.get(identifier=basket["Fonds-Nr."].strip())
27
+ valuation_date = datetime.datetime.strptime(basket["Datum"], "%Y%m%d")
28
+
29
+ currency_key = basket["Währung"]
30
+ currency = Currency.objects.get(key=currency_key)
31
+ group_currency = Currency.objects.get(key=basket["Assetwährung"])
32
+
33
+ if basket["Assetart"] == "TRES":
34
+ initial_currency_fx_rate = convert_string_to_number(basket["Wertpapierkurs"])
35
+
36
+ ticker = "CASH"
37
+ title = currency.title
38
+ initial_price = 1
39
+ underlying_instrument = {
40
+ "instrument_type": "cash",
41
+ "ticker": ticker,
42
+ "name": title,
43
+ "currency__key": currency.key,
44
+ }
45
+ elif basket["Assetart"] == "VMOB":
46
+ instrument_type = "equity"
47
+ if "STRUKT" in basket.get("TL2", ""):
48
+ instrument_type = "product"
49
+ initial_currency_fx_rate = float(currency.convert(valuation_date, group_currency))
50
+ initial_price = basket["Wertpapierkurs"]
51
+
52
+ exchange = f'X{basket["Bloomberg Code"]}' if basket["Bloomberg Code"] else None
53
+ underlying_instrument = {
54
+ "instrument_type": instrument_type,
55
+ "isin": basket["ISIN"],
56
+ "exchange": {"mic_code": exchange},
57
+ "name": basket["Assetbezeichnung"],
58
+ "currency__key": currency.key,
59
+ }
60
+
61
+ initial_shares = basket["Stk / Nominal"]
62
+
63
+ data.append(
64
+ {
65
+ "underlying_instrument": underlying_instrument,
66
+ "exchange": underlying_instrument.get("exchange", None),
67
+ "portfolio": {
68
+ "instrument_type": "product_group",
69
+ "id": product_group.id,
70
+ },
71
+ "is_estimated": False,
72
+ "currency__key": currency_key,
73
+ "date": valuation_date.strftime("%Y-%m-%d"),
74
+ "asset_valuation_date": valuation_date.strftime("%Y-%m-%d"),
75
+ "initial_price": round(convert_string_to_number(initial_price), 4),
76
+ "initial_currency_fx_rate": initial_currency_fx_rate,
77
+ "initial_shares": round(convert_string_to_number(initial_shares), 4),
78
+ }
79
+ )
80
+ csv_file.close()
81
+
82
+ df = pd.DataFrame(data) # quick Hack to compute weighting on import
83
+ df["weighting"] = df.initial_currency_fx_rate * df.initial_price * df.initial_shares
84
+ df["weighting"] = df.weighting / df.weighting.sum()
85
+
86
+ return {"data": df.to_dict("records")}