hyperquant 0.22__tar.gz → 0.23__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.23}/.gitignore +0 -1
  2. {hyperquant-0.22 → hyperquant-0.23}/PKG-INFO +1 -1
  3. {hyperquant-0.22 → hyperquant-0.23}/pyproject.toml +1 -1
  4. hyperquant-0.23/src/hyperquant/broker/lib/hpstore.py +252 -0
  5. hyperquant-0.23/src/hyperquant/broker/lib/hyper_types.py +48 -0
  6. {hyperquant-0.22 → hyperquant-0.23}/uv.lock +1 -1
  7. {hyperquant-0.22 → hyperquant-0.23}/.python-version +0 -0
  8. {hyperquant-0.22 → hyperquant-0.23}/README.md +0 -0
  9. {hyperquant-0.22 → hyperquant-0.23}/pub.sh +0 -0
  10. {hyperquant-0.22 → hyperquant-0.23}/requirements-dev.lock +0 -0
  11. {hyperquant-0.22 → hyperquant-0.23}/requirements.lock +0 -0
  12. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/__init__.py +0 -0
  13. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/broker/hyperliquid.py +0 -0
  14. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/core.py +0 -0
  15. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/datavison/_util.py +0 -0
  16. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/datavison/binance.py +0 -0
  17. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/datavison/coinglass.py +0 -0
  18. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/datavison/okx.py +0 -0
  19. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/db.py +0 -0
  20. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/draw.py +0 -0
  21. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/logkit.py +0 -0
  22. {hyperquant-0.22 → hyperquant-0.23}/src/hyperquant/notikit.py +0 -0
  23. {hyperquant-0.22 → hyperquant-0.23}/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.23
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
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "0.22"
3
+ version = "0.23"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -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.22"
534
534
  source = { editable = "." }
535
535
  dependencies = [
536
536
  { name = "aiohttp" },
File without changes
File without changes
File without changes
File without changes
File without changes