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.
- locator_parser/__init__.py +0 -0
- locator_parser/acl.py +73 -0
- locator_parser/actions.py +262 -0
- locator_parser/common.py +368 -0
- locator_parser/io.py +43 -0
- locator_parser/locator.py +150 -0
- onetick/__init__.py +101 -0
- onetick/doc_utilities/__init__.py +3 -0
- onetick/doc_utilities/napoleon.py +40 -0
- onetick/doc_utilities/ot_doctest.py +140 -0
- onetick/doc_utilities/snippets.py +279 -0
- onetick/lib/__init__.py +4 -0
- onetick/lib/instance.py +141 -0
- onetick/py/__init__.py +293 -0
- onetick/py/_stack_info.py +89 -0
- onetick/py/_version.py +2 -0
- onetick/py/aggregations/__init__.py +11 -0
- onetick/py/aggregations/_base.py +648 -0
- onetick/py/aggregations/_docs.py +948 -0
- onetick/py/aggregations/compute.py +286 -0
- onetick/py/aggregations/functions.py +2216 -0
- onetick/py/aggregations/generic.py +104 -0
- onetick/py/aggregations/high_low.py +80 -0
- onetick/py/aggregations/num_distinct.py +83 -0
- onetick/py/aggregations/order_book.py +501 -0
- onetick/py/aggregations/other.py +1014 -0
- onetick/py/backports.py +26 -0
- onetick/py/cache.py +374 -0
- onetick/py/callback/__init__.py +5 -0
- onetick/py/callback/callback.py +276 -0
- onetick/py/callback/callbacks.py +131 -0
- onetick/py/compatibility.py +798 -0
- onetick/py/configuration.py +771 -0
- onetick/py/core/__init__.py +0 -0
- onetick/py/core/_csv_inspector.py +93 -0
- onetick/py/core/_internal/__init__.py +0 -0
- onetick/py/core/_internal/_manually_bound_value.py +6 -0
- onetick/py/core/_internal/_nodes_history.py +250 -0
- onetick/py/core/_internal/_op_utils/__init__.py +0 -0
- onetick/py/core/_internal/_op_utils/every_operand.py +9 -0
- onetick/py/core/_internal/_op_utils/is_const.py +10 -0
- onetick/py/core/_internal/_per_tick_scripts/tick_list_sort_template.script +121 -0
- onetick/py/core/_internal/_proxy_node.py +140 -0
- onetick/py/core/_internal/_state_objects.py +2312 -0
- onetick/py/core/_internal/_state_vars.py +93 -0
- onetick/py/core/_source/__init__.py +0 -0
- onetick/py/core/_source/_symbol_param.py +95 -0
- onetick/py/core/_source/schema.py +97 -0
- onetick/py/core/_source/source_methods/__init__.py +0 -0
- onetick/py/core/_source/source_methods/aggregations.py +809 -0
- onetick/py/core/_source/source_methods/applyers.py +296 -0
- onetick/py/core/_source/source_methods/columns.py +141 -0
- onetick/py/core/_source/source_methods/data_quality.py +301 -0
- onetick/py/core/_source/source_methods/debugs.py +272 -0
- onetick/py/core/_source/source_methods/drops.py +120 -0
- onetick/py/core/_source/source_methods/fields.py +619 -0
- onetick/py/core/_source/source_methods/filters.py +1002 -0
- onetick/py/core/_source/source_methods/joins.py +1413 -0
- onetick/py/core/_source/source_methods/merges.py +605 -0
- onetick/py/core/_source/source_methods/misc.py +1455 -0
- onetick/py/core/_source/source_methods/pandases.py +155 -0
- onetick/py/core/_source/source_methods/renames.py +356 -0
- onetick/py/core/_source/source_methods/sorts.py +183 -0
- onetick/py/core/_source/source_methods/switches.py +142 -0
- onetick/py/core/_source/source_methods/symbols.py +117 -0
- onetick/py/core/_source/source_methods/times.py +627 -0
- onetick/py/core/_source/source_methods/writes.py +986 -0
- onetick/py/core/_source/symbol.py +205 -0
- onetick/py/core/_source/tmp_otq.py +222 -0
- onetick/py/core/column.py +209 -0
- onetick/py/core/column_operations/__init__.py +0 -0
- onetick/py/core/column_operations/_methods/__init__.py +4 -0
- onetick/py/core/column_operations/_methods/_internal.py +28 -0
- onetick/py/core/column_operations/_methods/conversions.py +216 -0
- onetick/py/core/column_operations/_methods/methods.py +292 -0
- onetick/py/core/column_operations/_methods/op_types.py +160 -0
- onetick/py/core/column_operations/accessors/__init__.py +0 -0
- onetick/py/core/column_operations/accessors/_accessor.py +28 -0
- onetick/py/core/column_operations/accessors/decimal_accessor.py +104 -0
- onetick/py/core/column_operations/accessors/dt_accessor.py +537 -0
- onetick/py/core/column_operations/accessors/float_accessor.py +184 -0
- onetick/py/core/column_operations/accessors/str_accessor.py +1367 -0
- onetick/py/core/column_operations/base.py +1121 -0
- onetick/py/core/cut_builder.py +150 -0
- onetick/py/core/db_constants.py +20 -0
- onetick/py/core/eval_query.py +245 -0
- onetick/py/core/lambda_object.py +441 -0
- onetick/py/core/multi_output_source.py +232 -0
- onetick/py/core/per_tick_script.py +2256 -0
- onetick/py/core/query_inspector.py +464 -0
- onetick/py/core/source.py +1744 -0
- onetick/py/db/__init__.py +2 -0
- onetick/py/db/_inspection.py +1128 -0
- onetick/py/db/db.py +1327 -0
- onetick/py/db/utils.py +64 -0
- onetick/py/docs/__init__.py +0 -0
- onetick/py/docs/docstring_parser.py +112 -0
- onetick/py/docs/utils.py +81 -0
- onetick/py/functions.py +2398 -0
- onetick/py/license.py +190 -0
- onetick/py/log.py +88 -0
- onetick/py/math.py +935 -0
- onetick/py/misc.py +470 -0
- onetick/py/oqd/__init__.py +22 -0
- onetick/py/oqd/eps.py +1195 -0
- onetick/py/oqd/sources.py +325 -0
- onetick/py/otq.py +216 -0
- onetick/py/pyomd_mock.py +47 -0
- onetick/py/run.py +916 -0
- onetick/py/servers.py +173 -0
- onetick/py/session.py +1347 -0
- onetick/py/sources/__init__.py +19 -0
- onetick/py/sources/cache.py +167 -0
- onetick/py/sources/common.py +128 -0
- onetick/py/sources/csv.py +642 -0
- onetick/py/sources/custom.py +85 -0
- onetick/py/sources/data_file.py +305 -0
- onetick/py/sources/data_source.py +1045 -0
- onetick/py/sources/empty.py +94 -0
- onetick/py/sources/odbc.py +337 -0
- onetick/py/sources/order_book.py +271 -0
- onetick/py/sources/parquet.py +168 -0
- onetick/py/sources/pit.py +191 -0
- onetick/py/sources/query.py +495 -0
- onetick/py/sources/snapshots.py +419 -0
- onetick/py/sources/split_query_output_by_symbol.py +198 -0
- onetick/py/sources/symbology_mapping.py +123 -0
- onetick/py/sources/symbols.py +374 -0
- onetick/py/sources/ticks.py +825 -0
- onetick/py/sql.py +70 -0
- onetick/py/state.py +251 -0
- onetick/py/types.py +2131 -0
- onetick/py/utils/__init__.py +70 -0
- onetick/py/utils/acl.py +93 -0
- onetick/py/utils/config.py +186 -0
- onetick/py/utils/default.py +49 -0
- onetick/py/utils/file.py +38 -0
- onetick/py/utils/helpers.py +76 -0
- onetick/py/utils/locator.py +94 -0
- onetick/py/utils/perf.py +498 -0
- onetick/py/utils/query.py +49 -0
- onetick/py/utils/render.py +1374 -0
- onetick/py/utils/script.py +244 -0
- onetick/py/utils/temp.py +471 -0
- onetick/py/utils/types.py +120 -0
- onetick/py/utils/tz.py +84 -0
- onetick_py-1.177.0.dist-info/METADATA +137 -0
- onetick_py-1.177.0.dist-info/RECORD +152 -0
- onetick_py-1.177.0.dist-info/WHEEL +5 -0
- onetick_py-1.177.0.dist-info/entry_points.txt +2 -0
- onetick_py-1.177.0.dist-info/licenses/LICENSE +21 -0
- 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)
|