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,150 @@
|
|
|
1
|
+
from abc import ABCMeta, abstractmethod
|
|
2
|
+
from onetick.py.otq import otq
|
|
3
|
+
from onetick.py.backports import singledispatchmethod
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class _BaseCutBuilder(metaclass=ABCMeta):
|
|
7
|
+
"""We need to build up query graph to compute bins based on max and min value.
|
|
8
|
+
As we need to set proper output column name in per-tick script:
|
|
9
|
+
1) instance of this class created on cut() and qcut() call,
|
|
10
|
+
2) and then this instance is called during _Source.__setattr__() with output_column_name as argument.
|
|
11
|
+
"""
|
|
12
|
+
|
|
13
|
+
def __init__(self, src, column, bins, **kwargs):
|
|
14
|
+
self.src = src
|
|
15
|
+
self.column = column
|
|
16
|
+
self.bins = bins
|
|
17
|
+
self.column_name = str(self.column)
|
|
18
|
+
self.output_column_name = None
|
|
19
|
+
self.labels = kwargs.get('labels')
|
|
20
|
+
self.res = None
|
|
21
|
+
self.bin_number = None
|
|
22
|
+
if isinstance(self.bins, (int, float)) and self.labels and len(self.labels) != self.bins:
|
|
23
|
+
raise ValueError('Number of labels is not equal to number of bins')
|
|
24
|
+
|
|
25
|
+
def __call__(self, output_column_name):
|
|
26
|
+
self.output_column_name = output_column_name
|
|
27
|
+
self.build_graph()
|
|
28
|
+
|
|
29
|
+
def build_graph(self):
|
|
30
|
+
res = self.define_state_variables(self.bins)
|
|
31
|
+
script = self.generate_script(res)
|
|
32
|
+
self.src.script(script, inplace=True)
|
|
33
|
+
|
|
34
|
+
@abstractmethod
|
|
35
|
+
def compute_bin_variables(self):
|
|
36
|
+
"""Compute state variables based on min/max and number of bins/quantiles."""
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
@singledispatchmethod
|
|
40
|
+
def define_state_variables(self, bins):
|
|
41
|
+
raise NotImplementedError(f'Method define_state_variables() is not implemented for parameter {type(bins)}')
|
|
42
|
+
|
|
43
|
+
@define_state_variables.register
|
|
44
|
+
def dsv_int(self, bins: int):
|
|
45
|
+
res = self.compute_bin_variables()
|
|
46
|
+
|
|
47
|
+
# merge src with bins res (to share state_vars)
|
|
48
|
+
res.schema.set(**{})
|
|
49
|
+
res, _ = res[(res['Time'] == 0)]
|
|
50
|
+
self.src.sink(otq.Merge(identify_input_ts=False))
|
|
51
|
+
self.src.source(res.node().copy_graph())
|
|
52
|
+
self.src.node().add_rules(res.node().copy_rules())
|
|
53
|
+
return res
|
|
54
|
+
|
|
55
|
+
@define_state_variables.register
|
|
56
|
+
def dsv_list(self, bins: list):
|
|
57
|
+
return self.define_state_variables_by_list(bins)
|
|
58
|
+
|
|
59
|
+
def define_state_variables_by_list(self, bins):
|
|
60
|
+
raise NotImplementedError("define_state_variables_by_list() not implemented")
|
|
61
|
+
|
|
62
|
+
def state_variable(self, inx):
|
|
63
|
+
"""State variable name used in bin's calculations"""
|
|
64
|
+
return f'_TMP_{self.output_column_name}_{self.column_name}_{inx}'
|
|
65
|
+
|
|
66
|
+
def generate_script(self, res):
|
|
67
|
+
"""
|
|
68
|
+
Per-tick script generator.
|
|
69
|
+
Every tick is compared state variable to find index of bin.
|
|
70
|
+
Resulted bin (interval or label) is saved in output column.
|
|
71
|
+
"""
|
|
72
|
+
bin_number = self.bin_number
|
|
73
|
+
labels = self.labels
|
|
74
|
+
column_name = self.column_name
|
|
75
|
+
output_column_name = self.output_column_name
|
|
76
|
+
|
|
77
|
+
s = ''
|
|
78
|
+
for inx in range(1, bin_number):
|
|
79
|
+
s += f'if ({column_name} <= STATE::{self.state_variable(inx)})' + '{\n'
|
|
80
|
+
if labels is None:
|
|
81
|
+
str_val = ''
|
|
82
|
+
if inx > 1:
|
|
83
|
+
str_val = '"(" + ' + f'tostring(STATE::{self.state_variable(inx - 1)}, 10, 10) + '
|
|
84
|
+
str_val += '", " + ' + f'tostring(STATE::{self.state_variable(inx)}, 10, 10)' + ' + "]"'
|
|
85
|
+
s += f'{output_column_name} = ' + str_val + ';\n'
|
|
86
|
+
else:
|
|
87
|
+
s += f'{output_column_name} = "{labels[inx - 1]}";\n'
|
|
88
|
+
|
|
89
|
+
s += '}'
|
|
90
|
+
if inx < bin_number - 1:
|
|
91
|
+
s += ' else '
|
|
92
|
+
else:
|
|
93
|
+
s += '\n'
|
|
94
|
+
|
|
95
|
+
# default output column value is the last bin
|
|
96
|
+
if labels is None:
|
|
97
|
+
var_name = self.state_variable(bin_number - 1)
|
|
98
|
+
self.src[output_column_name] = '(' + res.state_vars[var_name].apply(str) + ','
|
|
99
|
+
else:
|
|
100
|
+
self.src[output_column_name] = labels[-1]
|
|
101
|
+
|
|
102
|
+
return s
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
# pylint: disable-next=abstract-method
|
|
106
|
+
class _CutBuilder(_BaseCutBuilder):
|
|
107
|
+
|
|
108
|
+
def compute_bin_variables(self):
|
|
109
|
+
"""Compute state variables based on min/max and number of bins."""
|
|
110
|
+
res = self.src.copy()
|
|
111
|
+
column_name = self.column_name
|
|
112
|
+
self.bin_number = self.bins
|
|
113
|
+
|
|
114
|
+
res.sink(otq.Compute(
|
|
115
|
+
compute=f"HIGH(INPUT_FIELD_NAME='{column_name}') HV,LOW(INPUT_FIELD_NAME='{column_name}') LV",
|
|
116
|
+
append_output_field_name=False))
|
|
117
|
+
res.schema.set(**{"HV": self.column.dtype, "LV": self.column.dtype})
|
|
118
|
+
|
|
119
|
+
for inx in range(self.bins):
|
|
120
|
+
res.state_vars[self.state_variable(inx)] = 0.
|
|
121
|
+
res.state_vars[self.state_variable(inx)] = res['LV'] + (res['HV'] - res['LV']) / self.bins * inx
|
|
122
|
+
return res
|
|
123
|
+
|
|
124
|
+
def define_state_variables_by_list(self, bins: list):
|
|
125
|
+
res = self.src
|
|
126
|
+
self.bin_number = len(bins)
|
|
127
|
+
for inx, value in enumerate(bins):
|
|
128
|
+
res.state_vars[self.state_variable(inx)] = float(value)
|
|
129
|
+
return res
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class _QCutBuilder(_BaseCutBuilder):
|
|
133
|
+
|
|
134
|
+
def compute_bin_variables(self):
|
|
135
|
+
"""Compute state variables based on otq.Percentile()."""
|
|
136
|
+
res = self.src.copy()
|
|
137
|
+
column_name = self.column_name
|
|
138
|
+
self.bin_number = self.bins
|
|
139
|
+
|
|
140
|
+
res.sink(otq.Percentile(number_of_quantiles=self.bins, input_field_names=column_name))
|
|
141
|
+
res.sink(otq.Transpose(direction='ROWS_TO_COLUMNS', key_constraint_values=self.bins - 1))
|
|
142
|
+
res.schema.set(**{column_name + f'_{inx}': self.column.dtype for inx in range(1, self.bins)})
|
|
143
|
+
|
|
144
|
+
for inx in range(1, self.bins):
|
|
145
|
+
res.state_vars[self.state_variable(inx)] = .0
|
|
146
|
+
res.state_vars[self.state_variable(inx)] = res[f'{column_name}_{inx}']
|
|
147
|
+
return res
|
|
148
|
+
|
|
149
|
+
def define_state_variables_by_list(self, bins: list):
|
|
150
|
+
raise NotImplementedError("qcut() with q as list of float is not implemented yet.")
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
DEFAULT_START_DATE = datetime(year=2003, month=1, day=1)
|
|
5
|
+
DEFAULT_END_DATE = datetime(year=2099, month=12, day=31)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class compression_type:
|
|
9
|
+
LZ4 = "LZ4"
|
|
10
|
+
GZIP = "GZIP"
|
|
11
|
+
NATIVE = "NATIVE"
|
|
12
|
+
NATIVE_PLUS_LZ4 = "NATIVE_PLUS_LZ4"
|
|
13
|
+
NATIVE_PLUS_GZIP = "NATIVE_PLUS_GZIP"
|
|
14
|
+
NATIVE_PLUS_ZSTD = "NATIVE_PLUS_ZSTD"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class access_method:
|
|
18
|
+
FILE = "file"
|
|
19
|
+
MEMORY = "memory"
|
|
20
|
+
SOCKET = "socket"
|
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
import inspect
|
|
2
|
+
import types
|
|
3
|
+
import warnings
|
|
4
|
+
|
|
5
|
+
from onetick import py as otp
|
|
6
|
+
from onetick.py.core._source._symbol_param import _SymbolParamColumn, _SymbolParamSource
|
|
7
|
+
from onetick.py.core.column_operations.base import OnetickParameter
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class _QueryEvalWrapper:
|
|
11
|
+
def __init__(self, query, params=None, output_field=None, request_substitute_symbol=False,
|
|
12
|
+
generate_separate_file_only=False):
|
|
13
|
+
self.query = query
|
|
14
|
+
self.params = params
|
|
15
|
+
self.output_field = output_field
|
|
16
|
+
self.request_substitute_symbol = request_substitute_symbol
|
|
17
|
+
self.generate_separate_file_only = generate_separate_file_only
|
|
18
|
+
self._inner_source = None
|
|
19
|
+
if isinstance(query, otp.Source):
|
|
20
|
+
self._inner_source = query
|
|
21
|
+
params = params or {}
|
|
22
|
+
|
|
23
|
+
start, end = query._get_widest_time_range()
|
|
24
|
+
if start and end and '_START_TIME' not in params and '_END_TIME' not in params:
|
|
25
|
+
params['_START_TIME'] = start
|
|
26
|
+
params['_END_TIME'] = end
|
|
27
|
+
|
|
28
|
+
self.str_params = otp.query._params_to_str(params, with_expr=True)
|
|
29
|
+
elif isinstance(query, otp.query):
|
|
30
|
+
self.path = query.path
|
|
31
|
+
self.str_params = query._params_to_str(params or {}, with_expr=True)
|
|
32
|
+
else:
|
|
33
|
+
raise ValueError("Wrong query parameter, it should be otp.query, otp.Query or function, "
|
|
34
|
+
"which returns them.")
|
|
35
|
+
|
|
36
|
+
def _get_eval_string(self):
|
|
37
|
+
eval_str = f'eval("{self.path}", "{self.str_params}")'
|
|
38
|
+
if self.output_field:
|
|
39
|
+
return f'{eval_str}.{self.output_field}'
|
|
40
|
+
return eval_str
|
|
41
|
+
|
|
42
|
+
def to_eval_string(self,
|
|
43
|
+
tmp_otq=None,
|
|
44
|
+
operation_suffix='eval',
|
|
45
|
+
start=None, end=None, timezone=None,
|
|
46
|
+
file_suffix='_eval_query.otq',
|
|
47
|
+
query_name='main_eval_query',
|
|
48
|
+
symbol_date=None) -> str:
|
|
49
|
+
"""
|
|
50
|
+
If self._inner_source is not None, then temporary query needs to be saved
|
|
51
|
+
or added to tmp_otq storage
|
|
52
|
+
"""
|
|
53
|
+
if self._inner_source is not None:
|
|
54
|
+
# if substitute symbol is requested, then we need to set an unbound symbol for query in eval
|
|
55
|
+
# so that onetick can substitute it with the unbound symbol from the external query
|
|
56
|
+
symbols = None
|
|
57
|
+
if self.request_substitute_symbol:
|
|
58
|
+
symbols = 'SYMBOL_TO_SUBSTITUTE'
|
|
59
|
+
if not self.generate_separate_file_only and tmp_otq is not None:
|
|
60
|
+
tmp_otq.merge(self._inner_source._tmp_otq)
|
|
61
|
+
query_name = self._inner_source._store_in_tmp_otq(tmp_otq, symbols=symbols,
|
|
62
|
+
start=start, end=end, timezone=timezone,
|
|
63
|
+
operation_suffix=operation_suffix,
|
|
64
|
+
symbol_date=symbol_date)
|
|
65
|
+
self.path = f'THIS::{query_name}'
|
|
66
|
+
else:
|
|
67
|
+
self.path = self._inner_source.to_otq(file_suffix=file_suffix,
|
|
68
|
+
symbols=symbols,
|
|
69
|
+
query_name=query_name,
|
|
70
|
+
start=start, end=end, timezone=timezone,
|
|
71
|
+
symbol_date=symbol_date)
|
|
72
|
+
return self._get_eval_string()
|
|
73
|
+
|
|
74
|
+
def to_symbol_param(self):
|
|
75
|
+
if self._inner_source:
|
|
76
|
+
return self._inner_source.to_symbol_param()
|
|
77
|
+
else:
|
|
78
|
+
return _SymbolParamSource()
|
|
79
|
+
|
|
80
|
+
def __str__(self):
|
|
81
|
+
# TODO: deprecate after PY-952
|
|
82
|
+
# warnings.warn('This method is deprecated, use to_eval_string() instead', FutureWarning)
|
|
83
|
+
return self.to_eval_string()
|
|
84
|
+
|
|
85
|
+
def copy(self, output_field=None):
|
|
86
|
+
return _QueryEvalWrapper(query=self.query,
|
|
87
|
+
params=self.params,
|
|
88
|
+
output_field=output_field,
|
|
89
|
+
request_substitute_symbol=self.request_substitute_symbol,
|
|
90
|
+
generate_separate_file_only=self.generate_separate_file_only)
|
|
91
|
+
|
|
92
|
+
def __getitem__(self, item):
|
|
93
|
+
return self.copy(item)
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def eval(query, symbol=None, start=None, end=None,
|
|
97
|
+
generate_separate_file_only=False, **kwargs):
|
|
98
|
+
"""
|
|
99
|
+
Creates an object with ``query`` with saved parameters that can be used later.
|
|
100
|
+
|
|
101
|
+
It can be used to:
|
|
102
|
+
|
|
103
|
+
* return a list of symbols for which the main query
|
|
104
|
+
will be executed (multistage queries).
|
|
105
|
+
Note that in this case ``query`` must return ticks with column **SYMBOL_NAME**.
|
|
106
|
+
* return some value dynamically to be used in other places in the main query.
|
|
107
|
+
Note that in this case ``query`` must return only single tick.
|
|
108
|
+
|
|
109
|
+
Note that only constant expressions are allowed in query parameters,
|
|
110
|
+
they must not depend on ticks.
|
|
111
|
+
|
|
112
|
+
Parameters
|
|
113
|
+
----------
|
|
114
|
+
query: :py:class:`onetick.py.Source`, :py:class:`onetick.py.query` or function
|
|
115
|
+
source or query to evaluate.
|
|
116
|
+
If function, then it must return :py:class:`onetick.py.Source` or :py:class:`onetick.py.query`.
|
|
117
|
+
Parameter with name **symbol** and parameters specified in ``kwargs`` will be propagated
|
|
118
|
+
to this function. Parameter from ``kwargs`` *must* be specified in function signature,
|
|
119
|
+
but parameter **symbol** may be omitted if it is not used.
|
|
120
|
+
symbol: :py:class:`~onetick.py.core._source._symbol_param._SymbolParamSource`
|
|
121
|
+
symbol parameter that will be used by ``query`` as a symbol.
|
|
122
|
+
If the function is used as a ``query``, parameter **symbol** can be defined in function
|
|
123
|
+
signature and used in source operations.
|
|
124
|
+
start: meta field (:py:class:`~onetick.py.core.source.MetaFields`) \
|
|
125
|
+
or symbol param (:py:class:`~onetick.py.core._source._symbol_param._SymbolParamColumn`)
|
|
126
|
+
start time with which ``query`` will be executed.
|
|
127
|
+
By default the start time for evaluated query is inherited from the main query.
|
|
128
|
+
end: meta field (:py:class:`~onetick.py.core.source.MetaFields`) \
|
|
129
|
+
or symbol param (:py:class:`~onetick.py.core._source._symbol_param._SymbolParamColumn`)
|
|
130
|
+
end time with which ``query`` will be executed.
|
|
131
|
+
By default the end time for evaluated query is inherited from the main query.
|
|
132
|
+
generate_separate_file_only: bool
|
|
133
|
+
If set, sub-query will be generated in separate file.
|
|
134
|
+
It's needed in some cases, e.g. when generating query for *otq_query_loader_daily.exe*,
|
|
135
|
+
which executes all queries from a file.
|
|
136
|
+
kwargs: str, int, meta fields (:py:class:`~onetick.py.core.source.MetaFields`) \
|
|
137
|
+
or symbol params (:py:class:`~onetick.py.core._source._symbol_param._SymbolParamColumn`)
|
|
138
|
+
or :py:meth:`~onetick.py.core.source.Source.join_with_query` parameters
|
|
139
|
+
parameters that will be passed to ``query``.
|
|
140
|
+
If the function is used as a ``query``, parameters specified in ``kwargs``
|
|
141
|
+
*must* be defined in function signature and can be used in source operations.
|
|
142
|
+
|
|
143
|
+
See also
|
|
144
|
+
--------
|
|
145
|
+
:ref:`api/misc/symbol_param:Symbol Parameters Objects`
|
|
146
|
+
:ref:`static/concepts/symbols:Symbol parameters`
|
|
147
|
+
|
|
148
|
+
Examples
|
|
149
|
+
--------
|
|
150
|
+
|
|
151
|
+
Use ``otp.eval`` to be passed as symbols when running the query:
|
|
152
|
+
|
|
153
|
+
>>> def fsq():
|
|
154
|
+
... symbols = otp.Ticks(SYMBOL_NAME=['AAPL', 'AAP'])
|
|
155
|
+
... return symbols
|
|
156
|
+
>>> main = otp.DataSource(db='US_COMP', tick_type='TRD', date=otp.dt(2022, 3, 1))
|
|
157
|
+
>>> main['SYMBOL_NAME'] = main.Symbol.name
|
|
158
|
+
>>> main = otp.merge([main], symbols=otp.eval(fsq))
|
|
159
|
+
>>> otp.run(main) # OTdirective: snippet-name: eval with symbols;
|
|
160
|
+
Time PRICE SIZE SYMBOL_NAME
|
|
161
|
+
0 2022-03-01 00:00:00.000 1.30 100 AAPL
|
|
162
|
+
1 2022-03-01 00:00:00.000 45.37 0 AAP
|
|
163
|
+
2 2022-03-01 00:00:00.001 1.40 10 AAPL
|
|
164
|
+
3 2022-03-01 00:00:00.001 45.41 0 AAP
|
|
165
|
+
4 2022-03-01 00:00:00.002 1.40 50 AAPL
|
|
166
|
+
|
|
167
|
+
Use ``otp.eval`` as filter:
|
|
168
|
+
|
|
169
|
+
>>> def get_filter(a, b):
|
|
170
|
+
... return otp.Tick(WHERE=f'X >= {str(a)} and X < {str(b)}', OTHER_FIELD='X')
|
|
171
|
+
>>> data = otp.Ticks(X=[1, 2, 3])
|
|
172
|
+
>>> # note that in this case column WHERE must be specified,
|
|
173
|
+
>>> # because evaluated query returns tick with more than one field
|
|
174
|
+
>>> data = data.where(otp.eval(get_filter, a=0, b=2)['WHERE'])
|
|
175
|
+
>>> otp.run(data)
|
|
176
|
+
Time X
|
|
177
|
+
0 2003-12-01 1
|
|
178
|
+
|
|
179
|
+
Use ``otp.eval`` with meta fields:
|
|
180
|
+
|
|
181
|
+
>>> def filter_by_tt(tick_type):
|
|
182
|
+
... res = otp.Ticks({
|
|
183
|
+
... 'TICK_TYPE': ['TRD', 'QTE'],
|
|
184
|
+
... 'WHERE': ['PRICE>=1.4', 'ASK_PRICE>=1.4']
|
|
185
|
+
... })
|
|
186
|
+
... res = res.where(res['TICK_TYPE'] == tick_type)
|
|
187
|
+
... return res.drop(['TICK_TYPE'])
|
|
188
|
+
>>> t = otp.DataSource('US_COMP::TRD')
|
|
189
|
+
>>> # note that in this case column WHERE do not need to be specified,
|
|
190
|
+
>>> # because evaluated query returns tick with only one field
|
|
191
|
+
>>> t = t.where(otp.eval(filter_by_tt, tick_type=t['_TICK_TYPE']))
|
|
192
|
+
>>> otp.run(t, start=otp.dt(2022, 3, 1), end=otp.dt(2022, 3, 2))
|
|
193
|
+
Time PRICE SIZE
|
|
194
|
+
0 2022-03-01 00:00:00.001 1.4 10
|
|
195
|
+
1 2022-03-01 00:00:00.002 1.4 50
|
|
196
|
+
"""
|
|
197
|
+
if isinstance(query, (types.FunctionType, types.LambdaType)) or inspect.ismethod(query):
|
|
198
|
+
params = {}
|
|
199
|
+
params_to_convert = {}
|
|
200
|
+
sig = inspect.signature(query)
|
|
201
|
+
for param in sig.parameters:
|
|
202
|
+
if "symbol" == param:
|
|
203
|
+
if isinstance(symbol, _SymbolParamSource):
|
|
204
|
+
params['symbol'] = symbol
|
|
205
|
+
else:
|
|
206
|
+
params["symbol"] = _SymbolParamSource()
|
|
207
|
+
else:
|
|
208
|
+
value = kwargs[param]
|
|
209
|
+
if isinstance(value, otp.Column) and (value.name not in otp.Source.meta_fields
|
|
210
|
+
and not isinstance(value, _SymbolParamColumn)
|
|
211
|
+
and not isinstance(value, OnetickParameter)):
|
|
212
|
+
raise ValueError('Eval parameters can not depend on tick.')
|
|
213
|
+
params_to_convert[param] = value
|
|
214
|
+
params.update(prepare_params(**params_to_convert))
|
|
215
|
+
|
|
216
|
+
query = query(**params)
|
|
217
|
+
params = {}
|
|
218
|
+
request_substitute_symbol = False
|
|
219
|
+
if symbol is not None:
|
|
220
|
+
if not isinstance(symbol, _SymbolParamSource):
|
|
221
|
+
raise ValueError("Symbol parameter has wrong type, are you sure you are using it from function passed "
|
|
222
|
+
"to merge or join method?")
|
|
223
|
+
params["SYMBOL_NAME"] = symbol.name
|
|
224
|
+
request_substitute_symbol = True
|
|
225
|
+
|
|
226
|
+
if start is not None:
|
|
227
|
+
params["_START_TIME"] = start
|
|
228
|
+
if end is not None:
|
|
229
|
+
params["_END_TIME"] = end
|
|
230
|
+
params.update(kwargs)
|
|
231
|
+
|
|
232
|
+
return _QueryEvalWrapper(query, params, request_substitute_symbol=request_substitute_symbol,
|
|
233
|
+
generate_separate_file_only=generate_separate_file_only)
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def prepare_params(**kwargs):
|
|
237
|
+
converted_params = {}
|
|
238
|
+
for key, value in kwargs.items():
|
|
239
|
+
dtype = otp.types.get_object_type(value)
|
|
240
|
+
# pylint: disable-next=unidiomatic-typecheck
|
|
241
|
+
if type(value) is str and len(value) > otp.string.DEFAULT_LENGTH:
|
|
242
|
+
dtype = otp.string[len(value)]
|
|
243
|
+
param = OnetickParameter(key, dtype)
|
|
244
|
+
converted_params[key] = param
|
|
245
|
+
return converted_params
|