onetick-py 1.162.2__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.
Files changed (152) hide show
  1. locator_parser/__init__.py +0 -0
  2. locator_parser/acl.py +73 -0
  3. locator_parser/actions.py +266 -0
  4. locator_parser/common.py +365 -0
  5. locator_parser/io.py +41 -0
  6. locator_parser/locator.py +150 -0
  7. onetick/__init__.py +101 -0
  8. onetick/doc_utilities/__init__.py +3 -0
  9. onetick/doc_utilities/napoleon.py +40 -0
  10. onetick/doc_utilities/ot_doctest.py +140 -0
  11. onetick/doc_utilities/snippets.py +280 -0
  12. onetick/lib/__init__.py +4 -0
  13. onetick/lib/instance.py +138 -0
  14. onetick/py/__init__.py +290 -0
  15. onetick/py/_stack_info.py +89 -0
  16. onetick/py/_version.py +2 -0
  17. onetick/py/aggregations/__init__.py +11 -0
  18. onetick/py/aggregations/_base.py +645 -0
  19. onetick/py/aggregations/_docs.py +912 -0
  20. onetick/py/aggregations/compute.py +286 -0
  21. onetick/py/aggregations/functions.py +2216 -0
  22. onetick/py/aggregations/generic.py +104 -0
  23. onetick/py/aggregations/high_low.py +80 -0
  24. onetick/py/aggregations/num_distinct.py +83 -0
  25. onetick/py/aggregations/order_book.py +427 -0
  26. onetick/py/aggregations/other.py +1014 -0
  27. onetick/py/backports.py +26 -0
  28. onetick/py/cache.py +373 -0
  29. onetick/py/callback/__init__.py +5 -0
  30. onetick/py/callback/callback.py +275 -0
  31. onetick/py/callback/callbacks.py +131 -0
  32. onetick/py/compatibility.py +752 -0
  33. onetick/py/configuration.py +736 -0
  34. onetick/py/core/__init__.py +0 -0
  35. onetick/py/core/_csv_inspector.py +93 -0
  36. onetick/py/core/_internal/__init__.py +0 -0
  37. onetick/py/core/_internal/_manually_bound_value.py +6 -0
  38. onetick/py/core/_internal/_nodes_history.py +250 -0
  39. onetick/py/core/_internal/_op_utils/__init__.py +0 -0
  40. onetick/py/core/_internal/_op_utils/every_operand.py +9 -0
  41. onetick/py/core/_internal/_op_utils/is_const.py +10 -0
  42. onetick/py/core/_internal/_per_tick_scripts/tick_list_sort_template.script +121 -0
  43. onetick/py/core/_internal/_proxy_node.py +140 -0
  44. onetick/py/core/_internal/_state_objects.py +2307 -0
  45. onetick/py/core/_internal/_state_vars.py +87 -0
  46. onetick/py/core/_source/__init__.py +0 -0
  47. onetick/py/core/_source/_symbol_param.py +95 -0
  48. onetick/py/core/_source/schema.py +97 -0
  49. onetick/py/core/_source/source_methods/__init__.py +0 -0
  50. onetick/py/core/_source/source_methods/aggregations.py +810 -0
  51. onetick/py/core/_source/source_methods/applyers.py +296 -0
  52. onetick/py/core/_source/source_methods/columns.py +141 -0
  53. onetick/py/core/_source/source_methods/data_quality.py +301 -0
  54. onetick/py/core/_source/source_methods/debugs.py +270 -0
  55. onetick/py/core/_source/source_methods/drops.py +120 -0
  56. onetick/py/core/_source/source_methods/fields.py +619 -0
  57. onetick/py/core/_source/source_methods/filters.py +1001 -0
  58. onetick/py/core/_source/source_methods/joins.py +1393 -0
  59. onetick/py/core/_source/source_methods/merges.py +566 -0
  60. onetick/py/core/_source/source_methods/misc.py +1325 -0
  61. onetick/py/core/_source/source_methods/pandases.py +155 -0
  62. onetick/py/core/_source/source_methods/renames.py +356 -0
  63. onetick/py/core/_source/source_methods/sorts.py +183 -0
  64. onetick/py/core/_source/source_methods/switches.py +142 -0
  65. onetick/py/core/_source/source_methods/symbols.py +117 -0
  66. onetick/py/core/_source/source_methods/times.py +627 -0
  67. onetick/py/core/_source/source_methods/writes.py +702 -0
  68. onetick/py/core/_source/symbol.py +202 -0
  69. onetick/py/core/_source/tmp_otq.py +222 -0
  70. onetick/py/core/column.py +209 -0
  71. onetick/py/core/column_operations/__init__.py +0 -0
  72. onetick/py/core/column_operations/_methods/__init__.py +4 -0
  73. onetick/py/core/column_operations/_methods/_internal.py +28 -0
  74. onetick/py/core/column_operations/_methods/conversions.py +215 -0
  75. onetick/py/core/column_operations/_methods/methods.py +294 -0
  76. onetick/py/core/column_operations/_methods/op_types.py +150 -0
  77. onetick/py/core/column_operations/accessors/__init__.py +0 -0
  78. onetick/py/core/column_operations/accessors/_accessor.py +30 -0
  79. onetick/py/core/column_operations/accessors/decimal_accessor.py +92 -0
  80. onetick/py/core/column_operations/accessors/dt_accessor.py +464 -0
  81. onetick/py/core/column_operations/accessors/float_accessor.py +160 -0
  82. onetick/py/core/column_operations/accessors/str_accessor.py +1374 -0
  83. onetick/py/core/column_operations/base.py +1061 -0
  84. onetick/py/core/cut_builder.py +149 -0
  85. onetick/py/core/db_constants.py +20 -0
  86. onetick/py/core/eval_query.py +244 -0
  87. onetick/py/core/lambda_object.py +442 -0
  88. onetick/py/core/multi_output_source.py +193 -0
  89. onetick/py/core/per_tick_script.py +2253 -0
  90. onetick/py/core/query_inspector.py +465 -0
  91. onetick/py/core/source.py +1663 -0
  92. onetick/py/db/__init__.py +2 -0
  93. onetick/py/db/_inspection.py +1042 -0
  94. onetick/py/db/db.py +1423 -0
  95. onetick/py/db/utils.py +64 -0
  96. onetick/py/docs/__init__.py +0 -0
  97. onetick/py/docs/docstring_parser.py +112 -0
  98. onetick/py/docs/utils.py +81 -0
  99. onetick/py/functions.py +2354 -0
  100. onetick/py/license.py +188 -0
  101. onetick/py/log.py +88 -0
  102. onetick/py/math.py +947 -0
  103. onetick/py/misc.py +437 -0
  104. onetick/py/oqd/__init__.py +22 -0
  105. onetick/py/oqd/eps.py +1195 -0
  106. onetick/py/oqd/sources.py +325 -0
  107. onetick/py/otq.py +211 -0
  108. onetick/py/pyomd_mock.py +47 -0
  109. onetick/py/run.py +841 -0
  110. onetick/py/servers.py +173 -0
  111. onetick/py/session.py +1342 -0
  112. onetick/py/sources/__init__.py +19 -0
  113. onetick/py/sources/cache.py +167 -0
  114. onetick/py/sources/common.py +126 -0
  115. onetick/py/sources/csv.py +642 -0
  116. onetick/py/sources/custom.py +85 -0
  117. onetick/py/sources/data_file.py +305 -0
  118. onetick/py/sources/data_source.py +1049 -0
  119. onetick/py/sources/empty.py +94 -0
  120. onetick/py/sources/odbc.py +337 -0
  121. onetick/py/sources/order_book.py +238 -0
  122. onetick/py/sources/parquet.py +168 -0
  123. onetick/py/sources/pit.py +191 -0
  124. onetick/py/sources/query.py +495 -0
  125. onetick/py/sources/snapshots.py +419 -0
  126. onetick/py/sources/split_query_output_by_symbol.py +198 -0
  127. onetick/py/sources/symbology_mapping.py +123 -0
  128. onetick/py/sources/symbols.py +357 -0
  129. onetick/py/sources/ticks.py +825 -0
  130. onetick/py/sql.py +70 -0
  131. onetick/py/state.py +256 -0
  132. onetick/py/types.py +2056 -0
  133. onetick/py/utils/__init__.py +70 -0
  134. onetick/py/utils/acl.py +93 -0
  135. onetick/py/utils/config.py +186 -0
  136. onetick/py/utils/default.py +49 -0
  137. onetick/py/utils/file.py +38 -0
  138. onetick/py/utils/helpers.py +76 -0
  139. onetick/py/utils/locator.py +94 -0
  140. onetick/py/utils/perf.py +499 -0
  141. onetick/py/utils/query.py +49 -0
  142. onetick/py/utils/render.py +1139 -0
  143. onetick/py/utils/script.py +244 -0
  144. onetick/py/utils/temp.py +471 -0
  145. onetick/py/utils/types.py +118 -0
  146. onetick/py/utils/tz.py +82 -0
  147. onetick_py-1.162.2.dist-info/METADATA +148 -0
  148. onetick_py-1.162.2.dist-info/RECORD +152 -0
  149. onetick_py-1.162.2.dist-info/WHEEL +5 -0
  150. onetick_py-1.162.2.dist-info/entry_points.txt +2 -0
  151. onetick_py-1.162.2.dist-info/licenses/LICENSE +21 -0
  152. onetick_py-1.162.2.dist-info/top_level.txt +2 -0
@@ -0,0 +1,1061 @@
1
+ import copy
2
+ import warnings
3
+ from typing import Type, Sequence
4
+
5
+ from onetick.py import types as ott
6
+ from onetick.py.core.column_operations import _methods
7
+
8
+ from onetick.py.core.column_operations._methods.op_types import (
9
+ are_ints_not_time,
10
+ are_time,
11
+ are_floats,
12
+ are_strings
13
+ )
14
+ from onetick.py.core.column_operations._methods.methods import DatetimeSubtractionWarning
15
+
16
+
17
+ class Expr:
18
+ """
19
+ EP parameter's value can be set to an expression.
20
+ Expressions are evaluated before parameters are actually passed to event processors.
21
+
22
+ See also
23
+ --------
24
+ :py:attr:`onetick.py.Operation.expr`
25
+ """
26
+ def __init__(self, operation):
27
+ self.operation = operation
28
+
29
+ def __str__(self):
30
+ return f'expr({str(self.operation)})'
31
+
32
+ def __repr__(self):
33
+ """onetick.query_webapi calls repr() on the object to get the string representation of the object"""
34
+ # TODO
35
+ from onetick.py.otq import otq
36
+ return otq.onetick_repr(self.__str__())
37
+
38
+
39
+ class Operation:
40
+ """
41
+ :py:class:`~onetick.py.Source` column operation container.
42
+
43
+ This is the object you get when applying most operations on :py:class:`~onetick.py.Column`
44
+ or on other operations.
45
+ Eventually you can add a new column using the operation you got or pass it as a parameter
46
+ to some functions.
47
+
48
+ Examples
49
+ --------
50
+ >>> t = otp.Tick(A=1)
51
+ >>> t['A']
52
+ Column(A, <class 'int'>)
53
+ >>> t['A'] / 2
54
+ Operation((A) / (2))
55
+ >>> t['B'] = t['A'] / 2
56
+ >>> t['B']
57
+ Column(B, <class 'float'>)
58
+ """
59
+ emulation_enabled = False
60
+
61
+ def __init__(self, op_func=None, op_params=None, dtype=None, obj_ref=None, op_str=None):
62
+ self._op_func = op_func
63
+ self._op_params = op_params
64
+ self.obj_ref = obj_ref
65
+ self.__warnings = []
66
+ if op_func:
67
+ if op_str:
68
+ raise ValueError("You should specify either op_func or op_str")
69
+ with warnings.catch_warnings(record=True) as warning_list:
70
+ # we want to raise this warning only in some cases
71
+ # that's why we're catching it and saving for later use
72
+ warnings.simplefilter('always', category=DatetimeSubtractionWarning)
73
+ op_str, dtype = self._evaluate_func()
74
+
75
+ for w in warning_list:
76
+ if w.category is DatetimeSubtractionWarning:
77
+ self.__warnings.append(w)
78
+ else:
79
+ warnings.warn_explicit(w.message, w.category, w.filename, w.lineno)
80
+
81
+ self._op_str = op_str
82
+ self._dtype = dtype
83
+
84
+ def __bool__(self):
85
+ if Operation.emulation_enabled:
86
+ # True is default for classes without overriden __bool__
87
+ return True
88
+ raise TypeError('It is not allowed to use compare in if-else and while clauses')
89
+
90
+ def __str__(self):
91
+ return self.op_str
92
+
93
+ def __repr__(self):
94
+ return f"Operation({str(self)})"
95
+
96
+ @property
97
+ def dtype(self):
98
+ """
99
+ Returns the type of the column or operation.
100
+
101
+ See also
102
+ --------
103
+ :py:meth:`Source.schema <onetick.py.Source.schema>`
104
+
105
+ Examples
106
+ --------
107
+ >>> t = otp.Tick(A=1, B=2.3, C='3')
108
+ >>> t['TIMESTAMP'].dtype
109
+ <class 'onetick.py.types.nsectime'>
110
+ >>> t['A'].dtype
111
+ <class 'int'>
112
+ >>> t['B'].dtype
113
+ <class 'float'>
114
+ >>> t['C'].dtype
115
+ <class 'str'>
116
+ """
117
+ dtype = self._dtype
118
+ if not dtype:
119
+ _, dtype = self._evaluate_func(set_fields=True)
120
+ return dtype
121
+
122
+ @property
123
+ def op_str(self):
124
+ for w in self.__warnings:
125
+ warnings.showwarning(w.message, w.category, w.filename, w.lineno)
126
+ op_str = self._op_str
127
+ if not op_str:
128
+ op_str, _ = self._evaluate_func(set_fields=True)
129
+ return op_str
130
+
131
+ @property
132
+ def expr(self):
133
+ """
134
+ Get expression to use in EP parameters.
135
+
136
+ See also
137
+ --------
138
+ :py:class:`~onetick.py.core.column_operations.base.Expr`
139
+ """
140
+ return Expr(self)
141
+
142
+ def round(self, precision=None):
143
+ """
144
+ Rounds input column with specified `precision`.
145
+
146
+ Parameters
147
+ ----------
148
+ precision: int
149
+ Number from -12 to 12.
150
+ Positive precision is precision after the floating point.
151
+ Negative precision is precision before the floating point.
152
+
153
+ See also
154
+ --------
155
+ __round__
156
+
157
+ Examples
158
+ --------
159
+ >>> t = otp.Tick(A=1234.5678)
160
+ >>> t['B'] = t['A'].round()
161
+ >>> t['C'] = t['A'].round(2)
162
+ >>> t['D'] = t['A'].round(-2)
163
+ >>> otp.run(t)
164
+ Time A B C D
165
+ 0 2003-12-01 1234.5678 1235 1234.57 1200.0
166
+
167
+ Returns
168
+ -------
169
+ Operation
170
+ """
171
+ return round(self, precision)
172
+
173
+ def map(self, arg, default=None):
174
+ """
175
+ Map values of the column to new values according to the mapping in ``arg``.
176
+ If the value is not in the mapping, it is set to the ``default`` value.
177
+ If ``default`` value is not set, it is set to default value for the column type.
178
+
179
+ Parameters
180
+ ----------
181
+ arg: dict
182
+ Mapping from old values to new values.
183
+ All values must have the same type, compatible with the column type.
184
+ default: simple value or Column or Operation
185
+ Default value if no mapping is found in ``arg``.
186
+ By default, it is set to default value for the column type.
187
+ (0 for numbers, empty string for strings, etc.)
188
+
189
+ Examples
190
+ --------
191
+ >>> t = otp.Ticks(A=[1, 2, 3, 4, 5])
192
+ >>> t['B'] = t['A'].map({1: 10, 2: 20, 3: 30})
193
+ >>> otp.run(t)
194
+ Time A B
195
+ 0 2003-12-01 00:00:00.000 1 10
196
+ 1 2003-12-01 00:00:00.001 2 20
197
+ 2 2003-12-01 00:00:00.002 3 30
198
+ 3 2003-12-01 00:00:00.003 4 0
199
+ 4 2003-12-01 00:00:00.004 5 0
200
+
201
+ Example with ``default`` parameter set:
202
+
203
+ >>> t = otp.Ticks(A=[1, 2, 3, 4, 5])
204
+ >>> t['B'] = t['A'].map({1: 10, 2: 20, 3: 30}, default=-1)
205
+ >>> otp.run(t)
206
+ Time A B
207
+ 0 2003-12-01 00:00:00.000 1 10
208
+ 1 2003-12-01 00:00:00.001 2 20
209
+ 2 2003-12-01 00:00:00.002 3 30
210
+ 3 2003-12-01 00:00:00.003 4 -1
211
+ 4 2003-12-01 00:00:00.004 5 -1
212
+
213
+ ``default`` parameter can also be an :py:class:`~onetick.py.Operation` or :py:class:`~onetick.py.Column`.
214
+ For example, to keep unmapped values:
215
+
216
+ >>> t = otp.Ticks(A=[1, 2, 3, 4, 5])
217
+ >>> t['B'] = t['A'].map({1: 10, 2: 20, 3: 30}, default=t['A'])
218
+ >>> otp.run(t)
219
+ Time A B
220
+ 0 2003-12-01 00:00:00.000 1 10
221
+ 1 2003-12-01 00:00:00.001 2 20
222
+ 2 2003-12-01 00:00:00.002 3 30
223
+ 3 2003-12-01 00:00:00.003 4 4
224
+ 4 2003-12-01 00:00:00.004 5 5
225
+
226
+ Returns
227
+ -------
228
+ Operation
229
+ """
230
+ if not isinstance(arg, dict) or not arg:
231
+ raise TypeError("map() argument must be a dict with keys and values to map")
232
+
233
+ try:
234
+ values_type = ott.get_type_by_objects(arg.values())
235
+ except TypeError as e:
236
+ raise TypeError("map() argument must be a dict with same types for all values") from e
237
+
238
+ if default is not None:
239
+ try:
240
+ default_type = ott.get_type_by_objects([default])
241
+ ott.get_type_by_objects([default_type, values_type])
242
+ except TypeError as e:
243
+ raise TypeError(
244
+ f"map() default value type {default_type} must be compatible with values type {values_type}"
245
+ ) from e
246
+
247
+ try:
248
+ keys_type = ott.get_type_by_objects(arg.keys())
249
+ except TypeError as e:
250
+ raise TypeError("map() argument must be a dict with same types for all keys") from e
251
+
252
+ try:
253
+ ott.get_type_by_objects([keys_type, self.dtype])
254
+ except TypeError as e:
255
+ raise TypeError(f"map() keys type {keys_type} must be compatible with column type {self.dtype}") from e
256
+
257
+ return _Operation(_methods._map, [self, arg, values_type, default])
258
+
259
+ def apply(self, lambda_f):
260
+ """
261
+ Apply function or type to column
262
+
263
+ Parameters
264
+ ----------
265
+ lambda_f: type or callable
266
+ if type - will convert column to requested type
267
+
268
+ if callable - will translate python code to similar OneTick's CASE expression.
269
+ There are some limitations to which python operators can be used in this callable.
270
+ See :ref:`Python callables parsing guide <python callable parser>` article for details.
271
+ In :ref:`Remote OTP with Ray<ray-remote>` any `Callable` must be decorated with `@otp.remote` decorator,
272
+ see :ref:`Ray usage examples<apply-remote-context>` for details.
273
+
274
+ Examples
275
+ --------
276
+ Converting type of the column, e.g. string column to integer:
277
+
278
+ >>> data = otp.Ticks({'A': ['1', '2', '3']})
279
+ >>> data['B'] = data['A'].apply(int) + 10 # OTdirective: snippet-name: column operations.type convertation;
280
+ >>> otp.run(data)
281
+ Time A B
282
+ 0 2003-12-01 00:00:00.000 1 11
283
+ 1 2003-12-01 00:00:00.001 2 12
284
+ 2 2003-12-01 00:00:00.002 3 13
285
+
286
+ More complicated logic:
287
+
288
+ >>> data = otp.Ticks({'A': [-321, 0, 123]})
289
+ >>> data['SIGN'] = data['A'].apply(lambda x: 1 if x > 0 else -1 if x < 0 else 0)
290
+ >>> otp.run(data)
291
+ Time A SIGN
292
+ 0 2003-12-01 00:00:00.000 -321 -1
293
+ 1 2003-12-01 00:00:00.001 0 0
294
+ 2 2003-12-01 00:00:00.002 123 1
295
+
296
+ See also
297
+ --------
298
+ :py:meth:`onetick.py.Source.apply`
299
+ :ref:`Python callables parsing guide <python callable parser>`
300
+ """
301
+ if isinstance(lambda_f, Type) and ott.is_type_basic(lambda_f):
302
+ return self._convert_to(lambda_f)
303
+
304
+ from onetick.py.core.lambda_object import apply_lambda
305
+
306
+ return apply_lambda(lambda_f, self)
307
+
308
+ def astype(self, to_type):
309
+ """
310
+ Alias for the :meth:`apply` method with type.
311
+
312
+ See also
313
+ --------
314
+ :meth:`apply`
315
+
316
+ Examples
317
+ --------
318
+ >>> data = otp.Tick(A=1, B=2.2, C='3.3')
319
+ >>> data['A'] = data['A'].astype(str) + 'A'
320
+ >>> data['B'] = data['B'].astype(int) + 1
321
+ >>> data['C'] = data['C'].astype(float) + 0.1
322
+ >>> otp.run(data)
323
+ Time B A C
324
+ 0 2003-12-01 3 1A 3.4
325
+ """
326
+ return self.apply(to_type)
327
+
328
+ def isin(self, *items):
329
+ """
330
+ Check if column's value is in ``items``.
331
+
332
+ Parameters
333
+ ----------
334
+ items
335
+ Possible string or numeric values to be checked against column's value.
336
+ Such values can be passed as the function arguments
337
+ or as the list of such values in the first function argument.
338
+
339
+ Returns
340
+ -------
341
+ Operation
342
+ Returns an :py:class:`onetick.py.Operation` object with the value of 1.0 if
343
+ the column's value was found among ``items`` or 0.0 otherwise.
344
+
345
+ See also
346
+ --------
347
+ :py:meth:`Source.__getitem__`
348
+
349
+ Examples
350
+ --------
351
+
352
+ Passing values as function arguments:
353
+
354
+ >>> data = otp.Ticks(A=['a', 'b', 'c'])
355
+ >>> data['B'] = data['A'].isin('a', 'c')
356
+ >>> otp.run(data)
357
+ Time A B
358
+ 0 2003-12-01 00:00:00.000 a 1.0
359
+ 1 2003-12-01 00:00:00.001 b 0.0
360
+ 2 2003-12-01 00:00:00.002 c 1.0
361
+
362
+ Passing values as a list:
363
+
364
+ >>> data = otp.Ticks(A=['a', 'b', 'c'])
365
+ >>> data['B'] = data['A'].isin(['a', 'c'])
366
+ >>> otp.run(data)
367
+ Time A B
368
+ 0 2003-12-01 00:00:00.000 a 1.0
369
+ 1 2003-12-01 00:00:00.001 b 0.0
370
+ 2 2003-12-01 00:00:00.002 c 1.0
371
+
372
+ This function's result can be used as filter expression:
373
+
374
+ >>> data = otp.Ticks(A=[1, 2, 3, 0])
375
+ >>> yes, no = data[data["A"].isin(0, 1)] # OTdirective: snippet-name: column operations.is in.constant;
376
+ >>> otp.run(yes)[["A"]]
377
+ A
378
+ 0 1
379
+ 1 0
380
+
381
+ :py:class:`Columns <onetick.py.Column>` and :py:class:`operations <onetick.py.Operation>` are also supported:
382
+
383
+ >>> # OTdirective: snippet-name: column operations.is in.from fields;
384
+ >>> data = otp.Ticks(A=["ab", "cv", "bc", "a", "d"], B=["a", "c", "b", "a", "a"])
385
+ >>> yes, no = data[data["A"].isin(data["B"], data["B"] + "b")]
386
+ >>> otp.run(yes)[["A", "B"]]
387
+ A B
388
+ 0 ab a
389
+ 1 a a
390
+ """
391
+ if items and isinstance(items[0], Sequence) and not isinstance(items[0], str):
392
+ if len(items) > 1:
393
+ raise ValueError("If the first argument of isin() function is a list,"
394
+ " it must be the only argument passed to a function.")
395
+ items = items[0]
396
+ return _Operation(_methods.isin, [self, items])
397
+
398
+ def fillna(self, value):
399
+ """
400
+ Fill :py:class:`~onetick.py.nan` values with ``value``.
401
+
402
+ Parameters
403
+ ----------
404
+ value: float, int, :py:class:`~onetick.py.Operation`
405
+ value to use instead :py:class:`~onetick.py.nan`
406
+
407
+ Examples
408
+ --------
409
+
410
+ Replace NaN values with a constant:
411
+
412
+ >>> data = otp.Ticks({'A': [1, otp.nan, 2]})
413
+ >>> data['A'] = data['A'].fillna(100) # OTdirective: snippet-name: column operations.fillna;
414
+ >>> otp.run(data)
415
+ Time A
416
+ 0 2003-12-01 00:00:00.000 1.0
417
+ 1 2003-12-01 00:00:00.001 100.0
418
+ 2 2003-12-01 00:00:00.002 2.0
419
+
420
+ Replace NaN values with a value from the previous tick:
421
+
422
+ >>> data = otp.Ticks({'A': [1, otp.nan, 2]})
423
+ >>> data['A'] = data['A'].fillna(data['A'][-1])
424
+ >>> otp.run(data)
425
+ Time A
426
+ 0 2003-12-01 00:00:00.000 1.0
427
+ 1 2003-12-01 00:00:00.001 1.0
428
+ 2 2003-12-01 00:00:00.002 2.0
429
+ """
430
+ return _Operation(_methods.fillna, [self, value])
431
+
432
+ @property
433
+ def str(self):
434
+ """
435
+ Property that provides access to methods specific to string types.
436
+
437
+ See also
438
+ --------
439
+ :py:class:`otp.string <onetick.py.types.string>`
440
+ """
441
+
442
+ if issubclass(self.dtype, str):
443
+ from onetick.py.core.column_operations.accessors.str_accessor import _StrAccessor
444
+ return _StrAccessor(self)
445
+ else:
446
+ raise TypeError(".str accessor is available only for string type columns")
447
+
448
+ @property
449
+ def dt(self):
450
+ """
451
+ Property that provides access to methods specific to datetime types.
452
+
453
+ See also
454
+ --------
455
+ :py:class:`otp.nsectime <onetick.py.types.nsectime>`
456
+ :py:class:`otp.msectime <onetick.py.types.msectime>`
457
+ """
458
+
459
+ if issubclass(self.dtype, ott.nsectime) \
460
+ or issubclass(self.dtype, ott.msectime):
461
+ from onetick.py.core.column_operations.accessors.dt_accessor import _DtAccessor
462
+ return _DtAccessor(self)
463
+ else:
464
+ raise TypeError(".dt accessor is available only for datetime type columns")
465
+
466
+ @property
467
+ def float(self):
468
+ """
469
+ Property that provides access to
470
+ methods specific to float type.
471
+ """
472
+ if issubclass(self.dtype, float) and self.dtype is not ott.decimal:
473
+ from onetick.py.core.column_operations.accessors.float_accessor import _FloatAccessor
474
+ return _FloatAccessor(self)
475
+ else:
476
+ raise TypeError(".float accessor is available only for float type columns")
477
+
478
+ @property
479
+ def decimal(self):
480
+ """
481
+ Property that provides access to methods specific to decimal type.
482
+
483
+ See also
484
+ --------
485
+ :py:class:`otp.decimal <onetick.py.types.decimal>`
486
+ """
487
+ if self.dtype is ott.decimal:
488
+ from onetick.py.core.column_operations.accessors.decimal_accessor import _DecimalAccessor
489
+ return _DecimalAccessor(self)
490
+ else:
491
+ raise TypeError(".decimal accessor is available only for decimal type columns")
492
+
493
+ def __abs__(self):
494
+ """
495
+ Return the absolute value of float or int column.
496
+
497
+ Examples
498
+ --------
499
+ >>> t = otp.Tick(A=-1, B=-2.3)
500
+ >>> t['A'] = abs(t['A'])
501
+ >>> t['B'] = abs(t['B'])
502
+ >>> otp.run(t)[['A', 'B']]
503
+ A B
504
+ 0 1 2.3
505
+ """
506
+ return _Operation(_methods.abs, [self])
507
+
508
+ def __round__(self, precision=None):
509
+ """
510
+ Rounds value with specified ``precision``.
511
+
512
+ Parameters
513
+ ----------
514
+ precision: int
515
+ Number from -12 to 12.
516
+ Positive precision is precision after the floating point.
517
+ Negative precision is precision before the floating point.
518
+
519
+ Examples
520
+ --------
521
+ >>> t = otp.Tick(A=1234.5678)
522
+ >>> t['B'] = round(t['A'])
523
+ >>> t['C'] = round(t['A'], 2)
524
+ >>> t['D'] = round(t['A'], -2)
525
+ >>> otp.run(t)
526
+ Time A B C D
527
+ 0 2003-12-01 1234.5678 1235 1234.57 1200.0
528
+
529
+ Returns
530
+ -------
531
+ Operation
532
+ """
533
+ return _Operation(_methods.round, [self, precision])
534
+
535
+ def __neg__(self):
536
+ """
537
+ Return the negative value of float or int column.
538
+
539
+ Examples
540
+ --------
541
+ >>> t = otp.Tick(A=1, B=2.3)
542
+ >>> t['A'] = -t['A']
543
+ >>> t['B'] = -t['B']
544
+ >>> otp.run(t)[['A', 'B']]
545
+ A B
546
+ 0 -1 -2.3
547
+ """
548
+ return _Operation(_methods.neg, [self])
549
+
550
+ def __add__(self, other):
551
+ """
552
+ Return the sum of column and ``other`` value.
553
+
554
+ Parameters
555
+ ----------
556
+ other: int, float, str, :ref:`offset <datetime_offsets>`, :py:class:`onetick.py.Column`
557
+
558
+ Examples
559
+ --------
560
+ >>> t = otp.Tick(A=1, B=2.3, C='c', D=otp.datetime(2022, 5, 12))
561
+ >>> t['A'] = t['A'] + t['B']
562
+ >>> t['B'] = t['B'] + 1
563
+ >>> t['C'] = t['C'] + '_suffix'
564
+ >>> t['D'] = t['D'] + otp.Day(1)
565
+ >>> otp.run(t)[['A', 'B', 'C', 'D']]
566
+ A B C D
567
+ 0 3.3 3.3 c_suffix 2022-05-13
568
+ """
569
+ return _Operation(_methods.add, [self, other])
570
+
571
+ def __radd__(self, other):
572
+ """
573
+ See also
574
+ --------
575
+ __add__
576
+
577
+ Examples
578
+ --------
579
+ >>> t = otp.Tick(A=1, B=2.3, C='c', D=otp.datetime(2022, 5, 12))
580
+ >>> t['A'] += t['B']
581
+ >>> t['B'] += 1
582
+ >>> t['C'] += '_suffix'
583
+ >>> t['D'] += otp.Day(1)
584
+ >>> otp.run(t)[['A', 'B', 'C', 'D']]
585
+ A B C D
586
+ 0 3.3 3.3 c_suffix 2022-05-13
587
+ """
588
+ return _Operation(_methods.add, [other, self])
589
+
590
+ def __sub__(self, other):
591
+ """
592
+ Subtract ``other`` value from column.
593
+
594
+ Parameters
595
+ ----------
596
+ other: int, float, :ref:`offset <datetime_offsets>`, :py:class:`onetick.py.Column`
597
+
598
+ Examples
599
+ --------
600
+ >>> t = otp.Tick(A=1, B=2.3, D=otp.datetime(2022, 5, 12))
601
+ >>> t['A'] = t['A'] - t['B']
602
+ >>> t['B'] = t['B'] - 1
603
+ >>> t['D'] = t['D'] - otp.Day(1)
604
+ >>> otp.run(t)[['A', 'B', 'D']]
605
+ A B D
606
+ 0 -1.3 1.3 2022-05-11
607
+ """
608
+ return _Operation(_methods.sub, [self, other])
609
+
610
+ def __rsub__(self, other):
611
+ """
612
+ See also
613
+ --------
614
+ __sub__
615
+
616
+ Examples
617
+ --------
618
+ >>> t = otp.Tick(A=1, B=2.3, D=otp.datetime(2022, 5, 12))
619
+ >>> t['A'] -= t['B']
620
+ >>> t['B'] -= 1
621
+ >>> t['D'] -= otp.Day(1)
622
+ >>> otp.run(t)[['A', 'B', 'D']]
623
+ A B D
624
+ 0 -1.3 1.3 2022-05-11
625
+ """
626
+ return _Operation(_methods.sub, [other, self])
627
+
628
+ def __mul__(self, other):
629
+ """
630
+ Multiply column by ``other`` value.
631
+
632
+ Parameters
633
+ ----------
634
+ other: int, float, str, :py:class:`onetick.py.Column`
635
+
636
+ Examples
637
+ --------
638
+ >>> t = otp.Tick(A=1, B=2.3, C='c')
639
+ >>> t['A'] = t['A'] * t['B']
640
+ >>> t['B'] = t['B'] * 2
641
+ >>> t['C'] = t['C'] * 3
642
+ >>> otp.run(t)[['A', 'B', 'C']]
643
+ A B C
644
+ 0 2.3 4.6 ccc
645
+ """
646
+ return _Operation(_methods.mul, [self, other])
647
+
648
+ def __rmul__(self, other):
649
+ """
650
+ See also
651
+ --------
652
+ __mul__
653
+
654
+ Examples
655
+ --------
656
+ >>> t = otp.Tick(A=1, B=2.3, C='c')
657
+ >>> t['A'] *= t['B']
658
+ >>> t['B'] *= 2
659
+ >>> t['C'] *= 3
660
+ >>> otp.run(t)[['A', 'B', 'C']]
661
+ A B C
662
+ 0 2.3 4.6 ccc
663
+ """
664
+ return _Operation(_methods.mul, [other, self])
665
+
666
+ def __truediv__(self, other):
667
+ """
668
+ Divide column by ``other`` value.
669
+
670
+ Parameters
671
+ ----------
672
+ other: int, float, :py:class:`onetick.py.Column`
673
+
674
+ Examples
675
+ --------
676
+ >>> t = otp.Tick(A=1, B=2.3)
677
+ >>> t['A'] = t['A'] / t['B']
678
+ >>> t['B'] = t['B'] / 2
679
+ >>> otp.run(t)[['A', 'B']]
680
+ A B
681
+ 0 0.434783 1.15
682
+ """
683
+ return _Operation(_methods.div, [self, other])
684
+
685
+ def __rtruediv__(self, other):
686
+ """
687
+ See also
688
+ --------
689
+ __truediv__
690
+
691
+ Examples
692
+ --------
693
+ >>> t = otp.Tick(A=1, B=2.3)
694
+ >>> t['A'] /= t['B']
695
+ >>> t['B'] /= 2
696
+ >>> otp.run(t)[['A', 'B']]
697
+ A B
698
+ 0 0.434783 1.15
699
+ """
700
+ return _Operation(_methods.div, [other, self])
701
+
702
+ def __mod__(self, other):
703
+ """
704
+ Return modulo of division of int column by ``other`` value.
705
+
706
+ Parameters
707
+ ----------
708
+ other: int, :py:class:`onetick.py.Column`
709
+
710
+ Examples
711
+ --------
712
+ >>> t = otp.Tick(A=3, B=3)
713
+ >>> t['A'] = t['A'] % t['B']
714
+ >>> t['B'] = t['B'] % 2
715
+ >>> otp.run(t)[['A', 'B']]
716
+ A B
717
+ 0 0 1
718
+ """
719
+ return _Operation(_methods.mod, [self, other])
720
+
721
+ def __invert__(self):
722
+ """
723
+ Return inversion of filter operation.
724
+
725
+ Examples
726
+ --------
727
+ >>> t = otp.Ticks(A=range(4))
728
+ >>> t, _ = t[~(t['A'] > 1)]
729
+ >>> otp.run(t)[['A']]
730
+ A
731
+ 0 0
732
+ 1 1
733
+ """
734
+ result = _Operation(_methods.invert, [self])
735
+ return result
736
+
737
+ def __eq__(self, other):
738
+ """
739
+ Return equality in filter operation.
740
+
741
+ Examples
742
+ --------
743
+ >>> t = otp.Ticks(A=range(4))
744
+ >>> t, _ = t[(t['A'] == 1)]
745
+ >>> otp.run(t)[['A']]
746
+ A
747
+ 0 1
748
+ """
749
+ result = _Operation(_methods.eq, [self, other])
750
+ return result
751
+
752
+ def __ne__(self, other):
753
+ """
754
+ Return inequality in filter operation.
755
+
756
+ Examples
757
+ --------
758
+ >>> t = otp.Ticks(A=range(4))
759
+ >>> t, _ = t[(t['A'] != 1)]
760
+ >>> otp.run(t)[['A']]
761
+ A
762
+ 0 0
763
+ 1 2
764
+ 2 3
765
+ """
766
+ result = _Operation(_methods.ne, [self, other])
767
+ return result
768
+
769
+ def __or__(self, other):
770
+ """
771
+ Return logical ``or`` in filter operation.
772
+
773
+ Examples
774
+ --------
775
+ >>> t = otp.Ticks(A=range(4))
776
+ >>> t, _ = t[(t['A'] == 1) | (t['A'] == 2)]
777
+ >>> otp.run(t)[['A']]
778
+ A
779
+ 0 1
780
+ 1 2
781
+ """
782
+ result = _Operation(_methods.or_, [self, other])
783
+ return result
784
+
785
+ def __and__(self, other):
786
+ """
787
+ Return logical ``and`` in filter operation.
788
+
789
+ Examples
790
+ --------
791
+ >>> t = otp.Ticks(A=[1, 1], B=[1, 2])
792
+ >>> t, _ = t[(t['A'] == 1) & (t['B'] == 1)]
793
+ >>> otp.run(t)[['A', 'B']]
794
+ A B
795
+ 0 1 1
796
+ """
797
+ result = _Operation(_methods.and_, [self, other])
798
+ return result
799
+
800
+ def __le__(self, other):
801
+ """
802
+ Return <= in filter operation.
803
+
804
+ Examples
805
+ --------
806
+ >>> t = otp.Ticks(A=range(4))
807
+ >>> t, _ = t[t['A'] <= 2]
808
+ >>> otp.run(t)[['A']]
809
+ A
810
+ 0 0
811
+ 1 1
812
+ 2 2
813
+ """
814
+ result = _Operation(_methods.le, [self, other])
815
+ return result
816
+
817
+ def __lt__(self, other):
818
+ """
819
+ Return < in filter operation.
820
+
821
+ Examples
822
+ --------
823
+ >>> t = otp.Ticks(A=range(4))
824
+ >>> t, _ = t[t['A'] < 2]
825
+ >>> otp.run(t)[['A']]
826
+ A
827
+ 0 0
828
+ 1 1
829
+ """
830
+ result = _Operation(_methods.lt, [self, other])
831
+ return result
832
+
833
+ def __ge__(self, other):
834
+ """
835
+ Return >= in filter operation.
836
+
837
+ Examples
838
+ --------
839
+ >>> t = otp.Ticks(A=range(4))
840
+ >>> t, _ = t[t['A'] >= 2]
841
+ >>> otp.run(t)[['A']]
842
+ A
843
+ 0 2
844
+ 1 3
845
+ """
846
+ result = _Operation(_methods.ge, [self, other])
847
+ return result
848
+
849
+ def __gt__(self, other):
850
+ """
851
+ Return > in filter operation.
852
+
853
+ Examples
854
+ --------
855
+ >>> t = otp.Ticks(A=range(4))
856
+ >>> t, _ = t[t['A'] > 2]
857
+ >>> otp.run(t)[['A']]
858
+ A
859
+ 0 3
860
+ """
861
+ result = _Operation(_methods.gt, [self, other])
862
+ return result
863
+
864
+ def __format__(self, format_spec):
865
+ # pylint: disable=E0311
866
+ class_name = self.__class__.__name__
867
+ warnings.warn(
868
+ f"Using `{class_name}` in formatted string literals and `str.format` method is disallowed. "
869
+ f"You can use `otp.format` function for formatting `{class_name}` objects.",
870
+ FutureWarning,
871
+ stacklevel=2,
872
+ )
873
+
874
+ return super().__format__(format_spec)
875
+
876
+ def _evaluate_func(self, *, set_fields=False):
877
+ if self._op_func:
878
+ op_str, dtype = self._op_func(*self._op_params) if self._op_params else self._op_func()
879
+ if set_fields:
880
+ self._op_str = op_str
881
+ self._dtype = dtype
882
+ return op_str, dtype
883
+
884
+ def _convert_to(self, to_type):
885
+ return _Operation(_methods.CONVERSIONS[self.dtype, to_type], [self])
886
+
887
+ def _make_python_way_bool_expression(self):
888
+ dtype = ott.get_object_type(self)
889
+ if dtype is bool:
890
+ return self
891
+ if are_ints_not_time(dtype):
892
+ self = _Operation(_methods.ne, (self, 0))
893
+ elif are_time(dtype):
894
+ self = _Operation(_methods.ne, (self._convert_to(int), 0))
895
+ elif are_floats(dtype):
896
+ self = _Operation(_methods.ne, (self, 0.0))
897
+ elif are_strings(dtype):
898
+ self = _Operation(_methods.ne, (self, ""))
899
+ else:
900
+ raise TypeError("Filter expression should return bool, int, float or string")
901
+ return self
902
+
903
+ def _replace_parameters(self, operation_cb, return_replace_tuples=False):
904
+ """
905
+ Replaces operation parameters (on any nesting level)
906
+ by logic defined by ``operation_cb`` and returns new operation object.
907
+
908
+ Parameters
909
+ ----------
910
+ operation_cb: callable
911
+ Callable, with one parameter: current parameter.
912
+ If function returns anything current parameter will be replaced with the result of call
913
+ return_replace_tuples:
914
+ If ``True`` then also returns the list of tuples with old and new parameters.
915
+
916
+ Returns
917
+ -------
918
+ result: _Operation or Tuple[_Operation, List[Tuple[_Operation, _Operation]]]
919
+ Returns new operation object with parameters replaced by callback.
920
+ Also may return the list of tuples with old and new parameters.
921
+ """
922
+ self_copy = copy.copy(self)
923
+
924
+ replace_tuples = []
925
+
926
+ class Node:
927
+ def __init__(self, operation, parent):
928
+ self.operation = operation
929
+ self.parent = parent
930
+
931
+ nodes_to_reevaluate = []
932
+ nodes_to_process = [Node(self_copy, None)]
933
+
934
+ while nodes_to_process:
935
+ current_node = nodes_to_process.pop()
936
+ current_obj = current_node.operation
937
+ if not getattr(current_obj, '_op_params', None):
938
+ continue
939
+
940
+ op_params = current_obj._op_params.copy()
941
+
942
+ for i, op in enumerate(current_obj._op_params):
943
+ new_op = operation_cb(op)
944
+ if new_op is not None:
945
+ replace_tuples.append((op, new_op))
946
+ op_params[i] = new_op
947
+ nodes_to_reevaluate.append(Node(new_op, current_node))
948
+ else:
949
+ if isinstance(op, _Operation):
950
+ op = copy.copy(op)
951
+ op_params[i] = op
952
+ nodes_to_process.append(Node(op, current_node))
953
+
954
+ current_obj._op_params = op_params
955
+
956
+ for node in reversed(nodes_to_reevaluate):
957
+ parent = node.parent
958
+ while parent is not None:
959
+ parent.operation._evaluate_func(set_fields=True)
960
+ parent = parent.parent
961
+
962
+ if return_replace_tuples:
963
+ return self_copy, replace_tuples
964
+ return self_copy
965
+
966
+
967
+ _Operation = Operation # alias to support backward compatibility
968
+
969
+
970
+ class Raw(Operation):
971
+ """
972
+ Data type representing raw OneTick expression.
973
+
974
+ Examples
975
+ --------
976
+ >>> t = otp.Tick(A=1)
977
+ >>> t['A'] = '_TIMEZONE'
978
+ >>> t['B'] = otp.raw('_TIMEZONE', dtype=otp.string[64])
979
+ >>> otp.run(t, timezone='Asia/Yerevan')
980
+ Time A B
981
+ 0 2003-12-01 _TIMEZONE Asia/Yerevan
982
+ """
983
+ def __init__(self, raw, dtype):
984
+ if dtype is str:
985
+ warnings.warn(
986
+ f'Be careful, default string length in OneTick is {ott.string.DEFAULT_LENGTH}.'
987
+ "Length of the result raw expression can't be calculated automatically, "
988
+ "so you'd better use onetick.py.string type.",
989
+ stacklevel=2,
990
+ )
991
+ super().__init__(op_str=raw, dtype=dtype)
992
+
993
+
994
+ class OnetickParameter(Operation):
995
+ """
996
+ Data type representing OneTick parameter.
997
+
998
+ This object can be used in all places where :class:`~onetick.py.Operation` can be used
999
+ and also in some additional places, e.g. some functions' parameters.
1000
+
1001
+ Parameters
1002
+ ----------
1003
+ name: str
1004
+ The name of the parameter.
1005
+ dtype:
1006
+ The type of the parameter.
1007
+ string_literal: bool
1008
+ By default, OneTick inserts string parameters as is in the graph,
1009
+ and they are interpreted as an expression.
1010
+
1011
+ In case this parameter is ``True``
1012
+ quotes are added when evaluating string parameters, making them the string literals.
1013
+ We assume that in most cases it's desirable for the user's parameters to be used as a string literal,
1014
+ so the default value for this is ``True``.
1015
+
1016
+ If you want your string parameters to be interpreted as OneTick expressions, set this to ``False``.
1017
+
1018
+ Examples
1019
+ --------
1020
+
1021
+ Generate tick with parametrized field value:
1022
+
1023
+ >>> t = otp.Tick(A=otp.param('PARAM', dtype=int))
1024
+ >>> otp.run(t, query_params={'PARAM': 1})
1025
+ Time A
1026
+ 0 2003-12-01 1
1027
+
1028
+ Set bucket interval in aggregation as a parameter:
1029
+
1030
+ >>> t = otp.Ticks(A=[1, 2, 3, 4, 5, 6])
1031
+ >>> t = t.agg({'A': otp.agg.sum('A')},
1032
+ ... bucket_units='ticks', bucket_interval=otp.param('PARAM', dtype=int))
1033
+ >>> otp.run(t, query_params={'PARAM': 3})
1034
+ Time A
1035
+ 0 2003-12-01 00:00:00.002 6
1036
+ 1 2003-12-01 00:00:00.005 15
1037
+
1038
+ Parameter ``string_literal=False`` can be used if you need string to be interpreted as an expression:
1039
+
1040
+ >>> t = otp.Tick(A=otp.param('PARAM', dtype=str),
1041
+ ... B=otp.param('PARAM', dtype=str, string_literal=False))
1042
+ >>> otp.run(t, query_params={'PARAM': 'TOSTRING(NAN())'})
1043
+ Time A B
1044
+ 0 2003-12-01 TOSTRING(NAN()) nan
1045
+ """
1046
+ def __init__(self, name, dtype, string_literal=True):
1047
+ self.parameter_expression = f'${name}'
1048
+
1049
+ parameter_expression = self.parameter_expression
1050
+ if string_literal and issubclass(dtype, str):
1051
+ # OneTick parameters are inserted as is in the graph,
1052
+ # so we need to add quotes around string to make it a literal
1053
+ # (otherwise it would be interpreted as a column name)
1054
+ parameter_expression = ott.value2str(parameter_expression)
1055
+
1056
+ if dtype is float:
1057
+ # BDS-93
1058
+ # need atof to be able to convert string 'nan' to float
1059
+ parameter_expression = f'atof({ott.value2str(parameter_expression)})'
1060
+
1061
+ super().__init__(op_str=parameter_expression, dtype=dtype)