oxarchive 0.3.0__py3-none-any.whl → 0.3.6__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 +1 -1
- oxarchive/http.py +16 -3
- oxarchive/types.py +18 -7
- oxarchive/websocket.py +70 -1
- {oxarchive-0.3.0.dist-info → oxarchive-0.3.6.dist-info}/METADATA +113 -57
- {oxarchive-0.3.0.dist-info → oxarchive-0.3.6.dist-info}/RECORD +7 -7
- {oxarchive-0.3.0.dist-info → oxarchive-0.3.6.dist-info}/WHEEL +0 -0
oxarchive/__init__.py
CHANGED
oxarchive/http.py
CHANGED
|
@@ -50,13 +50,26 @@ class HttpClient:
|
|
|
50
50
|
return self._async_client
|
|
51
51
|
|
|
52
52
|
def close(self) -> None:
|
|
53
|
-
"""Close the HTTP clients.
|
|
53
|
+
"""Close the HTTP clients.
|
|
54
|
+
|
|
55
|
+
Note: This closes the sync client immediately. For the async client,
|
|
56
|
+
use aclose() instead, or call this from a sync context where you
|
|
57
|
+
don't need to await the async cleanup.
|
|
58
|
+
"""
|
|
54
59
|
if self._client is not None:
|
|
55
60
|
self._client.close()
|
|
56
61
|
self._client = None
|
|
57
62
|
if self._async_client is not None:
|
|
58
|
-
#
|
|
59
|
-
|
|
63
|
+
# Close async client synchronously (will log warning but works)
|
|
64
|
+
# For proper cleanup, use aclose() in async contexts
|
|
65
|
+
try:
|
|
66
|
+
import asyncio
|
|
67
|
+
loop = asyncio.get_running_loop()
|
|
68
|
+
loop.create_task(self._async_client.aclose())
|
|
69
|
+
except RuntimeError:
|
|
70
|
+
# No running loop, close synchronously (httpx supports this)
|
|
71
|
+
self._async_client.close()
|
|
72
|
+
self._async_client = None
|
|
60
73
|
|
|
61
74
|
async def aclose(self) -> None:
|
|
62
75
|
"""Close the async HTTP client."""
|
oxarchive/types.py
CHANGED
|
@@ -118,17 +118,23 @@ class Trade(BaseModel):
|
|
|
118
118
|
closed_pnl: Optional[str] = None
|
|
119
119
|
"""Realized PnL if closing a position."""
|
|
120
120
|
|
|
121
|
-
direction: Optional[
|
|
122
|
-
"""Position direction."""
|
|
121
|
+
direction: Optional[str] = None
|
|
122
|
+
"""Position direction (e.g., 'Open Long', 'Close Short', 'Long > Short')."""
|
|
123
123
|
|
|
124
124
|
start_position: Optional[str] = None
|
|
125
125
|
"""Position size before this trade."""
|
|
126
126
|
|
|
127
|
-
source: Optional[Literal["s3", "ws", "api"]] = None
|
|
128
|
-
"""Data source."""
|
|
127
|
+
source: Optional[Literal["s3", "ws", "api", "live"]] = None
|
|
128
|
+
"""Data source: 's3' (historical), 'api' (REST backfill), 'ws' (websocket), 'live' (real-time ingestion)."""
|
|
129
129
|
|
|
130
130
|
user_address: Optional[str] = None
|
|
131
|
-
"""User's wallet address."""
|
|
131
|
+
"""User's wallet address (for fill-level data)."""
|
|
132
|
+
|
|
133
|
+
maker_address: Optional[str] = None
|
|
134
|
+
"""Maker's wallet address (for market-level WebSocket trades)."""
|
|
135
|
+
|
|
136
|
+
taker_address: Optional[str] = None
|
|
137
|
+
"""Taker's wallet address (for market-level WebSocket trades)."""
|
|
132
138
|
|
|
133
139
|
|
|
134
140
|
# =============================================================================
|
|
@@ -261,12 +267,17 @@ class WsError(BaseModel):
|
|
|
261
267
|
|
|
262
268
|
|
|
263
269
|
class WsData(BaseModel):
|
|
264
|
-
"""Real-time data message from server.
|
|
270
|
+
"""Real-time data message from server.
|
|
271
|
+
|
|
272
|
+
Note: The `data` field can be either a dict (for orderbook) or a list (for trades).
|
|
273
|
+
- Orderbook: dict with 'levels', 'time', etc.
|
|
274
|
+
- Trades: list of trade objects with 'coin', 'side', 'px', 'sz', etc.
|
|
275
|
+
"""
|
|
265
276
|
|
|
266
277
|
type: Literal["data"]
|
|
267
278
|
channel: WsChannel
|
|
268
279
|
coin: str
|
|
269
|
-
data: dict[str, Any]
|
|
280
|
+
data: Union[dict[str, Any], list[dict[str, Any]]]
|
|
270
281
|
|
|
271
282
|
|
|
272
283
|
# =============================================================================
|
oxarchive/websocket.py
CHANGED
|
@@ -120,6 +120,74 @@ StreamProgressHandler = Callable[[int], None] # snapshots_sent
|
|
|
120
120
|
StreamCompleteHandler = Callable[[WsChannel, str, int], None] # channel, coin, snapshots_sent
|
|
121
121
|
|
|
122
122
|
|
|
123
|
+
def _transform_trade(coin: str, raw: dict) -> Trade:
|
|
124
|
+
"""Transform raw Hyperliquid trade format to SDK Trade type.
|
|
125
|
+
|
|
126
|
+
Raw WebSocket format: { coin, side, px, sz, time, hash, tid, users: [maker, taker] }
|
|
127
|
+
Historical replay format: { coin, side, price, size, time, hash, tradeId, userAddress, ... }
|
|
128
|
+
SDK format: { coin, side, price, size, timestamp, tx_hash, trade_id, maker_address, taker_address }
|
|
129
|
+
"""
|
|
130
|
+
from datetime import datetime
|
|
131
|
+
|
|
132
|
+
# Check if already in SDK format (from REST API or historical replay)
|
|
133
|
+
if "price" in raw and "size" in raw:
|
|
134
|
+
# Map camelCase keys from WebSocket to snake_case for Pydantic
|
|
135
|
+
mapped = {
|
|
136
|
+
"coin": raw.get("coin", coin),
|
|
137
|
+
"side": raw.get("side", "B"),
|
|
138
|
+
"price": raw.get("price"),
|
|
139
|
+
"size": raw.get("size"),
|
|
140
|
+
"timestamp": raw.get("timestamp") or (datetime.utcfromtimestamp(raw.get("time", 0) / 1000).isoformat() + "Z" if raw.get("time") else None),
|
|
141
|
+
"tx_hash": raw.get("tx_hash") or raw.get("hash"),
|
|
142
|
+
"trade_id": raw.get("trade_id") or raw.get("tradeId"),
|
|
143
|
+
"order_id": raw.get("order_id") or raw.get("orderId"),
|
|
144
|
+
"crossed": raw.get("crossed"),
|
|
145
|
+
"fee": raw.get("fee"),
|
|
146
|
+
"fee_token": raw.get("fee_token") or raw.get("feeToken"),
|
|
147
|
+
"closed_pnl": raw.get("closed_pnl") or raw.get("closedPnl"),
|
|
148
|
+
"direction": raw.get("direction"),
|
|
149
|
+
"start_position": raw.get("start_position") or raw.get("startPosition"),
|
|
150
|
+
"source": raw.get("source"),
|
|
151
|
+
"user_address": raw.get("user_address") or raw.get("userAddress"),
|
|
152
|
+
"maker_address": raw.get("maker_address"),
|
|
153
|
+
"taker_address": raw.get("taker_address"),
|
|
154
|
+
}
|
|
155
|
+
# Remove None values to let Pydantic use defaults
|
|
156
|
+
mapped = {k: v for k, v in mapped.items() if v is not None}
|
|
157
|
+
return Trade(**mapped)
|
|
158
|
+
|
|
159
|
+
# Transform from Hyperliquid raw format
|
|
160
|
+
time_ms = raw.get("time")
|
|
161
|
+
timestamp = datetime.utcfromtimestamp(time_ms / 1000).isoformat() + "Z" if time_ms else None
|
|
162
|
+
|
|
163
|
+
# Extract maker/taker addresses from users array
|
|
164
|
+
# WebSocket trades have: users: [maker_address, taker_address]
|
|
165
|
+
users = raw.get("users", [])
|
|
166
|
+
maker_address = users[0] if len(users) > 0 else None
|
|
167
|
+
taker_address = users[1] if len(users) > 1 else None
|
|
168
|
+
|
|
169
|
+
return Trade(
|
|
170
|
+
coin=raw.get("coin", coin),
|
|
171
|
+
side=raw.get("side", "B"),
|
|
172
|
+
price=str(raw.get("px", "0")),
|
|
173
|
+
size=str(raw.get("sz", "0")),
|
|
174
|
+
timestamp=timestamp,
|
|
175
|
+
tx_hash=raw.get("hash"),
|
|
176
|
+
trade_id=raw.get("tid"),
|
|
177
|
+
maker_address=maker_address,
|
|
178
|
+
taker_address=taker_address,
|
|
179
|
+
# user_address is for fill-level data (REST API), not market-level WebSocket trades
|
|
180
|
+
user_address=raw.get("user_address"),
|
|
181
|
+
)
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def _transform_trades(coin: str, raw_data: list) -> list[Trade]:
|
|
185
|
+
"""Transform a list of raw trades to SDK Trade types."""
|
|
186
|
+
if not isinstance(raw_data, list):
|
|
187
|
+
return [_transform_trade(coin, raw_data)]
|
|
188
|
+
return [_transform_trade(coin, t) for t in raw_data]
|
|
189
|
+
|
|
190
|
+
|
|
123
191
|
def _transform_orderbook(coin: str, raw: dict) -> OrderBook:
|
|
124
192
|
"""Transform raw Hyperliquid orderbook format to SDK OrderBook type.
|
|
125
193
|
|
|
@@ -642,7 +710,8 @@ class OxArchiveWs:
|
|
|
642
710
|
self._on_orderbook(coin, orderbook)
|
|
643
711
|
|
|
644
712
|
elif channel == "trades" and self._on_trades:
|
|
645
|
-
|
|
713
|
+
# Transform raw Hyperliquid format to SDK Trade type
|
|
714
|
+
trades = _transform_trades(coin, raw_data)
|
|
646
715
|
self._on_trades(coin, trades)
|
|
647
716
|
|
|
648
717
|
# Replay messages (Option B)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oxarchive
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
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
|
|
@@ -28,6 +28,7 @@ Requires-Dist: websockets>=12.0; extra == 'all'
|
|
|
28
28
|
Provides-Extra: dev
|
|
29
29
|
Requires-Dist: mypy>=1.9.0; extra == 'dev'
|
|
30
30
|
Requires-Dist: pytest-asyncio>=0.23.0; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-cov>=4.0.0; extra == 'dev'
|
|
31
32
|
Requires-Dist: pytest>=8.0.0; extra == 'dev'
|
|
32
33
|
Requires-Dist: ruff>=0.4.0; extra == 'dev'
|
|
33
34
|
Provides-Extra: websocket
|
|
@@ -44,6 +45,12 @@ Official Python SDK for [0xarchive](https://0xarchive.io) - Hyperliquid Historic
|
|
|
44
45
|
pip install oxarchive
|
|
45
46
|
```
|
|
46
47
|
|
|
48
|
+
For WebSocket support:
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install oxarchive[websocket]
|
|
52
|
+
```
|
|
53
|
+
|
|
47
54
|
## Quick Start
|
|
48
55
|
|
|
49
56
|
```python
|
|
@@ -96,13 +103,13 @@ async with Client(api_key="ox_your_api_key") as client:
|
|
|
96
103
|
|
|
97
104
|
```python
|
|
98
105
|
client = Client(
|
|
99
|
-
api_key="ox_your_api_key",
|
|
100
|
-
base_url="https://api.0xarchive.io",
|
|
101
|
-
timeout=30.0,
|
|
106
|
+
api_key="ox_your_api_key", # Required
|
|
107
|
+
base_url="https://api.0xarchive.io", # Optional
|
|
108
|
+
timeout=30.0, # Optional, request timeout in seconds (default: 30.0)
|
|
102
109
|
)
|
|
103
110
|
```
|
|
104
111
|
|
|
105
|
-
## API Reference
|
|
112
|
+
## REST API Reference
|
|
106
113
|
|
|
107
114
|
### Order Book
|
|
108
115
|
|
|
@@ -116,38 +123,63 @@ historical = client.orderbook.get("BTC", timestamp=1704067200000)
|
|
|
116
123
|
# Get with limited depth
|
|
117
124
|
shallow = client.orderbook.get("BTC", depth=10)
|
|
118
125
|
|
|
119
|
-
# Get historical snapshots
|
|
126
|
+
# Get historical snapshots (start and end are required)
|
|
120
127
|
history = client.orderbook.history(
|
|
121
128
|
"BTC",
|
|
122
129
|
start="2024-01-01",
|
|
123
130
|
end="2024-01-02",
|
|
124
|
-
limit=1000
|
|
131
|
+
limit=1000,
|
|
132
|
+
depth=20 # Price levels per side
|
|
125
133
|
)
|
|
134
|
+
|
|
135
|
+
# Async versions
|
|
136
|
+
orderbook = await client.orderbook.aget("BTC")
|
|
137
|
+
history = await client.orderbook.ahistory("BTC", start=..., end=...)
|
|
126
138
|
```
|
|
127
139
|
|
|
128
140
|
### Trades
|
|
129
141
|
|
|
142
|
+
The trades API uses cursor-based pagination for efficient retrieval of large datasets.
|
|
143
|
+
|
|
130
144
|
```python
|
|
131
145
|
# Get recent trades
|
|
132
146
|
recent = client.trades.recent("BTC", limit=100)
|
|
133
147
|
|
|
134
|
-
# Get trade history
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
148
|
+
# Get trade history with cursor-based pagination
|
|
149
|
+
result = client.trades.list("ETH", start="2024-01-01", end="2024-01-02", limit=1000)
|
|
150
|
+
trades = result.data
|
|
151
|
+
|
|
152
|
+
# Paginate through all results
|
|
153
|
+
while result.next_cursor:
|
|
154
|
+
result = client.trades.list(
|
|
155
|
+
"ETH",
|
|
156
|
+
start="2024-01-01",
|
|
157
|
+
end="2024-01-02",
|
|
158
|
+
cursor=result.next_cursor,
|
|
159
|
+
limit=1000
|
|
160
|
+
)
|
|
161
|
+
trades.extend(result.data)
|
|
162
|
+
|
|
163
|
+
# Filter by side
|
|
164
|
+
buys = client.trades.list("BTC", start=..., end=..., side="buy")
|
|
165
|
+
|
|
166
|
+
# Async versions
|
|
167
|
+
recent = await client.trades.arecent("BTC")
|
|
168
|
+
result = await client.trades.alist("ETH", start=..., end=...)
|
|
141
169
|
```
|
|
142
170
|
|
|
143
171
|
### Instruments
|
|
144
172
|
|
|
145
173
|
```python
|
|
146
|
-
# List all instruments
|
|
174
|
+
# List all trading instruments
|
|
147
175
|
instruments = client.instruments.list()
|
|
148
176
|
|
|
149
|
-
# Get specific instrument
|
|
177
|
+
# Get specific instrument details
|
|
150
178
|
btc = client.instruments.get("BTC")
|
|
179
|
+
|
|
180
|
+
# Async versions
|
|
181
|
+
instruments = await client.instruments.alist()
|
|
182
|
+
btc = await client.instruments.aget("BTC")
|
|
151
183
|
```
|
|
152
184
|
|
|
153
185
|
### Funding Rates
|
|
@@ -156,12 +188,16 @@ btc = client.instruments.get("BTC")
|
|
|
156
188
|
# Get current funding rate
|
|
157
189
|
current = client.funding.current("BTC")
|
|
158
190
|
|
|
159
|
-
# Get funding rate history
|
|
191
|
+
# Get funding rate history (start is required)
|
|
160
192
|
history = client.funding.history(
|
|
161
193
|
"ETH",
|
|
162
194
|
start="2024-01-01",
|
|
163
195
|
end="2024-01-07"
|
|
164
196
|
)
|
|
197
|
+
|
|
198
|
+
# Async versions
|
|
199
|
+
current = await client.funding.acurrent("BTC")
|
|
200
|
+
history = await client.funding.ahistory("ETH", start=..., end=...)
|
|
165
201
|
```
|
|
166
202
|
|
|
167
203
|
### Open Interest
|
|
@@ -170,40 +206,32 @@ history = client.funding.history(
|
|
|
170
206
|
# Get current open interest
|
|
171
207
|
current = client.open_interest.current("BTC")
|
|
172
208
|
|
|
173
|
-
# Get open interest history
|
|
209
|
+
# Get open interest history (start is required)
|
|
174
210
|
history = client.open_interest.history(
|
|
175
211
|
"ETH",
|
|
176
212
|
start="2024-01-01",
|
|
177
213
|
end="2024-01-07"
|
|
178
214
|
)
|
|
215
|
+
|
|
216
|
+
# Async versions
|
|
217
|
+
current = await client.open_interest.acurrent("BTC")
|
|
218
|
+
history = await client.open_interest.ahistory("ETH", start=..., end=...)
|
|
179
219
|
```
|
|
180
220
|
|
|
181
|
-
##
|
|
221
|
+
## WebSocket Client
|
|
182
222
|
|
|
183
|
-
The
|
|
223
|
+
The WebSocket client supports three modes: real-time streaming, historical replay, and bulk streaming.
|
|
184
224
|
|
|
185
225
|
```python
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
# Unix milliseconds
|
|
189
|
-
client.orderbook.get("BTC", timestamp=1704067200000)
|
|
190
|
-
|
|
191
|
-
# ISO string
|
|
192
|
-
client.orderbook.history("BTC", start="2024-01-01", end="2024-01-02")
|
|
226
|
+
import asyncio
|
|
227
|
+
from oxarchive import OxArchiveWs, WsOptions
|
|
193
228
|
|
|
194
|
-
|
|
195
|
-
client.orderbook.history("BTC", start=datetime(2024, 1, 1), end=datetime(2024, 1, 2))
|
|
229
|
+
ws = OxArchiveWs(WsOptions(api_key="ox_your_api_key"))
|
|
196
230
|
```
|
|
197
231
|
|
|
198
|
-
|
|
232
|
+
### Real-time Streaming
|
|
199
233
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
```bash
|
|
203
|
-
pip install oxarchive[websocket]
|
|
204
|
-
```
|
|
205
|
-
|
|
206
|
-
### Basic Usage
|
|
234
|
+
Subscribe to live market data from Hyperliquid.
|
|
207
235
|
|
|
208
236
|
```python
|
|
209
237
|
import asyncio
|
|
@@ -226,24 +254,26 @@ async def main():
|
|
|
226
254
|
ws.subscribe_trades("BTC")
|
|
227
255
|
ws.subscribe_all_tickers()
|
|
228
256
|
|
|
229
|
-
# Handle
|
|
257
|
+
# Handle real-time data
|
|
230
258
|
ws.on_orderbook(lambda coin, data: print(f"{coin}: {data.mid_price}"))
|
|
231
|
-
|
|
232
|
-
# Handle trade updates
|
|
233
259
|
ws.on_trades(lambda coin, trades: print(f"{coin}: {len(trades)} trades"))
|
|
234
260
|
|
|
235
261
|
# Keep running
|
|
236
262
|
await asyncio.sleep(60)
|
|
237
263
|
|
|
238
|
-
#
|
|
264
|
+
# Unsubscribe and disconnect
|
|
265
|
+
ws.unsubscribe_orderbook("ETH")
|
|
239
266
|
await ws.disconnect()
|
|
240
267
|
|
|
241
268
|
asyncio.run(main())
|
|
242
269
|
```
|
|
243
270
|
|
|
244
|
-
### Historical Replay
|
|
271
|
+
### Historical Replay
|
|
245
272
|
|
|
246
|
-
Replay historical data with timing preserved
|
|
273
|
+
Replay historical data with timing preserved. Perfect for backtesting.
|
|
274
|
+
|
|
275
|
+
> **Important:** Replay data is delivered via `on_historical_data()`, NOT `on_trades()` or `on_orderbook()`.
|
|
276
|
+
> The real-time callbacks only receive live market data from subscriptions.
|
|
247
277
|
|
|
248
278
|
```python
|
|
249
279
|
import asyncio
|
|
@@ -253,13 +283,14 @@ from oxarchive import OxArchiveWs, WsOptions
|
|
|
253
283
|
async def main():
|
|
254
284
|
ws = OxArchiveWs(WsOptions(api_key="ox_..."))
|
|
255
285
|
|
|
256
|
-
# Handle replay data
|
|
286
|
+
# Handle replay data - this is where historical records arrive
|
|
257
287
|
ws.on_historical_data(lambda coin, ts, data:
|
|
258
288
|
print(f"{ts}: {data['mid_price']}")
|
|
259
289
|
)
|
|
260
290
|
|
|
291
|
+
# Replay lifecycle events
|
|
261
292
|
ws.on_replay_start(lambda ch, coin, start, end, speed:
|
|
262
|
-
print(f"Starting replay
|
|
293
|
+
print(f"Starting replay: {ch}/{coin} at {speed}x")
|
|
263
294
|
)
|
|
264
295
|
|
|
265
296
|
ws.on_replay_complete(lambda ch, coin, sent:
|
|
@@ -272,7 +303,8 @@ async def main():
|
|
|
272
303
|
await ws.replay(
|
|
273
304
|
"orderbook", "BTC",
|
|
274
305
|
start=int(time.time() * 1000) - 86400000, # 24 hours ago
|
|
275
|
-
|
|
306
|
+
end=int(time.time() * 1000), # Optional
|
|
307
|
+
speed=10 # Optional, defaults to 1x
|
|
276
308
|
)
|
|
277
309
|
|
|
278
310
|
# Control playback
|
|
@@ -284,9 +316,9 @@ async def main():
|
|
|
284
316
|
asyncio.run(main())
|
|
285
317
|
```
|
|
286
318
|
|
|
287
|
-
### Bulk Streaming
|
|
319
|
+
### Bulk Streaming
|
|
288
320
|
|
|
289
|
-
Fast bulk download for data pipelines
|
|
321
|
+
Fast bulk download for data pipelines. Data arrives in batches without timing delays.
|
|
290
322
|
|
|
291
323
|
```python
|
|
292
324
|
import asyncio
|
|
@@ -303,7 +335,7 @@ async def main():
|
|
|
303
335
|
)
|
|
304
336
|
|
|
305
337
|
ws.on_stream_progress(lambda snapshots_sent:
|
|
306
|
-
print(f"
|
|
338
|
+
print(f"Progress: {snapshots_sent} snapshots")
|
|
307
339
|
)
|
|
308
340
|
|
|
309
341
|
ws.on_stream_complete(lambda ch, coin, sent:
|
|
@@ -317,25 +349,25 @@ async def main():
|
|
|
317
349
|
"orderbook", "ETH",
|
|
318
350
|
start=int(time.time() * 1000) - 3600000, # 1 hour ago
|
|
319
351
|
end=int(time.time() * 1000),
|
|
320
|
-
batch_size=1000
|
|
352
|
+
batch_size=1000 # Optional, defaults to 1000
|
|
321
353
|
)
|
|
322
354
|
|
|
323
|
-
# Stop
|
|
355
|
+
# Stop if needed
|
|
324
356
|
await ws.stream_stop()
|
|
325
357
|
|
|
326
358
|
asyncio.run(main())
|
|
327
359
|
```
|
|
328
360
|
|
|
329
|
-
### Configuration
|
|
361
|
+
### WebSocket Configuration
|
|
330
362
|
|
|
331
363
|
```python
|
|
332
364
|
ws = OxArchiveWs(WsOptions(
|
|
333
365
|
api_key="ox_your_api_key",
|
|
334
366
|
ws_url="wss://api.0xarchive.io/ws", # Optional
|
|
335
|
-
auto_reconnect=True,
|
|
336
|
-
reconnect_delay=1.0,
|
|
337
|
-
max_reconnect_attempts=10,
|
|
338
|
-
ping_interval=30.0,
|
|
367
|
+
auto_reconnect=True, # Auto-reconnect on disconnect (default: True)
|
|
368
|
+
reconnect_delay=1.0, # Initial reconnect delay in seconds (default: 1.0)
|
|
369
|
+
max_reconnect_attempts=10, # Max reconnect attempts (default: 10)
|
|
370
|
+
ping_interval=30.0, # Keep-alive ping interval in seconds (default: 30.0)
|
|
339
371
|
))
|
|
340
372
|
```
|
|
341
373
|
|
|
@@ -348,6 +380,27 @@ ws = OxArchiveWs(WsOptions(
|
|
|
348
380
|
| `ticker` | Price and 24h volume | Yes |
|
|
349
381
|
| `all_tickers` | All market tickers | No |
|
|
350
382
|
|
|
383
|
+
## Timestamp Formats
|
|
384
|
+
|
|
385
|
+
The SDK accepts timestamps in multiple formats:
|
|
386
|
+
|
|
387
|
+
```python
|
|
388
|
+
from datetime import datetime
|
|
389
|
+
|
|
390
|
+
# Unix milliseconds (int)
|
|
391
|
+
client.orderbook.get("BTC", timestamp=1704067200000)
|
|
392
|
+
|
|
393
|
+
# ISO string
|
|
394
|
+
client.orderbook.history("BTC", start="2024-01-01", end="2024-01-02")
|
|
395
|
+
|
|
396
|
+
# datetime object
|
|
397
|
+
client.orderbook.history(
|
|
398
|
+
"BTC",
|
|
399
|
+
start=datetime(2024, 1, 1),
|
|
400
|
+
end=datetime(2024, 1, 2)
|
|
401
|
+
)
|
|
402
|
+
```
|
|
403
|
+
|
|
351
404
|
## Error Handling
|
|
352
405
|
|
|
353
406
|
```python
|
|
@@ -368,12 +421,15 @@ except OxArchiveError as e:
|
|
|
368
421
|
Full type hint support with Pydantic models:
|
|
369
422
|
|
|
370
423
|
```python
|
|
371
|
-
from oxarchive import Client
|
|
424
|
+
from oxarchive import Client
|
|
425
|
+
from oxarchive.types import OrderBook, Trade, Instrument, FundingRate, OpenInterest
|
|
426
|
+
from oxarchive.resources.trades import CursorResponse
|
|
372
427
|
|
|
373
428
|
client = Client(api_key="ox_your_api_key")
|
|
374
429
|
|
|
375
430
|
orderbook: OrderBook = client.orderbook.get("BTC")
|
|
376
431
|
trades: list[Trade] = client.trades.recent("BTC")
|
|
432
|
+
result: CursorResponse = client.trades.list("BTC", start=..., end=...)
|
|
377
433
|
```
|
|
378
434
|
|
|
379
435
|
## Requirements
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
oxarchive/__init__.py,sha256=
|
|
1
|
+
oxarchive/__init__.py,sha256=Q6hk0SMNM5HLYIuyFXrCPYrT261n90iPKoGakQL11vk,2181
|
|
2
2
|
oxarchive/client.py,sha256=3P0fvOcyM5BWppkVV4054NduDHKvRg-cWeluoGymmRk,3163
|
|
3
|
-
oxarchive/http.py,sha256=
|
|
4
|
-
oxarchive/types.py,sha256=
|
|
5
|
-
oxarchive/websocket.py,sha256=
|
|
3
|
+
oxarchive/http.py,sha256=SY_o9Ag8ADo1HI3i3uAKW1xwkYjPE75gRAjnMsddAGs,4211
|
|
4
|
+
oxarchive/types.py,sha256=pQJt1ZilZaV6h4anPYHloVrB97Q9Y2v9B9iYTkMXFo0,11025
|
|
5
|
+
oxarchive/websocket.py,sha256=f5MeqwWL0WRn1X4uRXaSir7izUPPpkG1R75JuvA_fqE,28383
|
|
6
6
|
oxarchive/resources/__init__.py,sha256=WQ4GYQ8p3L0D2Isk4IV4h1DRpvyZlt6tOF1t_CJr6ls,385
|
|
7
7
|
oxarchive/resources/funding.py,sha256=TXkZxodVQTVcVbzNG6SpMQAzf8AkLm2NYZJxnP4MNXw,3500
|
|
8
8
|
oxarchive/resources/instruments.py,sha256=flD1sH6x3P3CTqV1ZwkfwbranVacmhsHn5Dhr7lGQhM,1606
|
|
9
9
|
oxarchive/resources/openinterest.py,sha256=h13yLA72LpfryUf8IqF6W7uE4ObYY2Qbc-auv4LtPqc,3552
|
|
10
10
|
oxarchive/resources/orderbook.py,sha256=o_DTdpzKrZvHL9YXm8cGGUugPM8uUa6r9O_72r1ByV0,4557
|
|
11
11
|
oxarchive/resources/trades.py,sha256=XCi2rXA2hxaTt0KNlWw8f7W0hzAvNWyT7DaivMz_rHw,10012
|
|
12
|
-
oxarchive-0.3.
|
|
13
|
-
oxarchive-0.3.
|
|
14
|
-
oxarchive-0.3.
|
|
12
|
+
oxarchive-0.3.6.dist-info/METADATA,sha256=mAi4P9emfIG3_rlaFXyocwpRjxLEw9xo5sAwnMBUE5U,11070
|
|
13
|
+
oxarchive-0.3.6.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
|
|
14
|
+
oxarchive-0.3.6.dist-info/RECORD,,
|
|
File without changes
|