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.
@@ -1,7 +1,7 @@
1
1
  __all__ = [
2
2
  "EventBus",
3
- "EventSubscriberLike",
3
+ "Subscriber",
4
4
  ]
5
5
 
6
6
  from .eventbus import EventBus
7
- from .contracts import EventSubscriberLike
7
+ from .subscriber import Subscriber
@@ -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
- from . import contracts
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[contracts.EventSubscriberLike]
16
+ type[events.bases.EventBase], set[Subscriber]
14
17
  ] = collections.defaultdict(set)
15
- self._subscribers: set[contracts.EventSubscriberLike] = 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: contracts.EventSubscriberLike,
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: contracts.EventSubscriberLike) -> None:
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.25.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=9yLobI20ZmqipPHG_pwVgdGOEoj-sIAdGWhH17MKSu4,132
8
- onesecondtrader/messaging/contracts.py,sha256=_LCDtwqgCqNZ5Js1Ht5iFvqNqZUMzi83RVeJgXpTeno,267
9
- onesecondtrader/messaging/eventbus.py,sha256=J36tmuemRjDATHikSSzL3-7Kmx5fu_sX09X7tb94IF0,1522
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.25.0.dist-info/METADATA,sha256=eWtsWhZOEqTGaEubNmJhXnWFtYxSfhYwJheci2HAwkI,9682
14
- onesecondtrader-0.25.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
15
- onesecondtrader-0.25.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
16
- onesecondtrader-0.25.0.dist-info/RECORD,,
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: ...