hyperquant 0.74__tar.gz → 0.75__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 (48) hide show
  1. {hyperquant-0.74 → hyperquant-0.75}/PKG-INFO +1 -1
  2. {hyperquant-0.74 → hyperquant-0.75}/pyproject.toml +1 -1
  3. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lbank.py +26 -4
  4. {hyperquant-0.74 → hyperquant-0.75}/tests/test_lbank.py +55 -105
  5. {hyperquant-0.74 → hyperquant-0.75}/uv.lock +1 -1
  6. {hyperquant-0.74 → hyperquant-0.75}/.gitignore +0 -0
  7. {hyperquant-0.74 → hyperquant-0.75}/.python-version +0 -0
  8. {hyperquant-0.74 → hyperquant-0.75}/README.md +0 -0
  9. {hyperquant-0.74 → hyperquant-0.75}/apis.json +0 -0
  10. {hyperquant-0.74 → hyperquant-0.75}/data/alpine_smoke.log +0 -0
  11. {hyperquant-0.74 → hyperquant-0.75}/data/logs/notikit.log +0 -0
  12. {hyperquant-0.74 → hyperquant-0.75}/data/logs/test_order_sync.log +0 -0
  13. {hyperquant-0.74 → hyperquant-0.75}/data/records_swap.csv +0 -0
  14. {hyperquant-0.74 → hyperquant-0.75}/data/records_swapc.csv +0 -0
  15. {hyperquant-0.74 → hyperquant-0.75}/doc/lbank.md +0 -0
  16. {hyperquant-0.74 → hyperquant-0.75}/pub.sh +0 -0
  17. {hyperquant-0.74 → hyperquant-0.75}/requirements-dev.lock +0 -0
  18. {hyperquant-0.74 → hyperquant-0.75}/requirements.lock +0 -0
  19. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/__init__.py +0 -0
  20. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/auth.py +0 -0
  21. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/bitget.py +0 -0
  22. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/edgex.py +0 -0
  23. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/hyperliquid.py +0 -0
  24. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
  25. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/hpstore.py +0 -0
  26. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  27. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/util.py +0 -0
  28. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/bitget.py +0 -0
  29. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/edgex.py +0 -0
  30. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  31. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/lbank.py +0 -0
  32. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/ourbit.py +0 -0
  33. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/ourbit.py +0 -0
  34. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/ws.py +0 -0
  35. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/core.py +0 -0
  36. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/_util.py +0 -0
  37. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/binance.py +0 -0
  38. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/coinglass.py +0 -0
  39. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/okx.py +0 -0
  40. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/db.py +0 -0
  41. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/draw.py +0 -0
  42. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/logkit.py +0 -0
  43. {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/notikit.py +0 -0
  44. {hyperquant-0.74 → hyperquant-0.75}/tests/test_bitget.py +0 -0
  45. {hyperquant-0.74 → hyperquant-0.75}/tests/test_draw.py +0 -0
  46. {hyperquant-0.74 → hyperquant-0.75}/tests/test_edgex.py +0 -0
  47. {hyperquant-0.74 → hyperquant-0.75}/tests/test_ourbit.py +0 -0
  48. {hyperquant-0.74 → hyperquant-0.75}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.74
3
+ Version: 0.75
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.74"
3
+ version = "0.75"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -223,7 +223,31 @@ class Lbank:
223
223
  page_index: int = 1,
224
224
  page_size: int = 20,
225
225
  ) -> dict[str, Any]:
226
- """Aggregate trade executions to summarize overall order statistics."""
226
+ """
227
+ 返回值示例:
228
+
229
+ .. code:: json
230
+
231
+ {
232
+ "order_id": "1000632478428573",
233
+ "instrument_id": "SOLUSDT",
234
+ "position_id": "1000632478428573",
235
+ "direction": "0",
236
+ "offset_flag": "0",
237
+ "trade_time": 1760123456,
238
+ "avg_price": 182.5,
239
+ "volume": 0.03,
240
+ "turnover": 5.475,
241
+ "fee": 0.003285,
242
+ "trade_count": 1
243
+ }
244
+
245
+ 如果没有订单成交返回
246
+ {
247
+ "order_id": "1000632478428573",
248
+ "trade_count": 0
249
+ }
250
+ """
227
251
 
228
252
  if not order_id:
229
253
  raise ValueError("order_id is required to query order statistics")
@@ -440,9 +464,7 @@ class Lbank:
440
464
  # logger.warning("Price is ignored for market orders")
441
465
  pass
442
466
 
443
- # if client_order_id:
444
- # payload["LocalID"] = client_order_id
445
- print(payload)
467
+
446
468
  res = await self.client.post(
447
469
  f"{self.front_api}/cfd/cff/v1/SendOrderInsert",
448
470
  json=payload,
@@ -148,44 +148,17 @@ async def order_sync_polling(
148
148
  volume: float | None = None,
149
149
  window_sec: float = 5.0,
150
150
  grace_sec: float = 5.0,
151
- poll_interval: float = 0.5,
152
- ) -> Union[dict, None]:
151
+ poll_interval: float = 0.5
152
+ ) :
153
+
153
154
  """
154
- 由于 LBank 暂无订单推送,这里通过 REST ``orders`` 与 ``position`` 查询实现订单同步,可在不同状态下返回仓位快照。
155
-
156
- - window_sec: 主轮询窗口,订单若持续存在则触发撤单流程;
157
- - grace_sec: 撤单后的额外等待窗口;
158
- - 返回值示例:
159
- .. code:: json
160
-
161
- {
162
- "position_id": "1000633222380983",
163
- "bus_id": "1001770970175249",
164
- "symbol": "SOLUSDT",
165
- "side": "long",
166
- "quantity": "0.06",
167
- "available": "0.0",
168
- "avg_price": "183.62",
169
- "entry_price": "183.62",
170
- "leverage": "100.0",
171
- "liquidation_price": "0",
172
- "margin_used": "0.110175",
173
- "unrealized_pnl": "0.0",
174
- "realized_pnl": "0.0",
175
- "update_time": "1760195121",
176
- "insert_time": "1758806193"
177
- }
155
+ 返回
156
+ {'order_id': '1000633291976722', 'instrument_id': 'SOLUSDT', 'position_id': '1000633291830781', 'direction': '1', 'offset_flag': '0', 'trade_time': 1760203736, 'avg_price': 183.95000000000002, 'volume': 0.03, 'turnover': 5.5185, 'fee': 0.0033111, 'trade_count': 1}
157
+ 或者
158
+ {'order_id': '1000633291976722', 'trade_count': 0}
178
159
  """
179
160
 
180
161
  norm_type = order_type.lower()
181
- if norm_type not in {"market", "limit_gtc", "limit_ioc"}:
182
- raise ValueError(f"unsupported order_type: {order_type}")
183
-
184
- if norm_type != "market" and price is None:
185
- raise ValueError("price is required for limit orders")
186
- if volume is None:
187
- raise ValueError("volume is required for LBank orders")
188
-
189
162
  started = int(time.time() * 1000)
190
163
  resp = await broker.place_order(
191
164
  symbol,
@@ -196,90 +169,66 @@ async def order_sync_polling(
196
169
  )
197
170
 
198
171
  latency = int(time.time() * 1000) - started
199
- print(f"下单延迟 {latency} ms")
200
172
 
201
- order_id = (
202
- resp.get("orderSysID")
203
- or resp.get("OrderSysID")
204
- or resp.get("order_id")
205
- or resp.get("orderId")
206
- )
173
+ order_id = resp.get("orderSysID")
174
+ # print(f"下单延迟 {latency} ms, 订单号: {order_id}")
175
+
207
176
  if not order_id:
208
177
  raise RuntimeError(f"place_order 返回缺少 order_id: {resp}")
209
178
 
210
- position_id = (
211
- resp.get("PositionID")
212
- or resp.get("positionID")
213
- or resp.get("positionId")
214
- )
215
179
 
216
- async def _refresh_position(*, allow_symbol_fallback: bool) -> dict | None:
217
- try:
218
- await broker.update("position")
219
- except ContentTypeError:
220
- await asyncio.sleep(poll_interval)
221
- return None
222
- if position_id:
223
- pos = broker.store.position.get({"position_id": position_id})
224
- if pos and pos.get("avg_price") is not None:
225
- return pos
226
- if allow_symbol_fallback:
227
- candidates = broker.store.position.find({"symbol": symbol}) or []
228
- if candidates:
229
- pos = candidates[0]
230
- if pos and pos.get("avg_price") is not None:
231
- return pos
232
- return None
233
-
234
- async def _poll_orders(timeout_sec: float, *, allow_symbol_fallback: bool) -> dict | None:
235
- nonlocal position_id
236
- order_seen = False
180
+ position_id = resp.get("positionID")
181
+ if not position_id:
182
+ raise RuntimeError(f"place_order 返回缺少 position_id: {resp}")
183
+
184
+ if 'volumeRemain' in resp and float(resp['volumeRemain']) == 0:
185
+ return {
186
+ "order_id": order_id,
187
+ "trade_count": 1,
188
+ "volume": volume,
189
+ "avg_price": float(resp.get('openPrice', 0)),
190
+ "turnover": float(resp.get('turnover', 0)),
191
+ "fee": float(resp.get('fee', 0)),
192
+ "position_id": position_id,
193
+ "direction": direction,
194
+ "offset_flag": resp.get('offsetFlag', '0'),
195
+ "trade_time": resp.get('updateTime'),
196
+ }
197
+
198
+ trade_resp = None
199
+
200
+ async def _poll_orders(timeout_sec: float) -> dict | None:
201
+ nonlocal trade_resp
237
202
  async with asyncio.timeout(timeout_sec):
238
203
  while True:
239
- try:
240
- await broker.update("orders")
241
- except ContentTypeError:
242
- await asyncio.sleep(poll_interval)
243
- continue
244
- snapshot = broker.store.orders.get({"order_id": order_id})
245
- if snapshot is None:
246
- if not order_seen and not allow_symbol_fallback:
247
- await asyncio.sleep(poll_interval)
248
- continue
249
- pos_snapshot = await _refresh_position(allow_symbol_fallback=allow_symbol_fallback)
250
- if pos_snapshot is not None:
251
- return pos_snapshot
252
- await asyncio.sleep(poll_interval)
253
- continue
254
- order_seen = True
255
- position_id = position_id or snapshot.get("position_id")
204
+ trade_resp = await broker.query_order(order_id)
205
+ traded_volume = float(trade_resp.get("volume", 0))
206
+ if traded_volume == volume:
207
+ return
256
208
  await asyncio.sleep(poll_interval)
257
209
 
258
210
  try:
259
- polled_position = await _poll_orders(window_sec, allow_symbol_fallback=False)
260
- if polled_position:
261
- return polled_position
211
+ await _poll_orders(window_sec)
212
+
262
213
  except TimeoutError:
263
214
  pass
264
215
 
265
- for _attempt in range(3):
266
- try:
267
- await broker.cancel_order(order_id)
268
- break
269
- except Exception as e:
270
- if '不存在' in str(e):
216
+ for _attempt in range(3):
217
+ try:
218
+ await broker.cancel_order(order_id)
271
219
  break
272
- else:
273
- print(f'撤单失败, 重试 {_attempt+1}/3: {e}')
274
- try:
275
- polled_position = await _poll_orders(grace_sec, allow_symbol_fallback=True)
276
- if polled_position:
277
- return polled_position
278
- except TimeoutError:
279
- pass
220
+ except Exception as e:
221
+ if '不存在' in str(e):
222
+ break
223
+ else:
224
+ print(f'撤单失败, 重试 {_attempt+1}/3: {e}')
225
+
226
+ try:
227
+ await _poll_orders(window_sec)
228
+ except TimeoutError:
229
+ pass
280
230
 
281
- # 超过宽限期仍没有仓位变更,尝试最后一次使用 symbol 兜底
282
- return await _refresh_position(allow_symbol_fallback=True)
231
+ return trade_resp
283
232
 
284
233
 
285
234
  async def test_order_sync_polling():
@@ -288,7 +237,8 @@ async def test_order_sync_polling():
288
237
  await lb.sub_orderbook(["SOLUSDT"], limit=1)
289
238
  await lb.store.book.wait()
290
239
  bid0 = float(lb.store.book.find({"s": "SOLUSDT", 'S': 'b'})[0]['p'])
291
- bid0 = bid0 - 0.03
240
+ bid0 = bid0 - 0.01
241
+ # bid0 = bid0 - 1
292
242
  print(bid0)
293
243
 
294
244
  result = await order_sync_polling(
@@ -307,7 +257,7 @@ async def test_order_sync_polling():
307
257
  async def test_query_order():
308
258
  async with pybotters.Client(apis='./apis.json') as client:
309
259
  async with Lbank(client) as lb:
310
- res = await lb.query_order("1000633129818889")
260
+ res = await lb.query_order("1000633284579483")
311
261
  print(res)
312
262
 
313
263
  if __name__ == "__main__":
@@ -530,7 +530,7 @@ wheels = [
530
530
 
531
531
  [[package]]
532
532
  name = "hyperquant"
533
- version = "0.73"
533
+ version = "0.74"
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
File without changes
File without changes
File without changes
File without changes
File without changes