onesecondtrader 0.25.0__py3-none-any.whl → 0.26.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- onesecondtrader/messaging/__init__.py +2 -2
- onesecondtrader/messaging/eventbus.py +8 -5
- onesecondtrader/messaging/subscriber.py +67 -0
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.26.0.dist-info}/METADATA +1 -1
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.26.0.dist-info}/RECORD +7 -7
- onesecondtrader/messaging/contracts.py +0 -11
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.26.0.dist-info}/WHEEL +0 -0
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.26.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,29 +2,32 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import collections
|
|
4
4
|
import threading
|
|
5
|
+
import typing
|
|
5
6
|
|
|
6
7
|
from onesecondtrader import events
|
|
7
|
-
|
|
8
|
+
|
|
9
|
+
if typing.TYPE_CHECKING:
|
|
10
|
+
from .subscriber import Subscriber
|
|
8
11
|
|
|
9
12
|
|
|
10
13
|
class EventBus:
|
|
11
14
|
def __init__(self) -> None:
|
|
12
15
|
self._per_event_subscriptions: collections.defaultdict[
|
|
13
|
-
type[events.bases.EventBase], set[
|
|
16
|
+
type[events.bases.EventBase], set[Subscriber]
|
|
14
17
|
] = collections.defaultdict(set)
|
|
15
|
-
self._subscribers: set[
|
|
18
|
+
self._subscribers: set[Subscriber] = set()
|
|
16
19
|
self._lock: threading.Lock = threading.Lock()
|
|
17
20
|
|
|
18
21
|
def subscribe(
|
|
19
22
|
self,
|
|
20
|
-
subscriber:
|
|
23
|
+
subscriber: Subscriber,
|
|
21
24
|
event_type: type[events.bases.EventBase],
|
|
22
25
|
) -> None:
|
|
23
26
|
with self._lock:
|
|
24
27
|
self._subscribers.add(subscriber)
|
|
25
28
|
self._per_event_subscriptions[event_type].add(subscriber)
|
|
26
29
|
|
|
27
|
-
def unsubscribe(self, subscriber:
|
|
30
|
+
def unsubscribe(self, subscriber: Subscriber) -> None:
|
|
28
31
|
with self._lock:
|
|
29
32
|
for set_of_event_subscribers in self._per_event_subscriptions.values():
|
|
30
33
|
set_of_event_subscribers.discard(subscriber)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import abc
|
|
2
|
+
import queue
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
from onesecondtrader import events
|
|
6
|
+
from .eventbus import EventBus
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Subscriber(abc.ABC):
|
|
10
|
+
def __init__(self, event_bus: EventBus) -> None:
|
|
11
|
+
self._event_bus = event_bus
|
|
12
|
+
self._queue: queue.Queue[events.bases.EventBase | None] = queue.Queue()
|
|
13
|
+
self._running: threading.Event = threading.Event()
|
|
14
|
+
self._running.set()
|
|
15
|
+
self._thread = threading.Thread(
|
|
16
|
+
target=self._event_loop, name=self.__class__.__name__
|
|
17
|
+
)
|
|
18
|
+
self._thread.start()
|
|
19
|
+
|
|
20
|
+
def receive(self, event: events.bases.EventBase) -> None:
|
|
21
|
+
if self._running.is_set():
|
|
22
|
+
self._queue.put(event)
|
|
23
|
+
|
|
24
|
+
def wait_until_idle(self) -> None:
|
|
25
|
+
if not self._running.is_set():
|
|
26
|
+
return
|
|
27
|
+
self._queue.join()
|
|
28
|
+
|
|
29
|
+
def shutdown(self) -> None:
|
|
30
|
+
if not self._running.is_set():
|
|
31
|
+
return
|
|
32
|
+
self._event_bus.unsubscribe(self)
|
|
33
|
+
self._running.clear()
|
|
34
|
+
self._queue.put(None)
|
|
35
|
+
if threading.current_thread() is not self._thread:
|
|
36
|
+
self._thread.join()
|
|
37
|
+
|
|
38
|
+
def _subscribe(self, *event_types: type[events.bases.EventBase]) -> None:
|
|
39
|
+
# Call as last line of subclass __init__ to avoid receiving events before fully initialized
|
|
40
|
+
for event_type in event_types:
|
|
41
|
+
self._event_bus.subscribe(self, event_type)
|
|
42
|
+
|
|
43
|
+
def _event_loop(self) -> None:
|
|
44
|
+
while True:
|
|
45
|
+
event = self._queue.get()
|
|
46
|
+
if event is None:
|
|
47
|
+
self._queue.task_done()
|
|
48
|
+
break
|
|
49
|
+
try:
|
|
50
|
+
self._on_event(event)
|
|
51
|
+
except Exception as exc:
|
|
52
|
+
self._on_exception(exc)
|
|
53
|
+
finally:
|
|
54
|
+
self._queue.task_done()
|
|
55
|
+
self._cleanup()
|
|
56
|
+
|
|
57
|
+
def _on_exception(self, exc: Exception) -> None:
|
|
58
|
+
# Override in subclass to log or handle exceptions
|
|
59
|
+
pass
|
|
60
|
+
|
|
61
|
+
def _cleanup(self) -> None:
|
|
62
|
+
pass
|
|
63
|
+
|
|
64
|
+
@abc.abstractmethod
|
|
65
|
+
def _on_event(self, event: events.bases.EventBase) -> None:
|
|
66
|
+
# Must not block indefinitely; wait_until_idle() has no timeout
|
|
67
|
+
...
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: onesecondtrader
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.26.0
|
|
4
4
|
Summary: The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place.
|
|
5
5
|
License-File: LICENSE
|
|
6
6
|
Author: Nils P. Kujath
|
|
@@ -4,13 +4,13 @@ onesecondtrader/events/bases.py,sha256=g-ykq2jgcitIAueRurUlqAq0jINQwuhSWi_khAniP
|
|
|
4
4
|
onesecondtrader/events/market.py,sha256=IfHuIGfp_IUiw-dFay4c4RYmkoNzshxbhuWTglBqfN0,509
|
|
5
5
|
onesecondtrader/events/requests.py,sha256=2KXwSckiar9-fy8wkN3vcSIeOkeBfeo_XhUhrNKEd2Q,831
|
|
6
6
|
onesecondtrader/events/responses.py,sha256=w_BH1nkkPyxQjh30EXEVFcUGDoMprFc2PuAaqpVrQ8A,1436
|
|
7
|
-
onesecondtrader/messaging/__init__.py,sha256=
|
|
8
|
-
onesecondtrader/messaging/
|
|
9
|
-
onesecondtrader/messaging/
|
|
7
|
+
onesecondtrader/messaging/__init__.py,sha256=vMRDabHBgse_vZRTRFtnU8M8v2sY_o4pHjGzgu3hp3E,115
|
|
8
|
+
onesecondtrader/messaging/eventbus.py,sha256=rTBDmtXKnUAVdOBeLyIn2pJmBLz9AszHGIcuOcVhEQI,1501
|
|
9
|
+
onesecondtrader/messaging/subscriber.py,sha256=Vg8po_h47qMPm_qN6OauIBiCE179cszjy3NCd493__s,2103
|
|
10
10
|
onesecondtrader/models/__init__.py,sha256=cH5xyniz78MQjM9_-fFdP1ZW6FFLTmayMwQauFO23bU,135
|
|
11
11
|
onesecondtrader/models/data.py,sha256=TqUvTtjpmzTJT8ZdTYnlVoyI7Qck2IsseCazWZxJgD0,173
|
|
12
12
|
onesecondtrader/models/orders.py,sha256=y6Ar-6fMqaOd_hRnRGvfWUF0Z13H_2hfTOW3ROOk0A8,254
|
|
13
|
-
onesecondtrader-0.
|
|
14
|
-
onesecondtrader-0.
|
|
15
|
-
onesecondtrader-0.
|
|
16
|
-
onesecondtrader-0.
|
|
13
|
+
onesecondtrader-0.26.0.dist-info/METADATA,sha256=4JFvirUCpSuaYhLlTru35NFBcLc0M0kjEMTjRZPqe5w,9682
|
|
14
|
+
onesecondtrader-0.26.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
|
|
15
|
+
onesecondtrader-0.26.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
16
|
+
onesecondtrader-0.26.0.dist-info/RECORD,,
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import typing
|
|
4
|
-
|
|
5
|
-
from onesecondtrader import events
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
@typing.runtime_checkable
|
|
9
|
-
class EventSubscriberLike(typing.Protocol):
|
|
10
|
-
def receive(self, event: events.bases.EventBase) -> None: ...
|
|
11
|
-
def wait_until_idle(self) -> None: ...
|
|
File without changes
|
|
File without changes
|