PyAlgoEngine 0.12.0.post3__cp313-cp313-win_amd64.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.
- algo_engine/__infra__.pxd +3 -0
- algo_engine/__init__.pxd +3 -0
- algo_engine/__init__.py +91 -0
- algo_engine/apps/__init__.py +17 -0
- algo_engine/apps/backtest/__init__.py +20 -0
- algo_engine/apps/backtest/doc_server.py +328 -0
- algo_engine/apps/backtest/static/styles/dash.css +48 -0
- algo_engine/apps/backtest/templates/dash.html +20 -0
- algo_engine/apps/backtest/templates/index.html +40 -0
- algo_engine/apps/backtest/tester.py +252 -0
- algo_engine/apps/backtest/web_app.py +125 -0
- algo_engine/apps/bokeh_server.py +245 -0
- algo_engine/apps/demo/__init__.py +0 -0
- algo_engine/apps/demo/test.py +40 -0
- algo_engine/apps/sim_input/__init__.py +23 -0
- algo_engine/apps/sim_input/client.py +412 -0
- algo_engine/apps/sim_input/sim_keyboard.py +88 -0
- algo_engine/apps/sim_input/sim_mouse.py +137 -0
- algo_engine/apps/sim_input/window.py +162 -0
- algo_engine/backtest/__init__.py +19 -0
- algo_engine/backtest/__main__.py +51 -0
- algo_engine/backtest/metrics.py +179 -0
- algo_engine/backtest/replay.py +635 -0
- algo_engine/backtest/sim_match.py +506 -0
- algo_engine/base/__infra__.pxd +3 -0
- algo_engine/base/__init__.pxd +3 -0
- algo_engine/base/__init__.py +60 -0
- algo_engine/base/c_allocator_protocol.c +10756 -0
- algo_engine/base/c_allocator_protocol.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_allocator_protocol.pxd +24 -0
- algo_engine/base/c_allocator_protocol.pyi +68 -0
- algo_engine/base/c_allocator_protocol.pyx +88 -0
- algo_engine/base/c_intern_string.c +5845 -0
- algo_engine/base/c_intern_string.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_intern_string.pxd +14 -0
- algo_engine/base/c_intern_string.pyi +22 -0
- algo_engine/base/c_intern_string.pyx +17 -0
- algo_engine/base/c_market_data/__infra__.pxd +196 -0
- algo_engine/base/c_market_data/__init__.pxd +196 -0
- algo_engine/base/c_market_data/__init__.py +24 -0
- algo_engine/base/c_market_data/c_candlestick.c +18960 -0
- algo_engine/base/c_market_data/c_candlestick.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_candlestick.pxd +27 -0
- algo_engine/base/c_market_data/c_candlestick.pyi +217 -0
- algo_engine/base/c_market_data/c_candlestick.pyx +255 -0
- algo_engine/base/c_market_data/c_internal.c +14023 -0
- algo_engine/base/c_market_data/c_internal.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_internal.pxd +14 -0
- algo_engine/base/c_market_data/c_internal.pyi +47 -0
- algo_engine/base/c_market_data/c_internal.pyx +41 -0
- algo_engine/base/c_market_data/c_market_data.c +30739 -0
- algo_engine/base/c_market_data/c_market_data.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_market_data.h +1464 -0
- algo_engine/base/c_market_data/c_market_data.pxd +418 -0
- algo_engine/base/c_market_data/c_market_data.pyi +550 -0
- algo_engine/base/c_market_data/c_market_data.pyx +688 -0
- algo_engine/base/c_market_data/c_market_data_buffer.c +29370 -0
- algo_engine/base/c_market_data/c_market_data_buffer.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_market_data_buffer.h +941 -0
- algo_engine/base/c_market_data/c_market_data_buffer.pxd +143 -0
- algo_engine/base/c_market_data/c_market_data_buffer.pyi +355 -0
- algo_engine/base/c_market_data/c_market_data_buffer.pyx +571 -0
- algo_engine/base/c_market_data/c_market_data_config.h +29 -0
- algo_engine/base/c_market_data/c_tick.c +44230 -0
- algo_engine/base/c_market_data/c_tick.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_tick.pxd +53 -0
- algo_engine/base/c_market_data/c_tick.pyi +466 -0
- algo_engine/base/c_market_data/c_tick.pyx +673 -0
- algo_engine/base/c_market_data/c_trade_utils.c +28665 -0
- algo_engine/base/c_market_data/c_trade_utils.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_trade_utils.pxd +53 -0
- algo_engine/base/c_market_data/c_trade_utils.pyi +602 -0
- algo_engine/base/c_market_data/c_trade_utils.pyx +609 -0
- algo_engine/base/c_market_data/c_transaction.c +23521 -0
- algo_engine/base/c_market_data/c_transaction.cp313-win_amd64.pyd +0 -0
- algo_engine/base/c_market_data/c_transaction.pxd +27 -0
- algo_engine/base/c_market_data/c_transaction.pyi +433 -0
- algo_engine/base/c_market_data/c_transaction.pyx +460 -0
- algo_engine/base/console_utils.py +1070 -0
- algo_engine/base/finance_decimal.py +258 -0
- algo_engine/base/telemetrics.py +104 -0
- algo_engine/engine/__infra__.pxd +10 -0
- algo_engine/engine/__init__.pxd +10 -0
- algo_engine/engine/__init__.py +40 -0
- algo_engine/engine/algo_engine.py +904 -0
- algo_engine/engine/c_event_engine.c +16289 -0
- algo_engine/engine/c_event_engine.cp313-win_amd64.pyd +0 -0
- algo_engine/engine/c_event_engine.pxd +25 -0
- algo_engine/engine/c_event_engine.pyi +68 -0
- algo_engine/engine/c_market_engine.c +24222 -0
- algo_engine/engine/c_market_engine.cp313-win_amd64.pyd +0 -0
- algo_engine/engine/c_market_engine.pxd +87 -0
- algo_engine/engine/c_market_engine.pyi +357 -0
- algo_engine/engine/event_engine.py +53 -0
- algo_engine/engine/trade_engine.py +2037 -0
- algo_engine/exchange_profile/__infra__.pxd +99 -0
- algo_engine/exchange_profile/__init__.pxd +99 -0
- algo_engine/exchange_profile/__init__.py +36 -0
- algo_engine/exchange_profile/c_ex_profile_base.c +87 -0
- algo_engine/exchange_profile/c_ex_profile_base.h +1148 -0
- algo_engine/exchange_profile/c_ex_profile_cn.c +968 -0
- algo_engine/exchange_profile/c_ex_profile_cn.h +39 -0
- algo_engine/exchange_profile/c_exchange_profile.c +52061 -0
- algo_engine/exchange_profile/c_exchange_profile.cp313-win_amd64.pyd +0 -0
- algo_engine/exchange_profile/c_exchange_profile.pxd +336 -0
- algo_engine/exchange_profile/c_exchange_profile.pyi +867 -0
- algo_engine/exchange_profile/c_exchange_profile.pyx +1482 -0
- algo_engine/exchange_profile/c_profile_cn.c +7779 -0
- algo_engine/exchange_profile/c_profile_cn.cp313-win_amd64.pyd +0 -0
- algo_engine/exchange_profile/c_profile_cn.pxd +1 -0
- algo_engine/exchange_profile/c_profile_cn.pyi +3 -0
- algo_engine/exchange_profile/c_profile_cn.pyx +1 -0
- algo_engine/exchange_profile/c_profile_default.c +7779 -0
- algo_engine/exchange_profile/c_profile_default.cp313-win_amd64.pyd +0 -0
- algo_engine/exchange_profile/c_profile_default.pxd +1 -0
- algo_engine/exchange_profile/c_profile_default.pyi +3 -0
- algo_engine/exchange_profile/c_profile_default.pyx +1 -0
- algo_engine/exchange_profile/c_profile_dispatcher.c +7779 -0
- algo_engine/exchange_profile/c_profile_dispatcher.cp313-win_amd64.pyd +0 -0
- algo_engine/exchange_profile/c_profile_dispatcher.pxd +1 -0
- algo_engine/exchange_profile/c_profile_dispatcher.pyi +3 -0
- algo_engine/exchange_profile/c_profile_dispatcher.pyx +1 -0
- algo_engine/includes/algo_engine/base/c_allocator_protocol.c +10756 -0
- algo_engine/includes/algo_engine/base/c_intern_string.c +5845 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_candlestick.c +18960 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_internal.c +14023 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_market_data.c +30739 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_market_data.h +1464 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_market_data_buffer.c +29370 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_market_data_buffer.h +941 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_market_data_config.h +29 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_tick.c +44230 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_trade_utils.c +28665 -0
- algo_engine/includes/algo_engine/base/c_market_data/c_transaction.c +23521 -0
- algo_engine/includes/algo_engine/engine/c_event_engine.c +16289 -0
- algo_engine/includes/algo_engine/engine/c_market_engine.c +24222 -0
- algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_base.c +87 -0
- algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_base.h +1148 -0
- algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_cn.c +968 -0
- algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_cn.h +39 -0
- algo_engine/includes/algo_engine/exchange_profile/c_exchange_profile.c +52061 -0
- algo_engine/includes/algo_engine/exchange_profile/c_profile_cn.c +7779 -0
- algo_engine/includes/algo_engine/exchange_profile/c_profile_default.c +7779 -0
- algo_engine/includes/algo_engine/exchange_profile/c_profile_dispatcher.c +7779 -0
- algo_engine/monitor/__init__.py +15 -0
- algo_engine/monitor/advanced_data_interface.py +334 -0
- algo_engine/strategy/__init__.py +44 -0
- algo_engine/strategy/strategy_engine.py +441 -0
- algo_engine/utils/__init__.py +3 -0
- algo_engine/utils/commit_regularizer.py +49 -0
- algo_engine/utils/data_utils.py +296 -0
- pyalgoengine-0.12.0.post3.dist-info/METADATA +142 -0
- pyalgoengine-0.12.0.post3.dist-info/RECORD +156 -0
- pyalgoengine-0.12.0.post3.dist-info/WHEEL +5 -0
- pyalgoengine-0.12.0.post3.dist-info/licenses/LICENSE +21 -0
- pyalgoengine-0.12.0.post3.dist-info/top_level.txt +2 -0
|
@@ -0,0 +1,867 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import enum
|
|
3
|
+
from datetime import timedelta
|
|
4
|
+
from typing import Self, overload, override
|
|
5
|
+
|
|
6
|
+
__all__ = [
|
|
7
|
+
"SessionType",
|
|
8
|
+
"SessionPhase",
|
|
9
|
+
"AuctionPhase",
|
|
10
|
+
"SessionTime",
|
|
11
|
+
"SessionTimeRange",
|
|
12
|
+
"SessionDate",
|
|
13
|
+
"SessionDateRange",
|
|
14
|
+
"SessionDateTime",
|
|
15
|
+
"CallAuction",
|
|
16
|
+
"SessionBreak",
|
|
17
|
+
"ExchangeProfile",
|
|
18
|
+
|
|
19
|
+
'PROFILE',
|
|
20
|
+
'PROFILE_DEFAULT',
|
|
21
|
+
'PROFILE_CN'
|
|
22
|
+
]
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class SessionType(enum.IntEnum):
|
|
26
|
+
"""Describes the type of trading session for a given market date.
|
|
27
|
+
|
|
28
|
+
The integer values map directly to the underlying C enum constants used
|
|
29
|
+
by the exchange profile implementation. Use these values to inspect or
|
|
30
|
+
annotate calendar/session types.
|
|
31
|
+
|
|
32
|
+
Attributes
|
|
33
|
+
----------
|
|
34
|
+
NON_TRADING: int
|
|
35
|
+
Market is closed for the date.
|
|
36
|
+
NORMINAL: int
|
|
37
|
+
Normal trading day.
|
|
38
|
+
SUSPENDED: int
|
|
39
|
+
Trading suspended for the date.
|
|
40
|
+
HALF_DAY: int
|
|
41
|
+
Half trading day.
|
|
42
|
+
CIRCUIT_BREAK: int
|
|
43
|
+
Trading day with a circuit breaker in effect.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
NON_TRADING: SessionType
|
|
47
|
+
NORMINAL: SessionType
|
|
48
|
+
SUSPENDED: SessionType
|
|
49
|
+
HALF_DAY: SessionType
|
|
50
|
+
CIRCUIT_BREAK: SessionType
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
class SessionPhase(enum.IntEnum):
|
|
54
|
+
"""The phase of the trading session at a particular time-of-day.
|
|
55
|
+
|
|
56
|
+
The values correspond to the phases used inside the C exchange profile
|
|
57
|
+
code (e.g. PREOPEN, CONTINUOUS, BREAK, CLOSED, ...). The value can be
|
|
58
|
+
retrieved from a :class:`SessionTime` via the ``session_phase`` property.
|
|
59
|
+
"""
|
|
60
|
+
|
|
61
|
+
UNKNOWN: SessionPhase
|
|
62
|
+
PREOPEN: SessionPhase
|
|
63
|
+
OPEN_AUCTION: SessionPhase
|
|
64
|
+
CONTINUOUS: SessionPhase
|
|
65
|
+
BREAK: SessionPhase
|
|
66
|
+
SUSPENDED: SessionPhase
|
|
67
|
+
CLOSE_AUCTION: SessionPhase
|
|
68
|
+
CLOSED: SessionPhase
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
class AuctionPhase(enum.IntEnum):
|
|
72
|
+
"""Auction-specific phase during call auctions.
|
|
73
|
+
|
|
74
|
+
These values map to the auction phases used by the exchange profile.
|
|
75
|
+
"""
|
|
76
|
+
|
|
77
|
+
ACTIVE: AuctionPhase
|
|
78
|
+
NO_CANCEL: AuctionPhase
|
|
79
|
+
FROZEN: AuctionPhase
|
|
80
|
+
UNCROSSING: AuctionPhase
|
|
81
|
+
DONE: AuctionPhase
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
def local_utc_offset_seconds() -> int:
|
|
85
|
+
"""Returns the local UTC offset in seconds for the current system timezone.
|
|
86
|
+
|
|
87
|
+
This is used internally to adjust timestamps when converting between
|
|
88
|
+
unix timestamps and session times, since the exchange profile operates
|
|
89
|
+
in local time. The function computes the offset by comparing the current
|
|
90
|
+
local time to UTC time.
|
|
91
|
+
|
|
92
|
+
Returns
|
|
93
|
+
-------
|
|
94
|
+
int
|
|
95
|
+
Local UTC offset in seconds (e.g. 28800 for UTC/GMT +8 hours).
|
|
96
|
+
"""
|
|
97
|
+
...
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
def unix_to_datetime(unix_ts: float) -> datetime.datetime:
|
|
101
|
+
"""Convert a UNIX timestamp to a timezone-aware datetime in the local timezone.
|
|
102
|
+
|
|
103
|
+
This function is used internally for timestamp conversions in the exchange
|
|
104
|
+
profile. It takes a UNIX timestamp (seconds since epoch) and returns a
|
|
105
|
+
datetime object that is aware of the local timezone, which is necessary
|
|
106
|
+
for accurate conversions to session times.
|
|
107
|
+
|
|
108
|
+
Args:
|
|
109
|
+
unix_ts: The UNIX timestamp to convert.
|
|
110
|
+
Returns:
|
|
111
|
+
A timezone-aware datetime object corresponding to the provided timestamp in the local timezone.
|
|
112
|
+
Raises:
|
|
113
|
+
ValueError: If the provided timestamp is negative or otherwise invalid.
|
|
114
|
+
"""
|
|
115
|
+
...
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
TimeLike = SessionTime | datetime.time
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class SessionTime(object):
|
|
122
|
+
"""Represents a time-of-day within an exchange session.
|
|
123
|
+
|
|
124
|
+
This class is a lightweight wrapper around a C struct (``session_time_t``)
|
|
125
|
+
and exposes a Python-friendly API for construction, inspection, and
|
|
126
|
+
comparisons. Instances are typically created by calling the class with
|
|
127
|
+
hour/minute/second/nanosecond arguments, or by converting from
|
|
128
|
+
``datetime.time`` via ``from_pytime``.
|
|
129
|
+
|
|
130
|
+
The object is immutable from the Python-level: its fields are exposed as
|
|
131
|
+
read-only properties. The underlying implementation caches a floating
|
|
132
|
+
seconds-since-midnight timestamp used to compute ``elapsed_seconds`` when
|
|
133
|
+
an exchange profile is active.
|
|
134
|
+
|
|
135
|
+
Example
|
|
136
|
+
-------
|
|
137
|
+
>>> st = SessionTime(9, 30, 0)
|
|
138
|
+
>>> st.hour
|
|
139
|
+
9
|
|
140
|
+
|
|
141
|
+
Parameters
|
|
142
|
+
----------
|
|
143
|
+
hour : int, optional
|
|
144
|
+
Hour in 24-hour clock (0-23). Default is 0.
|
|
145
|
+
minute : int, optional
|
|
146
|
+
Minute (0-59). Default is 0.
|
|
147
|
+
second : int, optional
|
|
148
|
+
Second (0-59). Default is 0.
|
|
149
|
+
nanosecond : int, optional
|
|
150
|
+
Nanoseconds portion (0-999_999_999). Default is 0.
|
|
151
|
+
"""
|
|
152
|
+
|
|
153
|
+
def __init__(self, hour: int = 0, minute: int = 0, second: int = 0, nanosecond: int = 0) -> None: ...
|
|
154
|
+
|
|
155
|
+
@classmethod
|
|
156
|
+
def from_pytime(cls, t: datetime.time) -> Self: ...
|
|
157
|
+
|
|
158
|
+
@classmethod
|
|
159
|
+
def from_ts(cls, ts: float) -> Self:
|
|
160
|
+
"""Create a SessionTime from a seconds elapsed since midnight timestamp.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
ts: Seconds since midnight (can be fractional).
|
|
164
|
+
Returns:
|
|
165
|
+
SessionTime instance corresponding to the provided timestamp.
|
|
166
|
+
Raises:
|
|
167
|
+
ValueError: If the timestamp is negative or exceeds the number of seconds in a day.
|
|
168
|
+
"""
|
|
169
|
+
...
|
|
170
|
+
|
|
171
|
+
@classmethod
|
|
172
|
+
def from_timestamp(cls, unix_ts: float) -> Self: ...
|
|
173
|
+
|
|
174
|
+
def to_pytime(self) -> datetime.time: ...
|
|
175
|
+
|
|
176
|
+
def isoformat(self, *args, **kwargs) -> str: ...
|
|
177
|
+
|
|
178
|
+
@classmethod
|
|
179
|
+
def fromisoformat(cls, time_str: str) -> Self: ...
|
|
180
|
+
|
|
181
|
+
# ----- Read-only properties -----
|
|
182
|
+
@property
|
|
183
|
+
def hour(self) -> int: ...
|
|
184
|
+
|
|
185
|
+
@property
|
|
186
|
+
def minute(self) -> int: ...
|
|
187
|
+
|
|
188
|
+
@property
|
|
189
|
+
def second(self) -> int: ...
|
|
190
|
+
|
|
191
|
+
@property
|
|
192
|
+
def microsecond(self) -> int: ...
|
|
193
|
+
|
|
194
|
+
@property
|
|
195
|
+
def nanosecond(self) -> int: ...
|
|
196
|
+
|
|
197
|
+
@property
|
|
198
|
+
def elapsed_seconds(self) -> float: ...
|
|
199
|
+
|
|
200
|
+
@property
|
|
201
|
+
def ts(self) -> float: ...
|
|
202
|
+
|
|
203
|
+
@property
|
|
204
|
+
def session_phase(self) -> SessionPhase: ...
|
|
205
|
+
|
|
206
|
+
def __lt__(self, other: TimeLike) -> bool: ...
|
|
207
|
+
|
|
208
|
+
def __le__(self, other: TimeLike) -> bool: ...
|
|
209
|
+
|
|
210
|
+
def __eq__(self, other: TimeLike) -> bool: ...
|
|
211
|
+
|
|
212
|
+
def __ne__(self, other: TimeLike) -> bool: ...
|
|
213
|
+
|
|
214
|
+
def __gt__(self, other: TimeLike) -> bool: ...
|
|
215
|
+
|
|
216
|
+
def __ge__(self, other: TimeLike) -> bool: ...
|
|
217
|
+
|
|
218
|
+
def __sub__(self, other: TimeLike) -> SessionTimeRange: ...
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
class SessionTimeRange(object):
|
|
222
|
+
"""Represents a duration between two :class:`SessionTime` instances.
|
|
223
|
+
|
|
224
|
+
The runtime type is a C-backed struct wrapper which contains an internal
|
|
225
|
+
header with fields ``start``, ``end`` and ``elapsed_seconds``. Instances
|
|
226
|
+
are usually created via subtraction (``end - start``) or by the C APIs.
|
|
227
|
+
"""
|
|
228
|
+
|
|
229
|
+
def __init__(self, start_time: SessionTime, end_time: SessionTime) -> None: ...
|
|
230
|
+
|
|
231
|
+
@property
|
|
232
|
+
def elapsed_seconds(self) -> float: ...
|
|
233
|
+
|
|
234
|
+
@property
|
|
235
|
+
def start_time(self) -> SessionTime: ...
|
|
236
|
+
|
|
237
|
+
@property
|
|
238
|
+
def end_time(self) -> SessionTime: ...
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
DateLike = SessionDate | datetime.date
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
class SessionDate(datetime.date):
|
|
245
|
+
"""Represents a calendar date in the exchange profile.
|
|
246
|
+
|
|
247
|
+
``SessionDate`` subclasses ``datetime.date`` and mirrors a C-backed
|
|
248
|
+
``session_date_t`` header used by exchange-profile operations. Because
|
|
249
|
+
``datetime.date`` allocates its date payload in ``__new__`` at the C level,
|
|
250
|
+
a ``SessionDate`` can exist in two distinct states depending on whether
|
|
251
|
+
``__init__`` was executed.
|
|
252
|
+
|
|
253
|
+
Fully initialized (bound):
|
|
254
|
+
Both the Python date payload and the internal C header pointer are
|
|
255
|
+
valid. Created via ``SessionDate(year, month, day)`` or any class
|
|
256
|
+
factory (``from_pydate``, ``from_unix``, ``from_ordinal``,
|
|
257
|
+
``fromisoformat``, ``fromisocalendar``, ``today``)::
|
|
258
|
+
|
|
259
|
+
>>> sd = SessionDate(2024, 11, 11)
|
|
260
|
+
>>> repr(sd)
|
|
261
|
+
'<SessionDate>(2024-11-11)'
|
|
262
|
+
>>> sd.addr
|
|
263
|
+
'0x55b3aff65a10'
|
|
264
|
+
|
|
265
|
+
Partially initialized (unbound):
|
|
266
|
+
The Python date payload is valid (``year``/``month``/``day`` readable),
|
|
267
|
+
but the internal C header pointer is null. Arises when only ``__new__``
|
|
268
|
+
runs without ``__init__``, for example via ``SessionDate.__new__(...)``
|
|
269
|
+
or inherited ``datetime.date`` classmethods that are not overridden::
|
|
270
|
+
|
|
271
|
+
>>> partial_sd = SessionDate.__new__(SessionDate, 2024, 11, 11)
|
|
272
|
+
>>> repr(partial_sd)
|
|
273
|
+
'<SessionDate Unbound>(2024-11-11)'
|
|
274
|
+
>>> partial_sd.addr
|
|
275
|
+
'0x0'
|
|
276
|
+
|
|
277
|
+
For an unbound SessionDate instance, calling any method that relies on the internal C header
|
|
278
|
+
(e.g. ``to_pydate()``, ``to_ordinal()``, ``is_valid()``, ``session_type``, etc.) will automatically call ``c_sync()`` cython internal method,
|
|
279
|
+
which will attempt to initialize the C header based on the Python date payload.
|
|
280
|
+
|
|
281
|
+
Unbound instance has a different __hash__ value, dict lookup will treat it as a different key.
|
|
282
|
+
For a consistent behavior, it is recommended to always use the fully initialized (bound) SessionDate instances.
|
|
283
|
+
The only known way to create unbound instances is via ``SessionDate.__new__``. All other methods are tested to return fully bound instances.
|
|
284
|
+
Use ``test.exchange_profile.test_03_c_exchange_profile_date_initialization_contract`` to verify the expected behavior across different python major versions.
|
|
285
|
+
``datetime.date`` API is not within Limited-ABI, and is subjected to change across python versions, use with caution.
|
|
286
|
+
|
|
287
|
+
``SessionDateEx`` provides a implementation of SessionDate that does not rely on ``datetime.date``.
|
|
288
|
+
For cross-platform / version programming, it may be safer to use ``SessionDateEx`` instead of ``SessionDate``.
|
|
289
|
+
"""
|
|
290
|
+
|
|
291
|
+
def __init__(self, year: int, month: int, day: int) -> None: ...
|
|
292
|
+
|
|
293
|
+
def __hash__(self) -> int: ...
|
|
294
|
+
|
|
295
|
+
@overload
|
|
296
|
+
def __sub__(self, other: timedelta) -> SessionDate: ...
|
|
297
|
+
|
|
298
|
+
@overload
|
|
299
|
+
def __sub__(self, other: DateLike) -> SessionDateRange: ...
|
|
300
|
+
|
|
301
|
+
def __sub__(self, other): ...
|
|
302
|
+
|
|
303
|
+
def __rsub__(self, other: DateLike) -> SessionDateRange: ...
|
|
304
|
+
|
|
305
|
+
def __lt__(self, other: DateLike) -> bool: ...
|
|
306
|
+
|
|
307
|
+
def __le__(self, other: DateLike) -> bool: ...
|
|
308
|
+
|
|
309
|
+
def __eq__(self, other: DateLike) -> bool: ...
|
|
310
|
+
|
|
311
|
+
def __ne__(self, other: DateLike) -> bool: ...
|
|
312
|
+
|
|
313
|
+
def __gt__(self, other: DateLike) -> bool: ...
|
|
314
|
+
|
|
315
|
+
def __ge__(self, other: DateLike) -> bool: ...
|
|
316
|
+
|
|
317
|
+
@staticmethod
|
|
318
|
+
def is_leap_year(year: int) -> bool: ...
|
|
319
|
+
|
|
320
|
+
@staticmethod
|
|
321
|
+
def days_in_month(year: int, month: int) -> int: ...
|
|
322
|
+
|
|
323
|
+
@classmethod
|
|
324
|
+
def today(cls) -> SessionDate: ...
|
|
325
|
+
|
|
326
|
+
@classmethod
|
|
327
|
+
def from_unix(cls, unix_ts: float) -> SessionDate: ...
|
|
328
|
+
|
|
329
|
+
@classmethod
|
|
330
|
+
def from_ordinal(cls, ordinal: int) -> SessionDate: ...
|
|
331
|
+
|
|
332
|
+
@classmethod
|
|
333
|
+
def from_pydate(cls, dt: datetime.date) -> SessionDate: ...
|
|
334
|
+
|
|
335
|
+
def to_pydate(self) -> datetime.date: ...
|
|
336
|
+
|
|
337
|
+
def to_ordinal(self) -> int: ...
|
|
338
|
+
|
|
339
|
+
def add_days(self, days: int) -> SessionDate: ...
|
|
340
|
+
|
|
341
|
+
def is_valid(self) -> bool: ...
|
|
342
|
+
|
|
343
|
+
def is_weekend(self) -> bool: ...
|
|
344
|
+
|
|
345
|
+
def fork(self) -> SessionDate:
|
|
346
|
+
"""Create a new SessionDate instance with the same underlying C struct (not owned), but a separate Python wrapper."""
|
|
347
|
+
...
|
|
348
|
+
|
|
349
|
+
@classmethod
|
|
350
|
+
def fromisocalendar(cls, year: int, week: int, weekday: int) -> SessionDate: ...
|
|
351
|
+
|
|
352
|
+
@classmethod
|
|
353
|
+
def fromisoformat(cls, date_str: str) -> SessionDate: ...
|
|
354
|
+
|
|
355
|
+
def isocalendar(self) -> tuple[int, int, int]: ...
|
|
356
|
+
|
|
357
|
+
def isoformat(self, *args, **kwargs) -> str: ...
|
|
358
|
+
|
|
359
|
+
def strftime(self, format: str) -> str: ...
|
|
360
|
+
|
|
361
|
+
def weekday(self) -> int: ...
|
|
362
|
+
|
|
363
|
+
def timestamp(self) -> float:
|
|
364
|
+
"""Return the UNIX timestamp (seconds since epoch) corresponding to this date at midnight in the profile's local time zone."""
|
|
365
|
+
...
|
|
366
|
+
|
|
367
|
+
@property
|
|
368
|
+
def year(self) -> int: ...
|
|
369
|
+
|
|
370
|
+
@property
|
|
371
|
+
def month(self) -> int: ...
|
|
372
|
+
|
|
373
|
+
@property
|
|
374
|
+
def day(self) -> int: ...
|
|
375
|
+
|
|
376
|
+
@property
|
|
377
|
+
def session_type(self) -> SessionType: ...
|
|
378
|
+
|
|
379
|
+
@property
|
|
380
|
+
def addr(self) -> str:
|
|
381
|
+
"""Return the memory address of the underlying C struct as a hex string (for debugging purposes)."""
|
|
382
|
+
...
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
DateLikeStandalone = SessionDateEx | DateLike
|
|
386
|
+
|
|
387
|
+
|
|
388
|
+
class SessionDateEx(object):
|
|
389
|
+
"""A standalone implementation of SessionDate that does not rely on datetime.date.
|
|
390
|
+
Most of the signature is the same as ``SessionDate``, but without ``fork()`` and ``.addr`` property.
|
|
391
|
+
And it is guaranteed to have valid ``session_date_t* header`` initialized.
|
|
392
|
+
"""
|
|
393
|
+
|
|
394
|
+
def __init__(self, year: int, month: int, day: int) -> None: ...
|
|
395
|
+
|
|
396
|
+
def __hash__(self) -> int: ...
|
|
397
|
+
|
|
398
|
+
def __format__(self, format_spec: str) -> str: ...
|
|
399
|
+
|
|
400
|
+
@overload
|
|
401
|
+
def __sub__(self, other: timedelta) -> SessionDateEx: ...
|
|
402
|
+
|
|
403
|
+
@overload
|
|
404
|
+
def __sub__(self, other: DateLikeStandalone) -> SessionDateRange: ...
|
|
405
|
+
|
|
406
|
+
def __sub__(self, other): ...
|
|
407
|
+
|
|
408
|
+
def __rsub__(self, other: DateLikeStandalone) -> SessionDateRange: ...
|
|
409
|
+
|
|
410
|
+
def __add__(self, other: timedelta) -> SessionDateEx: ...
|
|
411
|
+
|
|
412
|
+
def __iadd__(self, other: timedelta) -> Self: ...
|
|
413
|
+
|
|
414
|
+
def __lt__(self, other: DateLikeStandalone) -> bool: ...
|
|
415
|
+
|
|
416
|
+
def __le__(self, other: DateLikeStandalone) -> bool: ...
|
|
417
|
+
|
|
418
|
+
def __eq__(self, other: DateLikeStandalone) -> bool: ...
|
|
419
|
+
|
|
420
|
+
def __ne__(self, other: DateLikeStandalone) -> bool: ...
|
|
421
|
+
|
|
422
|
+
def __gt__(self, other: DateLikeStandalone) -> bool: ...
|
|
423
|
+
|
|
424
|
+
def __ge__(self, other: DateLikeStandalone) -> bool: ...
|
|
425
|
+
|
|
426
|
+
@staticmethod
|
|
427
|
+
def is_leap_year(year: int) -> bool: ...
|
|
428
|
+
|
|
429
|
+
@staticmethod
|
|
430
|
+
def days_in_month(year: int, month: int) -> int: ...
|
|
431
|
+
|
|
432
|
+
@classmethod
|
|
433
|
+
def today(cls) -> SessionDateEx: ...
|
|
434
|
+
|
|
435
|
+
@classmethod
|
|
436
|
+
def from_unix(cls, unix_ts: float) -> SessionDateEx: ...
|
|
437
|
+
|
|
438
|
+
@classmethod
|
|
439
|
+
def from_ordinal(cls, ordinal: int) -> SessionDateEx: ...
|
|
440
|
+
|
|
441
|
+
@classmethod
|
|
442
|
+
def from_pydate(cls, dt: datetime.date) -> SessionDateEx: ...
|
|
443
|
+
|
|
444
|
+
def to_pydate(self) -> datetime.date: ...
|
|
445
|
+
|
|
446
|
+
def to_ordinal(self) -> int: ...
|
|
447
|
+
|
|
448
|
+
def add_days(self, days: int) -> SessionDateEx: ...
|
|
449
|
+
|
|
450
|
+
def is_valid(self) -> bool: ...
|
|
451
|
+
|
|
452
|
+
def is_weekend(self) -> bool: ...
|
|
453
|
+
|
|
454
|
+
def fork(self) -> SessionDateEx:
|
|
455
|
+
"""Create a new SessionDateEx instance with the same underlying C struct (not owned), but a separate Python wrapper."""
|
|
456
|
+
...
|
|
457
|
+
|
|
458
|
+
def ctime(self) -> str: ...
|
|
459
|
+
|
|
460
|
+
@classmethod
|
|
461
|
+
def fromisocalendar(cls, year: int, week: int, weekday: int) -> SessionDateEx: ...
|
|
462
|
+
|
|
463
|
+
@classmethod
|
|
464
|
+
def fromisoformat(cls, date_str: str) -> SessionDateEx: ...
|
|
465
|
+
|
|
466
|
+
def isocalendar(self) -> tuple[int, int, int]: ...
|
|
467
|
+
|
|
468
|
+
def isoformat(self, *args, **kwargs) -> str: ...
|
|
469
|
+
|
|
470
|
+
def strftime(self, format: str) -> str: ...
|
|
471
|
+
|
|
472
|
+
def weekday(self) -> int: ...
|
|
473
|
+
|
|
474
|
+
def timestamp(self) -> float: ...
|
|
475
|
+
|
|
476
|
+
@property
|
|
477
|
+
def year(self) -> int: ...
|
|
478
|
+
|
|
479
|
+
@property
|
|
480
|
+
def month(self) -> int: ...
|
|
481
|
+
|
|
482
|
+
@property
|
|
483
|
+
def day(self) -> int: ...
|
|
484
|
+
|
|
485
|
+
@property
|
|
486
|
+
def session_type(self) -> SessionType: ...
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
class SessionDateRange(object):
|
|
490
|
+
"""Represents a contiguous range of :class:`SessionDate` instances.
|
|
491
|
+
|
|
492
|
+
Constructed from a start and end :class:`SessionDate`. Exposes length via
|
|
493
|
+
``n_days``, sequence access and iteration.
|
|
494
|
+
"""
|
|
495
|
+
|
|
496
|
+
def __init__(self, start_date: SessionDate, end_date: SessionDate) -> None: ...
|
|
497
|
+
|
|
498
|
+
def __iter__(self): ...
|
|
499
|
+
|
|
500
|
+
def __getitem__(self, idx: int) -> SessionDate: ...
|
|
501
|
+
|
|
502
|
+
def __contains__(self, item: DateLike) -> bool: ...
|
|
503
|
+
|
|
504
|
+
def __len__(self) -> int: ...
|
|
505
|
+
|
|
506
|
+
def index(self, item: DateLike) -> int: ...
|
|
507
|
+
|
|
508
|
+
def to_list(self) -> list[datetime.date]:
|
|
509
|
+
"""Convert the SessionDateRange to a list of datetime.date objects.
|
|
510
|
+
|
|
511
|
+
Returns:
|
|
512
|
+
List[datetime.date]: A list of datetime.date instances corresponding to the session dates in the range.
|
|
513
|
+
"""
|
|
514
|
+
...
|
|
515
|
+
|
|
516
|
+
@property
|
|
517
|
+
def n_days(self) -> int: ...
|
|
518
|
+
|
|
519
|
+
@property
|
|
520
|
+
def start_date(self) -> SessionDate: ...
|
|
521
|
+
|
|
522
|
+
@property
|
|
523
|
+
def end_date(self) -> SessionDate: ...
|
|
524
|
+
|
|
525
|
+
@property
|
|
526
|
+
def dates(self) -> tuple[SessionDate, ...]: ...
|
|
527
|
+
|
|
528
|
+
|
|
529
|
+
class SessionDateTime(object):
|
|
530
|
+
"""A combined date and time representation for exchange sessions.
|
|
531
|
+
Simplest wrapper around a C struct that contains a SessionDate and SessionTime.
|
|
532
|
+
"""
|
|
533
|
+
|
|
534
|
+
@classmethod
|
|
535
|
+
def from_pydatetime(cls, t: datetime.datetime) -> SessionDateTime: ...
|
|
536
|
+
|
|
537
|
+
def to_pydatetime(self) -> datetime.datetime: ...
|
|
538
|
+
|
|
539
|
+
def fork(self):
|
|
540
|
+
"""Create a new SessionDateTime instance with the same underlying C struct (not owned), but a separate Python wrapper."""
|
|
541
|
+
...
|
|
542
|
+
|
|
543
|
+
def update(self, unix_ts: float) -> Self:
|
|
544
|
+
"""Update the date and time based on a new UNIX timestamp, modifying the current instance in-place.
|
|
545
|
+
|
|
546
|
+
This method allows reusing the same SessionDateTime wrapper to point to different instants in time by updating its internal C struct with a new timestamp. The date and time properties will reflect the new timestamp after the update.
|
|
547
|
+
|
|
548
|
+
Args:
|
|
549
|
+
unix_ts: The new UNIX timestamp to update the SessionDateTime to.
|
|
550
|
+
Returns:
|
|
551
|
+
Self: The updated SessionDateTime instance (same wrapper, updated internal state).
|
|
552
|
+
"""
|
|
553
|
+
...
|
|
554
|
+
|
|
555
|
+
@classmethod
|
|
556
|
+
def from_unix(cls, unix_ts: float) -> SessionDateTime: ...
|
|
557
|
+
|
|
558
|
+
@property
|
|
559
|
+
def time(self) -> SessionTime: ...
|
|
560
|
+
|
|
561
|
+
@property
|
|
562
|
+
def date(self) -> SessionDateEx: ...
|
|
563
|
+
|
|
564
|
+
@property
|
|
565
|
+
def timestamp(self) -> float:
|
|
566
|
+
"""Return the cached UNIX timestamp."""
|
|
567
|
+
...
|
|
568
|
+
|
|
569
|
+
@property
|
|
570
|
+
def ts(self) -> float:
|
|
571
|
+
"""Return the cached total seconds since midnight."""
|
|
572
|
+
...
|
|
573
|
+
|
|
574
|
+
@property
|
|
575
|
+
def ordinal(self) -> int:
|
|
576
|
+
"""Return the cached ordinal of the date."""
|
|
577
|
+
...
|
|
578
|
+
|
|
579
|
+
|
|
580
|
+
class CallAuction(object):
|
|
581
|
+
"""Call auction metadata describing auction windows inside a trading day.
|
|
582
|
+
|
|
583
|
+
Lightweight wrapper around the C `call_auction` structure.
|
|
584
|
+
"""
|
|
585
|
+
|
|
586
|
+
@property
|
|
587
|
+
def auction_start(self) -> SessionTime:
|
|
588
|
+
"""The scheduled auction start time."""
|
|
589
|
+
...
|
|
590
|
+
|
|
591
|
+
@property
|
|
592
|
+
def active(self) -> SessionTimeRange | None:
|
|
593
|
+
"""Active matching window for the auction, or ``None`` if not present."""
|
|
594
|
+
...
|
|
595
|
+
|
|
596
|
+
@property
|
|
597
|
+
def no_cancel(self) -> SessionTimeRange | None:
|
|
598
|
+
"""No-cancel window during the auction, or ``None`` if not present."""
|
|
599
|
+
...
|
|
600
|
+
|
|
601
|
+
@property
|
|
602
|
+
def frozen(self) -> SessionTimeRange | None:
|
|
603
|
+
"""Frozen period for the auction, or ``None`` if not present."""
|
|
604
|
+
...
|
|
605
|
+
|
|
606
|
+
@property
|
|
607
|
+
def uncross(self) -> SessionTime:
|
|
608
|
+
"""The uncrossing instant as a :class:`SessionTime`."""
|
|
609
|
+
...
|
|
610
|
+
|
|
611
|
+
@property
|
|
612
|
+
def auction_end(self) -> SessionTime:
|
|
613
|
+
"""The scheduled auction end time."""
|
|
614
|
+
...
|
|
615
|
+
|
|
616
|
+
|
|
617
|
+
class SessionBreak(object):
|
|
618
|
+
"""Represents a break interval inside a session.
|
|
619
|
+
|
|
620
|
+
Lightweight wrapper around the C ``session_break`` linked-list node.
|
|
621
|
+
"""
|
|
622
|
+
|
|
623
|
+
@property
|
|
624
|
+
def break_start(self) -> SessionTime:
|
|
625
|
+
"""Start time of the break."""
|
|
626
|
+
...
|
|
627
|
+
|
|
628
|
+
@property
|
|
629
|
+
def break_end(self) -> SessionTime:
|
|
630
|
+
"""End time of the break."""
|
|
631
|
+
...
|
|
632
|
+
|
|
633
|
+
@property
|
|
634
|
+
def break_start_ts(self) -> float:
|
|
635
|
+
"""Cached timestamp (seconds from midnight) for break start."""
|
|
636
|
+
...
|
|
637
|
+
|
|
638
|
+
@property
|
|
639
|
+
def break_end_ts(self) -> float:
|
|
640
|
+
"""Cached timestamp (seconds from midnight) for break end."""
|
|
641
|
+
...
|
|
642
|
+
|
|
643
|
+
@property
|
|
644
|
+
def break_length_seconds(self) -> float:
|
|
645
|
+
"""Precomputed break length in seconds."""
|
|
646
|
+
...
|
|
647
|
+
|
|
648
|
+
@property
|
|
649
|
+
def next(self) -> SessionBreak | None:
|
|
650
|
+
"""Link to the next break, or ``None``."""
|
|
651
|
+
...
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
TS_LIKE = datetime.time | float | int
|
|
655
|
+
|
|
656
|
+
|
|
657
|
+
class ExchangeProfile(object):
|
|
658
|
+
"""Represents an exchange profile with session configuration and helpers.
|
|
659
|
+
|
|
660
|
+
This object mirrors the C ``exchange_profile`` struct and provides
|
|
661
|
+
convenience Python methods that dispatch to the underlying C function
|
|
662
|
+
pointers. Instances are typically obtained from module-level globals
|
|
663
|
+
``PROFILE_DEFAULT`` and ``PROFILE_CN`` or via the :meth:`c_from_header`
|
|
664
|
+
factory.
|
|
665
|
+
|
|
666
|
+
Note: Many methods accept both Python-level wrappers (``SessionDate``/
|
|
667
|
+
``SessionTime``) and their standard-library counterparts (``datetime.date``/
|
|
668
|
+
``datetime.time``) for convenience.
|
|
669
|
+
"""
|
|
670
|
+
|
|
671
|
+
def __repr__(self) -> str: ...
|
|
672
|
+
|
|
673
|
+
def activate(self) -> None:
|
|
674
|
+
"""Activate this profile as the global exchange profile for the process/thread.
|
|
675
|
+
|
|
676
|
+
This calls into the C-level activation callback and sets the global
|
|
677
|
+
profile pointer used by other APIs.
|
|
678
|
+
"""
|
|
679
|
+
...
|
|
680
|
+
|
|
681
|
+
def deactivate(self) -> None:
|
|
682
|
+
"""Deactivate this profile and restore the default profile.
|
|
683
|
+
|
|
684
|
+
If this profile is the currently active one the implementation will
|
|
685
|
+
switch back to ``PROFILE_DEFAULT``.
|
|
686
|
+
"""
|
|
687
|
+
...
|
|
688
|
+
|
|
689
|
+
def trade_calendar(self, start_date: DateLike, end_date: DateLike) -> SessionDateRange:
|
|
690
|
+
"""Return a :class:`SessionDateRange` containing trading dates between two dates.
|
|
691
|
+
|
|
692
|
+
Args:
|
|
693
|
+
start_date: inclusive start; may be a :class:`SessionDate` or :class:`datetime.date`.
|
|
694
|
+
end_date: inclusive end; may be a :class:`SessionDate` or :class:`datetime.date`.
|
|
695
|
+
|
|
696
|
+
Returns:
|
|
697
|
+
SessionDateRange: C-backed range object with ``dates`` sequence of :class:`SessionDate`.
|
|
698
|
+
"""
|
|
699
|
+
...
|
|
700
|
+
|
|
701
|
+
def resolve_auction_phase(self, session_time: TimeLike) -> AuctionPhase:
|
|
702
|
+
"""Resolve auction-phase at the provided time-of-day.
|
|
703
|
+
|
|
704
|
+
Args:
|
|
705
|
+
session_time: :class:`SessionTime` or :class:`datetime.time`.
|
|
706
|
+
|
|
707
|
+
Returns:
|
|
708
|
+
AuctionPhase: an enum value representing the auction sub-phase.
|
|
709
|
+
"""
|
|
710
|
+
...
|
|
711
|
+
|
|
712
|
+
def resolve_session_phase(self, session_time: TimeLike) -> SessionPhase:
|
|
713
|
+
"""Resolve high-level session phase at the provided time-of-day (preopen/open/continuous/etc.)."""
|
|
714
|
+
...
|
|
715
|
+
|
|
716
|
+
def resolve_session_type(self, session_date: DateLike) -> SessionType:
|
|
717
|
+
"""Return the :class:`SessionType` for the provided market date.
|
|
718
|
+
|
|
719
|
+
Args:
|
|
720
|
+
session_date: :class:`SessionDate` or :class:`datetime.date`.
|
|
721
|
+
"""
|
|
722
|
+
...
|
|
723
|
+
|
|
724
|
+
def timestamp_to_datetime(self, unix_ts: float) -> datetime.datetime:
|
|
725
|
+
"""Convert a UNIX timestamp to a timezone-aware datetime in the profile's time zone."""
|
|
726
|
+
...
|
|
727
|
+
|
|
728
|
+
def time_to_seconds(self, t: datetime.time, break_adjusted: bool = True) -> float:
|
|
729
|
+
"""Convert a time-of-day to seconds since trading session start.
|
|
730
|
+
|
|
731
|
+
Args:
|
|
732
|
+
t: datetime.time instance representing a clock time in the profile's local zone.
|
|
733
|
+
break_adjusted: If True, subtract non-trading break durations (e.g., lunch break).
|
|
734
|
+
|
|
735
|
+
Returns:
|
|
736
|
+
float: elapsed seconds since session open (breaks excluded when requested) or
|
|
737
|
+
raw seconds-of-day if break_adjusted is False.
|
|
738
|
+
"""
|
|
739
|
+
...
|
|
740
|
+
|
|
741
|
+
def timestamp_to_seconds(self, t: float, break_adjusted: bool = True) -> float:
|
|
742
|
+
"""Convert a UNIX timestamp (seconds) to seconds since session open, optionally break-adjusted."""
|
|
743
|
+
...
|
|
744
|
+
|
|
745
|
+
def break_adjusted(self, elapsed_seconds: float) -> float:
|
|
746
|
+
"""Return the break-adjusted elapsed seconds for a raw seconds-since-midnight value."""
|
|
747
|
+
...
|
|
748
|
+
|
|
749
|
+
def trading_time_between(self, start_time: TS_LIKE, end_time: TS_LIKE) -> float:
|
|
750
|
+
"""Compute total trading seconds between two datetime (or UNIX timestamps).
|
|
751
|
+
|
|
752
|
+
Accepts either naive datetime (interpreted in profile.time_zone) or numeric
|
|
753
|
+
UNIX timestamps. The result is the total trading-time (seconds) excluding
|
|
754
|
+
non-trading periods (e.g., lunch break).
|
|
755
|
+
"""
|
|
756
|
+
...
|
|
757
|
+
|
|
758
|
+
def is_market_session(self, timestamp) -> bool:
|
|
759
|
+
"""Return True if the provided timestamp/time/datetime is in continuous market session.
|
|
760
|
+
|
|
761
|
+
Accepts numeric UNIX timestamps, :class:`datetime.time` or :class:`datetime.datetime`.
|
|
762
|
+
"""
|
|
763
|
+
...
|
|
764
|
+
|
|
765
|
+
def is_auction_session(self, timestamp) -> bool:
|
|
766
|
+
"""Return True if the provided timestamp/time/datetime is in an auction period."""
|
|
767
|
+
...
|
|
768
|
+
|
|
769
|
+
def trading_days_before(self, market_date: datetime.date, days: int) -> datetime.date:
|
|
770
|
+
"""Return the market date that is a given number of trading days before the provided date.
|
|
771
|
+
|
|
772
|
+
If the provided date is not a trading day, it will be treated as if it were the nearest **NEXT** trading day.
|
|
773
|
+
That is, if days == 1 and the provided date is SAT or SUN, the result will be FRI, not THU.
|
|
774
|
+
"""
|
|
775
|
+
...
|
|
776
|
+
|
|
777
|
+
def trading_days_after(self, market_date: datetime.date, days: int) -> datetime.date:
|
|
778
|
+
"""Return the market date that is a given number of trading days after the provided date.
|
|
779
|
+
|
|
780
|
+
If the provided date is not a trading day, it will be treated as if it were the nearest **PREVIOUS** trading day.
|
|
781
|
+
That is, if days == 1 and the provided date is SAT or SUN, the result will be MON, not TUE.
|
|
782
|
+
"""
|
|
783
|
+
...
|
|
784
|
+
|
|
785
|
+
def trading_days_between(self, start_date: datetime.date, end_date: datetime.date) -> int:
|
|
786
|
+
"""Return the number of trading days between two market dates (inclusive)."""
|
|
787
|
+
...
|
|
788
|
+
|
|
789
|
+
def nearest_trading_date(self, market_date: datetime.date, method: str = 'previous') -> datetime.date:
|
|
790
|
+
"""Return the nearest trading date to the provided date.
|
|
791
|
+
|
|
792
|
+
Args:
|
|
793
|
+
market_date: The reference date for which to find the nearest trading date.
|
|
794
|
+
method: Method to resolve ties when the provided date is exactly between two trading days. Options are 'previous' (default) or 'next'.
|
|
795
|
+
|
|
796
|
+
Returns:
|
|
797
|
+
datetime.date: The nearest trading date to the provided date.
|
|
798
|
+
"""
|
|
799
|
+
...
|
|
800
|
+
|
|
801
|
+
def is_trading_day(self, market_date: datetime.date) -> bool: ...
|
|
802
|
+
|
|
803
|
+
@property
|
|
804
|
+
def profile_id(self) -> str:
|
|
805
|
+
"""Unique identifier for the profile (e.g. "UTC_NONSTOP_DEFAULT" (the default one), "CN_STOCK")."""
|
|
806
|
+
...
|
|
807
|
+
|
|
808
|
+
@property
|
|
809
|
+
def session_start(self) -> SessionTime:
|
|
810
|
+
"""Continuous session start time."""
|
|
811
|
+
...
|
|
812
|
+
|
|
813
|
+
@property
|
|
814
|
+
def session_end(self) -> SessionTime:
|
|
815
|
+
"""Continuous session end time."""
|
|
816
|
+
...
|
|
817
|
+
|
|
818
|
+
@property
|
|
819
|
+
def open_call_auction(self) -> CallAuction | None:
|
|
820
|
+
"""Open call auction metadata (maybe ``None``)."""
|
|
821
|
+
...
|
|
822
|
+
|
|
823
|
+
@property
|
|
824
|
+
def close_call_auction(self) -> CallAuction | None:
|
|
825
|
+
"""Close call auction metadata (maybe ``None``)."""
|
|
826
|
+
...
|
|
827
|
+
|
|
828
|
+
@property
|
|
829
|
+
def session_breaks(self) -> tuple[SessionBreak, ...]:
|
|
830
|
+
"""Tuple of :class:`SessionBreak` describing intraday breaks."""
|
|
831
|
+
...
|
|
832
|
+
|
|
833
|
+
@property
|
|
834
|
+
def time_zone(self) -> datetime.timezone:
|
|
835
|
+
"""IANA time zone as a :class:`zoneinfo.datetime.timezone` instance.
|
|
836
|
+
|
|
837
|
+
The live implementation returns a datetime.timezone object which can be used
|
|
838
|
+
to construct timezone-aware datetime for timestamp conversions.
|
|
839
|
+
"""
|
|
840
|
+
...
|
|
841
|
+
|
|
842
|
+
@property
|
|
843
|
+
def session_start_ts(self) -> float: ...
|
|
844
|
+
|
|
845
|
+
@property
|
|
846
|
+
def session_end_ts(self) -> float: ...
|
|
847
|
+
|
|
848
|
+
@property
|
|
849
|
+
def session_length_seconds(self) -> float: ...
|
|
850
|
+
|
|
851
|
+
@property
|
|
852
|
+
def tz_offset_seconds(self) -> float: ...
|
|
853
|
+
|
|
854
|
+
@property
|
|
855
|
+
def range_break(self) -> list[dict]:
|
|
856
|
+
"""Return a list of range break dicts for Plotly X-axis configuration based on the session breaks of the currently active exchange profile."""
|
|
857
|
+
...
|
|
858
|
+
|
|
859
|
+
@property
|
|
860
|
+
def trade_calendar_cache(self) -> SessionDateRange | None:
|
|
861
|
+
"""Return a cached SessionDateRange for the current active exchange profile, or None."""
|
|
862
|
+
...
|
|
863
|
+
|
|
864
|
+
|
|
865
|
+
PROFILE: ExchangeProfile
|
|
866
|
+
PROFILE_DEFAULT: ExchangeProfile
|
|
867
|
+
PROFILE_CN: ExchangeProfile
|