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,325 @@
|
|
|
1
|
+
from functools import partial
|
|
2
|
+
|
|
3
|
+
import pandas as pd
|
|
4
|
+
|
|
5
|
+
import onetick.py as otp
|
|
6
|
+
from onetick.py.otq import otq
|
|
7
|
+
|
|
8
|
+
from onetick.py import utils
|
|
9
|
+
from onetick.py.sources.data_source import _start_doc, _end_doc, _symbol_doc
|
|
10
|
+
from onetick.py.docs.utils import docstring, param_doc
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
COMMON_SOURCE_DOC_PARAMS = [_start_doc, _end_doc, _symbol_doc]
|
|
14
|
+
OQD_TICK_TYPE = 'OQD::*'
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _modify_query_times(src):
|
|
18
|
+
src.sink(otq.ModifyQueryTimes(
|
|
19
|
+
start_time=('parse_time("%Y%m%d %H:%M:%S.%q", '
|
|
20
|
+
'time_format("%Y%m%d", _START_TIME, _TIMEZONE) + " 00:00:00.000", "GMT")'),
|
|
21
|
+
end_time=('parse_time("%Y%m%d %H:%M:%S.%q", '
|
|
22
|
+
'time_format("%Y%m%d", _END_TIME, _TIMEZONE) + " 24:00:00.000", "GMT")'),
|
|
23
|
+
output_timestamp='min(max(TIMESTAMP,_START_TIME),_END_TIME)'
|
|
24
|
+
))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
_exch_doc = param_doc(
|
|
28
|
+
name='exch',
|
|
29
|
+
desc="""
|
|
30
|
+
The OneQuantData exchange code for the desired price series. Possible values:
|
|
31
|
+
|
|
32
|
+
- 'all'
|
|
33
|
+
return data for all exchanges;
|
|
34
|
+
|
|
35
|
+
- 'main'
|
|
36
|
+
return data main pricing exchange;
|
|
37
|
+
|
|
38
|
+
- any other string value will treated as exchange name to filter data.
|
|
39
|
+
|
|
40
|
+
Default: 'all'.
|
|
41
|
+
""",
|
|
42
|
+
str_annotation="str, 'all', 'main'",
|
|
43
|
+
default='all',
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
class OHLCV(otp.Source):
|
|
48
|
+
@docstring(parameters=[_exch_doc] + COMMON_SOURCE_DOC_PARAMS, add_self=True)
|
|
49
|
+
def __init__(
|
|
50
|
+
self,
|
|
51
|
+
exch='all',
|
|
52
|
+
symbol=utils.adaptive,
|
|
53
|
+
start=utils.adaptive,
|
|
54
|
+
end=utils.adaptive,
|
|
55
|
+
**kwargs
|
|
56
|
+
):
|
|
57
|
+
"""
|
|
58
|
+
OneQuantData™ source to retrieve a time series of unadjusted
|
|
59
|
+
prices for a symbol for one particular pricing exchange of daily OHLCV data.
|
|
60
|
+
Output ticks have fields: OPEN, HIGH, LOW, CLOSE, VOLUME, CURRENCY, EXCH.
|
|
61
|
+
|
|
62
|
+
Examples
|
|
63
|
+
--------
|
|
64
|
+
>>> src = otp.oqd.sources.OHLCV(exch="USPRIM") # doctest: +SKIP
|
|
65
|
+
>>> otp.run(src, # doctest: +SKIP
|
|
66
|
+
... symbols='BTKR::::GOOGL US',
|
|
67
|
+
... start=otp.dt(2018, 8, 1),
|
|
68
|
+
... end=otp.dt(2018, 8, 2),
|
|
69
|
+
... symbol_date=otp.dt(2018, 8, 1))
|
|
70
|
+
Time OID EXCH CURRENCY OPEN HIGH LOW CLOSE VOLUME
|
|
71
|
+
0 2018-08-01 00:00:00 74143 USPRIM USD 1242.73 1245.72 1225.00 1232.99 605680.0
|
|
72
|
+
1 2018-08-01 20:00:00 74143 USPRIM USD 1219.69 1244.25 1218.06 1241.13 596960.0
|
|
73
|
+
"""
|
|
74
|
+
if self._try_default_constructor(**kwargs):
|
|
75
|
+
return
|
|
76
|
+
|
|
77
|
+
super().__init__(
|
|
78
|
+
_symbols=symbol,
|
|
79
|
+
_start=start,
|
|
80
|
+
_end=end,
|
|
81
|
+
_base_ep_func=partial(self.build, exch=exch)
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
self.schema.set(OID=str,
|
|
85
|
+
EXCH=str,
|
|
86
|
+
CURRENCY=str,
|
|
87
|
+
OPEN=float,
|
|
88
|
+
HIGH=float,
|
|
89
|
+
LOW=float,
|
|
90
|
+
CLOSE=float,
|
|
91
|
+
VOLUME=float)
|
|
92
|
+
|
|
93
|
+
def build(self, exch):
|
|
94
|
+
ep = None
|
|
95
|
+
if exch == 'all':
|
|
96
|
+
ep = otp.oqd.eps.OqdSourceDprcAll()
|
|
97
|
+
elif exch == 'main':
|
|
98
|
+
ep = otp.oqd.eps.OqdSourceDprcMain()
|
|
99
|
+
else:
|
|
100
|
+
ep = otp.oqd.eps.OqdSourceDprcExch(exch=exch)
|
|
101
|
+
|
|
102
|
+
src = otp.Source(ep)
|
|
103
|
+
src.tick_type(OQD_TICK_TYPE)
|
|
104
|
+
_modify_query_times(src)
|
|
105
|
+
return src
|
|
106
|
+
|
|
107
|
+
|
|
108
|
+
class CorporateActions(otp.Source):
|
|
109
|
+
"""
|
|
110
|
+
OneQuantData™ source EP to retrieve a time series of corporate
|
|
111
|
+
actions for a symbol.
|
|
112
|
+
|
|
113
|
+
This source will return all corporate action fields available for a symbol
|
|
114
|
+
with EX-Dates between the query start time and end time. The
|
|
115
|
+
timestamp of the series is equal to the EX-Date of the corporate
|
|
116
|
+
action with a time of 0:00:00 GMT.
|
|
117
|
+
|
|
118
|
+
Examples
|
|
119
|
+
--------
|
|
120
|
+
>>> src = otp.oqd.sources.CorporateActions() # doctest: +SKIP
|
|
121
|
+
>>> otp.run(src, # doctest: +SKIP
|
|
122
|
+
... symbols='TDEQ::::AAPL',
|
|
123
|
+
... start=otp.dt(2021, 1, 1),
|
|
124
|
+
... end=otp.dt(2021, 8, 6),
|
|
125
|
+
... symbol_date=otp.dt(2021, 2, 18),
|
|
126
|
+
... timezone='GMT')
|
|
127
|
+
Time OID ACTION_ID ACTION_TYPE ACTION_ADJUST ACTION_CURRENCY ANN_DATE EX_DATE PAY_DATE REC_DATE\
|
|
128
|
+
TERM_NOTE TERM_RECORD_TYPE ACTION_STATUS
|
|
129
|
+
0 2021-02-05 9706 16799540 CASH_DIVIDEND 0.205 USD 20210127 20210205 20210211 20210208\
|
|
130
|
+
CASH:0.205@USD NORMAL
|
|
131
|
+
1 2021-05-07 9706 17098817 CASH_DIVIDEND 0.220 USD 20210428 20210507 20210513 20210510\
|
|
132
|
+
CASH:0.22@USD NORMAL
|
|
133
|
+
2 2021-08-06 9706 17331864 CASH_DIVIDEND 0.220 USD 20210727 20210806 20210812 20210809\
|
|
134
|
+
CASH:0.22@USD NORMAL
|
|
135
|
+
|
|
136
|
+
"""
|
|
137
|
+
|
|
138
|
+
@docstring(parameters=COMMON_SOURCE_DOC_PARAMS, add_self=True)
|
|
139
|
+
def __init__(
|
|
140
|
+
self,
|
|
141
|
+
symbol=utils.adaptive,
|
|
142
|
+
start=utils.adaptive,
|
|
143
|
+
end=utils.adaptive,
|
|
144
|
+
**kwargs
|
|
145
|
+
):
|
|
146
|
+
if self._try_default_constructor(**kwargs):
|
|
147
|
+
return
|
|
148
|
+
|
|
149
|
+
super().__init__(
|
|
150
|
+
_symbols=symbol,
|
|
151
|
+
_start=start,
|
|
152
|
+
_end=end,
|
|
153
|
+
_base_ep_func=partial(self.build)
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
self.schema.set(OID=str,
|
|
157
|
+
ACTION_ID=int,
|
|
158
|
+
ACTION_TYPE=str,
|
|
159
|
+
ACTION_ADJUST=float,
|
|
160
|
+
ACTION_CURRENCY=str,
|
|
161
|
+
ANN_DATE=int,
|
|
162
|
+
EX_DATE=int,
|
|
163
|
+
PAY_DATE=int,
|
|
164
|
+
REC_DATE=int,
|
|
165
|
+
TERM_NOTE=str,
|
|
166
|
+
TERM_RECORD_TYPE=str,
|
|
167
|
+
ACTION_STATUS=str)
|
|
168
|
+
|
|
169
|
+
def build(self):
|
|
170
|
+
ep = otp.oqd.eps.OqdSourceCacs()
|
|
171
|
+
src = otp.Source(ep)
|
|
172
|
+
src.tick_type(OQD_TICK_TYPE)
|
|
173
|
+
_modify_query_times(src)
|
|
174
|
+
return src
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class DescriptiveFields(otp.Source):
|
|
178
|
+
"""OneQuantData™ source to retrieve a time series of descriptive fields for a symbol.
|
|
179
|
+
There will only be ticks on days when some field in the descriptive data changes.
|
|
180
|
+
Output ticks will have fields:
|
|
181
|
+
OID, END_DATE, COUNTRY, EXCH, NAME,
|
|
182
|
+
ISSUE_DESC, ISSUE_CLASS, ISSUE_TYPE, ISSUE_STATUS,
|
|
183
|
+
SIC_CODE, IDSYM, TICKER, CALENDAR.
|
|
184
|
+
|
|
185
|
+
Note: currently actual fields have 9999 year in END_DATE, but it could not fit the
|
|
186
|
+
nanosecond timestamp, so it is replaced with 2035-01-01 date.
|
|
187
|
+
|
|
188
|
+
Examples
|
|
189
|
+
--------
|
|
190
|
+
>>> src = otp.oqd.sources.DescriptiveFields() # doctest: +SKIP
|
|
191
|
+
>>> otp.run(src, # doctest: +SKIP
|
|
192
|
+
... symbols='1000001589',
|
|
193
|
+
... start=otp.dt(2020, 3, 1),
|
|
194
|
+
... end=otp.dt(2023, 3, 2),
|
|
195
|
+
... timezone='GMT').iloc[:6]
|
|
196
|
+
Time OID END_DATE COUNTRY EXCH NAME ISSUE_DESC\
|
|
197
|
+
ISSUE_CLASS ISSUE_TYPE ISSUE_STATUS SIC_CODE IDSYM TICKER CALENDAR
|
|
198
|
+
0 2020-03-01 1000001589 2020-03-23 LUX EL^X INVESTEC GLOBAL ST EUROPEAN HIGH YLD BD INC 2\
|
|
199
|
+
FUND NORMAL B2PT4G9
|
|
200
|
+
1 2020-03-23 1000001589 2020-04-01 LUX EL^X NINETY ONE LIMITED EUROPEAN HIGH YLD BD INC 2\
|
|
201
|
+
FUND NORMAL B2PT4G9
|
|
202
|
+
2 2020-04-01 1000001589 2021-01-01 LUX EL^X NINETY ONE LUX S.A EUROPEAN HIGH YLD BD INC 2\
|
|
203
|
+
FUND NORMAL B2PT4G9
|
|
204
|
+
3 2021-01-01 1000001589 2021-06-18 LUX EL^X NINETY ONE LUX S.A EUROPEAN HIGH YLD BD INC 2\
|
|
205
|
+
FUND NORMAL B2PT4G9
|
|
206
|
+
4 2021-06-18 1000001589 2022-01-01 LUX EL^X NINETY ONE LUX S.A GSF GBL HIGH YLD A2 EUR DIS\
|
|
207
|
+
FUND NORMAL B2PT4G9
|
|
208
|
+
5 2022-01-01 1000001589 2022-01-28 LUX EL^X NINETY ONE LUX S.A GSF GBL HIGH YLD A2 EUR DIS\
|
|
209
|
+
FUND NORMAL B2PT4G9
|
|
210
|
+
"""
|
|
211
|
+
|
|
212
|
+
@docstring(parameters=COMMON_SOURCE_DOC_PARAMS, add_self=True)
|
|
213
|
+
def __init__(
|
|
214
|
+
self,
|
|
215
|
+
symbol=utils.adaptive,
|
|
216
|
+
start=utils.adaptive,
|
|
217
|
+
end=utils.adaptive,
|
|
218
|
+
**kwargs
|
|
219
|
+
):
|
|
220
|
+
if self._try_default_constructor(**kwargs):
|
|
221
|
+
return
|
|
222
|
+
|
|
223
|
+
super().__init__(
|
|
224
|
+
_symbols=symbol,
|
|
225
|
+
_start=start,
|
|
226
|
+
_end=end,
|
|
227
|
+
_base_ep_func=partial(self.build)
|
|
228
|
+
)
|
|
229
|
+
|
|
230
|
+
self.schema.set(
|
|
231
|
+
OID=str,
|
|
232
|
+
END_DATE=otp.nsectime,
|
|
233
|
+
COUNTRY=str,
|
|
234
|
+
EXCH=str,
|
|
235
|
+
NAME=str,
|
|
236
|
+
ISSUE_DESC=str,
|
|
237
|
+
ISSUE_CLASS=str,
|
|
238
|
+
ISSUE_TYPE=str,
|
|
239
|
+
ISSUE_STATUS=str,
|
|
240
|
+
SIC_CODE=str,
|
|
241
|
+
IDSYM=str,
|
|
242
|
+
TICKER=str,
|
|
243
|
+
CALENDAR=str,)
|
|
244
|
+
|
|
245
|
+
def build(self):
|
|
246
|
+
ep = otp.oqd.eps.OqdSourceDes()
|
|
247
|
+
src = otp.Source(ep)
|
|
248
|
+
src.tick_type(OQD_TICK_TYPE)
|
|
249
|
+
_modify_query_times(src)
|
|
250
|
+
|
|
251
|
+
# work-around to resolve problem with pandas timestamp out of bounds
|
|
252
|
+
pd_max = pd.Timestamp.max.strftime('%Y%m%d%H%M%S')
|
|
253
|
+
src.sink(otq.UpdateFields(
|
|
254
|
+
set='END_DATE=PARSE_NSECTIME("%Y-%m-%d", "2035-01-01", _TIMEZONE)',
|
|
255
|
+
where=f'AS_YYYYMMDDHHMMSS(END_DATE) > {pd_max}'))
|
|
256
|
+
return src
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
class SharesOutstanding(otp.Source):
|
|
260
|
+
"""
|
|
261
|
+
Logic is implemented in OQD_SOURCE_SHO EP to retrieve a time series of shares
|
|
262
|
+
outstanding for a stock.
|
|
263
|
+
|
|
264
|
+
The source retrieves a time series of shares outstanding
|
|
265
|
+
for a stock. This source only applies to stocks or securities that have
|
|
266
|
+
published shares outstanding data.
|
|
267
|
+
|
|
268
|
+
The series represents total shares outstanding and is not free float
|
|
269
|
+
adjusted.
|
|
270
|
+
|
|
271
|
+
Note: currently actual fields have 9999 year in END_DATE, but it could not fit the
|
|
272
|
+
nanosecond timestamp, so it is replaced with 2035-01-01 date.
|
|
273
|
+
|
|
274
|
+
|
|
275
|
+
Examples
|
|
276
|
+
--------
|
|
277
|
+
>>> src = otp.oqd.sources.SharesOutstanding() # doctest: +SKIP
|
|
278
|
+
>>> otp.run(src, # doctest: +SKIP
|
|
279
|
+
... symbols='TDEQ::::AAPL',
|
|
280
|
+
... start=otp.dt(2021, 1, 1),
|
|
281
|
+
... end=otp.dt(2021, 8, 6),
|
|
282
|
+
... symbol_date=otp.dt(2021, 2, 18),
|
|
283
|
+
... timezone='GMT')
|
|
284
|
+
Time OID END_DATE REPORT_MONTH SHARES
|
|
285
|
+
0 2021-01-01 9706 2021-01-06 202009 1.700180e+10
|
|
286
|
+
1 2021-01-06 9706 2021-01-29 202009 1.682326e+10
|
|
287
|
+
2 2021-01-29 9706 2021-05-03 202012 1.678810e+10
|
|
288
|
+
3 2021-05-03 9706 2021-07-30 202103 1.668763e+10
|
|
289
|
+
4 2021-07-30 9706 2021-10-29 202106 1.653017e+10
|
|
290
|
+
"""
|
|
291
|
+
@docstring(parameters=COMMON_SOURCE_DOC_PARAMS, add_self=True)
|
|
292
|
+
def __init__(
|
|
293
|
+
self,
|
|
294
|
+
symbol=otp.utils.adaptive,
|
|
295
|
+
start=otp.utils.adaptive,
|
|
296
|
+
end=otp.utils.adaptive,
|
|
297
|
+
**kwargs
|
|
298
|
+
):
|
|
299
|
+
if self._try_default_constructor(**kwargs):
|
|
300
|
+
return
|
|
301
|
+
|
|
302
|
+
super().__init__(
|
|
303
|
+
_symbols=symbol,
|
|
304
|
+
_start=start,
|
|
305
|
+
_end=end,
|
|
306
|
+
_base_ep_func=partial(self.build)
|
|
307
|
+
)
|
|
308
|
+
|
|
309
|
+
self.schema.set(OID=str,
|
|
310
|
+
END_DATE=otp.nsectime,
|
|
311
|
+
REPORT_MONTH=int,
|
|
312
|
+
SHARES=int)
|
|
313
|
+
|
|
314
|
+
def build(self):
|
|
315
|
+
ep = otp.oqd.eps.OqdSourceSho()
|
|
316
|
+
src = otp.Source(ep)
|
|
317
|
+
src.tick_type(OQD_TICK_TYPE)
|
|
318
|
+
_modify_query_times(src)
|
|
319
|
+
|
|
320
|
+
# work-around to resolve problem with pandas timestamp out of bounds
|
|
321
|
+
pd_max = pd.Timestamp.max.strftime('%Y%m%d%H%M%S')
|
|
322
|
+
src.sink(otq.UpdateFields(
|
|
323
|
+
set='END_DATE=PARSE_NSECTIME("%Y-%m-%d", "2035-01-01", _TIMEZONE)',
|
|
324
|
+
where=f'AS_YYYYMMDDHHMMSS(END_DATE) > {pd_max}'))
|
|
325
|
+
return src
|
onetick/py/otq.py
ADDED
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# This file is used to import the correct query module:
|
|
2
|
+
# onetick.query or onetick.query_webapi
|
|
3
|
+
# based on the environment variable OTP_WEBAPI
|
|
4
|
+
# Re-use this file in your tests to import the correct onetick.query module
|
|
5
|
+
# Also it is override pyomd and OneTickLib classes with mock classes
|
|
6
|
+
|
|
7
|
+
import getpass
|
|
8
|
+
import inspect
|
|
9
|
+
import os
|
|
10
|
+
import tempfile
|
|
11
|
+
import warnings
|
|
12
|
+
import onetick.py as otp
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class OneTickLib:
|
|
16
|
+
# mock class for OneTickLib, used for webapi and onetick-query-stubs
|
|
17
|
+
# maybe it is not right to combine this namesake classes (onetick.lib.OneTickLib and pyomd.OneTickLib)
|
|
18
|
+
# but it is done to simplify the code and it is not affecting anything except tests
|
|
19
|
+
LOGGING_LEVEL_MIN = 0
|
|
20
|
+
LOGGING_LEVEL_LOW = 1
|
|
21
|
+
LOGGING_LEVEL_MEDIUM = 2
|
|
22
|
+
LOGGING_LEVEL_MAX = 3
|
|
23
|
+
set_authentication_token = None
|
|
24
|
+
|
|
25
|
+
def __init__(self, *args, **kwargs): # NOSONAR
|
|
26
|
+
pass
|
|
27
|
+
|
|
28
|
+
def set_log_file(self, log_file): # NOSONAR
|
|
29
|
+
pass
|
|
30
|
+
|
|
31
|
+
def cleanup(self): # NOSONAR
|
|
32
|
+
pass
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
if os.getenv("OTP_SKIP_OTQ_VALIDATION"):
|
|
36
|
+
import onetick_stubs as otq # noqa: F401
|
|
37
|
+
import pyomd # noqa: F401
|
|
38
|
+
|
|
39
|
+
class ConfigStub:
|
|
40
|
+
API_CONFIG: dict = {}
|
|
41
|
+
|
|
42
|
+
class otli:
|
|
43
|
+
OneTickLib = OneTickLib # NOSONAR
|
|
44
|
+
|
|
45
|
+
for key, value in otq.query.__dict__.items():
|
|
46
|
+
setattr(otq, key, value)
|
|
47
|
+
setattr(otq, 'webapi', False)
|
|
48
|
+
setattr(otq, 'config', ConfigStub)
|
|
49
|
+
setattr(otq, 'graph_components', otq)
|
|
50
|
+
|
|
51
|
+
elif otp.__webapi__:
|
|
52
|
+
import onetick.query_webapi as otq # noqa: F401
|
|
53
|
+
setattr(otq, 'webapi', True)
|
|
54
|
+
|
|
55
|
+
from onetick.py.pyomd_mock import pyomd
|
|
56
|
+
|
|
57
|
+
__original_run = otq.run
|
|
58
|
+
|
|
59
|
+
def run(*args, **kwargs):
|
|
60
|
+
from onetick.py import config # noqa
|
|
61
|
+
from onetick.py.compatibility import is_max_concurrency_with_webapi_supported
|
|
62
|
+
|
|
63
|
+
if not config.http_address and 'http_address' not in kwargs:
|
|
64
|
+
raise ValueError('otp.run() http_address keyword param, '
|
|
65
|
+
'otp.config.http_address or OTP_HTTP_ADDRESS '
|
|
66
|
+
'environment variable are required '
|
|
67
|
+
'when using WebAPI mode.')
|
|
68
|
+
|
|
69
|
+
# TODO WEBAPI review this
|
|
70
|
+
# if file name is not in single quotes, then put it in single quotes
|
|
71
|
+
query_name = None
|
|
72
|
+
query = kwargs.get('query', None)
|
|
73
|
+
if isinstance(query, str):
|
|
74
|
+
if query[0] == "'" and query[-1] == "'":
|
|
75
|
+
query = query.replace("'", "")
|
|
76
|
+
if '::' in query:
|
|
77
|
+
query_name = query.split('::')[-1]
|
|
78
|
+
query = query.replace(f'::{query_name}', '')
|
|
79
|
+
kwargs['query'] = query
|
|
80
|
+
kwargs['query_name'] = query_name
|
|
81
|
+
|
|
82
|
+
del_params = [
|
|
83
|
+
'start_time_expression',
|
|
84
|
+
'end_time_expression',
|
|
85
|
+
'alternative_username',
|
|
86
|
+
'batch_size',
|
|
87
|
+
'treat_byte_arrays_as_strings',
|
|
88
|
+
'output_matrix_per_field',
|
|
89
|
+
'return_utc_times',
|
|
90
|
+
'connection',
|
|
91
|
+
'svg_path',
|
|
92
|
+
'use_connection_pool',
|
|
93
|
+
'time_as_nsec',
|
|
94
|
+
'max_expected_ticks_per_symbol',
|
|
95
|
+
]
|
|
96
|
+
ignore_deleted_params = [
|
|
97
|
+
'treat_byte_arrays_as_strings',
|
|
98
|
+
'time_as_nsec',
|
|
99
|
+
'alternative_username',
|
|
100
|
+
'max_expected_ticks_per_symbol'
|
|
101
|
+
]
|
|
102
|
+
for param in del_params:
|
|
103
|
+
if param in kwargs:
|
|
104
|
+
if kwargs[param] and param not in ignore_deleted_params:
|
|
105
|
+
warnings.warn(f'Parameter {param} is not supported in WebAPI mode and will be ignored.')
|
|
106
|
+
del kwargs[param]
|
|
107
|
+
|
|
108
|
+
from onetick.py import config # noqa
|
|
109
|
+
if 'http_address' not in kwargs:
|
|
110
|
+
kwargs['http_address'] = config.http_address
|
|
111
|
+
|
|
112
|
+
if kwargs.get('username'):
|
|
113
|
+
kwargs['http_username'] = kwargs['username']
|
|
114
|
+
del kwargs['username']
|
|
115
|
+
else:
|
|
116
|
+
kwargs['http_username'] = config.http_username
|
|
117
|
+
|
|
118
|
+
if kwargs.get('password'):
|
|
119
|
+
kwargs['http_password'] = kwargs['password']
|
|
120
|
+
del kwargs['password']
|
|
121
|
+
else:
|
|
122
|
+
kwargs['http_password'] = config.http_password
|
|
123
|
+
|
|
124
|
+
if 'access_token' not in kwargs:
|
|
125
|
+
if config.access_token:
|
|
126
|
+
kwargs['access_token'] = config.access_token
|
|
127
|
+
elif not kwargs['access_token']:
|
|
128
|
+
del kwargs['access_token']
|
|
129
|
+
|
|
130
|
+
access_token_url = kwargs.get('access_token_url', config.access_token_url)
|
|
131
|
+
if access_token_url:
|
|
132
|
+
if not hasattr(otq, 'get_access_token'):
|
|
133
|
+
raise RuntimeError('Current `onetick.query_webapi` version doesn\'t have `get_access_token` function')
|
|
134
|
+
|
|
135
|
+
if kwargs.get('access_token'):
|
|
136
|
+
raise ValueError('Both `access_token` and `access_token_url` set, instead of only one of them.')
|
|
137
|
+
|
|
138
|
+
if 'client_id' in kwargs:
|
|
139
|
+
client_id = kwargs.pop('client_id')
|
|
140
|
+
else:
|
|
141
|
+
client_id = config.client_id
|
|
142
|
+
|
|
143
|
+
if 'client_secret' in kwargs:
|
|
144
|
+
client_secret = kwargs.pop('client_secret')
|
|
145
|
+
else:
|
|
146
|
+
client_secret = config.client_secret
|
|
147
|
+
|
|
148
|
+
for param_name, param_value in zip(['client_id', 'client_secret'], [client_id, client_secret]):
|
|
149
|
+
if not param_value:
|
|
150
|
+
raise ValueError(f'`access_token_url` parameter set, however `{param_name}` parameter missing.')
|
|
151
|
+
|
|
152
|
+
kwargs['access_token'] = otq.get_access_token(access_token_url, client_id, client_secret)
|
|
153
|
+
|
|
154
|
+
if 'access_token_url' in kwargs:
|
|
155
|
+
del kwargs['access_token_url']
|
|
156
|
+
|
|
157
|
+
if 'http_proxy' not in kwargs:
|
|
158
|
+
kwargs['http_proxy'] = config.http_proxy
|
|
159
|
+
|
|
160
|
+
if 'https_proxy' not in kwargs:
|
|
161
|
+
kwargs['https_proxy'] = config.https_proxy
|
|
162
|
+
|
|
163
|
+
webapi_run_parameters = inspect.signature(__original_run).parameters
|
|
164
|
+
|
|
165
|
+
trusted_certificate_file_arg = kwargs.pop('trusted_certificates_file',
|
|
166
|
+
kwargs.pop('trusted_certificate_file', None))
|
|
167
|
+
trusted_certificate_file_value = (
|
|
168
|
+
trusted_certificate_file_arg if trusted_certificate_file_arg is not None
|
|
169
|
+
else config.trusted_certificates_file
|
|
170
|
+
)
|
|
171
|
+
if trusted_certificate_file_value is not None:
|
|
172
|
+
trusted_certificates_supported = set(webapi_run_parameters).intersection({'trusted_certificates_file',
|
|
173
|
+
'trusted_certificate_file'})
|
|
174
|
+
if not trusted_certificates_supported:
|
|
175
|
+
raise ValueError(
|
|
176
|
+
"Parameter `trusted_certificates_file` was set,"
|
|
177
|
+
" however current version of OneTick doesn't support it."
|
|
178
|
+
)
|
|
179
|
+
trusted_certificates_supported_param = list(trusted_certificates_supported)[0]
|
|
180
|
+
kwargs[trusted_certificates_supported_param] = trusted_certificate_file_value
|
|
181
|
+
|
|
182
|
+
if 'callback' in kwargs and kwargs['callback'] is not None:
|
|
183
|
+
kwargs['output_mode'] = otq.QueryOutputMode.callback
|
|
184
|
+
|
|
185
|
+
if 'max_concurrency' in kwargs and not is_max_concurrency_with_webapi_supported():
|
|
186
|
+
kwargs['max_concurrency'] = None
|
|
187
|
+
|
|
188
|
+
return __original_run(*args, **kwargs)
|
|
189
|
+
|
|
190
|
+
otq.run = run
|
|
191
|
+
|
|
192
|
+
otq.OneTickLib = OneTickLib
|
|
193
|
+
|
|
194
|
+
class otli: # type: ignore # noqa: F401
|
|
195
|
+
OneTickLib = otq.OneTickLib # NOSONAR
|
|
196
|
+
|
|
197
|
+
else:
|
|
198
|
+
import onetick.query as otq # type: ignore # noqa: F401
|
|
199
|
+
import pyomd # type: ignore # noqa: F401
|
|
200
|
+
import onetick.lib.instance as otli # type: ignore # noqa: F401
|
|
201
|
+
setattr(otq, 'webapi', False)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def _tmp_otq_path():
|
|
205
|
+
# copied from onetick.test.fixtures _keep_generated_dir() with replacement to /tmp
|
|
206
|
+
# required with OTP_WEBAPI_TEST_MODE to separate otq files from shared dbs+config+locator+acl files
|
|
207
|
+
from onetick.py import utils # noqa
|
|
208
|
+
res = os.path.join(utils.TMP_CONFIGS_DIR(), os.environ.get("ONE_TICK_TMP_DIR", "otqs"))
|
|
209
|
+
res = res.replace(utils.temp.WEBAPI_TEST_MODE_SHARED_CONFIG,
|
|
210
|
+
os.path.join(tempfile.gettempdir(), "test_" + getpass.getuser()))
|
|
211
|
+
|
|
212
|
+
# % and + is some webapi related path bugs, probably would be fixed someday
|
|
213
|
+
return res.replace("%", "_").replace("+", "_")
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
__all__ = ['otq', 'pyomd', 'otli', '_tmp_otq_path']
|
onetick/py/pyomd_mock.py
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import onetick.py as otp
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
if otp.__webapi__:
|
|
6
|
+
try:
|
|
7
|
+
from onetick.query_webapi import QueryProperties # noqa: E0611
|
|
8
|
+
except ImportError as e:
|
|
9
|
+
try:
|
|
10
|
+
import onetick.query_webapi # noqa
|
|
11
|
+
raise RuntimeError("You're trying to use onetick.query_webapi module, "
|
|
12
|
+
"that is not compatible with onetick.py. "
|
|
13
|
+
"Please, use onetick.query module instead (unset OTP_WEBAPI), "
|
|
14
|
+
"or install onetick.query_webapi==1.24.20240715 or newer. "
|
|
15
|
+
"Also, check that your PYTHONPATH doesn't have onetick binary path, "
|
|
16
|
+
"because onetick distribution could have older onetick.query_webapi, "
|
|
17
|
+
"that mirror your pip-installed version.") from e
|
|
18
|
+
except ImportError as e2:
|
|
19
|
+
raise ImportError(
|
|
20
|
+
"OTP_WEBAPI environment variable is set,"
|
|
21
|
+
" but onetick.query_webapi module is not available."
|
|
22
|
+
" Please, install onetick.query_webapi to avoid import errors"
|
|
23
|
+
" or unset OTP_WEBAPI to use onetick.query module instead."
|
|
24
|
+
) from e2
|
|
25
|
+
|
|
26
|
+
# copied from one_market_data/one_tick/bin/python/onetick/query/_internal_utils.py
|
|
27
|
+
def quoted(str_object):
|
|
28
|
+
if len(str_object) <= 1:
|
|
29
|
+
return str_object
|
|
30
|
+
if str_object[0] == "'" and str_object[-1] == "'" or str_object[0] == '"' and str_object[-1] == '"':
|
|
31
|
+
return str_object
|
|
32
|
+
return f"'{str_object}'"
|
|
33
|
+
|
|
34
|
+
class OT_time_nsec_mock: # NOSONAR
|
|
35
|
+
def __init__(self, number):
|
|
36
|
+
self.number = number
|
|
37
|
+
|
|
38
|
+
def __int__(self):
|
|
39
|
+
return int(self.number / 1e9)
|
|
40
|
+
|
|
41
|
+
class pyomd:
|
|
42
|
+
timeval_t = datetime.datetime # type: ignore
|
|
43
|
+
QueryProperties = QueryProperties # type: ignore # NOSONAR
|
|
44
|
+
|
|
45
|
+
@staticmethod
|
|
46
|
+
def OT_time_nsec(number): # NOSONAR
|
|
47
|
+
return int(number / 1e9)
|