everysk-lib 1.10.2__cp312-cp312-win_amd64.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.
Files changed (137) hide show
  1. everysk/__init__.py +30 -0
  2. everysk/_version.py +683 -0
  3. everysk/api/__init__.py +61 -0
  4. everysk/api/api_requestor.py +167 -0
  5. everysk/api/api_resources/__init__.py +23 -0
  6. everysk/api/api_resources/api_resource.py +371 -0
  7. everysk/api/api_resources/calculation.py +779 -0
  8. everysk/api/api_resources/custom_index.py +42 -0
  9. everysk/api/api_resources/datastore.py +81 -0
  10. everysk/api/api_resources/file.py +42 -0
  11. everysk/api/api_resources/market_data.py +223 -0
  12. everysk/api/api_resources/parser.py +66 -0
  13. everysk/api/api_resources/portfolio.py +43 -0
  14. everysk/api/api_resources/private_security.py +42 -0
  15. everysk/api/api_resources/report.py +65 -0
  16. everysk/api/api_resources/report_template.py +39 -0
  17. everysk/api/api_resources/tests.py +115 -0
  18. everysk/api/api_resources/worker_execution.py +64 -0
  19. everysk/api/api_resources/workflow.py +65 -0
  20. everysk/api/api_resources/workflow_execution.py +93 -0
  21. everysk/api/api_resources/workspace.py +42 -0
  22. everysk/api/http_client.py +63 -0
  23. everysk/api/tests.py +32 -0
  24. everysk/api/utils.py +262 -0
  25. everysk/config.py +451 -0
  26. everysk/core/_tests/serialize/test_json.py +336 -0
  27. everysk/core/_tests/serialize/test_orjson.py +295 -0
  28. everysk/core/_tests/serialize/test_pickle.py +48 -0
  29. everysk/core/cloud_function/main.py +78 -0
  30. everysk/core/cloud_function/tests.py +86 -0
  31. everysk/core/compress.py +245 -0
  32. everysk/core/datetime/__init__.py +12 -0
  33. everysk/core/datetime/calendar.py +144 -0
  34. everysk/core/datetime/date.py +424 -0
  35. everysk/core/datetime/date_expression.py +299 -0
  36. everysk/core/datetime/date_mixin.py +1475 -0
  37. everysk/core/datetime/date_settings.py +30 -0
  38. everysk/core/datetime/datetime.py +713 -0
  39. everysk/core/exceptions.py +435 -0
  40. everysk/core/fields.py +1176 -0
  41. everysk/core/firestore.py +555 -0
  42. everysk/core/fixtures/_settings.py +29 -0
  43. everysk/core/fixtures/other/_settings.py +18 -0
  44. everysk/core/fixtures/user_agents.json +88 -0
  45. everysk/core/http.py +691 -0
  46. everysk/core/lists.py +92 -0
  47. everysk/core/log.py +709 -0
  48. everysk/core/number.py +37 -0
  49. everysk/core/object.py +1469 -0
  50. everysk/core/redis.py +1021 -0
  51. everysk/core/retry.py +51 -0
  52. everysk/core/serialize.py +674 -0
  53. everysk/core/sftp.py +414 -0
  54. everysk/core/signing.py +53 -0
  55. everysk/core/slack.py +127 -0
  56. everysk/core/string.py +199 -0
  57. everysk/core/tests.py +240 -0
  58. everysk/core/threads.py +199 -0
  59. everysk/core/undefined.py +70 -0
  60. everysk/core/unittests.py +73 -0
  61. everysk/core/workers.py +241 -0
  62. everysk/sdk/__init__.py +23 -0
  63. everysk/sdk/base.py +98 -0
  64. everysk/sdk/brutils/cnpj.py +391 -0
  65. everysk/sdk/brutils/cnpj_pd.py +129 -0
  66. everysk/sdk/engines/__init__.py +26 -0
  67. everysk/sdk/engines/cache.py +185 -0
  68. everysk/sdk/engines/compliance.py +37 -0
  69. everysk/sdk/engines/cryptography.py +69 -0
  70. everysk/sdk/engines/expression.cp312-win_amd64.pyd +0 -0
  71. everysk/sdk/engines/expression.pyi +55 -0
  72. everysk/sdk/engines/helpers.cp312-win_amd64.pyd +0 -0
  73. everysk/sdk/engines/helpers.pyi +26 -0
  74. everysk/sdk/engines/lock.py +120 -0
  75. everysk/sdk/engines/market_data.py +244 -0
  76. everysk/sdk/engines/settings.py +19 -0
  77. everysk/sdk/entities/__init__.py +23 -0
  78. everysk/sdk/entities/base.py +784 -0
  79. everysk/sdk/entities/base_list.py +131 -0
  80. everysk/sdk/entities/custom_index/base.py +209 -0
  81. everysk/sdk/entities/custom_index/settings.py +29 -0
  82. everysk/sdk/entities/datastore/base.py +160 -0
  83. everysk/sdk/entities/datastore/settings.py +17 -0
  84. everysk/sdk/entities/fields.py +375 -0
  85. everysk/sdk/entities/file/base.py +215 -0
  86. everysk/sdk/entities/file/settings.py +63 -0
  87. everysk/sdk/entities/portfolio/base.py +248 -0
  88. everysk/sdk/entities/portfolio/securities.py +241 -0
  89. everysk/sdk/entities/portfolio/security.py +580 -0
  90. everysk/sdk/entities/portfolio/settings.py +97 -0
  91. everysk/sdk/entities/private_security/base.py +226 -0
  92. everysk/sdk/entities/private_security/settings.py +17 -0
  93. everysk/sdk/entities/query.py +603 -0
  94. everysk/sdk/entities/report/base.py +214 -0
  95. everysk/sdk/entities/report/settings.py +23 -0
  96. everysk/sdk/entities/script.py +310 -0
  97. everysk/sdk/entities/secrets/base.py +128 -0
  98. everysk/sdk/entities/secrets/script.py +119 -0
  99. everysk/sdk/entities/secrets/settings.py +17 -0
  100. everysk/sdk/entities/settings.py +48 -0
  101. everysk/sdk/entities/tags.py +174 -0
  102. everysk/sdk/entities/worker_execution/base.py +307 -0
  103. everysk/sdk/entities/worker_execution/settings.py +63 -0
  104. everysk/sdk/entities/workflow_execution/base.py +113 -0
  105. everysk/sdk/entities/workflow_execution/settings.py +32 -0
  106. everysk/sdk/entities/workspace/base.py +99 -0
  107. everysk/sdk/entities/workspace/settings.py +27 -0
  108. everysk/sdk/settings.py +67 -0
  109. everysk/sdk/tests.py +105 -0
  110. everysk/sdk/worker_base.py +47 -0
  111. everysk/server/__init__.py +9 -0
  112. everysk/server/applications.py +63 -0
  113. everysk/server/endpoints.py +516 -0
  114. everysk/server/example_api.py +69 -0
  115. everysk/server/middlewares.py +80 -0
  116. everysk/server/requests.py +62 -0
  117. everysk/server/responses.py +119 -0
  118. everysk/server/routing.py +64 -0
  119. everysk/server/settings.py +36 -0
  120. everysk/server/tests.py +36 -0
  121. everysk/settings.py +98 -0
  122. everysk/sql/__init__.py +9 -0
  123. everysk/sql/connection.py +232 -0
  124. everysk/sql/model.py +376 -0
  125. everysk/sql/query.py +417 -0
  126. everysk/sql/row_factory.py +63 -0
  127. everysk/sql/settings.py +49 -0
  128. everysk/sql/utils.py +129 -0
  129. everysk/tests.py +23 -0
  130. everysk/utils.py +81 -0
  131. everysk/version.py +15 -0
  132. everysk_lib-1.10.2.dist-info/.gitignore +5 -0
  133. everysk_lib-1.10.2.dist-info/METADATA +326 -0
  134. everysk_lib-1.10.2.dist-info/RECORD +137 -0
  135. everysk_lib-1.10.2.dist-info/WHEEL +5 -0
  136. everysk_lib-1.10.2.dist-info/licenses/LICENSE.txt +9 -0
  137. everysk_lib-1.10.2.dist-info/top_level.txt +2 -0
@@ -0,0 +1,580 @@
1
+ # -*- coding: utf_8 -*-
2
+ ###############################################################################
3
+ #
4
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
5
+ #
6
+ # This is an unpublished work containing confidential and proprietary
7
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
8
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
9
+ #
10
+ ###############################################################################
11
+ from typing import Callable, Any, Self
12
+
13
+ from everysk.config import settings
14
+ from everysk.core.datetime import Date, DateTime
15
+ from everysk.core.fields import DateField, DictField, FloatField, ListField, StrField
16
+ from everysk.core.object import BaseDict, BaseDictConfig, CLASS_KEY
17
+ from everysk.core.exceptions import FieldValueError
18
+ from everysk.sdk.engines import cryptography
19
+ from everysk.sdk.entities.base import BaseSDK
20
+
21
+
22
+ ###############################################################################
23
+ # ExtraDataField Class Implementation
24
+ ###############################################################################
25
+ class ExtraDataField(DictField):
26
+
27
+ def clean_value(self, value: Any) -> Any:
28
+ """
29
+ This function is used to clean the value before it is assigned to the field.
30
+ It can be used to ensure consistency in the data.
31
+ """
32
+ if isinstance(value, dict):
33
+ value = BaseDict(**value)
34
+
35
+ return super().clean_value(value)
36
+
37
+
38
+ ###############################################################################
39
+ # Security Class Implementation
40
+ ###############################################################################
41
+ class Security(BaseDict, BaseSDK):
42
+ """
43
+ This class represents a security entity and its attributes.
44
+
45
+ Attributes:
46
+ status (StrField): The status of the security.
47
+ id (StrField): The unique identifier of the security.
48
+ symbol (StrField): The symbol of the security.
49
+ quantity (FloatField): The quantity of the security.
50
+ instrument_class (StrField): The class of the instrument.
51
+ ticker (StrField): The ticker symbol of the security.
52
+ label (StrField): The label of the security.
53
+ name (StrField): The name of the security.
54
+ isin (StrField): The ISIN (International Securities Identification Number) of the security.
55
+ exchange (StrField): The exchange where the security is traded.
56
+ currency (StrField): The currency of the security.
57
+ fx_rate (FloatField): The foreign exchange rate of the security.
58
+ market_price (FloatField): The market price of the security.
59
+ premium (FloatField): The premium associated with the security.
60
+ market_value (FloatField): The market value of the security.
61
+ market_value_in_base (FloatField): The market value of the security in the base currency.
62
+ instrument_type (StrField): The type of instrument.
63
+ instrument_subtype (StrField): The subtype of the instrument.
64
+ asset_class (StrField): The asset class of the security.
65
+ asset_subclass (StrField): The asset subclass of the security.
66
+ error_type (StrField): The type of error associated with the security.
67
+ error_message (StrField): The error message associated with the security.
68
+ maturity_date (DateField): The maturity date of the security.
69
+ indexer (StrField): The indexer used for the security.
70
+ percent_index (FloatField): The percentage index value.
71
+ rate (FloatField): The rate value.
72
+ coupon (FloatField): The coupon value.
73
+ multiplier (FloatField): The multiplier value.
74
+ underlying (StrField): The underlying asset of the security.
75
+ series (StrField): The series of the security.
76
+ option_type (StrField): The type of option (if applicable).
77
+ strike (FloatField): The strike price (if applicable).
78
+ issue_price (FloatField): The issue price of the security.
79
+ issue_date (DateField): The issue date of the security.
80
+ issuer (StrField): The issuer of the security.
81
+ issuer_type (StrField): The type of issuer.
82
+ cost_price (FloatField): The cost price of the security.
83
+ unrealized_pl (FloatField): The unrealized profit or loss of the security.
84
+ unrealized_pl_in_base (FloatField): The unrealized profit or loss of the security in the base currency.
85
+ book (StrField): The book associated with the security.
86
+ trader (StrField): The trader responsible for the security.
87
+ trade_id (StrField): The trade identifier of the security.
88
+ operation (StrField): The operation related to the security.
89
+ accounting (StrField): The accounting information of the security.
90
+ warranty (FloatField): The warranty associated with the security.
91
+ return_date (DateField): The return date of the security.
92
+ settlement (DateField): The settlement date of the security.
93
+ look_through_reference (StrField): The look-through reference of the security.
94
+ extra_data (DictField): Additional data associated with the security.
95
+ hash (StrField): The hash value of the security.
96
+ display (StrField): The display information of the security.
97
+ comparable (StrField): The comparable information of the security.
98
+ previous_quantity (FloatField): The previous quantity of the security (not sure about its use).
99
+
100
+ Example:
101
+ >>> security = Security()
102
+ >>> security.symbol = 'AAPL'
103
+ >>> security.quantity = 100
104
+ >>> security.market_price = 150.0
105
+ >>> security.currency = 'USD'
106
+ >>> security.name = 'Apple Inc.'
107
+ >>> security.status = 'OK'
108
+ >>> security
109
+ {
110
+ 'status': 'OK',
111
+ 'id': None,
112
+ 'symbol': 'AAPL',
113
+ 'quantity': 100.0,
114
+ 'instrument_class': None,
115
+ 'ticker': None,
116
+ 'label': None,
117
+ 'name': 'Apple Inc.',
118
+ 'isin': None,
119
+ 'exchange': None,
120
+ 'currency': 'USD',
121
+ 'fx_rate': None,
122
+ 'market_price': 150.0,
123
+ 'premium': None,
124
+ 'market_value': None,
125
+ 'market_value_in_base': None,
126
+ 'instrument_type': None,
127
+ 'instrument_subtype': None,
128
+ 'asset_class': None,
129
+ 'asset_subclass': None,
130
+ 'error_type': None,
131
+ 'error_message': None,
132
+ 'maturity_date': None,
133
+ 'indexer': None,
134
+ 'percent_index': None,
135
+ 'rate': None,
136
+ 'coupon': None,
137
+ 'multiplier': None,
138
+ 'underlying': None,
139
+ 'series': None,
140
+ 'option_type': None,
141
+ 'strike': None,
142
+ 'issue_price': None,
143
+ 'issue_date': None,
144
+ 'issuer': None,
145
+ 'issuer_type': None,
146
+ 'cost_price': None,
147
+ 'unrealized_pl': None,
148
+ 'unrealized_pl_in_base': None,
149
+ 'book': None,
150
+ 'trader': None,
151
+ 'trade_id': None,
152
+ 'operation': None,
153
+ 'accounting': None,
154
+ 'warranty': None,
155
+ 'return_date': None,
156
+ 'settlement': None,
157
+ 'look_through_reference': None,
158
+ 'extra_data': None,
159
+ 'hash': None,
160
+ 'display': None,
161
+ 'comparable': None,
162
+ 'previous_quantity': None
163
+ }
164
+ """
165
+ class Config(BaseDictConfig):
166
+ default_status = StrField(default=settings.SECURITY_STATUS_OK, readonly=True)
167
+ valid_status = ListField(default=[settings.SECURITY_STATUS_OK, settings.SECURITY_STATUS_DELISTED], readonly=True)
168
+ exclude_keys: frozenset[str] = frozenset(['_is_frozen', '_silent', '_errors', '_orderable_attributes'])
169
+
170
+ _config: Config = None
171
+ status = StrField()
172
+ id = StrField(required_lazy=True, min_size=1, max_size=settings.SYMBOL_ID_MAX_LEN)
173
+
174
+ symbol = StrField(required_lazy=True, max_size=settings.SYMBOL_MAX_LENGTH)
175
+ quantity = FloatField(required_lazy=True, min_size=settings.QUANTITY_MIN_VALUE, max_size=settings.QUANTITY_MAX_VALUE)
176
+ instrument_class = StrField()
177
+
178
+ ticker = StrField()
179
+ label = StrField(min_size=0, max_size=settings.LABEL_MAX_LENGTH)
180
+ name = StrField()
181
+ isin = StrField(min_size=0, max_size=settings.SYMBOL_MAX_LENGTH)
182
+ exchange = StrField()
183
+ currency = StrField()
184
+ fx_rate = FloatField(min_size=settings.FX_RATE_MIN_VALUE, max_size=settings.FX_RATE_MAX_VALUE)
185
+ market_price = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
186
+ premium = FloatField()
187
+ market_value = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
188
+ market_value_in_base = FloatField()
189
+
190
+ instrument_type = StrField()
191
+ instrument_subtype = StrField()
192
+ asset_class = StrField()
193
+ asset_subclass = StrField()
194
+
195
+ error_type = StrField(min_size=0, max_size=settings.PORTFOLIO_SECURITY_ERROR_TYPE_MAX_LEN)
196
+ error_message = StrField(min_size=0, max_size=settings.PORTFOLIO_SECURITY_ERROR_MESSAGE_MAX_LEN)
197
+
198
+ maturity_date = DateField(empty_is_none=True)
199
+ indexer = StrField()
200
+ percent_index = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
201
+ rate = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
202
+ coupon = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
203
+
204
+ multiplier = FloatField(min_size=settings.MULTIPLIER_MIN_VALUE, max_size=settings.MULTIPLIER_MAX_VALUE)
205
+ underlying = StrField()
206
+ series = StrField()
207
+ option_type = StrField()
208
+ strike = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
209
+
210
+ issue_price = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
211
+ issue_date = DateField(empty_is_none=True)
212
+ issuer = StrField()
213
+ issuer_type = StrField()
214
+
215
+ cost_price = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
216
+ unrealized_pl = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
217
+ unrealized_pl_in_base = FloatField(min_size=settings.PRICE_MIN_VALUE, max_size=settings.PRICE_MAX_VALUE)
218
+
219
+ book = StrField()
220
+ trader = StrField(min_size=0, max_size=settings.PORTFOLIO_SECURITY_TYPE_MAX_LEN)
221
+ trade_id = StrField()
222
+
223
+ operation = StrField()
224
+ accounting = StrField()
225
+ warranty = FloatField(min_size=settings.QUANTITY_MIN_VALUE, max_size=settings.QUANTITY_MAX_VALUE)
226
+
227
+ return_date = DateField(empty_is_none=True)
228
+ settlement = DateField(empty_is_none=True)
229
+
230
+ look_through_reference = StrField()
231
+
232
+ extra_data = ExtraDataField(default=None)
233
+
234
+ hash = StrField()
235
+ display = StrField()
236
+ comparable = StrField()
237
+
238
+ #NOT SURE ABOUT IT
239
+ previous_quantity = FloatField(min_size=settings.QUANTITY_MIN_VALUE, max_size=settings.QUANTITY_MAX_VALUE)
240
+
241
+ def __init__(self, **kwargs):
242
+ kwargs.pop('id_', None)
243
+ kwargs.pop('mic', None)
244
+ kwargs.pop(CLASS_KEY, None)
245
+
246
+ # This creates the Security with all default attributes
247
+ super().__init__()
248
+
249
+ # We check if the extra_data is not initialized
250
+ _extra_data = kwargs.pop('extra_data', None) or BaseDict()
251
+ if not isinstance(_extra_data, (BaseDict, dict)):
252
+ raise FieldValueError(f'attribute extra_data must be a dictionary. {type(_extra_data)}')
253
+
254
+ self.extra_data = BaseDict()
255
+ if _extra_data is not None:
256
+ for extra_key, extra_value in _extra_data.items():
257
+ self._add_extra_data(extra_key, extra_value)
258
+
259
+ for key, value in kwargs.items():
260
+ # If the key already exists in the class we just store it
261
+ if key in self:
262
+ self[key] = value
263
+ # otherwise we store it inside the extra_data key.
264
+ else:
265
+ self._add_extra_data(key, value)
266
+
267
+ # If for some reason the extra_data is empty we convert it to None
268
+ if not self.extra_data:
269
+ self.extra_data = None
270
+
271
+ def _add_extra_data(self, key: str, value: Any) -> None:
272
+ """
273
+ Add an extra data attribute to the security.
274
+
275
+ This method adds an extra data attribute to the security object by storing it in the 'extra_data' dictionary.
276
+
277
+ Args:
278
+ key (str): The key for the extra data attribute.
279
+ value (Any): The value of the extra data attribute.
280
+
281
+ Example:
282
+ >>> security = Security()
283
+ >>> security._add_extra_data('industry', 'Technology')
284
+ >>> security.extra_data
285
+ {'industry': 'Technology'}
286
+ """
287
+ if value is None or isinstance(value, (int, str, bool, float, Date, DateTime)):
288
+ self.extra_data[key] = value
289
+
290
+ def _process_maturity_date(self, value: Date) -> str:
291
+ """
292
+ Converts a Date object to a string.
293
+
294
+ Args:
295
+ value (Date): The Date object to be converted.
296
+
297
+ Returns:
298
+ str: The converted Date, now represented as a string.
299
+
300
+ Example:
301
+ >>> _process_maturity_date(Date(2023, 9, 9))
302
+ '20230909'
303
+ """
304
+ return Date.strftime_or_null(value)
305
+
306
+ def _process_issue_date(self, value: Date) -> str:
307
+ """
308
+ Converts a Date object to a string.
309
+
310
+ Args:
311
+ value (Date): The Date object to be converted.
312
+
313
+ Returns:
314
+ str: The converted Date, now represented as a string.
315
+
316
+ Example:
317
+ >>> _process_issue_date(Date(2023, 9, 9))
318
+ '20230909'
319
+ """
320
+ return Date.strftime_or_null(value)
321
+
322
+ def _process_return_date(self, value: Date) -> str:
323
+ """
324
+ Converts a Date object to a string.
325
+
326
+ Args:
327
+ value (Date): The Date object to be converted.
328
+
329
+ Returns:
330
+ str: The converted Date, now represented as a string.
331
+
332
+ Example:
333
+ >>> _process_return_date(Date(2023, 9, 9))
334
+ '20230909'
335
+ """
336
+ return Date.strftime_or_null(value)
337
+
338
+ def _process_settlement(self, value: Date) -> str:
339
+ """
340
+ Converts a Date object to a string.
341
+
342
+ Args:
343
+ value (Date): The Date object to be converted.
344
+
345
+ Returns:
346
+ str: The converted Data, now represented as a string.
347
+
348
+ Example:
349
+ >>> _process_settlement(Date(2023, 9, 9))
350
+ '20230909'
351
+ """
352
+ return Date.strftime_or_null(value)
353
+
354
+ @staticmethod
355
+ def _get_attr(security: dict, key: str, fallback_func: Callable | None = None) -> Any:
356
+ """
357
+ Get an attribute value from a security dictionary with optional fallback.
358
+
359
+ This static method attempts to retrieve a value associated with a given key from a security dictionary.
360
+ If the key is not found in the main dictionary, it checks if the key exists in the 'extra_data' dictionary
361
+ within the security dictionary. If the key is still not found and a fallback function is provided, the
362
+ fallback function is called to provide a default value.
363
+
364
+ Args:
365
+ security (dict): A dictionary representing a security and its attributes.
366
+ key (str): The key for the attribute value to retrieve.
367
+ fallback_func (Callable | None, optional): A fallback function to call if the key is not found in
368
+ the main or 'extra_data' dictionaries. Defaults to None.
369
+
370
+ Returns:
371
+ Any: The attribute value if found, or the result of the fallback function (if provided), or None.
372
+
373
+ Example:
374
+ >>> from everysk.sdk.entities.portfolio.security import Security
375
+ >>> security_data = {
376
+ ... 'symbol': 'AAPL',
377
+ ... 'name': 'Apple Inc.',
378
+ ... 'extra_data': {'industry': 'Technology'},
379
+ ... }
380
+ >>> symbol = Security._get_attr(security_data, 'symbol')
381
+ >>> industry = Security._get_attr(security_data, 'industry')
382
+ >>> missing_attr = Security._get_attr(security_data, 'missing_attribute', lambda: 'Unknown')
383
+ >>> symbol
384
+ 'AAPL'
385
+ >>> industry
386
+ 'Technology'
387
+ >>> missing_attr
388
+ 'Unknown'
389
+ """
390
+ if key in security:
391
+ return security[key]
392
+
393
+ extra_data: dict = security['extra_data'] or {}
394
+ if key in extra_data:
395
+ return extra_data[key]
396
+
397
+ if fallback_func is not None:
398
+ return fallback_func()
399
+
400
+ return None
401
+
402
+ @staticmethod
403
+ def generate_security_id() -> str:
404
+ """
405
+ Generate a unique security ID.
406
+
407
+ This static method generates a unique security ID by combining a prefix specified in
408
+ 'settings.SECURITY_ID_PREFIX' with a unique identifier of a specified length
409
+ using the 'cryptography.generate_unique_id' function.
410
+
411
+ Returns:
412
+ str: A unique security ID.
413
+
414
+ Example:
415
+ >>> from everysk.sdk.entities.portfolio.security import Security
416
+ >>> unique_id = Security.generate_security_id()
417
+ >>> unique_id
418
+ 'SEC123456789'
419
+ """
420
+ return f'{settings.SECURITY_ID_PREFIX}{cryptography.generate_random_id(length=settings.SECURITY_ID_LENGTH)}'
421
+
422
+ @staticmethod
423
+ def sort_header(header: list[str]) -> list[str]:
424
+ """
425
+ Sort a header list based on a predefined order of properties.
426
+
427
+ This static method takes a list of header strings and sorts them based on a predefined order
428
+ specified in `settings.PORTFOLIO_PROPERTIES_ORDER`. Properties that are not found in the predefined
429
+ order are sorted alphabetically at the end.
430
+
431
+ Args:
432
+ header (list[str]): A list of header strings to be sorted.
433
+
434
+ Returns:
435
+ list[str]: A sorted list of header strings.
436
+
437
+ Example:
438
+ >>> from everysk.sdk.entities.portfolio.security import Security
439
+ >>> header = ['symbol', 'name', 'price', 'quantity']
440
+ >>> sorted_header = Security.sort_header(header)
441
+ >>> sorted_header
442
+ ['quantity', 'name', 'price', 'symbol']
443
+ """
444
+
445
+ def sorting_key(element: str) -> tuple[int, str]:
446
+ try:
447
+ return (settings.PORTFOLIO_PROPERTIES_ORDER.index(element), '')
448
+ except ValueError:
449
+ return (len(settings.PORTFOLIO_PROPERTIES_ORDER), element)
450
+
451
+ return sorted(header, key=sorting_key)
452
+
453
+ def generate_consolidation_key(self, consolidation_keys: str) -> str:
454
+ """
455
+ Generate a consolidation key based on specified attributes.
456
+
457
+ This method generates a consolidation key by extracting values from the security object
458
+ based on the provided consolidation keys. It uses the `_get_attr` method to retrieve
459
+ attribute values, and if a value is missing, it falls back to generating a security ID.
460
+
461
+ Args:
462
+ consolidation_keys (str): A string containing comma-separated attribute keys used for consolidation.
463
+
464
+ Returns:
465
+ str: The consolidation key generated from the specified attributes.
466
+
467
+ Example:
468
+ >>> from everysk.sdk.entities.portfolio.security import Security
469
+ >>> security_data = {
470
+ ... 'symbol': 'AAPL',
471
+ ... 'name': 'Apple Inc.',
472
+ ... 'industry': 'Technology',
473
+ ... 'extra_data': {'country': 'USA'}
474
+ ... }
475
+ >>> security = Security(security_data)
476
+ >>> consolidation_keys = 'symbol,name,industry,country'
477
+ >>> consolidation_key = security.generate_consolidation_key(consolidation_keys)
478
+ >>> consolidation_key
479
+ 'AAPL_Apple Inc._Technology_USA'
480
+ """
481
+ key_: list[Any] = [Security._get_attr(self, key, fallback_func=self.generate_security_id) for key in consolidation_keys]
482
+ key: str = "_".join(str(v) for v in key_)
483
+
484
+ return key
485
+
486
+ @staticmethod
487
+ def from_list(sec_as_list: list[Any], headers: list[str]) -> Self:
488
+ """
489
+ Create a Security object from a list of values and corresponding headers.
490
+
491
+ This static method takes a list of values representing a security's attributes and a list
492
+ of headers specifying the order of attributes. It constructs a Security object using the
493
+ provided values and headers.
494
+
495
+ Args:
496
+ sec_as_list (list[Any]): A list of attribute values for the security.
497
+ headers (list[str]): A list of headers specifying the order of attributes.
498
+
499
+ Returns:
500
+ Self: A new Security object initialized with the provided attribute values.
501
+
502
+ Example:
503
+ >>> from everysk.sdk.entities.portfolio.security import Security
504
+ >>> sec_as_list = ['AAPL', 'Apple Inc.', 150.0, 100]
505
+ >>> headers = ['symbol', 'name', 'market_price', 'quantity']
506
+ >>> security = Security.from_list(sec_as_list, headers)
507
+ >>> security
508
+ {
509
+ 'symbol': 'AAPL',
510
+ 'name': 'Apple Inc.',
511
+ 'market_price': 150.0,
512
+ 'quantity': 100
513
+ }
514
+ """
515
+ return Security(**dict(zip(headers, sec_as_list)))
516
+
517
+ def validate_required_fields(self) -> bool:
518
+ """
519
+ Validate the required fields of the Security object.
520
+
521
+ This method checks if the 'id' attribute is present in the Security object. If not, it generates
522
+ a security ID using the 'generate_security_id' method and assigns it to the 'id' attribute.
523
+ Then, it calls the superclass method to validate other required fields.
524
+
525
+ Returns:
526
+ bool: True if all required fields are valid, False otherwise.
527
+
528
+ Example:
529
+ >>> from everysk.sdk.entities.portfolio.security import Security
530
+ >>> security = Security()
531
+ >>> security.name = 'Apple Inc.'
532
+ >>> security.quantity = 100
533
+ >>> security.market_price = 150.0
534
+ >>> security.validate_required_fields()
535
+ True
536
+ """
537
+ if self.get('id', None) is None:
538
+ self.id = self.generate_security_id()
539
+
540
+ return super().validate_required_fields()
541
+
542
+ def to_list(self, header: list[str] | None = None) -> list[Any]:
543
+ """
544
+ Convert the Security object to a list of attribute values.
545
+
546
+ This method converts the Security object and its attributes to a list of values.
547
+ The order of attributes in the list is determined by the 'header' parameter.
548
+ If 'header' is not provided, it defaults to the sorted order specified by the
549
+ 'Security.sort_header' method.
550
+
551
+ Args:
552
+ header (list[str] | None, optional): A list of attribute keys specifying the order of attributes.
553
+ Defaults to None.
554
+
555
+ Returns:
556
+ list[Any]: A list of attribute values for the Security object.
557
+
558
+ Example:
559
+ >>> from everysk.sdk.entities.portfolio.security import Security
560
+ >>> security = Security()
561
+ >>> security.symbol = 'AAPL'
562
+ >>> security.quantity = 100
563
+ >>> security.market_price = 150.0
564
+ >>> security.name = 'Apple Inc.'
565
+ >>> attribute_list = security.to_list()
566
+ >>> attribute_list
567
+ ['AAPL', 100, 150.0, 'Apple Inc.', # ... (other attributes)]
568
+ """
569
+ if header is None:
570
+ header = Security.sort_header(self.keys())
571
+
572
+ security: dict = self.to_dict(add_class_path=False)
573
+
574
+ return [Security._get_attr(security, key) for key in header]
575
+
576
+ def _process_extra_data(self, value: dict | BaseDict | None) -> dict:
577
+ """
578
+ Process the extra data attribute.
579
+ """
580
+ return value.to_dict() if hasattr(value, 'to_dict') else value
@@ -0,0 +1,97 @@
1
+ ###############################################################################
2
+ #
3
+ # (C) Copyright 2023 EVERYSK TECHNOLOGIES
4
+ #
5
+ # This is an unpublished work containing confidential and proprietary
6
+ # information of EVERYSK TECHNOLOGIES. Disclosure, use, or reproduction
7
+ # without authorization of EVERYSK TECHNOLOGIES is prohibited.
8
+ #
9
+ ###############################################################################
10
+ from everysk.core.fields import FloatField, IntField, ListField, RegexField, StrField
11
+
12
+ PORTFOLIO_ID_REGEX = RegexField(default=r'^port_[a-zA-Z0-9]', readonly=True)
13
+ PORTFOLIO_ID_PREFIX = StrField(default='port_', readonly=True)
14
+ PORTFOLIO_ID_MAX_SIZE = IntField(default=30, readonly=True) # len(PORTFOLIO_ID_PREFIX) + ENTITY_ID_LENGTH
15
+
16
+ PORTFOLIO_MAX_SIZE = IntField(default=40000, readonly=True)
17
+ PORTFOLIO_LEVEL_MAX_LENGTH = IntField(default=32, readonly=True)
18
+
19
+ SECURITY_STATUS_OK = StrField(default='OK', readonly=True)
20
+ SECURITY_STATUS_ERROR = StrField(default='ERROR', readonly=True)
21
+ SECURITY_STATUS_DELISTED = StrField(default='DELISTED', readonly=True)
22
+ SECURITY_ID_LENGTH = IntField(default=6, readonly=True)
23
+ SECURITY_ID_PREFIX = StrField(default='sec_', readonly=True)
24
+ SYMBOL_ID_MAX_LEN = IntField(default=100, readonly=True)
25
+
26
+ PRICE_MIN_VALUE = FloatField(default=-9999999999999.99, readonly=True)
27
+ PRICE_MAX_VALUE = FloatField(default=+9999999999999.99, readonly=True)
28
+
29
+ FX_RATE_MIN_VALUE = FloatField(default=0.0, readonly=True)
30
+ FX_RATE_MAX_VALUE = FloatField(default=+9999999999999.99, readonly=True)
31
+
32
+ MULTIPLIER_MIN_VALUE = FloatField(default=0.0, readonly=True)
33
+ MULTIPLIER_MAX_VALUE = FloatField(default=+9999999999999.99, readonly=True)
34
+
35
+ QUANTITY_MIN_VALUE = FloatField(default=-9999999999999.99, readonly=True)
36
+ QUANTITY_MAX_VALUE = FloatField(default=+9999999999999.99, readonly=True)
37
+
38
+ SYMBOL_MAX_LENGTH = IntField(default=100, readonly=True)
39
+ LABEL_MAX_LENGTH = IntField(default=100, readonly=True)
40
+
41
+ PORTFOLIO_SECURITY_ERROR_TYPE_MAX_LEN = IntField(default=100, readonly=True)
42
+ PORTFOLIO_SECURITY_ERROR_MESSAGE_MAX_LEN = IntField(default=500, readonly=True)
43
+ PORTFOLIO_SECURITY_TYPE_MAX_LEN = IntField(default=100, readonly=True)
44
+
45
+ PORTFOLIO_PROPERTIES_ORDER = ListField(
46
+ default=[
47
+ 'status',
48
+ 'id',
49
+ 'symbol',
50
+ 'quantity',
51
+ 'instrument_class',
52
+ 'ticker',
53
+ 'label',
54
+ 'name',
55
+ 'isin',
56
+ 'exchange',
57
+ 'currency',
58
+ 'fx_rate',
59
+ 'market_price',
60
+ 'market_value',
61
+ 'instrument_type',
62
+ 'instrument_subtype',
63
+ 'asset_class',
64
+ 'asset_subclass',
65
+ 'error_type',
66
+ 'error_message',
67
+ 'maturity_date',
68
+ 'indexer',
69
+ 'percent_index',
70
+ 'rate',
71
+ 'coupon',
72
+ 'multiplier',
73
+ 'underlying',
74
+ 'series',
75
+ 'option_type',
76
+ 'strike',
77
+ 'issue_price',
78
+ 'issue_date',
79
+ 'issuer',
80
+ 'issuer_type',
81
+ 'cost_price',
82
+ 'unrealized_pl',
83
+ 'unrealized_pl_in_base',
84
+ 'book',
85
+ 'trader',
86
+ 'trade_id',
87
+ 'operation',
88
+ 'accounting',
89
+ 'warranty',
90
+ 'return_date',
91
+ 'settlement',
92
+ 'look_through_reference',
93
+ 'extra_data',
94
+ 'hash',
95
+ ],
96
+ readonly=True,
97
+ )