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,70 @@
|
|
|
1
|
+
from .helpers import (
|
|
2
|
+
get_symbol_list_from_df,
|
|
3
|
+
JSONEncoder,
|
|
4
|
+
json_dumps,
|
|
5
|
+
query_properties_to_dict,
|
|
6
|
+
query_properties_from_dict,
|
|
7
|
+
symbol_date_to_str,
|
|
8
|
+
)
|
|
9
|
+
from .temp import (
|
|
10
|
+
File,
|
|
11
|
+
PermanentFile,
|
|
12
|
+
TmpFile,
|
|
13
|
+
TmpDir,
|
|
14
|
+
GeneratedDir,
|
|
15
|
+
TMP_CONFIGS_DIR,
|
|
16
|
+
ONE_TICK_TMP_DIR,
|
|
17
|
+
)
|
|
18
|
+
from .default import (
|
|
19
|
+
get_local_number_of_cores,
|
|
20
|
+
default_license_dir,
|
|
21
|
+
default_license_file,
|
|
22
|
+
default_day_boundary_tz,
|
|
23
|
+
)
|
|
24
|
+
from .acl import (
|
|
25
|
+
if_db_in_acl,
|
|
26
|
+
add_user_to_acl,
|
|
27
|
+
remove_user_from_acl,
|
|
28
|
+
if_user_in_acl,
|
|
29
|
+
tmp_acl,
|
|
30
|
+
)
|
|
31
|
+
from .config import (
|
|
32
|
+
reload_config,
|
|
33
|
+
modify_config_param,
|
|
34
|
+
get_config_param,
|
|
35
|
+
is_param_in_config,
|
|
36
|
+
tmp_config,
|
|
37
|
+
)
|
|
38
|
+
from .locator import (
|
|
39
|
+
get_dbs_locations_from_locator,
|
|
40
|
+
tmp_locator,
|
|
41
|
+
empty_locator,
|
|
42
|
+
)
|
|
43
|
+
from .script import (
|
|
44
|
+
write_config_for_tick_server_run,
|
|
45
|
+
create_file_to_run_config,
|
|
46
|
+
omd_dist_path,
|
|
47
|
+
)
|
|
48
|
+
from .query import (
|
|
49
|
+
abspath_to_query_by_otq_path,
|
|
50
|
+
abspath_to_query_by_name,
|
|
51
|
+
query_to_path_and_name,
|
|
52
|
+
)
|
|
53
|
+
from .types import (
|
|
54
|
+
get_type_that_includes,
|
|
55
|
+
adaptive,
|
|
56
|
+
adaptive_to_default,
|
|
57
|
+
default,
|
|
58
|
+
range,
|
|
59
|
+
)
|
|
60
|
+
from .tz import (
|
|
61
|
+
get_tzfile_by_name,
|
|
62
|
+
get_timezone_from_datetime,
|
|
63
|
+
convert_timezone,
|
|
64
|
+
)
|
|
65
|
+
from .file import (
|
|
66
|
+
FileBuffer,
|
|
67
|
+
file,
|
|
68
|
+
)
|
|
69
|
+
from .render import render_otq
|
|
70
|
+
from . import perf
|
onetick/py/utils/acl.py
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import getpass
|
|
2
|
+
import os
|
|
3
|
+
|
|
4
|
+
from locator_parser.io import PrintWriter, FileReader, FileWriter
|
|
5
|
+
from locator_parser.actions import Get, Add, Delete
|
|
6
|
+
from locator_parser.acl import DB, User, Role, parse_acl
|
|
7
|
+
from locator_parser.common import apply_actions
|
|
8
|
+
|
|
9
|
+
from .temp import TmpFile
|
|
10
|
+
from .types import default
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def if_db_in_acl(acl, db_name):
|
|
14
|
+
get_db = Get()
|
|
15
|
+
get_db.add_where(DB, id=db_name)
|
|
16
|
+
|
|
17
|
+
return apply_actions(parse_acl, FileReader(acl), PrintWriter(), [get_db], flush=True)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def add_user_to_acl(acl, user):
|
|
21
|
+
add_user = Add(User(name=user))
|
|
22
|
+
add_user.add_where(Role, name="Admin")
|
|
23
|
+
|
|
24
|
+
assert apply_actions(parse_acl, FileReader(acl), FileWriter(acl), [add_user], flush=True)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def remove_user_from_acl(acl, user):
|
|
28
|
+
remove_user = Delete()
|
|
29
|
+
remove_user.add_where(Role, name="Admin")
|
|
30
|
+
remove_user.add_where(User, name=user)
|
|
31
|
+
|
|
32
|
+
assert apply_actions(parse_acl, FileReader(acl), FileWriter(acl), [remove_user], flush=True)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def if_user_in_acl(acl, user):
|
|
36
|
+
get_user = Get()
|
|
37
|
+
get_user.add_where(Role, name="Admin")
|
|
38
|
+
get_user.add_where(User, name=user)
|
|
39
|
+
|
|
40
|
+
return apply_actions(parse_acl, FileReader(acl), PrintWriter(), [get_user], flush=True)
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def tmp_acl(clean_up=default):
|
|
44
|
+
data = []
|
|
45
|
+
data.append("<roles>")
|
|
46
|
+
data.append('<role name="Admin">')
|
|
47
|
+
data.append(f'<user name="{getpass.getuser()}" />')
|
|
48
|
+
data.append('<user name="onetick" />')
|
|
49
|
+
|
|
50
|
+
ext_users = os.environ.get("TEST_SESSION_ACL_USERS", None)
|
|
51
|
+
|
|
52
|
+
if ext_users:
|
|
53
|
+
for usr in ext_users.split(","):
|
|
54
|
+
data.append(f'<user name="{usr}" />')
|
|
55
|
+
|
|
56
|
+
data.append("</role>")
|
|
57
|
+
data.append("</roles>")
|
|
58
|
+
|
|
59
|
+
data.append("<databases>")
|
|
60
|
+
data.append("</databases>")
|
|
61
|
+
|
|
62
|
+
data.append("<event_processors>")
|
|
63
|
+
data.append("")
|
|
64
|
+
data.append('<ep ID="RELOAD_CONFIG">')
|
|
65
|
+
data.append('<allow role="Admin" />')
|
|
66
|
+
data.append("</ep>")
|
|
67
|
+
data.append("")
|
|
68
|
+
data.append('<ep ID="WRITE_TEXT">')
|
|
69
|
+
data.append('<allow role="Admin" />')
|
|
70
|
+
data.append("</ep>")
|
|
71
|
+
data.append("")
|
|
72
|
+
data.append('<ep ID="COMMAND_EXECUTE">')
|
|
73
|
+
data.append('<allow role="Admin" />')
|
|
74
|
+
data.append("</ep>")
|
|
75
|
+
data.append("")
|
|
76
|
+
data.append('<ep ID="READ_FROM_RAW">')
|
|
77
|
+
data.append('<allow role="Admin" />')
|
|
78
|
+
data.append("</ep>")
|
|
79
|
+
data.append("")
|
|
80
|
+
data.append('<ep ID="SAVE_SNAPSHOT">')
|
|
81
|
+
data.append('<allow role="Admin" />')
|
|
82
|
+
data.append("</ep>")
|
|
83
|
+
data.append("</event_processors>")
|
|
84
|
+
|
|
85
|
+
if os.getenv('OTP_WEBAPI_TEST_MODE'):
|
|
86
|
+
tmp_file = TmpFile(name="acl.xml", clean_up=clean_up, force=True)
|
|
87
|
+
else:
|
|
88
|
+
tmp_file = TmpFile(suffix=".acl", clean_up=clean_up)
|
|
89
|
+
|
|
90
|
+
with open(tmp_file, "w") as fout:
|
|
91
|
+
fout.write("\n".join(data))
|
|
92
|
+
|
|
93
|
+
return tmp_file
|
|
@@ -0,0 +1,186 @@
|
|
|
1
|
+
import difflib
|
|
2
|
+
import os
|
|
3
|
+
import sysconfig
|
|
4
|
+
import warnings
|
|
5
|
+
from collections import OrderedDict
|
|
6
|
+
|
|
7
|
+
from onetick.py.otq import otq
|
|
8
|
+
|
|
9
|
+
from .temp import TmpFile, TmpDir, ONE_TICK_TMP_DIR
|
|
10
|
+
from ..core import db_constants
|
|
11
|
+
from . import types
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def reload_config(db=None, config_type='LOCATOR'):
|
|
15
|
+
import onetick.py as otp
|
|
16
|
+
|
|
17
|
+
if db is not None:
|
|
18
|
+
warnings.warn("Parameter 'db' is deprecated and has no meaning")
|
|
19
|
+
|
|
20
|
+
return otp.run(
|
|
21
|
+
otq.ReloadConfig(config_type=config_type).tick_type('ANY'),
|
|
22
|
+
symbols='LOCAL::',
|
|
23
|
+
# start and end times don't matter for this query, use some constants
|
|
24
|
+
start=db_constants.DEFAULT_START_DATE,
|
|
25
|
+
end=db_constants.DEFAULT_END_DATE,
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def _remove_quotes(s):
|
|
30
|
+
return s.replace('"', "").replace("'", "")
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _read_config_params(path, _included_paths=None):
|
|
34
|
+
params = OrderedDict()
|
|
35
|
+
|
|
36
|
+
if _included_paths is None:
|
|
37
|
+
_included_paths = set()
|
|
38
|
+
|
|
39
|
+
with open(path, "r") as fin:
|
|
40
|
+
for line in fin:
|
|
41
|
+
line = line.strip()
|
|
42
|
+
|
|
43
|
+
if line.startswith("#"):
|
|
44
|
+
continue
|
|
45
|
+
|
|
46
|
+
if line.startswith("INCLUDE"):
|
|
47
|
+
included_path = os.path.expandvars(_remove_quotes(line.split()[1]))
|
|
48
|
+
if included_path in _included_paths:
|
|
49
|
+
raise RecursionError(f"Path '{included_path}' is included more than once")
|
|
50
|
+
_included_paths.add(included_path)
|
|
51
|
+
included_params = _read_config_params(included_path, _included_paths)
|
|
52
|
+
params.update({
|
|
53
|
+
k: v for k, v in included_params.items()
|
|
54
|
+
if k not in params
|
|
55
|
+
})
|
|
56
|
+
continue
|
|
57
|
+
|
|
58
|
+
values = line.split("=")
|
|
59
|
+
key, value = values[0].strip(), os.path.expandvars("".join(values[1:]).strip())
|
|
60
|
+
|
|
61
|
+
if key and key not in params:
|
|
62
|
+
params[key] = value.strip()
|
|
63
|
+
|
|
64
|
+
return params
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _write_config_params(path, params):
|
|
68
|
+
with open(path, "w") as fout:
|
|
69
|
+
for key, value in params.items():
|
|
70
|
+
fout.write(f"{key}={value}\n")
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def _check_param_in_params(param, params, throw_exception=True):
|
|
74
|
+
if param in params:
|
|
75
|
+
return True
|
|
76
|
+
if not throw_exception:
|
|
77
|
+
return False
|
|
78
|
+
closest = difflib.get_close_matches(param, params.keys())
|
|
79
|
+
msg = f"Parameter '{param}' is not in the config file."
|
|
80
|
+
if closest:
|
|
81
|
+
msg = f"{msg} It might be you supposed '{closest[0]}'?"
|
|
82
|
+
raise AttributeError(msg)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
def modify_config_param(path, param, value, throw_on_missing=True):
|
|
86
|
+
params = _read_config_params(path)
|
|
87
|
+
|
|
88
|
+
_check_param_in_params(param, params, throw_on_missing)
|
|
89
|
+
|
|
90
|
+
params[param] = f'"{value}"'
|
|
91
|
+
|
|
92
|
+
_write_config_params(path, params)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def get_config_param(path, param, default=None):
|
|
96
|
+
params = _read_config_params(path)
|
|
97
|
+
|
|
98
|
+
res = _check_param_in_params(param, params, throw_exception=(default is None))
|
|
99
|
+
|
|
100
|
+
if res:
|
|
101
|
+
return _remove_quotes(params[param])
|
|
102
|
+
return default
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
def is_param_in_config(path, param):
|
|
106
|
+
params = _read_config_params(path)
|
|
107
|
+
|
|
108
|
+
return _check_param_in_params(param, params, throw_exception=False)
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
def tmp_config(
|
|
112
|
+
locator=None,
|
|
113
|
+
acl=None,
|
|
114
|
+
otq_path=None,
|
|
115
|
+
csv_path=None,
|
|
116
|
+
clean_up=types.default,
|
|
117
|
+
license_path=None,
|
|
118
|
+
license_dir=None,
|
|
119
|
+
license_servers=None,
|
|
120
|
+
):
|
|
121
|
+
data = []
|
|
122
|
+
|
|
123
|
+
if otq_path is None:
|
|
124
|
+
otq_path = []
|
|
125
|
+
|
|
126
|
+
if ONE_TICK_TMP_DIR():
|
|
127
|
+
otq_path.append(ONE_TICK_TMP_DIR())
|
|
128
|
+
|
|
129
|
+
if csv_path is None:
|
|
130
|
+
csv_path = []
|
|
131
|
+
|
|
132
|
+
otq_path = list(map(os.path.normpath, otq_path))
|
|
133
|
+
csv_path = list(map(os.path.normpath, csv_path))
|
|
134
|
+
|
|
135
|
+
data.append("ONE_TICK_CONFIG.ALLOW_ENV_VARS=Yes")
|
|
136
|
+
data.append("")
|
|
137
|
+
config_vars = sysconfig.get_config_vars()
|
|
138
|
+
data.append(f"PYTHON_VERSION='{config_vars['py_version_short']}{config_vars['abiflags']}'")
|
|
139
|
+
|
|
140
|
+
if locator:
|
|
141
|
+
data.append(f'DB_LOCATOR.DEFAULT="{_remove_quotes(str(locator))}"')
|
|
142
|
+
|
|
143
|
+
if acl:
|
|
144
|
+
data.append(f'ACCESS_CONTROL_FILE="{_remove_quotes(str(acl))}"')
|
|
145
|
+
|
|
146
|
+
if license_path:
|
|
147
|
+
data.append(f'ONE_TICK_LICENSE_FILE="{_remove_quotes(str(license_path))}"')
|
|
148
|
+
|
|
149
|
+
if license_dir:
|
|
150
|
+
data.append(f'LICENSE_REPOSITORY_DIR="{_remove_quotes(str(license_dir))}"')
|
|
151
|
+
|
|
152
|
+
if license_servers:
|
|
153
|
+
data.append(f'LICENSE_TICK_SERVERS="{_remove_quotes(str(license_servers))}"')
|
|
154
|
+
|
|
155
|
+
if otq_path:
|
|
156
|
+
data.append(f'OTQ_FILE_PATH="{",".join(otq_path)}"')
|
|
157
|
+
|
|
158
|
+
if csv_path:
|
|
159
|
+
data.append(f'CSV_FILE_PATH="{",".join(csv_path)}"')
|
|
160
|
+
|
|
161
|
+
if os.getenv('OTP_WEBAPI_TEST_MODE'):
|
|
162
|
+
tmp_dir = TmpDir()
|
|
163
|
+
data.append(f'TICK_SERVER_CSV_CACHE_DIR="{tmp_dir}"')
|
|
164
|
+
data.append(f'TICK_SERVER_DATA_CACHE_DIR="{tmp_dir}"')
|
|
165
|
+
data.append(f'TICK_SERVER_OTQ_CACHE_DIR="{tmp_dir}"')
|
|
166
|
+
|
|
167
|
+
data.append("")
|
|
168
|
+
data.append("ALLOW_REMOTE_CONTROL=Yes")
|
|
169
|
+
data.append("ALLOW_NO_CERTIFICATE=true")
|
|
170
|
+
# to be able to run otp.ODBC
|
|
171
|
+
data.append("LOAD_ODBC_UDF=true")
|
|
172
|
+
|
|
173
|
+
# # let's not strip quotes around params by default, this is the old behaviour
|
|
174
|
+
# new default behaviour breaks backward-compatibility (BEXRTS-1340, BEXRTS-1342)
|
|
175
|
+
# new behaviour can be achieved by setting STRIP_QUOTES_WHEN_ASSIGNING_SYMBOL_AND_OTQ_PARAMS param in JWQ EP
|
|
176
|
+
data.append("COMPATIBILITY.JOIN_WITH_QUERY.STRIP_QUOTES_AROUND_SYMBOL_AND_OTQ_PARAMS=FALSE")
|
|
177
|
+
|
|
178
|
+
if os.getenv('OTP_WEBAPI_TEST_MODE'):
|
|
179
|
+
tmp_file = TmpFile(name="onetick.cfg", clean_up=clean_up, force=True)
|
|
180
|
+
else:
|
|
181
|
+
tmp_file = TmpFile(suffix=".cfg", clean_up=clean_up)
|
|
182
|
+
|
|
183
|
+
with open(tmp_file, "w") as fout:
|
|
184
|
+
fout.write("\n".join(data))
|
|
185
|
+
|
|
186
|
+
return tmp_file
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sys
|
|
3
|
+
import multiprocessing
|
|
4
|
+
import warnings
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_local_number_of_cores():
|
|
8
|
+
try:
|
|
9
|
+
# number of cores allowed for user
|
|
10
|
+
return len(os.sched_getaffinity(0))
|
|
11
|
+
except Exception:
|
|
12
|
+
# number of cores
|
|
13
|
+
return multiprocessing.cpu_count()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def default_license_dir():
|
|
17
|
+
if sys.platform == "linux":
|
|
18
|
+
return os.path.join("/", "license")
|
|
19
|
+
elif sys.platform == "win32":
|
|
20
|
+
return os.path.join("C:\\", "OMD", "client_data", "config", "license_repository")
|
|
21
|
+
elif sys.platform == "darwin":
|
|
22
|
+
return os.path.join("/", "Library", "Application Support", "OneTick")
|
|
23
|
+
return None
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def default_license_file():
|
|
27
|
+
if sys.platform == "linux":
|
|
28
|
+
return os.path.join("/", "license", "license.dat")
|
|
29
|
+
elif sys.platform == "win32":
|
|
30
|
+
return os.path.join("C:\\", "OMD", "client_data", "config", "license.dat")
|
|
31
|
+
elif sys.platform == "darwin":
|
|
32
|
+
return os.path.join("/", "Library", "Application Support", "OneTick")
|
|
33
|
+
return None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def default_day_boundary_tz(db_name):
|
|
37
|
+
import onetick.py as otp
|
|
38
|
+
if otp.config.tz:
|
|
39
|
+
return otp.config.tz
|
|
40
|
+
warnings.warn(
|
|
41
|
+
"Database property 'day_boundary_tz' can't be set to default timezone "
|
|
42
|
+
"because default timezone is local and is not known at this moment. "
|
|
43
|
+
"Default value for this property will be 'GMT'. "
|
|
44
|
+
f"It may produce unexpected results "
|
|
45
|
+
f"when reading from or writing to database '{db_name}'. "
|
|
46
|
+
"Set otp.config.tz property to some known value to avoid this situation.",
|
|
47
|
+
stacklevel=2,
|
|
48
|
+
)
|
|
49
|
+
return None
|
onetick/py/utils/file.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import zlib
|
|
3
|
+
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
from typing import Union
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class FileBuffer:
|
|
9
|
+
'''
|
|
10
|
+
Class holds the file content with goal to delivery
|
|
11
|
+
it to the execution side in case of remote executions.
|
|
12
|
+
|
|
13
|
+
The basic implementation reads file content to a property
|
|
14
|
+
that allows to transfer file content as pickled object
|
|
15
|
+
to the server side since the pickling stores all class property
|
|
16
|
+
values.
|
|
17
|
+
'''
|
|
18
|
+
|
|
19
|
+
def __init__(self, path: Union[str, os.PathLike]):
|
|
20
|
+
content = Path(path).read_text()
|
|
21
|
+
self._content = zlib.compress(content.encode('utf-8'), level=9)
|
|
22
|
+
|
|
23
|
+
def get(self):
|
|
24
|
+
''' Returns file content '''
|
|
25
|
+
return zlib.decompress(self._content).decode('utf-8')
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def file(path: Union[str, os.PathLike]) -> FileBuffer:
|
|
29
|
+
'''
|
|
30
|
+
Helps to build a file buffer that could be used to
|
|
31
|
+
delivery on the remote site to be processed there.
|
|
32
|
+
For example it could be passed as input to the :class:`CSV <onetick.py.CSV>`
|
|
33
|
+
|
|
34
|
+
See Also
|
|
35
|
+
--------
|
|
36
|
+
:class:`CSV <onetick.py.CSV>`
|
|
37
|
+
'''
|
|
38
|
+
return FileBuffer(path)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
from onetick.py.otq import otq, pyomd
|
|
4
|
+
from datetime import datetime
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_symbol_list_from_df(df, symbol_name_column='SYMBOL_NAME'):
|
|
8
|
+
"""
|
|
9
|
+
Creates a onetick.query.Symbol object that may be passed as a symbol list from the dataframe
|
|
10
|
+
with query results. SYMBOL_NAME column is interpreted as symbol names, while other columns are
|
|
11
|
+
interpreted as symbol params.
|
|
12
|
+
"""
|
|
13
|
+
if symbol_name_column not in df.columns:
|
|
14
|
+
raise ValueError(f'Dataframe used as symbol list does not contain a {symbol_name_column} column')
|
|
15
|
+
|
|
16
|
+
df = df.drop(columns=['Time'])
|
|
17
|
+
|
|
18
|
+
def symbol_from_dict(params):
|
|
19
|
+
name = params[symbol_name_column]
|
|
20
|
+
del params[symbol_name_column]
|
|
21
|
+
return otq.Symbol(name=name, params=params)
|
|
22
|
+
|
|
23
|
+
symbols = [symbol_from_dict(row) for row in df.to_dict(orient='records')]
|
|
24
|
+
return symbols
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class JSONEncoder(json.JSONEncoder):
|
|
28
|
+
"""
|
|
29
|
+
onetick.py json encoder that also supports some of the onetick.py objects like otp.adaptive.
|
|
30
|
+
"""
|
|
31
|
+
def default(self, o):
|
|
32
|
+
# let's use python str representation by default, all objects in python should have it
|
|
33
|
+
# maybe we will add better representations for some types later
|
|
34
|
+
return str(o)
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def json_dumps(obj, **kwargs) -> str:
|
|
38
|
+
"""
|
|
39
|
+
Wrapper around json.dumps that also supports some of the onetick.py objects like otp.adaptive.
|
|
40
|
+
``kwargs`` arguments are propagated to json.dumps function.
|
|
41
|
+
By default ``cls`` parameter is set to otp.utils.JSONEncoder.
|
|
42
|
+
"""
|
|
43
|
+
kwargs.setdefault('cls', JSONEncoder)
|
|
44
|
+
return json.dumps(obj, **kwargs)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def query_properties_to_dict(query_properties: pyomd.QueryProperties) -> dict: # type: ignore[valid-type]
|
|
48
|
+
"""
|
|
49
|
+
Convert :py:class:`pyomd.QueryProperties` to dictionary.
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
str_qp = query_properties.convert_to_name_value_pairs_string() # type: ignore[attr-defined]
|
|
53
|
+
if not isinstance(str_qp, str):
|
|
54
|
+
str_qp = str_qp.c_str()
|
|
55
|
+
pairs = str_qp.split(',') if str_qp else []
|
|
56
|
+
return dict(pair.split('=', maxsplit=1) for pair in pairs)
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def query_properties_from_dict(query_properties_dict: dict) -> pyomd.QueryProperties: # type: ignore[valid-type]
|
|
60
|
+
"""
|
|
61
|
+
Convert dictionary to :py:class:`pyomd.QueryProperties`.
|
|
62
|
+
"""
|
|
63
|
+
query_properties = pyomd.QueryProperties()
|
|
64
|
+
for k, v in query_properties_dict.items():
|
|
65
|
+
query_properties.set_property_value(k, v)
|
|
66
|
+
return query_properties
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def symbol_date_to_str(symbol_date) -> str:
|
|
70
|
+
if isinstance(symbol_date, int):
|
|
71
|
+
symbol_date = str(symbol_date)
|
|
72
|
+
if isinstance(symbol_date, str):
|
|
73
|
+
symbol_date = datetime.strptime(symbol_date, '%Y%m%d')
|
|
74
|
+
if hasattr(symbol_date, 'strftime'):
|
|
75
|
+
symbol_date = symbol_date.strftime('%Y%m%d')
|
|
76
|
+
return symbol_date
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from locator_parser.io import PrintWriter, FileReader
|
|
3
|
+
from locator_parser.actions import GetAll
|
|
4
|
+
from locator_parser.locator import Location, parse_locator
|
|
5
|
+
from locator_parser.common import apply_actions
|
|
6
|
+
|
|
7
|
+
from .temp import TmpFile
|
|
8
|
+
from .types import default
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def get_dbs_locations_from_locator(locator):
|
|
12
|
+
action = GetAll()
|
|
13
|
+
action.add_where(Location)
|
|
14
|
+
|
|
15
|
+
apply_actions(parse_locator, FileReader(locator), PrintWriter(), [action])
|
|
16
|
+
|
|
17
|
+
return map(lambda x: x.location, action.result)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def tmp_locator(clean_up=default, empty=False):
|
|
21
|
+
import onetick.py as otp
|
|
22
|
+
|
|
23
|
+
STUBS = {'COMMON'}
|
|
24
|
+
default_db = otp.config.get('default_db')
|
|
25
|
+
if default_db:
|
|
26
|
+
STUBS.add(default_db)
|
|
27
|
+
|
|
28
|
+
data = []
|
|
29
|
+
data.append('<VERSION_INFO VERSION="2"/>')
|
|
30
|
+
data.append("<DATABASES>")
|
|
31
|
+
data.append("")
|
|
32
|
+
|
|
33
|
+
if not empty:
|
|
34
|
+
for stub_name in STUBS:
|
|
35
|
+
data.append(
|
|
36
|
+
f'<db ID="{stub_name}" symbology="{otp.config.default_symbology}" time_series_is_composite="YES">'
|
|
37
|
+
)
|
|
38
|
+
data.append("<locations>")
|
|
39
|
+
day_boundary_tz = otp.config.get('tz')
|
|
40
|
+
day_boundary_tz = f'day_boundary_tz="{day_boundary_tz}"' if day_boundary_tz else ''
|
|
41
|
+
data.append(
|
|
42
|
+
'<location access_method="file" location="/opt/one_market_data/one_tick/examples/data/demo_level1" '
|
|
43
|
+
'start_time="20001201000000" end_time="20301031050000" '
|
|
44
|
+
f'{day_boundary_tz}/>'
|
|
45
|
+
)
|
|
46
|
+
data.append("</locations>")
|
|
47
|
+
data.append('<feed type="heartbeat_generator">')
|
|
48
|
+
data.append('<options format="native" />')
|
|
49
|
+
data.append('</feed>')
|
|
50
|
+
data.append("</db>")
|
|
51
|
+
data.append("")
|
|
52
|
+
data.append("")
|
|
53
|
+
|
|
54
|
+
data.append("</DATABASES>")
|
|
55
|
+
|
|
56
|
+
data.append("<TICK_SERVERS>")
|
|
57
|
+
data.append("</TICK_SERVERS>")
|
|
58
|
+
data.append("<CEP_TICK_SERVERS>")
|
|
59
|
+
data.append("</CEP_TICK_SERVERS>")
|
|
60
|
+
data.append("<INCLUDES>")
|
|
61
|
+
data.append("</INCLUDES>")
|
|
62
|
+
|
|
63
|
+
tmp_file = new_tmp_locator(clean_up)
|
|
64
|
+
|
|
65
|
+
with open(tmp_file, "w") as fout:
|
|
66
|
+
fout.write("\n".join(data))
|
|
67
|
+
|
|
68
|
+
return tmp_file
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def new_tmp_locator(clean_up):
|
|
72
|
+
if os.getenv('OTP_WEBAPI_TEST_MODE'):
|
|
73
|
+
tmp_file = TmpFile(name="locator.default", clean_up=clean_up, force=True)
|
|
74
|
+
else:
|
|
75
|
+
tmp_file = TmpFile(suffix=".locator", clean_up=clean_up)
|
|
76
|
+
return tmp_file
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def empty_locator(clean_up=default):
|
|
80
|
+
data = []
|
|
81
|
+
data.append('<VERSION_INFO VERSION="2"/>')
|
|
82
|
+
data.append("<DATABASES>")
|
|
83
|
+
data.append("</DATABASES>")
|
|
84
|
+
data.append("<TICK_SERVERS>")
|
|
85
|
+
data.append("</TICK_SERVERS>")
|
|
86
|
+
data.append("<CEP_TICK_SERVERS>")
|
|
87
|
+
data.append("</CEP_TICK_SERVERS>")
|
|
88
|
+
data.append("<INCLUDES>")
|
|
89
|
+
data.append("</INCLUDES>")
|
|
90
|
+
|
|
91
|
+
tmp_file = new_tmp_locator(clean_up)
|
|
92
|
+
with open(tmp_file, "w") as fout:
|
|
93
|
+
fout.write("\n".join(data))
|
|
94
|
+
return tmp_file
|