onesecondtrader 0.9.0__py3-none-any.whl → 0.10.1__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/core/models.py +26 -0
- onesecondtrader/datafeeds/__init__.py +0 -0
- onesecondtrader/datafeeds/base_datafeed.py +255 -0
- {onesecondtrader-0.9.0.dist-info → onesecondtrader-0.10.1.dist-info}/METADATA +1 -1
- {onesecondtrader-0.9.0.dist-info → onesecondtrader-0.10.1.dist-info}/RECORD +7 -5
- {onesecondtrader-0.9.0.dist-info → onesecondtrader-0.10.1.dist-info}/LICENSE +0 -0
- {onesecondtrader-0.9.0.dist-info → onesecondtrader-0.10.1.dist-info}/WHEEL +0 -0
onesecondtrader/core/models.py
CHANGED
|
@@ -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()
|
|
File without changes
|
|
@@ -0,0 +1,255 @@
|
|
|
1
|
+
"""
|
|
2
|
+
This module provides the base class for all 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
|
+
Initialize the datafeed with the provided event bus.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
event_bus: The event bus to publish events to.
|
|
23
|
+
|
|
24
|
+
Attributes:
|
|
25
|
+
self.event_bus: The event bus to publish events to.
|
|
26
|
+
self._lock: Lock for thread safety.
|
|
27
|
+
self._is_connected: Flag indicating if the datafeed is connected.
|
|
28
|
+
self._watched_symbols: Set of symbols currently being watched.
|
|
29
|
+
"""
|
|
30
|
+
self.event_bus = event_bus
|
|
31
|
+
self._lock = threading.Lock()
|
|
32
|
+
self._is_connected = False
|
|
33
|
+
self._watched_symbols: set[tuple[str, models.TimeFrame]] = set()
|
|
34
|
+
|
|
35
|
+
def connect(self) -> bool:
|
|
36
|
+
"""
|
|
37
|
+
Connect to the datafeed.
|
|
38
|
+
|
|
39
|
+
Returns:
|
|
40
|
+
bool: True if connection successful, False otherwise.
|
|
41
|
+
"""
|
|
42
|
+
with self._lock:
|
|
43
|
+
if self._is_connected:
|
|
44
|
+
console.logger.warning(f"{self.__class__.__name__} already connected")
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
console.logger.info(f"Connecting to {self.__class__.__name__}...")
|
|
48
|
+
try:
|
|
49
|
+
success = self._connect()
|
|
50
|
+
if success:
|
|
51
|
+
self._is_connected = True
|
|
52
|
+
console.logger.info(
|
|
53
|
+
f"Successfully connected to {self.__class__.__name__}"
|
|
54
|
+
)
|
|
55
|
+
return True
|
|
56
|
+
else:
|
|
57
|
+
console.logger.error(
|
|
58
|
+
f"Failed to connect to {self.__class__.__name__}"
|
|
59
|
+
)
|
|
60
|
+
return False
|
|
61
|
+
except Exception as e:
|
|
62
|
+
console.logger.error(
|
|
63
|
+
f"Connection failed for {self.__class__.__name__}: {e}"
|
|
64
|
+
)
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
@abc.abstractmethod
|
|
68
|
+
def _connect(self) -> bool:
|
|
69
|
+
"""
|
|
70
|
+
Implement connection logic for the specific datafeed.
|
|
71
|
+
|
|
72
|
+
Returns:
|
|
73
|
+
bool: True if connection successful, False otherwise.
|
|
74
|
+
"""
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
def disconnect(self) -> bool:
|
|
78
|
+
"""
|
|
79
|
+
Disconnect from the datafeed.
|
|
80
|
+
|
|
81
|
+
Returns:
|
|
82
|
+
bool: True if disconnection successful, False otherwise.
|
|
83
|
+
"""
|
|
84
|
+
with self._lock:
|
|
85
|
+
if not self._is_connected:
|
|
86
|
+
console.logger.warning(
|
|
87
|
+
f"{self.__class__.__name__} already disconnected"
|
|
88
|
+
)
|
|
89
|
+
return True
|
|
90
|
+
|
|
91
|
+
console.logger.info(f"Disconnecting from {self.__class__.__name__}...")
|
|
92
|
+
try:
|
|
93
|
+
success = self._disconnect()
|
|
94
|
+
if success:
|
|
95
|
+
self._is_connected = False
|
|
96
|
+
self._watched_symbols.clear()
|
|
97
|
+
console.logger.info(
|
|
98
|
+
f"Successfully disconnected from {self.__class__.__name__}"
|
|
99
|
+
)
|
|
100
|
+
return True
|
|
101
|
+
else:
|
|
102
|
+
console.logger.error(
|
|
103
|
+
f"Failed to disconnect from {self.__class__.__name__}"
|
|
104
|
+
)
|
|
105
|
+
return False
|
|
106
|
+
except Exception as e:
|
|
107
|
+
console.logger.error(
|
|
108
|
+
f"Disconnection failed for {self.__class__.__name__}: {e}"
|
|
109
|
+
)
|
|
110
|
+
self._is_connected = False
|
|
111
|
+
self._watched_symbols.clear()
|
|
112
|
+
return False
|
|
113
|
+
|
|
114
|
+
@abc.abstractmethod
|
|
115
|
+
def _disconnect(self) -> bool:
|
|
116
|
+
"""
|
|
117
|
+
Implement disconnection logic for the specific datafeed.
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
bool: True if disconnection successful, False otherwise.
|
|
121
|
+
"""
|
|
122
|
+
pass
|
|
123
|
+
|
|
124
|
+
def watch(self, symbols: list[tuple[str, models.TimeFrame]]) -> bool:
|
|
125
|
+
"""
|
|
126
|
+
Start watching market data for the specified symbols and timeframes.
|
|
127
|
+
|
|
128
|
+
Args:
|
|
129
|
+
symbols: List of (symbol, timeframe) tuples to start watching.
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
bool: True if watching started successfully, False otherwise.
|
|
133
|
+
"""
|
|
134
|
+
if not symbols:
|
|
135
|
+
console.logger.warning("No symbols provided for watching")
|
|
136
|
+
return True
|
|
137
|
+
|
|
138
|
+
with self._lock:
|
|
139
|
+
if not self._is_connected:
|
|
140
|
+
console.logger.error("Cannot start watching: datafeed not connected")
|
|
141
|
+
return False
|
|
142
|
+
|
|
143
|
+
new_symbols = set(symbols) - self._watched_symbols
|
|
144
|
+
if not new_symbols:
|
|
145
|
+
console.logger.info("All requested symbols are already being watched")
|
|
146
|
+
return True
|
|
147
|
+
|
|
148
|
+
try:
|
|
149
|
+
success = self._watch(list(new_symbols))
|
|
150
|
+
if success:
|
|
151
|
+
self._watched_symbols.update(new_symbols)
|
|
152
|
+
console.logger.info(
|
|
153
|
+
f"Successfully started watching {len(new_symbols)} symbols"
|
|
154
|
+
)
|
|
155
|
+
return True
|
|
156
|
+
else:
|
|
157
|
+
console.logger.error("Failed to start watching symbols")
|
|
158
|
+
return False
|
|
159
|
+
except Exception as e:
|
|
160
|
+
console.logger.error(f"Exception while starting watching: {e}")
|
|
161
|
+
return False
|
|
162
|
+
|
|
163
|
+
@abc.abstractmethod
|
|
164
|
+
def _watch(self, symbols: list[tuple[str, models.TimeFrame]]) -> bool:
|
|
165
|
+
"""
|
|
166
|
+
Implement watching startup logic for the specific datafeed.
|
|
167
|
+
|
|
168
|
+
Args:
|
|
169
|
+
symbols: List of (symbol, timeframe) tuples to start watching.
|
|
170
|
+
These are guaranteed to be new symbols not already being watched.
|
|
171
|
+
|
|
172
|
+
Returns:
|
|
173
|
+
bool: True if watching started successfully, False otherwise.
|
|
174
|
+
"""
|
|
175
|
+
pass
|
|
176
|
+
|
|
177
|
+
def unwatch(self, symbols: list[tuple[str, models.TimeFrame]]) -> bool:
|
|
178
|
+
"""
|
|
179
|
+
Stop watching market data for the specified symbols and timeframes.
|
|
180
|
+
|
|
181
|
+
Args:
|
|
182
|
+
symbols: List of (symbol, timeframe) tuples to stop watching.
|
|
183
|
+
|
|
184
|
+
Returns:
|
|
185
|
+
bool: True if unwatching stopped successfully, False otherwise.
|
|
186
|
+
"""
|
|
187
|
+
if not symbols:
|
|
188
|
+
console.logger.warning("No symbols provided for unwatching")
|
|
189
|
+
return True
|
|
190
|
+
|
|
191
|
+
with self._lock:
|
|
192
|
+
if not self._is_connected:
|
|
193
|
+
console.logger.warning(
|
|
194
|
+
"Datafeed not connected, but removing symbols from tracking"
|
|
195
|
+
)
|
|
196
|
+
self._watched_symbols.difference_update(symbols)
|
|
197
|
+
return True
|
|
198
|
+
|
|
199
|
+
symbols_to_stop = set(symbols) & self._watched_symbols
|
|
200
|
+
if not symbols_to_stop:
|
|
201
|
+
console.logger.info(
|
|
202
|
+
"None of the requested symbols are currently being watched"
|
|
203
|
+
)
|
|
204
|
+
return True
|
|
205
|
+
|
|
206
|
+
console.logger.info(f"Unwatching {len(symbols_to_stop)} symbols")
|
|
207
|
+
try:
|
|
208
|
+
success = self._unwatch(list(symbols_to_stop))
|
|
209
|
+
if success:
|
|
210
|
+
self._watched_symbols.difference_update(symbols_to_stop)
|
|
211
|
+
console.logger.info(
|
|
212
|
+
f"Successfully unwatched {len(symbols_to_stop)} symbols"
|
|
213
|
+
)
|
|
214
|
+
return True
|
|
215
|
+
else:
|
|
216
|
+
console.logger.error("Failed to unwatch symbols")
|
|
217
|
+
return False
|
|
218
|
+
except Exception as e:
|
|
219
|
+
console.logger.error(f"Exception while unwatching: {e}")
|
|
220
|
+
self._watched_symbols.difference_update(symbols_to_stop)
|
|
221
|
+
return False
|
|
222
|
+
|
|
223
|
+
@abc.abstractmethod
|
|
224
|
+
def _unwatch(self, symbols: list[tuple[str, models.TimeFrame]]) -> bool:
|
|
225
|
+
"""
|
|
226
|
+
Implement unwatching logic for the specific datafeed.
|
|
227
|
+
|
|
228
|
+
Args:
|
|
229
|
+
symbols: List of (symbol, timeframe) tuples to stop watching.
|
|
230
|
+
These are guaranteed to be symbols currently being watched.
|
|
231
|
+
|
|
232
|
+
Returns:
|
|
233
|
+
bool: True if unwatching stopped successfully, False otherwise.
|
|
234
|
+
"""
|
|
235
|
+
pass
|
|
236
|
+
|
|
237
|
+
def is_connected(self) -> bool:
|
|
238
|
+
"""
|
|
239
|
+
Check if the datafeed is currently connected.
|
|
240
|
+
|
|
241
|
+
Returns:
|
|
242
|
+
bool: True if connected, False otherwise.
|
|
243
|
+
"""
|
|
244
|
+
with self._lock:
|
|
245
|
+
return self._is_connected
|
|
246
|
+
|
|
247
|
+
def get_watched_symbols(self) -> set[tuple[str, models.TimeFrame]]:
|
|
248
|
+
"""
|
|
249
|
+
Get the set of currently watched symbols and timeframes.
|
|
250
|
+
|
|
251
|
+
Returns:
|
|
252
|
+
set: Set of (symbol, timeframe) tuples currently being watched.
|
|
253
|
+
"""
|
|
254
|
+
with self._lock:
|
|
255
|
+
return self._watched_symbols.copy()
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: onesecondtrader
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.10.1
|
|
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,7 +1,9 @@
|
|
|
1
1
|
onesecondtrader/__init__.py,sha256=TNqlT20sH46-J7F6giBxwWYG1-wFZZt7toDbZeQK6KQ,210
|
|
2
2
|
onesecondtrader/core/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
3
|
-
onesecondtrader/core/models.py,sha256=
|
|
3
|
+
onesecondtrader/core/models.py,sha256=gvspEZp7pISZgpHeaKNQfvNJgwZY7DnS_kWpoGwXC-c,3940
|
|
4
4
|
onesecondtrader/core/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
5
|
+
onesecondtrader/datafeeds/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
|
+
onesecondtrader/datafeeds/base_datafeed.py,sha256=cHt8bdA9zON6CJLjz7blgNcs4xu4-iWxM15s3Gu3FO0,8774
|
|
5
7
|
onesecondtrader/messaging/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
6
8
|
onesecondtrader/messaging/eventbus.py,sha256=R2K85INeYVwJ1tMOybC3WpRraK0ZKVe8WehCbAzzznU,19359
|
|
7
9
|
onesecondtrader/messaging/events.py,sha256=eaWXQQIUnRNOR-9n5-6lyLbZ6bUtzjD4GI567U_vh4g,23625
|
|
@@ -9,7 +11,7 @@ onesecondtrader/monitoring/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJ
|
|
|
9
11
|
onesecondtrader/monitoring/console.py,sha256=1mrojXkyL4ro7ebkvDMGNQiCL-93WEylRuwnfmEKzVs,299
|
|
10
12
|
onesecondtrader/monitoring/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
11
13
|
onesecondtrader/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
|
12
|
-
onesecondtrader-0.
|
|
13
|
-
onesecondtrader-0.
|
|
14
|
-
onesecondtrader-0.
|
|
15
|
-
onesecondtrader-0.
|
|
14
|
+
onesecondtrader-0.10.1.dist-info/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
|
|
15
|
+
onesecondtrader-0.10.1.dist-info/METADATA,sha256=tGtxjkcRkaC39mi4glsawyMVYHmuBDzpsZQwR4-k3nY,9519
|
|
16
|
+
onesecondtrader-0.10.1.dist-info/WHEEL,sha256=b4K_helf-jlQoXBBETfwnf4B04YC67LOev0jo4fX5m8,88
|
|
17
|
+
onesecondtrader-0.10.1.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|