onesecondtrader 0.14.2__py3-none-any.whl → 0.16.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/__init__.py +0 -12
- onesecondtrader/indicators.py +102 -0
- onesecondtrader/ontology.py +18 -0
- {onesecondtrader-0.14.2.dist-info → onesecondtrader-0.16.0.dist-info}/METADATA +2 -1
- onesecondtrader-0.16.0.dist-info/RECORD +7 -0
- onesecondtrader/brokers/__init__.py +0 -0
- onesecondtrader/brokers/base_broker.py +0 -99
- onesecondtrader/brokers/simulated_broker.py +0 -10
- onesecondtrader/core/__init__.py +0 -0
- onesecondtrader/core/models.py +0 -188
- onesecondtrader/core/portfolio.py +0 -359
- onesecondtrader/core/py.typed +0 -0
- onesecondtrader/datafeeds/__init__.py +0 -0
- onesecondtrader/datafeeds/base_datafeed.py +0 -54
- onesecondtrader/datafeeds/csv_datafeed.py +0 -297
- onesecondtrader/indicators/__init__.py +0 -0
- onesecondtrader/indicators/base_indicator.py +0 -136
- onesecondtrader/indicators/moving_averages.py +0 -132
- onesecondtrader/messaging/__init__.py +0 -9
- onesecondtrader/messaging/eventbus.py +0 -499
- onesecondtrader/messaging/events.py +0 -868
- onesecondtrader/monitoring/__init__.py +0 -0
- onesecondtrader/monitoring/console.py +0 -14
- onesecondtrader/monitoring/py.typed +0 -0
- onesecondtrader/py.typed +0 -0
- onesecondtrader/strategies/__init__.py +0 -0
- onesecondtrader/strategies/base_strategy.py +0 -46
- onesecondtrader-0.14.2.dist-info/RECORD +0 -27
- {onesecondtrader-0.14.2.dist-info → onesecondtrader-0.16.0.dist-info}/WHEEL +0 -0
- {onesecondtrader-0.14.2.dist-info → onesecondtrader-0.16.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,359 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module provides the Portfolio class.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import threading
|
|
6
|
-
from collections.abc import Iterable
|
|
7
|
-
from onesecondtrader import messaging
|
|
8
|
-
from onesecondtrader.messaging import events
|
|
9
|
-
from onesecondtrader.monitoring import console
|
|
10
|
-
from onesecondtrader.brokers import base_broker
|
|
11
|
-
from onesecondtrader.strategies import base_strategy
|
|
12
|
-
from onesecondtrader.core.models import StrategyShutdownMode
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
class Portfolio:
|
|
16
|
-
"""
|
|
17
|
-
The Portfolio class orchestrates the trading infrastructure's components.
|
|
18
|
-
It manages the broker connection, market data reception, and strategy execution.
|
|
19
|
-
|
|
20
|
-
Multiple instances of the same Strategy class can be registered concurrently.
|
|
21
|
-
Symbol ownership is exclusive and enforced by the portfolio: each symbol may be
|
|
22
|
-
owned by at most one strategy instance at a time. Use `add_strategy()` with a list
|
|
23
|
-
of symbols or `assign_symbols(...)` with a specific strategy and a list of symbols
|
|
24
|
-
to claim symbols; `owner_of(symbol)` returns the current owner.
|
|
25
|
-
"""
|
|
26
|
-
|
|
27
|
-
def __init__(
|
|
28
|
-
self,
|
|
29
|
-
event_bus: messaging.EventBus | None = None,
|
|
30
|
-
broker_class: type[base_broker.BaseBroker] | None = None,
|
|
31
|
-
):
|
|
32
|
-
"""
|
|
33
|
-
Initialize the Portfolio class, subscribe to events, and connect to the broker.
|
|
34
|
-
|
|
35
|
-
Args:
|
|
36
|
-
event_bus (EventBus | None): Event bus to use; defaults to
|
|
37
|
-
system_event_bus when None.
|
|
38
|
-
broker_class (type[base_broker.BaseBroker] | None): Broker class to
|
|
39
|
-
instantiate and connect. Must be a subclass of BaseBroker.
|
|
40
|
-
|
|
41
|
-
Attributes:
|
|
42
|
-
self.event_bus (eventbus.EventBus): Event bus used for communication between
|
|
43
|
-
the trading infrastructure's components.
|
|
44
|
-
self._lock (threading.Lock): Lock for thread-safe operations.
|
|
45
|
-
self._strategies (set[base_strategy.Strategy]): Registered strategy
|
|
46
|
-
instances.
|
|
47
|
-
self._symbol_owner (dict[str, base_strategy.Strategy]): Exclusive symbol
|
|
48
|
-
ownership map; each symbol is owned by at most one strategy instance at
|
|
49
|
-
a time.
|
|
50
|
-
self.strategy_removal_pending (set[base_strategy.Strategy]): Set of
|
|
51
|
-
strategies that are still active but marked for removal once all symbols
|
|
52
|
-
are released.
|
|
53
|
-
self.broker (base_broker.BaseBroker | None): Instantiated broker; may be
|
|
54
|
-
disconnected if connect failed.
|
|
55
|
-
"""
|
|
56
|
-
# INITIALIZE EVENT BUS
|
|
57
|
-
# ------------------------------------------------------------------------------
|
|
58
|
-
self.event_bus: messaging.EventBus = (
|
|
59
|
-
event_bus if event_bus else messaging.system_event_bus
|
|
60
|
-
)
|
|
61
|
-
|
|
62
|
-
# SUBSCRIBE HANDLER METHODS TO EVENTS VIA event_bus.subscribe
|
|
63
|
-
# ------------------------------------------------------------------------------
|
|
64
|
-
self.event_bus.subscribe(events.Strategy.SymbolRelease, self.on_symbol_release)
|
|
65
|
-
|
|
66
|
-
# INITIALIZE LOCK FOR THREAD-SAFE OPERATIONS WITHIN THE PORTFOLIO
|
|
67
|
-
# ------------------------------------------------------------------------------
|
|
68
|
-
self._lock = threading.Lock()
|
|
69
|
-
|
|
70
|
-
# KEEP TRACK OF STRATEGIES AND SYMBOL OWNERSHIP
|
|
71
|
-
# ------------------------------------------------------------------------------
|
|
72
|
-
self._strategies: set[base_strategy.Strategy] = set()
|
|
73
|
-
self.strategy_removal_pending: set[base_strategy.Strategy] = set()
|
|
74
|
-
self._symbol_owner: dict[str, base_strategy.Strategy] = {}
|
|
75
|
-
|
|
76
|
-
# INITIALIZE BROKER
|
|
77
|
-
# ------------------------------------------------------------------------------
|
|
78
|
-
# TODO Decouple by also doing this via an event
|
|
79
|
-
self.broker: base_broker.BaseBroker | None = None
|
|
80
|
-
if broker_class is None or not issubclass(broker_class, base_broker.BaseBroker):
|
|
81
|
-
broker_name = (
|
|
82
|
-
getattr(broker_class, "__name__", str(broker_class))
|
|
83
|
-
if broker_class
|
|
84
|
-
else None
|
|
85
|
-
)
|
|
86
|
-
console.logger.error(
|
|
87
|
-
"Portfolio requires a valid broker_class (subclass of BaseBroker), "
|
|
88
|
-
f"got {broker_name}"
|
|
89
|
-
)
|
|
90
|
-
return
|
|
91
|
-
try:
|
|
92
|
-
self.broker = broker_class(self.event_bus)
|
|
93
|
-
except Exception as e:
|
|
94
|
-
console.logger.error(
|
|
95
|
-
f"Failed to instantiate broker "
|
|
96
|
-
f"{getattr(broker_class, '__name__', str(broker_class))}: {e}"
|
|
97
|
-
)
|
|
98
|
-
return
|
|
99
|
-
|
|
100
|
-
# CONNECT TO BROKER
|
|
101
|
-
# ------------------------------------------------------------------------------
|
|
102
|
-
try:
|
|
103
|
-
connected = self.broker.connect()
|
|
104
|
-
if not connected:
|
|
105
|
-
console.logger.error(
|
|
106
|
-
f"Failed to connect broker {type(self.broker).__name__}"
|
|
107
|
-
)
|
|
108
|
-
except Exception as e:
|
|
109
|
-
console.logger.error(f"Broker connect failed: {e}")
|
|
110
|
-
|
|
111
|
-
def add_strategy(
|
|
112
|
-
self,
|
|
113
|
-
strategy_instance: base_strategy.Strategy,
|
|
114
|
-
symbols: Iterable[str] | None = None,
|
|
115
|
-
) -> bool:
|
|
116
|
-
"""
|
|
117
|
-
Register a Strategy instance and optionally assign a list of symbols to it.
|
|
118
|
-
|
|
119
|
-
If symbols are provided, potential conflicts are checked first under a lock.
|
|
120
|
-
If any conflicts exist, no symbols are assigned; a warning is logged listing
|
|
121
|
-
both non_conflicting and conflicting symbols and instructions to use
|
|
122
|
-
assign_symbols(...) are provided.
|
|
123
|
-
If no conflicts exist, all provided symbols are claimed by the strategy.
|
|
124
|
-
|
|
125
|
-
Args:
|
|
126
|
-
strategy_instance (base_strategy.Strategy): Strategy instance to register.
|
|
127
|
-
symbols (Iterable[str] | None): Optional list of symbols to assign to the
|
|
128
|
-
strategy.
|
|
129
|
-
|
|
130
|
-
Returns:
|
|
131
|
-
bool: True if the strategy was registered, False otherwise.
|
|
132
|
-
"""
|
|
133
|
-
# VALIDATE THAT INSTANCE IS A SUBCLASS OF base_strategy.Strategy
|
|
134
|
-
# ------------------------------------------------------------------------------
|
|
135
|
-
if not isinstance(strategy_instance, base_strategy.Strategy):
|
|
136
|
-
console.logger.error("add_strategy: strategy must inherit from Strategy")
|
|
137
|
-
return False
|
|
138
|
-
|
|
139
|
-
# ADD STRATEGY INSTANCE TO REGISTRY IF NOT ALREADY REGISTERED
|
|
140
|
-
# ------------------------------------------------------------------------------
|
|
141
|
-
with self._lock:
|
|
142
|
-
if strategy_instance in self._strategies:
|
|
143
|
-
console.logger.warning("add_strategy: strategy already registered")
|
|
144
|
-
return False
|
|
145
|
-
self._strategies.add(strategy_instance)
|
|
146
|
-
|
|
147
|
-
# ASSIGN SYMBOLS IF PROVIDED AND NO CONFLICTS EXIST, ELSE LOG WARNING
|
|
148
|
-
# ------------------------------------------------------------------------------
|
|
149
|
-
if symbols is not None:
|
|
150
|
-
# Create an ordered list of unique, non-empty, trimmed symbols
|
|
151
|
-
symbols_list = list(
|
|
152
|
-
dict.fromkeys(s.strip() for s in symbols if s and s.strip())
|
|
153
|
-
)
|
|
154
|
-
|
|
155
|
-
# Check for conflicts, claim symbols for strategy if no conflicts arise
|
|
156
|
-
if symbols_list:
|
|
157
|
-
non_conflicting: list[str] = []
|
|
158
|
-
conflicting: list[str] = []
|
|
159
|
-
with self._lock:
|
|
160
|
-
for sym in symbols_list:
|
|
161
|
-
owner = self._symbol_owner.get(sym)
|
|
162
|
-
if owner is None or owner is strategy_instance:
|
|
163
|
-
non_conflicting.append(sym)
|
|
164
|
-
else:
|
|
165
|
-
conflicting.append(sym)
|
|
166
|
-
if conflicting:
|
|
167
|
-
console.logger.warning(
|
|
168
|
-
"add_strategy: symbols not assigned due to conflicts; "
|
|
169
|
-
"use Portfolio.assign_symbols(...) after resolving. "
|
|
170
|
-
f"non_conflicting={non_conflicting}, conflicts={conflicting}"
|
|
171
|
-
)
|
|
172
|
-
return False
|
|
173
|
-
else:
|
|
174
|
-
for sym in symbols_list:
|
|
175
|
-
self._symbol_owner[sym] = strategy_instance
|
|
176
|
-
self.event_bus.publish(
|
|
177
|
-
events.Strategy.SymbolAssignment(
|
|
178
|
-
strategy=strategy_instance,
|
|
179
|
-
symbol_list=symbols_list,
|
|
180
|
-
)
|
|
181
|
-
)
|
|
182
|
-
return True
|
|
183
|
-
|
|
184
|
-
return True
|
|
185
|
-
|
|
186
|
-
def remove_strategy(
|
|
187
|
-
self,
|
|
188
|
-
strategy_instance: base_strategy.Strategy,
|
|
189
|
-
shutdown_mode: StrategyShutdownMode = StrategyShutdownMode.SOFT,
|
|
190
|
-
) -> bool:
|
|
191
|
-
"""
|
|
192
|
-
Mark a strategy for removal and request it to close its positions in the manner
|
|
193
|
-
dictated via the `shutdown_mode` argument (default to soft shutdown, i.e. wait
|
|
194
|
-
for open positions to close naturally and release symbols once they are flat).
|
|
195
|
-
|
|
196
|
-
Args:
|
|
197
|
-
strategy_instance (base_strategy.Strategy): Strategy instance to remove.
|
|
198
|
-
shutdown_mode (StrategyShutdownMode): Shutdown mode to use. Defaults to
|
|
199
|
-
StrategyShutdownMode.SOFT.
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
# IF STRATEGY IS REGISTERED, MARK IT FOR REMOVAL AND PUBLISH STOP TRADING EVENT
|
|
203
|
-
# ------------------------------------------------------------------------------
|
|
204
|
-
with self._lock:
|
|
205
|
-
if strategy_instance not in self._strategies:
|
|
206
|
-
console.logger.warning("remove_strategy: strategy not registered")
|
|
207
|
-
return False
|
|
208
|
-
self.strategy_removal_pending.add(strategy_instance)
|
|
209
|
-
|
|
210
|
-
# PUBLISH STOP TRADING REQUEST TO EVENT BUS
|
|
211
|
-
# ------------------------------------------------------------------------------
|
|
212
|
-
self.event_bus.publish(
|
|
213
|
-
events.Strategy.StopTrading(
|
|
214
|
-
strategy=strategy_instance,
|
|
215
|
-
shutdown_mode=shutdown_mode,
|
|
216
|
-
)
|
|
217
|
-
)
|
|
218
|
-
return True
|
|
219
|
-
|
|
220
|
-
def assign_symbols(
|
|
221
|
-
self, strategy_instance: base_strategy.Strategy, symbols: Iterable[str]
|
|
222
|
-
):
|
|
223
|
-
"""
|
|
224
|
-
Assign a list of symbols to a strategy.
|
|
225
|
-
|
|
226
|
-
Args:
|
|
227
|
-
strategy_instance (base_strategy.Strategy): Strategy instance to assign
|
|
228
|
-
symbols to.
|
|
229
|
-
symbols (Iterable[str]): List of symbols to assign.
|
|
230
|
-
"""
|
|
231
|
-
# IF STRATEGY IS REGISTERED, MARK IT FOR REMOVAL AND PUBLISH STOP TRADING EVENT
|
|
232
|
-
# ------------------------------------------------------------------------------
|
|
233
|
-
with self._lock:
|
|
234
|
-
if strategy_instance not in self._strategies:
|
|
235
|
-
console.logger.warning("remove_strategy: strategy not registered")
|
|
236
|
-
return False
|
|
237
|
-
self.strategy_removal_pending.add(strategy_instance)
|
|
238
|
-
|
|
239
|
-
# ASSIGN SYMBOLS IF PROVIDED AND NO CONFLICTS EXIST, ELSE LOG WARNING
|
|
240
|
-
# ------------------------------------------------------------------------------
|
|
241
|
-
# TODO This is an repetition of the same logic as in add_strategy; refactor
|
|
242
|
-
|
|
243
|
-
if symbols is not None:
|
|
244
|
-
# Create an ordered list of unique, non-empty, trimmed symbols
|
|
245
|
-
symbols_list = list(
|
|
246
|
-
dict.fromkeys(s.strip() for s in symbols if s and s.strip())
|
|
247
|
-
)
|
|
248
|
-
|
|
249
|
-
# Check for conflicts, claim symbols for strategy if no conflicts arise
|
|
250
|
-
if symbols_list:
|
|
251
|
-
non_conflicting: list[str] = []
|
|
252
|
-
conflicting: list[str] = []
|
|
253
|
-
with self._lock:
|
|
254
|
-
for sym in symbols_list:
|
|
255
|
-
owner = self._symbol_owner.get(sym)
|
|
256
|
-
if owner is None or owner is strategy_instance:
|
|
257
|
-
non_conflicting.append(sym)
|
|
258
|
-
else:
|
|
259
|
-
conflicting.append(sym)
|
|
260
|
-
if conflicting:
|
|
261
|
-
console.logger.warning(
|
|
262
|
-
"assign_symbols: symbols not assigned due to conflicts; "
|
|
263
|
-
"use Portfolio.assign_symbols(...) after resolving. "
|
|
264
|
-
f"non_conflicting={non_conflicting}, conflicts={conflicting}"
|
|
265
|
-
)
|
|
266
|
-
return False
|
|
267
|
-
else:
|
|
268
|
-
for sym in symbols_list:
|
|
269
|
-
self._symbol_owner[sym] = strategy_instance
|
|
270
|
-
self.event_bus.publish(
|
|
271
|
-
events.Strategy.SymbolAssignment(
|
|
272
|
-
strategy=strategy_instance,
|
|
273
|
-
symbol_list=symbols_list,
|
|
274
|
-
)
|
|
275
|
-
)
|
|
276
|
-
return True
|
|
277
|
-
|
|
278
|
-
def unassign_symbols(
|
|
279
|
-
self, strategy: base_strategy.Strategy, symbols: Iterable[str]
|
|
280
|
-
) -> list[str]:
|
|
281
|
-
if not isinstance(strategy, base_strategy.Strategy):
|
|
282
|
-
console.logger.error(
|
|
283
|
-
"unassign_symbols: strategy must inherit from Strategy"
|
|
284
|
-
)
|
|
285
|
-
return []
|
|
286
|
-
symbols_list = list(
|
|
287
|
-
dict.fromkeys(s.strip() for s in symbols if s and s.strip())
|
|
288
|
-
)
|
|
289
|
-
if not symbols_list:
|
|
290
|
-
return []
|
|
291
|
-
removed: list[str] = []
|
|
292
|
-
with self._lock:
|
|
293
|
-
for sym in symbols_list:
|
|
294
|
-
if self._symbol_owner.get(sym) is strategy:
|
|
295
|
-
del self._symbol_owner[sym]
|
|
296
|
-
removed.append(sym)
|
|
297
|
-
if removed:
|
|
298
|
-
strategy.remove_symbols(removed)
|
|
299
|
-
return removed
|
|
300
|
-
|
|
301
|
-
def owner_of(self, symbol: str) -> base_strategy.Strategy | None:
|
|
302
|
-
"""
|
|
303
|
-
Return the owning strategy for a symbol or None if unowned.
|
|
304
|
-
"""
|
|
305
|
-
with self._lock:
|
|
306
|
-
return self._symbol_owner.get(symbol)
|
|
307
|
-
|
|
308
|
-
def on_symbol_release(self, event: events.Base.Event) -> None:
|
|
309
|
-
"""
|
|
310
|
-
Handle symbol release events. Ignores unrelated event types.
|
|
311
|
-
|
|
312
|
-
If a symbol is released, it is unassigned from the strategy that owns it
|
|
313
|
-
(inside the symbol_owner registry). If the strategy is marked for removal and
|
|
314
|
-
has no more symbols assigned to it, it is automatically deregistered.
|
|
315
|
-
"""
|
|
316
|
-
|
|
317
|
-
# IGNORE UNRELATED EVENT TYPES
|
|
318
|
-
# ------------------------------------------------------------------------------
|
|
319
|
-
if not isinstance(event, events.Strategy.SymbolRelease):
|
|
320
|
-
return
|
|
321
|
-
|
|
322
|
-
# IF STRATEGY IS REGISTERED, RELEASE SYMBOL FROM STRATEGY
|
|
323
|
-
# ------------------------------------------------------------------------------
|
|
324
|
-
# TODO This needs reworking; this will be the same logic as unassig_symbols
|
|
325
|
-
strategy = event.strategy
|
|
326
|
-
with self._lock:
|
|
327
|
-
if strategy not in self._strategies:
|
|
328
|
-
console.logger.warning("on_symbol_release: strategy not registered")
|
|
329
|
-
return
|
|
330
|
-
removed = self.unassign_symbols(strategy, [event.symbol])
|
|
331
|
-
if not removed:
|
|
332
|
-
console.logger.warning(
|
|
333
|
-
f"on_symbol_release: symbol {event.symbol} not owned by "
|
|
334
|
-
f"{getattr(event.strategy, 'name', type(event.strategy).__name__)}"
|
|
335
|
-
)
|
|
336
|
-
return
|
|
337
|
-
pending = False
|
|
338
|
-
with self._lock:
|
|
339
|
-
pending = strategy in self.strategy_removal_pending
|
|
340
|
-
has_owned_left = any(
|
|
341
|
-
owner is strategy for owner in self._symbol_owner.values()
|
|
342
|
-
)
|
|
343
|
-
if pending and not has_owned_left:
|
|
344
|
-
try:
|
|
345
|
-
if bool(strategy.is_flat()):
|
|
346
|
-
with self._lock:
|
|
347
|
-
if strategy in self._strategies:
|
|
348
|
-
self._strategies.remove(strategy)
|
|
349
|
-
self.strategy_removal_pending.discard(strategy)
|
|
350
|
-
console.logger.info(
|
|
351
|
-
f"Strategy {getattr(strategy, 'name', type(strategy).__name__)} "
|
|
352
|
-
f"removed: all symbols released and flat"
|
|
353
|
-
)
|
|
354
|
-
except Exception:
|
|
355
|
-
pass
|
|
356
|
-
console.logger.info(
|
|
357
|
-
f"on_symbol_release: symbol {event.symbol} released from "
|
|
358
|
-
f"{getattr(event.strategy, 'name', type(event.strategy).__name__)}"
|
|
359
|
-
)
|
onesecondtrader/core/py.typed
DELETED
|
File without changes
|
|
File without changes
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"""
|
|
2
|
-
This module provides the base class for all datafeeds.
|
|
3
|
-
"""
|
|
4
|
-
|
|
5
|
-
import abc
|
|
6
|
-
from onesecondtrader import messaging
|
|
7
|
-
from onesecondtrader.core import models
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
class BaseDatafeed(abc.ABC):
|
|
11
|
-
"""
|
|
12
|
-
Base class for all datafeeds.
|
|
13
|
-
"""
|
|
14
|
-
|
|
15
|
-
def __init__(self, event_bus: messaging.EventBus | None = None):
|
|
16
|
-
self.event_bus: messaging.EventBus = (
|
|
17
|
-
event_bus if event_bus else messaging.system_event_bus
|
|
18
|
-
)
|
|
19
|
-
|
|
20
|
-
@abc.abstractmethod
|
|
21
|
-
def connect(self):
|
|
22
|
-
"""
|
|
23
|
-
Connect to the datafeed.
|
|
24
|
-
"""
|
|
25
|
-
pass
|
|
26
|
-
|
|
27
|
-
@abc.abstractmethod
|
|
28
|
-
def watch(self, symbols: list[tuple[str, models.RecordType]]):
|
|
29
|
-
"""
|
|
30
|
-
Start watching symbols.
|
|
31
|
-
|
|
32
|
-
Args:
|
|
33
|
-
symbols (list[tuple[str, models.TimeFrame]]): List of symbols to watch with
|
|
34
|
-
their respective timeframes.
|
|
35
|
-
"""
|
|
36
|
-
pass
|
|
37
|
-
|
|
38
|
-
@abc.abstractmethod
|
|
39
|
-
def unwatch(self, symbols: list[tuple[str, models.RecordType]]):
|
|
40
|
-
"""
|
|
41
|
-
Stop watching symbols.
|
|
42
|
-
|
|
43
|
-
Args:
|
|
44
|
-
symbols (list[tuple[str, models.TimeFrame]]): List of symbols to stop
|
|
45
|
-
watching with their respective timeframes.
|
|
46
|
-
"""
|
|
47
|
-
pass
|
|
48
|
-
|
|
49
|
-
@abc.abstractmethod
|
|
50
|
-
def disconnect(self):
|
|
51
|
-
"""
|
|
52
|
-
Disconnect from the datafeed.
|
|
53
|
-
"""
|
|
54
|
-
pass
|