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
onetick/py/types.py
ADDED
|
@@ -0,0 +1,2131 @@
|
|
|
1
|
+
import ctypes
|
|
2
|
+
import functools
|
|
3
|
+
import inspect
|
|
4
|
+
import warnings
|
|
5
|
+
import decimal as _decimal
|
|
6
|
+
from typing import Optional, Type, Union
|
|
7
|
+
from datetime import date as _date
|
|
8
|
+
from datetime import datetime as _datetime
|
|
9
|
+
from datetime import timedelta as _timedelta
|
|
10
|
+
|
|
11
|
+
import pandas as pd
|
|
12
|
+
import numpy as np
|
|
13
|
+
from pandas.tseries import offsets
|
|
14
|
+
from packaging.version import parse as parse_version
|
|
15
|
+
|
|
16
|
+
import onetick.py as otp
|
|
17
|
+
from onetick.py.otq import otq, pyomd
|
|
18
|
+
from onetick.py.compatibility import has_timezone_parameter
|
|
19
|
+
from onetick.py.core._internal._op_utils.every_operand import every_operand
|
|
20
|
+
from onetick.py.utils import get_tzfile_by_name, get_timezone_from_datetime
|
|
21
|
+
from onetick.py.docs.utils import is_windows
|
|
22
|
+
|
|
23
|
+
# --------------------------------------------------------------- #
|
|
24
|
+
# TYPES IMPLEMENTATION
|
|
25
|
+
# --------------------------------------------------------------- #
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class OTPBaseTimeStamp(type):
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _nsectime(OTPBaseTimeStamp):
|
|
33
|
+
def __str__(cls):
|
|
34
|
+
return "nsectime"
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class nsectime(int, metaclass=_nsectime):
|
|
38
|
+
"""
|
|
39
|
+
OneTick data type representing datetime with nanoseconds precision.
|
|
40
|
+
Can be used to specify otp.Source column type when converting columns or creating new ones.
|
|
41
|
+
Note that this constructor creates datetime value in GMT timezone
|
|
42
|
+
and doesn't take into account the timezone with which the query is executed.
|
|
43
|
+
|
|
44
|
+
Examples
|
|
45
|
+
--------
|
|
46
|
+
>>> t = otp.Tick(A=0)
|
|
47
|
+
>>> t['A'] = t['A'].apply(otp.nsectime)
|
|
48
|
+
>>> t['B'] = otp.nsectime(24 * 60 * 60 * 1000 * 1000 * 1000 + 2)
|
|
49
|
+
>>> t.schema
|
|
50
|
+
{'A': <class 'onetick.py.types.nsectime'>, 'B': <class 'onetick.py.types.nsectime'>}
|
|
51
|
+
>>> otp.run(t)
|
|
52
|
+
Time A B
|
|
53
|
+
0 2003-12-01 1969-12-31 19:00:00 1970-01-01 19:00:00.000000002
|
|
54
|
+
"""
|
|
55
|
+
def __str__(self):
|
|
56
|
+
return super().__repr__()
|
|
57
|
+
|
|
58
|
+
def __repr__(self):
|
|
59
|
+
return f'{self.__class__.__name__}({self})'
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class _msectime(OTPBaseTimeStamp):
|
|
63
|
+
def __str__(cls):
|
|
64
|
+
return "msectime"
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class msectime(int, metaclass=_msectime):
|
|
68
|
+
"""
|
|
69
|
+
OneTick data type representing datetime with milliseconds precision.
|
|
70
|
+
Can be used to specify otp.Source column type when converting columns or creating new ones.
|
|
71
|
+
Note that this constructor creates datetime value in GMT timezone
|
|
72
|
+
and doesn't take into account the timezone with which the query is executed.
|
|
73
|
+
|
|
74
|
+
Examples
|
|
75
|
+
--------
|
|
76
|
+
>>> t = otp.Tick(A=1)
|
|
77
|
+
>>> t = t.table(A=otp.msectime)
|
|
78
|
+
>>> t['B'] = otp.msectime(2)
|
|
79
|
+
>>> t.schema
|
|
80
|
+
{'A': <class 'onetick.py.types.msectime'>, 'B': <class 'onetick.py.types.msectime'>}
|
|
81
|
+
>>> otp.run(t)
|
|
82
|
+
Time A B
|
|
83
|
+
0 2003-12-01 1969-12-31 19:00:00.001 1969-12-31 19:00:00.002
|
|
84
|
+
"""
|
|
85
|
+
def __str__(self):
|
|
86
|
+
return super().__repr__()
|
|
87
|
+
|
|
88
|
+
def __repr__(self):
|
|
89
|
+
return f'{self.__class__.__name__}({self})'
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
class OTPBaseTimeOffset:
|
|
93
|
+
datepart = "'invalid'" # that is just base class for other dateparts
|
|
94
|
+
n = 0
|
|
95
|
+
delta = pd.Timedelta(seconds=0)
|
|
96
|
+
|
|
97
|
+
def get_offset(self):
|
|
98
|
+
return self.n, self.datepart[1:-1]
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class ExpressionDefinedTimeOffset(OTPBaseTimeOffset):
|
|
102
|
+
def __init__(self, datepart, n):
|
|
103
|
+
self.datepart = datepart
|
|
104
|
+
self.n = n
|
|
105
|
+
|
|
106
|
+
from onetick.py.core.column_operations.base import _Operation
|
|
107
|
+
|
|
108
|
+
def proxy_wrap(attr):
|
|
109
|
+
def f(self, *args, **kwargs):
|
|
110
|
+
return getattr(self.n, attr)(*args, **kwargs)
|
|
111
|
+
return f
|
|
112
|
+
|
|
113
|
+
for attr, value in inspect.getmembers(_Operation, callable):
|
|
114
|
+
if attr in {'__class__', '__init__', '__new__', '__init_subclass__', '__dir__',
|
|
115
|
+
'__getattribute__', '__getattr__', '__delattr__', '__setattr__',
|
|
116
|
+
'__subclasshook__', '__sizeof__', '__str__', '__repr__'}:
|
|
117
|
+
continue
|
|
118
|
+
setattr(ExpressionDefinedTimeOffset, attr, proxy_wrap(attr))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
# ---------------------------- #
|
|
122
|
+
# Implement datepart units
|
|
123
|
+
|
|
124
|
+
def _construct_dpf(dp_class, str_repr=None, **dp_class_params):
|
|
125
|
+
""" construct a datepart factory """
|
|
126
|
+
|
|
127
|
+
if str_repr is None:
|
|
128
|
+
str_repr = dp_class.__name__.lower()
|
|
129
|
+
|
|
130
|
+
class _DatePartCls(dp_class, OTPBaseTimeOffset):
|
|
131
|
+
datepart = f"'{str_repr}'"
|
|
132
|
+
|
|
133
|
+
def _factory(n):
|
|
134
|
+
from onetick.py.core.column_operations._methods.methods import is_arithmetical
|
|
135
|
+
from onetick.py.core.column import _Column
|
|
136
|
+
|
|
137
|
+
if isinstance(n, int):
|
|
138
|
+
if dp_class_params:
|
|
139
|
+
return _DatePartCls(**dp_class_params) * n
|
|
140
|
+
return _DatePartCls(n)
|
|
141
|
+
if is_arithmetical(n):
|
|
142
|
+
n = _process_datediff(n)
|
|
143
|
+
return ExpressionDefinedTimeOffset(_DatePartCls.datepart, n)
|
|
144
|
+
if isinstance(n, _Column):
|
|
145
|
+
return ExpressionDefinedTimeOffset(_DatePartCls.datepart, n)
|
|
146
|
+
raise ValueError("Unknown type was passed as arg, integer constant or column or expression is expected here")
|
|
147
|
+
|
|
148
|
+
def _process_datediff(n):
|
|
149
|
+
|
|
150
|
+
n_time_operand = _get_n_time_operand(n)
|
|
151
|
+
if n_time_operand:
|
|
152
|
+
# check if otp.Hour(date1 - date2) is called, return a number of hours between two days in such ways
|
|
153
|
+
from onetick.py.core.column_operations._methods.methods import sub, _wrap_object
|
|
154
|
+
from onetick.py.core.column_operations.base import _Operation
|
|
155
|
+
from onetick.py.core.column import _LagOperator
|
|
156
|
+
|
|
157
|
+
available_types = (_Operation, _LagOperator)
|
|
158
|
+
if (getattr(n, "_op_func", sub) and len(n._op_params) == 2
|
|
159
|
+
and isinstance(n._op_params[0], available_types) and isinstance(n._op_params[1], available_types)):
|
|
160
|
+
def _datediff(*args):
|
|
161
|
+
args = ', '.join(map(_wrap_object, args))
|
|
162
|
+
return f'DATEDIFF({_DatePartCls.datepart}, {args}, _TIMEZONE)', int
|
|
163
|
+
return _Operation(_datediff, [n._op_params[1], n._op_params[0]])
|
|
164
|
+
else:
|
|
165
|
+
raise ValueError(
|
|
166
|
+
"Date arithmetic operations (except date2-date1, which calculate an amount of "
|
|
167
|
+
"periods between two dates) are not accepted in TimeOffset constructor"
|
|
168
|
+
)
|
|
169
|
+
return n
|
|
170
|
+
|
|
171
|
+
def _get_n_time_operand(n):
|
|
172
|
+
from onetick.py.core.column_operations._methods.op_types import are_time
|
|
173
|
+
|
|
174
|
+
result = 0
|
|
175
|
+
for op in every_operand(n):
|
|
176
|
+
if are_time(get_object_type(op)):
|
|
177
|
+
result += 1
|
|
178
|
+
return result
|
|
179
|
+
|
|
180
|
+
return _factory
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
def _construct_float_dpf(dp_class, dp_float_class, power, str_repr=None, float_str_repr=None, **dp_class_params):
|
|
184
|
+
def _factory(n):
|
|
185
|
+
if isinstance(n, float):
|
|
186
|
+
return _construct_dpf(dp_float_class, float_str_repr, **dp_class_params)(int(n * (10 ** power)))
|
|
187
|
+
else:
|
|
188
|
+
return _construct_dpf(dp_class, str_repr, **dp_class_params)(n)
|
|
189
|
+
|
|
190
|
+
return _factory
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
_add_examples_to_docs = functools.partial(
|
|
194
|
+
"""
|
|
195
|
+
Object representing {0}'s datetime offset.
|
|
196
|
+
|
|
197
|
+
Can be added to or subtracted from:
|
|
198
|
+
|
|
199
|
+
* :py:class:`otp.datetime <onetick.py.datetime>` objects
|
|
200
|
+
* :py:class:`Source <onetick.py.Source>` columns of datetime type
|
|
201
|
+
|
|
202
|
+
Parameters
|
|
203
|
+
----------
|
|
204
|
+
n: int, :class:`~onetick.py.Column`, :class:`~onetick.py.Operation`{additional_types}
|
|
205
|
+
Offset integer value or column of :class:`~onetick.py.Source`.
|
|
206
|
+
The only :class:`~onetick.py.Operation` supported is
|
|
207
|
+
subtracting one datetime column from another. See example below.{additional_notes}
|
|
208
|
+
|
|
209
|
+
Examples
|
|
210
|
+
--------
|
|
211
|
+
{1}
|
|
212
|
+
""".format, additional_types="", additional_notes="",
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
_float_dpf_types = ", float"
|
|
216
|
+
_float_dpf_notes = """
|
|
217
|
+
Offset could be ``float`` to pass a fractional time unit value."""
|
|
218
|
+
|
|
219
|
+
|
|
220
|
+
Year = _construct_dpf(offsets.DateOffset, "year", years=1)
|
|
221
|
+
Year.__doc__ = _add_examples_to_docs('year', """
|
|
222
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
223
|
+
|
|
224
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Year(1)
|
|
225
|
+
2013-12-12 12:00:00
|
|
226
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Year(1)
|
|
227
|
+
2011-12-12 12:00:00
|
|
228
|
+
|
|
229
|
+
Use offset in columns:
|
|
230
|
+
|
|
231
|
+
>>> t = otp.Tick(A=1)
|
|
232
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
233
|
+
>>> t['T'] += otp.Year(t['A'])
|
|
234
|
+
>>> otp.run(t)
|
|
235
|
+
Time T A
|
|
236
|
+
0 2003-12-01 2013-12-12 12:00:00 1
|
|
237
|
+
|
|
238
|
+
Use it to calculate difference between two dates:
|
|
239
|
+
|
|
240
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2023, 1, 1))
|
|
241
|
+
>>> t['DIFF'] = otp.Year(t['B'] - t['A'])
|
|
242
|
+
>>> otp.run(t)
|
|
243
|
+
Time A B DIFF
|
|
244
|
+
0 2003-12-01 2022-01-01 2023-01-01 1
|
|
245
|
+
""")
|
|
246
|
+
|
|
247
|
+
Quarter = _construct_dpf(offsets.DateOffset, "quarter", months=3)
|
|
248
|
+
Quarter.__doc__ = _add_examples_to_docs('quarter', """
|
|
249
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
250
|
+
|
|
251
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Quarter(1)
|
|
252
|
+
2013-03-12 12:00:00
|
|
253
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Quarter(1)
|
|
254
|
+
2012-09-12 12:00:00
|
|
255
|
+
|
|
256
|
+
Use offset in columns:
|
|
257
|
+
|
|
258
|
+
>>> t = otp.Tick(A=1)
|
|
259
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12, tz='GMT')
|
|
260
|
+
>>> t['T'] += otp.Quarter(t['A'])
|
|
261
|
+
>>> otp.run(t, start=otp.datetime(2003, 12, 2), end=otp.datetime(2003, 12, 3), timezone='GMT')
|
|
262
|
+
Time T A
|
|
263
|
+
0 2003-12-02 2013-03-12 12:00:00 1
|
|
264
|
+
|
|
265
|
+
Use it to calculate difference between two dates:
|
|
266
|
+
|
|
267
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2023, 1, 1))
|
|
268
|
+
>>> t['DIFF'] = otp.Quarter(t['B'] - t['A'])
|
|
269
|
+
>>> otp.run(t)
|
|
270
|
+
Time A B DIFF
|
|
271
|
+
0 2003-12-01 2022-01-01 2023-01-01 4
|
|
272
|
+
""")
|
|
273
|
+
|
|
274
|
+
Month = _construct_dpf(offsets.DateOffset, "month", months=1)
|
|
275
|
+
Month.__doc__ = _add_examples_to_docs('month', """
|
|
276
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
277
|
+
|
|
278
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Month(1)
|
|
279
|
+
2013-01-12 12:00:00
|
|
280
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Month(1)
|
|
281
|
+
2012-11-12 12:00:00
|
|
282
|
+
|
|
283
|
+
Use offset in columns:
|
|
284
|
+
|
|
285
|
+
>>> t = otp.Tick(A=1)
|
|
286
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
287
|
+
>>> t['T'] += otp.Month(t['A'])
|
|
288
|
+
>>> otp.run(t)
|
|
289
|
+
Time T A
|
|
290
|
+
0 2003-12-01 2013-01-12 12:00:00 1
|
|
291
|
+
|
|
292
|
+
Use it to calculate difference between two dates:
|
|
293
|
+
|
|
294
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2023, 1, 1))
|
|
295
|
+
>>> t['DIFF'] = otp.Month(t['B'] - t['A'])
|
|
296
|
+
>>> otp.run(t)
|
|
297
|
+
Time A B DIFF
|
|
298
|
+
0 2003-12-01 2022-01-01 2023-01-01 12
|
|
299
|
+
""")
|
|
300
|
+
|
|
301
|
+
Week = _construct_dpf(offsets.Week)
|
|
302
|
+
Week.__doc__ = _add_examples_to_docs('week', """
|
|
303
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
304
|
+
|
|
305
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Week(1)
|
|
306
|
+
2012-12-19 12:00:00
|
|
307
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Week(1)
|
|
308
|
+
2012-12-05 12:00:00
|
|
309
|
+
|
|
310
|
+
Use offset in columns:
|
|
311
|
+
|
|
312
|
+
>>> t = otp.Tick(A=1)
|
|
313
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
314
|
+
>>> t['T'] += otp.Week(t['A'])
|
|
315
|
+
>>> otp.run(t)
|
|
316
|
+
Time T A
|
|
317
|
+
0 2003-12-01 2012-12-19 12:00:00 1
|
|
318
|
+
|
|
319
|
+
Use it to calculate difference between two dates:
|
|
320
|
+
|
|
321
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2023, 1, 1))
|
|
322
|
+
>>> t['DIFF'] = otp.Week(t['B'] - t['A'])
|
|
323
|
+
>>> otp.run(t)
|
|
324
|
+
Time A B DIFF
|
|
325
|
+
0 2003-12-01 2022-01-01 2023-01-01 53
|
|
326
|
+
""")
|
|
327
|
+
|
|
328
|
+
Day = _construct_dpf(offsets.Day)
|
|
329
|
+
Day.__doc__ = _add_examples_to_docs('day', """
|
|
330
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
331
|
+
|
|
332
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Day(1)
|
|
333
|
+
2012-12-13 12:00:00
|
|
334
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Day(1)
|
|
335
|
+
2012-12-11 12:00:00
|
|
336
|
+
|
|
337
|
+
Use offset in columns:
|
|
338
|
+
|
|
339
|
+
>>> t = otp.Tick(A=1)
|
|
340
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
341
|
+
>>> t['T'] += otp.Day(t['A'])
|
|
342
|
+
>>> otp.run(t)
|
|
343
|
+
Time T A
|
|
344
|
+
0 2003-12-01 2012-12-13 12:00:00 1
|
|
345
|
+
|
|
346
|
+
Use it to calculate difference between two dates:
|
|
347
|
+
|
|
348
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2023, 1, 1))
|
|
349
|
+
>>> t['DIFF'] = otp.Day(t['B'] - t['A'])
|
|
350
|
+
>>> otp.run(t)
|
|
351
|
+
Time A B DIFF
|
|
352
|
+
0 2003-12-01 2022-01-01 2023-01-01 365
|
|
353
|
+
""")
|
|
354
|
+
|
|
355
|
+
Hour = _construct_dpf(offsets.Hour)
|
|
356
|
+
Hour.__doc__ = _add_examples_to_docs('hour', """
|
|
357
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
358
|
+
|
|
359
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Hour(1)
|
|
360
|
+
2012-12-12 13:00:00
|
|
361
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Hour(1)
|
|
362
|
+
2012-12-12 11:00:00
|
|
363
|
+
|
|
364
|
+
Use offset in columns:
|
|
365
|
+
|
|
366
|
+
>>> t = otp.Tick(A=1)
|
|
367
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
368
|
+
>>> t['T'] += otp.Hour(t['A'])
|
|
369
|
+
>>> otp.run(t)
|
|
370
|
+
Time T A
|
|
371
|
+
0 2003-12-01 2012-12-12 13:00:00 1
|
|
372
|
+
|
|
373
|
+
Use it to calculate difference between two dates:
|
|
374
|
+
|
|
375
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2022, 1, 2))
|
|
376
|
+
>>> t['DIFF'] = otp.Hour(t['B'] - t['A'])
|
|
377
|
+
>>> otp.run(t)
|
|
378
|
+
Time A B DIFF
|
|
379
|
+
0 2003-12-01 2022-01-01 2022-01-02 24
|
|
380
|
+
""")
|
|
381
|
+
|
|
382
|
+
Minute = _construct_dpf(offsets.Minute)
|
|
383
|
+
Minute.__doc__ = _add_examples_to_docs('minute', """
|
|
384
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
385
|
+
|
|
386
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Minute(1)
|
|
387
|
+
2012-12-12 12:01:00
|
|
388
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Minute(1)
|
|
389
|
+
2012-12-12 11:59:00
|
|
390
|
+
|
|
391
|
+
Use offset in columns:
|
|
392
|
+
|
|
393
|
+
>>> t = otp.Tick(A=1)
|
|
394
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
395
|
+
>>> t['T'] += otp.Minute(t['A'])
|
|
396
|
+
>>> otp.run(t)
|
|
397
|
+
Time T A
|
|
398
|
+
0 2003-12-01 2012-12-12 12:01:00 1
|
|
399
|
+
|
|
400
|
+
Use it to calculate difference between two dates:
|
|
401
|
+
|
|
402
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2022, 1, 1, 1))
|
|
403
|
+
>>> t['DIFF'] = otp.Minute(t['B'] - t['A'])
|
|
404
|
+
>>> otp.run(t)
|
|
405
|
+
Time A B DIFF
|
|
406
|
+
0 2003-12-01 2022-01-01 2022-01-01 01:00:00 60
|
|
407
|
+
""")
|
|
408
|
+
|
|
409
|
+
Second = _construct_float_dpf(offsets.Second, offsets.Nano, 9, None, "nanosecond")
|
|
410
|
+
Second.__doc__ = _add_examples_to_docs('second', """
|
|
411
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
412
|
+
|
|
413
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Second(1)
|
|
414
|
+
2012-12-12 12:00:01
|
|
415
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Second(1)
|
|
416
|
+
2012-12-12 11:59:59
|
|
417
|
+
|
|
418
|
+
Using ``float`` value to pass nanoseconds:
|
|
419
|
+
|
|
420
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Second(1.000000123)
|
|
421
|
+
2012-12-12 12:00:01.000000123
|
|
422
|
+
|
|
423
|
+
Use offset in columns:
|
|
424
|
+
|
|
425
|
+
>>> t = otp.Tick(A=1)
|
|
426
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
427
|
+
>>> t['T'] += otp.Second(t['A'])
|
|
428
|
+
>>> otp.run(t)
|
|
429
|
+
Time T A
|
|
430
|
+
0 2003-12-01 2012-12-12 12:00:01 1
|
|
431
|
+
|
|
432
|
+
Use it to calculate difference between two dates:
|
|
433
|
+
|
|
434
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2022, 1, 1, 0, 1))
|
|
435
|
+
>>> t['DIFF'] = otp.Second(t['B'] - t['A'])
|
|
436
|
+
>>> otp.run(t)
|
|
437
|
+
Time A B DIFF
|
|
438
|
+
0 2003-12-01 2022-01-01 2022-01-01 00:01:00 60
|
|
439
|
+
""", additional_types=_float_dpf_types, additional_notes=_float_dpf_notes)
|
|
440
|
+
|
|
441
|
+
Milli = _construct_float_dpf(offsets.Milli, offsets.Nano, 6, "millisecond", "nanosecond")
|
|
442
|
+
Milli.__doc__ = _add_examples_to_docs('millisecond', """
|
|
443
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
444
|
+
|
|
445
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Milli(1)
|
|
446
|
+
2012-12-12 12:00:00.001000
|
|
447
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Milli(1)
|
|
448
|
+
2012-12-12 11:59:59.999000
|
|
449
|
+
|
|
450
|
+
Using ``float`` value to pass nanoseconds:
|
|
451
|
+
|
|
452
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Milli(1.000123)
|
|
453
|
+
2012-12-12 12:00:00.001000123
|
|
454
|
+
|
|
455
|
+
Use offset in columns:
|
|
456
|
+
|
|
457
|
+
>>> t = otp.Tick(A=1)
|
|
458
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
459
|
+
>>> t['T'] += otp.Milli(t['A'])
|
|
460
|
+
>>> otp.run(t)
|
|
461
|
+
Time T A
|
|
462
|
+
0 2003-12-01 2012-12-12 12:00:00.001 1
|
|
463
|
+
|
|
464
|
+
Use it to calculate difference between two dates:
|
|
465
|
+
|
|
466
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2022, 1, 1, 0, 0, 1))
|
|
467
|
+
>>> t['DIFF'] = otp.Milli(t['B'] - t['A'])
|
|
468
|
+
>>> otp.run(t)
|
|
469
|
+
Time A B DIFF
|
|
470
|
+
0 2003-12-01 2022-01-01 2022-01-01 00:00:01 1000
|
|
471
|
+
""", additional_types=_float_dpf_types, additional_notes=_float_dpf_notes)
|
|
472
|
+
|
|
473
|
+
# microseconds are not supported yet
|
|
474
|
+
|
|
475
|
+
Nano = _construct_dpf(offsets.Nano, "nanosecond")
|
|
476
|
+
Nano.__doc__ = _add_examples_to_docs('nanosecond', """
|
|
477
|
+
Add to or subtract from :py:class:`otp.datetime <onetick.py.datetime>` object:
|
|
478
|
+
|
|
479
|
+
>>> otp.datetime(2012, 12, 12, 12) + otp.Nano(1)
|
|
480
|
+
2012-12-12 12:00:00.000000001
|
|
481
|
+
>>> otp.datetime(2012, 12, 12, 12) - otp.Nano(1)
|
|
482
|
+
2012-12-12 11:59:59.999999999
|
|
483
|
+
|
|
484
|
+
Use offset in columns:
|
|
485
|
+
|
|
486
|
+
>>> t = otp.Tick(A=1)
|
|
487
|
+
>>> t['T'] = otp.datetime(2012, 12, 12, 12)
|
|
488
|
+
>>> t['T'] += otp.Nano(t['A'])
|
|
489
|
+
>>> otp.run(t)
|
|
490
|
+
Time T A
|
|
491
|
+
0 2003-12-01 2012-12-12 12:00:00.000000001 1
|
|
492
|
+
|
|
493
|
+
Use it to calculate difference between two dates:
|
|
494
|
+
|
|
495
|
+
>>> t = otp.Tick(A=otp.dt(2022, 1, 1), B=otp.dt(2022, 1, 1, 0, 0, 1))
|
|
496
|
+
>>> t['DIFF'] = otp.Nano(t['B'] - t['A'])
|
|
497
|
+
>>> otp.run(t)
|
|
498
|
+
Time A B DIFF
|
|
499
|
+
0 2003-12-01 2022-01-01 2022-01-01 00:00:01 1000000000
|
|
500
|
+
""")
|
|
501
|
+
|
|
502
|
+
# ---------------------------- #
|
|
503
|
+
|
|
504
|
+
|
|
505
|
+
class _inner_string(type):
|
|
506
|
+
def __str__(cls):
|
|
507
|
+
if cls.length is Ellipsis:
|
|
508
|
+
return "varstring"
|
|
509
|
+
if cls.length:
|
|
510
|
+
return f"string[{cls.length}]"
|
|
511
|
+
else:
|
|
512
|
+
return "string"
|
|
513
|
+
|
|
514
|
+
def __repr__(cls):
|
|
515
|
+
return str(cls)
|
|
516
|
+
|
|
517
|
+
# We have ot use functools.cache, because 'class' in python is an object,
|
|
518
|
+
# and _inner_str for the same item is different for every call,
|
|
519
|
+
# but we want to make str[1024] be equal to another str[1024]
|
|
520
|
+
@functools.lru_cache(maxsize=None) # noqa: W1518
|
|
521
|
+
def __getitem__(cls, item):
|
|
522
|
+
|
|
523
|
+
if (not isinstance(item, int) or item < 1) and item is not Ellipsis:
|
|
524
|
+
raise TypeError("It is not allowed to have non numeric index")
|
|
525
|
+
|
|
526
|
+
class _inner_str(string): # type: ignore[misc]
|
|
527
|
+
length = item
|
|
528
|
+
|
|
529
|
+
def __len__(self):
|
|
530
|
+
return self.__class__.length
|
|
531
|
+
|
|
532
|
+
return _inner_str
|
|
533
|
+
|
|
534
|
+
|
|
535
|
+
class string(str, metaclass=_inner_string): # type: ignore[misc]
|
|
536
|
+
"""
|
|
537
|
+
OneTick data type representing string with length and varstring.
|
|
538
|
+
To set string length use ``__getitem__``.
|
|
539
|
+
If the length is not set then the :py:attr:`~DEFAULT_LENGTH` length is used by default.
|
|
540
|
+
In this case using ``otp.string`` is the same as using ``str``.
|
|
541
|
+
If the length is set to Ellipse it represents varstring. Varstring is used for returning variably sized strings.
|
|
542
|
+
|
|
543
|
+
Note
|
|
544
|
+
----
|
|
545
|
+
If you try to set value with length x to string[y] and x > y, value will be truncated to y length.
|
|
546
|
+
|
|
547
|
+
Attributes
|
|
548
|
+
----------
|
|
549
|
+
DEFAULT_LENGTH: int
|
|
550
|
+
default length of the string when the length is not specified
|
|
551
|
+
|
|
552
|
+
Examples
|
|
553
|
+
--------
|
|
554
|
+
|
|
555
|
+
Adding new fields with :class:`otp.string <string>` type:
|
|
556
|
+
|
|
557
|
+
>>> t = otp.Tick(A=otp.string[32]('HELLO'))
|
|
558
|
+
>>> t['B'] = otp.string[128]('WORLD')
|
|
559
|
+
>>> t.schema
|
|
560
|
+
{'A': string[32], 'B': string[128]}
|
|
561
|
+
>>> otp.run(t)
|
|
562
|
+
Time A B
|
|
563
|
+
0 2003-12-01 HELLO WORLD
|
|
564
|
+
|
|
565
|
+
Note that class :class:`otp.string <string>` is a child of python's ``str`` class,
|
|
566
|
+
so every object passed to constructor is converted to string.
|
|
567
|
+
So it may not work as expected in some cases, e.g. when passing :class:`~onetick.py.Operation` objects
|
|
568
|
+
(because their string representation is the name of the column or OneTick expression).
|
|
569
|
+
In this case it's better to use direct type conversion to get :class:`otp.string <string>` object:
|
|
570
|
+
|
|
571
|
+
>>> t = otp.Tick(X=otp.string[256](t['_SYMBOL_NAME']))
|
|
572
|
+
>>> t['Y'] = t['_SYMBOL_NAME'].astype(otp.string[256])
|
|
573
|
+
>>> t.schema
|
|
574
|
+
{'X': string[256], 'Y': string[256]}
|
|
575
|
+
>>> otp.run(t, symbols='AAAA')
|
|
576
|
+
Time X Y
|
|
577
|
+
0 2003-12-01 _SYMBOL_NAME AAAA
|
|
578
|
+
|
|
579
|
+
Setting the type of the existing field:
|
|
580
|
+
|
|
581
|
+
>>> # OTdirective: skip-snippet:;
|
|
582
|
+
>>> t = otp.Tick(A='a')
|
|
583
|
+
>>> t = t.table(A=otp.string[10])
|
|
584
|
+
>>> t.schema
|
|
585
|
+
{'A': string[10]}
|
|
586
|
+
|
|
587
|
+
Example of truncation column value to set string length.
|
|
588
|
+
|
|
589
|
+
>>> # OTdirective: skip-snippet:;
|
|
590
|
+
>>> t['A'] *= 100
|
|
591
|
+
>>> t['B'] = t['A'].str.len()
|
|
592
|
+
>>> otp.run(t)
|
|
593
|
+
Time A B
|
|
594
|
+
0 2003-12-01 aaaaaaaaaa 10
|
|
595
|
+
|
|
596
|
+
Example of string with default length.
|
|
597
|
+
|
|
598
|
+
>>> t = otp.Tick(A='a')
|
|
599
|
+
>>> t['A'] *= 100
|
|
600
|
+
>>> t['B'] = t['A'].str.len()
|
|
601
|
+
>>> otp.run(t)
|
|
602
|
+
Time A B
|
|
603
|
+
0 2003-12-01 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 64
|
|
604
|
+
|
|
605
|
+
Setting Ellipsis as length represents varstring.
|
|
606
|
+
|
|
607
|
+
>>> t = otp.Tick(A='a')
|
|
608
|
+
>>> t = t.table(A=otp.string[...])
|
|
609
|
+
>>> t.schema
|
|
610
|
+
{'A': varstring}
|
|
611
|
+
|
|
612
|
+
Varstring length is multiplied.
|
|
613
|
+
|
|
614
|
+
>>> t['A'] *= 65
|
|
615
|
+
>>> t['B'] = t['A'].str.len()
|
|
616
|
+
>>> otp.run(t)
|
|
617
|
+
Time A B
|
|
618
|
+
0 2003-12-01 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa 65
|
|
619
|
+
|
|
620
|
+
`otp.varstring` is a shortcut:
|
|
621
|
+
|
|
622
|
+
>>> t = otp.Tick(A='a')
|
|
623
|
+
>>> t = t.table(A=otp.varstring)
|
|
624
|
+
>>> t.schema
|
|
625
|
+
{'A': varstring}
|
|
626
|
+
"""
|
|
627
|
+
|
|
628
|
+
DEFAULT_LENGTH = 64
|
|
629
|
+
length = None
|
|
630
|
+
|
|
631
|
+
def __repr__(self):
|
|
632
|
+
return f'{self.__class__}({super().__repr__()})'
|
|
633
|
+
|
|
634
|
+
|
|
635
|
+
varstring = string[...] # type: ignore[type-arg,misc]
|
|
636
|
+
|
|
637
|
+
|
|
638
|
+
class _nan_base(type):
|
|
639
|
+
def __str__(cls):
|
|
640
|
+
return "double"
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
class _nan(float, metaclass=_nan_base):
|
|
644
|
+
"""
|
|
645
|
+
Object that represents NaN (not a number) float value.
|
|
646
|
+
Can be used anywhere where float value is expected.
|
|
647
|
+
|
|
648
|
+
Examples
|
|
649
|
+
--------
|
|
650
|
+
>>> t = otp.Ticks({'A': [1.1, 2.2, otp.nan]})
|
|
651
|
+
>>> t['B'] = otp.nan
|
|
652
|
+
>>> t['C'] = t['A'] / 0
|
|
653
|
+
>>> t['D'] = t['A'] + otp.nan
|
|
654
|
+
>>> otp.run(t)
|
|
655
|
+
Time A B C D
|
|
656
|
+
0 2003-12-01 00:00:00.000 1.1 NaN inf NaN
|
|
657
|
+
1 2003-12-01 00:00:00.001 2.2 NaN inf NaN
|
|
658
|
+
2 2003-12-01 00:00:00.002 NaN NaN NaN NaN
|
|
659
|
+
"""
|
|
660
|
+
|
|
661
|
+
__name__ = 'nan'
|
|
662
|
+
|
|
663
|
+
def __str__(self):
|
|
664
|
+
return "NAN()"
|
|
665
|
+
|
|
666
|
+
def __repr__(self):
|
|
667
|
+
return 'nan'
|
|
668
|
+
|
|
669
|
+
|
|
670
|
+
nan = _nan()
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
class _inf(float, metaclass=_nan_base):
|
|
674
|
+
"""
|
|
675
|
+
Object that represents infinity value.
|
|
676
|
+
Can be used anywhere where float value is expected.
|
|
677
|
+
|
|
678
|
+
Examples
|
|
679
|
+
--------
|
|
680
|
+
>>> t = otp.Ticks({'A': [1.1, 2.2, otp.inf]})
|
|
681
|
+
>>> t['B'] = otp.inf
|
|
682
|
+
>>> t['C'] = t['A'] / 0
|
|
683
|
+
>>> t['D'] = t['A'] - otp.inf
|
|
684
|
+
>>> otp.run(t)
|
|
685
|
+
Time A B C D
|
|
686
|
+
0 2003-12-01 00:00:00.000 1.1 inf inf -inf
|
|
687
|
+
1 2003-12-01 00:00:00.001 2.2 inf inf -inf
|
|
688
|
+
2 2003-12-01 00:00:00.002 inf inf inf NaN
|
|
689
|
+
"""
|
|
690
|
+
|
|
691
|
+
__name__ = 'inf'
|
|
692
|
+
|
|
693
|
+
def __init__(self):
|
|
694
|
+
self._sign = "" # empty string or '-' for negative infinity
|
|
695
|
+
|
|
696
|
+
def __str__(self):
|
|
697
|
+
return f"{self._sign}INFINITY()"
|
|
698
|
+
|
|
699
|
+
def __repr__(self):
|
|
700
|
+
return f'{self._sign}inf'
|
|
701
|
+
|
|
702
|
+
def __neg__(self):
|
|
703
|
+
result = _inf()
|
|
704
|
+
result._sign = "" if self._sign else "-"
|
|
705
|
+
return result
|
|
706
|
+
|
|
707
|
+
|
|
708
|
+
inf = _inf()
|
|
709
|
+
|
|
710
|
+
|
|
711
|
+
class decimal:
|
|
712
|
+
"""
|
|
713
|
+
Object that represents decimal OneTick value.
|
|
714
|
+
Decimal is 128 bit base 10 floating point number.
|
|
715
|
+
|
|
716
|
+
Parameters
|
|
717
|
+
----------
|
|
718
|
+
value: int, float, str
|
|
719
|
+
The value to initialize decimal from.
|
|
720
|
+
Note that float values may be converted with precision lost.
|
|
721
|
+
|
|
722
|
+
Examples
|
|
723
|
+
--------
|
|
724
|
+
|
|
725
|
+
:py:class:`~onetick.py.types.decimal` objects can be used in tick generators
|
|
726
|
+
and column operations as any other onetick-py type:
|
|
727
|
+
|
|
728
|
+
>>> t = otp.Ticks({'A': [otp.decimal(1), otp.decimal(2)]})
|
|
729
|
+
>>> t['B'] = otp.decimal(1.23456789)
|
|
730
|
+
>>> t['C'] = t['A'] / 0
|
|
731
|
+
>>> t['D'] = t['A'] + otp.nan
|
|
732
|
+
>>> otp.run(t)
|
|
733
|
+
Time A B C D
|
|
734
|
+
0 2003-12-01 00:00:00.000 1.0 1.234568 inf NaN
|
|
735
|
+
1 2003-12-01 00:00:00.001 2.0 1.234568 inf NaN
|
|
736
|
+
|
|
737
|
+
Additionally, any arithmetic operation with :py:class:`~onetick.py.types.decimal` object will return
|
|
738
|
+
an :py:class:`~onetick.py.Operation` object:
|
|
739
|
+
|
|
740
|
+
>>> t = otp.Tick(A=1)
|
|
741
|
+
>>> t['X'] = otp.decimal(1) / 0
|
|
742
|
+
>>> otp.run(t)
|
|
743
|
+
Time A X
|
|
744
|
+
0 2003-12-01 1 inf
|
|
745
|
+
|
|
746
|
+
Note that converting from float (first row) may result in losing precision.
|
|
747
|
+
:py:class:`~onetick.py.types.decimal` objects are created from strings or integers, so they don't lose precision:
|
|
748
|
+
|
|
749
|
+
>>> t0 = otp.Tick(A=0.1)
|
|
750
|
+
>>> t1 = otp.Tick(A=otp.decimal(0.01))
|
|
751
|
+
>>> t2 = otp.Tick(A=otp.decimal('0.001'))
|
|
752
|
+
>>> t3 = otp.Tick(A=otp.decimal(1) / otp.decimal(10_000))
|
|
753
|
+
>>> t = otp.merge([t0, t1, t2, t3], enforce_order=True)
|
|
754
|
+
>>> t['STR_A'] = t['A'].decimal.str(34)
|
|
755
|
+
>>> otp.run(t)
|
|
756
|
+
Time A STR_A
|
|
757
|
+
0 2003-12-01 0.1000 0.1000000000000000055511151231257827
|
|
758
|
+
1 2003-12-01 0.0100 0.0100000000000000000000000000000000
|
|
759
|
+
2 2003-12-01 0.0010 0.0010000000000000000000000000000000
|
|
760
|
+
3 2003-12-01 0.0001 0.0001000000000000000000000000000000
|
|
761
|
+
|
|
762
|
+
Note that :py:class:`otp.Ticks <onetick.py.Ticks>` will convert everything from string under the hood,
|
|
763
|
+
so even the float values will not lose precision:
|
|
764
|
+
|
|
765
|
+
>>> t = otp.Ticks({'A': [0.1, otp.decimal(0.01), otp.decimal('0.001'), otp.decimal(1e-4)]})
|
|
766
|
+
>>> t['STR_A'] = t['A'].decimal.str(34)
|
|
767
|
+
>>> otp.run(t)
|
|
768
|
+
Time A STR_A
|
|
769
|
+
0 2003-12-01 00:00:00.000 0.1000 0.1000000000000000000000000000000000
|
|
770
|
+
1 2003-12-01 00:00:00.001 0.0100 0.0100000000000000000000000000000000
|
|
771
|
+
2 2003-12-01 00:00:00.002 0.0010 0.0010000000000000000000000000000000
|
|
772
|
+
3 2003-12-01 00:00:00.003 0.0001 0.0001000000000000000000000000000000
|
|
773
|
+
"""
|
|
774
|
+
def __new__(cls, *args, **kwargs):
|
|
775
|
+
# this method dynamically adds properties and methods
|
|
776
|
+
# from otp.Operation class to this one
|
|
777
|
+
|
|
778
|
+
# otp.decimal class doesn't fit well in onetick-py type system,
|
|
779
|
+
# so this class is a mix of both type and Operation logic
|
|
780
|
+
|
|
781
|
+
# Basically it works like this:
|
|
782
|
+
# otp.decimal is a OneTick type
|
|
783
|
+
# otp.decimal(1) is a decimal type object
|
|
784
|
+
# Doing anything with this object returns an otp.Operation:
|
|
785
|
+
# otp.decimal(1) / 2
|
|
786
|
+
|
|
787
|
+
def proxy_wrap(attr, value):
|
|
788
|
+
if callable(value):
|
|
789
|
+
@functools.wraps(value)
|
|
790
|
+
def f(self, *args, **kwargs):
|
|
791
|
+
op = self.to_operation()
|
|
792
|
+
return getattr(op, attr)(*args, **kwargs)
|
|
793
|
+
return f
|
|
794
|
+
else:
|
|
795
|
+
@functools.wraps(value)
|
|
796
|
+
def f(self):
|
|
797
|
+
op = self.to_operation()
|
|
798
|
+
return getattr(op, attr)
|
|
799
|
+
return property(f)
|
|
800
|
+
|
|
801
|
+
for attr, value in inspect.getmembers(otp.Operation):
|
|
802
|
+
# comparison methods are defined by default for some reason,
|
|
803
|
+
# but we want to get them from otp.Operation
|
|
804
|
+
if not hasattr(cls, attr) or attr in ('__lt__', '__le__', '__eq__', '__ne__', '__gt__', '__ge__'):
|
|
805
|
+
setattr(cls, attr, proxy_wrap(attr, value))
|
|
806
|
+
|
|
807
|
+
return super().__new__(cls)
|
|
808
|
+
|
|
809
|
+
def __init__(self, value):
|
|
810
|
+
from onetick.py.core.column_operations.base import OnetickParameter
|
|
811
|
+
supported_types = (str, int, float, OnetickParameter)
|
|
812
|
+
if not isinstance(value, supported_types):
|
|
813
|
+
raise TypeError(f"Parameter 'value' must be one of these types: {supported_types}, got {type(value)}")
|
|
814
|
+
self.__value = value
|
|
815
|
+
|
|
816
|
+
@classmethod
|
|
817
|
+
def _to_onetick_type_string(cls):
|
|
818
|
+
# called by ott.type2str
|
|
819
|
+
return 'decimal'
|
|
820
|
+
|
|
821
|
+
def _to_onetick_string(self):
|
|
822
|
+
# called by ott.value2str
|
|
823
|
+
from onetick.py.core.column_operations.base import OnetickParameter
|
|
824
|
+
if isinstance(self.__value, OnetickParameter):
|
|
825
|
+
value = self.__value
|
|
826
|
+
else:
|
|
827
|
+
value = str(self.__value)
|
|
828
|
+
return f'STRING_TO_DECIMAL({value2str(value)})'
|
|
829
|
+
|
|
830
|
+
def to_operation(self):
|
|
831
|
+
return otp.Operation(op_str=self._to_onetick_string(), dtype=decimal)
|
|
832
|
+
|
|
833
|
+
def __str__(self):
|
|
834
|
+
# called by otp.CSV, we don't need to convert the value with OneTick functions in this case
|
|
835
|
+
return str(self.__value)
|
|
836
|
+
|
|
837
|
+
def __repr__(self):
|
|
838
|
+
return f"{self.__class__.__name__}({value2str(self.__value)})"
|
|
839
|
+
|
|
840
|
+
def __format__(self, __format_spec: str) -> str:
|
|
841
|
+
return _decimal.Decimal(self.__value).__format__(__format_spec)
|
|
842
|
+
|
|
843
|
+
# --------------------------------------------------------------- #
|
|
844
|
+
# AUXILIARY FUNCTIONS
|
|
845
|
+
# --------------------------------------------------------------- #
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
def is_type_basic(dtype):
|
|
849
|
+
return dtype in (
|
|
850
|
+
int,
|
|
851
|
+
float,
|
|
852
|
+
str,
|
|
853
|
+
byte,
|
|
854
|
+
short,
|
|
855
|
+
uint,
|
|
856
|
+
ulong,
|
|
857
|
+
_int,
|
|
858
|
+
long,
|
|
859
|
+
nsectime,
|
|
860
|
+
msectime,
|
|
861
|
+
decimal,
|
|
862
|
+
) or issubclass(dtype, string)
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
# TODO: PY-632: unify these functions with others
|
|
866
|
+
def get_source_base_type(value):
|
|
867
|
+
if inspect.isclass(value):
|
|
868
|
+
value_type = value
|
|
869
|
+
if not is_type_basic(value_type):
|
|
870
|
+
warnings.warn('Setting schema with complex types is deprecated,'
|
|
871
|
+
' use basic type instead', FutureWarning, stacklevel=2)
|
|
872
|
+
else:
|
|
873
|
+
warnings.warn('Setting schema with instance of the class is deprecated,'
|
|
874
|
+
' use type instead', FutureWarning, stacklevel=2)
|
|
875
|
+
value_type = type(value)
|
|
876
|
+
# convert string to custom string if necessary
|
|
877
|
+
if value_type is str and len(value) > string.DEFAULT_LENGTH:
|
|
878
|
+
value_type = string[len(value)]
|
|
879
|
+
|
|
880
|
+
if issubclass(value_type, bool):
|
|
881
|
+
value_type = float
|
|
882
|
+
|
|
883
|
+
if is_time_type(value_type):
|
|
884
|
+
value_type = nsectime
|
|
885
|
+
|
|
886
|
+
# check valid value type
|
|
887
|
+
if get_base_type(value_type) not in [int, float, str, bool, decimal]:
|
|
888
|
+
raise TypeError(f'Type "{repr(value_type)}" is not supported.')
|
|
889
|
+
|
|
890
|
+
if not is_type_basic(value_type):
|
|
891
|
+
raise TypeError(f"Type {repr(value_type)} can't be set in schema.")
|
|
892
|
+
return value_type
|
|
893
|
+
|
|
894
|
+
|
|
895
|
+
def is_type_supported(dtype):
|
|
896
|
+
return get_base_type(dtype) in [int, float, str, bool, decimal] or issubclass(dtype, (datetime, date))
|
|
897
|
+
|
|
898
|
+
|
|
899
|
+
def get_base_type(obj):
|
|
900
|
+
if issubclass(obj, str):
|
|
901
|
+
return str
|
|
902
|
+
elif issubclass(obj, bool):
|
|
903
|
+
return bool
|
|
904
|
+
elif issubclass(obj, int):
|
|
905
|
+
return int
|
|
906
|
+
elif issubclass(obj, float):
|
|
907
|
+
return float
|
|
908
|
+
elif issubclass(obj, decimal):
|
|
909
|
+
return decimal
|
|
910
|
+
|
|
911
|
+
return type(None)
|
|
912
|
+
|
|
913
|
+
|
|
914
|
+
def get_object_type(obj):
|
|
915
|
+
if isinstance(obj, (_nan, _inf)):
|
|
916
|
+
return float
|
|
917
|
+
if isinstance(obj, Type):
|
|
918
|
+
return obj
|
|
919
|
+
if hasattr(obj, 'dtype'):
|
|
920
|
+
dtype = obj.dtype
|
|
921
|
+
if isinstance(dtype, np.dtype):
|
|
922
|
+
return dtype.type
|
|
923
|
+
return dtype
|
|
924
|
+
if is_time_type(obj):
|
|
925
|
+
return nsectime
|
|
926
|
+
# pylint: disable-next=unidiomatic-typecheck
|
|
927
|
+
if type(obj) is int and obj > long.MAX:
|
|
928
|
+
# by default we use python's int (onetick's long) for numbers
|
|
929
|
+
# in case the number is too big, let's use onetick's ulong
|
|
930
|
+
return ulong
|
|
931
|
+
return type(obj)
|
|
932
|
+
|
|
933
|
+
|
|
934
|
+
def get_type_by_objects(objs):
|
|
935
|
+
"""
|
|
936
|
+
Helper that calculates the widest type of the list passed objects.
|
|
937
|
+
Used to determine type by returned values.
|
|
938
|
+
"""
|
|
939
|
+
|
|
940
|
+
# collect types
|
|
941
|
+
types = set()
|
|
942
|
+
for v in objs:
|
|
943
|
+
t = get_object_type(v)
|
|
944
|
+
if issubclass(t, str):
|
|
945
|
+
t = str
|
|
946
|
+
types.add(t)
|
|
947
|
+
|
|
948
|
+
# does not allow to mix string and numeric types
|
|
949
|
+
dtype = None
|
|
950
|
+
if str in types and (float in types or int in types or bool in types or nsectime in types or msectime in types):
|
|
951
|
+
raise TypeError("It is not allowed to return values of string type and numeric type in one function.")
|
|
952
|
+
|
|
953
|
+
# if there is only one value there, then
|
|
954
|
+
# use it as is
|
|
955
|
+
if len(types) == 1:
|
|
956
|
+
dtype = next(iter(types))
|
|
957
|
+
if dtype is bool:
|
|
958
|
+
return dtype
|
|
959
|
+
|
|
960
|
+
# process numeric types: the most generic is float
|
|
961
|
+
if int in types:
|
|
962
|
+
dtype = int
|
|
963
|
+
if bool in types:
|
|
964
|
+
dtype = float
|
|
965
|
+
# None is equal to otp.nan
|
|
966
|
+
if float in types or type(None) in types:
|
|
967
|
+
dtype = float
|
|
968
|
+
|
|
969
|
+
# process string types, taking into account OneTick long strings
|
|
970
|
+
if str in types:
|
|
971
|
+
max_len = string.DEFAULT_LENGTH
|
|
972
|
+
for v in objs:
|
|
973
|
+
t = get_object_type(v)
|
|
974
|
+
if issubclass(t, string):
|
|
975
|
+
if t.length is Ellipsis or max_len is Ellipsis:
|
|
976
|
+
max_len = Ellipsis
|
|
977
|
+
else:
|
|
978
|
+
max_len = max(t.length, max_len)
|
|
979
|
+
elif isinstance(v, str):
|
|
980
|
+
max_len = max(len(v), max_len)
|
|
981
|
+
|
|
982
|
+
if max_len == string.DEFAULT_LENGTH:
|
|
983
|
+
dtype = str
|
|
984
|
+
else:
|
|
985
|
+
dtype = string[max_len] # pylint: disable=E1136
|
|
986
|
+
|
|
987
|
+
# process msectime and nsectime
|
|
988
|
+
if dtype is float and (msectime in types or nsectime in types):
|
|
989
|
+
raise TypeError("It is not allowed to return value of time type and float type in one function.")
|
|
990
|
+
|
|
991
|
+
if msectime in types:
|
|
992
|
+
dtype = msectime
|
|
993
|
+
if nsectime in types:
|
|
994
|
+
dtype = nsectime
|
|
995
|
+
|
|
996
|
+
# we assume the None value has float default value, ie NaN
|
|
997
|
+
# pylint: disable-next=unidiomatic-typecheck
|
|
998
|
+
if type(None) is dtype:
|
|
999
|
+
dtype = float
|
|
1000
|
+
|
|
1001
|
+
return dtype
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
# ------------------- #
|
|
1005
|
+
# extend datetime
|
|
1006
|
+
|
|
1007
|
+
|
|
1008
|
+
class AbstractTime:
|
|
1009
|
+
def __init__(self):
|
|
1010
|
+
self.ts: pd.Timestamp
|
|
1011
|
+
|
|
1012
|
+
@property
|
|
1013
|
+
def year(self):
|
|
1014
|
+
return self.ts.year
|
|
1015
|
+
|
|
1016
|
+
@property
|
|
1017
|
+
def month(self):
|
|
1018
|
+
return self.ts.month
|
|
1019
|
+
|
|
1020
|
+
@property
|
|
1021
|
+
def day(self):
|
|
1022
|
+
return self.ts.day
|
|
1023
|
+
|
|
1024
|
+
def date(self):
|
|
1025
|
+
return _date(self.year, self.month, self.day)
|
|
1026
|
+
|
|
1027
|
+
@property
|
|
1028
|
+
def start(self):
|
|
1029
|
+
return pd.Timestamp(self.year, self.month, self.day)
|
|
1030
|
+
|
|
1031
|
+
@property
|
|
1032
|
+
def end(self):
|
|
1033
|
+
return pd.Timestamp(next_day(self.start))
|
|
1034
|
+
|
|
1035
|
+
def strftime(self, fmt):
|
|
1036
|
+
return self.ts.strftime(fmt)
|
|
1037
|
+
|
|
1038
|
+
@property
|
|
1039
|
+
def value(self):
|
|
1040
|
+
return self.ts.value
|
|
1041
|
+
|
|
1042
|
+
def timestamp(self):
|
|
1043
|
+
return self.ts.timestamp()
|
|
1044
|
+
|
|
1045
|
+
def __eq__(self, other):
|
|
1046
|
+
other = getattr(other, "ts", other)
|
|
1047
|
+
return self.ts == other
|
|
1048
|
+
|
|
1049
|
+
def __hash__(self):
|
|
1050
|
+
return hash(self.ts)
|
|
1051
|
+
|
|
1052
|
+
def __gt__(self, other):
|
|
1053
|
+
other = getattr(other, "ts", other)
|
|
1054
|
+
return self.ts > other
|
|
1055
|
+
|
|
1056
|
+
def __ge__(self, other):
|
|
1057
|
+
other = getattr(other, "ts", other)
|
|
1058
|
+
return self.ts >= other
|
|
1059
|
+
|
|
1060
|
+
def __lt__(self, other):
|
|
1061
|
+
other = getattr(other, "ts", other)
|
|
1062
|
+
return self.ts < other
|
|
1063
|
+
|
|
1064
|
+
def __le__(self, other):
|
|
1065
|
+
other = getattr(other, "ts", other)
|
|
1066
|
+
return self.ts <= other
|
|
1067
|
+
|
|
1068
|
+
|
|
1069
|
+
class datetime(AbstractTime):
|
|
1070
|
+
"""
|
|
1071
|
+
Class :py:class:`otp.datetime <onetick.py.datetime>` is used for representing date with time in onetick-py.
|
|
1072
|
+
It can be used both when specifying start and end time for queries and
|
|
1073
|
+
in column operations with :py:class:`onetick.py.Source`.
|
|
1074
|
+
:ref:`Datetime offset objects <datetime_offsets>` (e.g. `otp.Nano`, `otp.Day`)
|
|
1075
|
+
can be added to or subtracted from `otp.datetime` object.
|
|
1076
|
+
|
|
1077
|
+
Note
|
|
1078
|
+
----
|
|
1079
|
+
Class :py:class:`otp.datetime <onetick.py.datetime>` share many methods
|
|
1080
|
+
that classes :pandas:`pandas.Timestamp` and :py:class:`datetime.datetime` have,
|
|
1081
|
+
but these objects are not fully interchangeable.
|
|
1082
|
+
Class :py:class:`otp.datetime <onetick.py.datetime>` should work in all onetick-py methods and classes,
|
|
1083
|
+
other classes should work too if documented,
|
|
1084
|
+
and may even work when not documented, but the users should not count on it.
|
|
1085
|
+
|
|
1086
|
+
Parameters
|
|
1087
|
+
----------
|
|
1088
|
+
first_arg: int, str, :py:class:`otp.datetime <onetick.py.datetime>`, :py:class:`otp.date <onetick.py.date>`\
|
|
1089
|
+
:pandas:`pandas.Timestamp`, :py:class:`datetime.datetime`
|
|
1090
|
+
If `month`, `day` and other parts of date are specified,
|
|
1091
|
+
first argument will be considered as year.
|
|
1092
|
+
Otherwise, first argument will be converted to :py:class:`otp.datetime <onetick.py.datetime>`.
|
|
1093
|
+
month: int
|
|
1094
|
+
Number between 1 and 12.
|
|
1095
|
+
day: int
|
|
1096
|
+
Number between 1 and 31.
|
|
1097
|
+
hour: int, default=0
|
|
1098
|
+
Number between 0 and 23.
|
|
1099
|
+
minute: int, default=0
|
|
1100
|
+
Number between 0 and 59.
|
|
1101
|
+
second: int, default=0
|
|
1102
|
+
Number between 0 and 59.
|
|
1103
|
+
microsecond: int, default=0
|
|
1104
|
+
Number between 0 and 999999.
|
|
1105
|
+
nanosecond: int, default=0
|
|
1106
|
+
Number between 0 and 999.
|
|
1107
|
+
tzinfo: :py:class:`datetime.tzinfo`
|
|
1108
|
+
Timezone object.
|
|
1109
|
+
tz: str
|
|
1110
|
+
Timezone name.
|
|
1111
|
+
|
|
1112
|
+
Examples
|
|
1113
|
+
--------
|
|
1114
|
+
|
|
1115
|
+
Initialization by :py:class:`datetime.datetime` class from standard library:
|
|
1116
|
+
|
|
1117
|
+
>>> otp.datetime(datetime.datetime(2019, 1, 1, 1))
|
|
1118
|
+
2019-01-01 01:00:00
|
|
1119
|
+
|
|
1120
|
+
Initialization by :pandas:`pandas.Timestamp` class:
|
|
1121
|
+
|
|
1122
|
+
>>> otp.datetime(pd.Timestamp(2019, 1, 1, 1))
|
|
1123
|
+
2019-01-01 01:00:00
|
|
1124
|
+
|
|
1125
|
+
Initialization by int timestamp:
|
|
1126
|
+
|
|
1127
|
+
>>> otp.datetime(1234567890)
|
|
1128
|
+
1970-01-01 00:00:01.234567890
|
|
1129
|
+
|
|
1130
|
+
Initialization by params with nanoseconds:
|
|
1131
|
+
|
|
1132
|
+
>>> otp.datetime(2019, 1, 1, 1, 2, 3, 4, 5)
|
|
1133
|
+
2019-01-01 01:02:03.000004005
|
|
1134
|
+
|
|
1135
|
+
Initialization by string:
|
|
1136
|
+
|
|
1137
|
+
>>> otp.datetime('2019/01/01 1:02')
|
|
1138
|
+
2019-01-01 01:02:00
|
|
1139
|
+
|
|
1140
|
+
`otp.dt` is the alias for `otp.datetime`:
|
|
1141
|
+
|
|
1142
|
+
>>> otp.dt(2019, 1, 1)
|
|
1143
|
+
2019-01-01 00:00:00
|
|
1144
|
+
|
|
1145
|
+
See also
|
|
1146
|
+
--------
|
|
1147
|
+
:ref:`Datetime offset objects <datetime_guide>`.
|
|
1148
|
+
"""
|
|
1149
|
+
def __init__(
|
|
1150
|
+
self,
|
|
1151
|
+
first_arg,
|
|
1152
|
+
month=None,
|
|
1153
|
+
day=None,
|
|
1154
|
+
hour=None,
|
|
1155
|
+
minute=None,
|
|
1156
|
+
second=None,
|
|
1157
|
+
microsecond=None,
|
|
1158
|
+
nanosecond=None,
|
|
1159
|
+
*,
|
|
1160
|
+
tzinfo=None,
|
|
1161
|
+
tz=None,
|
|
1162
|
+
): # TODO: python 3.8 change first_arg to positional only arg
|
|
1163
|
+
tz, tzinfo = self._process_timezones_args(tz, tzinfo)
|
|
1164
|
+
|
|
1165
|
+
if not any([month, day, hour, minute, second, microsecond, nanosecond]):
|
|
1166
|
+
result = self._create_from_one_arg(first_arg, tz, tzinfo)
|
|
1167
|
+
else:
|
|
1168
|
+
result = self._create_from_several_arg(first_arg, month, day, hour, minute, second, microsecond, nanosecond,
|
|
1169
|
+
tzinfo)
|
|
1170
|
+
self.ts = result
|
|
1171
|
+
|
|
1172
|
+
def _process_timezones_args(self, tz, tzinfo):
|
|
1173
|
+
if tz is not None:
|
|
1174
|
+
if tzinfo is None:
|
|
1175
|
+
# parameter tz in pandas.Timestamp is broken https://github.com/pandas-dev/pandas/issues/31929
|
|
1176
|
+
# it is fixed in pandas>=2.0.0, but we need to support older versions
|
|
1177
|
+
tzinfo = get_tzfile_by_name(tz)
|
|
1178
|
+
tz = None
|
|
1179
|
+
else:
|
|
1180
|
+
raise ValueError(
|
|
1181
|
+
"tzinfo and tz params are mutually exclusive parameters, "
|
|
1182
|
+
"they can't be specified both at the same time"
|
|
1183
|
+
)
|
|
1184
|
+
return tz, tzinfo
|
|
1185
|
+
|
|
1186
|
+
def _create_from_several_arg(self, first_arg, month, day, hour, minute, second, microsecond, nanosecond, tzinfo):
|
|
1187
|
+
if nanosecond is not None and not (0 <= nanosecond <= 999):
|
|
1188
|
+
raise ValueError(
|
|
1189
|
+
"Nanosecond parameter should be between 0 and 999. "
|
|
1190
|
+
"Please use microsecond parameter or otp.Nano object."
|
|
1191
|
+
)
|
|
1192
|
+
if parse_version(pd.__version__) >= parse_version("2.0.0"):
|
|
1193
|
+
result = pd.Timestamp(
|
|
1194
|
+
first_arg, month, day, hour or 0, minute or 0, second or 0, microsecond or 0,
|
|
1195
|
+
nanosecond=nanosecond or 0,
|
|
1196
|
+
).replace(tzinfo=tzinfo)
|
|
1197
|
+
else:
|
|
1198
|
+
result = pd.Timestamp(
|
|
1199
|
+
first_arg, month, day, hour or 0, minute or 0, second or 0, microsecond or 0, nanosecond or 0,
|
|
1200
|
+
).replace(tzinfo=tzinfo)
|
|
1201
|
+
return result
|
|
1202
|
+
|
|
1203
|
+
def _create_from_one_arg(self, first_arg, tz, tzinfo):
|
|
1204
|
+
arg_tz = getattr(first_arg, "tz", None)
|
|
1205
|
+
arg_tzinfo = getattr(first_arg, "tzinfo", None)
|
|
1206
|
+
if tz and arg_tz and arg_tz != tz or tzinfo and arg_tzinfo and arg_tzinfo != tzinfo:
|
|
1207
|
+
raise ValueError(
|
|
1208
|
+
"You've specified the timezone for the object, which already has it. "
|
|
1209
|
+
"It is recommended to swap the current timezone to desired by method of this object "
|
|
1210
|
+
"and then create otp.datetime object."
|
|
1211
|
+
)
|
|
1212
|
+
if isinstance(first_arg, (datetime, date)):
|
|
1213
|
+
first_arg = first_arg.ts
|
|
1214
|
+
result = pd.Timestamp(first_arg, tzinfo=tzinfo, tz=tz)
|
|
1215
|
+
return result
|
|
1216
|
+
|
|
1217
|
+
@property
|
|
1218
|
+
def start(self):
|
|
1219
|
+
return super().start.replace(tzinfo=self.tzinfo)
|
|
1220
|
+
|
|
1221
|
+
@property
|
|
1222
|
+
def end(self):
|
|
1223
|
+
return super().end.replace(tzinfo=self.tzinfo)
|
|
1224
|
+
|
|
1225
|
+
def replace(self, **kwargs):
|
|
1226
|
+
"""
|
|
1227
|
+
Replace parts of `otp.datetime` object.
|
|
1228
|
+
|
|
1229
|
+
Parameters
|
|
1230
|
+
----------
|
|
1231
|
+
year: int, optional
|
|
1232
|
+
month: int, optional
|
|
1233
|
+
day: int, optional
|
|
1234
|
+
hour: int, optional
|
|
1235
|
+
minute: int, optional
|
|
1236
|
+
second: int, optional
|
|
1237
|
+
microsecond: int, optional
|
|
1238
|
+
nanosecond: int, optional
|
|
1239
|
+
tzinfo: tz-convertible, optional
|
|
1240
|
+
|
|
1241
|
+
Returns
|
|
1242
|
+
-------
|
|
1243
|
+
result: :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1244
|
+
Timestamp with fields replaced.
|
|
1245
|
+
|
|
1246
|
+
Examples
|
|
1247
|
+
--------
|
|
1248
|
+
>>> ts = otp.datetime(2022, 2, 24, 3, 15, 54, 999, 1)
|
|
1249
|
+
>>> ts
|
|
1250
|
+
2022-02-24 03:15:54.000999001
|
|
1251
|
+
>>> ts.replace(year=2000, month=2, day=2, hour=2, minute=2, second=2, microsecond=2, nanosecond=2)
|
|
1252
|
+
2000-02-02 02:02:02.000002002
|
|
1253
|
+
"""
|
|
1254
|
+
return datetime(self.ts.replace(**kwargs))
|
|
1255
|
+
|
|
1256
|
+
@property
|
|
1257
|
+
def tz(self):
|
|
1258
|
+
return self.ts.tz
|
|
1259
|
+
|
|
1260
|
+
@property
|
|
1261
|
+
def tzinfo(self):
|
|
1262
|
+
return self.ts.tzinfo
|
|
1263
|
+
|
|
1264
|
+
@property
|
|
1265
|
+
def hour(self):
|
|
1266
|
+
return self.ts.hour
|
|
1267
|
+
|
|
1268
|
+
@property
|
|
1269
|
+
def minute(self):
|
|
1270
|
+
return self.ts.minute
|
|
1271
|
+
|
|
1272
|
+
@property
|
|
1273
|
+
def second(self):
|
|
1274
|
+
return self.ts.second
|
|
1275
|
+
|
|
1276
|
+
@property
|
|
1277
|
+
def microsecond(self):
|
|
1278
|
+
return self.ts.microsecond
|
|
1279
|
+
|
|
1280
|
+
@property
|
|
1281
|
+
def nanosecond(self):
|
|
1282
|
+
return self.ts.nanosecond
|
|
1283
|
+
|
|
1284
|
+
@staticmethod
|
|
1285
|
+
def now(tz=None):
|
|
1286
|
+
"""
|
|
1287
|
+
Will return :py:class:`otp.datetime <onetick.py.datetime>` object
|
|
1288
|
+
with timestamp at the moment of calling this function.
|
|
1289
|
+
Not to be confused with function :func:`otp.now <onetick.py.now>` which can only add column
|
|
1290
|
+
with current timestamp to the :py:class:`otp.Source <onetick.py.Source>` when running the query.
|
|
1291
|
+
|
|
1292
|
+
Parameters
|
|
1293
|
+
----------
|
|
1294
|
+
tz : str or timezone object, default None
|
|
1295
|
+
Timezone to localize to.
|
|
1296
|
+
"""
|
|
1297
|
+
return datetime(pd.Timestamp.now(tz))
|
|
1298
|
+
|
|
1299
|
+
def __add__(self, other):
|
|
1300
|
+
"""
|
|
1301
|
+
Add :ref:`datetime offset <datetime_offsets>` to otp.datetime.
|
|
1302
|
+
|
|
1303
|
+
Parameters
|
|
1304
|
+
----------
|
|
1305
|
+
other: :ref:`datetime offset <datetime_offsets>`, :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1306
|
+
object to add
|
|
1307
|
+
|
|
1308
|
+
Returns
|
|
1309
|
+
-------
|
|
1310
|
+
result: :py:class:`otp.datetime <onetick.py.datetime>`, :pandas:`pandas.Timedelta`
|
|
1311
|
+
return :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1312
|
+
if otp.Nano or another :ref:`datetime offset <datetime_offsets>` object was passed as an argument,
|
|
1313
|
+
or :pandas:`pandas.Timedelta` object if :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1314
|
+
was passed as an argument.
|
|
1315
|
+
|
|
1316
|
+
Examples
|
|
1317
|
+
--------
|
|
1318
|
+
>>> otp.datetime(2022, 2, 24) + otp.Nano(1)
|
|
1319
|
+
2022-02-24 00:00:00.000000001
|
|
1320
|
+
"""
|
|
1321
|
+
self._error_on_int_param(other, "+")
|
|
1322
|
+
return datetime(self.ts + other)
|
|
1323
|
+
|
|
1324
|
+
def __sub__(self, other):
|
|
1325
|
+
"""
|
|
1326
|
+
Subtract :ref:`datetime offset <datetime_offsets>` from otp.datetime.
|
|
1327
|
+
|
|
1328
|
+
Parameters
|
|
1329
|
+
----------
|
|
1330
|
+
other: :ref:`datetime offset <datetime_offsets>`, :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1331
|
+
object to subtract
|
|
1332
|
+
|
|
1333
|
+
Returns
|
|
1334
|
+
-------
|
|
1335
|
+
result: :py:class:`otp.datetime <onetick.py.datetime>`, :pandas:`pandas.Timedelta`
|
|
1336
|
+
return datetime if otp.Nano or another :ref:`datetime offset <datetime_offsets>`
|
|
1337
|
+
object was passed as an argument,
|
|
1338
|
+
or :pandas:`pandas.Timedelta` object if :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1339
|
+
was passed as an argument.
|
|
1340
|
+
|
|
1341
|
+
Examples
|
|
1342
|
+
--------
|
|
1343
|
+
>>> otp.datetime(2022, 2, 24) - otp.Nano(1)
|
|
1344
|
+
2022-02-23 23:59:59.999999999
|
|
1345
|
+
"""
|
|
1346
|
+
self._error_on_int_param(other, "-")
|
|
1347
|
+
other = getattr(other, "ts", other)
|
|
1348
|
+
result = self.ts - other
|
|
1349
|
+
# do not convert to datetime in case timedelta is returned (arg is date)
|
|
1350
|
+
result = datetime(result) if isinstance(result, pd.Timestamp) else result
|
|
1351
|
+
return result
|
|
1352
|
+
|
|
1353
|
+
def _error_on_int_param(self, other, op):
|
|
1354
|
+
if isinstance(other, int):
|
|
1355
|
+
raise TypeError(f"unsupported operand type(s) for {op}: 'otp.datetime' and 'int'")
|
|
1356
|
+
|
|
1357
|
+
def __str__(self):
|
|
1358
|
+
return str(self.ts)
|
|
1359
|
+
|
|
1360
|
+
def __repr__(self):
|
|
1361
|
+
return str(self.ts)
|
|
1362
|
+
|
|
1363
|
+
def tz_localize(self, tz):
|
|
1364
|
+
"""
|
|
1365
|
+
Localize tz-naive datetime object to a given timezone
|
|
1366
|
+
|
|
1367
|
+
Parameters
|
|
1368
|
+
----------
|
|
1369
|
+
tz: str or tzinfo
|
|
1370
|
+
timezone to localize datetime object into
|
|
1371
|
+
|
|
1372
|
+
Returns
|
|
1373
|
+
-------
|
|
1374
|
+
result: :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1375
|
+
localized datetime object
|
|
1376
|
+
|
|
1377
|
+
Examples
|
|
1378
|
+
--------
|
|
1379
|
+
>>> d = otp.datetime(2021, 6, 3)
|
|
1380
|
+
>>> d.tz_localize("EST5EDT")
|
|
1381
|
+
2021-06-03 00:00:00-04:00
|
|
1382
|
+
"""
|
|
1383
|
+
return datetime(self.ts.tz_localize(tz))
|
|
1384
|
+
|
|
1385
|
+
def tz_convert(self, tz):
|
|
1386
|
+
"""
|
|
1387
|
+
Convert tz-aware datetime object to another timezone
|
|
1388
|
+
|
|
1389
|
+
Parameters
|
|
1390
|
+
----------
|
|
1391
|
+
tz: str or tzinfo
|
|
1392
|
+
timezone to convert datetime object into
|
|
1393
|
+
|
|
1394
|
+
Returns
|
|
1395
|
+
-------
|
|
1396
|
+
result: :py:class:`otp.datetime <onetick.py.datetime>`
|
|
1397
|
+
converted datetime object
|
|
1398
|
+
|
|
1399
|
+
Examples
|
|
1400
|
+
--------
|
|
1401
|
+
>>> d = otp.datetime(2021, 6, 3, tz="EST5EDT")
|
|
1402
|
+
>>> d.tz_convert("Europe/Moscow")
|
|
1403
|
+
2021-06-03 07:00:00+03:00
|
|
1404
|
+
"""
|
|
1405
|
+
return datetime(self.ts.tz_convert(tz))
|
|
1406
|
+
|
|
1407
|
+
def to_operation(self, timezone=None):
|
|
1408
|
+
"""
|
|
1409
|
+
Convert :py:class:`otp.datetime <onetick.py.datetime>` object to
|
|
1410
|
+
:py:class:`otp.Operation <onetick.py.Operation>`
|
|
1411
|
+
|
|
1412
|
+
Parameters
|
|
1413
|
+
----------
|
|
1414
|
+
timezone: Operation
|
|
1415
|
+
Can be used to specify timezone as an Operation.
|
|
1416
|
+
|
|
1417
|
+
Examples
|
|
1418
|
+
--------
|
|
1419
|
+
>>> t = otp.Ticks(TZ=['EST5EDT', 'GMT'])
|
|
1420
|
+
>>> t['DT'] = otp.dt(2022, 1, 1).to_operation(timezone=t['TZ'])
|
|
1421
|
+
>>> otp.run(t, timezone='GMT')[['TZ', 'DT']]
|
|
1422
|
+
TZ DT
|
|
1423
|
+
0 EST5EDT 2022-01-01 05:00:00
|
|
1424
|
+
1 GMT 2022-01-01 00:00:00
|
|
1425
|
+
"""
|
|
1426
|
+
return otp.Operation(op_str=otp.types.datetime2expr(self, timezone=timezone), dtype=otp.nsectime)
|
|
1427
|
+
|
|
1428
|
+
|
|
1429
|
+
dt = datetime
|
|
1430
|
+
|
|
1431
|
+
|
|
1432
|
+
class date(datetime):
|
|
1433
|
+
"""
|
|
1434
|
+
Class ``date`` is used for representing date in onetick-py.
|
|
1435
|
+
It can be used both when specifying start and end time for queries and
|
|
1436
|
+
in column operations with :py:class:`onetick.py.Source`.
|
|
1437
|
+
|
|
1438
|
+
Note
|
|
1439
|
+
----
|
|
1440
|
+
Class :py:class:`otp.date <onetick.py.date>` share many methods
|
|
1441
|
+
that classes :pandas:`pandas.Timestamp` and :py:class:`datetime.date` have,
|
|
1442
|
+
but these objects are not fully interchangeable.
|
|
1443
|
+
Class :py:class:`otp.date <onetick.py.date>` should work in all onetick-py methods and classes,
|
|
1444
|
+
other classes should work too if documented,
|
|
1445
|
+
and may even work when not documented, but the users should not count on it.
|
|
1446
|
+
|
|
1447
|
+
Parameters
|
|
1448
|
+
----------
|
|
1449
|
+
first_arg: int, str, :py:class:`otp.datetime <onetick.py.datetime>`, :py:class:`otp.date <onetick.py.date>`\
|
|
1450
|
+
:pandas:`pandas.Timestamp`, :py:class:`datetime.datetime`, :py:class:`datetime.date`
|
|
1451
|
+
If `month` and `day` arguments are specified, first argument will be considered as year.
|
|
1452
|
+
Otherwise, first argument will be converted to otp.date.
|
|
1453
|
+
month: int
|
|
1454
|
+
Number between 1 and 12.
|
|
1455
|
+
day: int
|
|
1456
|
+
Number between 1 and 31.
|
|
1457
|
+
|
|
1458
|
+
Examples
|
|
1459
|
+
--------
|
|
1460
|
+
:ref:`Datetime guide <datetime_guide>`.
|
|
1461
|
+
"""
|
|
1462
|
+
|
|
1463
|
+
def __init__(self, first_arg: Union[int, str, _date, _datetime, pd.Timestamp, AbstractTime],
|
|
1464
|
+
month=None, day=None):
|
|
1465
|
+
if month is None and day is None:
|
|
1466
|
+
if isinstance(first_arg, AbstractTime):
|
|
1467
|
+
first_arg = first_arg.ts
|
|
1468
|
+
elif isinstance(first_arg, (int, str)):
|
|
1469
|
+
first_arg = pd.Timestamp(first_arg)
|
|
1470
|
+
if isinstance(first_arg, (_datetime, pd.Timestamp, datetime)):
|
|
1471
|
+
first_arg = first_arg.date()
|
|
1472
|
+
self.ts = pd.Timestamp(first_arg) # remove hour, minutes and so on
|
|
1473
|
+
elif all((month, day)):
|
|
1474
|
+
self.ts = pd.Timestamp(first_arg, month, day)
|
|
1475
|
+
else:
|
|
1476
|
+
raise ValueError("Please specify three integers (year, month, day) "
|
|
1477
|
+
"or object or create date from (string, int timestamp, "
|
|
1478
|
+
"pandas.Timestamp, otp.datetime, otp.date, "
|
|
1479
|
+
"datetime.datetime, datetime.date)")
|
|
1480
|
+
|
|
1481
|
+
def __str__(self):
|
|
1482
|
+
return self.ts.strftime("%Y-%m-%d")
|
|
1483
|
+
|
|
1484
|
+
def __repr__(self):
|
|
1485
|
+
return self.ts.strftime("%Y-%m-%d")
|
|
1486
|
+
|
|
1487
|
+
def to_str(self, format="%Y%m%d"):
|
|
1488
|
+
"""
|
|
1489
|
+
Convert date to string, by default it will be in YYYYMMDD format.
|
|
1490
|
+
|
|
1491
|
+
Parameters
|
|
1492
|
+
----------
|
|
1493
|
+
format: str
|
|
1494
|
+
strftime format of string to convert to.
|
|
1495
|
+
Returns
|
|
1496
|
+
-------
|
|
1497
|
+
result: str
|
|
1498
|
+
"""
|
|
1499
|
+
return self.ts.strftime(format)
|
|
1500
|
+
|
|
1501
|
+
|
|
1502
|
+
class _integer_meta(type):
|
|
1503
|
+
def __str__(cls):
|
|
1504
|
+
return getattr(cls, '_NAME', cls.__name__)
|
|
1505
|
+
|
|
1506
|
+
@property
|
|
1507
|
+
def TYPE_SIZE(cls):
|
|
1508
|
+
return 8 * ctypes.sizeof(cls._CTYPE)
|
|
1509
|
+
|
|
1510
|
+
@property
|
|
1511
|
+
def MIN(cls):
|
|
1512
|
+
if cls._UNSIGNED:
|
|
1513
|
+
return 0
|
|
1514
|
+
else:
|
|
1515
|
+
return -(2 ** (cls.TYPE_SIZE - 1))
|
|
1516
|
+
|
|
1517
|
+
@property
|
|
1518
|
+
def MAX(cls):
|
|
1519
|
+
if cls._UNSIGNED:
|
|
1520
|
+
return (2 ** cls.TYPE_SIZE) - 1
|
|
1521
|
+
else:
|
|
1522
|
+
return (2 ** (cls.TYPE_SIZE - 1)) - 1
|
|
1523
|
+
|
|
1524
|
+
|
|
1525
|
+
class _integer(int, metaclass=_integer_meta):
|
|
1526
|
+
def __new__(cls, value, *args, **kwargs):
|
|
1527
|
+
if not cls.MIN <= value <= cls.MAX:
|
|
1528
|
+
raise ValueError(f"{cls.__name__} values must be between {cls.MIN} and {cls.MAX}")
|
|
1529
|
+
return super().__new__(cls, value, *args, **kwargs)
|
|
1530
|
+
|
|
1531
|
+
def __get_result(self, value):
|
|
1532
|
+
if isinstance(value, int):
|
|
1533
|
+
return self.__class__(self._CTYPE(value).value)
|
|
1534
|
+
return value
|
|
1535
|
+
|
|
1536
|
+
def __add__(self, other):
|
|
1537
|
+
return self.__get_result(
|
|
1538
|
+
super().__add__(other)
|
|
1539
|
+
)
|
|
1540
|
+
|
|
1541
|
+
def __radd__(self, other):
|
|
1542
|
+
return self.__get_result(
|
|
1543
|
+
super().__radd__(other)
|
|
1544
|
+
)
|
|
1545
|
+
|
|
1546
|
+
def __sub__(self, other):
|
|
1547
|
+
return self.__get_result(
|
|
1548
|
+
super().__sub__(other)
|
|
1549
|
+
)
|
|
1550
|
+
|
|
1551
|
+
def __rsub__(self, other):
|
|
1552
|
+
return self.__get_result(
|
|
1553
|
+
super().__rsub__(other)
|
|
1554
|
+
)
|
|
1555
|
+
|
|
1556
|
+
def __mul__(self, other):
|
|
1557
|
+
return self.__get_result(
|
|
1558
|
+
super().__mul__(other)
|
|
1559
|
+
)
|
|
1560
|
+
|
|
1561
|
+
def __rmul__(self, other):
|
|
1562
|
+
return self.__get_result(
|
|
1563
|
+
super().__rmul__(other)
|
|
1564
|
+
)
|
|
1565
|
+
|
|
1566
|
+
def __truediv__(self, other):
|
|
1567
|
+
return self.__get_result(
|
|
1568
|
+
super().__truediv__(other)
|
|
1569
|
+
)
|
|
1570
|
+
|
|
1571
|
+
def __rtruediv__(self, other):
|
|
1572
|
+
return self.__get_result(
|
|
1573
|
+
super().__rtruediv__(other)
|
|
1574
|
+
)
|
|
1575
|
+
|
|
1576
|
+
def __str__(self):
|
|
1577
|
+
return super().__repr__()
|
|
1578
|
+
|
|
1579
|
+
def __repr__(self):
|
|
1580
|
+
return f"{self.__class__.__name__}({self})"
|
|
1581
|
+
|
|
1582
|
+
|
|
1583
|
+
class long(_integer):
|
|
1584
|
+
"""
|
|
1585
|
+
OneTick data type representing signed long integer.
|
|
1586
|
+
|
|
1587
|
+
The size of the type is not specified and may vary across different systems.
|
|
1588
|
+
Most commonly it's a 8-byte type with allowed values from -2**63 to 2**63 - 1.
|
|
1589
|
+
|
|
1590
|
+
Note that the value is checked to be valid in constructor,
|
|
1591
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1592
|
+
|
|
1593
|
+
Examples
|
|
1594
|
+
--------
|
|
1595
|
+
>>> t = otp.Tick(A=otp.long(1))
|
|
1596
|
+
>>> t['B'] = otp.long(1) + 1
|
|
1597
|
+
>>> t.schema
|
|
1598
|
+
{'A': <class 'onetick.py.types.long'>, 'B': <class 'onetick.py.types.long'>}
|
|
1599
|
+
"""
|
|
1600
|
+
_CTYPE = ctypes.c_long
|
|
1601
|
+
_UNSIGNED = False
|
|
1602
|
+
|
|
1603
|
+
|
|
1604
|
+
class ulong(_integer):
|
|
1605
|
+
"""
|
|
1606
|
+
OneTick data type representing unsigned long integer.
|
|
1607
|
+
|
|
1608
|
+
The size of the type is not specified and may vary across different systems.
|
|
1609
|
+
Most commonly it's a 8-byte type with allowed values from 0 to 2**64 - 1.
|
|
1610
|
+
|
|
1611
|
+
Note that the value is checked to be valid in constructor,
|
|
1612
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1613
|
+
|
|
1614
|
+
Examples
|
|
1615
|
+
--------
|
|
1616
|
+
>>> t = otp.Tick(A=otp.ulong(1))
|
|
1617
|
+
>>> t['B'] = otp.ulong(1) + 1
|
|
1618
|
+
>>> t.schema
|
|
1619
|
+
{'A': <class 'onetick.py.types.ulong'>, 'B': <class 'onetick.py.types.ulong'>}
|
|
1620
|
+
|
|
1621
|
+
Note that arithmetic operations may result in overflow.
|
|
1622
|
+
Here we get 2**64 - 1 instead of -1.
|
|
1623
|
+
|
|
1624
|
+
.. testcode::
|
|
1625
|
+
:skipif: is_windows()
|
|
1626
|
+
|
|
1627
|
+
t = otp.Tick(A=otp.ulong(0) - 1)
|
|
1628
|
+
df = otp.run(t)
|
|
1629
|
+
print(df)
|
|
1630
|
+
|
|
1631
|
+
.. testoutput::
|
|
1632
|
+
|
|
1633
|
+
Time A
|
|
1634
|
+
0 2003-12-01 18446744073709551615
|
|
1635
|
+
"""
|
|
1636
|
+
_CTYPE = ctypes.c_ulong
|
|
1637
|
+
_UNSIGNED = True
|
|
1638
|
+
|
|
1639
|
+
|
|
1640
|
+
class _int(_integer):
|
|
1641
|
+
"""
|
|
1642
|
+
OneTick data type representing signed integer.
|
|
1643
|
+
|
|
1644
|
+
The size of the type is not specified and may vary across different systems.
|
|
1645
|
+
Most commonly it's a 4-byte type with allowed values from -2**31 to 2**31 - 1.
|
|
1646
|
+
|
|
1647
|
+
Note that the value is checked to be valid in constructor,
|
|
1648
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1649
|
+
|
|
1650
|
+
Examples
|
|
1651
|
+
--------
|
|
1652
|
+
>>> t = otp.Tick(A=otp.int(1))
|
|
1653
|
+
>>> t['B'] = otp.int(1) + 1
|
|
1654
|
+
>>> t.schema
|
|
1655
|
+
{'A': <class 'onetick.py.types._int'>, 'B': <class 'onetick.py.types._int'>}
|
|
1656
|
+
"""
|
|
1657
|
+
_CTYPE = ctypes.c_int
|
|
1658
|
+
_UNSIGNED = False
|
|
1659
|
+
_NAME = 'int'
|
|
1660
|
+
|
|
1661
|
+
|
|
1662
|
+
class uint(_integer):
|
|
1663
|
+
"""
|
|
1664
|
+
OneTick data type representing unsigned integer.
|
|
1665
|
+
|
|
1666
|
+
The size of the type is not specified and may vary across different systems.
|
|
1667
|
+
Most commonly it's a 4-byte type with allowed values from 0 to 2**32 - 1.
|
|
1668
|
+
|
|
1669
|
+
Note that the value is checked to be valid in constructor,
|
|
1670
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1671
|
+
|
|
1672
|
+
Examples
|
|
1673
|
+
--------
|
|
1674
|
+
>>> t = otp.Tick(A=otp.uint(1))
|
|
1675
|
+
>>> t['B'] = otp.uint(1) + 1
|
|
1676
|
+
>>> t.schema
|
|
1677
|
+
{'A': <class 'onetick.py.types.uint'>, 'B': <class 'onetick.py.types.uint'>}
|
|
1678
|
+
|
|
1679
|
+
Note that arithmetic operations may result in overflow.
|
|
1680
|
+
Here we get 2**32 - 1 instead of -1.
|
|
1681
|
+
|
|
1682
|
+
.. testcode::
|
|
1683
|
+
:skipif: is_windows()
|
|
1684
|
+
|
|
1685
|
+
t = otp.Tick(A=otp.uint(0) - 1)
|
|
1686
|
+
df = otp.run(t)
|
|
1687
|
+
print(df)
|
|
1688
|
+
|
|
1689
|
+
.. testoutput::
|
|
1690
|
+
|
|
1691
|
+
Time A
|
|
1692
|
+
0 2003-12-01 4294967295
|
|
1693
|
+
"""
|
|
1694
|
+
_CTYPE = ctypes.c_uint
|
|
1695
|
+
_UNSIGNED = True
|
|
1696
|
+
|
|
1697
|
+
|
|
1698
|
+
class byte(_integer):
|
|
1699
|
+
"""
|
|
1700
|
+
OneTick data type representing byte integer.
|
|
1701
|
+
|
|
1702
|
+
The size of the type is not specified and may vary across different systems.
|
|
1703
|
+
Most commonly it's a 1-byte type with allowed values from -128 to 127.
|
|
1704
|
+
|
|
1705
|
+
Note that the value is checked to be valid in constructor,
|
|
1706
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1707
|
+
|
|
1708
|
+
Examples
|
|
1709
|
+
--------
|
|
1710
|
+
>>> t = otp.Tick(A=otp.byte(1))
|
|
1711
|
+
>>> t['B'] = otp.byte(1) + 1
|
|
1712
|
+
>>> t.schema
|
|
1713
|
+
{'A': <class 'onetick.py.types.byte'>, 'B': <class 'onetick.py.types.byte'>}
|
|
1714
|
+
|
|
1715
|
+
Note that arithmetic operations may result in overflow.
|
|
1716
|
+
Here we get 127 instead of -129.
|
|
1717
|
+
|
|
1718
|
+
>>> t = otp.Tick(A=otp.byte(-128) - 1)
|
|
1719
|
+
>>> otp.run(t)
|
|
1720
|
+
Time A
|
|
1721
|
+
0 2003-12-01 127
|
|
1722
|
+
"""
|
|
1723
|
+
_CTYPE = ctypes.c_byte
|
|
1724
|
+
_UNSIGNED = False
|
|
1725
|
+
|
|
1726
|
+
|
|
1727
|
+
class short(_integer):
|
|
1728
|
+
"""
|
|
1729
|
+
OneTick data type representing short integer.
|
|
1730
|
+
|
|
1731
|
+
The size of the type is not specified and may vary across different systems.
|
|
1732
|
+
Most commonly it's a 2-byte type with allowed values from -32768 to 32767.
|
|
1733
|
+
|
|
1734
|
+
Note that the value is checked to be valid in constructor,
|
|
1735
|
+
but no overflow checking is done when arithmetic operations are performed.
|
|
1736
|
+
|
|
1737
|
+
Examples
|
|
1738
|
+
--------
|
|
1739
|
+
>>> t = otp.Tick(A=otp.short(1))
|
|
1740
|
+
>>> t['B'] = otp.short(1) + 1
|
|
1741
|
+
>>> t.schema
|
|
1742
|
+
{'A': <class 'onetick.py.types.short'>, 'B': <class 'onetick.py.types.short'>}
|
|
1743
|
+
|
|
1744
|
+
Note that arithmetic operations may result in overflow.
|
|
1745
|
+
Here we get 32767 instead of -32769.
|
|
1746
|
+
|
|
1747
|
+
>>> t = otp.Tick(A=otp.short(-32768) - 1)
|
|
1748
|
+
>>> otp.run(t)
|
|
1749
|
+
Time A
|
|
1750
|
+
0 2003-12-01 32767
|
|
1751
|
+
"""
|
|
1752
|
+
_CTYPE = ctypes.c_short
|
|
1753
|
+
_UNSIGNED = False
|
|
1754
|
+
|
|
1755
|
+
|
|
1756
|
+
# ------------------- #
|
|
1757
|
+
def type2str(t):
|
|
1758
|
+
if t is int:
|
|
1759
|
+
return "long"
|
|
1760
|
+
if t is str:
|
|
1761
|
+
return "string"
|
|
1762
|
+
if t is float:
|
|
1763
|
+
return "double"
|
|
1764
|
+
if t is None:
|
|
1765
|
+
return ''
|
|
1766
|
+
if t is decimal:
|
|
1767
|
+
return t._to_onetick_type_string()
|
|
1768
|
+
return str(t)
|
|
1769
|
+
|
|
1770
|
+
|
|
1771
|
+
def str2type(type_name: str):
|
|
1772
|
+
"""
|
|
1773
|
+
Converts OneTick type by its name into Python/OTP domain type.
|
|
1774
|
+
|
|
1775
|
+
Parameters
|
|
1776
|
+
----------
|
|
1777
|
+
type_name: str
|
|
1778
|
+
name of type from CSV or OneTick DB
|
|
1779
|
+
|
|
1780
|
+
Returns
|
|
1781
|
+
-------
|
|
1782
|
+
class:
|
|
1783
|
+
Python/OTP type representing OneTick type
|
|
1784
|
+
"""
|
|
1785
|
+
if type_name == "time32":
|
|
1786
|
+
return int
|
|
1787
|
+
if type_name == "long":
|
|
1788
|
+
# otp.long can be used too, but we use int for backward compatibility
|
|
1789
|
+
return int
|
|
1790
|
+
if type_name == "int":
|
|
1791
|
+
return _int
|
|
1792
|
+
if type_name == "byte":
|
|
1793
|
+
return byte
|
|
1794
|
+
if type_name == "short":
|
|
1795
|
+
return short
|
|
1796
|
+
if type_name == "uint":
|
|
1797
|
+
return uint
|
|
1798
|
+
if type_name == "ulong":
|
|
1799
|
+
return ulong
|
|
1800
|
+
elif type_name in ["double", "float"]:
|
|
1801
|
+
return float
|
|
1802
|
+
elif type_name == "decimal":
|
|
1803
|
+
return decimal
|
|
1804
|
+
elif type_name == "msectime":
|
|
1805
|
+
return msectime
|
|
1806
|
+
elif type_name == "nsectime":
|
|
1807
|
+
return nsectime
|
|
1808
|
+
elif type_name in ["string", "matrix", f"string[{string.DEFAULT_LENGTH}]"]:
|
|
1809
|
+
return str
|
|
1810
|
+
elif type_name == "varstring":
|
|
1811
|
+
return varstring
|
|
1812
|
+
elif type_name.find("string") != -1:
|
|
1813
|
+
length = int(type_name[type_name.find("[") + 1:type_name.find("]")])
|
|
1814
|
+
return string[length]
|
|
1815
|
+
return None
|
|
1816
|
+
|
|
1817
|
+
|
|
1818
|
+
def type2np(t):
|
|
1819
|
+
if issubclass(t, str):
|
|
1820
|
+
if issubclass(t, otp.string) and isinstance(t.length, int):
|
|
1821
|
+
return '<U' + str(t.length)
|
|
1822
|
+
return '<U64'
|
|
1823
|
+
elif issubclass(t, bool):
|
|
1824
|
+
return 'boolean'
|
|
1825
|
+
elif issubclass(t, nsectime):
|
|
1826
|
+
return 'datetime64[ns]'
|
|
1827
|
+
elif issubclass(t, msectime):
|
|
1828
|
+
return 'datetime64[ms]'
|
|
1829
|
+
elif issubclass(t, datetime):
|
|
1830
|
+
return 'datetime64[ns]'
|
|
1831
|
+
elif issubclass(t, byte):
|
|
1832
|
+
if otq.webapi:
|
|
1833
|
+
return 'int8'
|
|
1834
|
+
return 'int32'
|
|
1835
|
+
elif issubclass(t, short):
|
|
1836
|
+
if otq.webapi:
|
|
1837
|
+
return 'int16'
|
|
1838
|
+
return 'int32'
|
|
1839
|
+
elif issubclass(t, uint):
|
|
1840
|
+
return 'uint32'
|
|
1841
|
+
elif issubclass(t, ulong):
|
|
1842
|
+
return 'uint64'
|
|
1843
|
+
elif issubclass(t, _int):
|
|
1844
|
+
return 'int32'
|
|
1845
|
+
elif issubclass(t, long):
|
|
1846
|
+
return 'int64'
|
|
1847
|
+
elif issubclass(t, int):
|
|
1848
|
+
return 'int64'
|
|
1849
|
+
elif issubclass(t, float):
|
|
1850
|
+
return 'float64'
|
|
1851
|
+
elif issubclass(t, decimal):
|
|
1852
|
+
return 'float64'
|
|
1853
|
+
else:
|
|
1854
|
+
return np.dtype(t)
|
|
1855
|
+
|
|
1856
|
+
|
|
1857
|
+
# TODO: move this union of types to some common place
|
|
1858
|
+
def datetime2expr(
|
|
1859
|
+
dt_obj: Union[_datetime, _date, pd.Timestamp, date, datetime],
|
|
1860
|
+
timezone: Optional[str] = None,
|
|
1861
|
+
timezone_naive: Optional[str] = None,
|
|
1862
|
+
) -> str:
|
|
1863
|
+
"""
|
|
1864
|
+
Convert python datetime values to OneTick string representation.
|
|
1865
|
+
If ``dt_obj`` is timezone-aware then timezone will be taken from ``dt_obj`` value.
|
|
1866
|
+
If ``dt_obj`` is timezone-naive then timezone specified with otp.config['tz'] or otp.run() will be used.
|
|
1867
|
+
|
|
1868
|
+
Parameters
|
|
1869
|
+
----------
|
|
1870
|
+
dt_obj
|
|
1871
|
+
date or datetime value
|
|
1872
|
+
timezone: str or Operation
|
|
1873
|
+
This timezone will be used unconditionally.
|
|
1874
|
+
timezone_naive: str or Operation
|
|
1875
|
+
This timezone will be used if ``dt_obj`` is timezone-naive.
|
|
1876
|
+
"""
|
|
1877
|
+
dt_str = _format_datetime(dt_obj, '%Y-%m-%d %H:%M:%S.%f', add_nano_suffix=True)
|
|
1878
|
+
if timezone is None:
|
|
1879
|
+
timezone = get_timezone_from_datetime(dt_obj)
|
|
1880
|
+
if timezone is None:
|
|
1881
|
+
timezone = timezone_naive
|
|
1882
|
+
if not isinstance(timezone, otp.Operation):
|
|
1883
|
+
timezone = f'"{timezone}"' if timezone else '_TIMEZONE'
|
|
1884
|
+
return f'PARSE_NSECTIME("%Y-%m-%d %H:%M:%S.%J", "{dt_str}", {str(timezone)})'
|
|
1885
|
+
|
|
1886
|
+
|
|
1887
|
+
def datetime2timeval(dt_obj: Union[_datetime, _date, pd.Timestamp, date, datetime], timezone: str = 'GMT'):
|
|
1888
|
+
"""
|
|
1889
|
+
Get nanosecond-precision pyomd.timeval_t
|
|
1890
|
+
from different datetime types supported by onetick-py.
|
|
1891
|
+
|
|
1892
|
+
If ``dt_obj`` is timezone-aware, then its timezone will be used.
|
|
1893
|
+
If ``dt_obj`` is timezone-naive , then it will be localized to ``timezone`` parameter (GMT by default).
|
|
1894
|
+
"""
|
|
1895
|
+
dt_str = _format_datetime(dt_obj, '%Y-%m-%d %H:%M:%S.%f', add_nano_suffix=True)
|
|
1896
|
+
tz_str = get_timezone_from_datetime(dt_obj)
|
|
1897
|
+
if tz_str:
|
|
1898
|
+
# use timezone from the object
|
|
1899
|
+
return pyomd.TimeParser('%Y-%m-%d %H:%M:%S.%J', tz_str).parse_time(dt_str)
|
|
1900
|
+
else:
|
|
1901
|
+
# localize to the timezone specified in fucntion parameter
|
|
1902
|
+
return pyomd.TimeParser('%Y-%m-%d %H:%M:%S.%J', timezone).parse_time(dt_str)
|
|
1903
|
+
|
|
1904
|
+
|
|
1905
|
+
def _format_datetime(dt_obj, fmt, add_nano_suffix=True):
|
|
1906
|
+
dt_str = dt_obj.strftime(fmt)
|
|
1907
|
+
if add_nano_suffix:
|
|
1908
|
+
if isinstance(dt_obj, (pd.Timestamp, datetime)):
|
|
1909
|
+
dt_str += f'{dt_obj.nanosecond:03}'[-3:]
|
|
1910
|
+
else:
|
|
1911
|
+
dt_str += '000'
|
|
1912
|
+
return dt_str
|
|
1913
|
+
|
|
1914
|
+
|
|
1915
|
+
def value2str(v):
|
|
1916
|
+
"""
|
|
1917
|
+
Converts a python value from the `v` parameter into OneTick format.
|
|
1918
|
+
"""
|
|
1919
|
+
if issubclass(type(v), str):
|
|
1920
|
+
# there is no escape, so replacing double quotes with concatenation with it
|
|
1921
|
+
return '"' + str(v).replace('"', '''"+'"'+"''') + '"'
|
|
1922
|
+
|
|
1923
|
+
if isinstance(v, decimal):
|
|
1924
|
+
return v._to_onetick_string()
|
|
1925
|
+
|
|
1926
|
+
if isinstance(v, float) and not (isinstance(v, (_inf, _nan))):
|
|
1927
|
+
# PY-286: support science notation
|
|
1928
|
+
s = str(v)
|
|
1929
|
+
if "e" in s:
|
|
1930
|
+
return f'atof({value2str(s)})'
|
|
1931
|
+
if s == "nan":
|
|
1932
|
+
return str(nan)
|
|
1933
|
+
return s
|
|
1934
|
+
|
|
1935
|
+
if is_time_type(v):
|
|
1936
|
+
return datetime2expr(v)
|
|
1937
|
+
|
|
1938
|
+
if isinstance(v, nsectime):
|
|
1939
|
+
# we do not need the same for msectime because it works as is
|
|
1940
|
+
if int(v) == 0 or int(v) > 15e12: # it is 2445/5/1
|
|
1941
|
+
return f'NSECTIME({v})'
|
|
1942
|
+
# This branch is for backward compatibility. Originally here was a bug that
|
|
1943
|
+
# allowed to pass only milliseconds as a value into the otp.nsectime constructor.
|
|
1944
|
+
# Obviously we expect there only nanoseconds, and the built-in NSECTIME works only
|
|
1945
|
+
# with nanoseconds.
|
|
1946
|
+
warnings.warn('It seems that you are using number of milliseconds as nanoseconds. ', stacklevel=2)
|
|
1947
|
+
|
|
1948
|
+
return str(v)
|
|
1949
|
+
|
|
1950
|
+
|
|
1951
|
+
# TODO: maybe can be removed, it is used only in tests now
|
|
1952
|
+
def time2nsectime(time, timezone=None):
|
|
1953
|
+
"""
|
|
1954
|
+
Converts complex time types to nsectime timestamp.
|
|
1955
|
+
|
|
1956
|
+
Parameters
|
|
1957
|
+
----------
|
|
1958
|
+
time: :py:class:`datetime.datetime`, :py:class:`datetime.date`,\
|
|
1959
|
+
:py:class:`otp.datetime <onetick.py.datetime>`, :py:class:`otp.date <onetick.py.date>`, pandas.Timestamp
|
|
1960
|
+
time to convert
|
|
1961
|
+
timezone:
|
|
1962
|
+
convert timezone before nsectime calculation
|
|
1963
|
+
|
|
1964
|
+
Returns
|
|
1965
|
+
-------
|
|
1966
|
+
result: int
|
|
1967
|
+
number of nanoseconds since epoch
|
|
1968
|
+
"""
|
|
1969
|
+
if isinstance(time, (_datetime, _date)):
|
|
1970
|
+
time = pd.Timestamp(time)
|
|
1971
|
+
elif isinstance(time, date):
|
|
1972
|
+
time = datetime(time)
|
|
1973
|
+
if timezone:
|
|
1974
|
+
if not has_timezone_parameter(): # accommodating legacy behavior prior to 20220327-3 weekly build
|
|
1975
|
+
time = time.replace(tzinfo=None)
|
|
1976
|
+
else:
|
|
1977
|
+
if time.tzinfo is None:
|
|
1978
|
+
time = time.tz_localize(timezone)
|
|
1979
|
+
else:
|
|
1980
|
+
# timezone conversion doesn't change the offset from epoch, only string representation,
|
|
1981
|
+
# so time.value (the number of nanoseconds) will stay the same
|
|
1982
|
+
# this line can be deleted
|
|
1983
|
+
time = time.tz_convert(timezone)
|
|
1984
|
+
return time.value
|
|
1985
|
+
|
|
1986
|
+
|
|
1987
|
+
def is_time_type(time):
|
|
1988
|
+
""" Returns true if argument is subclass of any time type
|
|
1989
|
+
|
|
1990
|
+
Checks if pass type is time type, currently checks for otp.date, otp.datetime,
|
|
1991
|
+
pd.Timestamp, datetime.date, datetime.datetime
|
|
1992
|
+
|
|
1993
|
+
Parameters
|
|
1994
|
+
----------
|
|
1995
|
+
time:
|
|
1996
|
+
object or type of the object
|
|
1997
|
+
|
|
1998
|
+
Returns
|
|
1999
|
+
-------
|
|
2000
|
+
result: bool
|
|
2001
|
+
Return true if argument is time type
|
|
2002
|
+
|
|
2003
|
+
Examples
|
|
2004
|
+
--------
|
|
2005
|
+
|
|
2006
|
+
>>> is_time_type(datetime.datetime) # OTdirective: skip-example: ;
|
|
2007
|
+
True
|
|
2008
|
+
>>> is_time_type(type(5)) # OTdirective: skip-example: ;
|
|
2009
|
+
False
|
|
2010
|
+
>>> is_time_type(datetime.datetime(2019, 1, 1)) # OTdirective: snippet-name: types.is time;
|
|
2011
|
+
True
|
|
2012
|
+
"""
|
|
2013
|
+
time = time if inspect.isclass(time) else type(time)
|
|
2014
|
+
# do not check for datetime.datetime and pd.Timestamp, because they are in the same hierarchy
|
|
2015
|
+
# datetime.date -> datetime.datetime -> pd.Timestamp, where `->` means base class
|
|
2016
|
+
return issubclass(time, (_date, datetime, date))
|
|
2017
|
+
|
|
2018
|
+
|
|
2019
|
+
def next_day(dt_obj: Union[_date, _datetime, date, datetime, pd.Timestamp]) -> _datetime:
|
|
2020
|
+
"""
|
|
2021
|
+
Return the start of the next day of ``dt_obj`` as timezone-naive :py:class:`datetime.datetime`.
|
|
2022
|
+
|
|
2023
|
+
Next day in this case means simply incrementing day/month/year number,
|
|
2024
|
+
not adding 24 hours (which may return the same date on DST days).
|
|
2025
|
+
"""
|
|
2026
|
+
return _datetime(dt_obj.year, dt_obj.month, dt_obj.day) + _timedelta(days=1)
|
|
2027
|
+
|
|
2028
|
+
|
|
2029
|
+
def default_by_type(dtype):
|
|
2030
|
+
"""
|
|
2031
|
+
Get default value by OneTick type.
|
|
2032
|
+
|
|
2033
|
+
Parameters
|
|
2034
|
+
----------
|
|
2035
|
+
dtype:
|
|
2036
|
+
one of onetick-py base types
|
|
2037
|
+
|
|
2038
|
+
Examples
|
|
2039
|
+
--------
|
|
2040
|
+
>>> otp.default_by_type(float)
|
|
2041
|
+
nan
|
|
2042
|
+
>>> otp.default_by_type(otp.decimal)
|
|
2043
|
+
decimal(0)
|
|
2044
|
+
>>> otp.default_by_type(int)
|
|
2045
|
+
0
|
|
2046
|
+
>>> otp.default_by_type(otp.ulong)
|
|
2047
|
+
ulong(0)
|
|
2048
|
+
>>> otp.default_by_type(otp.uint)
|
|
2049
|
+
uint(0)
|
|
2050
|
+
>>> otp.default_by_type(otp.short)
|
|
2051
|
+
short(0)
|
|
2052
|
+
>>> otp.default_by_type(otp.byte)
|
|
2053
|
+
byte(0)
|
|
2054
|
+
>>> otp.default_by_type(otp.nsectime)
|
|
2055
|
+
nsectime(0)
|
|
2056
|
+
>>> otp.default_by_type(otp.msectime)
|
|
2057
|
+
msectime(0)
|
|
2058
|
+
>>> otp.default_by_type(str)
|
|
2059
|
+
''
|
|
2060
|
+
>>> otp.default_by_type(otp.string)
|
|
2061
|
+
string('')
|
|
2062
|
+
>>> otp.default_by_type(otp.string[123])
|
|
2063
|
+
string[123]('')
|
|
2064
|
+
>>> otp.default_by_type(otp.varstring)
|
|
2065
|
+
varstring('')
|
|
2066
|
+
"""
|
|
2067
|
+
# TODO: think if we want to treat bool as basic onetick type
|
|
2068
|
+
if dtype is bool:
|
|
2069
|
+
return 0
|
|
2070
|
+
if not is_type_basic(dtype):
|
|
2071
|
+
raise TypeError(f"Can't get default value for type: {dtype}")
|
|
2072
|
+
if issubclass(dtype, int):
|
|
2073
|
+
return dtype(0)
|
|
2074
|
+
if dtype is otp.decimal:
|
|
2075
|
+
return otp.decimal(0)
|
|
2076
|
+
if issubclass(dtype, float):
|
|
2077
|
+
return nan
|
|
2078
|
+
if issubclass(dtype, str):
|
|
2079
|
+
return dtype('')
|
|
2080
|
+
if issubclass(dtype, nsectime) or issubclass(dtype, msectime):
|
|
2081
|
+
return dtype(0)
|
|
2082
|
+
raise TypeError(f"Can't get default value for type: {dtype}")
|
|
2083
|
+
|
|
2084
|
+
|
|
2085
|
+
class timedelta(pd.Timedelta):
|
|
2086
|
+
"""
|
|
2087
|
+
The object representing the delta between timestamps.
|
|
2088
|
+
|
|
2089
|
+
Parameters
|
|
2090
|
+
----------
|
|
2091
|
+
value: :py:class:`otp.timedelta <onetick.py.timedelta>`, :pandas:`pandas.Timedelta`,\
|
|
2092
|
+
:py:class:`datetime.timedelta`, str, or int
|
|
2093
|
+
Initialize this object from other types of objects.
|
|
2094
|
+
kwargs:
|
|
2095
|
+
Dictionary of offset names and their values.
|
|
2096
|
+
Available offset names:
|
|
2097
|
+
*weeks*, *days*, *hours*, *minutes*, *seconds*,
|
|
2098
|
+
*milliseconds*, *microseconds*, *nanoseconds*.
|
|
2099
|
+
|
|
2100
|
+
Examples
|
|
2101
|
+
--------
|
|
2102
|
+
|
|
2103
|
+
Create :py:class:`otp.timedelta <onetick.py.timedelta>` from key-value arguments:
|
|
2104
|
+
|
|
2105
|
+
>>> otp.timedelta(weeks=1, days=1, hours=1, minutes=1, seconds=1, milliseconds=1, microseconds=1, nanoseconds=1)
|
|
2106
|
+
timedelta('8 days 01:01:01.001001001')
|
|
2107
|
+
|
|
2108
|
+
Create :py:class:`otp.timedelta <onetick.py.timedelta>` from different types of objects:
|
|
2109
|
+
|
|
2110
|
+
>>> otp.timedelta(datetime.timedelta(days=2, hours=3))
|
|
2111
|
+
timedelta('2 days 03:00:00')
|
|
2112
|
+
|
|
2113
|
+
>>> otp.timedelta('20 days 13:02:01.999777666')
|
|
2114
|
+
timedelta('20 days 13:02:01.999777666')
|
|
2115
|
+
|
|
2116
|
+
Adding :py:class:`otp.timedelta <onetick.py.timedelta>` object to :py:class:`otp.datetime <onetick.py.datetime>`:
|
|
2117
|
+
|
|
2118
|
+
>>> otp.datetime(2022, 1, 1, 1, 2, 3) + otp.timedelta(days=1, hours=1, minutes=1, seconds=1)
|
|
2119
|
+
2022-01-02 02:03:04
|
|
2120
|
+
|
|
2121
|
+
Adding :py:class:`otp.timedelta <onetick.py.timedelta>` object to :py:class:`otp.date <onetick.py.date>`:
|
|
2122
|
+
|
|
2123
|
+
>>> otp.date(2022, 1, 1) + otp.timedelta(weeks=1, nanoseconds=1)
|
|
2124
|
+
2022-01-08 00:00:00.000000001
|
|
2125
|
+
"""
|
|
2126
|
+
|
|
2127
|
+
def __repr__(self):
|
|
2128
|
+
return super().__repr__().lower()
|
|
2129
|
+
|
|
2130
|
+
def _get_offset(self):
|
|
2131
|
+
return self.value, 'nanosecond'
|