hyperquant 0.85__tar.gz → 0.87__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.
- {hyperquant-0.85 → hyperquant-0.87}/PKG-INFO +1 -1
- {hyperquant-0.85 → hyperquant-0.87}/pyproject.toml +1 -1
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/coinw.py +46 -6
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/coinw.py +7 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/ws.py +1 -1
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_coinw.py +22 -7
- {hyperquant-0.85 → hyperquant-0.87}/uv.lock +1 -1
- {hyperquant-0.85 → hyperquant-0.87}/.gitignore +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/.python-version +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/README.md +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/apis.json +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/data/alpine_smoke.log +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/data/logs/notikit.log +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/data/logs/test_order_sync.log +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/data/records_swap.csv +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/data/records_swapc.csv +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/doc/lbank.md +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/pub.sh +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/requirements-dev.lock +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/requirements.lock +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/__init__.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/bitget.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/lbank.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/lib/util.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/bitget.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/core.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/db.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/draw.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/logkit.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/src/hyperquant/notikit.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_bitget.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_draw.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_edgex.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_lbank.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/test_ourbit.py +0 -0
- {hyperquant-0.85 → hyperquant-0.87}/tests/tmp.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: hyperquant
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.87
|
|
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
|
|
@@ -2,6 +2,7 @@ from __future__ import annotations
|
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
4
|
import logging
|
|
5
|
+
import time
|
|
5
6
|
from typing import Any, Literal, Sequence
|
|
6
7
|
|
|
7
8
|
import pybotters
|
|
@@ -307,6 +308,7 @@ class Coinw:
|
|
|
307
308
|
*,
|
|
308
309
|
depth_limit: int | None = 1,
|
|
309
310
|
biz: str = "futures",
|
|
311
|
+
stale_timeout: float = 5,
|
|
310
312
|
) -> pybotters.ws.WebSocketApp:
|
|
311
313
|
"""订阅 ``type=depth`` 订单簿数据,批量控制发送频率。"""
|
|
312
314
|
|
|
@@ -332,12 +334,50 @@ class Coinw:
|
|
|
332
334
|
await ws_app._event.wait()
|
|
333
335
|
|
|
334
336
|
chunk_size = 10
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
for
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
337
|
+
|
|
338
|
+
async def send_subs(target: pybotters.ws.WebSocketApp) -> None:
|
|
339
|
+
for idx in range(0, len(subscriptions), chunk_size):
|
|
340
|
+
batch = subscriptions[idx : idx + chunk_size]
|
|
341
|
+
for msg in batch:
|
|
342
|
+
await target.current_ws.send_json(msg)
|
|
343
|
+
if idx + chunk_size < len(subscriptions):
|
|
344
|
+
await asyncio.sleep(2.05)
|
|
345
|
+
|
|
346
|
+
await send_subs(ws_app)
|
|
347
|
+
|
|
348
|
+
ws_ref: dict[str, pybotters.ws.WebSocketApp] = {"app": ws_app}
|
|
349
|
+
|
|
350
|
+
async def monitor() -> None:
|
|
351
|
+
poll_interval = 1.0
|
|
352
|
+
while True:
|
|
353
|
+
await asyncio.sleep(poll_interval)
|
|
354
|
+
last_update = self.store.book.last_update
|
|
355
|
+
if not last_update:
|
|
356
|
+
continue
|
|
357
|
+
if time.time() - last_update < stale_timeout:
|
|
358
|
+
continue
|
|
359
|
+
|
|
360
|
+
logger.warning(f"CoinW订单簿超过{stale_timeout:.1f}秒未更新,正在重连。")
|
|
361
|
+
try:
|
|
362
|
+
current = ws_ref["app"]
|
|
363
|
+
if current.current_ws and not current.current_ws.closed:
|
|
364
|
+
await current.current_ws.close()
|
|
365
|
+
except Exception:
|
|
366
|
+
logger.exception("Error closing stale CoinW orderbook websocket")
|
|
367
|
+
|
|
368
|
+
try:
|
|
369
|
+
new_ws = self.client.ws_connect(
|
|
370
|
+
self.ws_url_public,
|
|
371
|
+
hdlr_json=self.store.onmessage,
|
|
372
|
+
headers=self._ws_headers,
|
|
373
|
+
)
|
|
374
|
+
await new_ws._event.wait()
|
|
375
|
+
await send_subs(new_ws)
|
|
376
|
+
ws_ref["app"] = new_ws
|
|
377
|
+
except Exception:
|
|
378
|
+
logger.exception("Failed to reconnect CoinW orderbook websocket")
|
|
379
|
+
|
|
380
|
+
asyncio.create_task(monitor())
|
|
341
381
|
|
|
342
382
|
return ws_app
|
|
343
383
|
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
from __future__ import annotations
|
|
2
2
|
|
|
3
3
|
import asyncio
|
|
4
|
+
import time
|
|
4
5
|
from typing import TYPE_CHECKING, Any, Awaitable
|
|
5
6
|
|
|
6
7
|
import aiohttp
|
|
@@ -35,6 +36,7 @@ class Book(DataStore):
|
|
|
35
36
|
|
|
36
37
|
def _init(self) -> None:
|
|
37
38
|
self.limit: int | None = None
|
|
39
|
+
self._last_update: float = 0.0
|
|
38
40
|
|
|
39
41
|
def _on_message(self, msg: dict[str, Any]) -> None:
|
|
40
42
|
data = msg.get("data")
|
|
@@ -80,6 +82,7 @@ class Book(DataStore):
|
|
|
80
82
|
|
|
81
83
|
self._find_and_delete({"s": str(symbol)})
|
|
82
84
|
self._insert(entries)
|
|
85
|
+
self._last_update = time.time()
|
|
83
86
|
|
|
84
87
|
def sorted(
|
|
85
88
|
self, query: Item | None = None, limit: int | None = None
|
|
@@ -93,6 +96,10 @@ class Book(DataStore):
|
|
|
93
96
|
limit=limit,
|
|
94
97
|
)
|
|
95
98
|
|
|
99
|
+
@property
|
|
100
|
+
def last_update(self) -> float:
|
|
101
|
+
return self._last_update
|
|
102
|
+
|
|
96
103
|
|
|
97
104
|
class Detail(DataStore):
|
|
98
105
|
"""CoinW 合约信息数据存储。
|
|
@@ -36,7 +36,7 @@ class Heartbeat:
|
|
|
36
36
|
async def coinw(ws: ClientWebSocketResponse):
|
|
37
37
|
while not ws.closed:
|
|
38
38
|
await ws.send_json({"event": "ping"})
|
|
39
|
-
await asyncio.sleep(
|
|
39
|
+
await asyncio.sleep(3.0)
|
|
40
40
|
|
|
41
41
|
pybotters.ws.HeartbeatHosts.items['futures.ourbit.com'] = Heartbeat.ourbit
|
|
42
42
|
pybotters.ws.HeartbeatHosts.items['www.ourbit.com'] = Heartbeat.ourbit_spot
|
|
@@ -37,15 +37,30 @@ async def test_sub_orderbook(
|
|
|
37
37
|
interval: float = 1.0,
|
|
38
38
|
) -> None:
|
|
39
39
|
"""Subscribe CoinW order book and print snapshots."""
|
|
40
|
+
start = time.time()
|
|
41
|
+
print(f"订阅开始: {start:.3f}")
|
|
42
|
+
|
|
43
|
+
symbols = ['NMR_USDT', 'TRB_USDT', 'MELANIA_USDT', 'INJ_USDT', 'LTC_USDT', 'AUCTION_USDT']
|
|
44
|
+
|
|
45
|
+
# 去掉USDT
|
|
46
|
+
symbols = [s[:-5] if s.endswith('_USDT') else s for s in symbols]
|
|
47
|
+
|
|
40
48
|
async with pybotters.Client() as client:
|
|
41
49
|
async with Coinw(client) as cw:
|
|
42
50
|
await cw.sub_orderbook(symbols, depth_limit=depth)
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
51
|
+
with cw.store.book.watch() as watcher:
|
|
52
|
+
while True:
|
|
53
|
+
try:
|
|
54
|
+
change = await asyncio.wait_for(watcher.__anext__(), timeout=15.0)
|
|
55
|
+
except asyncio.TimeoutError:
|
|
56
|
+
print("超过15秒未收到新数据,退出订阅。")
|
|
57
|
+
break
|
|
58
|
+
else:
|
|
59
|
+
print(change.data)
|
|
60
|
+
|
|
61
|
+
end = time.time()
|
|
62
|
+
print(f"订阅结束: {end:.3f}, 耗时: {(end - start):.3f} 秒")
|
|
63
|
+
|
|
49
64
|
|
|
50
65
|
async def test_place_cancel() -> None:
|
|
51
66
|
"""Demonstrate place/cancel flow (requires credentials and tradable environment)."""
|
|
@@ -209,4 +224,4 @@ async def test_order_sync_polling() -> None:
|
|
|
209
224
|
|
|
210
225
|
|
|
211
226
|
if __name__ == "__main__":
|
|
212
|
-
asyncio.run(
|
|
227
|
+
asyncio.run(test_sub_orderbook())
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|