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