wbportfolio 1.52.0__py2.py3-none-any.whl → 1.59.4__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wbportfolio might be problematic. Click here for more details.

Files changed (273) hide show
  1. wbportfolio/admin/__init__.py +3 -1
  2. wbportfolio/admin/indexes.py +1 -1
  3. wbportfolio/admin/orders/__init__.py +2 -0
  4. wbportfolio/admin/orders/order_proposals.py +16 -0
  5. wbportfolio/admin/orders/orders.py +32 -0
  6. wbportfolio/admin/portfolio.py +11 -5
  7. wbportfolio/admin/product_groups.py +1 -1
  8. wbportfolio/admin/products.py +2 -1
  9. wbportfolio/admin/{transactions/rebalancing.py → rebalancing.py} +1 -1
  10. wbportfolio/admin/transactions/__init__.py +0 -2
  11. wbportfolio/admin/transactions/dividends.py +40 -4
  12. wbportfolio/admin/transactions/fees.py +24 -14
  13. wbportfolio/admin/transactions/trades.py +34 -27
  14. wbportfolio/analysis/claims.py +5 -6
  15. wbportfolio/api_clients/ubs.py +162 -0
  16. wbportfolio/constants.py +1 -0
  17. wbportfolio/contrib/company_portfolio/configs/display.py +22 -10
  18. wbportfolio/contrib/company_portfolio/configs/previews.py +3 -3
  19. wbportfolio/contrib/company_portfolio/filters.py +10 -10
  20. wbportfolio/contrib/company_portfolio/models.py +69 -39
  21. wbportfolio/contrib/company_portfolio/scripts.py +7 -2
  22. wbportfolio/contrib/company_portfolio/serializers.py +32 -22
  23. wbportfolio/contrib/company_portfolio/tasks.py +12 -1
  24. wbportfolio/contrib/company_portfolio/tests/conftest.py +2 -2
  25. wbportfolio/defaults/fees/default.py +7 -15
  26. wbportfolio/factories/__init__.py +2 -2
  27. wbportfolio/factories/assets.py +1 -1
  28. wbportfolio/factories/dividends.py +8 -3
  29. wbportfolio/factories/fees.py +8 -4
  30. wbportfolio/factories/orders/__init__.py +2 -0
  31. wbportfolio/factories/orders/order_proposals.py +21 -0
  32. wbportfolio/factories/orders/orders.py +34 -0
  33. wbportfolio/factories/portfolios.py +2 -1
  34. wbportfolio/factories/product_groups.py +3 -3
  35. wbportfolio/factories/products.py +3 -3
  36. wbportfolio/factories/rebalancing.py +1 -1
  37. wbportfolio/factories/trades.py +12 -16
  38. wbportfolio/filters/assets.py +18 -4
  39. wbportfolio/filters/orders/__init__.py +2 -0
  40. wbportfolio/filters/orders/order_proposals.py +55 -0
  41. wbportfolio/filters/orders/orders.py +11 -0
  42. wbportfolio/filters/portfolios.py +38 -1
  43. wbportfolio/filters/positions.py +0 -1
  44. wbportfolio/filters/transactions/__init__.py +1 -2
  45. wbportfolio/filters/transactions/fees.py +5 -12
  46. wbportfolio/filters/transactions/trades.py +16 -8
  47. wbportfolio/filters/transactions/utils.py +42 -0
  48. wbportfolio/import_export/backends/ubs/__init__.py +1 -0
  49. wbportfolio/import_export/backends/ubs/asset_position.py +6 -7
  50. wbportfolio/import_export/backends/ubs/fees.py +10 -20
  51. wbportfolio/import_export/backends/ubs/instrument_price.py +6 -6
  52. wbportfolio/import_export/backends/ubs/trade.py +48 -0
  53. wbportfolio/import_export/backends/utils.py +0 -17
  54. wbportfolio/import_export/handlers/asset_position.py +22 -10
  55. wbportfolio/import_export/handlers/dividend.py +8 -8
  56. wbportfolio/import_export/handlers/fees.py +13 -23
  57. wbportfolio/import_export/handlers/orders.py +71 -0
  58. wbportfolio/import_export/handlers/trade.py +53 -77
  59. wbportfolio/import_export/parsers/default_mapping.py +1 -1
  60. wbportfolio/import_export/parsers/jpmorgan/customer_trade.py +2 -2
  61. wbportfolio/import_export/parsers/jpmorgan/fees.py +4 -4
  62. wbportfolio/import_export/parsers/jpmorgan/strategy.py +59 -85
  63. wbportfolio/import_export/parsers/jpmorgan/valuation.py +2 -2
  64. wbportfolio/import_export/parsers/leonteq/customer_trade.py +5 -5
  65. wbportfolio/import_export/parsers/leonteq/fees.py +11 -7
  66. wbportfolio/import_export/parsers/leonteq/trade.py +2 -6
  67. wbportfolio/import_export/parsers/natixis/d1_fees.py +2 -2
  68. wbportfolio/import_export/parsers/natixis/dividend.py +4 -9
  69. wbportfolio/import_export/parsers/natixis/equity.py +22 -4
  70. wbportfolio/import_export/parsers/natixis/fees.py +7 -9
  71. wbportfolio/import_export/parsers/natixis/utils.py +13 -19
  72. wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +1 -1
  73. wbportfolio/import_export/parsers/sg_lux/equity.py +10 -10
  74. wbportfolio/import_export/parsers/sg_lux/fees.py +2 -2
  75. wbportfolio/import_export/parsers/sg_lux/perf_fees.py +2 -2
  76. wbportfolio/import_export/parsers/sg_lux/sylk.py +12 -11
  77. wbportfolio/import_export/parsers/sg_lux/utils.py +2 -2
  78. wbportfolio/import_export/parsers/sg_lux/valuation.py +4 -2
  79. wbportfolio/import_export/parsers/societe_generale/strategy.py +5 -5
  80. wbportfolio/import_export/parsers/tellco/customer_trade.py +2 -1
  81. wbportfolio/import_export/parsers/tellco/valuation.py +4 -3
  82. wbportfolio/import_export/parsers/ubs/api/fees.py +2 -2
  83. wbportfolio/import_export/parsers/ubs/api/trade.py +39 -0
  84. wbportfolio/import_export/parsers/ubs/customer_trade.py +7 -5
  85. wbportfolio/import_export/parsers/ubs/equity.py +3 -2
  86. wbportfolio/import_export/parsers/ubs/valuation.py +2 -1
  87. wbportfolio/import_export/parsers/vontobel/customer_trade.py +2 -3
  88. wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -1
  89. wbportfolio/import_export/parsers/vontobel/management_fees.py +12 -20
  90. wbportfolio/import_export/parsers/vontobel/performance_fees.py +5 -8
  91. wbportfolio/import_export/parsers/vontobel/valuation_api.py +4 -1
  92. wbportfolio/import_export/resources/trades.py +3 -3
  93. wbportfolio/import_export/utils.py +3 -1
  94. wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +2 -2
  95. wbportfolio/metric/backends/base.py +2 -2
  96. wbportfolio/migrations/0059_fees_unique_fees.py +1 -1
  97. wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +622 -0
  98. wbportfolio/migrations/0078_trade_drift_factor.py +26 -0
  99. wbportfolio/migrations/0079_alter_trade_drift_factor.py +19 -0
  100. wbportfolio/migrations/0080_alter_trade_drift_factor_alter_trade_weighting.py +19 -0
  101. wbportfolio/migrations/0081_alter_trade_drift_factor.py +19 -0
  102. wbportfolio/migrations/0082_remove_tradeproposal_creator_and_more.py +93 -0
  103. wbportfolio/migrations/0083_order_alter_trade_options_and_more.py +181 -0
  104. wbportfolio/migrations/0084_orderproposal_min_order_value.py +25 -0
  105. wbportfolio/migrations/0085_order_desired_target_weight.py +26 -0
  106. wbportfolio/migrations/0086_orderproposal_total_cash_weight.py +19 -0
  107. wbportfolio/migrations/0087_product_order_routing_custodian_adapter.py +94 -0
  108. wbportfolio/migrations/0088_orderproposal_total_effective_portfolio_contribution.py +19 -0
  109. wbportfolio/migrations/0089_orderproposal_min_weighting.py +71 -0
  110. wbportfolio/migrations/0090_dividendtransaction_price_fx_portfolio_and_more.py +44 -0
  111. wbportfolio/migrations/0091_remove_order_execution_confirmed_and_more.py +32 -0
  112. wbportfolio/migrations/0092_order_quantization_error_alter_orderproposal_status.py +49 -0
  113. wbportfolio/migrations/0093_remove_portfolioportfoliothroughmodel_unique_primary_and_more.py +35 -0
  114. wbportfolio/models/__init__.py +2 -0
  115. wbportfolio/models/adjustments.py +1 -1
  116. wbportfolio/models/asset.py +28 -170
  117. wbportfolio/models/builder.py +323 -0
  118. wbportfolio/models/custodians.py +3 -3
  119. wbportfolio/models/exceptions.py +1 -1
  120. wbportfolio/models/graphs/portfolio.py +1 -1
  121. wbportfolio/models/graphs/utils.py +11 -11
  122. wbportfolio/models/mixins/instruments.py +7 -0
  123. wbportfolio/models/mixins/liquidity_stress_test.py +4 -4
  124. wbportfolio/models/orders/__init__.py +2 -0
  125. wbportfolio/models/orders/order_proposals.py +1414 -0
  126. wbportfolio/models/orders/orders.py +410 -0
  127. wbportfolio/models/portfolio.py +311 -289
  128. wbportfolio/models/portfolio_relationship.py +6 -0
  129. wbportfolio/models/products.py +12 -0
  130. wbportfolio/models/{transactions/rebalancing.py → rebalancing.py} +40 -27
  131. wbportfolio/models/roles.py +4 -10
  132. wbportfolio/models/transactions/__init__.py +0 -4
  133. wbportfolio/models/transactions/claim.py +7 -6
  134. wbportfolio/models/transactions/dividends.py +42 -5
  135. wbportfolio/models/transactions/fees.py +55 -22
  136. wbportfolio/models/transactions/trades.py +121 -442
  137. wbportfolio/models/transactions/transactions.py +78 -158
  138. wbportfolio/models/utils.py +100 -1
  139. wbportfolio/order_routing/__init__.py +35 -0
  140. wbportfolio/order_routing/adapters/__init__.py +65 -0
  141. wbportfolio/order_routing/adapters/ubs.py +195 -0
  142. wbportfolio/order_routing/router.py +33 -0
  143. wbportfolio/order_routing/tests/__init__.py +0 -0
  144. wbportfolio/order_routing/tests/test_router.py +110 -0
  145. wbportfolio/permissions.py +7 -0
  146. wbportfolio/pms/analytics/portfolio.py +17 -9
  147. wbportfolio/pms/analytics/utils.py +9 -0
  148. wbportfolio/pms/trading/__init__.py +0 -1
  149. wbportfolio/pms/trading/optimizer.py +61 -0
  150. wbportfolio/pms/typing.py +198 -63
  151. wbportfolio/rebalancing/base.py +12 -1
  152. wbportfolio/rebalancing/decorators.py +1 -1
  153. wbportfolio/rebalancing/models/composite.py +4 -8
  154. wbportfolio/rebalancing/models/equally_weighted.py +13 -11
  155. wbportfolio/rebalancing/models/market_capitalization_weighted.py +21 -14
  156. wbportfolio/rebalancing/models/model_portfolio.py +14 -18
  157. wbportfolio/risk_management/backends/__init__.py +1 -0
  158. wbportfolio/risk_management/backends/controversy_portfolio.py +2 -2
  159. wbportfolio/risk_management/backends/esg_aggregation_portfolio.py +64 -0
  160. wbportfolio/risk_management/backends/exposure_portfolio.py +4 -4
  161. wbportfolio/risk_management/backends/instrument_list_portfolio.py +3 -3
  162. wbportfolio/risk_management/tests/test_esg_aggregation_portfolio.py +49 -0
  163. wbportfolio/risk_management/tests/test_exposure_portfolio.py +1 -1
  164. wbportfolio/risk_management/tests/test_stop_loss_instrument.py +2 -2
  165. wbportfolio/risk_management/tests/test_stop_loss_portfolio.py +1 -1
  166. wbportfolio/serializers/__init__.py +1 -0
  167. wbportfolio/serializers/orders/__init__.py +2 -0
  168. wbportfolio/serializers/orders/order_proposals.py +115 -0
  169. wbportfolio/serializers/orders/orders.py +283 -0
  170. wbportfolio/serializers/portfolios.py +7 -7
  171. wbportfolio/serializers/positions.py +2 -2
  172. wbportfolio/serializers/rebalancing.py +1 -1
  173. wbportfolio/serializers/signals.py +9 -12
  174. wbportfolio/serializers/transactions/__init__.py +1 -10
  175. wbportfolio/serializers/transactions/claim.py +2 -2
  176. wbportfolio/serializers/transactions/dividends.py +37 -9
  177. wbportfolio/serializers/transactions/fees.py +39 -10
  178. wbportfolio/serializers/transactions/trades.py +55 -157
  179. wbportfolio/tasks.py +43 -5
  180. wbportfolio/tests/analysis/__init__.py +0 -0
  181. wbportfolio/tests/analysis/test_claims.py +85 -0
  182. wbportfolio/tests/conftest.py +12 -12
  183. wbportfolio/tests/models/orders/__init__.py +0 -0
  184. wbportfolio/tests/models/orders/test_order_proposals.py +1046 -0
  185. wbportfolio/tests/models/test_assets.py +7 -3
  186. wbportfolio/tests/models/test_imports.py +9 -13
  187. wbportfolio/tests/models/test_portfolios.py +102 -95
  188. wbportfolio/tests/models/test_products.py +11 -0
  189. wbportfolio/tests/models/test_splits.py +1 -6
  190. wbportfolio/tests/models/test_utils.py +140 -0
  191. wbportfolio/tests/models/transactions/test_fees.py +7 -13
  192. wbportfolio/tests/models/transactions/test_rebalancing.py +5 -5
  193. wbportfolio/tests/models/transactions/test_trades.py +0 -20
  194. wbportfolio/tests/pms/test_analytics.py +22 -3
  195. wbportfolio/tests/rebalancing/test_models.py +51 -57
  196. wbportfolio/tests/signals.py +10 -20
  197. wbportfolio/tests/tests.py +3 -1
  198. wbportfolio/tests/viewsets/test_products.py +1 -0
  199. wbportfolio/urls.py +10 -13
  200. wbportfolio/viewsets/__init__.py +9 -4
  201. wbportfolio/viewsets/assets.py +3 -204
  202. wbportfolio/viewsets/charts/__init__.py +6 -1
  203. wbportfolio/viewsets/charts/assets.py +344 -154
  204. wbportfolio/viewsets/configs/buttons/__init__.py +2 -2
  205. wbportfolio/viewsets/configs/buttons/assets.py +1 -1
  206. wbportfolio/viewsets/configs/buttons/mixins.py +4 -4
  207. wbportfolio/viewsets/configs/buttons/portfolios.py +45 -1
  208. wbportfolio/viewsets/configs/buttons/products.py +32 -2
  209. wbportfolio/viewsets/configs/display/__init__.py +2 -5
  210. wbportfolio/viewsets/configs/display/assets.py +6 -19
  211. wbportfolio/viewsets/configs/display/fees.py +3 -3
  212. wbportfolio/viewsets/configs/display/portfolios.py +5 -5
  213. wbportfolio/viewsets/configs/display/products.py +1 -1
  214. wbportfolio/viewsets/configs/display/rebalancing.py +2 -2
  215. wbportfolio/viewsets/configs/display/reconciliations.py +4 -4
  216. wbportfolio/viewsets/configs/display/trades.py +1 -189
  217. wbportfolio/viewsets/configs/endpoints/__init__.py +3 -7
  218. wbportfolio/viewsets/configs/endpoints/fees.py +2 -2
  219. wbportfolio/viewsets/configs/endpoints/trades.py +0 -41
  220. wbportfolio/viewsets/configs/menu/__init__.py +1 -1
  221. wbportfolio/viewsets/configs/menu/orders.py +11 -0
  222. wbportfolio/viewsets/configs/titles/__init__.py +2 -3
  223. wbportfolio/viewsets/configs/titles/fees.py +4 -8
  224. wbportfolio/viewsets/esg.py +3 -5
  225. wbportfolio/viewsets/mixins.py +5 -1
  226. wbportfolio/viewsets/orders/__init__.py +6 -0
  227. wbportfolio/viewsets/orders/configs/__init__.py +4 -0
  228. wbportfolio/viewsets/orders/configs/buttons/__init__.py +2 -0
  229. wbportfolio/viewsets/orders/configs/buttons/order_proposals.py +188 -0
  230. wbportfolio/viewsets/orders/configs/buttons/orders.py +113 -0
  231. wbportfolio/viewsets/orders/configs/displays/__init__.py +2 -0
  232. wbportfolio/viewsets/orders/configs/displays/order_proposals.py +157 -0
  233. wbportfolio/viewsets/orders/configs/displays/orders.py +232 -0
  234. wbportfolio/viewsets/orders/configs/endpoints/__init__.py +2 -0
  235. wbportfolio/viewsets/orders/configs/endpoints/order_proposals.py +21 -0
  236. wbportfolio/viewsets/orders/configs/endpoints/orders.py +28 -0
  237. wbportfolio/viewsets/orders/configs/titles/__init__.py +0 -0
  238. wbportfolio/viewsets/orders/configs/titles/orders.py +0 -0
  239. wbportfolio/viewsets/orders/order_proposals.py +252 -0
  240. wbportfolio/viewsets/orders/orders.py +277 -0
  241. wbportfolio/viewsets/portfolios.py +36 -12
  242. wbportfolio/viewsets/positions.py +3 -2
  243. wbportfolio/viewsets/products.py +6 -6
  244. wbportfolio/viewsets/{transactions/rebalancing.py → rebalancing.py} +2 -2
  245. wbportfolio/viewsets/transactions/__init__.py +3 -14
  246. wbportfolio/viewsets/transactions/fees.py +22 -22
  247. wbportfolio/viewsets/transactions/trades.py +1 -180
  248. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/METADATA +3 -1
  249. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/RECORD +252 -203
  250. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/WHEEL +1 -1
  251. wbportfolio/admin/transactions/transactions.py +0 -38
  252. wbportfolio/factories/transactions.py +0 -22
  253. wbportfolio/fdm/tasks.py +0 -13
  254. wbportfolio/filters/transactions/transactions.py +0 -99
  255. wbportfolio/models/transactions/expiry.py +0 -7
  256. wbportfolio/models/transactions/trade_proposals.py +0 -704
  257. wbportfolio/pms/trading/handler.py +0 -161
  258. wbportfolio/serializers/transactions/expiry.py +0 -18
  259. wbportfolio/serializers/transactions/trade_proposals.py +0 -76
  260. wbportfolio/serializers/transactions/transactions.py +0 -85
  261. wbportfolio/tests/models/transactions/test_trade_proposals.py +0 -410
  262. wbportfolio/viewsets/configs/buttons/trade_proposals.py +0 -66
  263. wbportfolio/viewsets/configs/display/trade_proposals.py +0 -100
  264. wbportfolio/viewsets/configs/display/transactions.py +0 -55
  265. wbportfolio/viewsets/configs/endpoints/trade_proposals.py +0 -18
  266. wbportfolio/viewsets/configs/endpoints/transactions.py +0 -14
  267. wbportfolio/viewsets/configs/menu/transactions.py +0 -9
  268. wbportfolio/viewsets/configs/titles/transactions.py +0 -9
  269. wbportfolio/viewsets/signals.py +0 -43
  270. wbportfolio/viewsets/transactions/trade_proposals.py +0 -139
  271. wbportfolio/viewsets/transactions/transactions.py +0 -122
  272. /wbportfolio/{fdm → api_clients}/__init__.py +0 -0
  273. {wbportfolio-1.52.0.dist-info → wbportfolio-1.59.4.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.0.14 on 2025-07-10 09:00
2
+
3
+ from decimal import Decimal
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wbportfolio', '0079_alter_trade_drift_factor'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='assetposition',
16
+ name='weighting',
17
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'), help_text='The Weight of the Asset on the price date of the Asset.', max_digits=9, verbose_name='Weight'),
18
+ ),
19
+ ]
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.0.14 on 2025-07-16 12:39
2
+
3
+ from decimal import Decimal
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wbportfolio', '0080_alter_trade_drift_factor_alter_trade_weighting'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AlterField(
15
+ model_name='trade',
16
+ name='drift_factor',
17
+ field=models.DecimalField(decimal_places=16, default=Decimal('1'), help_text='Drift factor to be applied to the previous portfolio weight to get the actual effective weight including daily return', max_digits=19, verbose_name='Drift Factor'),
18
+ ),
19
+ ]
@@ -0,0 +1,93 @@
1
+ # Generated by Django 5.0.14 on 2025-07-17 14:53
2
+
3
+ import django.db.models.deletion
4
+ import django_fsm
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('currency', '0001_initial'),
12
+ ('io', '0008_importsource_resource_kwargs'),
13
+ ('wbfdm', '0031_exchange_apply_round_lot_size_and_more'),
14
+ ('directory', '0013_alter_clientmanagerrelationship_options'),
15
+ ('wbportfolio', '0081_alter_trade_drift_factor'),
16
+ ]
17
+
18
+ operations = [
19
+ migrations.RenameModel(
20
+ old_name='TradeProposal',
21
+ new_name='OrderProposal',
22
+ ),
23
+ migrations.AlterField(
24
+ model_name='orderproposal',
25
+ name='creator',
26
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT,
27
+ related_name='order_proposals', to='directory.person', verbose_name='Owner'),
28
+ ),
29
+ migrations.AlterField(
30
+ model_name='orderproposal',
31
+ name='portfolio',
32
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='order_proposals',
33
+ to='wbportfolio.portfolio', verbose_name='Portfolio'),
34
+ ),
35
+ migrations.AlterField(
36
+ model_name='orderproposal',
37
+ name='rebalancing_model',
38
+ field=models.ForeignKey(blank=True, help_text='Rebalancing Model that generates the target portfolio',
39
+ null=True, on_delete=django.db.models.deletion.SET_NULL,
40
+ related_name='order_proposals', to='wbportfolio.rebalancingmodel',
41
+ verbose_name='Rebalancing Model'),
42
+ ),
43
+ migrations.AlterModelOptions(
44
+ name='orderproposal',
45
+ options={'verbose_name': 'Order Proposal', 'verbose_name_plural': 'Order Proposals'},
46
+ ),
47
+ migrations.RemoveConstraint(
48
+ model_name='orderproposal',
49
+ name='unique_trade_proposal',
50
+ ),
51
+ migrations.RemoveConstraint(
52
+ model_name='trade',
53
+ name='unique_manual_trade',
54
+ ),
55
+ migrations.RenameField(
56
+ model_name='rebalancer',
57
+ old_name='approve_trade_proposal_automatically',
58
+ new_name='approve_order_proposal_automatically',
59
+ ),
60
+ migrations.RenameField(
61
+ model_name='trade',
62
+ old_name='trade_proposal',
63
+ new_name='order_proposal',
64
+ ),
65
+ migrations.AlterField(
66
+ model_name='portfolio',
67
+ name='is_manageable',
68
+ field=models.BooleanField(default=False,
69
+ help_text='True if the portfolio can be manually modified (e.g. Order Proposal be submitted or total weight recomputed)'),
70
+ ),
71
+ migrations.AddConstraint(
72
+ model_name='orderproposal',
73
+ constraint=models.UniqueConstraint(fields=('portfolio', 'trade_date'), name='unique_order_proposal'),
74
+ ),
75
+ migrations.AddConstraint(
76
+ model_name='trade',
77
+ constraint=models.UniqueConstraint(condition=models.Q(('order_proposal__isnull', False)),
78
+ fields=('portfolio', 'transaction_date', 'underlying_instrument'),
79
+ name='unique_manual_trade'),
80
+ ),
81
+ migrations.AlterField(
82
+ model_name='rebalancer',
83
+ name='approve_order_proposal_automatically',
84
+ field=models.BooleanField(default=False, verbose_name='Apply Order Proposal Automatically'),
85
+ ),
86
+ migrations.AlterField(
87
+ model_name='trade',
88
+ name='order_proposal',
89
+ field=models.ForeignKey(blank=True, help_text='The Order Proposal this trade is coming from', null=True,
90
+ on_delete=django.db.models.deletion.CASCADE, related_name='trades',
91
+ to='wbportfolio.orderproposal'),
92
+ ),
93
+ ]
@@ -0,0 +1,181 @@
1
+ # Generated by Django 5.0.14 on 2025-07-18 06:37
2
+
3
+ import django.db.models.deletion
4
+ import django.db.models.expressions
5
+ import django_fsm
6
+ from decimal import Decimal
7
+ from django.db import migrations, models
8
+ from tqdm import tqdm
9
+ def migrate_order(apps, schema_editor):
10
+ Order = apps.get_model("wbportfolio", "Order")
11
+ Trade = apps.get_model("wbportfolio", "Trade")
12
+ objs = []
13
+ qs = Trade.objects.filter(order_proposal__isnull=False).select_related("order_proposal")
14
+ for order in tqdm(qs, total=qs.count()):
15
+ objs.append(Order(
16
+ order=order.order,
17
+ value_date=order.order_proposal.trade_date,
18
+ currency_fx_rate=order.currency_fx_rate,
19
+ price=order.price,
20
+ price_gross=order.price_gross,
21
+ fees=order.fees,
22
+ comment=order.comment,
23
+ created=order.created,
24
+ updated=order.updated,
25
+ order_type=order.transaction_subtype,
26
+ status=order.status,
27
+ shares=order.shares,
28
+ weighting=order.weighting,
29
+ drift_factor=order.drift_factor,
30
+ import_source=order.import_source,
31
+ portfolio=order.portfolio,
32
+ underlying_instrument=order.underlying_instrument,
33
+ order_proposal=order.order_proposal,
34
+ ))
35
+ Order.objects.bulk_create(objs)
36
+ qs.delete()
37
+
38
+ class Migration(migrations.Migration):
39
+
40
+ dependencies = [
41
+ ('io', '0008_importsource_resource_kwargs'),
42
+ ('wbfdm', '0031_exchange_apply_round_lot_size_and_more'),
43
+ ('wbportfolio', '0082_remove_tradeproposal_creator_and_more'),
44
+ ]
45
+
46
+ operations = [
47
+ migrations.CreateModel(
48
+ name='Order',
49
+ fields=[
50
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
51
+ ('order', models.PositiveIntegerField(db_index=True, editable=False, verbose_name='order')),
52
+ ('value_date', models.DateField(help_text='The date that this transaction was valuated/paid.', verbose_name='Value Date')),
53
+ ('currency_fx_rate', models.DecimalField(decimal_places=8, default=Decimal('1'), max_digits=14, verbose_name='FOREX rate')),
54
+ ('price', models.DecimalField(decimal_places=4, help_text='The price per share.', max_digits=16, verbose_name='Price')),
55
+ ('price_gross', models.DecimalField(decimal_places=4, help_text='The gross price per share.', max_digits=16, verbose_name='Gross Price')),
56
+ ('fees', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('price_gross'), '-', models.F('price')), output_field=models.DecimalField(decimal_places=4, max_digits=20))),
57
+ ('total_value_gross', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('price_gross'), '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20))),
58
+ ('total_value', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('price'), '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20))),
59
+ ('total_value_fx_portfolio', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')), '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20))),
60
+ ('total_value_gross_fx_portfolio', models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price_gross')), '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20))),
61
+ ('comment', models.TextField(blank=True, default='', verbose_name='Comment')),
62
+ ('created', models.DateTimeField(auto_now_add=True)),
63
+ ('updated', models.DateTimeField(auto_now=True)),
64
+ ('order_type', models.CharField(choices=[('REBALANCE', 'Rebalance'), ('DECREASE', 'Decrease'), ('INCREASE', 'Increase'), ('BUY', 'Buy'), ('SELL', 'Sell'), ('NO_CHANGE', 'No Change')], default='BUY', max_length=32, verbose_name='Trade Type')),
65
+ ('status', django_fsm.FSMField(choices=[('DRAFT', 'Draft'), ('SUBMIT', 'Submit'), ('EXECUTED', 'Executed'), ('CONFIRMED', 'Confirmed'), ('FAILED', 'Failed')], default='CONFIRMED', max_length=50, verbose_name='Status')),
66
+ ('shares', models.DecimalField(decimal_places=4, default=Decimal('0.0'), help_text='The number of shares that were traded.', max_digits=15, verbose_name='Shares')),
67
+ ('weighting', models.DecimalField(decimal_places=8, default=Decimal('0'), help_text='The weight to be multiplied against the target', max_digits=9, verbose_name='Weight')),
68
+ ('drift_factor', models.DecimalField(decimal_places=16, default=Decimal('1'), help_text='Drift factor to be applied to the previous portfolio weight to get the actual effective weight including daily return', max_digits=19, verbose_name='Drift Factor')),
69
+ ],
70
+ options={
71
+ 'verbose_name': 'Order',
72
+ 'verbose_name_plural': 'Orders',
73
+ 'ordering': ('order',),
74
+ 'abstract': False,
75
+ },
76
+ ),
77
+ migrations.AddField(
78
+ model_name='order',
79
+ name='order_proposal',
80
+ field=models.ForeignKey(help_text='The Order Proposal this trade is coming from',
81
+ on_delete=django.db.models.deletion.CASCADE, related_name='orders',
82
+ to='wbportfolio.orderproposal'),
83
+ ),
84
+ migrations.AddField(
85
+ model_name='order',
86
+ name='import_source',
87
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
88
+ to='io.importsource'),
89
+ ),
90
+ migrations.AddField(
91
+ model_name='order',
92
+ name='portfolio',
93
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
94
+ to='wbportfolio.portfolio', verbose_name='Portfolio'),
95
+ ),
96
+ migrations.AddField(
97
+ model_name='order',
98
+ name='underlying_instrument',
99
+ field=models.ForeignKey(help_text='The instrument that is this transaction.',
100
+ limit_choices_to=models.Q(('children__isnull', True)),
101
+ on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
102
+ to='wbfdm.instrument', verbose_name='Underlying Instrument'),
103
+ ),
104
+ migrations.RunSQL(
105
+ sql="SET CONSTRAINTS ALL IMMEDIATE;",
106
+ ),
107
+ migrations.RunPython(migrate_order),
108
+ migrations.RunSQL(
109
+ sql="SET CONSTRAINTS ALL DEFERRED;",
110
+ ),
111
+ migrations.AlterModelOptions(
112
+ name='trade',
113
+ options={'verbose_name': 'Trade', 'verbose_name_plural': 'Trades'},
114
+ ),
115
+ migrations.RemoveConstraint(
116
+ model_name='trade',
117
+ name='unique_manual_trade',
118
+ ),
119
+ migrations.RemoveField(
120
+ model_name='trade',
121
+ name='drift_factor',
122
+ ),
123
+ migrations.RemoveField(
124
+ model_name='trade',
125
+ name='order',
126
+ ),
127
+ migrations.RemoveField(
128
+ model_name='trade',
129
+ name='order_proposal',
130
+ ),
131
+ migrations.AddIndex(
132
+ model_name='order',
133
+ index=models.Index(fields=['underlying_instrument', 'value_date'], name='wbportfolio_underly_051048_idx'),
134
+ ),
135
+ migrations.AddIndex(
136
+ model_name='order',
137
+ index=models.Index(fields=['portfolio', 'underlying_instrument', 'value_date'], name='wbportfolio_portfol_26d2a7_idx'),
138
+ ),
139
+ migrations.AddIndex(
140
+ model_name='order',
141
+ index=models.Index(fields=['order_proposal', 'underlying_instrument'], name='wbportfolio_order_p_637d28_idx'),
142
+ ),
143
+ migrations.AddConstraint(
144
+ model_name='order',
145
+ constraint=models.UniqueConstraint(fields=('order_proposal', 'underlying_instrument'), name='unique_order'),
146
+ ),
147
+ migrations.AlterField(
148
+ model_name='orderproposal',
149
+ name='comment',
150
+ field=models.TextField(blank=True, default='', verbose_name='Order Comment'),
151
+ ),
152
+ migrations.RemoveField(
153
+ model_name='order',
154
+ name='drift_factor',
155
+ ),
156
+ migrations.AddField(
157
+ model_name='order',
158
+ name='daily_return',
159
+ field=models.DecimalField(decimal_places=16, default=Decimal('0'), help_text='The Ex-Post daily return',
160
+ max_digits=19, verbose_name='Daily Return'),
161
+ ),
162
+ migrations.AddIndex(
163
+ model_name='order',
164
+ index=models.Index(fields=['order_proposal'], name='wbportfolio_order_p_630213_idx'),
165
+ ),
166
+ migrations.RemoveField(
167
+ model_name='order',
168
+ name='status',
169
+ ),
170
+ migrations.RemoveField(
171
+ model_name='trade',
172
+ name='status',
173
+ ),
174
+ migrations.AlterField(
175
+ model_name='orderproposal',
176
+ name='status',
177
+ field=django_fsm.FSMField(
178
+ choices=[('DRAFT', 'Draft'), ('SUBMIT', 'Pending'), ('APPROVED', 'Approved'), ('DENIED', 'Denied'),
179
+ ('FAILED', 'Failed')], default='DRAFT', max_length=50, verbose_name='Status'),
180
+ ),
181
+ ]
@@ -0,0 +1,25 @@
1
+ # Generated by Django 5.0.14 on 2025-07-30 14:25
2
+
3
+ from django.db import migrations, models
4
+ from decimal import Decimal
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('wbportfolio', '0083_order_alter_trade_options_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.AddField(
14
+ model_name='orderproposal',
15
+ name='min_order_value',
16
+ field=models.IntegerField(default=0, help_text='Minimum Order Value in the Portfolio currency', verbose_name='Minimum Order Value'),
17
+ ),
18
+ migrations.AddField(
19
+ model_name='order',
20
+ name='desired_target_weight',
21
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'),
22
+ help_text='Desired Target Weight (for compliance and audit)', max_digits=9,
23
+ verbose_name='Desired Target Weight'),
24
+ ),
25
+ ]
@@ -0,0 +1,26 @@
1
+ # Generated by Django 5.0.14 on 2025-07-30 14:40
2
+
3
+ from decimal import Decimal
4
+ from django.db import migrations, models
5
+ from tqdm import tqdm
6
+
7
+ def migrate_desired_target_weight(apps, schema_editor):
8
+ from wbportfolio.models.orders import Order, OrderProposal
9
+ objs = []
10
+ qs = OrderProposal.objects.filter(orders__isnull=False).distinct()
11
+ for op in tqdm(qs, total=qs.count()):
12
+ for o in op.get_orders():
13
+ o.desired_target_weight = o._target_weight
14
+ objs.append(o)
15
+ Order.objects.bulk_update(objs, ["desired_target_weight"], batch_size=10000)
16
+
17
+
18
+ class Migration(migrations.Migration):
19
+
20
+ dependencies = [
21
+ ('wbportfolio', '0084_orderproposal_min_order_value'),
22
+ ]
23
+
24
+ operations = [
25
+ migrations.RunPython(migrate_desired_target_weight)
26
+ ]
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.0.14 on 2025-08-04 09:30
2
+
3
+ from decimal import Decimal
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wbportfolio', '0085_order_desired_target_weight'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='orderproposal',
16
+ name='total_cash_weight',
17
+ field=models.DecimalField(decimal_places=4, default=Decimal('0'), help_text='The desired percentage for the cash component. The remaining percentage (100% minus this value) will be allocated to total target weighting. Default is 0%.', max_digits=5, verbose_name='Total Cash Weight'),
18
+ ),
19
+ ]
@@ -0,0 +1,94 @@
1
+ # Generated by Django 5.0.14 on 2025-08-11 14:01
2
+
3
+ import django.db.models.deletion
4
+ import django_fsm
5
+ from django.db import migrations, models
6
+
7
+ def migrate_approve_to_apply(apps, schema_editor):
8
+ OrderProposal = apps.get_model("wbportfolio", "OrderProposal")
9
+ OrderProposal.objects.filter(status="APPROVED").update(status="APPLIED")
10
+
11
+
12
+ class Migration(migrations.Migration):
13
+
14
+ dependencies = [
15
+ ('wbportfolio', '0086_orderproposal_total_cash_weight'),
16
+ ]
17
+
18
+ operations = [
19
+ migrations.AddField(
20
+ model_name='product',
21
+ name='order_routing_custodian_adapter',
22
+ field=models.CharField(blank=True, help_text='The dotted path to the order routing custodian adapter', max_length=1024, null=True, verbose_name='Order Routing Custodian Adapter'),
23
+ ),
24
+ migrations.AddField(
25
+ model_name='order',
26
+ name='execution_comment',
27
+ field=models.TextField(blank=True, default='', verbose_name='Execution Comment'),
28
+ ),
29
+ migrations.AddField(
30
+ model_name='order',
31
+ name='execution_confirmed',
32
+ field=models.BooleanField(default=False, verbose_name='Execution Confirmed'),
33
+ ),
34
+ migrations.AddField(
35
+ model_name='orderproposal',
36
+ name='approver',
37
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT,
38
+ related_name='approver_order_proposals', to='directory.person',
39
+ verbose_name='Approver'),
40
+ ),
41
+ migrations.AddField(
42
+ model_name='orderproposal',
43
+ name='execution_comment',
44
+ field=models.CharField(blank=True, default='', verbose_name='Execution Comment'),
45
+ ),
46
+ migrations.AddField(
47
+ model_name='orderproposal',
48
+ name='execution_status',
49
+ field=models.CharField(blank=True, choices=[('PENDING', 'Pending'), ('IN_DRAFT', 'In Draft'),
50
+ ('COMPLETED', 'Completed'), ('CANCELLED', 'Cancelled'),
51
+ ('REJECTED', 'Rejected'), ('FAILED', 'Failed'),
52
+ ('UNKNOWN', 'Unknown')], default='',
53
+ verbose_name='Execution Status'),
54
+ ),
55
+ migrations.AddField(
56
+ model_name='orderproposal',
57
+ name='execution_status_detail',
58
+ field=models.CharField(blank=True, default='', verbose_name='Execution Status Detail'),
59
+ ),
60
+ migrations.AlterField(
61
+ model_name='orderproposal',
62
+ name='status',
63
+ field=django_fsm.FSMField(choices=[('DRAFT', 'Draft'), ('SUBMIT', 'Pending'), ('APPROVED', 'Approved'),
64
+ ('PENDING_EXECUTION', 'Pending Execution'), ('EXECUTED', 'Executed'),
65
+ ('DENIED', 'Denied'), ('FAILED', 'Failed')], default='DRAFT',
66
+ max_length=50, verbose_name='Status'),
67
+ ),
68
+ migrations.AddField(
69
+ model_name='index',
70
+ name='order_routing_custodian_adapter',
71
+ field=models.CharField(blank=True, help_text='The dotted path to the order routing custodian adapter',
72
+ max_length=1024, null=True, verbose_name='Order Routing Custodian Adapter'),
73
+ ),
74
+ migrations.AddField(
75
+ model_name='productgroup',
76
+ name='order_routing_custodian_adapter',
77
+ field=models.CharField(blank=True, help_text='The dotted path to the order routing custodian adapter',
78
+ max_length=1024, null=True, verbose_name='Order Routing Custodian Adapter'),
79
+ ),
80
+ migrations.RenameField(
81
+ model_name='rebalancer',
82
+ old_name='approve_order_proposal_automatically',
83
+ new_name='apply_order_proposal_automatically',
84
+ ),
85
+ migrations.RunPython(migrate_approve_to_apply),
86
+ migrations.AlterField(
87
+ model_name='orderproposal',
88
+ name='status',
89
+ field=django_fsm.FSMField(
90
+ choices=[('DRAFT', 'Draft'), ('PENDING', 'Pending'), ('APPROVED', 'Approved'), ('DENIED', 'Denied'),
91
+ ('APPLIED', 'Applied'), ('EXECUTION', 'Execution'), ('FAILED', 'Failed')], default='DRAFT',
92
+ max_length=50, verbose_name='Status'),
93
+ ),
94
+ ]
@@ -0,0 +1,19 @@
1
+ # Generated by Django 5.0.14 on 2025-08-18 08:34
2
+
3
+ from decimal import Decimal
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wbportfolio', '0087_product_order_routing_custodian_adapter'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='orderproposal',
16
+ name='total_effective_portfolio_contribution',
17
+ field=models.DecimalField(decimal_places=16, default=Decimal('1'), max_digits=19),
18
+ ),
19
+ ]
@@ -0,0 +1,71 @@
1
+ # Generated by Django 5.0.12 on 2025-09-15 13:45
2
+
3
+ import django.core.validators
4
+ from decimal import Decimal
5
+ from django.db import migrations, models
6
+
7
+
8
+ class Migration(migrations.Migration):
9
+
10
+ dependencies = [
11
+ ('wbportfolio', '0088_orderproposal_total_effective_portfolio_contribution'),
12
+ ]
13
+
14
+ operations = [
15
+ migrations.AddField(
16
+ model_name='orderproposal',
17
+ name='min_weighting',
18
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'), help_text='The minimum weight allowed for this order proposal ', max_digits=9, verbose_name='Minimum Weight'),
19
+ ),
20
+ migrations.AddField(
21
+ model_name='portfolio',
22
+ name='default_order_proposal_min_order_value',
23
+ field=models.IntegerField(default=0, verbose_name='Default Order Proposal Minimum Order Value'),
24
+ ),
25
+ migrations.AddField(
26
+ model_name='portfolio',
27
+ name='default_order_proposal_min_weighting',
28
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'), max_digits=9,
29
+ verbose_name='Default Order Proposal Minimum Weight'),
30
+ ),
31
+ migrations.AddField(
32
+ model_name='portfolio',
33
+ name='default_order_proposal_total_cash_weight',
34
+ field=models.DecimalField(decimal_places=4, default=Decimal('0'), max_digits=5,
35
+ verbose_name='Default Order Proposal Total Cash Weight'),
36
+ ),
37
+ migrations.AlterField(
38
+ model_name='orderproposal',
39
+ name='min_weighting',
40
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'),
41
+ help_text='The minimum weight allowed for this order proposal ', max_digits=9,
42
+ validators=[django.core.validators.MinValueValidator(Decimal('0')),
43
+ django.core.validators.MaxValueValidator(Decimal('1'))],
44
+ verbose_name='Minimum Weight'),
45
+ ),
46
+ migrations.AlterField(
47
+ model_name='orderproposal',
48
+ name='total_cash_weight',
49
+ field=models.DecimalField(decimal_places=4, default=Decimal('0'),
50
+ help_text='The desired percentage for the cash component. The remaining percentage (100% minus this value) will be allocated to total target weighting. Default is 0%.',
51
+ max_digits=5, validators=[django.core.validators.MinValueValidator(Decimal('0')),
52
+ django.core.validators.MaxValueValidator(Decimal('1'))],
53
+ verbose_name='Total Cash Weight'),
54
+ ),
55
+ migrations.AlterField(
56
+ model_name='portfolio',
57
+ name='default_order_proposal_min_weighting',
58
+ field=models.DecimalField(decimal_places=8, default=Decimal('0'), max_digits=9,
59
+ validators=[django.core.validators.MinValueValidator(Decimal('0')),
60
+ django.core.validators.MaxValueValidator(Decimal('1'))],
61
+ verbose_name='Default Order Proposal Minimum Weight'),
62
+ ),
63
+ migrations.AlterField(
64
+ model_name='portfolio',
65
+ name='default_order_proposal_total_cash_weight',
66
+ field=models.DecimalField(decimal_places=4, default=Decimal('0'), max_digits=5,
67
+ validators=[django.core.validators.MinValueValidator(Decimal('0')),
68
+ django.core.validators.MaxValueValidator(Decimal('1'))],
69
+ verbose_name='Default Order Proposal Total Cash Weight'),
70
+ ),
71
+ ]
@@ -0,0 +1,44 @@
1
+ # Generated by Django 5.0.12 on 2025-09-18 08:48
2
+
3
+ import django.db.models.expressions
4
+ from django.db import migrations, models
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+
9
+ dependencies = [
10
+ ('wbportfolio', '0089_orderproposal_min_weighting'),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name='dividendtransaction',
16
+ name='price_fx_portfolio',
17
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
18
+ ),
19
+ migrations.AddField(
20
+ model_name='dividendtransaction',
21
+ name='price_gross_fx_portfolio',
22
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price_gross')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
23
+ ),
24
+ migrations.AddField(
25
+ model_name='order',
26
+ name='price_fx_portfolio',
27
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
28
+ ),
29
+ migrations.AddField(
30
+ model_name='order',
31
+ name='price_gross_fx_portfolio',
32
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price_gross')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
33
+ ),
34
+ migrations.AddField(
35
+ model_name='trade',
36
+ name='price_fx_portfolio',
37
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
38
+ ),
39
+ migrations.AddField(
40
+ model_name='trade',
41
+ name='price_gross_fx_portfolio',
42
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price_gross')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
43
+ ),
44
+ ]
@@ -0,0 +1,32 @@
1
+ # Generated by Django 5.0.12 on 2025-11-06 12:59
2
+
3
+ from django.db import migrations, models
4
+
5
+
6
+ class Migration(migrations.Migration):
7
+
8
+ dependencies = [
9
+ ('wbportfolio', '0090_dividendtransaction_price_fx_portfolio_and_more'),
10
+ ]
11
+
12
+ operations = [
13
+ migrations.RemoveField(
14
+ model_name='order',
15
+ name='execution_confirmed',
16
+ ),
17
+ migrations.AddField(
18
+ model_name='order',
19
+ name='execution_instruction',
20
+ field=models.CharField(choices=[('MARKET_ON_CLOSE', 'Market On Close'), ('GUARANTEED_MARKET_ON_CLOSE', 'Guaranteed Market On Close'), ('GUARANTEED_MARKET_ON_OPEN', 'Guaranteed Market On Open'), ('GPW_MARKET_ON_CLOSE', 'GPW Market On Close'), ('MARKET_ON_OPEN', 'Market On Open'), ('IN_LINE_WITH_VOLUME', 'In Line With Volume'), ('LIMIT_ORDER', 'Limit Order'), ('VWAP', 'VWAP'), ('TWAP', 'TWAP')], default='MARKET_ON_CLOSE', max_length=26, verbose_name='Execution Instruction'),
21
+ ),
22
+ migrations.AddField(
23
+ model_name='order',
24
+ name='execution_instruction_parameters',
25
+ field=models.JSONField(blank=True, default=dict, verbose_name='Execution Instruction Parameters'),
26
+ ),
27
+ migrations.AddField(
28
+ model_name='order',
29
+ name='execution_status',
30
+ field=models.CharField(choices=[('PENDING', 'Pending'), ('CONFIRMED', 'Confirmed'), ('EXECUTED', 'Executed'), ('FAILED', 'Failed'), ('IGNORED', 'Ignored')], default='PENDING', max_length=12, verbose_name='Execution Status'),
31
+ ),
32
+ ]