onesecondtrader 0.54.0__py3-none-any.whl → 0.56.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.
@@ -14,17 +14,19 @@ class OrderSubmissionRequest(RequestBase):
14
14
 
15
15
  The `system_order_id` is a unique identifier assigned by the system to the order submission request by default at object creation.
16
16
 
17
- | Field | Type | Semantics |
18
- |-------------------|--------------------------|----------------------------------------------------------------------------|
19
- | `ts_event_ns` | `int` | Time at which the submission request was issued, as UTC epoch nanoseconds. |
20
- | `ts_created_ns` | `int` | Time at which the event object was created, as UTC epoch nanoseconds. |
21
- | `system_order_id` | `uuid.UUID` | System-assigned unique identifier for the order submission. |
22
- | `symbol` | `str` | Identifier of the traded instrument. |
23
- | `order_type` | `models.OrderType` | Execution constraint of the order. |
24
- | `side` | `models.TradeSide` | Direction of the trade. |
25
- | `quantity` | `float` | Requested order quantity. |
26
- | `limit_price` | `float` or `None` | Limit price, if applicable to the order type. |
27
- | `stop_price` | `float` or `None` | Stop price, if applicable to the order type. |
17
+ | Field | Type | Semantics |
18
+ |-------------------|----------------------------|----------------------------------------------------------------------------|
19
+ | `ts_event_ns` | `int` | Time at which the submission request was issued, as UTC epoch nanoseconds. |
20
+ | `ts_created_ns` | `int` | Time at which the event object was created, as UTC epoch nanoseconds. |
21
+ | `system_order_id` | `uuid.UUID` | System-assigned unique identifier for the order submission. |
22
+ | `symbol` | `str` | Identifier of the traded instrument. |
23
+ | `order_type` | `models.OrderType` | Execution constraint of the order. |
24
+ | `side` | `models.TradeSide` | Direction of the trade. |
25
+ | `quantity` | `float` | Requested order quantity. |
26
+ | `limit_price` | `float` or `None` | Limit price, if applicable to the order type. |
27
+ | `stop_price` | `float` or `None` | Stop price, if applicable to the order type. |
28
+ | `action` | `models.ActionType` or `None` | Intent of the order from the strategy's perspective (e.g., entry, exit). |
29
+ | `signal` | `str` or `None` | Optional signal name or identifier that triggered this order. |
28
30
  """
29
31
 
30
32
  system_order_id: uuid.UUID = dataclasses.field(default_factory=uuid.uuid4)
@@ -33,3 +35,5 @@ class OrderSubmissionRequest(RequestBase):
33
35
  quantity: float
34
36
  limit_price: float | None = None
35
37
  stop_price: float | None = None
38
+ action: models.ActionType | None = None
39
+ signal: str | None = None
@@ -2,6 +2,7 @@
2
2
  Defines the fundamental domain concepts used throughout the trading system.
3
3
  """
4
4
 
5
+ from .action_types import ActionType
5
6
  from .bar_fields import BarField
6
7
  from .bar_period import BarPeriod
7
8
  from .order_types import OrderType
@@ -13,6 +14,7 @@ from .rejection_reasons import (
13
14
  from .trade_sides import TradeSide
14
15
 
15
16
  __all__ = [
17
+ "ActionType",
16
18
  "BarField",
17
19
  "BarPeriod",
18
20
  "OrderType",
@@ -0,0 +1,34 @@
1
+ from __future__ import annotations
2
+
3
+ import enum
4
+
5
+
6
+ class ActionType(enum.Enum):
7
+ """
8
+ Enumeration of trading action types.
9
+
10
+ `ActionType` specifies the intent or purpose of an order from the strategy's perspective,
11
+ describing what the order is meant to accomplish in terms of position management.
12
+
13
+ | Value | Semantics |
14
+ |---------------|----------------------------------------------------------------------------|
15
+ | `ENTRY` | Opens a new position (direction-agnostic). |
16
+ | `ENTRY_LONG` | Opens a new long position. |
17
+ | `ENTRY_SHORT` | Opens a new short position. |
18
+ | `EXIT` | Closes an existing position (direction-agnostic). |
19
+ | `EXIT_LONG` | Closes an existing long position. |
20
+ | `EXIT_SHORT` | Closes an existing short position. |
21
+ | `ADD` | Increases the size of an existing position. |
22
+ | `REDUCE` | Decreases the size of an existing position without fully closing it. |
23
+ | `REVERSE` | Closes the current position and opens a new one in the opposite direction. |
24
+ """
25
+
26
+ ENTRY = enum.auto()
27
+ ENTRY_LONG = enum.auto()
28
+ ENTRY_SHORT = enum.auto()
29
+ EXIT = enum.auto()
30
+ EXIT_LONG = enum.auto()
31
+ EXIT_SHORT = enum.auto()
32
+ ADD = enum.auto()
33
+ REDUCE = enum.auto()
34
+ REVERSE = enum.auto()
@@ -0,0 +1,8 @@
1
+ """
2
+ Orchestrates the execution of a trading run and records all events to a SQLite database.
3
+ """
4
+
5
+ from .orchestrator import Orchestrator
6
+ from .run_recorder import RunRecorder
7
+
8
+ __all__ = ["Orchestrator", "RunRecorder"]
@@ -0,0 +1,161 @@
1
+ from __future__ import annotations
2
+
3
+ import pathlib
4
+
5
+ import dotenv
6
+ import pandas as pd
7
+
8
+ from onesecondtrader import messaging, models
9
+ from onesecondtrader.brokers.base import BrokerBase
10
+ from onesecondtrader.datafeeds.base import DatafeedBase
11
+ from onesecondtrader.strategies.base import StrategyBase
12
+ from .run_recorder import RunRecorder
13
+
14
+
15
+ class Orchestrator:
16
+ """
17
+ Orchestrates the execution of a trading run.
18
+
19
+ The orchestrator instantiates strategies, broker, datafeed, and recorder components,
20
+ connects them via an event bus, and coordinates the run lifecycle from start to shutdown.
21
+ """
22
+
23
+ db_path: str = "runs.db"
24
+ mode: str = "backtest"
25
+
26
+ def __init__(
27
+ self,
28
+ strategies: list[type[StrategyBase]],
29
+ broker: type[BrokerBase],
30
+ datafeed: type[DatafeedBase],
31
+ ) -> None:
32
+ """
33
+ Initialize the orchestrator with component classes.
34
+
35
+ Parameters:
36
+ strategies:
37
+ List of strategy classes to instantiate for the run.
38
+ broker:
39
+ Broker class to instantiate for order execution.
40
+ datafeed:
41
+ Datafeed class to instantiate for market data delivery.
42
+ """
43
+ dotenv.load_dotenv()
44
+ self._strategy_classes = strategies
45
+ self._broker_class = broker
46
+ self._datafeed_class = datafeed
47
+ self._event_bus: messaging.EventBus | None = None
48
+ self._strategies: list[StrategyBase] = []
49
+ self._broker: BrokerBase | None = None
50
+ self._datafeed: DatafeedBase | None = None
51
+ self._recorder: RunRecorder | None = None
52
+
53
+ def run(self) -> None:
54
+ """
55
+ Execute the trading run.
56
+
57
+ Creates all components, connects them, subscribes to symbols, waits for
58
+ the datafeed to complete, and then shuts down all components.
59
+ """
60
+ run_id = self._generate_run_id()
61
+
62
+ self._event_bus = messaging.EventBus()
63
+
64
+ self._recorder = self._create_recorder(run_id)
65
+ self._broker = self._broker_class(self._event_bus)
66
+ self._strategies = [s(self._event_bus) for s in self._strategy_classes]
67
+ self._datafeed = self._datafeed_class(self._event_bus)
68
+
69
+ try:
70
+ self._broker.connect()
71
+ self._datafeed.connect()
72
+ self._subscribe_symbols()
73
+ self._datafeed.wait_until_complete()
74
+ self._event_bus.wait_until_system_idle()
75
+ self._recorder.update_run_status(
76
+ "completed", pd.Timestamp.now(tz="UTC").value
77
+ )
78
+ except Exception:
79
+ if self._recorder:
80
+ self._recorder.update_run_status(
81
+ "failed", pd.Timestamp.now(tz="UTC").value
82
+ )
83
+ raise
84
+ finally:
85
+ self._shutdown()
86
+
87
+ def _generate_run_id(self) -> str:
88
+ """
89
+ Generate a unique run identifier.
90
+
91
+ Returns:
92
+ A string combining the current UTC timestamp and strategy names.
93
+ """
94
+ timestamp = pd.Timestamp.now(tz="UTC").strftime("%Y-%m-%d_%H-%M-%S")
95
+ strategy_names = "_".join(s.name for s in self._strategy_classes)
96
+ return f"{timestamp}_{strategy_names}"
97
+
98
+ def _collect_symbols(self) -> list[str]:
99
+ """
100
+ Collect all unique symbols from the strategy classes.
101
+
102
+ Returns:
103
+ A deduplicated list of symbols from all strategies.
104
+ """
105
+ symbols = []
106
+ for strategy_class in self._strategy_classes:
107
+ symbols.extend(strategy_class.symbols)
108
+ return list(set(symbols))
109
+
110
+ def _create_recorder(self, run_id: str) -> RunRecorder:
111
+ """
112
+ Create and return a RunRecorder instance for this run.
113
+
114
+ Parameters:
115
+ run_id:
116
+ Unique identifier for this run.
117
+
118
+ Returns:
119
+ A configured RunRecorder instance.
120
+ """
121
+ assert self._event_bus is not None
122
+ config = {
123
+ "mode": self.mode,
124
+ "symbols": self._collect_symbols(),
125
+ "strategies": [s.name for s in self._strategy_classes],
126
+ }
127
+ return RunRecorder(
128
+ event_bus=self._event_bus,
129
+ db_path=pathlib.Path(self.db_path),
130
+ run_id=run_id,
131
+ name="_".join(s.name for s in self._strategy_classes),
132
+ config=config,
133
+ )
134
+
135
+ def _subscribe_symbols(self) -> None:
136
+ """
137
+ Subscribe the datafeed to symbols for each strategy's bar period.
138
+ """
139
+ assert self._datafeed is not None
140
+ subscriptions: dict[models.BarPeriod, list[str]] = {}
141
+ for strategy_class in self._strategy_classes:
142
+ bar_period_value = strategy_class.parameters["bar_period"].default
143
+ assert isinstance(bar_period_value, models.BarPeriod)
144
+ if bar_period_value not in subscriptions:
145
+ subscriptions[bar_period_value] = []
146
+ subscriptions[bar_period_value].extend(strategy_class.symbols)
147
+ for bar_period, symbols in subscriptions.items():
148
+ self._datafeed.subscribe(list(set(symbols)), bar_period)
149
+
150
+ def _shutdown(self) -> None:
151
+ """
152
+ Shut down all components in the correct order.
153
+ """
154
+ if self._datafeed:
155
+ self._datafeed.disconnect()
156
+ if self._broker:
157
+ self._broker.disconnect()
158
+ for strategy in self._strategies:
159
+ strategy.shutdown()
160
+ if self._recorder:
161
+ self._recorder.shutdown()