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,286 @@
1
+ from typing import List, Dict, TYPE_CHECKING, Tuple, Optional, Union
2
+ from copy import deepcopy
3
+ from collections import namedtuple
4
+ from onetick.py.compatibility import is_supported_agg_option_price
5
+
6
+ if TYPE_CHECKING:
7
+ from onetick.py.core.source import Source # hack for annotations
8
+
9
+ from onetick.py.core.column import Column
10
+ from onetick.py import types as ott
11
+ from onetick.py.otq import otq
12
+ import onetick.py as otp
13
+
14
+ from ._base import _Aggregation, operation_gb, operation_replacer, _MultiColumnAggregation
15
+ from onetick.py.aggregations.other import (
16
+ FirstTick, LastTick, OptionPrice, Ranking, Percentile, PortfolioPrice, MultiPortfolioPrice,
17
+ )
18
+ from onetick.py.aggregations.high_low import HighTick, LowTick
19
+ from onetick.py.aggregations.generic import Generic
20
+
21
+
22
+ class Compute(_Aggregation):
23
+ @property
24
+ def NAME(self):
25
+ return "COMPUTE"
26
+
27
+ @property
28
+ def EP(self):
29
+ try:
30
+ return otq.compute
31
+ except AttributeError:
32
+ return otq.ComputeEp
33
+
34
+ FIELDS_MAPPING = deepcopy(_Aggregation.FIELDS_MAPPING)
35
+ FIELDS_MAPPING['all_fields'] = 'SHOW_ALL_FIELDS'
36
+ FIELDS_TO_SKIP = ['column_name']
37
+
38
+ DISALLOWED_FIELDS = ["running", "all_fields", "bucket_interval", "bucket_time",
39
+ "bucket_units", "end_condition_per_group", "boundary_tick_bucket", "group_by"]
40
+ # [bucket_end_condition, all_fields] can not be used without bucket_units=flexible -> already disallowed
41
+
42
+ _validations_to_skip = ['running_all_fields']
43
+
44
+ def __init__(self,
45
+ *args,
46
+ **kwargs):
47
+ super().__init__(column=Column('Time'), *args, **kwargs)
48
+
49
+ self.aggrs = {}
50
+ self.has_multi_column_aggregations = False
51
+
52
+ # Aggregation from `all_fields` parameter is saved as regular aggregation in `self.aggrs` with empty field name
53
+ if isinstance(self.all_fields, str):
54
+ if self.all_fields.lower() not in ["last", "first", "high", "low", "when_ticks_exit_window"]:
55
+ raise ValueError(f"Unknown all_fields '{self.all_fields}' policy provided.")
56
+
57
+ if isinstance(self.all_fields, str) and self.all_fields.lower() != "when_ticks_exit_window":
58
+ if self.running:
59
+ raise ValueError(
60
+ "`all_fields` can't be one of 'last', 'first', 'high' or 'low' when `running=True`"
61
+ )
62
+
63
+ aggr_class = globals()[self.all_fields.capitalize() + "Tick"]
64
+ aggr_args = {}
65
+ if self.all_fields in {"high", "low"}:
66
+ aggr_args['column'] = "PRICE"
67
+
68
+ all_fields_aggr = aggr_class(**aggr_args)
69
+
70
+ self.add('', all_fields_aggr)
71
+
72
+ if isinstance(self.all_fields, (HighTick, LowTick)):
73
+ self.add('', self.all_fields)
74
+
75
+ if self.all_fields is True and not self.running:
76
+ self.add('', FirstTick())
77
+
78
+ def add(self, name: str, aggr: _Aggregation):
79
+ """Adds aggregation for multiple aggregation"""
80
+ self._validate_aggregation(aggr)
81
+ if name in self.aggrs:
82
+ raise KeyError(f'You are trying to output two aggregations to one field: "{name}"')
83
+
84
+ if name == '' and not isinstance(aggr, (FirstTick, LastTick, HighTick, LowTick)):
85
+ raise ValueError(
86
+ 'Only one instance of FirstTick, LastTick, HighTick or LowTick aggregation '
87
+ 'is allowed to have empty name in order to save compatibility with `all_fields` parameter'
88
+ )
89
+
90
+ if aggr.is_multi_column_aggregation:
91
+ self.has_multi_column_aggregations = True
92
+
93
+ self.aggrs[name] = aggr
94
+
95
+ def _validate_aggregation(self, aggr: _Aggregation):
96
+ if not isinstance(aggr, _Aggregation):
97
+ raise TypeError(f"It is allowed to pass only aggregations, but got '{type(aggr)}'")
98
+
99
+ if isinstance(aggr, OptionPrice) and not is_supported_agg_option_price():
100
+ raise NotImplementedError(f".agg() method does not support {type(aggr)} on OneTick {otp.__build__} build")
101
+
102
+ if isinstance(aggr, Ranking):
103
+ raise ValueError('Using ranking aggregation in otp.Source.agg method is not supported. '
104
+ 'Use otp.agg.ranking.apply() or otp.Source.ranking() methods.')
105
+
106
+ if isinstance(aggr, Percentile):
107
+ raise ValueError('Using percentile aggregation in otp.Source.agg method is not supported. '
108
+ 'Use otp.agg.percentile.apply() or otp.Source.percentile() methods.')
109
+
110
+ if isinstance(aggr, PortfolioPrice) and getattr(aggr, 'symbols'):
111
+ raise ValueError('It\'s not allowed to pass `symbols` parameter while using `portfolio_price` '
112
+ 'in compute or `Source.agg`')
113
+
114
+ if isinstance(aggr, MultiPortfolioPrice):
115
+ raise ValueError('Using multi_portfolio_price aggregation in otp.Source.agg method is not supported, '
116
+ 'because it outputs multiple ticks at once. '
117
+ 'Use otp.agg.percentile.apply() or otp.Source.percentile() methods.')
118
+
119
+ for field in self.DISALLOWED_FIELDS:
120
+ if field not in aggr.FIELDS_TO_SKIP and getattr(aggr, field) != aggr.FIELDS_DEFAULT[field]:
121
+ raise ValueError(f'"{field}" parameter can not be specified in multiple aggregation')
122
+
123
+ def validate_input_columns(self, src: 'Source'):
124
+ self._validate_aggregation_with_source(src)
125
+
126
+ def _validate_aggregation_with_source(self, src: 'Source'):
127
+ for name, aggr in self.aggrs.items():
128
+ aggr.validate_input_columns(src)
129
+
130
+ @property
131
+ def ep_params(self) -> Dict:
132
+ all_fields_orig = self.all_fields
133
+ if self.has_multi_column_aggregations:
134
+ self.all_fields = False
135
+ params = super().ep_params
136
+ if self.has_multi_column_aggregations:
137
+ self.all_fields = all_fields_orig
138
+
139
+ params['append_output_field_name'] = self.has_multi_column_aggregations
140
+
141
+ what_to_compute = []
142
+ for name, aggr in self.aggrs.items():
143
+ if name:
144
+ str_aggr = str(aggr) + " " + name
145
+ else:
146
+ agg_params = [f'{k}={aggr._attr2str(v)}' for k, v in aggr.ep_params.items()]
147
+ agg_params.append("KEEP_INITIAL_SCHEMA='true'")
148
+ str_aggr = aggr.NAME + "(" + ",".join(agg_params) + ")"
149
+
150
+ what_to_compute.append(str_aggr)
151
+
152
+ if what_to_compute:
153
+ params['COMPUTE'] = ','.join(what_to_compute)
154
+
155
+ return params
156
+
157
+ def to_ep(self, *args, **kwargs) -> otq.EpBase:
158
+ params = dict((k.lower(), v) for k, v in self.ep_params.items())
159
+ return self.EP(**params)
160
+
161
+ @operation_gb
162
+ @operation_replacer
163
+ def apply(self, src: 'Source') -> 'Source':
164
+ if not self.aggrs:
165
+ raise TypeError('Nothing to aggregate')
166
+
167
+ res = src.copy()
168
+ res, what_to_wrap = self._ts_to_long(res)
169
+ schema = self._get_common_schema(res, [key for key in self.aggrs.keys() if key])
170
+
171
+ # run _modify_source like it is in apply
172
+ for aggr in self.aggrs.values():
173
+ if isinstance(aggr, Generic):
174
+ aggr_schema = aggr._detect_query_fun_schema(res)
175
+
176
+ if aggr._query is None:
177
+ raise RuntimeError('Generic aggregation was not initialized correctly.')
178
+
179
+ # keep only fields from schema
180
+ query = aggr._query.table(**aggr_schema, strict=True)
181
+
182
+ # add LAST_TICK EP
183
+ default_tick = ','.join(f'{field} {ott.type2str(dtype)}' for field, dtype in aggr_schema.items())
184
+ aggr._query = query.sink(otq.LastTick(default_tick=default_tick), inplace=False)
185
+
186
+ # set empty query params for Generic aggregations
187
+ aggr._set_query_params()
188
+
189
+ aggr._modify_source(res)
190
+
191
+ # it's important to validate input schema before sinking
192
+ res.sink(self.to_ep())
193
+
194
+ for name, aggr in self.aggrs.items():
195
+ if not name:
196
+ # No need to check `all_fields` aggregation: it will have the same schema, as input source
197
+ continue
198
+
199
+ if not aggr.is_multi_column_aggregation:
200
+ agg_out_schema = aggr._get_output_schema(res, name=name)
201
+ else:
202
+ aggr_schema_base = aggr._get_output_schema(res)
203
+ if aggr.is_all_columns_aggregation:
204
+ aggr_schema_base = src.schema
205
+
206
+ agg_out_schema = {f'{name}.{key}': value for key, value in aggr_schema_base.items()}
207
+
208
+ schema.update(agg_out_schema)
209
+
210
+ res.schema.set(**schema)
211
+
212
+ if self.has_multi_column_aggregations:
213
+ res = self._remove_all_fields_tick_suffix(res)
214
+
215
+ res = self._long_to_ts(res, what_to_wrap)
216
+ return res
217
+
218
+ def _ts_to_long(self, src: 'Source') -> Tuple['Source', List]:
219
+ """Convert nsectime columns to long, so aggregation can work in a proper way"""
220
+ res = src.copy()
221
+ forward_result = namedtuple('forward_result', ('aggr', 'columns'))
222
+ what_to_wrap = []
223
+ for name, aggr in self.aggrs.items():
224
+ if '_ts_to_long' in dir(aggr) and callable(aggr._ts_to_long):
225
+ res, col, convert_back = aggr._ts_to_long(res, name)
226
+ if convert_back:
227
+ what_to_wrap.append(forward_result(aggr, col))
228
+ for r in what_to_wrap:
229
+ self.aggrs[r.columns.tmp_out_column] = self.aggrs.pop(r.columns.out_column)
230
+ return res, what_to_wrap
231
+
232
+ def _long_to_ts(self, src: 'Source', what_to_wrap: List) -> 'Source':
233
+ """Convert long columns to nsectime if needed (used along with _ts_to_long)"""
234
+ res = src.copy()
235
+ for r in what_to_wrap:
236
+ res = r.aggr._long_to_ts(res, r.columns)
237
+ self.aggrs[r.columns.out_column] = self.aggrs.pop(r.columns.tmp_out_column)
238
+ return res
239
+
240
+ def _remove_all_fields_tick_suffix(self, src: 'Source') -> 'Source':
241
+ """
242
+ renames columns (in query and schema) after compute with multi-column aggregations
243
+ """
244
+ schema = src.schema.copy()
245
+ rename_rule = {}
246
+ fields_to_drop = []
247
+
248
+ for name, aggr in self.aggrs.items():
249
+ if aggr.is_all_columns_aggregation or isinstance(aggr, Generic):
250
+ # In case of Generic: remove TICK_TIME field returned by LAST_TICK from generic aggregation
251
+ field_name = name if name else aggr.DEFAULT_OUTPUT_NAME
252
+ tick_time_field = f'{field_name}.TICK_TIME'
253
+ schema.update(**{tick_time_field: ott.nsectime})
254
+ fields_to_drop.append(tick_time_field)
255
+
256
+ if aggr.is_multi_column_aggregation:
257
+ continue
258
+
259
+ new_name = f'{name}.{aggr.DEFAULT_OUTPUT_NAME}'
260
+ schema[new_name] = schema.pop(name)
261
+ rename_rule[new_name] = name
262
+
263
+ res = src.copy()
264
+ res.schema.set(**schema)
265
+
266
+ if fields_to_drop:
267
+ res.drop(fields_to_drop, inplace=True)
268
+
269
+ if rename_rule:
270
+ res.rename(rename_rule, inplace=True)
271
+
272
+ all_fields_aggr = self.aggrs.get('')
273
+ if all_fields_aggr:
274
+ # drop first_tick columns duplicating group_by columns
275
+ all_fields_tick_name = all_fields_aggr.DEFAULT_OUTPUT_NAME
276
+
277
+ for group_by in self.group_by:
278
+ group_by_name = group_by
279
+ if isinstance(group_by, Column):
280
+ group_by_name = group_by.name
281
+ first_tick_field = f'{all_fields_tick_name}.{group_by_name}'
282
+ res.sink(otq.Passthrough(fields=first_tick_field, drop_fields=True))
283
+
284
+ res.sink(otq.RenameFieldsEp(rename_fields=rf"{all_fields_tick_name}\.(.*)=\1", use_regex=True))
285
+
286
+ return res