onesecondtrader 0.39.0__py3-none-any.whl → 0.41.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.
Files changed (33) hide show
  1. onesecondtrader/__init__.py +8 -3
  2. onesecondtrader/connectors/__init__.py +1 -0
  3. onesecondtrader/connectors/brokers/__init__.py +2 -1
  4. onesecondtrader/connectors/brokers/ib.py +418 -0
  5. onesecondtrader/connectors/brokers/simulated.py +3 -0
  6. onesecondtrader/connectors/datafeeds/__init__.py +2 -2
  7. onesecondtrader/connectors/datafeeds/ib.py +286 -0
  8. onesecondtrader/connectors/datafeeds/simulated.py +141 -73
  9. onesecondtrader/connectors/gateways/__init__.py +3 -0
  10. onesecondtrader/connectors/gateways/ib.py +314 -0
  11. onesecondtrader/core/__init__.py +1 -0
  12. onesecondtrader/core/brokers/base.py +7 -0
  13. onesecondtrader/core/datafeeds/__init__.py +3 -0
  14. onesecondtrader/core/datafeeds/base.py +32 -0
  15. onesecondtrader/core/models/__init__.py +2 -0
  16. onesecondtrader/core/models/params.py +21 -0
  17. onesecondtrader/core/strategies/base.py +9 -3
  18. onesecondtrader/core/strategies/examples.py +15 -7
  19. onesecondtrader/dashboard/__init__.py +3 -0
  20. onesecondtrader/dashboard/app.py +1677 -0
  21. onesecondtrader/dashboard/registry.py +100 -0
  22. onesecondtrader/orchestrator/__init__.py +7 -0
  23. onesecondtrader/orchestrator/orchestrator.py +105 -0
  24. onesecondtrader/orchestrator/recorder.py +196 -0
  25. onesecondtrader/orchestrator/schema.sql +208 -0
  26. onesecondtrader/secmaster/schema.sql +48 -0
  27. onesecondtrader/secmaster/utils.py +90 -0
  28. {onesecondtrader-0.39.0.dist-info → onesecondtrader-0.41.0.dist-info}/METADATA +4 -1
  29. onesecondtrader-0.41.0.dist-info/RECORD +49 -0
  30. onesecondtrader/connectors/datafeeds/base.py +0 -19
  31. onesecondtrader-0.39.0.dist-info/RECORD +0 -37
  32. {onesecondtrader-0.39.0.dist-info → onesecondtrader-0.41.0.dist-info}/WHEEL +0 -0
  33. {onesecondtrader-0.39.0.dist-info → onesecondtrader-0.41.0.dist-info}/licenses/LICENSE +0 -0
@@ -187,6 +187,8 @@ def ingest_dbzip(zip_path: pathlib.Path, db_path: pathlib.Path) -> tuple[int, in
187
187
  _disable_bulk_loading(connection)
188
188
  connection.close()
189
189
 
190
+ update_meta(db_path)
191
+ update_symbol_coverage(db_path)
190
192
  return dbn_count, symbology_count
191
193
 
192
194
 
@@ -217,6 +219,8 @@ def ingest_dbn(dbn_path: pathlib.Path, db_path: pathlib.Path) -> int:
217
219
  finally:
218
220
  _disable_bulk_loading(connection)
219
221
  connection.close()
222
+ update_meta(db_path)
223
+ update_symbol_coverage(db_path)
220
224
  return count
221
225
 
222
226
 
@@ -645,3 +649,89 @@ def _instrument_to_tuple(record: databento.InstrumentDefMsg) -> tuple:
645
649
  record.group,
646
650
  record.ts_recv,
647
651
  )
652
+
653
+
654
+ def update_meta(db_path: pathlib.Path) -> None:
655
+ """
656
+ Compute and store aggregate statistics in the meta table.
657
+
658
+ This function runs expensive COUNT/MIN/MAX queries once and stores the results
659
+ in the meta table for fast retrieval by the dashboard.
660
+
661
+ Args:
662
+ db_path: Path to the secmaster SQLite database.
663
+ """
664
+ import time
665
+
666
+ connection = sqlite3.connect(str(db_path))
667
+ cursor = connection.cursor()
668
+
669
+ cursor.execute("SELECT COUNT(DISTINCT instrument_id) FROM symbology")
670
+ symbol_count = cursor.fetchone()[0]
671
+
672
+ cursor.execute("SELECT COUNT(*) FROM ohlcv")
673
+ ohlcv_count = cursor.fetchone()[0]
674
+
675
+ cursor.execute("SELECT MIN(ts_event), MAX(ts_event) FROM ohlcv")
676
+ row = cursor.fetchone()
677
+ min_ts, max_ts = row[0] or 0, row[1] or 0
678
+
679
+ cursor.execute("SELECT DISTINCT rtype FROM ohlcv ORDER BY rtype")
680
+ rtypes = ",".join(str(r[0]) for r in cursor.fetchall())
681
+
682
+ stats = [
683
+ ("symbol_count", str(symbol_count)),
684
+ ("ohlcv_record_count", str(ohlcv_count)),
685
+ ("ohlcv_min_ts", str(min_ts)),
686
+ ("ohlcv_max_ts", str(max_ts)),
687
+ ("ohlcv_schemas", rtypes),
688
+ ("last_updated", str(int(time.time()))),
689
+ ]
690
+
691
+ cursor.executemany(
692
+ "INSERT OR REPLACE INTO meta (key, value) VALUES (?, ?)",
693
+ stats,
694
+ )
695
+
696
+ connection.commit()
697
+ connection.close()
698
+
699
+
700
+ def update_symbol_coverage(db_path: pathlib.Path) -> int:
701
+ """
702
+ Compute and store per-symbol coverage statistics in the symbol_coverage table.
703
+
704
+ This function aggregates OHLCV data per instrument_id/rtype first (fast, uses
705
+ primary key), then joins with symbology to get symbols.
706
+
707
+ Args:
708
+ db_path: Path to the secmaster SQLite database.
709
+
710
+ Returns:
711
+ The number of symbol/rtype combinations stored.
712
+ """
713
+ connection = sqlite3.connect(str(db_path))
714
+ cursor = connection.cursor()
715
+
716
+ cursor.execute("DELETE FROM symbol_coverage")
717
+
718
+ cursor.execute(
719
+ """
720
+ INSERT INTO symbol_coverage (symbol, rtype, min_ts, max_ts, record_count)
721
+ SELECT s.symbol, agg.rtype, MIN(agg.min_ts), MAX(agg.max_ts), SUM(agg.cnt)
722
+ FROM (
723
+ SELECT instrument_id, rtype, MIN(ts_event) as min_ts, MAX(ts_event) as max_ts, COUNT(*) as cnt
724
+ FROM ohlcv
725
+ GROUP BY instrument_id, rtype
726
+ ) agg
727
+ JOIN (
728
+ SELECT DISTINCT instrument_id, symbol FROM symbology
729
+ ) s ON agg.instrument_id = s.instrument_id
730
+ GROUP BY s.symbol, agg.rtype
731
+ """
732
+ )
733
+
734
+ count = cursor.rowcount
735
+ connection.commit()
736
+ connection.close()
737
+ return count
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: onesecondtrader
3
- Version: 0.39.0
3
+ Version: 0.41.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
@@ -12,11 +12,14 @@ Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3.13
13
13
  Classifier: Programming Language :: Python :: 3.14
14
14
  Requires-Dist: databento (>=0.69.0,<0.70.0)
15
+ Requires-Dist: fastapi (>=0.128.0,<0.129.0)
16
+ Requires-Dist: ib-async (>=2.1.0,<3.0.0)
15
17
  Requires-Dist: matplotlib (>=3.10.7,<4.0.0)
16
18
  Requires-Dist: mplfinance (>=0.12.10b0,<0.13.0)
17
19
  Requires-Dist: pandas (>=2.3.1,<3.0.0)
18
20
  Requires-Dist: python-dotenv (>=1.0.0,<2.0.0)
19
21
  Requires-Dist: tqdm (>=4.67.1,<5.0.0)
22
+ Requires-Dist: uvicorn (>=0.40.0,<0.41.0)
20
23
  Description-Content-Type: text/markdown
21
24
 
22
25
  # OneSecondTrader
@@ -0,0 +1,49 @@
1
+ onesecondtrader/__init__.py,sha256=_jslG2TQRbaiUCQe5LZrmP4tuvpaULdxX2SK2x4cHUc,1228
2
+ onesecondtrader/connectors/__init__.py,sha256=rAbQCRdwxk3gkZ8QgMHPzcZXsS7a5rIj3F0rV6PqjDM,180
3
+ onesecondtrader/connectors/brokers/__init__.py,sha256=CpZQ04U8t-KlFb4oePcdJ8W8djaBIoBe8ZOlyg7_S1A,107
4
+ onesecondtrader/connectors/brokers/ib.py,sha256=KSldO_ZXWDHu56F5TVizvFlevhLl1gbyFzBHH35vXE0,15244
5
+ onesecondtrader/connectors/brokers/simulated.py,sha256=Jhq8YfskEkV0rePLp8nGFI4oG_Kb_vbhMzJiWOgj-q0,12767
6
+ onesecondtrader/connectors/datafeeds/__init__.py,sha256=ChSoiZQGN4E8p_TX0AgwNFFsE4b63ef2e6QhsTBkdLE,115
7
+ onesecondtrader/connectors/datafeeds/ib.py,sha256=Ba4WWJXEt9SMUzFUStpfqE9aOFawOBgnfr0XexBlMuc,10353
8
+ onesecondtrader/connectors/datafeeds/simulated.py,sha256=jQSjmsZDpnbjNZsbBHEHFci6W4El2TiZD6lKK4kYnJo,5408
9
+ onesecondtrader/connectors/gateways/__init__.py,sha256=K80iGnZeJFMhtD9HnEz1B4YWwgkRCQX4pNTYl2QZ-wU,83
10
+ onesecondtrader/connectors/gateways/ib.py,sha256=XnjiUc0Z99JD09Ou90ctCVEAKfYLCKNGoWicyEvnk4s,10819
11
+ onesecondtrader/core/__init__.py,sha256=Yde6Vy8osWbc2Du__VmC0AhD_bQ5-qSdt3VXFkCS6YM,380
12
+ onesecondtrader/core/brokers/__init__.py,sha256=mC-nNPdaT17oy-rjluwNvbKzxi5q8xxZ4mAkU7aJU0Y,55
13
+ onesecondtrader/core/brokers/base.py,sha256=NNcYWYYRPrvreCmn6TwFymEnIrfMLCyLFyaGXYy0UAw,1478
14
+ onesecondtrader/core/datafeeds/__init__.py,sha256=grSCxzBCmYau1BgA9Kyj2zeK8afoBlHzpN3JqInNtTs,59
15
+ onesecondtrader/core/datafeeds/base.py,sha256=kgCgKRsF0AyJRy-WTaYcr_hzJjnQUDJ8BP9ZWOnYATY,762
16
+ onesecondtrader/core/events/__init__.py,sha256=IOlFRdiOXz93SpvkpKL8wr1954d_8olKSB1n9mlTL3Y,898
17
+ onesecondtrader/core/events/bases.py,sha256=g-ykq2jgcitIAueRurUlqAq0jINQwuhSWi_khAniPHw,662
18
+ onesecondtrader/core/events/market.py,sha256=UY04TH6G-98NgYPEvBQSY92_ddeiT4yNwaUXnHdongQ,514
19
+ onesecondtrader/core/events/requests.py,sha256=7cnt7TiuE7yl9ezFruIixY0v5A-mzZDWdoTBkAcVff0,836
20
+ onesecondtrader/core/events/responses.py,sha256=biHIFa6usnsgSEX9bh2zOs1zB00I7HVSS01Dh_pZISE,1441
21
+ onesecondtrader/core/indicators/__init__.py,sha256=hRg3FCP1FT7LYOLzztybWn48gTR5QvewzzdELPYbdoY,239
22
+ onesecondtrader/core/indicators/averages.py,sha256=sCAIJrOYhtkwO5MkS2vx-4CfzHIVLJZpwYDzwv1GZ7Y,1905
23
+ onesecondtrader/core/indicators/bar.py,sha256=9NUckrLO1AhyO3uTJlNCL2_Pqge58x5S_TcSz4qrk-c,1120
24
+ onesecondtrader/core/indicators/base.py,sha256=_2pJ7PS0MRUz85UT0YpvzJ5V6ce60koT8MbjoerZ9eM,1894
25
+ onesecondtrader/core/messaging/__init__.py,sha256=vMRDabHBgse_vZRTRFtnU8M8v2sY_o4pHjGzgu3hp3E,115
26
+ onesecondtrader/core/messaging/eventbus.py,sha256=SaXLRoqz9tWBBlyEo0ry1HHr_8azj2U2dEaQEnr3PNo,1581
27
+ onesecondtrader/core/messaging/subscriber.py,sha256=Sp77pB6bGyW57FlV0rdzAWy1Jv_nHA77YEtN64spZjs,2111
28
+ onesecondtrader/core/models/__init__.py,sha256=w-Gi7_NciopNJu3kvsmgIbPrjmJofVmjynJ6v8SOfSc,296
29
+ onesecondtrader/core/models/data.py,sha256=fBmddVl6EXYC5u2UnvQ59DXAXeZeIb48KP1ZdeTL52A,322
30
+ onesecondtrader/core/models/orders.py,sha256=y6Ar-6fMqaOd_hRnRGvfWUF0Z13H_2hfTOW3ROOk0A8,254
31
+ onesecondtrader/core/models/params.py,sha256=8hZNcQ2NF4tH4gVaYvWJgdLjs_hfA2kduw2B3hcgzNw,540
32
+ onesecondtrader/core/models/records.py,sha256=vdCWBtoDQs5R4iB_8_3fXkxWEvoCxOssk9XBnS4l7Vk,599
33
+ onesecondtrader/core/strategies/__init__.py,sha256=Nq1n6HCdZ-GKkpn4WAlKxconPnOmeVKo0nhTk0J1ybA,121
34
+ onesecondtrader/core/strategies/base.py,sha256=SJ-9rEq4Y4x_rRcC0mPyr8RbZ00OoYaXO9SVw7WisRQ,11409
35
+ onesecondtrader/core/strategies/examples.py,sha256=tkEX5oRifts7uUis4uO4cE8TckXU2SwJD17m5-JDPvo,1593
36
+ onesecondtrader/dashboard/__init__.py,sha256=vJRSXOvmNoEQ2_az79gFCRkgA1IYuQshNc6M0H3ljd4,40
37
+ onesecondtrader/dashboard/app.py,sha256=OvbNtGoAHl0S56-Dh_-6t7wnGT-Ecsavysol-YtxK6o,60468
38
+ onesecondtrader/dashboard/registry.py,sha256=MWnfks7K_5_ndi-6YYYbX2Lm5xhak62fomgLkjCAsvw,2734
39
+ onesecondtrader/orchestrator/__init__.py,sha256=M0m9QP0g_2qpma4EYiG2DJF7lXQbHrAda8N30Db-V0Y,127
40
+ onesecondtrader/orchestrator/orchestrator.py,sha256=okSsvIiUPXsOTwIVnSTxSCP-p3GPpaKvr-418mo4r0A,3681
41
+ onesecondtrader/orchestrator/recorder.py,sha256=WtfNgStskCKweKqCCD28sDFxsT4vHlX_1es-loiQquI,7166
42
+ onesecondtrader/orchestrator/schema.sql,sha256=0nY_jqwfypkTrVoqC4IsNXbn7DM5_WpjfZnQF6YgH9k,10350
43
+ onesecondtrader/secmaster/__init__.py,sha256=0vKGVhRXEDMx_UoH1SIDe-ZlwGt28leslZQ8y7gr-Rs,136
44
+ onesecondtrader/secmaster/schema.sql,sha256=E2nIu3jotjJOjP4LIUEvT2upzviqq4G94ZahHuDafpc,55438
45
+ onesecondtrader/secmaster/utils.py,sha256=4rIBxnS9tQSrMPTLfMcktIL3TwHE82oNmCSnyeTT9p8,23941
46
+ onesecondtrader-0.41.0.dist-info/METADATA,sha256=85O_TKyRPvTSjn4-2X95XnY0bY1KvS8xZuBs-CRcGOE,9939
47
+ onesecondtrader-0.41.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
48
+ onesecondtrader-0.41.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
49
+ onesecondtrader-0.41.0.dist-info/RECORD,,
@@ -1,19 +0,0 @@
1
- import abc
2
-
3
- from onesecondtrader.core import events, messaging, models
4
-
5
-
6
- class Datafeed(abc.ABC):
7
- def __init__(self, event_bus: messaging.EventBus) -> None:
8
- self._event_bus = event_bus
9
-
10
- def _publish(self, event: events.EventBase) -> None:
11
- self._event_bus.publish(event)
12
-
13
- @abc.abstractmethod
14
- def stream(self, symbols: list[str], bar_period: models.BarPeriod) -> None:
15
- pass
16
-
17
- @abc.abstractmethod
18
- def shutdown(self) -> None:
19
- pass
@@ -1,37 +0,0 @@
1
- onesecondtrader/__init__.py,sha256=MZbEb45XiQOuWY-8EbBfidLnCZ7Qwp0cVajOpbgbQn4,1090
2
- onesecondtrader/connectors/__init__.py,sha256=TDV1mXCkNVuMS8FQWRts_6FDwBEeNciMqYtZb8HNl2w,120
3
- onesecondtrader/connectors/brokers/__init__.py,sha256=O67ETIic6yrGDQp_wJSNTsjZ4Tt_3NGO3v4RJf3bm7Q,70
4
- onesecondtrader/connectors/brokers/simulated.py,sha256=ck0gWdz88KSyEMkiHW2CP0vuLrBELBTz3KveYIwbLuI,12722
5
- onesecondtrader/connectors/datafeeds/__init__.py,sha256=OzrPQcmdwzI6Fo8BONoWeJQtp0ttQ6TMYL6dUvvery4,113
6
- onesecondtrader/connectors/datafeeds/base.py,sha256=hpffDlv5Z92OZnL_B3vs_rRmq7uRU4HCf8N6IZkRxmM,482
7
- onesecondtrader/connectors/datafeeds/simulated.py,sha256=aMLSDu2CVaQcxxeWOcznFrfPgXq3icEB2rRe4KNK0Wg,3011
8
- onesecondtrader/core/__init__.py,sha256=5T2eAX4I_yo2ku9zywhFvl628kPTINxoLY92u7x_gy0,324
9
- onesecondtrader/core/brokers/__init__.py,sha256=mC-nNPdaT17oy-rjluwNvbKzxi5q8xxZ4mAkU7aJU0Y,55
10
- onesecondtrader/core/brokers/base.py,sha256=n82DHGvqkP9c4ATW8qT9yosPRoRQGUrs1oveGASdhlY,1350
11
- onesecondtrader/core/events/__init__.py,sha256=IOlFRdiOXz93SpvkpKL8wr1954d_8olKSB1n9mlTL3Y,898
12
- onesecondtrader/core/events/bases.py,sha256=g-ykq2jgcitIAueRurUlqAq0jINQwuhSWi_khAniPHw,662
13
- onesecondtrader/core/events/market.py,sha256=UY04TH6G-98NgYPEvBQSY92_ddeiT4yNwaUXnHdongQ,514
14
- onesecondtrader/core/events/requests.py,sha256=7cnt7TiuE7yl9ezFruIixY0v5A-mzZDWdoTBkAcVff0,836
15
- onesecondtrader/core/events/responses.py,sha256=biHIFa6usnsgSEX9bh2zOs1zB00I7HVSS01Dh_pZISE,1441
16
- onesecondtrader/core/indicators/__init__.py,sha256=hRg3FCP1FT7LYOLzztybWn48gTR5QvewzzdELPYbdoY,239
17
- onesecondtrader/core/indicators/averages.py,sha256=sCAIJrOYhtkwO5MkS2vx-4CfzHIVLJZpwYDzwv1GZ7Y,1905
18
- onesecondtrader/core/indicators/bar.py,sha256=9NUckrLO1AhyO3uTJlNCL2_Pqge58x5S_TcSz4qrk-c,1120
19
- onesecondtrader/core/indicators/base.py,sha256=_2pJ7PS0MRUz85UT0YpvzJ5V6ce60koT8MbjoerZ9eM,1894
20
- onesecondtrader/core/messaging/__init__.py,sha256=vMRDabHBgse_vZRTRFtnU8M8v2sY_o4pHjGzgu3hp3E,115
21
- onesecondtrader/core/messaging/eventbus.py,sha256=SaXLRoqz9tWBBlyEo0ry1HHr_8azj2U2dEaQEnr3PNo,1581
22
- onesecondtrader/core/messaging/subscriber.py,sha256=Sp77pB6bGyW57FlV0rdzAWy1Jv_nHA77YEtN64spZjs,2111
23
- onesecondtrader/core/models/__init__.py,sha256=7amHCQ6BAhHKps0ke63E-zh8IJNmkdDogZq-PfBukMs,249
24
- onesecondtrader/core/models/data.py,sha256=fBmddVl6EXYC5u2UnvQ59DXAXeZeIb48KP1ZdeTL52A,322
25
- onesecondtrader/core/models/orders.py,sha256=y6Ar-6fMqaOd_hRnRGvfWUF0Z13H_2hfTOW3ROOk0A8,254
26
- onesecondtrader/core/models/records.py,sha256=vdCWBtoDQs5R4iB_8_3fXkxWEvoCxOssk9XBnS4l7Vk,599
27
- onesecondtrader/core/strategies/__init__.py,sha256=Nq1n6HCdZ-GKkpn4WAlKxconPnOmeVKo0nhTk0J1ybA,121
28
- onesecondtrader/core/strategies/base.py,sha256=wZMjPu4sSMclvoyMptIZKllaqFkRrA06CZ5EG7uQ-Uo,11211
29
- onesecondtrader/core/strategies/examples.py,sha256=j4K092_qt0bcvajp-i4ugrGqzbaFebYX6rBbtZawtvE,1124
30
- onesecondtrader/dashboard/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
31
- onesecondtrader/secmaster/__init__.py,sha256=0vKGVhRXEDMx_UoH1SIDe-ZlwGt28leslZQ8y7gr-Rs,136
32
- onesecondtrader/secmaster/schema.sql,sha256=6UP4DgNhWteP9EmgRNFXogJG__UBdgRwa6RiqTrbnhQ,53306
33
- onesecondtrader/secmaster/utils.py,sha256=r3DJ95ZoPQEagPEOCXq-fMZ3Dx0K9QCaAdHgTXzkyfE,21223
34
- onesecondtrader-0.39.0.dist-info/METADATA,sha256=nakHtF4WlHfQm9b8mwLmqjcQ6RIlwVqO02ls4uNlce4,9812
35
- onesecondtrader-0.39.0.dist-info/WHEEL,sha256=3ny-bZhpXrU6vSQ1UPG34FoxZBp3lVcvK0LkgUz6VLk,88
36
- onesecondtrader-0.39.0.dist-info/licenses/LICENSE,sha256=OXLcl0T2SZ8Pmy2_dmlvKuetivmyPd5m1q-Gyd-zaYY,35149
37
- onesecondtrader-0.39.0.dist-info/RECORD,,