onesecondtrader 0.9.0__tar.gz → 0.10.0__tar.gz

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 (17) hide show
  1. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/PKG-INFO +1 -1
  2. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/pyproject.toml +1 -1
  3. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/core/models.py +26 -0
  4. onesecondtrader-0.10.0/src/onesecondtrader/datafeeds/base_datafeed.py +263 -0
  5. onesecondtrader-0.10.0/src/onesecondtrader/py.typed +0 -0
  6. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/LICENSE +0 -0
  7. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/README.md +0 -0
  8. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/__init__.py +0 -0
  9. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/core/__init__.py +0 -0
  10. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/core/py.typed +0 -0
  11. {onesecondtrader-0.9.0/src/onesecondtrader/messaging → onesecondtrader-0.10.0/src/onesecondtrader/datafeeds}/__init__.py +0 -0
  12. {onesecondtrader-0.9.0/src/onesecondtrader/monitoring → onesecondtrader-0.10.0/src/onesecondtrader/messaging}/__init__.py +0 -0
  13. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/messaging/eventbus.py +0 -0
  14. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/messaging/events.py +0 -0
  15. /onesecondtrader-0.9.0/src/onesecondtrader/monitoring/py.typed → /onesecondtrader-0.10.0/src/onesecondtrader/monitoring/__init__.py +0 -0
  16. {onesecondtrader-0.9.0 → onesecondtrader-0.10.0}/src/onesecondtrader/monitoring/console.py +0 -0
  17. {onesecondtrader-0.9.0/src/onesecondtrader → onesecondtrader-0.10.0/src/onesecondtrader/monitoring}/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: onesecondtrader
3
- Version: 0.9.0
3
+ Version: 0.10.0
4
4
  Summary: The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place.
5
5
  Author: Nils P. Kujath
6
6
  Author-email: 63961429+NilsKujath@users.noreply.github.com
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "onesecondtrader"
3
- version = "0.9.0"
3
+ version = "0.10.0"
4
4
  description = "The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place."
5
5
  authors = [
6
6
  {name = "Nils P. Kujath",email = "63961429+NilsKujath@users.noreply.github.com"}
@@ -131,3 +131,29 @@ class OrderRejectionReason(enum.Enum):
131
131
 
132
132
  UNKNOWN = enum.auto()
133
133
  NEGATIVE_QUANTITY = enum.auto()
134
+
135
+
136
+ class TimeFrame(enum.Enum):
137
+ """
138
+ Enum for timeframes.
139
+
140
+ **Attributes:**
141
+
142
+ | Enum | Value | Description |
143
+ |------|-------|-------------|
144
+ | `SECOND` | `enum.auto()` | 1 second |
145
+ | `MINUTE` | `enum.auto()` | 1 minute |
146
+ | `HOUR` | `enum.auto()` | 1 hour |
147
+ | `DAY` | `enum.auto()` | 1 day |
148
+ | `WEEK` | `enum.auto()` | 1 week |
149
+ | `MONTH` | `enum.auto()` | 1 month |
150
+ | `YEAR` | `enum.auto()` | 1 year
151
+ """
152
+
153
+ SECOND = enum.auto()
154
+ MINUTE = enum.auto()
155
+ HOUR = enum.auto()
156
+ DAY = enum.auto()
157
+ WEEK = enum.auto()
158
+ MONTH = enum.auto()
159
+ YEAR = enum.auto()
@@ -0,0 +1,263 @@
1
+ """
2
+ This module provides the base class for datafeeds.
3
+ """
4
+
5
+ import abc
6
+ import threading
7
+ from onesecondtrader.messaging import eventbus
8
+ from onesecondtrader.core import models
9
+ from onesecondtrader.monitoring import console
10
+
11
+
12
+ class BaseDatafeed(abc.ABC):
13
+ """
14
+ Base class for all datafeeds.
15
+ """
16
+
17
+ def __init__(self, event_bus: eventbus.EventBus) -> None:
18
+ """
19
+ Initializes the datafeed with the provided event bus.
20
+
21
+ Args:
22
+ event_bus (eventbus.EventBus): The event bus to publish events to.
23
+
24
+ Attributes:
25
+ self.event_bus (eventbus.EventBus): The event bus to publish events to.
26
+ self._lock (threading.Lock): Lock for thread safety.
27
+ self._is_connected (bool): Whether the datafeed is connected. `True` if
28
+ connected, `False` otherwise.
29
+ self._streamed_symbols (set[tuple[str, models.TimeFrame]]): Set of symbols
30
+ and timeframes that are currently being streamed.
31
+ """
32
+ self.event_bus = event_bus
33
+
34
+ self._lock = threading.Lock()
35
+ self._is_connected = False
36
+ self._streamed_symbols: set[tuple[str, models.TimeFrame]] = set()
37
+
38
+ def connect(self) -> bool:
39
+ """
40
+ Connect to the datafeed.
41
+
42
+ Returns:
43
+ bool: True if connection successful, False otherwise.
44
+ """
45
+ with self._lock:
46
+ if self._is_connected:
47
+ console.logger.warning(f"{self.__class__.__name__} already connected")
48
+ return True
49
+
50
+ console.logger.info(f"Connecting to {self.__class__.__name__}...")
51
+ try:
52
+ success = self._connect()
53
+ if success:
54
+ self._is_connected = True
55
+ console.logger.info(
56
+ f"Successfully connected to {self.__class__.__name__}"
57
+ )
58
+ return True
59
+ else:
60
+ console.logger.error(
61
+ f"Failed to connect to {self.__class__.__name__}"
62
+ )
63
+ return False
64
+ except Exception as e:
65
+ console.logger.error(
66
+ f"Connection failed for {self.__class__.__name__}: {e}"
67
+ )
68
+ return False
69
+
70
+ @abc.abstractmethod
71
+ def _connect(self) -> bool:
72
+ """
73
+ Implement connection logic for the specific datafeed.
74
+
75
+ Returns:
76
+ bool: True if connection successful, False otherwise.
77
+ """
78
+ pass
79
+
80
+ def disconnect(self) -> bool:
81
+ """
82
+ Disconnect from the datafeed.
83
+ Clears the set of streamed symbols.
84
+
85
+ Returns:
86
+ bool: True if disconnection successful, False otherwise.
87
+ """
88
+ with self._lock:
89
+ if not self._is_connected:
90
+ console.logger.warning(
91
+ f"{self.__class__.__name__} already disconnected"
92
+ )
93
+ return True
94
+
95
+ console.logger.info(f"Disconnecting from {self.__class__.__name__}...")
96
+ try:
97
+ success = self._disconnect()
98
+ if success:
99
+ self._is_connected = False
100
+ self._streamed_symbols.clear()
101
+ console.logger.info(
102
+ f"Successfully disconnected from {self.__class__.__name__}"
103
+ )
104
+ return True
105
+ else:
106
+ console.logger.error(
107
+ f"Failed to disconnect from {self.__class__.__name__}"
108
+ )
109
+ return False
110
+ except Exception as e:
111
+ console.logger.error(
112
+ f"Disconnection failed for {self.__class__.__name__}: {e}"
113
+ )
114
+ self._is_connected = False
115
+ self._streamed_symbols.clear()
116
+ return False
117
+
118
+ @abc.abstractmethod
119
+ def _disconnect(self) -> bool:
120
+ """
121
+ Implement disconnection logic for the specific datafeed.
122
+
123
+ Returns:
124
+ bool: True if disconnection successful, False otherwise.
125
+ """
126
+ pass
127
+
128
+ def start_streaming_for_symbols(
129
+ self, symbols: list[tuple[str, models.TimeFrame]]
130
+ ) -> bool:
131
+ """
132
+ Start streaming market data for the specified symbols and timeframes.
133
+
134
+ Args:
135
+ symbols: List of (symbol, timeframe) tuples to start streaming.
136
+
137
+ Returns:
138
+ bool: True if streaming started successfully, False otherwise.
139
+ """
140
+ if not symbols:
141
+ console.logger.warning("No symbols provided for streaming")
142
+ return True
143
+
144
+ with self._lock:
145
+ if not self._is_connected:
146
+ console.logger.error("Cannot start streaming: datafeed not connected")
147
+ return False
148
+
149
+ new_symbols = set(symbols) - self._streamed_symbols
150
+ if not new_symbols:
151
+ console.logger.info("All requested symbols are already being streamed")
152
+ return True
153
+
154
+ try:
155
+ success = self._start_streaming_for_symbols(list(new_symbols))
156
+ if success:
157
+ self._streamed_symbols.update(new_symbols)
158
+ console.logger.info(
159
+ f"Successfully started streaming for {len(new_symbols)} symbols"
160
+ )
161
+ return True
162
+ else:
163
+ console.logger.error("Failed to start streaming for symbols")
164
+ return False
165
+ except Exception as e:
166
+ console.logger.error(f"Exception while starting streaming: {e}")
167
+ return False
168
+
169
+ @abc.abstractmethod
170
+ def _start_streaming_for_symbols(
171
+ self, symbols: list[tuple[str, models.TimeFrame]]
172
+ ) -> bool:
173
+ """
174
+ Implement streaming startup logic for the specific datafeed.
175
+
176
+ Args:
177
+ symbols: List of (symbol, timeframe) tuples to start streaming.
178
+ These are guaranteed to be new symbols not already being streamed.
179
+
180
+ Returns:
181
+ bool: True if streaming started successfully, False otherwise.
182
+ """
183
+ pass
184
+
185
+ def stop_streaming_for_symbols(
186
+ self, symbols: list[tuple[str, models.TimeFrame]]
187
+ ) -> bool:
188
+ """
189
+ Stop streaming market data for the specified symbols and timeframes.
190
+
191
+ Args:
192
+ symbols: List of (symbol, timeframe) tuples to stop streaming.
193
+
194
+ Returns:
195
+ bool: True if streaming stopped successfully, False otherwise.
196
+ """
197
+ if not symbols:
198
+ console.logger.warning("No symbols provided for stopping streaming")
199
+ return True
200
+
201
+ with self._lock:
202
+ if not self._is_connected:
203
+ console.logger.warning(
204
+ "Datafeed not connected, but removing symbols from tracking"
205
+ )
206
+ self._streamed_symbols.difference_update(symbols)
207
+ return True
208
+
209
+ symbols_to_stop = set(symbols) & self._streamed_symbols
210
+ if not symbols_to_stop:
211
+ console.logger.info(
212
+ "None of the requested symbols are currently being streamed"
213
+ )
214
+ return True
215
+
216
+ console.logger.info(
217
+ f"Stopping streaming for {len(symbols_to_stop)} symbols"
218
+ )
219
+ try:
220
+ success = self._stop_streaming_for_symbols(list(symbols_to_stop))
221
+ if success:
222
+ self._streamed_symbols.difference_update(symbols_to_stop)
223
+ console.logger.info(
224
+ f"Successfully stopped streaming for {len(symbols_to_stop)} "
225
+ f"symbols"
226
+ )
227
+ return True
228
+ else:
229
+ console.logger.error("Failed to stop streaming for symbols")
230
+ return False
231
+ except Exception as e:
232
+ console.logger.error(f"Exception while stopping streaming: {e}")
233
+ self._streamed_symbols.difference_update(symbols_to_stop)
234
+ return False
235
+
236
+ @abc.abstractmethod
237
+ def _stop_streaming_for_symbols(
238
+ self, symbols: list[tuple[str, models.TimeFrame]]
239
+ ) -> bool:
240
+ """
241
+ Implement streaming shutdown logic for the specific datafeed.
242
+
243
+ Args:
244
+ symbols: List of (symbol, timeframe) tuples to stop streaming.
245
+ These are guaranteed to be symbols currently being streamed.
246
+
247
+ Returns:
248
+ bool: True if streaming stopped successfully, False otherwise.
249
+ """
250
+ pass
251
+
252
+ @abc.abstractmethod
253
+ def preload_bars(
254
+ self, preload_list: list[tuple[str, models.TimeFrame, int]]
255
+ ) -> None:
256
+ """
257
+ Preload historical bars for the specified symbols, timeframes, and counts.
258
+
259
+ Args:
260
+ preload_list: List of (symbol, timeframe, count) tuples specifying
261
+ what historical data to preload.
262
+ """
263
+ pass
File without changes