onetick-py 1.169.0__py3-none-any.whl → 1.171.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.
- onetick/py/__init__.py +8 -2
- onetick/py/_version.py +1 -1
- onetick/py/aggregations/functions.py +1 -1
- onetick/py/aggregations/order_book.py +15 -0
- onetick/py/cache.py +3 -3
- onetick/py/callback/callbacks.py +1 -1
- onetick/py/configuration.py +35 -9
- onetick/py/core/_internal/_state_objects.py +11 -6
- onetick/py/core/_internal/_state_vars.py +8 -2
- onetick/py/core/_source/source_methods/joins.py +1 -1
- onetick/py/core/_source/source_methods/misc.py +1 -1
- onetick/py/core/column_operations/accessors/str_accessor.py +3 -3
- onetick/py/core/column_operations/base.py +9 -9
- onetick/py/core/eval_query.py +3 -3
- onetick/py/core/per_tick_script.py +2 -0
- onetick/py/db/_inspection.py +82 -49
- onetick/py/math.py +265 -386
- onetick/py/misc.py +70 -38
- onetick/py/otq.py +18 -12
- onetick/py/run.py +75 -5
- onetick/py/sources/data_source.py +14 -8
- onetick/py/sources/order_book.py +33 -3
- onetick/py/sources/symbols.py +10 -1
- onetick/py/sources/ticks.py +1 -1
- onetick/py/state.py +14 -20
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/METADATA +1 -1
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/RECORD +31 -31
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/WHEEL +0 -0
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/entry_points.txt +0 -0
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/licenses/LICENSE +0 -0
- {onetick_py-1.169.0.dist-info → onetick_py-1.171.0.dist-info}/top_level.txt +0 -0
onetick/py/__init__.py
CHANGED
|
@@ -214,9 +214,15 @@ from onetick.py.core.per_tick_script import (
|
|
|
214
214
|
)
|
|
215
215
|
from onetick.py.callback import CallbackBase
|
|
216
216
|
from onetick.py.sql import SqlQuery
|
|
217
|
-
from onetick.py.run import run
|
|
217
|
+
from onetick.py.run import run, run_async
|
|
218
218
|
from onetick.py.math import rand, now
|
|
219
|
-
from onetick.py.misc import
|
|
219
|
+
from onetick.py.misc import (
|
|
220
|
+
bit_and, bit_or, bit_at, bit_xor, bit_not,
|
|
221
|
+
hash_code,
|
|
222
|
+
get_symbology_mapping,
|
|
223
|
+
get_onetick_version,
|
|
224
|
+
get_username,
|
|
225
|
+
)
|
|
220
226
|
from onetick.py.core.column import Column
|
|
221
227
|
from onetick.py.core.column_operations.base import Operation, Expr as expr, Raw as raw, OnetickParameter as param
|
|
222
228
|
from onetick.py.core.per_tick_script import remote, Once, once, logf, throw_exception
|
onetick/py/_version.py
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
# This file was generated automatically. DO NOT CHANGE.
|
|
2
|
-
VERSION = '1.
|
|
2
|
+
VERSION = '1.171.0'
|
|
@@ -956,7 +956,7 @@ def generic(*args, **kwargs):
|
|
|
956
956
|
|
|
957
957
|
>>> data = otp.Ticks({'A': [1, 2, 1]})
|
|
958
958
|
>>> def count_values(source, value):
|
|
959
|
-
... values
|
|
959
|
+
... values = source.where(source['A'] == value)
|
|
960
960
|
... return values.agg({'count': otp.agg.count()})
|
|
961
961
|
>>> data = otp.agg.generic(count_values).apply(data, value=1)
|
|
962
962
|
>>> otp.run(data)
|
|
@@ -146,6 +146,8 @@ class _OrderBookAggregation(_Aggregation, ABC):
|
|
|
146
146
|
self.max_initialization_days = max_initialization_days
|
|
147
147
|
self.book_uncross_method = book_uncross_method
|
|
148
148
|
self.dq_events_that_clear_book = ','.join(dq_events_that_clear_book) if dq_events_that_clear_book else None
|
|
149
|
+
self.bound_symbols = None
|
|
150
|
+
|
|
149
151
|
super().__init__(_Column('TIMESTAMP'), *args, **kwargs)
|
|
150
152
|
|
|
151
153
|
def _param_validation(self):
|
|
@@ -170,6 +172,19 @@ class _OrderBookAggregation(_Aggregation, ABC):
|
|
|
170
172
|
raise TypeError(f"Aggregation `{self.NAME}` need these columns: "
|
|
171
173
|
f"BUY_SELL_FLAG, PRICE, SIZE and (UPDATE_TIME or DELETED_TIME)")
|
|
172
174
|
|
|
175
|
+
def to_ep(self, *args, **kwargs):
|
|
176
|
+
ob_ep = super().to_ep(*args, **kwargs)
|
|
177
|
+
if self.bound_symbols:
|
|
178
|
+
ob_ep = ob_ep.symbols(self.bound_symbols)
|
|
179
|
+
|
|
180
|
+
return ob_ep
|
|
181
|
+
|
|
182
|
+
def set_bound_symbols(self, bound_symbols=None):
|
|
183
|
+
if isinstance(bound_symbols, str):
|
|
184
|
+
bound_symbols = [bound_symbols]
|
|
185
|
+
|
|
186
|
+
self.bound_symbols = bound_symbols
|
|
187
|
+
|
|
173
188
|
|
|
174
189
|
class ObSnapshot(_OrderBookAggregation):
|
|
175
190
|
NAME = 'OB_SNAPSHOT'
|
onetick/py/cache.py
CHANGED
|
@@ -113,7 +113,7 @@ def create_cache(
|
|
|
113
113
|
The cache will be cleared every X seconds, triggering new query executions when data is requested.
|
|
114
114
|
tick_type: str
|
|
115
115
|
Tick type.
|
|
116
|
-
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`,
|
|
116
|
+
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`, :pandas:`pandas.DataFrame`, optional
|
|
117
117
|
``symbols`` parameter of ``otp.run()``.
|
|
118
118
|
db: str
|
|
119
119
|
Database.
|
|
@@ -259,7 +259,7 @@ def delete_cache(
|
|
|
259
259
|
:func:`<onetick.py.create_cache>`.
|
|
260
260
|
tick_type: str
|
|
261
261
|
Tick type.
|
|
262
|
-
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`,
|
|
262
|
+
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`, :pandas:`pandas.DataFrame`, optional
|
|
263
263
|
``symbols`` parameter of ``otp.run()``.
|
|
264
264
|
db: str
|
|
265
265
|
Database.
|
|
@@ -329,7 +329,7 @@ def modify_cache_config(
|
|
|
329
329
|
New value of configuration parameter. Will be converted to string.
|
|
330
330
|
tick_type: str
|
|
331
331
|
Tick type.
|
|
332
|
-
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`,
|
|
332
|
+
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`, :pandas:`pandas.DataFrame`, optional
|
|
333
333
|
``symbols`` parameter of ``otp.run()``.
|
|
334
334
|
db: str
|
|
335
335
|
Database.
|
onetick/py/callback/callbacks.py
CHANGED
|
@@ -18,7 +18,7 @@ class LogCallback(CallbackBase):
|
|
|
18
18
|
|
|
19
19
|
class ManualDataframeCallback(CallbackBase):
|
|
20
20
|
"""
|
|
21
|
-
This callback class can be used to generate the same pandas.DataFrame result as in otp.run.
|
|
21
|
+
This callback class can be used to generate the same :pandas:`pandas.DataFrame` result as in otp.run.
|
|
22
22
|
Unlike otp.run, here result is constructed manually, one tick at a time.
|
|
23
23
|
This may lead to lower memory usage in some cases.
|
|
24
24
|
See task PY-863 for details.
|
onetick/py/configuration.py
CHANGED
|
@@ -32,6 +32,28 @@ def parse_datetime(s):
|
|
|
32
32
|
)
|
|
33
33
|
|
|
34
34
|
|
|
35
|
+
def parse_bool(value) -> Optional[bool]:
|
|
36
|
+
str_value = str(value).lower()
|
|
37
|
+
if str_value in ('1', 'true', 'yes'):
|
|
38
|
+
return True
|
|
39
|
+
elif str_value in ('0', 'false', 'no'):
|
|
40
|
+
return False
|
|
41
|
+
else:
|
|
42
|
+
return None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def parse_true(value) -> bool:
|
|
46
|
+
return parse_bool(value) is True
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def parse_bool_or_string(value) -> Union[bool, str]:
|
|
50
|
+
parsed_value = parse_bool(value)
|
|
51
|
+
if parsed_value is not None:
|
|
52
|
+
return parsed_value
|
|
53
|
+
else:
|
|
54
|
+
return str(value)
|
|
55
|
+
|
|
56
|
+
|
|
35
57
|
def _env_func_concurrency(value: str) -> Optional[int]:
|
|
36
58
|
if not value:
|
|
37
59
|
return None
|
|
@@ -197,7 +219,7 @@ class OtpShowStackInfoProperty(OtpProperty):
|
|
|
197
219
|
"""
|
|
198
220
|
@staticmethod
|
|
199
221
|
def parser(value):
|
|
200
|
-
return
|
|
222
|
+
return parse_true(value)
|
|
201
223
|
|
|
202
224
|
def __init__(self, *args, **kwargs):
|
|
203
225
|
super().__init__(*args, **kwargs)
|
|
@@ -492,7 +514,7 @@ class Config:
|
|
|
492
514
|
base_default=False,
|
|
493
515
|
allowed_types=[bool],
|
|
494
516
|
env_var_name='OTP_PRESORT_FORCE_DEFAULT_CONCURRENCY',
|
|
495
|
-
env_var_func=
|
|
517
|
+
env_var_func=parse_true,
|
|
496
518
|
)
|
|
497
519
|
|
|
498
520
|
# default batch size is set to 0, so the number of symbols in batch is not limited
|
|
@@ -623,10 +645,14 @@ class Config:
|
|
|
623
645
|
)
|
|
624
646
|
|
|
625
647
|
trusted_certificates_file = OtpProperty(
|
|
626
|
-
description='
|
|
648
|
+
description='Either a boolean, in which case it controls whether we verify the server TLS certificate '
|
|
649
|
+
'or a string with the path to the file with list of '
|
|
650
|
+
'trusted Certificate Authority certificates for WebAPI requests. '
|
|
651
|
+
'Default behaviour implies verification is enabled.',
|
|
627
652
|
base_default=None,
|
|
628
|
-
allowed_types=str,
|
|
653
|
+
allowed_types=(bool, str),
|
|
629
654
|
env_var_name='OTP_SSL_CERT_FILE',
|
|
655
|
+
env_var_func=parse_bool_or_string,
|
|
630
656
|
)
|
|
631
657
|
|
|
632
658
|
max_expected_ticks_per_symbol = OtpProperty(
|
|
@@ -641,7 +667,7 @@ class Config:
|
|
|
641
667
|
base_default=False,
|
|
642
668
|
allowed_types=(str, bool, int),
|
|
643
669
|
env_var_name='OTP_SHOW_STACK_INFO',
|
|
644
|
-
env_var_func=
|
|
670
|
+
env_var_func=parse_true,
|
|
645
671
|
)
|
|
646
672
|
|
|
647
673
|
log_symbol = OtpProperty(
|
|
@@ -651,7 +677,7 @@ class Config:
|
|
|
651
677
|
base_default=False,
|
|
652
678
|
allowed_types=(str, bool, int),
|
|
653
679
|
env_var_name='OTP_LOG_SYMBOL',
|
|
654
|
-
env_var_func=
|
|
680
|
+
env_var_func=parse_true,
|
|
655
681
|
)
|
|
656
682
|
|
|
657
683
|
ignore_ticks_in_unentitled_time_range = OtpProperty(
|
|
@@ -659,7 +685,7 @@ class Config:
|
|
|
659
685
|
base_default=False,
|
|
660
686
|
env_var_name='OTP_IGNORE_TICKS_IN_UNENTITLED_TIME_RANGE',
|
|
661
687
|
allowed_types=(str, bool, int),
|
|
662
|
-
env_var_func=
|
|
688
|
+
env_var_func=parse_true,
|
|
663
689
|
)
|
|
664
690
|
|
|
665
691
|
main_query_generated_filename = OtpProperty(
|
|
@@ -685,7 +711,7 @@ class Config:
|
|
|
685
711
|
base_default=False,
|
|
686
712
|
env_var_name='OTP_OTQ_DEBUG_MODE',
|
|
687
713
|
allowed_types=(str, bool, int),
|
|
688
|
-
env_var_func=
|
|
714
|
+
env_var_func=parse_true,
|
|
689
715
|
)
|
|
690
716
|
|
|
691
717
|
allow_lowercase_in_saved_fields = OtpProperty(
|
|
@@ -702,7 +728,7 @@ class Config:
|
|
|
702
728
|
base_default=True,
|
|
703
729
|
env_var_name='OTP_CLEAN_UP_TMP_FILES',
|
|
704
730
|
allowed_types=(str, bool, int),
|
|
705
|
-
env_var_func=
|
|
731
|
+
env_var_func=parse_true,
|
|
706
732
|
)
|
|
707
733
|
|
|
708
734
|
default_schema_policy = OtpProperty(
|
|
@@ -165,7 +165,7 @@ class _StateBase(ABC):
|
|
|
165
165
|
data.state_vars['VAR'] = otp.state.tick_list()
|
|
166
166
|
def fun(min_value):
|
|
167
167
|
t = otp.Ticks(X=[123, 234])
|
|
168
|
-
t
|
|
168
|
+
t = t.where(t['X'] > min_value)
|
|
169
169
|
return t
|
|
170
170
|
data = data.state_vars['VAR'].modify_from_query(fun, params={'min_value': 200})
|
|
171
171
|
data = data.state_vars['VAR'].dump()
|
|
@@ -344,8 +344,9 @@ class _TickSequence(_StateBase):
|
|
|
344
344
|
def __init__(self, name, obj_ref, default_value, scope, schema=None, **kwargs):
|
|
345
345
|
if kwargs:
|
|
346
346
|
raise ValueError(f"Unknown parameters for '{self.__class__.__name__}': {list(kwargs)}")
|
|
347
|
-
|
|
348
|
-
|
|
347
|
+
from onetick.py.core.source import Source
|
|
348
|
+
if default_value is not None and not isinstance(default_value, (_QueryEvalWrapper, Source)):
|
|
349
|
+
raise ValueError('only otp.eval and otp.Source objects can be used as initial value for tick sequences')
|
|
349
350
|
if default_value is not None and schema is not None:
|
|
350
351
|
# TODO: check that the two schemas align or possibly that they are exactly the same
|
|
351
352
|
pass
|
|
@@ -396,9 +397,13 @@ class _TickSequence(_StateBase):
|
|
|
396
397
|
self._schema = None
|
|
397
398
|
if not self._schema:
|
|
398
399
|
if self.default_value is not None:
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
400
|
+
from onetick.py.core.source import Source
|
|
401
|
+
if isinstance(self.default_value, _QueryEvalWrapper):
|
|
402
|
+
# If tick sequence is initialized from eval,
|
|
403
|
+
# then we get schema from the Source in eval.
|
|
404
|
+
self._schema = self.default_value.query.schema.copy()
|
|
405
|
+
elif isinstance(self.default_value, Source):
|
|
406
|
+
self._schema = self.default_value.schema.copy()
|
|
402
407
|
else:
|
|
403
408
|
# If tick sequence is initialized as empty,
|
|
404
409
|
# then it's schema will be derived from the schema of the parent object (e.g. source)
|
|
@@ -81,7 +81,13 @@ class StateVars:
|
|
|
81
81
|
str_type = type2str(base_type)
|
|
82
82
|
|
|
83
83
|
expression = f'{str_type} {name}'
|
|
84
|
+
|
|
85
|
+
import onetick.py as otp
|
|
84
86
|
if value.default_value is not None:
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
if isinstance(value.default_value, otp.Source):
|
|
88
|
+
value_expression = otp.eval(value.default_value).to_eval_string(self._owner._tmp_otq)
|
|
89
|
+
else:
|
|
90
|
+
# TODO: PY-952: use to_eval_string(self._owner._tmp_otq) here if otp.eval is passed
|
|
91
|
+
value_expression = value2str(value.default_value)
|
|
92
|
+
expression += f' = {value_expression}'
|
|
87
93
|
self._owner.sink(otq.DeclareStateVariables(variables=expression, scope=value.scope))
|
|
@@ -394,7 +394,7 @@ def join_with_collection(
|
|
|
394
394
|
>>>
|
|
395
395
|
>>> trd_qte = trd_qte.state_vars['LAST_QUOTE_PER_EXCHANGE'].update(where=trd_qte['TICK_TYPE'] == 'QTE',
|
|
396
396
|
... value_fields=['ASK_PRICE', 'BID_PRICE'])
|
|
397
|
-
>>> trd
|
|
397
|
+
>>> trd = trd_qte.where(trd_qte['TICK_TYPE'] == 'TRD')
|
|
398
398
|
>>> trd.drop(['ASK_PRICE', 'BID_PRICE', 'EXCHANGE'], inplace=True)
|
|
399
399
|
>>> trd = trd.join_with_collection('LAST_QUOTE_PER_EXCHANGE')
|
|
400
400
|
>>> otp.run(trd)[['PRICE', 'SIZE', 'EXCHANGE', 'ASK_PRICE', 'BID_PRICE']]
|
|
@@ -514,7 +514,7 @@ def cache(
|
|
|
514
514
|
the result data not found in the cache. Otherwise, the cache remains unchanged.
|
|
515
515
|
tick_type: str
|
|
516
516
|
Tick type.
|
|
517
|
-
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`,
|
|
517
|
+
symbol: str, list of str, list of otq.Symbol, :py:class:`onetick.py.Source`, :pandas:`pandas.DataFrame`, optional
|
|
518
518
|
``symbols`` parameter of ``otp.run()``.
|
|
519
519
|
db: str
|
|
520
520
|
Database.
|
|
@@ -227,7 +227,7 @@ class _StrAccessor(_Accessor):
|
|
|
227
227
|
|
|
228
228
|
>>> q = otp.DataSource('US_COMP', tick_type='TRD', symbols=['SPY']) # doctest: +SKIP
|
|
229
229
|
>>> q = q[['PRICE', 'SIZE', 'COND', 'EXCHANGE']] # doctest: +SKIP
|
|
230
|
-
>>> q
|
|
230
|
+
>>> q = q.where(q['COND'].str.match('^[^O6TUHILNRWZ47QMBCGPV]*$')) # doctest: +SKIP
|
|
231
231
|
>>> otp.run(q, start=otp.dt(2023, 5, 15, 9, 30), end=otp.dt(2023, 5, 15, 9, 30, 1)) # doctest: +SKIP
|
|
232
232
|
Time PRICE SIZE COND EXCHANGE
|
|
233
233
|
0 2023-05-15 09:30:00.000776704 412.220 247 Z
|
|
@@ -1225,7 +1225,7 @@ class _StrAccessor(_Accessor):
|
|
|
1225
1225
|
This function can be used to filter out ticks:
|
|
1226
1226
|
|
|
1227
1227
|
>>> data = otp.Ticks(X=['a', 'ab', 'b_', 'b%'])
|
|
1228
|
-
>>> data
|
|
1228
|
+
>>> data = data.where(data['X'].str.like('a%'))
|
|
1229
1229
|
>>> otp.run(data)
|
|
1230
1230
|
Time X
|
|
1231
1231
|
0 2003-12-01 00:00:00.000 a
|
|
@@ -1335,7 +1335,7 @@ class _StrAccessor(_Accessor):
|
|
|
1335
1335
|
:skipif: not is_ilike_supported()
|
|
1336
1336
|
|
|
1337
1337
|
data = otp.Ticks(X=['a', 'ab', 'Ab', 'b_'])
|
|
1338
|
-
data
|
|
1338
|
+
data = data.where(data['X'].str.ilike('a%'))
|
|
1339
1339
|
df = otp.run(data)
|
|
1340
1340
|
print(df)
|
|
1341
1341
|
|
|
@@ -725,7 +725,7 @@ class Operation:
|
|
|
725
725
|
Examples
|
|
726
726
|
--------
|
|
727
727
|
>>> t = otp.Ticks(A=range(4))
|
|
728
|
-
>>> t
|
|
728
|
+
>>> t = t.where(~(t['A'] > 1))
|
|
729
729
|
>>> otp.run(t)[['A']]
|
|
730
730
|
A
|
|
731
731
|
0 0
|
|
@@ -741,7 +741,7 @@ class Operation:
|
|
|
741
741
|
Examples
|
|
742
742
|
--------
|
|
743
743
|
>>> t = otp.Ticks(A=range(4))
|
|
744
|
-
>>> t
|
|
744
|
+
>>> t = t.where((t['A'] == 1))
|
|
745
745
|
>>> otp.run(t)[['A']]
|
|
746
746
|
A
|
|
747
747
|
0 1
|
|
@@ -756,7 +756,7 @@ class Operation:
|
|
|
756
756
|
Examples
|
|
757
757
|
--------
|
|
758
758
|
>>> t = otp.Ticks(A=range(4))
|
|
759
|
-
>>> t
|
|
759
|
+
>>> t = t.where((t['A'] != 1))
|
|
760
760
|
>>> otp.run(t)[['A']]
|
|
761
761
|
A
|
|
762
762
|
0 0
|
|
@@ -773,7 +773,7 @@ class Operation:
|
|
|
773
773
|
Examples
|
|
774
774
|
--------
|
|
775
775
|
>>> t = otp.Ticks(A=range(4))
|
|
776
|
-
>>> t
|
|
776
|
+
>>> t = t.where((t['A'] == 1) | (t['A'] == 2))
|
|
777
777
|
>>> otp.run(t)[['A']]
|
|
778
778
|
A
|
|
779
779
|
0 1
|
|
@@ -789,7 +789,7 @@ class Operation:
|
|
|
789
789
|
Examples
|
|
790
790
|
--------
|
|
791
791
|
>>> t = otp.Ticks(A=[1, 1], B=[1, 2])
|
|
792
|
-
>>> t
|
|
792
|
+
>>> t = t.where((t['A'] == 1) & (t['B'] == 1))
|
|
793
793
|
>>> otp.run(t)[['A', 'B']]
|
|
794
794
|
A B
|
|
795
795
|
0 1 1
|
|
@@ -804,7 +804,7 @@ class Operation:
|
|
|
804
804
|
Examples
|
|
805
805
|
--------
|
|
806
806
|
>>> t = otp.Ticks(A=range(4))
|
|
807
|
-
>>> t
|
|
807
|
+
>>> t = t.where(t['A'] <= 2)
|
|
808
808
|
>>> otp.run(t)[['A']]
|
|
809
809
|
A
|
|
810
810
|
0 0
|
|
@@ -821,7 +821,7 @@ class Operation:
|
|
|
821
821
|
Examples
|
|
822
822
|
--------
|
|
823
823
|
>>> t = otp.Ticks(A=range(4))
|
|
824
|
-
>>> t
|
|
824
|
+
>>> t = t.where(t['A'] < 2)
|
|
825
825
|
>>> otp.run(t)[['A']]
|
|
826
826
|
A
|
|
827
827
|
0 0
|
|
@@ -837,7 +837,7 @@ class Operation:
|
|
|
837
837
|
Examples
|
|
838
838
|
--------
|
|
839
839
|
>>> t = otp.Ticks(A=range(4))
|
|
840
|
-
>>> t
|
|
840
|
+
>>> t = t.where(t['A'] >= 2)
|
|
841
841
|
>>> otp.run(t)[['A']]
|
|
842
842
|
A
|
|
843
843
|
0 2
|
|
@@ -853,7 +853,7 @@ class Operation:
|
|
|
853
853
|
Examples
|
|
854
854
|
--------
|
|
855
855
|
>>> t = otp.Ticks(A=range(4))
|
|
856
|
-
>>> t
|
|
856
|
+
>>> t = t.where(t['A'] > 2)
|
|
857
857
|
>>> otp.run(t)[['A']]
|
|
858
858
|
A
|
|
859
859
|
0 3
|
onetick/py/core/eval_query.py
CHANGED
|
@@ -171,7 +171,7 @@ def eval(query, symbol=None, start=None, end=None,
|
|
|
171
171
|
>>> data = otp.Ticks(X=[1, 2, 3])
|
|
172
172
|
>>> # note that in this case column WHERE must be specified,
|
|
173
173
|
>>> # because evaluated query returns tick with more than one field
|
|
174
|
-
>>> data
|
|
174
|
+
>>> data = data.where(otp.eval(get_filter, a=0, b=2)['WHERE'])
|
|
175
175
|
>>> otp.run(data)
|
|
176
176
|
Time X
|
|
177
177
|
0 2003-12-01 1
|
|
@@ -183,12 +183,12 @@ def eval(query, symbol=None, start=None, end=None,
|
|
|
183
183
|
... 'TICK_TYPE': ['TRD', 'QTE'],
|
|
184
184
|
... 'WHERE': ['PRICE>=1.4', 'ASK_PRICE>=1.4']
|
|
185
185
|
... })
|
|
186
|
-
... res
|
|
186
|
+
... res = res.where(res['TICK_TYPE'] == tick_type)
|
|
187
187
|
... return res.drop(['TICK_TYPE'])
|
|
188
188
|
>>> t = otp.DataSource('US_COMP::TRD')
|
|
189
189
|
>>> # note that in this case column WHERE do not need to be specified,
|
|
190
190
|
>>> # because evaluated query returns tick with only one field
|
|
191
|
-
>>> t
|
|
191
|
+
>>> t = t.where(otp.eval(filter_by_tt, tick_type=t['_TICK_TYPE']))
|
|
192
192
|
>>> otp.run(t, start=otp.dt(2022, 3, 1), end=otp.dt(2022, 3, 2))
|
|
193
193
|
Time PRICE SIZE
|
|
194
194
|
0 2022-03-01 00:00:00.001 1.4 10
|
|
@@ -1095,6 +1095,8 @@ class CaseExpressionParser(ExpressionParser):
|
|
|
1095
1095
|
try:
|
|
1096
1096
|
return super().call(expr)
|
|
1097
1097
|
except Exception:
|
|
1098
|
+
if orig_err is not None:
|
|
1099
|
+
raise err from orig_err
|
|
1098
1100
|
raise ValueError(
|
|
1099
1101
|
f"Can't convert function '{astunparse(expr)}' to CASE() expression."
|
|
1100
1102
|
) from err
|
onetick/py/db/_inspection.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import itertools
|
|
1
2
|
import warnings
|
|
2
3
|
from typing import Union, Iterable, Tuple, Optional, Any, Literal
|
|
3
4
|
from datetime import date as dt_date, datetime, timedelta
|
|
@@ -7,6 +8,7 @@ from dateutil.tz import gettz
|
|
|
7
8
|
|
|
8
9
|
import onetick.py as otp
|
|
9
10
|
from onetick.py import configuration, utils
|
|
11
|
+
from onetick.py import types as ott
|
|
10
12
|
from onetick.py.compatibility import is_native_plus_zstd_supported, is_show_db_list_show_description_supported
|
|
11
13
|
from onetick.py.core import db_constants
|
|
12
14
|
from onetick.py.otq import otq
|
|
@@ -909,10 +911,12 @@ class DB:
|
|
|
909
911
|
|
|
910
912
|
|
|
911
913
|
def databases(
|
|
912
|
-
context=utils.default, derived: bool = False, readable_only: bool = True,
|
|
913
|
-
|
|
914
|
+
context=utils.default, derived: bool = False, readable_only: bool = True,
|
|
915
|
+
fetch_description: Optional[bool] = None,
|
|
916
|
+
as_table: bool = False,
|
|
917
|
+
) -> Union[dict[str, DB], pd.DataFrame]:
|
|
914
918
|
"""
|
|
915
|
-
Gets all available databases in the ``context
|
|
919
|
+
Gets all available databases in the ``context``.
|
|
916
920
|
|
|
917
921
|
Parameters
|
|
918
922
|
----------
|
|
@@ -931,6 +935,9 @@ def databases(
|
|
|
931
935
|
fetch_description: bool
|
|
932
936
|
If set to True, retrieves descriptions for databases and puts them into ``description`` property of
|
|
933
937
|
:py:class:`~onetick.py.DB` objects in a returned dict.
|
|
938
|
+
as_table: bool
|
|
939
|
+
If False (default), this function returns a dictionary of database names and database objects.
|
|
940
|
+
If True, returns a :pandas:`pandas.DataFrame` table where each row contains the info for each database.
|
|
934
941
|
|
|
935
942
|
See also
|
|
936
943
|
--------
|
|
@@ -940,50 +947,66 @@ def databases(
|
|
|
940
947
|
|
|
941
948
|
Returns
|
|
942
949
|
-------
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
with ``context`` specified.
|
|
946
|
-
"""
|
|
947
|
-
if fetch_description and not is_show_db_list_show_description_supported():
|
|
948
|
-
fetch_description = False
|
|
950
|
+
Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
|
|
951
|
+
or :pandas:`pandas.DataFrame` object depending on ``as_table`` parameter.
|
|
949
952
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
otq.AccessInfo(info_type='DATABASES', show_for_all_users=False, deep_scan=True).tick_type('ANY')
|
|
953
|
-
>> otq.Passthrough('DB_NAME,READ_ACCESS')
|
|
954
|
-
>> otq.WhereClause(where='READ_ACCESS = 1')
|
|
955
|
-
)
|
|
953
|
+
Examples
|
|
954
|
+
--------
|
|
956
955
|
|
|
957
|
-
|
|
958
|
-
join = otq.Join(
|
|
959
|
-
left_source='LEFT', join_type='LEFT_OUTER', join_criteria='LEFT.DB_NAME = RIGHT.DATABASE_NAME'
|
|
960
|
-
)
|
|
961
|
-
|
|
962
|
-
_ = node.set_node_name('LEFT') >> join
|
|
963
|
-
_ = (
|
|
964
|
-
otq.ShowDbList(show_description=fetch_description).tick_type('ANY')
|
|
965
|
-
>> otq.Passthrough('DATABASE_NAME,DESCRIPTION').set_node_name('RIGHT')
|
|
966
|
-
>> join
|
|
967
|
-
)
|
|
968
|
-
|
|
969
|
-
node = (
|
|
970
|
-
join >> otq.Passthrough('LEFT.DB_NAME,RIGHT.DESCRIPTION')
|
|
971
|
-
>> otq.RenameFields("LEFT.DB_NAME=DB_NAME,RIGHT.DESCRIPTION=DESCRIPTION")
|
|
972
|
-
)
|
|
973
|
-
else:
|
|
974
|
-
db_list_kwargs = {}
|
|
975
|
-
output_fields = ['DATABASE_NAME']
|
|
976
|
-
if fetch_description:
|
|
977
|
-
db_list_kwargs['show_description'] = fetch_description
|
|
978
|
-
output_fields.append('DESCRIPTION')
|
|
956
|
+
Get the dictionary of database names and objects:
|
|
979
957
|
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
958
|
+
>>> otp.databases() # doctest: +SKIP
|
|
959
|
+
{'ABU_DHABI': <onetick.py.db._inspection.DB at 0x7f9413a5e8e0>,
|
|
960
|
+
'ABU_DHABI_BARS': <onetick.py.db._inspection.DB at 0x7f9413a5ef40>,
|
|
961
|
+
'ABU_DHABI_DAILY': <onetick.py.db._inspection.DB at 0x7f9413a5eac0>,
|
|
962
|
+
'ALPHA': <onetick.py.db._inspection.DB at 0x7f9413a5e940>,
|
|
963
|
+
'ALPHA_X': <onetick.py.db._inspection.DB at 0x7f9413a5e490>,
|
|
964
|
+
...
|
|
965
|
+
}
|
|
966
|
+
|
|
967
|
+
Get a table with database info:
|
|
984
968
|
|
|
985
|
-
|
|
986
|
-
|
|
969
|
+
>>> otp.databases(as_table=True) # doctest: +SKIP
|
|
970
|
+
Time DB_NAME READ_ACCESS WRITE_ACCESS ...
|
|
971
|
+
0 2003-01-01 ABU_DHABI 1 0 ...
|
|
972
|
+
1 2003-01-01 ABU_DHABI_BARS 1 1 ...
|
|
973
|
+
2 2003-01-01 ABU_DHABI_DAILY 1 1 ...
|
|
974
|
+
3 2003-01-01 ALPHA 1 1 ...
|
|
975
|
+
4 2003-01-01 ALPHA_X 1 1 ...
|
|
976
|
+
... ... ... ... ... ...
|
|
977
|
+
"""
|
|
978
|
+
show_db_list_kwargs = {}
|
|
979
|
+
if fetch_description is not None and is_show_db_list_show_description_supported() and (
|
|
980
|
+
'show_description' in otq.ShowDbList.Parameters.list_parameters()
|
|
981
|
+
):
|
|
982
|
+
show_db_list_kwargs['show_description'] = fetch_description
|
|
983
|
+
|
|
984
|
+
node = otq.AccessInfo(info_type='DATABASES', show_for_all_users=False, deep_scan=True).tick_type('ANY')
|
|
985
|
+
# for some reason ACCESS_INFO sometimes return several ticks
|
|
986
|
+
# for the same database with different SERVER_ADDRESS values
|
|
987
|
+
# so we get only the first tick
|
|
988
|
+
node = (
|
|
989
|
+
node >> otq.NumTicks(is_running_aggr=True, group_by='DB_NAME',
|
|
990
|
+
all_fields_for_sliding=False, output_field_name='NUM_TICKS')
|
|
991
|
+
>> otq.WhereClause(where='NUM_TICKS = 1')
|
|
992
|
+
>> otq.Passthrough('NUM_TICKS', drop_fields=True)
|
|
993
|
+
)
|
|
994
|
+
if readable_only:
|
|
995
|
+
node = node >> otq.WhereClause(where='READ_ACCESS = 1')
|
|
996
|
+
|
|
997
|
+
left = node.set_node_name('LEFT')
|
|
998
|
+
right = otq.ShowDbList(**show_db_list_kwargs).tick_type('ANY').set_node_name('RIGHT')
|
|
999
|
+
join = otq.Join(
|
|
1000
|
+
left_source='LEFT', join_type='INNER', join_criteria='LEFT.DB_NAME = RIGHT.DATABASE_NAME',
|
|
1001
|
+
add_source_prefix=False,
|
|
1002
|
+
)
|
|
1003
|
+
left >> join << right # pylint: disable=pointless-statement
|
|
1004
|
+
node = join >> otq.Passthrough('LEFT.TIMESTAMP,RIGHT.TIMESTAMP,DATABASE_NAME', drop_fields=True)
|
|
1005
|
+
|
|
1006
|
+
# times bigger than datetime.max are not representable in python
|
|
1007
|
+
max_dt = ott.value2str(datetime.max)
|
|
1008
|
+
node = node >> otq.UpdateFields(set=f'INTERVAL_START={max_dt}', where=f'INTERVAL_START > {max_dt}')
|
|
1009
|
+
node = node >> otq.UpdateFields(set=f'INTERVAL_END={max_dt}', where=f'INTERVAL_END > {max_dt}')
|
|
987
1010
|
|
|
988
1011
|
dbs = otp.run(node,
|
|
989
1012
|
symbols='LOCAL::',
|
|
@@ -992,15 +1015,20 @@ def databases(
|
|
|
992
1015
|
end=db_constants.DEFAULT_END_DATE,
|
|
993
1016
|
context=context)
|
|
994
1017
|
|
|
1018
|
+
if as_table:
|
|
1019
|
+
return dbs
|
|
1020
|
+
|
|
995
1021
|
# WebAPI returns empty DataFrame (no columns) if there are no databases
|
|
996
1022
|
if len(dbs) == 0:
|
|
997
1023
|
return {}
|
|
998
1024
|
|
|
999
|
-
db_list = list(dbs['DB_NAME']
|
|
1000
|
-
|
|
1025
|
+
db_list = list(dbs['DB_NAME'])
|
|
1026
|
+
db_description_list = dbs['DESCRIPTION'] if 'DESCRIPTION' in dbs else itertools.repeat('')
|
|
1027
|
+
merged_db_list = list(zip(db_list, db_description_list))
|
|
1001
1028
|
|
|
1002
1029
|
db_dict = {
|
|
1003
|
-
db_name: DB(db_name, description=db_description, context=context)
|
|
1030
|
+
db_name: DB(db_name, description=db_description, context=context)
|
|
1031
|
+
for db_name, db_description in merged_db_list
|
|
1004
1032
|
}
|
|
1005
1033
|
|
|
1006
1034
|
if derived:
|
|
@@ -1018,6 +1046,7 @@ def derived_databases(
|
|
|
1018
1046
|
selection_criteria='all',
|
|
1019
1047
|
db=None,
|
|
1020
1048
|
db_discovery_scope='query_host_only',
|
|
1049
|
+
as_table: bool = False,
|
|
1021
1050
|
) -> dict[str, DB]:
|
|
1022
1051
|
"""
|
|
1023
1052
|
Gets available derived databases.
|
|
@@ -1052,6 +1081,9 @@ def derived_databases(
|
|
|
1052
1081
|
an attempt will be performed to get derived databases from all reachable hosts.
|
|
1053
1082
|
When *query_host_only* is specified,
|
|
1054
1083
|
only derived databases from the host on which the query is performed will be returned.
|
|
1084
|
+
as_table: bool
|
|
1085
|
+
If False (default), this function returns a dictionary of database names and database objects.
|
|
1086
|
+
If True, returns a :pandas:`pandas.DataFrame` table where each row contains the info for each database.
|
|
1055
1087
|
|
|
1056
1088
|
See also
|
|
1057
1089
|
--------
|
|
@@ -1059,9 +1091,8 @@ def derived_databases(
|
|
|
1059
1091
|
|
|
1060
1092
|
Returns
|
|
1061
1093
|
-------
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
with ``context`` specified.
|
|
1094
|
+
Dict where keys are database names and values are :class:`DB <onetick.py.db._inspection.DB>` objects
|
|
1095
|
+
or :pandas:`pandas.DataFrame` object depending on ``as_table`` parameter.
|
|
1065
1096
|
"""
|
|
1066
1097
|
if start and end:
|
|
1067
1098
|
time_range = otq.ShowDerivedDbList.TimeRange.QUERY_TIME_INTERVAL
|
|
@@ -1089,6 +1120,8 @@ def derived_databases(
|
|
|
1089
1120
|
ep = ep.tick_type('ANY')
|
|
1090
1121
|
db = db or 'LOCAL'
|
|
1091
1122
|
dbs = otp.run(ep, symbols=f'{db}::', start=start, end=end, context=context)
|
|
1123
|
+
if as_table:
|
|
1124
|
+
return dbs
|
|
1092
1125
|
if len(dbs) == 0:
|
|
1093
1126
|
return {}
|
|
1094
1127
|
db_list = list(dbs['DERIVED_DB_NAME'])
|