onesecondtrader 0.34.0__py3-none-any.whl → 0.35.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.
@@ -0,0 +1,5 @@
1
+ __all__ = [
2
+ "CSVBookkeeper",
3
+ ]
4
+
5
+ from .csvbookkeeper import CSVBookkeeper
@@ -0,0 +1,180 @@
1
+ import pathlib
2
+
3
+ import pandas as pd
4
+
5
+ from onesecondtrader import events, messaging
6
+
7
+
8
+ class CSVBookkeeper(messaging.Subscriber):
9
+ BATCH_SIZE: int = 1000
10
+
11
+ def __init__(
12
+ self, event_bus: messaging.EventBus, results_path: pathlib.Path
13
+ ) -> None:
14
+ self._results_path = results_path
15
+ self._bars_buffer: list[dict] = []
16
+ self._fills_buffer: list[dict] = []
17
+ self._orders_buffer: list[dict] = []
18
+
19
+ super().__init__(event_bus)
20
+ self._subscribe(
21
+ events.BarProcessed,
22
+ events.OrderFilled,
23
+ events.OrderSubmission,
24
+ events.OrderModification,
25
+ events.OrderCancellation,
26
+ events.OrderSubmissionAccepted,
27
+ events.OrderModificationAccepted,
28
+ events.OrderCancellationAccepted,
29
+ events.OrderSubmissionRejected,
30
+ events.OrderModificationRejected,
31
+ events.OrderCancellationRejected,
32
+ events.OrderExpired,
33
+ )
34
+
35
+ def _on_event(self, event: events.EventBase) -> None:
36
+ match event:
37
+ case events.BarProcessed() as e:
38
+ self._on_processed_bar(e)
39
+ case events.OrderFilled() as e:
40
+ self._on_fill(e)
41
+ case events.OrderSubmission() as e:
42
+ self._on_order_event(e, "submission_requested")
43
+ case events.OrderModification() as e:
44
+ self._on_order_event(e, "modification_requested")
45
+ case events.OrderCancellation() as e:
46
+ self._on_order_event(e, "cancellation_requested")
47
+ case events.OrderSubmissionAccepted() as e:
48
+ self._on_order_event(e, "submission_accepted")
49
+ case events.OrderModificationAccepted() as e:
50
+ self._on_order_event(e, "modification_accepted")
51
+ case events.OrderCancellationAccepted() as e:
52
+ self._on_order_event(e, "cancellation_accepted")
53
+ case events.OrderSubmissionRejected() as e:
54
+ self._on_order_event(e, "submission_rejected")
55
+ case events.OrderModificationRejected() as e:
56
+ self._on_order_event(e, "modification_rejected")
57
+ case events.OrderCancellationRejected() as e:
58
+ self._on_order_event(e, "cancellation_rejected")
59
+ case events.OrderExpired() as e:
60
+ self._on_order_event(e, "expired")
61
+
62
+ def _on_processed_bar(self, event: events.BarProcessed) -> None:
63
+ record = {
64
+ "ts_event": event.ts_event,
65
+ "symbol": event.symbol,
66
+ "bar_period": event.bar_period.name,
67
+ "open": event.open,
68
+ "high": event.high,
69
+ "low": event.low,
70
+ "close": event.close,
71
+ "volume": event.volume,
72
+ }
73
+ record.update(event.indicators)
74
+ self._bars_buffer.append(record)
75
+ if len(self._bars_buffer) >= self.BATCH_SIZE:
76
+ self._flush_bars()
77
+
78
+ def _on_fill(self, event: events.OrderFilled) -> None:
79
+ self._fills_buffer.append(
80
+ {
81
+ "ts_event": event.ts_event,
82
+ "fill_id": str(event.fill_id),
83
+ "broker_fill_id": event.broker_fill_id,
84
+ "order_id": str(event.associated_order_id),
85
+ "symbol": event.symbol,
86
+ "side": event.side.name,
87
+ "quantity": event.quantity_filled,
88
+ "price": event.fill_price,
89
+ "commission": event.commission,
90
+ "exchange": event.exchange,
91
+ }
92
+ )
93
+ if len(self._fills_buffer) >= self.BATCH_SIZE:
94
+ self._flush_fills()
95
+
96
+ def _on_order_event(self, event: events.EventBase, event_type: str) -> None:
97
+ record: dict = {
98
+ "ts_event": event.ts_event,
99
+ "event_type": event_type,
100
+ }
101
+ match event:
102
+ case events.OrderSubmission():
103
+ record.update(
104
+ {
105
+ "order_id": str(event.system_order_id),
106
+ "symbol": event.symbol,
107
+ "order_type": event.order_type.name,
108
+ "side": event.side.name,
109
+ "quantity": event.quantity,
110
+ "limit_price": event.limit_price,
111
+ "stop_price": event.stop_price,
112
+ }
113
+ )
114
+ case events.OrderModification():
115
+ record.update(
116
+ {
117
+ "order_id": str(event.system_order_id),
118
+ "symbol": event.symbol,
119
+ "quantity": event.quantity,
120
+ "limit_price": event.limit_price,
121
+ "stop_price": event.stop_price,
122
+ }
123
+ )
124
+ case events.OrderCancellation():
125
+ record.update(
126
+ {
127
+ "order_id": str(event.system_order_id),
128
+ "symbol": event.symbol,
129
+ }
130
+ )
131
+ case events.OrderSubmissionAccepted() | events.OrderModificationAccepted():
132
+ record.update(
133
+ {
134
+ "order_id": str(event.associated_order_id),
135
+ "broker_order_id": event.broker_order_id,
136
+ }
137
+ )
138
+ case events.OrderCancellationAccepted():
139
+ record.update({"order_id": str(event.associated_order_id)})
140
+ case (
141
+ events.OrderSubmissionRejected()
142
+ | events.OrderModificationRejected()
143
+ | events.OrderCancellationRejected()
144
+ ):
145
+ record.update({"order_id": str(event.associated_order_id)})
146
+ case events.OrderExpired():
147
+ record.update({"order_id": str(event.associated_order_id)})
148
+
149
+ self._orders_buffer.append(record)
150
+ if len(self._orders_buffer) >= self.BATCH_SIZE:
151
+ self._flush_orders()
152
+
153
+ def _flush_bars(self) -> None:
154
+ if not self._bars_buffer:
155
+ return
156
+ df = pd.DataFrame(self._bars_buffer)
157
+ path = self._results_path / "processed_bars.csv"
158
+ df.to_csv(path, mode="a", header=not path.exists(), index=False)
159
+ self._bars_buffer.clear()
160
+
161
+ def _flush_fills(self) -> None:
162
+ if not self._fills_buffer:
163
+ return
164
+ df = pd.DataFrame(self._fills_buffer)
165
+ path = self._results_path / "fills.csv"
166
+ df.to_csv(path, mode="a", header=not path.exists(), index=False)
167
+ self._fills_buffer.clear()
168
+
169
+ def _flush_orders(self) -> None:
170
+ if not self._orders_buffer:
171
+ return
172
+ df = pd.DataFrame(self._orders_buffer)
173
+ path = self._results_path / "orders.csv"
174
+ df.to_csv(path, mode="a", header=not path.exists(), index=False)
175
+ self._orders_buffer.clear()
176
+
177
+ def _cleanup(self) -> None:
178
+ self._flush_bars()
179
+ self._flush_fills()
180
+ self._flush_orders()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onesecondtrader
3
- Version: 0.34.0
3
+ Version: 0.35.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
@@ -21,10 +21,12 @@ onesecondtrader/models/__init__.py,sha256=7amHCQ6BAhHKps0ke63E-zh8IJNmkdDogZq-Pf
21
21
  onesecondtrader/models/data.py,sha256=fBmddVl6EXYC5u2UnvQ59DXAXeZeIb48KP1ZdeTL52A,322
22
22
  onesecondtrader/models/orders.py,sha256=y6Ar-6fMqaOd_hRnRGvfWUF0Z13H_2hfTOW3ROOk0A8,254
23
23
  onesecondtrader/models/records.py,sha256=vdCWBtoDQs5R4iB_8_3fXkxWEvoCxOssk9XBnS4l7Vk,599
24
+ onesecondtrader/observers/__init__.py,sha256=fYF9tUW4H7L6Iueqkn2wnBf2LpXZtfdppqG4RkZCi2M,77
25
+ onesecondtrader/observers/csvbookkeeper.py,sha256=hTRHhithHY4r2bjgroO2DchvTDOM6DEO3m6jdvWeUeM,7021
24
26
  onesecondtrader/strategies/__init__.py,sha256=5TlEckz3RnwZTs1Isj0wJ_9Og5R9MMXBL90Vu9b45io,126
25
27
  onesecondtrader/strategies/base.py,sha256=kIi6by4Y8YuB9gPMPMr2Unm5_i9SGAANyiW2UaHiRO0,11206
26
28
  onesecondtrader/strategies/sma_crossover.py,sha256=s2u_uL_D5CrZTACiAbojnrLrLf4jqIPdfOCiNDEIsDA,1119
27
- onesecondtrader-0.34.0.dist-info/METADATA,sha256=N-0PPAPIFmnllV7fvuNLRNJSrRfyWoHT3SIVDOSPOU8,9682
28
- onesecondtrader-0.34.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
29
- onesecondtrader-0.34.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
30
- onesecondtrader-0.34.0.dist-info/RECORD,,
29
+ onesecondtrader-0.35.0.dist-info/METADATA,sha256=3qckSVPhiHalNJt8HeQSto06RfjM3Af84DtXgJ9m5lo,9682
30
+ onesecondtrader-0.35.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
31
+ onesecondtrader-0.35.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
32
+ onesecondtrader-0.35.0.dist-info/RECORD,,