hyperquant 0.22__tar.gz → 0.24__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.
Files changed (23) hide show
  1. {hyperquant-0.22 → hyperquant-0.24}/.gitignore +0 -1
  2. {hyperquant-0.22 → hyperquant-0.24}/PKG-INFO +2 -2
  3. {hyperquant-0.22 → hyperquant-0.24}/pyproject.toml +2 -2
  4. hyperquant-0.24/src/hyperquant/broker/lib/hpstore.py +252 -0
  5. hyperquant-0.24/src/hyperquant/broker/lib/hyper_types.py +48 -0
  6. {hyperquant-0.22 → hyperquant-0.24}/uv.lock +5 -5
  7. {hyperquant-0.22 → hyperquant-0.24}/.python-version +0 -0
  8. {hyperquant-0.22 → hyperquant-0.24}/README.md +0 -0
  9. {hyperquant-0.22 → hyperquant-0.24}/pub.sh +0 -0
  10. {hyperquant-0.22 → hyperquant-0.24}/requirements-dev.lock +0 -0
  11. {hyperquant-0.22 → hyperquant-0.24}/requirements.lock +0 -0
  12. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/__init__.py +0 -0
  13. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/broker/hyperliquid.py +0 -0
  14. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/core.py +0 -0
  15. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/datavison/_util.py +0 -0
  16. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/datavison/binance.py +0 -0
  17. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/datavison/coinglass.py +0 -0
  18. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/datavison/okx.py +0 -0
  19. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/db.py +0 -0
  20. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/draw.py +0 -0
  21. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/logkit.py +0 -0
  22. {hyperquant-0.22 → hyperquant-0.24}/src/hyperquant/notikit.py +0 -0
  23. {hyperquant-0.22 → hyperquant-0.24}/test.py +0 -0
@@ -10,7 +10,6 @@ dist/
10
10
  downloads/
11
11
  eggs/
12
12
  .eggs/
13
- lib/
14
13
  lib64/
15
14
  parts/
16
15
  sdist/
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.22
3
+ Version: 0.24
4
4
  Summary: A minimal yet hyper-efficient backtesting framework for quantitative trading
5
5
  Project-URL: Homepage, https://github.com/yourusername/hyperquant
6
6
  Project-URL: Issues, https://github.com/yourusername/hyperquant/issues
@@ -19,7 +19,7 @@ Requires-Dist: cryptography>=44.0.2
19
19
  Requires-Dist: duckdb>=1.2.2
20
20
  Requires-Dist: numpy>=1.21.0
21
21
  Requires-Dist: pandas>=2.2.3
22
- Requires-Dist: pybotters>=1.8.2
22
+ Requires-Dist: pybotters>=1.9.0
23
23
  Requires-Dist: pyecharts>=2.0.8
24
24
  Description-Content-Type: text/markdown
25
25
 
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "0.22"
3
+ version = "0.24"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -13,7 +13,7 @@ dependencies = [
13
13
  "cryptography>=44.0.2",
14
14
  "numpy>=1.21.0", # Added numpy as a new dependency
15
15
  "duckdb>=1.2.2",
16
- "pybotters>=1.8.2",
16
+ "pybotters>=1.9.0",
17
17
  ]
18
18
  readme = "README.md"
19
19
  requires-python = ">=3.9"
@@ -0,0 +1,252 @@
1
+ from __future__ import annotations
2
+
3
+ import time
4
+ from aiohttp import ClientWebSocketResponse
5
+ import aiohttp
6
+
7
+ from pybotters.store import DataStore
8
+ from pybotters.models.hyperliquid import HyperliquidDataStore
9
+ from typing import TYPE_CHECKING, Awaitable
10
+
11
+ if TYPE_CHECKING:
12
+ from pybotters.typedefs import Item
13
+ from pybotters.ws import ClientWebSocketResponse
14
+
15
+
16
+
17
+ # {'channel': 'orderUpdates', 'data': [{'order': {'coin': 'HYPE', 'side': 'A', 'limitPx': '22.887', 'sz': '1.12', 'oid': 29641480516, 'timestamp': 1746766108031, 'origSz': '1.12', 'reduceOnly': True}, 'status': 'rejected', 'statusTimestamp': 1746766108031}]}
18
+ class OrderStore(DataStore):
19
+ _KEYS = ["oid"]
20
+
21
+ def _onmessage(self, msg: Item) -> None:
22
+
23
+ for rec in msg:
24
+ order = rec["order"]
25
+ item = {
26
+ **order,
27
+ "status": rec.get("status"),
28
+ "px": None,
29
+ 'fee': None,
30
+ "statusTimestamp": rec.get("statusTimestamp"),
31
+ }
32
+
33
+ if item["status"] == "open":
34
+ self._update([item])
35
+ else:
36
+ self._delete([item])
37
+
38
+ class FillStore(DataStore):
39
+ _KEYS = ["oid"]
40
+
41
+ def _onmessage(self, msg: Item) -> None:
42
+ for fill in msg:
43
+ self._update([fill])
44
+
45
+
46
+
47
+ class Account(DataStore):
48
+ _KEYS = ["marginCoin", "value"]
49
+
50
+ def _onmessage(self, data: list[Item]) -> None:
51
+ self._update(
52
+ [
53
+ {
54
+ "marginCoin": 'USDC',
55
+ 'value': float(item['accountValue']),
56
+ 'frozen': float(item['totalMarginUsed']),
57
+ 'available': float(item['accountValue']) - float(item['totalMarginUsed']),
58
+ }
59
+ for item in data
60
+ ]
61
+ )
62
+
63
+ class SpotAccount(DataStore):
64
+
65
+ _KEYS = ["coin"]
66
+
67
+ def _onmessage(self, data: list[Item]) -> None:
68
+ self._update(
69
+ [
70
+ {
71
+ "coin": item['coin'],
72
+ "total": float(item['total']),
73
+ "frozen": float(item['hold']),
74
+ "available": float(item['total']) - float(item['hold']),
75
+ "entryNtl": float(item['entryNtl']),
76
+ }
77
+ for item in data
78
+ ]
79
+ )
80
+
81
+ class PositionStore(DataStore):
82
+ _KEYS = ["coin"]
83
+
84
+ def _onmessage(self, data: list[Item]) -> None:
85
+
86
+ if len(data) == 0 and self.__len__() > 0:
87
+ self._clear()
88
+ elif len(data) > 0:
89
+ self._update([
90
+
91
+ {
92
+ "coin": item['position']['coin'],
93
+ "sz": float(item['position']['szi']),
94
+ "px": float(item['position']['entryPx']),
95
+ 'unpnl': float(item['position']['unrealizedPnl']),
96
+ 'rt': float(item['position']['returnOnEquity']),
97
+ 'lv': int(item['position']['leverage']['value']),
98
+ }
99
+ for item in data
100
+ ])
101
+
102
+
103
+ class MyHyperStore(HyperliquidDataStore):
104
+ ORDER_TYPE = 'orderUpdates'
105
+ WEBDATA2_TYPE = 'webData2'
106
+ ORDER_FILL_TYPE = 'userFills'
107
+
108
+ def _init(self) -> None:
109
+ self._create("orders", datastore_class=OrderStore)
110
+ self._create("account", datastore_class=Account)
111
+ self._create("positions", datastore_class=PositionStore)
112
+ self._create("spot_account", datastore_class=SpotAccount)
113
+ self._create("fills", datastore_class=FillStore)
114
+ super()._init()
115
+
116
+ def _onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
117
+
118
+ if msg.get("channel") == self.ORDER_TYPE:
119
+ self.orders._onmessage(msg.get('data', []))
120
+ elif msg.get("channel") == self.WEBDATA2_TYPE:
121
+ # print(msg.get('data', {}).get('clearinghouseState', {}))
122
+ act_data = msg.get('data', {}).get('clearinghouseState', {}).get('crossMarginSummary', [])
123
+ if act_data:
124
+ self.account._onmessage([act_data])
125
+
126
+ pos_data = msg.get('data', {}).get('clearinghouseState', {}).get('assetPositions', [])
127
+ self.positions._onmessage(pos_data)
128
+
129
+ spot_act_data = msg.get('data', {}).get('spotState', {}).get('balances', [])
130
+ self.spot_account._onmessage(spot_act_data)
131
+
132
+ elif msg.get("channel") == self.ORDER_FILL_TYPE:
133
+ fills = msg.get('data', {}).get('fills', [])
134
+ is_snap = msg.get('data', {}).get('isSnapshot', False)
135
+ if not is_snap:
136
+ self.fills._onmessage(fills)
137
+
138
+ super()._onmessage(msg, ws)
139
+
140
+ async def initialize(self, *aws: tuple[str, Awaitable[aiohttp.ClientResponse]]) -> None:
141
+
142
+ for a in aws:
143
+ method, f = a
144
+ resp = await f
145
+ data = await resp.json()
146
+ if method == "orders":
147
+
148
+ self.orders._onmessage(
149
+ [
150
+ {
151
+ 'order': o,
152
+ 'status': "open",
153
+ 'statusTimestamp': int(time.time() * 1000)
154
+ } for o in data
155
+ ]
156
+ )
157
+
158
+ pass
159
+
160
+ @property
161
+ def orders(self) -> OrderStore:
162
+ """``orders`` data stream.
163
+
164
+ https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
165
+
166
+ Data structure:
167
+
168
+ .. code:: python
169
+ [
170
+ {
171
+ "coin": "HYPE",
172
+ "side": "A",
173
+ "limitPx": "22.887",
174
+ "sz": "1.12",
175
+ "oid": 29641480516,
176
+ "timestamp": 1746766108031,
177
+ "origSz": "1.12",
178
+ "reduceOnly": True
179
+ "status": "open",
180
+ "statusTimestamp": 1746766108031
181
+ }...
182
+ ]
183
+ """
184
+ return self._get("orders", OrderStore)
185
+ @property
186
+ def account(self) -> Account:
187
+ """``account`` data stream.
188
+ https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
189
+ Data structure:
190
+ .. code:: python
191
+ [
192
+ {
193
+ "marginCoin": 'USDC',
194
+ 'value': float(item['accountValue']),
195
+ 'frozen': float(item['totalMarginUsed']),
196
+ 'available': float(item['accountValue']) - float(item['totalMarginUsed']),
197
+ }...
198
+ ]
199
+ """
200
+ return self._get("account", Account)
201
+
202
+ @property
203
+ def positions(self) -> PositionStore:
204
+ return self._get("positions", PositionStore)
205
+
206
+ @property
207
+ def spot_account(self) -> SpotAccount:
208
+ """``spot_account`` data stream.
209
+ https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
210
+ Data structure:
211
+ .. code:: python
212
+ [
213
+ {
214
+ "coin": 'FEUSD',
215
+ "sz": "21.0",
216
+ "px": "0.9719",
217
+ "unpnl": "0.0",
218
+ "rt": "0.0",
219
+ "lv": 1,
220
+ }...
221
+ ]
222
+ """
223
+ return self._get("spot_account", SpotAccount)
224
+
225
+ @property
226
+ def fills(self) -> FillStore:
227
+ """``fills`` data stream.
228
+ https://hyperliquid.gitbook.io/hyperliquid-docs/for-developers/api/websocket/subscriptions
229
+ Data structure:
230
+ .. code:: python
231
+ [
232
+ {
233
+ "coin": 'FEUSD',
234
+ "px": "0.9719",
235
+ "sz": "21.0",
236
+ "side": 'buy',
237
+ "time": 1679999999999,
238
+ "startPosition": '0.0',
239
+ "dir": 'buy',
240
+ "closedPnl": '0.0',
241
+ "hash": '0x123456789abcdef',
242
+ "oid": 123456789,
243
+ "crossed": True,
244
+ "fee": '-0.0001',
245
+ "tid": 987654321,
246
+ "liquidation": None,
247
+ "feeToken": 'USDC',
248
+ }...
249
+ ]
250
+ """
251
+ return self._get("fills", FillStore)
252
+
@@ -0,0 +1,48 @@
1
+ from typing import TypedDict, Dict
2
+
3
+ class Leverage(TypedDict):
4
+ rawUsd: str
5
+ type: str
6
+ value: int
7
+
8
+ class CumFunding(TypedDict):
9
+ allTime: str
10
+ sinceChange: str
11
+ sinceOpen: str
12
+
13
+ class Position(TypedDict):
14
+ coin: str
15
+ cumFunding: CumFunding
16
+ entryPx: str
17
+ leverage: Leverage
18
+ liquidationPx: str
19
+ marginUsed: str
20
+ maxLeverage: int
21
+ positionValue: str
22
+ returnOnEquity: str
23
+ szi: str
24
+ unrealizedPnl: str
25
+
26
+ class AssetPosition(TypedDict):
27
+ position: Position
28
+ type: str
29
+
30
+ class CrossMarginSummary(TypedDict):
31
+ accountValue: str
32
+ totalMarginUsed: str
33
+ totalNtlPos: str
34
+ totalRawUsd: str
35
+
36
+ class MarginSummary(TypedDict):
37
+ accountValue: str
38
+ totalMarginUsed: str
39
+ totalNtlPos: str
40
+ totalRawUsd: str
41
+
42
+ class AccountBalance(TypedDict):
43
+ assetPositions: list[AssetPosition]
44
+ crossMaintenanceMarginUsed: str
45
+ crossMarginSummary: CrossMarginSummary
46
+ marginSummary: MarginSummary
47
+ time: int
48
+ withdrawable: str
@@ -530,7 +530,7 @@ wheels = [
530
530
 
531
531
  [[package]]
532
532
  name = "hyperquant"
533
- version = "0.21"
533
+ version = "0.23"
534
534
  source = { editable = "." }
535
535
  dependencies = [
536
536
  { name = "aiohttp" },
@@ -557,7 +557,7 @@ requires-dist = [
557
557
  { name = "duckdb", specifier = ">=1.2.2" },
558
558
  { name = "numpy", specifier = ">=1.21.0" },
559
559
  { name = "pandas", specifier = ">=2.2.3" },
560
- { name = "pybotters", specifier = ">=1.8.2" },
560
+ { name = "pybotters", specifier = ">=1.9.0" },
561
561
  { name = "pyecharts", specifier = ">=2.0.8" },
562
562
  ]
563
563
 
@@ -1221,15 +1221,15 @@ wheels = [
1221
1221
 
1222
1222
  [[package]]
1223
1223
  name = "pybotters"
1224
- version = "1.8.2"
1224
+ version = "1.9.0"
1225
1225
  source = { registry = "https://pypi.org/simple" }
1226
1226
  dependencies = [
1227
1227
  { name = "aiohttp" },
1228
1228
  { name = "typing-extensions", marker = "python_full_version < '3.10'" },
1229
1229
  ]
1230
- sdist = { url = "https://files.pythonhosted.org/packages/3d/dd/dedd0e9882aba4ac14ec4697e97c33a70c7f0bc1433581c376f50b093e82/pybotters-1.8.2.tar.gz", hash = "sha256:b15e7c52582f139cf3fb6858296324fe0cbc5349084b86b9dbc7f76c3ea3c109", size = 551553 }
1230
+ sdist = { url = "https://files.pythonhosted.org/packages/1c/32/c90531c4fab11030afba9343188b74bb56b009390e0b873af01a460e2cd2/pybotters-1.9.0.tar.gz", hash = "sha256:91f0d54ae60805ce408494f0ee0cb83c7d4a74f70d49eda8f550bde0aa71a7d1", size = 558643 }
1231
1231
  wheels = [
1232
- { url = "https://files.pythonhosted.org/packages/89/21/f0cc2bedac2b2ef5914321515970f9e7813ab85250c0e86fe13a850da92a/pybotters-1.8.2-py3-none-any.whl", hash = "sha256:e3955f6dfd100c7fded4f8d60bbe736e0dd7837517868bc7aab3b08a740416d0", size = 516721 },
1232
+ { url = "https://files.pythonhosted.org/packages/a0/6c/c382df909de72ad90bf9b319ccb67e7274a5bd2cb8f178c1322cf4b6da16/pybotters-1.9.0-py3-none-any.whl", hash = "sha256:91a70301e0b0e234351cda270638151a527bbe272d5de12466d8bb130f293ffd", size = 519494 },
1233
1233
  ]
1234
1234
 
1235
1235
  [[package]]
File without changes
File without changes
File without changes
File without changes
File without changes