wbportfolio 1.52.0__py2.py3-none-any.whl → 1.52.2__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 (86) hide show
  1. wbportfolio/admin/__init__.py +1 -1
  2. wbportfolio/admin/transactions/__init__.py +0 -1
  3. wbportfolio/admin/transactions/dividends.py +40 -4
  4. wbportfolio/admin/transactions/fees.py +24 -14
  5. wbportfolio/admin/transactions/trades.py +34 -12
  6. wbportfolio/defaults/fees/default.py +7 -15
  7. wbportfolio/factories/__init__.py +0 -1
  8. wbportfolio/factories/dividends.py +8 -3
  9. wbportfolio/factories/fees.py +8 -4
  10. wbportfolio/factories/trades.py +10 -3
  11. wbportfolio/filters/transactions/__init__.py +1 -2
  12. wbportfolio/filters/transactions/fees.py +5 -10
  13. wbportfolio/filters/transactions/trades.py +17 -8
  14. wbportfolio/filters/transactions/utils.py +42 -0
  15. wbportfolio/import_export/handlers/dividend.py +7 -7
  16. wbportfolio/import_export/handlers/fees.py +11 -21
  17. wbportfolio/import_export/handlers/trade.py +5 -7
  18. wbportfolio/import_export/parsers/jpmorgan/fees.py +2 -2
  19. wbportfolio/import_export/parsers/leonteq/customer_trade.py +5 -5
  20. wbportfolio/import_export/parsers/leonteq/fees.py +11 -7
  21. wbportfolio/import_export/parsers/leonteq/trade.py +0 -5
  22. wbportfolio/import_export/parsers/natixis/d1_fees.py +2 -2
  23. wbportfolio/import_export/parsers/natixis/dividend.py +4 -9
  24. wbportfolio/import_export/parsers/natixis/fees.py +7 -9
  25. wbportfolio/import_export/parsers/sg_lux/customer_trade_pending_slk.py +1 -1
  26. wbportfolio/import_export/parsers/sg_lux/fees.py +2 -2
  27. wbportfolio/import_export/parsers/sg_lux/perf_fees.py +2 -2
  28. wbportfolio/import_export/parsers/sg_lux/utils.py +2 -2
  29. wbportfolio/import_export/parsers/ubs/api/fees.py +2 -2
  30. wbportfolio/import_export/parsers/vontobel/customer_trade.py +2 -3
  31. wbportfolio/import_export/parsers/vontobel/historical_customer_trade.py +0 -1
  32. wbportfolio/import_export/parsers/vontobel/management_fees.py +7 -7
  33. wbportfolio/import_export/parsers/vontobel/performance_fees.py +3 -3
  34. wbportfolio/jinja2/wbportfolio/sql/aum_nnm.sql +2 -2
  35. wbportfolio/migrations/0059_fees_unique_fees.py +1 -1
  36. wbportfolio/migrations/0077_remove_transaction_currency_and_more.py +622 -0
  37. wbportfolio/models/mixins/liquidity_stress_test.py +3 -3
  38. wbportfolio/models/transactions/__init__.py +0 -2
  39. wbportfolio/models/transactions/claim.py +1 -1
  40. wbportfolio/models/transactions/dividends.py +41 -5
  41. wbportfolio/models/transactions/fees.py +55 -22
  42. wbportfolio/models/transactions/trade_proposals.py +26 -6
  43. wbportfolio/models/transactions/trades.py +111 -50
  44. wbportfolio/models/transactions/transactions.py +60 -156
  45. wbportfolio/serializers/signals.py +15 -10
  46. wbportfolio/serializers/transactions/__init__.py +0 -5
  47. wbportfolio/serializers/transactions/dividends.py +37 -9
  48. wbportfolio/serializers/transactions/fees.py +39 -10
  49. wbportfolio/serializers/transactions/trades.py +56 -16
  50. wbportfolio/tasks.py +2 -2
  51. wbportfolio/tests/conftest.py +2 -8
  52. wbportfolio/tests/models/test_imports.py +2 -7
  53. wbportfolio/tests/models/transactions/test_fees.py +7 -13
  54. wbportfolio/tests/models/transactions/test_trade_proposals.py +4 -2
  55. wbportfolio/urls.py +3 -6
  56. wbportfolio/viewsets/configs/buttons/__init__.py +1 -0
  57. wbportfolio/viewsets/configs/buttons/mixins.py +2 -2
  58. wbportfolio/viewsets/configs/buttons/trades.py +8 -0
  59. wbportfolio/viewsets/configs/display/__init__.py +2 -3
  60. wbportfolio/viewsets/configs/display/fees.py +3 -3
  61. wbportfolio/viewsets/configs/endpoints/__init__.py +3 -4
  62. wbportfolio/viewsets/configs/endpoints/fees.py +2 -2
  63. wbportfolio/viewsets/configs/menu/__init__.py +0 -1
  64. wbportfolio/viewsets/configs/titles/__init__.py +2 -3
  65. wbportfolio/viewsets/configs/titles/fees.py +4 -8
  66. wbportfolio/viewsets/mixins.py +5 -1
  67. wbportfolio/viewsets/products.py +6 -6
  68. wbportfolio/viewsets/transactions/__init__.py +2 -7
  69. wbportfolio/viewsets/transactions/fees.py +22 -22
  70. wbportfolio/viewsets/transactions/trade_proposals.py +1 -0
  71. wbportfolio/viewsets/transactions/trades.py +2 -0
  72. {wbportfolio-1.52.0.dist-info → wbportfolio-1.52.2.dist-info}/METADATA +1 -1
  73. {wbportfolio-1.52.0.dist-info → wbportfolio-1.52.2.dist-info}/RECORD +75 -84
  74. wbportfolio/admin/transactions/transactions.py +0 -38
  75. wbportfolio/factories/transactions.py +0 -22
  76. wbportfolio/filters/transactions/transactions.py +0 -99
  77. wbportfolio/models/transactions/expiry.py +0 -7
  78. wbportfolio/serializers/transactions/expiry.py +0 -18
  79. wbportfolio/serializers/transactions/transactions.py +0 -85
  80. wbportfolio/viewsets/configs/display/transactions.py +0 -55
  81. wbportfolio/viewsets/configs/endpoints/transactions.py +0 -14
  82. wbportfolio/viewsets/configs/menu/transactions.py +0 -9
  83. wbportfolio/viewsets/configs/titles/transactions.py +0 -9
  84. wbportfolio/viewsets/transactions/transactions.py +0 -122
  85. {wbportfolio-1.52.0.dist-info → wbportfolio-1.52.2.dist-info}/WHEEL +0 -0
  86. {wbportfolio-1.52.0.dist-info → wbportfolio-1.52.2.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,622 @@
1
+ # Generated by Django 5.0.14 on 2025-06-17 13:58
2
+
3
+ import django.db.models.deletion
4
+ import django.db.models.expressions
5
+ import django.utils.timezone
6
+ from decimal import Decimal
7
+ from django.db import migrations, models
8
+ from django.db.migrations.operations.models import ModelOptionOperation
9
+ from django.db.models import Count
10
+
11
+
12
+ def remove_duplicate(apps, schema_editor):
13
+ Trade = apps.get_model("wbportfolio", "Trade")
14
+ for row in Trade.objects.filter(trade_proposal__isnull=False).values("underlying_instrument", "transaction_date", "portfolio").annotate(c=Count("*")).filter(c__gt=1):
15
+ qs = Trade.objects.filter(underlying_instrument=row["underlying_instrument"], transaction_date=row["transaction_date"], portfolio=row["portfolio"])
16
+ for t in qs[1:]:
17
+ t.delete()
18
+
19
+ class SetModelBasesOptionOperation(ModelOptionOperation):
20
+ """
21
+ A migration operation that updates the bases of a model.
22
+ This can be used to separate a model from its parent. Specifically
23
+ when multi-table inheritance is used.
24
+ """
25
+ def __init__(self, name, bases):
26
+ super().__init__(name)
27
+ self.bases = bases
28
+
29
+ def deconstruct(self):
30
+ return (self.__class__.__qualname__, [], {"bases": self.bases})
31
+
32
+ def state_forwards(self, app_label, state):
33
+ model_state = state.models[app_label, self.name_lower]
34
+ model_state.bases = self.bases
35
+ state.reload_model(app_label, self.name_lower, delay=True)
36
+
37
+ def database_forwards(self, app_label, schema_editor, from_state, to_state):
38
+ pass
39
+
40
+ def database_backwards(self, app_label, schema_editor, from_state, to_state):
41
+ pass
42
+
43
+ def describe(self):
44
+ return "Update bases of the model %s" % self.name
45
+
46
+ @property
47
+ def migration_name_fragment(self):
48
+ return "set_%s_bases" % self.name_lower
49
+
50
+ class Migration(migrations.Migration):
51
+
52
+ dependencies = [
53
+ ('currency', '0001_initial'),
54
+ ('io', '0008_importsource_resource_kwargs'),
55
+ ('wbfdm', '0030_alter_relatedinstrumentthroughmodel_related_type'),
56
+ ('wbportfolio', '0076_alter_dividendtransaction_price_and_more'),
57
+ ]
58
+
59
+ operations = [
60
+ migrations.AlterField(
61
+ model_name='transaction',
62
+ name='transaction_type',
63
+ field=models.CharField(
64
+ choices=[('Trade', 'Trade'), ('DividendTransaction', 'Dividend Transaction'), ('Fees', 'Fees')],
65
+ default='Trade', max_length=255, verbose_name='Type'),
66
+ ),
67
+ migrations.DeleteModel(
68
+ name='Expiry',
69
+ ),
70
+ migrations.RemoveIndex(
71
+ model_name='fees',
72
+ name='wbportfolio_linked__a49c5d_idx',
73
+ ),
74
+ migrations.RemoveIndex(
75
+ model_name='fees',
76
+ name='wbportfolio_transac_1f7a29_idx',
77
+ ),
78
+ migrations.RenameField(
79
+ model_name='fees',
80
+ old_name='linked_product',
81
+ new_name='product',
82
+ ),
83
+ migrations.RenameField(
84
+ model_name='trade',
85
+ old_name='external_identifier2',
86
+ new_name='external_id_alternative',
87
+ ),
88
+ SetModelBasesOptionOperation("Fees", (models.Model, )),
89
+ SetModelBasesOptionOperation("Trade", (models.Model, )),
90
+ SetModelBasesOptionOperation("DividendTransaction", (models.Model, )),
91
+ migrations.RenameField(
92
+ model_name='dividendtransaction',
93
+ old_name='transaction_ptr',
94
+ new_name='id',
95
+ ),
96
+ migrations.RenameField(
97
+ model_name='fees',
98
+ old_name='transaction_ptr',
99
+ new_name='id',
100
+ ),
101
+ migrations.RenameField(
102
+ model_name='trade',
103
+ old_name='transaction_ptr',
104
+ new_name='id',
105
+ ),
106
+ migrations.AlterField(
107
+ model_name='dividendtransaction',
108
+ name='id',
109
+ field=models.AutoField(auto_created=True, primary_key=True, serialize=False,
110
+ verbose_name='ID'),
111
+ ),
112
+ migrations.AlterField(
113
+ model_name='fees',
114
+ name='id',
115
+ field=models.AutoField(auto_created=True, primary_key=True, serialize=False,
116
+ verbose_name='ID'),
117
+ ),
118
+ migrations.AlterField(
119
+ model_name='trade',
120
+ name='id',
121
+ field=models.AutoField(auto_created=True, primary_key=True, serialize=False,
122
+ verbose_name='ID'),
123
+ ),
124
+ migrations.AlterField(
125
+ model_name='dividendtransaction',
126
+ name='price',
127
+ field=models.DecimalField(decimal_places=4, help_text='The amount paid per share', max_digits=15,
128
+ verbose_name='DPS'),
129
+ ),
130
+ migrations.AlterField(
131
+ model_name='dividendtransaction',
132
+ name='shares',
133
+ field=models.DecimalField(decimal_places=4, default=Decimal('0.0'),
134
+ help_text='The number of shares held at record date, used to calculate the dividend',
135
+ max_digits=15, verbose_name='Shares / Quantity'),
136
+ ),
137
+ migrations.AlterField(
138
+ model_name='fees',
139
+ name='fee_date',
140
+ field=models.DateField(help_text='The date that this fee was paid.', verbose_name='Fees Date'),
141
+ ),
142
+
143
+
144
+ migrations.AddField(
145
+ model_name='dividendtransaction',
146
+ name='comment',
147
+ field=models.TextField(blank=True, default='', verbose_name='Comment'),
148
+ ),
149
+ migrations.AddField(
150
+ model_name='dividendtransaction',
151
+ name='created',
152
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
153
+ preserve_default=False,
154
+ ),
155
+ migrations.AddField(
156
+ model_name='dividendtransaction',
157
+ name='currency',
158
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='currency.currency', verbose_name='Currency'),
159
+ preserve_default=False,
160
+ ),
161
+ migrations.AddField(
162
+ model_name='dividendtransaction',
163
+ name='currency_fx_rate',
164
+ field=models.DecimalField(decimal_places=8, default=Decimal('1'), max_digits=14, verbose_name='FOREX rate'),
165
+ ),
166
+ migrations.AddField(
167
+ model_name='dividendtransaction',
168
+ name='distribution_method',
169
+ field=models.CharField(choices=[('Payment', 'Payment'), ('Reinvestment', 'Reinvestment')], default='Payment', max_length=255, verbose_name='Type'),
170
+ ),
171
+ migrations.AddField(
172
+ model_name='dividendtransaction',
173
+ name='ex_date',
174
+ field=models.DateField(blank=True, null=True, help_text='The date on which the stock starts trading without the dividend', verbose_name='Ex-Dividend Date'),
175
+ preserve_default=False,
176
+ ),
177
+ migrations.AddField(
178
+ model_name='dividendtransaction',
179
+ name='import_source',
180
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, to='io.importsource'),
181
+ ),
182
+ migrations.AddField(
183
+ model_name='dividendtransaction',
184
+ name='portfolio',
185
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='wbportfolio.portfolio', verbose_name='Portfolio'),
186
+ preserve_default=False,
187
+ ),
188
+ migrations.AddField(
189
+ model_name='dividendtransaction',
190
+ name='record_date',
191
+ field=models.DateField(blank=True, null=True, help_text='The date on which the holder must own the shares to be eligible for the dividend', verbose_name='Record Date'),
192
+ preserve_default=False,
193
+ ),
194
+ migrations.AddField(
195
+ model_name='dividendtransaction',
196
+ name='underlying_instrument',
197
+ field=models.ForeignKey(blank=True, null=True, help_text='The instrument that is this transaction.', limit_choices_to=models.Q(('children__isnull', True)), on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss', to='wbfdm.instrument', verbose_name='Underlying Instrument'),
198
+ preserve_default=False,
199
+ ),
200
+ migrations.AddField(
201
+ model_name='dividendtransaction',
202
+ name='updated',
203
+ field=models.DateTimeField(auto_now=True),
204
+ ),
205
+ migrations.AddField(
206
+ model_name='dividendtransaction',
207
+ name='value_date',
208
+ field=models.DateField(blank=True, null=True, help_text='The date that this transaction was valuated/paid.', verbose_name='Value Date'),
209
+ preserve_default=False,
210
+ ),
211
+
212
+ migrations.AddField(
213
+ model_name='fees',
214
+ name='currency',
215
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT,
216
+ related_name='fees', to='currency.currency', verbose_name='Currency'),
217
+ preserve_default=False,
218
+ ),
219
+ migrations.AddField(
220
+ model_name='fees',
221
+ name='import_source',
222
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
223
+ to='io.importsource'),
224
+ ),
225
+ migrations.AddField(
226
+ model_name='fees',
227
+ name='currency_fx_rate',
228
+ field=models.DecimalField(decimal_places=8, default=Decimal('1'), max_digits=14, verbose_name='FOREX rate'),
229
+ ),
230
+ migrations.AddField(
231
+ model_name='fees',
232
+ name='created',
233
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
234
+ preserve_default=False,
235
+ ),
236
+ migrations.AddField(
237
+ model_name='fees',
238
+ name='total_value',
239
+ field=models.DecimalField(decimal_places=4, blank=True, null=True, max_digits=20, verbose_name='Total Value'),
240
+ preserve_default=False,
241
+ ),
242
+ migrations.AddField(
243
+ model_name='fees',
244
+ name='total_value_gross',
245
+ field=models.DecimalField(decimal_places=4, blank=True, null=True, max_digits=20, verbose_name='Total Value Gross'),
246
+ preserve_default=False,
247
+ ),
248
+ migrations.AddField(
249
+ model_name='fees',
250
+ name='updated',
251
+ field=models.DateTimeField(auto_now=True),
252
+ ),
253
+
254
+
255
+ migrations.AddField(
256
+ model_name='trade',
257
+ name='currency_fx_rate',
258
+ field=models.DecimalField(decimal_places=8, default=Decimal('1'), max_digits=14, verbose_name='FOREX rate'),
259
+ ),
260
+ migrations.AddField(
261
+ model_name='trade',
262
+ name='book_date',
263
+ field=models.DateField(blank=True, null=True, help_text='The date that this transaction was booked.', verbose_name='Trade Date'),
264
+ preserve_default=False,
265
+ ),
266
+ migrations.AddField(
267
+ model_name='trade',
268
+ name='comment',
269
+ field=models.TextField(blank=True, default='', verbose_name='Comment'),
270
+ ),
271
+ migrations.AddField(
272
+ model_name='trade',
273
+ name='created',
274
+ field=models.DateTimeField(auto_now_add=True, default=django.utils.timezone.now),
275
+ preserve_default=False,
276
+ ),
277
+ migrations.AddField(
278
+ model_name='trade',
279
+ name='external_id',
280
+ field=models.CharField(blank=True, help_text='An external identifier that was supplied.', max_length=255, null=True, verbose_name='External Identifier'),
281
+ ),
282
+ migrations.AddField(
283
+ model_name='trade',
284
+ name='transaction_date',
285
+ field=models.DateField(blank=True, null=True, help_text='The date that this transaction was traded.', verbose_name='Trade Date'),
286
+ preserve_default=False,
287
+ ),
288
+ migrations.AddField(
289
+ model_name='trade',
290
+ name='updated',
291
+ field=models.DateTimeField(auto_now=True),
292
+ ),
293
+ migrations.AddField(
294
+ model_name='trade',
295
+ name='value_date',
296
+ field=models.DateField(blank=True, null=True, help_text='The date that this transaction was valuated/paid.', verbose_name='Value Date'),
297
+ preserve_default=False,
298
+ ),
299
+ migrations.AddField(
300
+ model_name='trade',
301
+ name='currency',
302
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT,
303
+ related_name='%(class)ss', to='currency.currency', verbose_name='Currency'),
304
+ preserve_default=False,
305
+ ),
306
+ migrations.AddField(
307
+ model_name='trade',
308
+ name='import_source',
309
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL,
310
+ to='io.importsource'),
311
+ ),
312
+ migrations.AddField(
313
+ model_name='trade',
314
+ name='portfolio',
315
+ field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT,
316
+ related_name='%(class)ss', to='wbportfolio.portfolio', verbose_name='Portfolio'),
317
+ preserve_default=False,
318
+ ),
319
+ migrations.AddField(
320
+ model_name='trade',
321
+ name='underlying_instrument',
322
+ field=models.ForeignKey(blank=True, null=True, help_text='The instrument that is this transaction.',
323
+ limit_choices_to=models.Q(('children__isnull', True)),
324
+ on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
325
+ to='wbfdm.instrument', verbose_name='Underlying Instrument'),
326
+ preserve_default=False,
327
+ ),
328
+
329
+
330
+ migrations.RunSQL(
331
+ """
332
+ UPDATE wbportfolio_dividendtransaction AS o
333
+ SET comment = t.comment, currency_id = t.currency_id, currency_fx_rate = t.currency_fx_rate, ex_date = t.transaction_date, import_source_id = t.import_source_id, portfolio_id = t.portfolio_id, record_date = t.transaction_date, underlying_instrument_id = t.underlying_instrument_id, value_date = t.value_date
334
+ FROM wbportfolio_transaction AS t
335
+ WHERE o.id = t.id
336
+ """
337
+ ),
338
+ migrations.RunSQL(
339
+ """
340
+ UPDATE wbportfolio_fees AS o
341
+ SET currency_id = t.currency_id, import_source_id = t.import_source_id, currency_fx_rate = t.currency_fx_rate, total_value = t.total_value, total_value_gross = t.total_value_gross
342
+ FROM wbportfolio_transaction AS t
343
+ WHERE o.id = t.id
344
+ """
345
+ ),
346
+ migrations.RunSQL(
347
+ """
348
+ UPDATE wbportfolio_trade o
349
+ SET underlying_instrument_id = t.underlying_instrument_id, portfolio_id = t.portfolio_id, currency_fx_rate = t.currency_fx_rate, book_date = t.book_date, comment = t.comment, external_id = t.external_id, transaction_date = t.transaction_date, value_date = t.value_date, currency_id = t.currency_id, import_source_id = t.import_source_id
350
+ FROM wbportfolio_transaction AS t
351
+ WHERE o.id = t.id
352
+ """
353
+ ),
354
+
355
+
356
+
357
+ migrations.AlterField(
358
+ model_name='dividendtransaction',
359
+ name='currency',
360
+ field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
361
+ to='currency.currency', verbose_name='Currency'),
362
+ preserve_default=False,
363
+ ),
364
+ migrations.AlterField(
365
+ model_name='dividendtransaction',
366
+ name='ex_date',
367
+ field=models.DateField(default=None,
368
+ help_text='The date on which the stock starts trading without the dividend',
369
+ verbose_name='Ex-Dividend Date'),
370
+ preserve_default=False,
371
+ ),
372
+ migrations.AlterField(
373
+ model_name='dividendtransaction',
374
+ name='portfolio',
375
+ field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
376
+ to='wbportfolio.portfolio', verbose_name='Portfolio'),
377
+ preserve_default=False,
378
+ ),
379
+ migrations.AlterField(
380
+ model_name='dividendtransaction',
381
+ name='record_date',
382
+ field=models.DateField(default=None,
383
+ help_text='The date on which the holder must own the shares to be eligible for the dividend',
384
+ verbose_name='Record Date'),
385
+ preserve_default=False,
386
+ ),
387
+ migrations.AlterField(
388
+ model_name='dividendtransaction',
389
+ name='underlying_instrument',
390
+ field=models.ForeignKey(default=None, help_text='The instrument that is this transaction.',
391
+ limit_choices_to=models.Q(('children__isnull', True)),
392
+ on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
393
+ to='wbfdm.instrument', verbose_name='Underlying Instrument'),
394
+ preserve_default=False,
395
+ ),
396
+ migrations.AlterField(
397
+ model_name='dividendtransaction',
398
+ name='value_date',
399
+ field=models.DateField(default=None, help_text='The date that this transaction was valuated/paid.',
400
+ verbose_name='Value Date'),
401
+ preserve_default=False,
402
+ ),
403
+ migrations.AlterField(
404
+ model_name='fees',
405
+ name='currency',
406
+ field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, related_name='fees',
407
+ to='currency.currency', verbose_name='Currency'),
408
+ preserve_default=False,
409
+ ),
410
+ migrations.AlterField(
411
+ model_name='fees',
412
+ name='total_value',
413
+ field=models.DecimalField(decimal_places=4, default=None, max_digits=20, verbose_name='Total Value'),
414
+ preserve_default=False,
415
+ ),
416
+ migrations.AlterField(
417
+ model_name='fees',
418
+ name='total_value_gross',
419
+ field=models.DecimalField(decimal_places=4, default=None, max_digits=20, verbose_name='Total Value Gross'),
420
+ preserve_default=False,
421
+ ),
422
+ migrations.AlterField(
423
+ model_name='fees',
424
+ name='product',
425
+ field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, related_name='fees',
426
+ to='wbportfolio.product', verbose_name='Product'),
427
+ ),
428
+ migrations.AlterField(
429
+ model_name='trade',
430
+ name='book_date',
431
+ field=models.DateField(default=None, help_text='The date that this transaction was booked.',
432
+ verbose_name='Trade Date'),
433
+ preserve_default=False,
434
+ ),
435
+ migrations.AlterField(
436
+ model_name='trade',
437
+ name='currency',
438
+ field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
439
+ to='currency.currency', verbose_name='Currency'),
440
+ preserve_default=False,
441
+ ),
442
+ migrations.AlterField(
443
+ model_name='trade',
444
+ name='external_id_alternative',
445
+ field=models.CharField(blank=True, help_text='A second external identifier that was supplied.',
446
+ max_length=255, null=True, verbose_name='Alternative External Identifier'),
447
+ ),
448
+ migrations.AlterField(
449
+ model_name='trade',
450
+ name='portfolio',
451
+ field=models.ForeignKey(default=None, on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
452
+ to='wbportfolio.portfolio', verbose_name='Portfolio'),
453
+ preserve_default=False,
454
+ ),
455
+ migrations.AlterField(
456
+ model_name='trade',
457
+ name='transaction_date',
458
+ field=models.DateField(default=None, help_text='The date that this transaction was traded.',
459
+ verbose_name='Trade Date'),
460
+ preserve_default=False,
461
+ ),
462
+ migrations.AlterField(
463
+ model_name='trade',
464
+ name='underlying_instrument',
465
+ field=models.ForeignKey(default=None, help_text='The instrument that is this transaction.',
466
+ limit_choices_to=models.Q(('children__isnull', True)),
467
+ on_delete=django.db.models.deletion.PROTECT, related_name='%(class)ss',
468
+ to='wbfdm.instrument', verbose_name='Underlying Instrument'),
469
+ preserve_default=False,
470
+ ),
471
+ migrations.AlterField(
472
+ model_name='trade',
473
+ name='value_date',
474
+ field=models.DateField(default=None, help_text='The date that this transaction was valuated/paid.',
475
+ verbose_name='Value Date'),
476
+ preserve_default=False,
477
+ ),
478
+
479
+ migrations.AddField(
480
+ model_name='dividendtransaction',
481
+ name='fees',
482
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
483
+ models.F('price_gross'), '-', models.F('price')),
484
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
485
+ ),
486
+ migrations.AddField(
487
+ model_name='dividendtransaction',
488
+ name='total_value',
489
+ field=models.GeneratedField(db_persist=True,
490
+ expression=django.db.models.expressions.CombinedExpression(models.F('price'),
491
+ '*',
492
+ models.F('shares')),
493
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
494
+ ),
495
+ migrations.AddField(
496
+ model_name='dividendtransaction',
497
+ name='total_value_fx_portfolio',
498
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
499
+ django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')),
500
+ '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
501
+ ),
502
+ migrations.AddField(
503
+ model_name='dividendtransaction',
504
+ name='total_value_gross',
505
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
506
+ django.db.models.expressions.CombinedExpression(models.F('price'), '*', models.F('shares')), '*',
507
+ models.F('retrocession')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
508
+ ),
509
+ migrations.AddField(
510
+ model_name='dividendtransaction',
511
+ name='total_value_gross_fx_portfolio',
512
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
513
+ django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*',
514
+ models.F('price_gross')), '*', models.F('shares')),
515
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
516
+ ),
517
+ migrations.AddField(
518
+ model_name='trade',
519
+ name='total_value',
520
+ field=models.GeneratedField(db_persist=True,
521
+ expression=django.db.models.expressions.CombinedExpression(models.F('price'),
522
+ '*',
523
+ models.F('shares')),
524
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
525
+ ),
526
+ migrations.AddField(
527
+ model_name='trade',
528
+ name='total_value_gross',
529
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
530
+ models.F('price_gross'), '*', models.F('shares')),
531
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
532
+ ),
533
+ migrations.AddField(
534
+ model_name='trade',
535
+ name='fees',
536
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
537
+ models.F('price_gross'), '-', models.F('price')),
538
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
539
+ ),
540
+ migrations.AddField(
541
+ model_name='trade',
542
+ name='total_value_fx_portfolio',
543
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
544
+ django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*', models.F('price')),
545
+ '*', models.F('shares')), output_field=models.DecimalField(decimal_places=4, max_digits=20)),
546
+ ),
547
+ migrations.AddField(
548
+ model_name='trade',
549
+ name='total_value_gross_fx_portfolio',
550
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
551
+ django.db.models.expressions.CombinedExpression(models.F('currency_fx_rate'), '*',
552
+ models.F('price_gross')), '*', models.F('shares')),
553
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
554
+ ),
555
+ migrations.AlterField(
556
+ model_name='trade',
557
+ name='price',
558
+ field=models.DecimalField(decimal_places=4, help_text='The price per share.', max_digits=16,
559
+ verbose_name='Price'),
560
+ ),
561
+ migrations.AddField(
562
+ model_name='fees',
563
+ name='total_value_fx_portfolio',
564
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
565
+ models.F('currency_fx_rate'), '*', models.F('total_value')),
566
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
567
+ ),
568
+ migrations.AddField(
569
+ model_name='fees',
570
+ name='total_value_gross_fx_portfolio',
571
+ field=models.GeneratedField(db_persist=True, expression=django.db.models.expressions.CombinedExpression(
572
+ models.F('currency_fx_rate'), '*', models.F('total_value_gross')),
573
+ output_field=models.DecimalField(decimal_places=4, max_digits=20)),
574
+ ),
575
+
576
+ # cleanup
577
+ migrations.RemoveField(
578
+ model_name='transaction',
579
+ name='currency',
580
+ ),
581
+ migrations.RemoveField(
582
+ model_name='transaction',
583
+ name='import_source',
584
+ ),
585
+ migrations.RemoveField(
586
+ model_name='transaction',
587
+ name='portfolio',
588
+ ),
589
+ migrations.RemoveField(
590
+ model_name='transaction',
591
+ name='underlying_instrument',
592
+ ),
593
+ migrations.DeleteModel(
594
+ name='Transaction',
595
+ ),
596
+ migrations.AddIndex(
597
+ model_name='fees',
598
+ index=models.Index(fields=['product'], name='wbportfolio_product_daf107_idx'),
599
+ ),
600
+ migrations.AddIndex(
601
+ model_name='fees',
602
+ index=models.Index(fields=['transaction_subtype', 'product', 'fee_date', 'calculated'],
603
+ name='wbportfolio_transac_7355c2_idx'),
604
+ ),
605
+ migrations.AddIndex(
606
+ model_name='trade',
607
+ index=models.Index(fields=['underlying_instrument', 'transaction_date'],
608
+ name='wbportfolio_underly_a0f0ff_idx'),
609
+ ),
610
+ migrations.AddIndex(
611
+ model_name='trade',
612
+ index=models.Index(fields=['portfolio', 'underlying_instrument', 'transaction_date'],
613
+ name='wbportfolio_portfol_6a42a2_idx'),
614
+ ),
615
+ migrations.RunPython(remove_duplicate),
616
+ migrations.AddConstraint(
617
+ model_name='trade',
618
+ constraint=models.UniqueConstraint(condition=models.Q(('trade_proposal__isnull', False)),
619
+ fields=('portfolio', 'transaction_date', 'underlying_instrument'),
620
+ name='unique_manual_trade'),
621
+ ),
622
+ ]
@@ -966,7 +966,7 @@ class LiquidityStressMixin:
966
966
 
967
967
  qs_trades = Trade.objects.filter(
968
968
  underlying_instrument__in=product_ids,
969
- transaction_subtype__in=["SUBSCRIPTION", "REDEMPTION"],
969
+ type__in=["SUBSCRIPTION", "REDEMPTION"],
970
970
  transaction_date__lte=report_date,
971
971
  ).order_by("transaction_date")
972
972
  if not qs_trades.exists():
@@ -974,7 +974,7 @@ class LiquidityStressMixin:
974
974
 
975
975
  trades_fields = [
976
976
  "transaction_date",
977
- "transaction_subtype",
977
+ "type",
978
978
  "underlying_instrument",
979
979
  "underlying_instrument__currency",
980
980
  "total_value",
@@ -999,7 +999,7 @@ class LiquidityStressMixin:
999
999
 
1000
1000
  # df_trades.transaction_date = pd.to_datetime(df_trades["transaction_date"]) # to use df.rolling
1001
1001
  # Gross Redemption
1002
- df_gross_redemption = df_trades.where(df_trades.transaction_subtype == "REDEMPTION")
1002
+ df_gross_redemption = df_trades.where(df_trades.type == "REDEMPTION")
1003
1003
  df_gross_redemption = df_gross_redemption.groupby("date").total_value_usd.sum()
1004
1004
  df_gross_redemption.name = "gross_redemption"
1005
1005
  df_gross_redemption = df_aum.join(df_gross_redemption)
@@ -1,8 +1,6 @@
1
1
  from .claim import Claim
2
2
  from .dividends import DividendTransaction
3
- from .expiry import Expiry
4
3
  from .fees import FeeCalculation, Fees
5
4
  from .trade_proposals import TradeProposal
6
5
  from .rebalancing import RebalancingModel, Rebalancer
7
6
  from .trades import Trade
8
- from .transactions import Transaction
@@ -477,7 +477,7 @@ class Claim(ReferenceIDMixin, WBModel):
477
477
  # Find trades by external_id
478
478
  if not auto_match_trade and self.external_id and trades.count() > 1:
479
479
  trades = trades.filter(
480
- Q(external_id__icontains=self.external_id) | Q(external_identifier2__icontains=self.external_id)
480
+ Q(external_id__icontains=self.external_id) | Q(external_id_alternative__icontains=self.external_id)
481
481
  )
482
482
  if trades.count() == 1:
483
483
  auto_match_trade = trades.first()