oxarchive 0.5.1__py3-none-any.whl → 0.5.3__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.
oxarchive/__init__.py CHANGED
@@ -67,7 +67,7 @@ except ImportError:
67
67
  OxArchiveWs = None # type: ignore
68
68
  WsOptions = None # type: ignore
69
69
 
70
- __version__ = "0.5.1"
70
+ __version__ = "0.5.3"
71
71
 
72
72
  __all__ = [
73
73
  # Client
oxarchive/exchanges.py CHANGED
@@ -11,6 +11,7 @@ from .resources import (
11
11
  FundingResource,
12
12
  OpenInterestResource,
13
13
  CandlesResource,
14
+ LiquidationsResource,
14
15
  )
15
16
 
16
17
 
@@ -48,6 +49,9 @@ class HyperliquidClient:
48
49
  self.candles = CandlesResource(http, base_path)
49
50
  """OHLCV candle data"""
50
51
 
52
+ self.liquidations = LiquidationsResource(http, base_path)
53
+ """Liquidation events (May 2025+)"""
54
+
51
55
 
52
56
  class LighterClient:
53
57
  """
@@ -6,6 +6,7 @@ from .instruments import InstrumentsResource, LighterInstrumentsResource
6
6
  from .funding import FundingResource
7
7
  from .openinterest import OpenInterestResource
8
8
  from .candles import CandlesResource
9
+ from .liquidations import LiquidationsResource
9
10
 
10
11
  __all__ = [
11
12
  "OrderBookResource",
@@ -15,4 +16,5 @@ __all__ = [
15
16
  "FundingResource",
16
17
  "OpenInterestResource",
17
18
  "CandlesResource",
19
+ "LiquidationsResource",
18
20
  ]
@@ -0,0 +1,198 @@
1
+ """Liquidations API resource."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from datetime import datetime
6
+ from typing import Optional
7
+
8
+ from ..http import HttpClient
9
+ from ..types import CursorResponse, Liquidation, Timestamp
10
+
11
+
12
+ class LiquidationsResource:
13
+ """
14
+ Liquidations API resource.
15
+
16
+ Retrieve historical liquidation events from Hyperliquid.
17
+
18
+ Note: Liquidation data is available from May 25, 2025 onwards.
19
+
20
+ Example:
21
+ >>> # Get recent liquidations
22
+ >>> liquidations = client.hyperliquid.liquidations.history(
23
+ ... "BTC",
24
+ ... start="2025-06-01",
25
+ ... end="2025-06-02"
26
+ ... )
27
+ >>>
28
+ >>> # Get liquidations for a specific user
29
+ >>> user_liquidations = client.hyperliquid.liquidations.by_user(
30
+ ... "0x1234...",
31
+ ... start="2025-06-01",
32
+ ... end="2025-06-02"
33
+ ... )
34
+ """
35
+
36
+ def __init__(self, http: HttpClient, base_path: str = "/v1"):
37
+ self._http = http
38
+ self._base_path = base_path
39
+
40
+ def _convert_timestamp(self, ts: Optional[Timestamp]) -> Optional[int]:
41
+ """Convert timestamp to Unix milliseconds."""
42
+ if ts is None:
43
+ return None
44
+ if isinstance(ts, int):
45
+ return ts
46
+ if isinstance(ts, datetime):
47
+ return int(ts.timestamp() * 1000)
48
+ if isinstance(ts, str):
49
+ try:
50
+ dt = datetime.fromisoformat(ts.replace("Z", "+00:00"))
51
+ return int(dt.timestamp() * 1000)
52
+ except ValueError:
53
+ return int(ts)
54
+ return None
55
+
56
+ def history(
57
+ self,
58
+ coin: str,
59
+ *,
60
+ start: Timestamp,
61
+ end: Timestamp,
62
+ cursor: Optional[str] = None,
63
+ limit: Optional[int] = None,
64
+ ) -> CursorResponse[list[Liquidation]]:
65
+ """
66
+ Get liquidation history for a coin with cursor-based pagination.
67
+
68
+ Args:
69
+ coin: The coin symbol (e.g., 'BTC', 'ETH')
70
+ start: Start timestamp (required)
71
+ end: End timestamp (required)
72
+ cursor: Cursor from previous response's next_cursor
73
+ limit: Maximum number of results (default: 100, max: 1000)
74
+
75
+ Returns:
76
+ CursorResponse with liquidation records and next_cursor for pagination
77
+
78
+ Example:
79
+ >>> result = client.hyperliquid.liquidations.history("BTC", start=start, end=end, limit=1000)
80
+ >>> liquidations = result.data
81
+ >>> while result.next_cursor:
82
+ ... result = client.hyperliquid.liquidations.history(
83
+ ... "BTC", start=start, end=end, cursor=result.next_cursor, limit=1000
84
+ ... )
85
+ ... liquidations.extend(result.data)
86
+ """
87
+ data = self._http.get(
88
+ f"{self._base_path}/liquidations/{coin.upper()}",
89
+ params={
90
+ "start": self._convert_timestamp(start),
91
+ "end": self._convert_timestamp(end),
92
+ "cursor": cursor,
93
+ "limit": limit,
94
+ },
95
+ )
96
+ return CursorResponse(
97
+ data=[Liquidation.model_validate(item) for item in data["data"]],
98
+ next_cursor=data.get("meta", {}).get("next_cursor"),
99
+ )
100
+
101
+ async def ahistory(
102
+ self,
103
+ coin: str,
104
+ *,
105
+ start: Timestamp,
106
+ end: Timestamp,
107
+ cursor: Optional[str] = None,
108
+ limit: Optional[int] = None,
109
+ ) -> CursorResponse[list[Liquidation]]:
110
+ """Async version of history(). start and end are required."""
111
+ data = await self._http.aget(
112
+ f"{self._base_path}/liquidations/{coin.upper()}",
113
+ params={
114
+ "start": self._convert_timestamp(start),
115
+ "end": self._convert_timestamp(end),
116
+ "cursor": cursor,
117
+ "limit": limit,
118
+ },
119
+ )
120
+ return CursorResponse(
121
+ data=[Liquidation.model_validate(item) for item in data["data"]],
122
+ next_cursor=data.get("meta", {}).get("next_cursor"),
123
+ )
124
+
125
+ def by_user(
126
+ self,
127
+ user_address: str,
128
+ *,
129
+ start: Timestamp,
130
+ end: Timestamp,
131
+ coin: Optional[str] = None,
132
+ cursor: Optional[str] = None,
133
+ limit: Optional[int] = None,
134
+ ) -> CursorResponse[list[Liquidation]]:
135
+ """
136
+ Get liquidation history for a specific user.
137
+
138
+ This returns liquidations where the user was either:
139
+ - The liquidated party (their position was liquidated)
140
+ - The liquidator (they executed the liquidation)
141
+
142
+ Args:
143
+ user_address: User's wallet address (e.g., '0x1234...')
144
+ start: Start timestamp (required)
145
+ end: End timestamp (required)
146
+ coin: Optional coin filter (e.g., 'BTC', 'ETH')
147
+ cursor: Cursor from previous response's next_cursor
148
+ limit: Maximum number of results (default: 100, max: 1000)
149
+
150
+ Returns:
151
+ CursorResponse with liquidation records and next_cursor for pagination
152
+ """
153
+ params = {
154
+ "start": self._convert_timestamp(start),
155
+ "end": self._convert_timestamp(end),
156
+ "cursor": cursor,
157
+ "limit": limit,
158
+ }
159
+ if coin:
160
+ params["coin"] = coin.upper()
161
+
162
+ data = self._http.get(
163
+ f"{self._base_path}/liquidations/user/{user_address}",
164
+ params=params,
165
+ )
166
+ return CursorResponse(
167
+ data=[Liquidation.model_validate(item) for item in data["data"]],
168
+ next_cursor=data.get("meta", {}).get("next_cursor"),
169
+ )
170
+
171
+ async def aby_user(
172
+ self,
173
+ user_address: str,
174
+ *,
175
+ start: Timestamp,
176
+ end: Timestamp,
177
+ coin: Optional[str] = None,
178
+ cursor: Optional[str] = None,
179
+ limit: Optional[int] = None,
180
+ ) -> CursorResponse[list[Liquidation]]:
181
+ """Async version of by_user()."""
182
+ params = {
183
+ "start": self._convert_timestamp(start),
184
+ "end": self._convert_timestamp(end),
185
+ "cursor": cursor,
186
+ "limit": limit,
187
+ }
188
+ if coin:
189
+ params["coin"] = coin.upper()
190
+
191
+ data = await self._http.aget(
192
+ f"{self._base_path}/liquidations/user/{user_address}",
193
+ params=params,
194
+ )
195
+ return CursorResponse(
196
+ data=[Liquidation.model_validate(item) for item in data["data"]],
197
+ next_cursor=data.get("meta", {}).get("next_cursor"),
198
+ )
@@ -14,17 +14,17 @@ class TradesResource:
14
14
  Trades API resource.
15
15
 
16
16
  Example:
17
- >>> # Get recent trades
18
- >>> trades = client.trades.recent("BTC")
19
- >>>
20
17
  >>> # Get trade history with cursor-based pagination (recommended)
21
- >>> result = client.trades.list("BTC", start="2024-01-01", end="2024-01-02")
18
+ >>> result = client.hyperliquid.trades.list("BTC", start="2024-01-01", end="2024-01-02")
22
19
  >>> trades = result.data
23
20
  >>>
24
21
  >>> # Get all pages
25
22
  >>> while result.next_cursor:
26
- ... result = client.trades.list("BTC", start="2024-01-01", end="2024-01-02", cursor=result.next_cursor)
23
+ ... result = client.hyperliquid.trades.list("BTC", start="2024-01-01", end="2024-01-02", cursor=result.next_cursor)
27
24
  ... trades.extend(result.data)
25
+ >>>
26
+ >>> # Get recent trades (Lighter only - has real-time data)
27
+ >>> recent = client.lighter.trades.recent("BTC")
28
28
  """
29
29
 
30
30
  def __init__(self, http: HttpClient, base_path: str = "/v1"):
@@ -135,6 +135,10 @@ class TradesResource:
135
135
  """
136
136
  Get most recent trades for a coin.
137
137
 
138
+ Note: This method is only available for Lighter (client.lighter.trades.recent())
139
+ which has real-time data ingestion. Hyperliquid uses hourly backfill so this
140
+ endpoint is not available for Hyperliquid.
141
+
138
142
  Args:
139
143
  coin: The coin symbol (e.g., 'BTC', 'ETH')
140
144
  limit: Number of trades to return (default: 100)
oxarchive/types.py CHANGED
@@ -270,6 +270,51 @@ class OpenInterest(BaseModel):
270
270
  """Impact ask price for liquidations."""
271
271
 
272
272
 
273
+ # =============================================================================
274
+ # Liquidation Types
275
+ # =============================================================================
276
+
277
+
278
+ class Liquidation(BaseModel):
279
+ """Liquidation event record."""
280
+
281
+ coin: str
282
+ """Trading pair symbol."""
283
+
284
+ timestamp: datetime
285
+ """Liquidation timestamp (UTC)."""
286
+
287
+ liquidated_user: str
288
+ """Address of the liquidated user."""
289
+
290
+ liquidator_user: str
291
+ """Address of the liquidator."""
292
+
293
+ price: str
294
+ """Liquidation execution price."""
295
+
296
+ size: str
297
+ """Liquidation size."""
298
+
299
+ side: Literal["B", "S"]
300
+ """Side: 'B' (buy) or 'S' (sell)."""
301
+
302
+ mark_price: Optional[str] = None
303
+ """Mark price at time of liquidation."""
304
+
305
+ closed_pnl: Optional[str] = None
306
+ """Realized PnL from the liquidation."""
307
+
308
+ direction: Optional[str] = None
309
+ """Position direction (e.g., 'Open Long', 'Close Short')."""
310
+
311
+ trade_id: Optional[int] = None
312
+ """Unique trade ID."""
313
+
314
+ tx_hash: Optional[str] = None
315
+ """Blockchain transaction hash."""
316
+
317
+
273
318
  # =============================================================================
274
319
  # Candle Types
275
320
  # =============================================================================
@@ -311,8 +356,8 @@ class Candle(BaseModel):
311
356
  # WebSocket Types
312
357
  # =============================================================================
313
358
 
314
- WsChannel = Literal["orderbook", "trades", "candles", "ticker", "all_tickers"]
315
- """Available WebSocket channels. Note: ticker/all_tickers are real-time only."""
359
+ WsChannel = Literal["orderbook", "trades", "candles", "liquidations", "ticker", "all_tickers"]
360
+ """Available WebSocket channels. Note: ticker/all_tickers are real-time only. Liquidations is historical only (May 2025+)."""
316
361
 
317
362
  WsConnectionState = Literal["connecting", "connected", "disconnected", "reconnecting"]
318
363
  """WebSocket connection state."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: oxarchive
3
- Version: 0.5.1
3
+ Version: 0.5.3
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
@@ -211,9 +211,6 @@ history = client.lighter.orderbook.history(
211
211
  The trades API uses cursor-based pagination for efficient retrieval of large datasets.
212
212
 
213
213
  ```python
214
- # Get recent trades
215
- recent = client.hyperliquid.trades.recent("BTC", limit=100)
216
-
217
214
  # Get trade history with cursor-based pagination
218
215
  result = client.hyperliquid.trades.list("ETH", start="2024-01-01", end="2024-01-02", limit=1000)
219
216
  trades = result.data
@@ -232,8 +229,7 @@ while result.next_cursor:
232
229
  # Filter by side
233
230
  buys = client.hyperliquid.trades.list("BTC", start=..., end=..., side="buy")
234
231
 
235
- # Async versions
236
- recent = await client.hyperliquid.trades.arecent("BTC")
232
+ # Async version
237
233
  result = await client.hyperliquid.trades.alist("ETH", start=..., end=...)
238
234
  ```
239
235
 
@@ -641,9 +637,11 @@ from oxarchive.resources.trades import CursorResponse
641
637
 
642
638
  client = Client(api_key="ox_your_api_key")
643
639
 
644
- orderbook: OrderBook = client.orderbook.get("BTC")
645
- trades: list[Trade] = client.trades.recent("BTC")
646
- result: CursorResponse = client.trades.list("BTC", start=..., end=...)
640
+ orderbook: OrderBook = client.hyperliquid.orderbook.get("BTC")
641
+ result: CursorResponse = client.hyperliquid.trades.list("BTC", start=..., end=...)
642
+
643
+ # Lighter has real-time data, so recent() is available
644
+ recent: list[Trade] = client.lighter.trades.recent("BTC")
647
645
 
648
646
  # Lighter granularity type hint
649
647
  granularity: LighterGranularity = "10s"
@@ -1,16 +1,17 @@
1
- oxarchive/__init__.py,sha256=8-68R4dD9xFfeUQ1yAuy1IadC10el1QRBNJOn3DXMfA,2738
1
+ oxarchive/__init__.py,sha256=-TIv-IqajJ0h3W4QyZsnBKb-PLc3hrRcsz54ynKA_hw,2738
2
2
  oxarchive/client.py,sha256=XWQ_VEBQy3UIAnmZQ-Z_FyzXnvMA3FITwtinBOf3o-Y,4453
3
- oxarchive/exchanges.py,sha256=ozw_eDGnzyb7D5HKMo2Hfl7-dIcVKSXJCyFlFIhiaos,2631
3
+ oxarchive/exchanges.py,sha256=nTd0gRrgV2wDoptWWxwh38HXkCcunVNuNdNEwzNDsBM,2773
4
4
  oxarchive/http.py,sha256=SY_o9Ag8ADo1HI3i3uAKW1xwkYjPE75gRAjnMsddAGs,4211
5
- oxarchive/types.py,sha256=LX5Usgn6RgUoS6l48ufQW2zKjzH1C3xjlV5UbsEp2fY,14293
5
+ oxarchive/types.py,sha256=tfL6QG2WTBe4cdgk5TAbgpTRGAQALvhPTADH9umqd4g,15463
6
6
  oxarchive/websocket.py,sha256=sS-kLDKv2qS77-61hXChRePjL_hz-URcALM9UW5zxXU,30609
7
- oxarchive/resources/__init__.py,sha256=pFCP01qP6g9A9Dbzn-lGgF0i6x8GhGlwmwpOXGg3UWM,510
7
+ oxarchive/resources/__init__.py,sha256=JyNkR6dKBOGPQpYAuG6Qy1lDMCxJ68dXNLUAOua1Vs8,587
8
8
  oxarchive/resources/candles.py,sha256=GI7-YSNFckEd1i49W9mlrLn1cl955sY8ki0u12TuLgw,4449
9
9
  oxarchive/resources/funding.py,sha256=ybMWkpoccrkdwnd6W3oHgsaor7cBcA2nkYy4CbjmHUg,4485
10
10
  oxarchive/resources/instruments.py,sha256=6q7rMdIaixXgFVXgwQsVd-YuO7RIXr1oGPT5jBsqI9A,3733
11
+ oxarchive/resources/liquidations.py,sha256=kX3mEX2u6uEvgk1aKfL4U0JE9gOjJOwsLVpkIj84arE,6741
11
12
  oxarchive/resources/openinterest.py,sha256=whwo60KFNLGwvVrDmDYYc-rMZr35Fcizb5Iil-DSvD8,4553
12
13
  oxarchive/resources/orderbook.py,sha256=NzgKH45MBb2oAHyPmy6BSikaYyq0nM-8GFjur9LIRN8,6661
13
- oxarchive/resources/trades.py,sha256=t4iicyi1waaHzC7Q_cC-c7O4yVx1vqS4eMH8F8_5hxk,5503
14
- oxarchive-0.5.1.dist-info/METADATA,sha256=iR7PKuDuF89N-I5b1QqcNyZNKr-OI2tJXBirT1-tYTU,17974
15
- oxarchive-0.5.1.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
16
- oxarchive-0.5.1.dist-info/RECORD,,
14
+ oxarchive/resources/trades.py,sha256=RhOTbhqSSBAaekden6rLY8qJL-NDArGTqCempvUbX08,5801
15
+ oxarchive-0.5.3.dist-info/METADATA,sha256=a134ZFK2iEmo5UPDAI2sw3ZcqpqjzVphjSKGUS2-4LA,17924
16
+ oxarchive-0.5.3.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
17
+ oxarchive-0.5.3.dist-info/RECORD,,