oxarchive 0.3.2__tar.gz → 0.3.3__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.
- oxarchive-0.3.3/.gitignore +78 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/PKG-INFO +2 -1
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/__init__.py +1 -1
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/http.py +16 -3
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/types.py +9 -3
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/websocket.py +12 -2
- {oxarchive-0.3.2 → oxarchive-0.3.3}/pyproject.toml +2 -1
- {oxarchive-0.3.2 → oxarchive-0.3.3}/README.md +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/client.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/__init__.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/funding.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/instruments.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/openinterest.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/orderbook.py +0 -0
- {oxarchive-0.3.2 → oxarchive-0.3.3}/oxarchive/resources/trades.py +0 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
# Tests (internal only, not published)
|
|
2
|
+
tests/
|
|
3
|
+
|
|
4
|
+
# Byte-compiled / optimized / DLL files
|
|
5
|
+
__pycache__/
|
|
6
|
+
*.py[cod]
|
|
7
|
+
*$py.class
|
|
8
|
+
|
|
9
|
+
# C extensions
|
|
10
|
+
*.so
|
|
11
|
+
|
|
12
|
+
# Distribution / packaging
|
|
13
|
+
.Python
|
|
14
|
+
build/
|
|
15
|
+
develop-eggs/
|
|
16
|
+
dist/
|
|
17
|
+
downloads/
|
|
18
|
+
eggs/
|
|
19
|
+
.eggs/
|
|
20
|
+
lib/
|
|
21
|
+
lib64/
|
|
22
|
+
parts/
|
|
23
|
+
sdist/
|
|
24
|
+
var/
|
|
25
|
+
wheels/
|
|
26
|
+
*.egg-info/
|
|
27
|
+
.installed.cfg
|
|
28
|
+
*.egg
|
|
29
|
+
|
|
30
|
+
# PyInstaller
|
|
31
|
+
*.manifest
|
|
32
|
+
*.spec
|
|
33
|
+
|
|
34
|
+
# Installer logs
|
|
35
|
+
pip-log.txt
|
|
36
|
+
pip-delete-this-directory.txt
|
|
37
|
+
|
|
38
|
+
# Unit test / coverage reports
|
|
39
|
+
htmlcov/
|
|
40
|
+
.tox/
|
|
41
|
+
.nox/
|
|
42
|
+
.coverage
|
|
43
|
+
.coverage.*
|
|
44
|
+
.cache
|
|
45
|
+
nosetests.xml
|
|
46
|
+
coverage.xml
|
|
47
|
+
*.cover
|
|
48
|
+
*.py,cover
|
|
49
|
+
.hypothesis/
|
|
50
|
+
.pytest_cache/
|
|
51
|
+
|
|
52
|
+
# Translations
|
|
53
|
+
*.mo
|
|
54
|
+
*.pot
|
|
55
|
+
|
|
56
|
+
# Environments
|
|
57
|
+
.env
|
|
58
|
+
.venv
|
|
59
|
+
env/
|
|
60
|
+
venv/
|
|
61
|
+
ENV/
|
|
62
|
+
env.bak/
|
|
63
|
+
venv.bak/
|
|
64
|
+
|
|
65
|
+
# mypy
|
|
66
|
+
.mypy_cache/
|
|
67
|
+
.dmypy.json
|
|
68
|
+
dmypy.json
|
|
69
|
+
|
|
70
|
+
# IDE
|
|
71
|
+
.idea/
|
|
72
|
+
.vscode/
|
|
73
|
+
*.swp
|
|
74
|
+
*.swo
|
|
75
|
+
|
|
76
|
+
# OS
|
|
77
|
+
.DS_Store
|
|
78
|
+
Thumbs.db
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: oxarchive
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.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
|
|
@@ -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
|
|
@@ -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."""
|
|
@@ -124,11 +124,17 @@ class Trade(BaseModel):
|
|
|
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
|
# =============================================================================
|
|
@@ -123,8 +123,8 @@ StreamCompleteHandler = Callable[[WsChannel, str, int], None] # channel, coin,
|
|
|
123
123
|
def _transform_trade(coin: str, raw: dict) -> Trade:
|
|
124
124
|
"""Transform raw Hyperliquid trade format to SDK Trade type.
|
|
125
125
|
|
|
126
|
-
Raw format: { coin, side, px, sz, time, hash, tid }
|
|
127
|
-
SDK format: { coin, side, price, size, timestamp, tx_hash, trade_id }
|
|
126
|
+
Raw WebSocket format: { coin, side, px, sz, time, hash, tid, users: [maker, taker] }
|
|
127
|
+
SDK format: { coin, side, price, size, timestamp, tx_hash, trade_id, maker_address, taker_address }
|
|
128
128
|
"""
|
|
129
129
|
from datetime import datetime
|
|
130
130
|
|
|
@@ -136,6 +136,12 @@ def _transform_trade(coin: str, raw: dict) -> Trade:
|
|
|
136
136
|
time_ms = raw.get("time")
|
|
137
137
|
timestamp = datetime.utcfromtimestamp(time_ms / 1000).isoformat() + "Z" if time_ms else None
|
|
138
138
|
|
|
139
|
+
# Extract maker/taker addresses from users array
|
|
140
|
+
# WebSocket trades have: users: [maker_address, taker_address]
|
|
141
|
+
users = raw.get("users", [])
|
|
142
|
+
maker_address = users[0] if len(users) > 0 else None
|
|
143
|
+
taker_address = users[1] if len(users) > 1 else None
|
|
144
|
+
|
|
139
145
|
return Trade(
|
|
140
146
|
coin=raw.get("coin", coin),
|
|
141
147
|
side=raw.get("side", "B"),
|
|
@@ -144,6 +150,10 @@ def _transform_trade(coin: str, raw: dict) -> Trade:
|
|
|
144
150
|
timestamp=timestamp,
|
|
145
151
|
tx_hash=raw.get("hash"),
|
|
146
152
|
trade_id=raw.get("tid"),
|
|
153
|
+
maker_address=maker_address,
|
|
154
|
+
taker_address=taker_address,
|
|
155
|
+
# user_address is for fill-level data (REST API), not market-level WebSocket trades
|
|
156
|
+
user_address=raw.get("user_address"),
|
|
147
157
|
)
|
|
148
158
|
|
|
149
159
|
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "oxarchive"
|
|
7
|
-
version = "0.3.
|
|
7
|
+
version = "0.3.3"
|
|
8
8
|
description = "Official Python SDK for 0xarchive - Hyperliquid Historical Data API"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
@@ -38,6 +38,7 @@ websocket = [
|
|
|
38
38
|
dev = [
|
|
39
39
|
"pytest>=8.0.0",
|
|
40
40
|
"pytest-asyncio>=0.23.0",
|
|
41
|
+
"pytest-cov>=4.0.0",
|
|
41
42
|
"ruff>=0.4.0",
|
|
42
43
|
"mypy>=1.9.0",
|
|
43
44
|
]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|