onesecondtrader 0.41.0__tar.gz → 0.43.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 (50) hide show
  1. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/PKG-INFO +1 -1
  2. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/pyproject.toml +2 -1
  3. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/__init__.py +2 -0
  4. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/datafeeds/simulated.py +42 -11
  5. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/events/requests.py +2 -0
  6. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/models/__init__.py +2 -1
  7. onesecondtrader-0.43.0/src/onesecondtrader/core/models/orders.py +27 -0
  8. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/models/records.py +2 -0
  9. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/strategies/base.py +8 -1
  10. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/strategies/examples.py +4 -0
  11. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/dashboard/app.py +1301 -6
  12. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/orchestrator/recorder.py +5 -2
  13. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/orchestrator/schema.sql +5 -1
  14. onesecondtrader-0.41.0/src/onesecondtrader/core/models/orders.py +0 -15
  15. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/LICENSE +0 -0
  16. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/README.md +0 -0
  17. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/__init__.py +0 -0
  18. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/brokers/__init__.py +0 -0
  19. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/brokers/ib.py +0 -0
  20. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/brokers/simulated.py +0 -0
  21. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/datafeeds/__init__.py +0 -0
  22. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/datafeeds/ib.py +0 -0
  23. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/gateways/__init__.py +0 -0
  24. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/connectors/gateways/ib.py +0 -0
  25. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/__init__.py +0 -0
  26. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/brokers/__init__.py +0 -0
  27. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/brokers/base.py +0 -0
  28. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/datafeeds/__init__.py +0 -0
  29. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/datafeeds/base.py +0 -0
  30. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/events/__init__.py +0 -0
  31. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/events/bases.py +0 -0
  32. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/events/market.py +0 -0
  33. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/events/responses.py +0 -0
  34. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/indicators/__init__.py +0 -0
  35. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/indicators/averages.py +0 -0
  36. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/indicators/bar.py +0 -0
  37. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/indicators/base.py +0 -0
  38. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/messaging/__init__.py +0 -0
  39. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/messaging/eventbus.py +0 -0
  40. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/messaging/subscriber.py +0 -0
  41. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/models/data.py +0 -0
  42. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/models/params.py +0 -0
  43. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/core/strategies/__init__.py +0 -0
  44. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/dashboard/__init__.py +0 -0
  45. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/dashboard/registry.py +0 -0
  46. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/orchestrator/__init__.py +0 -0
  47. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/orchestrator/orchestrator.py +0 -0
  48. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/secmaster/__init__.py +0 -0
  49. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/secmaster/schema.sql +0 -0
  50. {onesecondtrader-0.41.0 → onesecondtrader-0.43.0}/src/onesecondtrader/secmaster/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onesecondtrader
3
- Version: 0.41.0
3
+ Version: 0.43.0
4
4
  Summary: The Trading Infrastructure Toolkit for Python. Research, simulate, and deploy algorithmic trading strategies — all in one place.
5
5
  License-File: LICENSE
6
6
  Author: Nils P. Kujath
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "onesecondtrader"
3
- version = "0.41.0"
3
+ version = "0.43.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"}
@@ -64,6 +64,7 @@ build-backend = "poetry.core.masonry.api"
64
64
  explicit_package_bases = true
65
65
  mypy_path = "src"
66
66
  namespace_packages = true
67
+ exclude = ["ignore/"]
67
68
 
68
69
  [tool.pytest.ini_options]
69
70
  testpaths = ["tests"]
@@ -1,4 +1,5 @@
1
1
  __all__ = [
2
+ "ActionType",
2
3
  "BarPeriod",
3
4
  "BarProcessed",
4
5
  "BarReceived",
@@ -47,6 +48,7 @@ from onesecondtrader.core.indicators import (
47
48
  Volume,
48
49
  )
49
50
  from onesecondtrader.core.models import (
51
+ ActionType,
50
52
  BarPeriod,
51
53
  FillRecord,
52
54
  InputSource,
@@ -88,12 +88,16 @@ class SimulatedDatafeed(DatafeedBase):
88
88
 
89
89
  cursor = self._connection.cursor()
90
90
 
91
- instrument_ids = self._resolve_instrument_ids(cursor, symbols)
92
- if not instrument_ids:
91
+ symbology_map = self._load_symbology(cursor, symbols)
92
+ if not symbology_map:
93
93
  return
94
94
 
95
- instrument_to_symbol = {v: k for k, v in instrument_ids.items()}
96
- id_list = list(instrument_ids.values())
95
+ all_instrument_ids = set()
96
+ for entries in symbology_map.values():
97
+ for entry in entries:
98
+ all_instrument_ids.add(entry["instrument_id"])
99
+
100
+ id_list = list(all_instrument_ids)
97
101
  rtype_list = list(set(rtype_by_symbol.values()))
98
102
 
99
103
  placeholders_ids = ",".join("?" * len(id_list))
@@ -128,7 +132,10 @@ class SimulatedDatafeed(DatafeedBase):
128
132
  break
129
133
 
130
134
  instrument_id, rtype, ts_event, open_, high, low, close, volume = row
131
- symbol = instrument_to_symbol.get(instrument_id)
135
+
136
+ symbol = self._resolve_symbol_for_bar(
137
+ symbology_map, instrument_id, ts_event
138
+ )
132
139
  if symbol is None:
133
140
  continue
134
141
 
@@ -152,16 +159,40 @@ class SimulatedDatafeed(DatafeedBase):
152
159
  )
153
160
  self._event_bus.wait_until_system_idle()
154
161
 
155
- def _resolve_instrument_ids(
162
+ def _load_symbology(
156
163
  self, cursor: sqlite3.Cursor, symbols: list[str]
157
- ) -> dict[str, int]:
164
+ ) -> dict[str, list[dict]]:
158
165
  placeholders = ",".join("?" * len(symbols))
159
166
  query = f"""
160
- SELECT symbol, instrument_id
167
+ SELECT symbol, instrument_id, start_date, end_date
161
168
  FROM symbology
162
169
  WHERE symbol IN ({placeholders})
163
- GROUP BY symbol
164
- HAVING start_date = MAX(start_date)
170
+ ORDER BY symbol, start_date
165
171
  """
166
172
  cursor.execute(query, symbols)
167
- return {row[0]: row[1] for row in cursor.fetchall()}
173
+
174
+ result: dict[str, list[dict]] = {}
175
+ for row in cursor.fetchall():
176
+ symbol, instrument_id, start_date, end_date = row
177
+ start_ns = int(pd.Timestamp(start_date, tz="UTC").value)
178
+ end_ns = int(pd.Timestamp(end_date, tz="UTC").value)
179
+ if symbol not in result:
180
+ result[symbol] = []
181
+ result[symbol].append(
182
+ {
183
+ "instrument_id": instrument_id,
184
+ "start_ns": start_ns,
185
+ "end_ns": end_ns,
186
+ }
187
+ )
188
+ return result
189
+
190
+ def _resolve_symbol_for_bar(
191
+ self, symbology_map: dict[str, list[dict]], instrument_id: int, ts_event: int
192
+ ) -> str | None:
193
+ for symbol, entries in symbology_map.items():
194
+ for entry in entries:
195
+ if entry["instrument_id"] == instrument_id:
196
+ if entry["start_ns"] <= ts_event < entry["end_ns"]:
197
+ return symbol
198
+ return None
@@ -16,6 +16,8 @@ class OrderSubmission(bases.BrokerRequestEvent):
16
16
  quantity: float
17
17
  limit_price: float | None = None
18
18
  stop_price: float | None = None
19
+ action: models.orders.ActionType | None = None
20
+ signal: str | None = None
19
21
 
20
22
 
21
23
  @dataclasses.dataclass(kw_only=True, frozen=True)
@@ -1,4 +1,5 @@
1
1
  __all__ = [
2
+ "ActionType",
2
3
  "BarPeriod",
3
4
  "InputSource",
4
5
  "OrderSide",
@@ -9,6 +10,6 @@ __all__ = [
9
10
  ]
10
11
 
11
12
  from .data import BarPeriod, InputSource
12
- from .orders import OrderSide, OrderType
13
+ from .orders import ActionType, OrderSide, OrderType
13
14
  from .records import OrderRecord, FillRecord
14
15
  from .params import ParamSpec
@@ -0,0 +1,27 @@
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()
16
+
17
+
18
+ class ActionType(enum.Enum):
19
+ ENTRY = enum.auto()
20
+ ENTRY_LONG = enum.auto()
21
+ ENTRY_SHORT = enum.auto()
22
+ EXIT = enum.auto()
23
+ EXIT_LONG = enum.auto()
24
+ EXIT_SHORT = enum.auto()
25
+ ADD = enum.auto()
26
+ REDUCE = enum.auto()
27
+ REVERSE = enum.auto()
@@ -17,6 +17,8 @@ class OrderRecord:
17
17
  quantity: float
18
18
  limit_price: float | None = None
19
19
  stop_price: float | None = None
20
+ action: orders.ActionType | None = None
21
+ signal: str | None = None
20
22
  filled_quantity: float = 0.0
21
23
 
22
24
 
@@ -76,8 +76,9 @@ class StrategyBase(messaging.Subscriber, abc.ABC):
76
76
  quantity: float,
77
77
  limit_price: float | None = None,
78
78
  stop_price: float | None = None,
79
+ action: models.ActionType | None = None,
80
+ signal: str | None = None,
79
81
  ) -> uuid.UUID:
80
- # Uses bar timestamp for backtest compatibility; ts_created tracks real wall-clock time
81
82
  order_id = uuid.uuid4()
82
83
 
83
84
  event = events.OrderSubmission(
@@ -89,6 +90,8 @@ class StrategyBase(messaging.Subscriber, abc.ABC):
89
90
  quantity=quantity,
90
91
  limit_price=limit_price,
91
92
  stop_price=stop_price,
93
+ action=action,
94
+ signal=signal,
92
95
  )
93
96
 
94
97
  order = models.OrderRecord(
@@ -99,6 +102,8 @@ class StrategyBase(messaging.Subscriber, abc.ABC):
99
102
  quantity=quantity,
100
103
  limit_price=limit_price,
101
104
  stop_price=stop_price,
105
+ action=action,
106
+ signal=signal,
102
107
  )
103
108
 
104
109
  self._submitted_orders[order_id] = order
@@ -137,6 +142,8 @@ class StrategyBase(messaging.Subscriber, abc.ABC):
137
142
  stop_price=(
138
143
  stop_price if stop_price is not None else original_order.stop_price
139
144
  ),
145
+ action=original_order.action,
146
+ signal=original_order.signal,
140
147
  filled_quantity=original_order.filled_quantity,
141
148
  )
142
149
 
@@ -29,6 +29,8 @@ class SMACrossover(StrategyBase):
29
29
  models.OrderType.MARKET,
30
30
  models.OrderSide.BUY,
31
31
  self.quantity, # type: ignore[attr-defined]
32
+ action=models.ActionType.ENTRY,
33
+ signal="sma_crossover_up",
32
34
  )
33
35
 
34
36
  if (
@@ -40,4 +42,6 @@ class SMACrossover(StrategyBase):
40
42
  models.OrderType.MARKET,
41
43
  models.OrderSide.SELL,
42
44
  self.quantity, # type: ignore[attr-defined]
45
+ action=models.ActionType.EXIT,
46
+ signal="sma_crossover_down",
43
47
  )