onesecondtrader 0.25.0__py3-none-any.whl → 0.27.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.
@@ -0,0 +1,5 @@
1
+ __all__ = [
2
+ "BrokerBase",
3
+ ]
4
+
5
+ from .base import BrokerBase
@@ -0,0 +1,39 @@
1
+ import abc
2
+
3
+ from onesecondtrader import events, messaging
4
+
5
+
6
+ class BrokerBase(messaging.Subscriber):
7
+ def __init__(self, event_bus: messaging.EventBus) -> None:
8
+ super().__init__(event_bus)
9
+ self._subscribe(
10
+ events.requests.OrderSubmission,
11
+ events.requests.OrderCancellation,
12
+ events.requests.OrderModification,
13
+ )
14
+
15
+ def _on_event(self, event: events.bases.EventBase) -> None:
16
+ match event:
17
+ case events.requests.OrderSubmission() as submit_order:
18
+ self._on_submit_order(submit_order)
19
+ case events.requests.OrderCancellation() as cancel_order:
20
+ self._on_cancel_order(cancel_order)
21
+ case events.requests.OrderModification() as modify_order:
22
+ self._on_modify_order(modify_order)
23
+ case _:
24
+ return
25
+
26
+ @abc.abstractmethod
27
+ def _on_submit_order(self, event: events.requests.OrderSubmission) -> None:
28
+ pass
29
+
30
+ @abc.abstractmethod
31
+ def _on_cancel_order(self, event: events.requests.OrderCancellation) -> None:
32
+ pass
33
+
34
+ @abc.abstractmethod
35
+ def _on_modify_order(self, event: events.requests.OrderModification) -> None:
36
+ pass
37
+
38
+ def _respond(self, response_event: events.bases.BrokerResponseEvent) -> None:
39
+ self._publish(response_event)
@@ -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,69 @@
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
+ for event_type in event_types:
40
+ self._event_bus.subscribe(self, event_type)
41
+
42
+ def _publish(self, event: events.bases.EventBase) -> None:
43
+ self._event_bus.publish(event)
44
+
45
+ def _event_loop(self) -> None:
46
+ while True:
47
+ event = self._queue.get()
48
+ if event is None:
49
+ self._queue.task_done()
50
+ break
51
+ try:
52
+ self._on_event(event)
53
+ except Exception as exc:
54
+ self._on_exception(exc)
55
+ finally:
56
+ self._queue.task_done()
57
+ self._cleanup()
58
+
59
+ def _on_exception(self, exc: Exception) -> None:
60
+ # Override in subclass to log or handle exceptions
61
+ pass
62
+
63
+ def _cleanup(self) -> None:
64
+ pass
65
+
66
+ @abc.abstractmethod
67
+ def _on_event(self, event: events.bases.EventBase) -> None:
68
+ # Must not block indefinitely; wait_until_idle() has no timeout
69
+ ...
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onesecondtrader
3
- Version: 0.25.0
3
+ Version: 0.27.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
@@ -1,16 +1,18 @@
1
1
  onesecondtrader/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ onesecondtrader/brokers/__init__.py,sha256=n-idxbvvlPrAnbxdA7l6S3ecRVqgroTZ0XBkse8GamQ,62
3
+ onesecondtrader/brokers/base.py,sha256=b6Xq2gBUdy3RTpnUfpUiNSXwbuq_bRIjXJ-s89Xu7nE,1345
2
4
  onesecondtrader/events/__init__.py,sha256=IOlFRdiOXz93SpvkpKL8wr1954d_8olKSB1n9mlTL3Y,898
3
5
  onesecondtrader/events/bases.py,sha256=g-ykq2jgcitIAueRurUlqAq0jINQwuhSWi_khAniPHw,662
4
6
  onesecondtrader/events/market.py,sha256=IfHuIGfp_IUiw-dFay4c4RYmkoNzshxbhuWTglBqfN0,509
5
7
  onesecondtrader/events/requests.py,sha256=2KXwSckiar9-fy8wkN3vcSIeOkeBfeo_XhUhrNKEd2Q,831
6
8
  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
9
+ onesecondtrader/messaging/__init__.py,sha256=vMRDabHBgse_vZRTRFtnU8M8v2sY_o4pHjGzgu3hp3E,115
10
+ onesecondtrader/messaging/eventbus.py,sha256=rTBDmtXKnUAVdOBeLyIn2pJmBLz9AszHGIcuOcVhEQI,1501
11
+ onesecondtrader/messaging/subscriber.py,sha256=ImpFmu5IstLXLoKVMaebmLp5MXN6225vHLdTL1ZOPvw,2106
10
12
  onesecondtrader/models/__init__.py,sha256=cH5xyniz78MQjM9_-fFdP1ZW6FFLTmayMwQauFO23bU,135
11
13
  onesecondtrader/models/data.py,sha256=TqUvTtjpmzTJT8ZdTYnlVoyI7Qck2IsseCazWZxJgD0,173
12
14
  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,,
15
+ onesecondtrader-0.27.0.dist-info/METADATA,sha256=aHM_QsfmD8cIv5lqkvVFIveYEx5SxHsS1NjqaumOuXI,9682
16
+ onesecondtrader-0.27.0.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
17
+ onesecondtrader-0.27.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
18
+ onesecondtrader-0.27.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: ...