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,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