hyperquant 0.86__tar.gz → 0.88__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 (51) hide show
  1. {hyperquant-0.86 → hyperquant-0.88}/PKG-INFO +1 -1
  2. {hyperquant-0.86 → hyperquant-0.88}/pyproject.toml +1 -1
  3. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/coinw.py +5 -5
  4. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/coinw.py +22 -11
  5. {hyperquant-0.86 → hyperquant-0.88}/tests/test_coinw.py +33 -22
  6. {hyperquant-0.86 → hyperquant-0.88}/uv.lock +1 -1
  7. {hyperquant-0.86 → hyperquant-0.88}/.gitignore +0 -0
  8. {hyperquant-0.86 → hyperquant-0.88}/.python-version +0 -0
  9. {hyperquant-0.86 → hyperquant-0.88}/README.md +0 -0
  10. {hyperquant-0.86 → hyperquant-0.88}/apis.json +0 -0
  11. {hyperquant-0.86 → hyperquant-0.88}/data/alpine_smoke.log +0 -0
  12. {hyperquant-0.86 → hyperquant-0.88}/data/logs/notikit.log +0 -0
  13. {hyperquant-0.86 → hyperquant-0.88}/data/logs/test_order_sync.log +0 -0
  14. {hyperquant-0.86 → hyperquant-0.88}/data/records_swap.csv +0 -0
  15. {hyperquant-0.86 → hyperquant-0.88}/data/records_swapc.csv +0 -0
  16. {hyperquant-0.86 → hyperquant-0.88}/doc/lbank.md +0 -0
  17. {hyperquant-0.86 → hyperquant-0.88}/pub.sh +0 -0
  18. {hyperquant-0.86 → hyperquant-0.88}/requirements-dev.lock +0 -0
  19. {hyperquant-0.86 → hyperquant-0.88}/requirements.lock +0 -0
  20. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/__init__.py +0 -0
  21. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/auth.py +0 -0
  22. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/bitget.py +0 -0
  23. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/edgex.py +0 -0
  24. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/hyperliquid.py +0 -0
  25. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/lbank.py +0 -0
  26. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
  27. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/lib/hpstore.py +0 -0
  28. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  29. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/lib/util.py +0 -0
  30. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/bitget.py +0 -0
  31. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/edgex.py +0 -0
  32. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  33. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/lbank.py +0 -0
  34. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/models/ourbit.py +0 -0
  35. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/ourbit.py +0 -0
  36. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/broker/ws.py +0 -0
  37. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/core.py +0 -0
  38. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/datavison/_util.py +0 -0
  39. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/datavison/binance.py +0 -0
  40. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/datavison/coinglass.py +0 -0
  41. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/datavison/okx.py +0 -0
  42. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/db.py +0 -0
  43. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/draw.py +0 -0
  44. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/logkit.py +0 -0
  45. {hyperquant-0.86 → hyperquant-0.88}/src/hyperquant/notikit.py +0 -0
  46. {hyperquant-0.86 → hyperquant-0.88}/tests/test_bitget.py +0 -0
  47. {hyperquant-0.86 → hyperquant-0.88}/tests/test_draw.py +0 -0
  48. {hyperquant-0.86 → hyperquant-0.88}/tests/test_edgex.py +0 -0
  49. {hyperquant-0.86 → hyperquant-0.88}/tests/test_lbank.py +0 -0
  50. {hyperquant-0.86 → hyperquant-0.88}/tests/test_ourbit.py +0 -0
  51. {hyperquant-0.86 → hyperquant-0.88}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.86
3
+ Version: 0.88
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.86"
3
+ version = "0.88"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -292,7 +292,7 @@ class Coinw:
292
292
  ws_app = await self._ensure_private_ws()
293
293
  payloads = [
294
294
  {"event": "sub", "params": {"biz": "futures", "type": "order"}},
295
- {"event": "sub", "params": {"biz": "futures", "type": "position"}},
295
+ # {"event": "sub", "params": {"biz": "futures", "type": "position"}},
296
296
  {"event": "sub", "params": {"biz": "futures", "type": "position_change"}},
297
297
  {"event": "sub", "params": {"biz": "futures", "type": "assets"}},
298
298
  ]
@@ -348,16 +348,16 @@ class Coinw:
348
348
  ws_ref: dict[str, pybotters.ws.WebSocketApp] = {"app": ws_app}
349
349
 
350
350
  async def monitor() -> None:
351
+ poll_interval = 1.0
351
352
  while True:
352
- await asyncio.sleep(stale_timeout)
353
+ await asyncio.sleep(poll_interval)
353
354
  last_update = self.store.book.last_update
354
355
  if not last_update:
355
356
  continue
356
357
  if time.time() - last_update < stale_timeout:
357
358
  continue
358
- logger.warning(
359
- "CoinW order book idle for %.1f seconds, reconnecting.", stale_timeout
360
- )
359
+
360
+ logger.warning(f"CoinW订单簿超过{stale_timeout:.1f}秒未更新,正在重连。")
361
361
  try:
362
362
  current = ws_ref["app"]
363
363
  if current.current_ws and not current.current_ws.closed:
@@ -280,15 +280,21 @@ class Orders(DataStore):
280
280
  class Position(DataStore):
281
281
  """CoinW 当前持仓数据存储。"""
282
282
 
283
- _KEYS = ["id"]
283
+ _KEYS = ["openId"]
284
284
 
285
285
  @staticmethod
286
286
  def _normalize(entry: dict[str, Any]) -> dict[str, Any] | None:
287
- position_id = entry.get("id")
288
- if position_id is None:
287
+ open_id = entry.get("openId")
288
+ if open_id is None:
289
289
  return None
290
290
  normalized = dict(entry)
291
- normalized["id"] = str(position_id)
291
+ normalized["openId"] = str(open_id)
292
+ normalized["status"] = str(entry.get("status") or entry.get("orderStatus") or "").lower()
293
+ normalized["is_closed"] = normalized["status"] in {"close", "closed", "finish"}
294
+ normalized["currentPiece"] = str(entry.get("currentPiece")) if entry.get("currentPiece") is not None else None
295
+ normalized["closedPiece"] = str(entry.get("closedPiece")) if entry.get("closedPiece") is not None else None
296
+ normalized["quantity"] = str(entry.get("quantity")) if entry.get("quantity") is not None else None
297
+ normalized["updatedDate"] = entry.get("updatedDate")
292
298
  return normalized
293
299
 
294
300
  def _onresponse(self, data: Any) -> None:
@@ -325,6 +331,7 @@ class Position(DataStore):
325
331
  return
326
332
 
327
333
  to_insert: list[dict[str, Any]] = []
334
+ to_update: list[dict[str, Any]] = []
328
335
  to_delete: list[dict[str, Any]] = []
329
336
 
330
337
  for entry in entries:
@@ -334,17 +341,21 @@ class Position(DataStore):
334
341
  if not normalized:
335
342
  continue
336
343
 
337
- status = normalized.get("status")
338
- normalized_status = str(status).lower() if status is not None else ""
339
- remove = normalized_status in {"close", "closed", "1", "2"}
344
+ criteria = {"openId": normalized["openId"]}
340
345
 
341
- query = {"id": normalized["id"]}
342
- to_delete.append(query)
343
- if not remove:
346
+ if normalized.get("is_closed"):
347
+ to_delete.append(criteria)
348
+ continue
349
+
350
+ if self.find(criteria):
351
+ to_update.append(normalized)
352
+ else:
344
353
  to_insert.append(normalized)
345
354
 
346
355
  if to_delete:
347
356
  self._delete(to_delete)
357
+ if to_update:
358
+ self._update(to_update)
348
359
  if to_insert:
349
360
  self._insert(to_insert)
350
361
 
@@ -453,7 +464,7 @@ class CoinwFuturesDataStore(DataStoreCollection):
453
464
  self.book._on_message(msg)
454
465
  elif msg_type == "order":
455
466
  self.orders._on_message(msg)
456
- elif msg_type == "position":
467
+ elif msg_type == "position" or msg_type == "position_change":
457
468
  self.position._on_message(msg)
458
469
  elif msg_type == "assets":
459
470
  self.balance._on_message(msg)
@@ -51,9 +51,9 @@ async def test_sub_orderbook(
51
51
  with cw.store.book.watch() as watcher:
52
52
  while True:
53
53
  try:
54
- change = await asyncio.wait_for(watcher.__anext__(), timeout=10.0)
54
+ change = await asyncio.wait_for(watcher.__anext__(), timeout=15.0)
55
55
  except asyncio.TimeoutError:
56
- print("超过10秒未收到新数据,退出订阅。")
56
+ print("超过15秒未收到新数据,退出订阅。")
57
57
  break
58
58
  else:
59
59
  print(change.data)
@@ -67,25 +67,36 @@ async def test_place_cancel() -> None:
67
67
  async with pybotters.Client(apis="./apis.json") as client:
68
68
  async with Coinw(client) as cw:
69
69
  start = time.time()
70
- order = await cw.place_order(
71
- instrument="SOL",
72
- direction="long",
73
- quantity_unit=0,
74
- leverage=25,
75
- quantity=0.8,
70
+ # order = await cw.place_order(
71
+ # instrument="SOL",
72
+ # direction="long",
73
+ # quantity_unit=1,
74
+ # leverage=25,
75
+ # quantity=2,
76
+ # position_type="plan",
77
+ # price=175,
78
+ # position_model="cross",
79
+ # )
80
+ # latency = time.time() - start
81
+ # print(f'下单延迟: {latency*1000:.2f} ms')
82
+ # order_id = order.get("value") or order.get("data")
83
+ # print("place_order response:", order)
84
+ # if order_id:
85
+ # await asyncio.sleep(1)
86
+ # cancel_resp = await cw.cancel_order(order_id)
87
+ # print("cancel_order response:", cancel_resp)
88
+
89
+ # {'instrument': 'JUP', 'direction': 'short', 'leverage': 50, 'quantityUnit': 1, 'quantity': '57', 'positionModel': 1, 'positionType': 'plan', 'openPrice': 0.3527}
90
+ await cw.place_order(
91
+ instrument="JUP",
92
+ direction="short",
93
+ quantity_unit=1,
94
+ leverage=50,
95
+ quantity="57",
76
96
  position_type="plan",
77
- price=175,
78
- position_model="cross",
97
+ price=0.3527,
98
+ position_model=1,
79
99
  )
80
- latency = time.time() - start
81
- print(f'下单延迟: {latency*1000:.2f} ms')
82
- order_id = order.get("value") or order.get("data")
83
- print("place_order response:", order)
84
- if order_id:
85
- await asyncio.sleep(1)
86
- cancel_resp = await cw.cancel_order(order_id)
87
- print("cancel_order response:", cancel_resp)
88
-
89
100
 
90
101
  async def test_place_web() -> None:
91
102
  """Use the web interface to place an order (requires device/token)."""
@@ -196,9 +207,10 @@ async def test_subp() -> None:
196
207
  async with pybotters.Client(apis="./apis.json") as client:
197
208
  async with Coinw(client) as cw:
198
209
  await cw.sub_personal()
199
- with cw.store.orders.watch() as watcher:
210
+ with cw.store.position.watch() as watcher:
200
211
  async for change in watcher:
201
212
  print(change)
213
+ print('\n\n----\n\n')
202
214
 
203
215
 
204
216
  async def test_order_sync_polling() -> None:
@@ -222,6 +234,5 @@ async def test_order_sync_polling() -> None:
222
234
  )
223
235
  print("order_sync_polling result:", result)
224
236
 
225
-
226
237
  if __name__ == "__main__":
227
- asyncio.run(test_sub_orderbook())
238
+ asyncio.run(test_subp())
@@ -662,7 +662,7 @@ wheels = [
662
662
 
663
663
  [[package]]
664
664
  name = "hyperquant"
665
- version = "0.85"
665
+ version = "0.87"
666
666
  source = { editable = "." }
667
667
  dependencies = [
668
668
  { name = "aiohttp" },
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