PyAlgoEngine 0.12.3__cp315-cp315-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 +107 -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 +11608 -0
  29. algo_engine/base/c_allocator_protocol.cp315-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 +111 -0
  33. algo_engine/base/c_intern_string.c +5908 -0
  34. algo_engine/base/c_intern_string.cp315-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 +18996 -0
  42. algo_engine/base/c_market_data/c_candlestick.cp315-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 +14059 -0
  47. algo_engine/base/c_market_data/c_internal.cp315-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 +30420 -0
  52. algo_engine/base/c_market_data/c_market_data.cp315-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 +414 -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 +701 -0
  57. algo_engine/base/c_market_data/c_market_data_buffer.c +29407 -0
  58. algo_engine/base/c_market_data/c_market_data_buffer.cp315-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 +44303 -0
  65. algo_engine/base/c_market_data/c_tick.cp315-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 +28702 -0
  70. algo_engine/base/c_market_data/c_trade_utils.cp315-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 +23558 -0
  75. algo_engine/base/c_market_data/c_transaction.cp315-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 +18 -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 +16325 -0
  87. algo_engine/engine/c_event_engine.cp315-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 +24258 -0
  91. algo_engine/engine/c_market_engine.cp315-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 +100 -0
  97. algo_engine/exchange_profile/__init__.pxd +100 -0
  98. algo_engine/exchange_profile/__init__.py +53 -0
  99. algo_engine/exchange_profile/c_ex_profile_base.c +87 -0
  100. algo_engine/exchange_profile/c_ex_profile_base.h +1204 -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 +52375 -0
  104. algo_engine/exchange_profile/c_exchange_profile.cp315-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 +883 -0
  107. algo_engine/exchange_profile/c_exchange_profile.pyx +1495 -0
  108. algo_engine/exchange_profile/c_profile_cn.c +7798 -0
  109. algo_engine/exchange_profile/c_profile_cn.cp315-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 +7798 -0
  114. algo_engine/exchange_profile/c_profile_default.cp315-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 +7798 -0
  119. algo_engine/exchange_profile/c_profile_dispatcher.cp315-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 +11608 -0
  124. algo_engine/includes/algo_engine/base/c_intern_string.c +5908 -0
  125. algo_engine/includes/algo_engine/base/c_market_data/c_candlestick.c +18996 -0
  126. algo_engine/includes/algo_engine/base/c_market_data/c_internal.c +14059 -0
  127. algo_engine/includes/algo_engine/base/c_market_data/c_market_data.c +30420 -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 +29407 -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 +44303 -0
  133. algo_engine/includes/algo_engine/base/c_market_data/c_trade_utils.c +28702 -0
  134. algo_engine/includes/algo_engine/base/c_market_data/c_transaction.c +23558 -0
  135. algo_engine/includes/algo_engine/engine/c_event_engine.c +16325 -0
  136. algo_engine/includes/algo_engine/engine/c_market_engine.c +24258 -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 +1204 -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 +52375 -0
  142. algo_engine/includes/algo_engine/exchange_profile/c_profile_cn.c +7798 -0
  143. algo_engine/includes/algo_engine/exchange_profile/c_profile_default.c +7798 -0
  144. algo_engine/includes/algo_engine/exchange_profile/c_profile_dispatcher.c +7798 -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.3.dist-info/METADATA +142 -0
  153. pyalgoengine-0.12.3.dist-info/RECORD +156 -0
  154. pyalgoengine-0.12.3.dist-info/WHEEL +5 -0
  155. pyalgoengine-0.12.3.dist-info/licenses/LICENSE +21 -0
  156. pyalgoengine-0.12.3.dist-info/top_level.txt +2 -0
@@ -0,0 +1,87 @@
1
+ from cpython.object cimport PyObject
2
+ from libcpp cimport bool as c_bool
3
+
4
+ from algo_engine.base.c_market_data.c_internal cimport InternalData
5
+ from algo_engine.base.c_market_data.c_market_data cimport MarketData, md_internal, md_variant
6
+ from algo_engine.exchange_profile.c_exchange_profile cimport ExchangeProfile
7
+
8
+
9
+ cdef extern from "Python.h":
10
+ PyObject* PyDict_GetItemString(PyObject* py_dict, const char* key)
11
+ int PyDict_SetItemString(PyObject* py_dict, const char* key, PyObject* val)
12
+ PyObject* PyLong_FromSize_t(size_t v)
13
+ size_t PyLong_AsSize_t(PyObject* pylong)
14
+ PyObject* PyFloat_FromDouble(double v)
15
+
16
+
17
+ cdef class MonitorManager:
18
+ cdef readonly dict monitor
19
+
20
+ cpdef void feed_monitor(self, object monitor_id, MarketData market_data)
21
+
22
+ cdef void c_on_market_data(self, const md_variant* market_data)
23
+
24
+ cpdef void on_market_data(self, MarketData market_data)
25
+
26
+ cpdef void add_monitor(self, object monitor)
27
+
28
+ cpdef void pop_monitor(self, object monitor_id)
29
+
30
+ cpdef void clear_monitors(self)
31
+
32
+ cpdef void start(self)
33
+
34
+ cpdef void stop(self)
35
+
36
+ cpdef void clear(self)
37
+
38
+ cpdef dict get_values(self)
39
+
40
+
41
+ cdef struct mds_subscription:
42
+ const char* ticker
43
+ double last_update
44
+ double last_price
45
+ size_t n_feeds
46
+ c_bool is_subscribed_td
47
+ c_bool is_subscribed_od
48
+ c_bool is_subscribed_tk_lite
49
+ c_bool is_subscribed_tk
50
+ c_bool is_subscribed_cs
51
+
52
+
53
+ cdef class MarketDataService:
54
+ cdef size_t subscription_capacity
55
+ cdef dict subscription_mapping
56
+ cdef mds_subscription* subscription_status
57
+
58
+ cdef readonly ExchangeProfile profile
59
+ cdef readonly double timestamp
60
+ cdef readonly size_t n_subscribed
61
+ cdef readonly dict monitor
62
+ cdef readonly MonitorManager monitor_manager
63
+
64
+ cdef void c_subscription_buffer_extend(self)
65
+
66
+ cdef void c_update_subscription(self, const md_variant* md)
67
+
68
+ cdef void c_on_internal_data(self, const md_internal* md)
69
+
70
+ cdef void c_on_market_data(self, const md_variant* md)
71
+
72
+ cpdef void on_internal_data(self, InternalData internal_data)
73
+
74
+ cpdef void on_market_data(self, MarketData market_data)
75
+
76
+ cpdef double get_market_price(self, str ticker)
77
+
78
+ cpdef void set_manager(self, MonitorManager manager)
79
+
80
+ cpdef void add_monitor(self, object monitor)
81
+
82
+ cpdef void pop_monitor(self, object monitor=?, object monitor_id=?, str monitor_name=?)
83
+
84
+ cpdef void clear(self)
85
+
86
+
87
+ cdef MarketDataService MDS
@@ -0,0 +1,357 @@
1
+ import abc
2
+ from datetime import date, datetime
3
+ from typing import Any
4
+
5
+ from algo_engine.base import InternalData, MarketData
6
+ from algo_engine.exchange_profile import ExchangeProfile
7
+
8
+ MDS: MarketDataService
9
+
10
+
11
+ class MarketDataMonitor(metaclass=abc.ABCMeta):
12
+ """
13
+ Template for a market data monitor.
14
+
15
+ A monitor processes incoming market data and generates custom indices.
16
+
17
+ When MDS receives an update, it triggers the monitor's `__call__` method. All subscribed tickers' data
18
+ will be passed to the monitor, so proper storage for multiple tickers is assumed.
19
+
20
+ To use:
21
+ - Access via: `monitor = MDS[monitor_id]`
22
+ - Access output via: `monitor.value`
23
+ - Mark ready via: `monitor.is_ready = True`
24
+ - Add to engine using: `MDS.add_monitor(monitor)`
25
+
26
+ Attributes:
27
+ name (str): Unique name of the monitor (not enforced).
28
+ monitor_id (Any): Unique identifier, auto-generated if not provided.
29
+ enabled (bool): Whether the monitor is active (default: True).
30
+ """
31
+ name: str
32
+ monitor_id: Any
33
+ enabled: bool
34
+
35
+ def __init__(self, name: str, monitor_id: Any = None):
36
+ """
37
+ Initialize the monitor.
38
+
39
+ Args:
40
+ name (str): Unique name of the monitor.
41
+ monitor_id (Any): Unique identifier, auto-generated if not provided.
42
+ """
43
+
44
+ @abc.abstractmethod
45
+ def __call__(self, market_data: MarketData, **kwargs):
46
+ """
47
+ Feed market data into the monitor.
48
+
49
+ Args:
50
+ market_data (MarketData): The incoming market data.
51
+ **kwargs: For compatibility only; should not be used.
52
+ """
53
+
54
+ @abc.abstractmethod
55
+ def clear(self) -> None:
56
+ """
57
+ Clear the monitor's internal data.
58
+
59
+ Called at end-of-day (EoD) before shutdown, for graceful termination.
60
+ """
61
+
62
+ @property
63
+ @abc.abstractmethod
64
+ def value(self) -> float | dict[str, float]:
65
+ """
66
+ Retrieve the computed value(s) from this monitor.
67
+
68
+ Returns:
69
+ Either a single float or a dictionary of string keys to floats.
70
+ """
71
+
72
+ @property
73
+ def is_ready(self) -> bool:
74
+ """
75
+ Indicates whether the monitor is ready to produce values.
76
+
77
+ Returns:
78
+ True if ready; False otherwise. Defaults to True.
79
+ """
80
+
81
+
82
+ class MonitorManager(object):
83
+ """
84
+ Manages market data monitors.
85
+
86
+ This is a basic, single-threaded implementation. It is typically used as a component of MDS.
87
+
88
+ Attributes:
89
+ monitor (dict[Any, MarketDataMonitor]): Registered monitors.
90
+ """
91
+ monitor: dict[Any, MarketDataMonitor]
92
+
93
+ def __call__(self, market_data: MarketData):
94
+ """
95
+ Dispatch market data to all registered monitors.
96
+
97
+ Args:
98
+ market_data (MarketData): Incoming data.
99
+ """
100
+
101
+ def feed_monitor(self, monitor_id: Any, market_data: MarketData) -> None:
102
+ """
103
+ Feed market data to a specific monitor.
104
+
105
+ Args:
106
+ monitor_id (Any): The monitor's unique ID.
107
+ market_data (MarketData): Incoming data.
108
+ """
109
+
110
+ def on_market_data(self, market_data: MarketData) -> None:
111
+ """
112
+ Dispatch market data to all registered monitors.
113
+
114
+ Args:
115
+ market_data (MarketData): Incoming data.
116
+ """
117
+
118
+ def add_monitor(self, monitor: MarketDataMonitor) -> None:
119
+ """
120
+ Register a monitor.
121
+
122
+ Args:
123
+ monitor (MarketDataMonitor): The monitor to add.
124
+ """
125
+
126
+ def pop_monitor(self, monitor_id: Any) -> None:
127
+ """
128
+ Unregister a monitor by ID.
129
+
130
+ Args:
131
+ monitor_id (Any): ID of the monitor to remove.
132
+ """
133
+
134
+ def clear_monitors(self) -> None:
135
+ """
136
+ Clear all monitors.
137
+ """
138
+
139
+ def get_values(self) -> dict:
140
+ """
141
+ Collect current monitor values into a single dictionary.
142
+
143
+ Iterates over all monitors and merges their ``value`` dicts.
144
+
145
+ Returns:
146
+ A dictionary of aggregated monitor values.
147
+ """
148
+
149
+ def __contains__(self, monitor_id: Any) -> bool:
150
+ """
151
+ Check if a monitor is registered.
152
+
153
+ Args:
154
+ monitor_id (Any): The monitor's unique ID.
155
+
156
+ Returns:
157
+ True if the monitor is registered.
158
+ """
159
+
160
+ def start(self):
161
+ """
162
+ Start the manager.
163
+
164
+ Placeholder for subclasses that require initialization.
165
+ """
166
+
167
+ def stop(self):
168
+ """
169
+ Stop the manager.
170
+
171
+ Placeholder for subclasses that require cleanup.
172
+ """
173
+
174
+ def clear(self):
175
+ """
176
+ Clear all monitor data for graceful shutdown.
177
+ """
178
+
179
+ def __enter__(self):
180
+ """Start the manager as a context manager."""
181
+
182
+ def __exit__(self, exc_type, exc_val, exc_tb):
183
+ """Stop the manager when exiting the context."""
184
+
185
+ @property
186
+ def values(self) -> dict[str, float]:
187
+ """
188
+ Collect current values from all monitors.
189
+
190
+ Returns:
191
+ A dictionary mapping monitor names to their values.
192
+ """
193
+
194
+
195
+ class MarketDataService:
196
+ """
197
+ Singleton service for managing market data.
198
+
199
+ Handles distribution, storage, and monitor coordination.
200
+ All market data–related operations should be registered here.
201
+
202
+ Attributes:
203
+ profile (ExchangeProfile): The active market profile.
204
+ n_subscribed (int): Number of tickers currently subscribed.
205
+ monitor (dict): Direct reference to monitor storage.
206
+ monitor_manager (MonitorManager): The monitor manager in use.
207
+ timestamp (float): UNIX timestamp of the latest market data (NaN if uninitialized).
208
+ """
209
+ profile: ExchangeProfile
210
+ n_subscribed: int
211
+ monitor: dict[Any, MarketDataMonitor]
212
+ monitor_manager: MonitorManager
213
+ timestamp: float
214
+
215
+ def __len__(self) -> int:
216
+ """
217
+ Get number of tickers processed.
218
+
219
+ Returns:
220
+ Number of tickers with available data.
221
+ """
222
+ ...
223
+
224
+ def __call__(self, market_data: MarketData):
225
+ """
226
+ Alias for `on_market_data`.
227
+
228
+ Args:
229
+ market_data (MarketData): Incoming data.
230
+ """
231
+ ...
232
+
233
+ def __getitem__(self, monitor_id: Any) -> MarketDataMonitor:
234
+ """
235
+ Access monitor by ID.
236
+
237
+ Args:
238
+ monitor_id (Any): Monitor's unique ID.
239
+
240
+ Returns:
241
+ MarketDataMonitor: The corresponding monitor.
242
+ """
243
+ ...
244
+
245
+ def on_internal_data(self, internal_data: InternalData) -> None:
246
+ """
247
+ Feed internal communication protocol data to the service.
248
+
249
+ Args:
250
+ internal_data (InternalData): The internal protocol message.
251
+ """
252
+ ...
253
+
254
+ def on_market_data(self, market_data: MarketData) -> None:
255
+ """
256
+ Handle market data update and trigger monitors.
257
+
258
+ Args:
259
+ market_data (MarketData): Incoming data.
260
+ """
261
+ ...
262
+
263
+ def set_manager(self, manager: MonitorManager) -> None:
264
+ """
265
+ Replace the monitor manager, re-registering all existing monitors.
266
+
267
+ Args:
268
+ manager (MonitorManager): The new manager to assign.
269
+ """
270
+
271
+ def get_market_price(self, ticker: str) -> float:
272
+ """
273
+ Retrieve the latest price of a ticker.
274
+
275
+ Args:
276
+ ticker (str): The instrument's symbol.
277
+
278
+ Returns:
279
+ float: Latest price or NaN if unavailable.
280
+ """
281
+ ...
282
+
283
+ def add_monitor(self, monitor: MarketDataMonitor) -> None:
284
+ """
285
+ Register a monitor with the service.
286
+
287
+ Note:
288
+ MDS and its ``MonitorManager`` store monitors independently.
289
+
290
+ Args:
291
+ monitor (MarketDataMonitor): The monitor to add.
292
+ """
293
+ ...
294
+
295
+ def pop_monitor(
296
+ self,
297
+ monitor: MarketDataMonitor = None,
298
+ monitor_id: Any = None,
299
+ monitor_name: str = None,
300
+ ) -> None:
301
+ """
302
+ Remove a monitor from the service.
303
+
304
+ At least one of ``monitor``, ``monitor_id``, or ``monitor_name`` must be provided.
305
+
306
+ Args:
307
+ monitor (MarketDataMonitor): The monitor instance to remove.
308
+ monitor_id (Any): The ID of the monitor to remove.
309
+ monitor_name (str): The name of the monitor to remove.
310
+ """
311
+ ...
312
+
313
+ def clear(self):
314
+ """
315
+ Reset the service to its initial state.
316
+ """
317
+ ...
318
+
319
+ @property
320
+ def market_price(self) -> dict[str, float]:
321
+ """
322
+ Latest known market prices.
323
+
324
+ Returns:
325
+ A dictionary mapping tickers to prices.
326
+ """
327
+ ...
328
+
329
+ @property
330
+ def market_time(self) -> datetime | None:
331
+ """
332
+ Latest timestamp of received market data.
333
+
334
+ Returns:
335
+ A `datetime` object or None.
336
+ """
337
+ ...
338
+
339
+ @property
340
+ def market_date(self) -> date | None:
341
+ """
342
+ Date component of the latest market data.
343
+
344
+ Returns:
345
+ A `date` object or None.
346
+ """
347
+ ...
348
+
349
+ @property
350
+ def subscriptions(self) -> dict[str, int]:
351
+ """
352
+ Current subscription mapping.
353
+
354
+ Returns:
355
+ A dictionary mapping ticker symbols to their subscription indices.
356
+ """
357
+ ...
@@ -0,0 +1,53 @@
1
+ from types import SimpleNamespace
2
+
3
+ import event_engine
4
+ from event_engine import Topic, EventEngine
5
+
6
+ from . import LOGGER
7
+
8
+ __all__ = ['EVENT_ENGINE', 'TOPIC']
9
+
10
+ event_engine.set_logger(LOGGER.getChild('EventEngine'))
11
+
12
+
13
+ class TopicSet(object):
14
+ on_order = Topic('on_order')
15
+ on_report = Topic('on_report')
16
+ eod = Topic('eod')
17
+ eod_done = Topic('eod_done')
18
+ bod = Topic('bod')
19
+ bod_done = Topic('bod_done')
20
+
21
+ launch_order = Topic('launch_order.{ticker}')
22
+ cancel_order = Topic('cancel_order.{ticker}')
23
+ realtime = Topic('realtime.{ticker}.{dtype}')
24
+
25
+ @classmethod
26
+ def push(cls, market_data):
27
+ return cls.realtime(ticker=market_data.ticker, dtype=market_data.__class__.__name__)
28
+
29
+ @classmethod
30
+ def parse(cls, topic: Topic) -> SimpleNamespace:
31
+ try:
32
+ _ = topic.value.split('.')
33
+
34
+ action = _.pop(0)
35
+ if action in ['open', 'close']:
36
+ dtype = None
37
+ else:
38
+ dtype = _.pop(-1)
39
+ ticker = '.'.join(_)
40
+
41
+ p = SimpleNamespace(
42
+ action=action,
43
+ dtype=dtype,
44
+ ticker=ticker
45
+ )
46
+ return p
47
+ except Exception as _:
48
+ raise ValueError(f'Invalid topic {topic}')
49
+
50
+
51
+ EVENT_ENGINE = EventEngine()
52
+ TOPIC = TopicSet
53
+ # EVENT_ENGINE.start()