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.
- onesecondtrader/brokers/__init__.py +5 -0
- onesecondtrader/brokers/base.py +39 -0
- onesecondtrader/messaging/__init__.py +2 -2
- onesecondtrader/messaging/eventbus.py +8 -5
- onesecondtrader/messaging/subscriber.py +69 -0
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.27.0.dist-info}/METADATA +1 -1
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.27.0.dist-info}/RECORD +9 -7
- onesecondtrader/messaging/contracts.py +0 -11
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.27.0.dist-info}/WHEEL +0 -0
- {onesecondtrader-0.25.0.dist-info → onesecondtrader-0.27.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -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)
|
|
@@ -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,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.
|
|
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=
|
|
8
|
-
onesecondtrader/messaging/
|
|
9
|
-
onesecondtrader/messaging/
|
|
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.
|
|
14
|
-
onesecondtrader-0.
|
|
15
|
-
onesecondtrader-0.
|
|
16
|
-
onesecondtrader-0.
|
|
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: ...
|
|
File without changes
|
|
File without changes
|