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.
Files changed (156) hide show
  1. algo_engine/__infra__.pxd +3 -0
  2. algo_engine/__init__.pxd +3 -0
  3. algo_engine/__init__.py +91 -0
  4. algo_engine/apps/__init__.py +17 -0
  5. algo_engine/apps/backtest/__init__.py +20 -0
  6. algo_engine/apps/backtest/doc_server.py +328 -0
  7. algo_engine/apps/backtest/static/styles/dash.css +48 -0
  8. algo_engine/apps/backtest/templates/dash.html +20 -0
  9. algo_engine/apps/backtest/templates/index.html +40 -0
  10. algo_engine/apps/backtest/tester.py +252 -0
  11. algo_engine/apps/backtest/web_app.py +125 -0
  12. algo_engine/apps/bokeh_server.py +245 -0
  13. algo_engine/apps/demo/__init__.py +0 -0
  14. algo_engine/apps/demo/test.py +40 -0
  15. algo_engine/apps/sim_input/__init__.py +23 -0
  16. algo_engine/apps/sim_input/client.py +412 -0
  17. algo_engine/apps/sim_input/sim_keyboard.py +88 -0
  18. algo_engine/apps/sim_input/sim_mouse.py +137 -0
  19. algo_engine/apps/sim_input/window.py +162 -0
  20. algo_engine/backtest/__init__.py +19 -0
  21. algo_engine/backtest/__main__.py +51 -0
  22. algo_engine/backtest/metrics.py +179 -0
  23. algo_engine/backtest/replay.py +635 -0
  24. algo_engine/backtest/sim_match.py +506 -0
  25. algo_engine/base/__infra__.pxd +3 -0
  26. algo_engine/base/__init__.pxd +3 -0
  27. algo_engine/base/__init__.py +60 -0
  28. algo_engine/base/c_allocator_protocol.c +10756 -0
  29. algo_engine/base/c_allocator_protocol.cp313-win_amd64.pyd +0 -0
  30. algo_engine/base/c_allocator_protocol.pxd +24 -0
  31. algo_engine/base/c_allocator_protocol.pyi +68 -0
  32. algo_engine/base/c_allocator_protocol.pyx +88 -0
  33. algo_engine/base/c_intern_string.c +5845 -0
  34. algo_engine/base/c_intern_string.cp313-win_amd64.pyd +0 -0
  35. algo_engine/base/c_intern_string.pxd +14 -0
  36. algo_engine/base/c_intern_string.pyi +22 -0
  37. algo_engine/base/c_intern_string.pyx +17 -0
  38. algo_engine/base/c_market_data/__infra__.pxd +196 -0
  39. algo_engine/base/c_market_data/__init__.pxd +196 -0
  40. algo_engine/base/c_market_data/__init__.py +24 -0
  41. algo_engine/base/c_market_data/c_candlestick.c +18960 -0
  42. algo_engine/base/c_market_data/c_candlestick.cp313-win_amd64.pyd +0 -0
  43. algo_engine/base/c_market_data/c_candlestick.pxd +27 -0
  44. algo_engine/base/c_market_data/c_candlestick.pyi +217 -0
  45. algo_engine/base/c_market_data/c_candlestick.pyx +255 -0
  46. algo_engine/base/c_market_data/c_internal.c +14023 -0
  47. algo_engine/base/c_market_data/c_internal.cp313-win_amd64.pyd +0 -0
  48. algo_engine/base/c_market_data/c_internal.pxd +14 -0
  49. algo_engine/base/c_market_data/c_internal.pyi +47 -0
  50. algo_engine/base/c_market_data/c_internal.pyx +41 -0
  51. algo_engine/base/c_market_data/c_market_data.c +30739 -0
  52. algo_engine/base/c_market_data/c_market_data.cp313-win_amd64.pyd +0 -0
  53. algo_engine/base/c_market_data/c_market_data.h +1464 -0
  54. algo_engine/base/c_market_data/c_market_data.pxd +418 -0
  55. algo_engine/base/c_market_data/c_market_data.pyi +550 -0
  56. algo_engine/base/c_market_data/c_market_data.pyx +688 -0
  57. algo_engine/base/c_market_data/c_market_data_buffer.c +29370 -0
  58. algo_engine/base/c_market_data/c_market_data_buffer.cp313-win_amd64.pyd +0 -0
  59. algo_engine/base/c_market_data/c_market_data_buffer.h +941 -0
  60. algo_engine/base/c_market_data/c_market_data_buffer.pxd +143 -0
  61. algo_engine/base/c_market_data/c_market_data_buffer.pyi +355 -0
  62. algo_engine/base/c_market_data/c_market_data_buffer.pyx +571 -0
  63. algo_engine/base/c_market_data/c_market_data_config.h +29 -0
  64. algo_engine/base/c_market_data/c_tick.c +44230 -0
  65. algo_engine/base/c_market_data/c_tick.cp313-win_amd64.pyd +0 -0
  66. algo_engine/base/c_market_data/c_tick.pxd +53 -0
  67. algo_engine/base/c_market_data/c_tick.pyi +466 -0
  68. algo_engine/base/c_market_data/c_tick.pyx +673 -0
  69. algo_engine/base/c_market_data/c_trade_utils.c +28665 -0
  70. algo_engine/base/c_market_data/c_trade_utils.cp313-win_amd64.pyd +0 -0
  71. algo_engine/base/c_market_data/c_trade_utils.pxd +53 -0
  72. algo_engine/base/c_market_data/c_trade_utils.pyi +602 -0
  73. algo_engine/base/c_market_data/c_trade_utils.pyx +609 -0
  74. algo_engine/base/c_market_data/c_transaction.c +23521 -0
  75. algo_engine/base/c_market_data/c_transaction.cp313-win_amd64.pyd +0 -0
  76. algo_engine/base/c_market_data/c_transaction.pxd +27 -0
  77. algo_engine/base/c_market_data/c_transaction.pyi +433 -0
  78. algo_engine/base/c_market_data/c_transaction.pyx +460 -0
  79. algo_engine/base/console_utils.py +1070 -0
  80. algo_engine/base/finance_decimal.py +258 -0
  81. algo_engine/base/telemetrics.py +104 -0
  82. algo_engine/engine/__infra__.pxd +10 -0
  83. algo_engine/engine/__init__.pxd +10 -0
  84. algo_engine/engine/__init__.py +40 -0
  85. algo_engine/engine/algo_engine.py +904 -0
  86. algo_engine/engine/c_event_engine.c +16289 -0
  87. algo_engine/engine/c_event_engine.cp313-win_amd64.pyd +0 -0
  88. algo_engine/engine/c_event_engine.pxd +25 -0
  89. algo_engine/engine/c_event_engine.pyi +68 -0
  90. algo_engine/engine/c_market_engine.c +24222 -0
  91. algo_engine/engine/c_market_engine.cp313-win_amd64.pyd +0 -0
  92. algo_engine/engine/c_market_engine.pxd +87 -0
  93. algo_engine/engine/c_market_engine.pyi +357 -0
  94. algo_engine/engine/event_engine.py +53 -0
  95. algo_engine/engine/trade_engine.py +2037 -0
  96. algo_engine/exchange_profile/__infra__.pxd +99 -0
  97. algo_engine/exchange_profile/__init__.pxd +99 -0
  98. algo_engine/exchange_profile/__init__.py +36 -0
  99. algo_engine/exchange_profile/c_ex_profile_base.c +87 -0
  100. algo_engine/exchange_profile/c_ex_profile_base.h +1148 -0
  101. algo_engine/exchange_profile/c_ex_profile_cn.c +968 -0
  102. algo_engine/exchange_profile/c_ex_profile_cn.h +39 -0
  103. algo_engine/exchange_profile/c_exchange_profile.c +52061 -0
  104. algo_engine/exchange_profile/c_exchange_profile.cp313-win_amd64.pyd +0 -0
  105. algo_engine/exchange_profile/c_exchange_profile.pxd +336 -0
  106. algo_engine/exchange_profile/c_exchange_profile.pyi +867 -0
  107. algo_engine/exchange_profile/c_exchange_profile.pyx +1482 -0
  108. algo_engine/exchange_profile/c_profile_cn.c +7779 -0
  109. algo_engine/exchange_profile/c_profile_cn.cp313-win_amd64.pyd +0 -0
  110. algo_engine/exchange_profile/c_profile_cn.pxd +1 -0
  111. algo_engine/exchange_profile/c_profile_cn.pyi +3 -0
  112. algo_engine/exchange_profile/c_profile_cn.pyx +1 -0
  113. algo_engine/exchange_profile/c_profile_default.c +7779 -0
  114. algo_engine/exchange_profile/c_profile_default.cp313-win_amd64.pyd +0 -0
  115. algo_engine/exchange_profile/c_profile_default.pxd +1 -0
  116. algo_engine/exchange_profile/c_profile_default.pyi +3 -0
  117. algo_engine/exchange_profile/c_profile_default.pyx +1 -0
  118. algo_engine/exchange_profile/c_profile_dispatcher.c +7779 -0
  119. algo_engine/exchange_profile/c_profile_dispatcher.cp313-win_amd64.pyd +0 -0
  120. algo_engine/exchange_profile/c_profile_dispatcher.pxd +1 -0
  121. algo_engine/exchange_profile/c_profile_dispatcher.pyi +3 -0
  122. algo_engine/exchange_profile/c_profile_dispatcher.pyx +1 -0
  123. algo_engine/includes/algo_engine/base/c_allocator_protocol.c +10756 -0
  124. algo_engine/includes/algo_engine/base/c_intern_string.c +5845 -0
  125. algo_engine/includes/algo_engine/base/c_market_data/c_candlestick.c +18960 -0
  126. algo_engine/includes/algo_engine/base/c_market_data/c_internal.c +14023 -0
  127. algo_engine/includes/algo_engine/base/c_market_data/c_market_data.c +30739 -0
  128. algo_engine/includes/algo_engine/base/c_market_data/c_market_data.h +1464 -0
  129. algo_engine/includes/algo_engine/base/c_market_data/c_market_data_buffer.c +29370 -0
  130. algo_engine/includes/algo_engine/base/c_market_data/c_market_data_buffer.h +941 -0
  131. algo_engine/includes/algo_engine/base/c_market_data/c_market_data_config.h +29 -0
  132. algo_engine/includes/algo_engine/base/c_market_data/c_tick.c +44230 -0
  133. algo_engine/includes/algo_engine/base/c_market_data/c_trade_utils.c +28665 -0
  134. algo_engine/includes/algo_engine/base/c_market_data/c_transaction.c +23521 -0
  135. algo_engine/includes/algo_engine/engine/c_event_engine.c +16289 -0
  136. algo_engine/includes/algo_engine/engine/c_market_engine.c +24222 -0
  137. algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_base.c +87 -0
  138. algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_base.h +1148 -0
  139. algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_cn.c +968 -0
  140. algo_engine/includes/algo_engine/exchange_profile/c_ex_profile_cn.h +39 -0
  141. algo_engine/includes/algo_engine/exchange_profile/c_exchange_profile.c +52061 -0
  142. algo_engine/includes/algo_engine/exchange_profile/c_profile_cn.c +7779 -0
  143. algo_engine/includes/algo_engine/exchange_profile/c_profile_default.c +7779 -0
  144. algo_engine/includes/algo_engine/exchange_profile/c_profile_dispatcher.c +7779 -0
  145. algo_engine/monitor/__init__.py +15 -0
  146. algo_engine/monitor/advanced_data_interface.py +334 -0
  147. algo_engine/strategy/__init__.py +44 -0
  148. algo_engine/strategy/strategy_engine.py +441 -0
  149. algo_engine/utils/__init__.py +3 -0
  150. algo_engine/utils/commit_regularizer.py +49 -0
  151. algo_engine/utils/data_utils.py +296 -0
  152. pyalgoengine-0.12.0.post3.dist-info/METADATA +142 -0
  153. pyalgoengine-0.12.0.post3.dist-info/RECORD +156 -0
  154. pyalgoengine-0.12.0.post3.dist-info/WHEEL +5 -0
  155. pyalgoengine-0.12.0.post3.dist-info/licenses/LICENSE +21 -0
  156. 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