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.
@@ -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.2
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
@@ -57,7 +57,7 @@ except ImportError:
57
57
  OxArchiveWs = None # type: ignore
58
58
  WsOptions = None # type: ignore
59
59
 
60
- __version__ = "0.1.0"
60
+ __version__ = "0.3.3"
61
61
 
62
62
  __all__ = [
63
63
  # Client
@@ -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
- # Note: async client should be closed with await
59
- pass
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.2"
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