onesecondtrader 0.41.0__py3-none-any.whl → 0.44.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 -58
- onesecondtrader/models/__init__.py +11 -0
- onesecondtrader/models/bar_fields.py +23 -0
- onesecondtrader/models/bar_period.py +21 -0
- onesecondtrader/models/order_types.py +21 -0
- onesecondtrader/models/trade_sides.py +20 -0
- {onesecondtrader-0.41.0.dist-info → onesecondtrader-0.44.0.dist-info}/METADATA +2 -2
- onesecondtrader-0.44.0.dist-info/RECORD +10 -0
- onesecondtrader/connectors/__init__.py +0 -3
- onesecondtrader/connectors/brokers/__init__.py +0 -4
- onesecondtrader/connectors/brokers/ib.py +0 -418
- onesecondtrader/connectors/brokers/simulated.py +0 -349
- onesecondtrader/connectors/datafeeds/__init__.py +0 -4
- onesecondtrader/connectors/datafeeds/ib.py +0 -286
- onesecondtrader/connectors/datafeeds/simulated.py +0 -167
- onesecondtrader/connectors/gateways/__init__.py +0 -3
- onesecondtrader/connectors/gateways/ib.py +0 -314
- onesecondtrader/core/__init__.py +0 -7
- onesecondtrader/core/brokers/__init__.py +0 -3
- onesecondtrader/core/brokers/base.py +0 -46
- onesecondtrader/core/datafeeds/__init__.py +0 -3
- onesecondtrader/core/datafeeds/base.py +0 -32
- onesecondtrader/core/events/__init__.py +0 -33
- onesecondtrader/core/events/bases.py +0 -29
- onesecondtrader/core/events/market.py +0 -22
- onesecondtrader/core/events/requests.py +0 -31
- onesecondtrader/core/events/responses.py +0 -54
- onesecondtrader/core/indicators/__init__.py +0 -13
- onesecondtrader/core/indicators/averages.py +0 -56
- onesecondtrader/core/indicators/bar.py +0 -47
- onesecondtrader/core/indicators/base.py +0 -60
- onesecondtrader/core/messaging/__init__.py +0 -7
- onesecondtrader/core/messaging/eventbus.py +0 -47
- onesecondtrader/core/messaging/subscriber.py +0 -69
- onesecondtrader/core/models/__init__.py +0 -14
- onesecondtrader/core/models/data.py +0 -18
- onesecondtrader/core/models/orders.py +0 -15
- onesecondtrader/core/models/params.py +0 -21
- onesecondtrader/core/models/records.py +0 -32
- onesecondtrader/core/strategies/__init__.py +0 -7
- onesecondtrader/core/strategies/base.py +0 -324
- onesecondtrader/core/strategies/examples.py +0 -43
- onesecondtrader/dashboard/__init__.py +0 -3
- onesecondtrader/dashboard/app.py +0 -1677
- onesecondtrader/dashboard/registry.py +0 -100
- onesecondtrader/orchestrator/__init__.py +0 -7
- onesecondtrader/orchestrator/orchestrator.py +0 -105
- onesecondtrader/orchestrator/recorder.py +0 -196
- onesecondtrader/orchestrator/schema.sql +0 -208
- onesecondtrader/secmaster/__init__.py +0 -6
- onesecondtrader/secmaster/schema.sql +0 -740
- onesecondtrader/secmaster/utils.py +0 -737
- onesecondtrader-0.41.0.dist-info/RECORD +0 -49
- {onesecondtrader-0.41.0.dist-info → onesecondtrader-0.44.0.dist-info}/WHEEL +0 -0
- {onesecondtrader-0.41.0.dist-info → onesecondtrader-0.44.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import dataclasses
|
|
4
|
-
import uuid
|
|
5
|
-
|
|
6
|
-
from onesecondtrader.core import models
|
|
7
|
-
from . import bases
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
11
|
-
class OrderSubmission(bases.BrokerRequestEvent):
|
|
12
|
-
system_order_id: uuid.UUID = dataclasses.field(default_factory=uuid.uuid4)
|
|
13
|
-
symbol: str
|
|
14
|
-
order_type: models.orders.OrderType
|
|
15
|
-
side: models.orders.OrderSide
|
|
16
|
-
quantity: float
|
|
17
|
-
limit_price: float | None = None
|
|
18
|
-
stop_price: float | None = None
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
22
|
-
class OrderCancellation(bases.BrokerRequestEvent):
|
|
23
|
-
symbol: str
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
27
|
-
class OrderModification(bases.BrokerRequestEvent):
|
|
28
|
-
symbol: str
|
|
29
|
-
quantity: float | None = None
|
|
30
|
-
limit_price: float | None = None
|
|
31
|
-
stop_price: float | None = None
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import dataclasses
|
|
4
|
-
import uuid
|
|
5
|
-
|
|
6
|
-
from onesecondtrader.core import models
|
|
7
|
-
from . import bases
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
11
|
-
class OrderSubmissionAccepted(bases.BrokerResponseEvent):
|
|
12
|
-
broker_order_id: str | None = None
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
16
|
-
class OrderSubmissionRejected(bases.BrokerResponseEvent):
|
|
17
|
-
reason: str | None = None
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
21
|
-
class OrderModificationAccepted(bases.BrokerResponseEvent):
|
|
22
|
-
broker_order_id: str | None = None
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
26
|
-
class OrderModificationRejected(bases.BrokerResponseEvent):
|
|
27
|
-
reason: str | None = None
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
31
|
-
class OrderCancellationAccepted(bases.BrokerResponseEvent):
|
|
32
|
-
pass
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
36
|
-
class OrderCancellationRejected(bases.BrokerResponseEvent):
|
|
37
|
-
reason: str | None = None
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
41
|
-
class OrderFilled(bases.BrokerResponseEvent):
|
|
42
|
-
fill_id: uuid.UUID = dataclasses.field(default_factory=uuid.uuid4)
|
|
43
|
-
broker_fill_id: str | None = None
|
|
44
|
-
symbol: str
|
|
45
|
-
side: models.orders.OrderSide
|
|
46
|
-
quantity_filled: float
|
|
47
|
-
fill_price: float
|
|
48
|
-
commission: float
|
|
49
|
-
exchange: str = "SIMULATED"
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
@dataclasses.dataclass(kw_only=True, frozen=True)
|
|
53
|
-
class OrderExpired(bases.BrokerResponseEvent):
|
|
54
|
-
pass
|
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import collections
|
|
4
|
-
|
|
5
|
-
import numpy as np
|
|
6
|
-
|
|
7
|
-
from onesecondtrader.core import events, models
|
|
8
|
-
from .base import Indicator
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
class SimpleMovingAverage(Indicator):
|
|
12
|
-
def __init__(
|
|
13
|
-
self,
|
|
14
|
-
period: int = 200,
|
|
15
|
-
max_history: int = 100,
|
|
16
|
-
input_source: models.InputSource = models.InputSource.CLOSE,
|
|
17
|
-
plot_at: int = 0,
|
|
18
|
-
) -> None:
|
|
19
|
-
super().__init__(max_history=max_history, plot_at=plot_at)
|
|
20
|
-
self.period: int = max(1, int(period))
|
|
21
|
-
self.input_source: models.InputSource = input_source
|
|
22
|
-
self._window: dict[str, collections.deque[float]] = {}
|
|
23
|
-
|
|
24
|
-
@property
|
|
25
|
-
def name(self) -> str:
|
|
26
|
-
return f"SMA_{self.period}_{self.input_source.name}"
|
|
27
|
-
|
|
28
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
29
|
-
symbol = incoming_bar.symbol
|
|
30
|
-
if symbol not in self._window:
|
|
31
|
-
self._window[symbol] = collections.deque(maxlen=self.period)
|
|
32
|
-
window = self._window[symbol]
|
|
33
|
-
value = self._extract_input(incoming_bar)
|
|
34
|
-
window.append(value)
|
|
35
|
-
if len(window) < self.period:
|
|
36
|
-
return np.nan
|
|
37
|
-
return sum(window) / self.period
|
|
38
|
-
|
|
39
|
-
def _extract_input(self, incoming_bar: events.BarReceived) -> float:
|
|
40
|
-
match self.input_source:
|
|
41
|
-
case models.InputSource.OPEN:
|
|
42
|
-
return incoming_bar.open
|
|
43
|
-
case models.InputSource.HIGH:
|
|
44
|
-
return incoming_bar.high
|
|
45
|
-
case models.InputSource.LOW:
|
|
46
|
-
return incoming_bar.low
|
|
47
|
-
case models.InputSource.CLOSE:
|
|
48
|
-
return incoming_bar.close
|
|
49
|
-
case models.InputSource.VOLUME:
|
|
50
|
-
return (
|
|
51
|
-
float(incoming_bar.volume)
|
|
52
|
-
if incoming_bar.volume is not None
|
|
53
|
-
else np.nan
|
|
54
|
-
)
|
|
55
|
-
case _:
|
|
56
|
-
return incoming_bar.close
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from onesecondtrader.core import events
|
|
2
|
-
from .base import Indicator
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class Open(Indicator):
|
|
6
|
-
@property
|
|
7
|
-
def name(self) -> str:
|
|
8
|
-
return "OPEN"
|
|
9
|
-
|
|
10
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
11
|
-
return incoming_bar.open
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
class High(Indicator):
|
|
15
|
-
@property
|
|
16
|
-
def name(self) -> str:
|
|
17
|
-
return "HIGH"
|
|
18
|
-
|
|
19
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
20
|
-
return incoming_bar.high
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
class Low(Indicator):
|
|
24
|
-
@property
|
|
25
|
-
def name(self) -> str:
|
|
26
|
-
return "LOW"
|
|
27
|
-
|
|
28
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
29
|
-
return incoming_bar.low
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
class Close(Indicator):
|
|
33
|
-
@property
|
|
34
|
-
def name(self) -> str:
|
|
35
|
-
return "CLOSE"
|
|
36
|
-
|
|
37
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
38
|
-
return incoming_bar.close
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
class Volume(Indicator):
|
|
42
|
-
@property
|
|
43
|
-
def name(self) -> str:
|
|
44
|
-
return "VOLUME"
|
|
45
|
-
|
|
46
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
47
|
-
return float(incoming_bar.volume) if incoming_bar.volume is not None else 0.0
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import abc
|
|
4
|
-
import collections
|
|
5
|
-
import threading
|
|
6
|
-
|
|
7
|
-
import numpy as np
|
|
8
|
-
|
|
9
|
-
from onesecondtrader.core import events
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class Indicator(abc.ABC):
|
|
13
|
-
def __init__(self, max_history: int = 100, plot_at: int = 99) -> None:
|
|
14
|
-
self._lock = threading.Lock()
|
|
15
|
-
self._max_history = max(1, int(max_history))
|
|
16
|
-
self._current_symbol: str = ""
|
|
17
|
-
self._history_data: dict[str, collections.deque[float]] = {}
|
|
18
|
-
self._plot_at = plot_at
|
|
19
|
-
|
|
20
|
-
@property
|
|
21
|
-
@abc.abstractmethod
|
|
22
|
-
def name(self) -> str:
|
|
23
|
-
pass
|
|
24
|
-
|
|
25
|
-
@abc.abstractmethod
|
|
26
|
-
def _compute_indicator(self, incoming_bar: events.BarReceived) -> float:
|
|
27
|
-
pass
|
|
28
|
-
|
|
29
|
-
def update(self, incoming_bar: events.BarReceived) -> None:
|
|
30
|
-
symbol = incoming_bar.symbol
|
|
31
|
-
self._current_symbol = symbol
|
|
32
|
-
value = self._compute_indicator(incoming_bar)
|
|
33
|
-
with self._lock:
|
|
34
|
-
if symbol not in self._history_data:
|
|
35
|
-
self._history_data[symbol] = collections.deque(maxlen=self._max_history)
|
|
36
|
-
self._history_data[symbol].append(value)
|
|
37
|
-
|
|
38
|
-
@property
|
|
39
|
-
def latest(self) -> float:
|
|
40
|
-
with self._lock:
|
|
41
|
-
h = self._history_data.get(self._current_symbol, collections.deque())
|
|
42
|
-
return h[-1] if h else np.nan
|
|
43
|
-
|
|
44
|
-
@property
|
|
45
|
-
def history(self) -> collections.deque[float]:
|
|
46
|
-
with self._lock:
|
|
47
|
-
h = self._history_data.get(self._current_symbol, collections.deque())
|
|
48
|
-
return collections.deque(h, maxlen=self._max_history)
|
|
49
|
-
|
|
50
|
-
def __getitem__(self, index: int) -> float:
|
|
51
|
-
# Returns np.nan on out-of-bounds access. Since np.nan comparisons always
|
|
52
|
-
# return False, strategies can skip explicit length checks.
|
|
53
|
-
try:
|
|
54
|
-
return self.history[index]
|
|
55
|
-
except IndexError:
|
|
56
|
-
return np.nan
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def plot_at(self) -> int:
|
|
60
|
-
return self._plot_at
|
|
@@ -1,47 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import collections
|
|
4
|
-
import threading
|
|
5
|
-
import typing
|
|
6
|
-
|
|
7
|
-
from onesecondtrader.core import events
|
|
8
|
-
|
|
9
|
-
if typing.TYPE_CHECKING:
|
|
10
|
-
from .subscriber import Subscriber
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class EventBus:
|
|
14
|
-
def __init__(self) -> None:
|
|
15
|
-
self._per_event_subscriptions: collections.defaultdict[
|
|
16
|
-
type[events.bases.EventBase], set[Subscriber]
|
|
17
|
-
] = collections.defaultdict(set)
|
|
18
|
-
self._subscribers: set[Subscriber] = set()
|
|
19
|
-
self._lock: threading.Lock = threading.Lock()
|
|
20
|
-
|
|
21
|
-
def subscribe(
|
|
22
|
-
self,
|
|
23
|
-
subscriber: Subscriber,
|
|
24
|
-
event_type: type[events.bases.EventBase],
|
|
25
|
-
) -> None:
|
|
26
|
-
with self._lock:
|
|
27
|
-
self._subscribers.add(subscriber)
|
|
28
|
-
self._per_event_subscriptions[event_type].add(subscriber)
|
|
29
|
-
|
|
30
|
-
def unsubscribe(self, subscriber: Subscriber) -> None:
|
|
31
|
-
with self._lock:
|
|
32
|
-
for set_of_event_subscribers in self._per_event_subscriptions.values():
|
|
33
|
-
set_of_event_subscribers.discard(subscriber)
|
|
34
|
-
self._subscribers.discard(subscriber)
|
|
35
|
-
|
|
36
|
-
def publish(self, event: events.bases.EventBase) -> None:
|
|
37
|
-
# Intentionally matches exact event types only, not parent classes
|
|
38
|
-
with self._lock:
|
|
39
|
-
subscribers = self._per_event_subscriptions[type(event)].copy()
|
|
40
|
-
for subscriber in subscribers:
|
|
41
|
-
subscriber.receive(event)
|
|
42
|
-
|
|
43
|
-
def wait_until_system_idle(self) -> None:
|
|
44
|
-
with self._lock:
|
|
45
|
-
subscribers = self._subscribers.copy()
|
|
46
|
-
for subscriber in subscribers:
|
|
47
|
-
subscriber.wait_until_idle()
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import abc
|
|
2
|
-
import queue
|
|
3
|
-
import threading
|
|
4
|
-
|
|
5
|
-
from onesecondtrader.core 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,14 +0,0 @@
|
|
|
1
|
-
__all__ = [
|
|
2
|
-
"BarPeriod",
|
|
3
|
-
"InputSource",
|
|
4
|
-
"OrderSide",
|
|
5
|
-
"OrderType",
|
|
6
|
-
"OrderRecord",
|
|
7
|
-
"FillRecord",
|
|
8
|
-
"ParamSpec",
|
|
9
|
-
]
|
|
10
|
-
|
|
11
|
-
from .data import BarPeriod, InputSource
|
|
12
|
-
from .orders import OrderSide, OrderType
|
|
13
|
-
from .records import OrderRecord, FillRecord
|
|
14
|
-
from .params import ParamSpec
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class BarPeriod(enum.Enum):
|
|
7
|
-
SECOND = enum.auto()
|
|
8
|
-
MINUTE = enum.auto()
|
|
9
|
-
HOUR = enum.auto()
|
|
10
|
-
DAY = enum.auto()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class InputSource(enum.Enum):
|
|
14
|
-
OPEN = enum.auto()
|
|
15
|
-
HIGH = enum.auto()
|
|
16
|
-
LOW = enum.auto()
|
|
17
|
-
CLOSE = enum.auto()
|
|
18
|
-
VOLUME = enum.auto()
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import enum
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
class OrderType(enum.Enum):
|
|
7
|
-
LIMIT = enum.auto()
|
|
8
|
-
MARKET = enum.auto()
|
|
9
|
-
STOP = enum.auto()
|
|
10
|
-
STOP_LIMIT = enum.auto()
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class OrderSide(enum.Enum):
|
|
14
|
-
BUY = enum.auto()
|
|
15
|
-
SELL = enum.auto()
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import dataclasses
|
|
4
|
-
import enum
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
@dataclasses.dataclass
|
|
8
|
-
class ParamSpec:
|
|
9
|
-
default: int | float | str | bool | enum.Enum
|
|
10
|
-
min: int | float | None = None
|
|
11
|
-
max: int | float | None = None
|
|
12
|
-
step: int | float | None = None
|
|
13
|
-
choices: list | None = None
|
|
14
|
-
|
|
15
|
-
@property
|
|
16
|
-
def resolved_choices(self) -> list | None:
|
|
17
|
-
if self.choices is not None:
|
|
18
|
-
return self.choices
|
|
19
|
-
if isinstance(self.default, enum.Enum):
|
|
20
|
-
return list(type(self.default))
|
|
21
|
-
return None
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
from __future__ import annotations
|
|
2
|
-
|
|
3
|
-
import dataclasses
|
|
4
|
-
import uuid
|
|
5
|
-
|
|
6
|
-
import pandas as pd
|
|
7
|
-
|
|
8
|
-
from . import orders
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
@dataclasses.dataclass
|
|
12
|
-
class OrderRecord:
|
|
13
|
-
order_id: uuid.UUID
|
|
14
|
-
symbol: str
|
|
15
|
-
order_type: orders.OrderType
|
|
16
|
-
side: orders.OrderSide
|
|
17
|
-
quantity: float
|
|
18
|
-
limit_price: float | None = None
|
|
19
|
-
stop_price: float | None = None
|
|
20
|
-
filled_quantity: float = 0.0
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
@dataclasses.dataclass
|
|
24
|
-
class FillRecord:
|
|
25
|
-
fill_id: uuid.UUID
|
|
26
|
-
order_id: uuid.UUID
|
|
27
|
-
symbol: str
|
|
28
|
-
side: orders.OrderSide
|
|
29
|
-
quantity: float
|
|
30
|
-
price: float
|
|
31
|
-
commission: float
|
|
32
|
-
ts_event: pd.Timestamp
|