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.
Files changed (46) hide show
  1. {hyperquant-1.61 → hyperquant-1.62}/PKG-INFO +1 -1
  2. {hyperquant-1.61 → hyperquant-1.62}/pyproject.toml +1 -1
  3. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/polymarket.py +48 -6
  4. {hyperquant-1.61 → hyperquant-1.62}/uv.lock +1 -1
  5. {hyperquant-1.61 → hyperquant-1.62}/.gitignore +0 -0
  6. {hyperquant-1.61 → hyperquant-1.62}/README.md +0 -0
  7. {hyperquant-1.61 → hyperquant-1.62}/requirements-dev.lock +0 -0
  8. {hyperquant-1.61 → hyperquant-1.62}/requirements.lock +0 -0
  9. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/__init__.py +0 -0
  10. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/auth.py +0 -0
  11. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/bitget.py +0 -0
  12. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/bitmart.py +0 -0
  13. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/coinw.py +0 -0
  14. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/deepcoin.py +0 -0
  15. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/edgex.py +0 -0
  16. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/hyperliquid.py +0 -0
  17. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lbank.py +0 -0
  18. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
  19. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/hpstore.py +0 -0
  20. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  21. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/polymarket/ctfAbi.py +0 -0
  22. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/polymarket/safeAbi.py +0 -0
  23. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lib/util.py +0 -0
  24. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/lighter.py +0 -0
  25. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/apexpro.py +0 -0
  26. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/bitget.py +0 -0
  27. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/bitmart.py +0 -0
  28. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/coinw.py +0 -0
  29. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/deepcoin.py +0 -0
  30. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/edgex.py +0 -0
  31. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  32. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/lbank.py +0 -0
  33. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/lighter.py +0 -0
  34. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/models/ourbit.py +0 -0
  35. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/ourbit.py +0 -0
  36. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/polymarket.py +0 -0
  37. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/broker/ws.py +0 -0
  38. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/core.py +0 -0
  39. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/_util.py +0 -0
  40. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/binance.py +0 -0
  41. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/coinglass.py +0 -0
  42. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/datavison/okx.py +0 -0
  43. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/db.py +0 -0
  44. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/draw.py +0 -0
  45. {hyperquant-1.61 → hyperquant-1.62}/src/hyperquant/logkit.py +0 -0
  46. {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.61
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "1.61"
3
+ version = "1.62"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -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, *, symbol: str, side: str, price_ticks: int, size_units: int, alias: str | None
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
- if not self._accept_sequence(symbol, self._extract_timestamp(msg)):
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 cur_size != new_size or (alias is not None and cur_alias != alias):
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
- if not self._accept_sequence(symbol, Book._extract_timestamp(msg)):
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
@@ -694,7 +694,7 @@ wheels = [
694
694
 
695
695
  [[package]]
696
696
  name = "hyperquant"
697
- version = "1.6"
697
+ version = "1.61"
698
698
  source = { editable = "." }
699
699
  dependencies = [
700
700
  { name = "aiohttp" },
File without changes
File without changes
File without changes