hyperquant 1.61__tar.gz → 1.62__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.
- {hyperquant-1.61 → hyperquant-1.62}/PKG-INFO +1 -1
- {hyperquant-1.61 → hyperquant-1.62}/pyproject.toml +1 -1
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/polymarket.py +48 -6
- {hyperquant-1.61 → hyperquant-1.62}/uv.lock +1 -1
- {hyperquant-1.61 → hyperquant-1.62}/.gitignore +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/README.md +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/requirements-dev.lock +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/requirements.lock +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/__init__.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/bitget.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/bitmart.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/coinw.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/deepcoin.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lbank.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/polymarket/ctfAbi.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/polymarket/safeAbi.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/util.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lighter.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/apexpro.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/bitget.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/bitmart.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/coinw.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/deepcoin.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/lighter.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/polymarket.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/ws.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/core.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/db.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/draw.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/logkit.py +0 -0
- {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/notikit.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperquant
|
|
3
|
-
Version: 1.
|
|
3
|
+
Version: 1.62
|
|
4
4
|
Summary: A minimal yet hyper-efficient backtesting framework for quantitative trading
|
|
5
5
|
Project-URL: Homepage, https://github.com/yourusername/hyperquant
|
|
6
6
|
Project-URL: Issues, https://github.com/yourusername/hyperquant/issues
|
|
@@ -635,6 +635,8 @@ class Book(DataStore):
|
|
|
635
635
|
# Internal hot-path storage:
|
|
636
636
|
# symbol -> {"a": {price_ticks: size_units}, "b": {price_ticks: size_units}}
|
|
637
637
|
self._levels: dict[str, dict[str, dict[int, int]]] = {}
|
|
638
|
+
# Keep per-level event timestamps so rows can surface Polymarket ws timestamp.
|
|
639
|
+
self._level_ts: dict[str, dict[str, dict[int, int | None]]] = {}
|
|
638
640
|
# Per-symbol monotonic sequence/timestamp gate.
|
|
639
641
|
self._last_seq: dict[str, int] = {}
|
|
640
642
|
|
|
@@ -767,14 +769,29 @@ class Book(DataStore):
|
|
|
767
769
|
self._levels[symbol] = state
|
|
768
770
|
return state
|
|
769
771
|
|
|
772
|
+
def _symbol_level_ts(self, symbol: str) -> dict[str, dict[int, int | None]]:
|
|
773
|
+
state = self._level_ts.get(symbol)
|
|
774
|
+
if state is None:
|
|
775
|
+
state = {"a": {}, "b": {}}
|
|
776
|
+
self._level_ts[symbol] = state
|
|
777
|
+
return state
|
|
778
|
+
|
|
770
779
|
def _record(
|
|
771
|
-
self,
|
|
780
|
+
self,
|
|
781
|
+
*,
|
|
782
|
+
symbol: str,
|
|
783
|
+
side: str,
|
|
784
|
+
price_ticks: int,
|
|
785
|
+
size_units: int,
|
|
786
|
+
alias: str | None,
|
|
787
|
+
event_time_ms: int | None,
|
|
772
788
|
) -> dict[str, Any]:
|
|
773
789
|
payload: dict[str, Any] = {
|
|
774
790
|
"s": symbol,
|
|
775
791
|
"S": side,
|
|
776
792
|
"p": self._ticks_to_price(price_ticks),
|
|
777
793
|
"q": self._units_to_size(size_units),
|
|
794
|
+
"event_time_ms": event_time_ms,
|
|
778
795
|
}
|
|
779
796
|
if alias is not None:
|
|
780
797
|
payload["alias"] = alias
|
|
@@ -790,8 +807,10 @@ class Book(DataStore):
|
|
|
790
807
|
side: str,
|
|
791
808
|
entries: Iterable[dict[str, Any]] | None,
|
|
792
809
|
alias: str | None,
|
|
810
|
+
event_time_ms: int | None,
|
|
793
811
|
) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]:
|
|
794
812
|
next_levels: dict[int, int] = {}
|
|
813
|
+
next_timestamps: dict[int, int | None] = {}
|
|
795
814
|
if entries:
|
|
796
815
|
for entry in entries:
|
|
797
816
|
if not isinstance(entry, dict):
|
|
@@ -803,9 +822,12 @@ class Book(DataStore):
|
|
|
803
822
|
if size_units <= 0:
|
|
804
823
|
continue
|
|
805
824
|
next_levels[price_ticks] = size_units
|
|
825
|
+
next_timestamps[price_ticks] = event_time_ms
|
|
806
826
|
|
|
807
827
|
symbol_levels = self._symbol_levels(symbol)
|
|
828
|
+
symbol_ts = self._symbol_level_ts(symbol)
|
|
808
829
|
prev_levels = symbol_levels[side]
|
|
830
|
+
prev_ts = symbol_ts[side]
|
|
809
831
|
removals = [
|
|
810
832
|
self._delete_key(symbol=symbol, side=side, price_ticks=price_ticks)
|
|
811
833
|
for price_ticks in prev_levels
|
|
@@ -818,11 +840,14 @@ class Book(DataStore):
|
|
|
818
840
|
price_ticks=price_ticks,
|
|
819
841
|
size_units=size_units,
|
|
820
842
|
alias=alias,
|
|
843
|
+
event_time_ms=event_time_ms,
|
|
821
844
|
)
|
|
822
845
|
for price_ticks, size_units in next_levels.items()
|
|
823
846
|
if prev_levels.get(price_ticks) != size_units
|
|
847
|
+
or prev_ts.get(price_ticks) != next_timestamps.get(price_ticks)
|
|
824
848
|
]
|
|
825
849
|
symbol_levels[side] = next_levels
|
|
850
|
+
symbol_ts[side] = next_timestamps
|
|
826
851
|
return removals, updates
|
|
827
852
|
|
|
828
853
|
def _on_message(self, msg: dict[str, Any]) -> None:
|
|
@@ -835,19 +860,22 @@ class Book(DataStore):
|
|
|
835
860
|
symbol, alias = self._alias(asset_id)
|
|
836
861
|
if symbol is None:
|
|
837
862
|
return
|
|
838
|
-
|
|
863
|
+
event_time_ms = self._extract_timestamp(msg)
|
|
864
|
+
if not self._accept_sequence(symbol, event_time_ms):
|
|
839
865
|
return
|
|
840
866
|
bid_deletes, bid_updates = self._snapshot_side(
|
|
841
867
|
symbol=symbol,
|
|
842
868
|
side="b",
|
|
843
869
|
entries=msg.get("bids"),
|
|
844
870
|
alias=alias,
|
|
871
|
+
event_time_ms=event_time_ms,
|
|
845
872
|
)
|
|
846
873
|
ask_deletes, ask_updates = self._snapshot_side(
|
|
847
874
|
symbol=symbol,
|
|
848
875
|
side="a",
|
|
849
876
|
entries=msg.get("asks"),
|
|
850
877
|
alias=alias,
|
|
878
|
+
event_time_ms=event_time_ms,
|
|
851
879
|
)
|
|
852
880
|
|
|
853
881
|
deletes = bid_deletes + ask_deletes
|
|
@@ -884,6 +912,7 @@ class Book(DataStore):
|
|
|
884
912
|
continue
|
|
885
913
|
alias = bucket["alias"]
|
|
886
914
|
symbol_levels = self._symbol_levels(symbol)
|
|
915
|
+
symbol_ts = self._symbol_level_ts(symbol)
|
|
887
916
|
for change in bucket["changes"]:
|
|
888
917
|
side = "b" if str(change.get("side") or "").upper() == "BUY" else "a"
|
|
889
918
|
price_ticks = self._price_to_ticks(change.get("price"))
|
|
@@ -891,26 +920,30 @@ class Book(DataStore):
|
|
|
891
920
|
if price_ticks is None or size_units is None:
|
|
892
921
|
continue
|
|
893
922
|
side_levels = symbol_levels[side]
|
|
923
|
+
side_ts = symbol_ts[side]
|
|
894
924
|
key = (symbol, side, price_ticks)
|
|
895
925
|
|
|
896
926
|
if size_units <= 0:
|
|
897
927
|
if price_ticks in side_levels:
|
|
898
928
|
side_levels.pop(price_ticks, None)
|
|
929
|
+
side_ts.pop(price_ticks, None)
|
|
899
930
|
removals[key] = self._delete_key(
|
|
900
931
|
symbol=symbol, side=side, price_ticks=price_ticks
|
|
901
932
|
)
|
|
902
933
|
updates.pop(key, None)
|
|
903
934
|
continue
|
|
904
935
|
|
|
905
|
-
if side_levels.get(price_ticks) == size_units:
|
|
936
|
+
if side_levels.get(price_ticks) == size_units and side_ts.get(price_ticks) == bucket["seq"]:
|
|
906
937
|
continue
|
|
907
938
|
side_levels[price_ticks] = size_units
|
|
939
|
+
side_ts[price_ticks] = bucket["seq"]
|
|
908
940
|
updates[key] = self._record(
|
|
909
941
|
symbol=symbol,
|
|
910
942
|
side=side,
|
|
911
943
|
price_ticks=price_ticks,
|
|
912
944
|
size_units=size_units,
|
|
913
945
|
alias=alias,
|
|
946
|
+
event_time_ms=bucket["seq"],
|
|
914
947
|
)
|
|
915
948
|
removals.pop(key, None)
|
|
916
949
|
|
|
@@ -976,6 +1009,7 @@ class Book(DataStore):
|
|
|
976
1009
|
"S": side,
|
|
977
1010
|
"p": self._ticks_to_price(price_ticks),
|
|
978
1011
|
"q": self._units_to_size(side_levels[price_ticks]),
|
|
1012
|
+
"event_time_ms": self._level_ts.get(str(symbol), {}).get(side, {}).get(price_ticks),
|
|
979
1013
|
}
|
|
980
1014
|
if alias is not None:
|
|
981
1015
|
row["alias"] = alias
|
|
@@ -1093,6 +1127,7 @@ class BBO(DataStore):
|
|
|
1093
1127
|
key = {"s": symbol, "S": side}
|
|
1094
1128
|
current = self.get(key)
|
|
1095
1129
|
best = self._symbol_best(symbol).get(side)
|
|
1130
|
+
event_time_ms = self._last_seq.get(symbol)
|
|
1096
1131
|
|
|
1097
1132
|
if best is None:
|
|
1098
1133
|
if current:
|
|
@@ -1105,6 +1140,7 @@ class BBO(DataStore):
|
|
|
1105
1140
|
"S": side,
|
|
1106
1141
|
"p": self._price_to_str(price_ticks),
|
|
1107
1142
|
"q": self._size_to_str(size_units),
|
|
1143
|
+
"event_time_ms": event_time_ms,
|
|
1108
1144
|
}
|
|
1109
1145
|
if alias is not None:
|
|
1110
1146
|
payload["alias"] = alias
|
|
@@ -1113,12 +1149,17 @@ class BBO(DataStore):
|
|
|
1113
1149
|
cur_price = str(current.get("p"))
|
|
1114
1150
|
cur_size = str(current.get("q"))
|
|
1115
1151
|
cur_alias = current.get("alias")
|
|
1152
|
+
cur_event_time_ms = current.get("event_time_ms")
|
|
1116
1153
|
new_price = payload["p"]
|
|
1117
1154
|
new_size = payload["q"]
|
|
1118
1155
|
|
|
1119
1156
|
if cur_price == new_price:
|
|
1120
|
-
# price unchanged -> only update quantities / alias changes
|
|
1121
|
-
if
|
|
1157
|
+
# price unchanged -> only update quantities / alias / timestamp changes
|
|
1158
|
+
if (
|
|
1159
|
+
cur_size != new_size
|
|
1160
|
+
or (alias is not None and cur_alias != alias)
|
|
1161
|
+
or cur_event_time_ms != event_time_ms
|
|
1162
|
+
):
|
|
1122
1163
|
self._update([payload])
|
|
1123
1164
|
return
|
|
1124
1165
|
|
|
@@ -1247,7 +1288,8 @@ class BBO(DataStore):
|
|
|
1247
1288
|
symbol, alias = self._alias(asset_id)
|
|
1248
1289
|
if symbol is None:
|
|
1249
1290
|
return
|
|
1250
|
-
|
|
1291
|
+
event_time_ms = Book._extract_timestamp(msg)
|
|
1292
|
+
if not self._accept_sequence(symbol, event_time_ms):
|
|
1251
1293
|
return
|
|
1252
1294
|
|
|
1253
1295
|
bid_size = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|