oxarchive 0.6.0__tar.gz → 0.6.1__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxarchive
3
- Version: 0.6.0
3
+ Version: 0.6.1
4
4
  Summary: Official Python SDK for 0xarchive - Hyperliquid Historical Data API
5
5
  Project-URL: Homepage, https://0xarchive.io
6
6
  Project-URL: Documentation, https://0xarchive.io/docs/sdks
@@ -639,6 +639,43 @@ async def main():
639
639
  asyncio.run(main())
640
640
  ```
641
641
 
642
+ ### Gap Detection
643
+
644
+ During historical replay and bulk streaming, the server automatically detects gaps in the data and notifies the client. This helps identify periods where data may be missing.
645
+
646
+ ```python
647
+ import asyncio
648
+ from oxarchive import OxArchiveWs, WsOptions
649
+
650
+ async def main():
651
+ ws = OxArchiveWs(WsOptions(api_key="ox_..."))
652
+
653
+ # Handle gap notifications during replay/stream
654
+ def handle_gap(channel, coin, gap_start, gap_end, duration_minutes):
655
+ print(f"Gap detected in {channel}/{coin}:")
656
+ print(f" From: {gap_start}")
657
+ print(f" To: {gap_end}")
658
+ print(f" Duration: {duration_minutes} minutes")
659
+
660
+ ws.on_gap(handle_gap)
661
+
662
+ await ws.connect()
663
+
664
+ # Start replay - gaps will be reported via on_gap callback
665
+ await ws.replay(
666
+ "orderbook", "BTC",
667
+ start=int(time.time() * 1000) - 86400000,
668
+ end=int(time.time() * 1000),
669
+ speed=10
670
+ )
671
+
672
+ asyncio.run(main())
673
+ ```
674
+
675
+ Gap thresholds vary by channel:
676
+ - **orderbook**, **candles**, **liquidations**: 2 minutes
677
+ - **trades**: 60 minutes (trades can naturally have longer gaps during low activity periods)
678
+
642
679
  ### WebSocket Configuration
643
680
 
644
681
  ```python
@@ -659,6 +696,7 @@ ws = OxArchiveWs(WsOptions(
659
696
  | `orderbook` | L2 order book updates | Yes | Yes |
660
697
  | `trades` | Trade/fill updates | Yes | Yes |
661
698
  | `candles` | OHLCV candle data | Yes | Yes (replay/stream only) |
699
+ | `liquidations` | Liquidation events (May 2025+) | Yes | Yes (replay/stream only) |
662
700
  | `ticker` | Price and 24h volume | Yes | Real-time only |
663
701
  | `all_tickers` | All market tickers | No | Real-time only |
664
702
 
@@ -602,6 +602,43 @@ async def main():
602
602
  asyncio.run(main())
603
603
  ```
604
604
 
605
+ ### Gap Detection
606
+
607
+ During historical replay and bulk streaming, the server automatically detects gaps in the data and notifies the client. This helps identify periods where data may be missing.
608
+
609
+ ```python
610
+ import asyncio
611
+ from oxarchive import OxArchiveWs, WsOptions
612
+
613
+ async def main():
614
+ ws = OxArchiveWs(WsOptions(api_key="ox_..."))
615
+
616
+ # Handle gap notifications during replay/stream
617
+ def handle_gap(channel, coin, gap_start, gap_end, duration_minutes):
618
+ print(f"Gap detected in {channel}/{coin}:")
619
+ print(f" From: {gap_start}")
620
+ print(f" To: {gap_end}")
621
+ print(f" Duration: {duration_minutes} minutes")
622
+
623
+ ws.on_gap(handle_gap)
624
+
625
+ await ws.connect()
626
+
627
+ # Start replay - gaps will be reported via on_gap callback
628
+ await ws.replay(
629
+ "orderbook", "BTC",
630
+ start=int(time.time() * 1000) - 86400000,
631
+ end=int(time.time() * 1000),
632
+ speed=10
633
+ )
634
+
635
+ asyncio.run(main())
636
+ ```
637
+
638
+ Gap thresholds vary by channel:
639
+ - **orderbook**, **candles**, **liquidations**: 2 minutes
640
+ - **trades**: 60 minutes (trades can naturally have longer gaps during low activity periods)
641
+
605
642
  ### WebSocket Configuration
606
643
 
607
644
  ```python
@@ -622,6 +659,7 @@ ws = OxArchiveWs(WsOptions(
622
659
  | `orderbook` | L2 order book updates | Yes | Yes |
623
660
  | `trades` | Trade/fill updates | Yes | Yes |
624
661
  | `candles` | OHLCV candle data | Yes | Yes (replay/stream only) |
662
+ | `liquidations` | Liquidation events (May 2025+) | Yes | Yes (replay/stream only) |
625
663
  | `ticker` | Price and 24h volume | Yes | Real-time only |
626
664
  | `all_tickers` | All market tickers | No | Real-time only |
627
665
 
@@ -68,7 +68,7 @@ except ImportError:
68
68
  OxArchiveWs = None # type: ignore
69
69
  WsOptions = None # type: ignore
70
70
 
71
- __version__ = "0.6.0"
71
+ __version__ = "0.6.1"
72
72
 
73
73
  __all__ = [
74
74
  # Client
@@ -555,6 +555,24 @@ class WsStreamStopped(BaseModel):
555
555
  snapshots_sent: int
556
556
 
557
557
 
558
+ class WsGapDetected(BaseModel):
559
+ """Gap detected in historical data stream.
560
+
561
+ Sent when there's a gap exceeding the threshold between consecutive data points.
562
+ Thresholds: 2 minutes for orderbook/candles/liquidations, 60 minutes for trades.
563
+ """
564
+
565
+ type: Literal["gap_detected"]
566
+ channel: WsChannel
567
+ coin: str
568
+ gap_start: int
569
+ """Start of the gap (last data point timestamp in ms)."""
570
+ gap_end: int
571
+ """End of the gap (next data point timestamp in ms)."""
572
+ duration_minutes: int
573
+ """Gap duration in minutes."""
574
+
575
+
558
576
  # =============================================================================
559
577
  # Error Types
560
578
  # =============================================================================
@@ -64,6 +64,7 @@ from .types import (
64
64
  WsHistoricalBatch,
65
65
  WsStreamCompleted,
66
66
  WsStreamStopped,
67
+ WsGapDetected,
67
68
  TimestampedRecord,
68
69
  )
69
70
 
@@ -122,6 +123,9 @@ StreamStartHandler = Callable[[WsChannel, str, int, int], None] # channel, coin
122
123
  StreamProgressHandler = Callable[[int], None] # snapshots_sent
123
124
  StreamCompleteHandler = Callable[[WsChannel, str, int], None] # channel, coin, snapshots_sent
124
125
 
126
+ # Gap detection handler
127
+ GapHandler = Callable[[WsChannel, str, int, int, int], None] # channel, coin, gap_start, gap_end, duration_minutes
128
+
125
129
 
126
130
  def _transform_trade(coin: str, raw: dict) -> Trade:
127
131
  """Transform raw Hyperliquid trade format to SDK Trade type.
@@ -289,6 +293,9 @@ class OxArchiveWs:
289
293
  self._on_stream_progress: Optional[StreamProgressHandler] = None
290
294
  self._on_stream_complete: Optional[StreamCompleteHandler] = None
291
295
 
296
+ # Gap detection handler
297
+ self._on_gap: Optional[GapHandler] = None
298
+
292
299
  @property
293
300
  def state(self) -> WsConnectionState:
294
301
  """Get current connection state."""
@@ -626,6 +633,23 @@ class OxArchiveWs:
626
633
  """
627
634
  self._on_stream_complete = handler
628
635
 
636
+ def on_gap(self, handler: GapHandler) -> None:
637
+ """Set handler for gap detected events during replay or streaming.
638
+
639
+ Called when there's a gap in the historical data exceeding the threshold.
640
+ Thresholds: 2 minutes for orderbook/candles/liquidations, 60 minutes for trades.
641
+
642
+ Handler receives: (channel, coin, gap_start, gap_end, duration_minutes)
643
+
644
+ Example:
645
+ >>> def handle_gap(channel, coin, gap_start, gap_end, duration_minutes):
646
+ ... print(f"Gap detected in {channel} {coin}: {duration_minutes} minutes")
647
+ ... print(f" From: {datetime.fromtimestamp(gap_start/1000)}")
648
+ ... print(f" To: {datetime.fromtimestamp(gap_end/1000)}")
649
+ >>> ws.on_gap(handle_gap)
650
+ """
651
+ self._on_gap = handler
652
+
629
653
  # Private methods
630
654
 
631
655
  async def _send(self, msg: dict) -> None:
@@ -778,6 +802,16 @@ class OxArchiveWs:
778
802
  elif msg_type == "stream_completed" and self._on_stream_complete:
779
803
  self._on_stream_complete(data["channel"], data["coin"], data["snapshots_sent"])
780
804
 
805
+ # Gap detection
806
+ elif msg_type == "gap_detected" and self._on_gap:
807
+ self._on_gap(
808
+ data["channel"],
809
+ data["coin"],
810
+ data["gap_start"],
811
+ data["gap_end"],
812
+ data["duration_minutes"],
813
+ )
814
+
781
815
  except Exception as e:
782
816
  logger.error(f"Error handling message: {e}")
783
817
 
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "oxarchive"
7
- version = "0.6.0"
7
+ version = "0.6.1"
8
8
  description = "Official Python SDK for 0xarchive - Hyperliquid Historical Data API"
9
9
  readme = "README.md"
10
10
  license = "MIT"
File without changes
File without changes
File without changes