hyperquant 0.87__py3-none-any.whl → 0.89__py3-none-any.whl

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.

Potentially problematic release.


This version of hyperquant might be problematic. Click here for more details.

@@ -60,11 +60,10 @@ class Coinw:
60
60
  "all",
61
61
  ] = "all",
62
62
  *,
63
- instrument: str | None = None,
64
63
  position_type: Literal["execute", "plan", "planTrigger"] = "execute",
65
64
  page: int | None = None,
66
65
  page_size: int | None = None,
67
- open_ids: str | None = None,
66
+ instrument: str | None = None,
68
67
  ) -> None:
69
68
  """刷新本地缓存,使用 CoinW REST API。
70
69
 
@@ -108,16 +107,8 @@ class Coinw:
108
107
  )
109
108
 
110
109
  if include_position:
111
- if not instrument:
112
- raise ValueError("instrument is required when updating positions")
113
- params = {"instrument": instrument}
114
- if open_ids:
115
- params["openIds"] = open_ids
116
110
  requests.append(
117
- self.client.get(
118
- f"{self.rest_api}/v1/perpum/positions",
119
- params=params,
120
- )
111
+ self.client.get(f"{self.rest_api}/v1/perpum/positions/all")
121
112
  )
122
113
 
123
114
  if include_balance:
@@ -186,6 +177,51 @@ class Coinw:
186
177
  data = await res.json()
187
178
  return self._ensure_ok("place_order", data)
188
179
 
180
+ async def close_position(
181
+ self,
182
+ open_id: str | int,
183
+ *,
184
+ position_type: Literal["plan", "planTrigger", "execute"] = "plan",
185
+ close_num: str | float | int | None = None,
186
+ close_rate: str | float | int | None = None,
187
+ order_price: str | float | None = None,
188
+ instrument: str | None = None,
189
+ ) -> dict[str, Any]:
190
+ """关闭单个仓位(``DELETE /v1/perpum/positions``)。
191
+
192
+ Params
193
+ ------
194
+ open_id: ``openId`` / 持仓唯一 ID。
195
+ position_type: 订单类型 ``plan`` / ``planTrigger`` / ``execute``。
196
+ close_num: 按合约数量平仓(与 ``close_rate`` 至少指定其一)。
197
+ close_rate: 按比例平仓(0-1)。
198
+ order_price: 限价平仓时指定价格。
199
+ instrument: 交易品种(部分情况下需要传入,例如限价单)。
200
+ """
201
+
202
+ if close_num is None and close_rate is None:
203
+ raise ValueError("close_num or close_rate must be provided")
204
+
205
+ payload: dict[str, Any] = {
206
+ "id": str(open_id),
207
+ "positionType": position_type,
208
+ }
209
+ if close_num is not None:
210
+ payload["closeNum"] = str(close_num)
211
+ if close_rate is not None:
212
+ payload["closeRate"] = str(close_rate)
213
+ if order_price is not None:
214
+ payload["orderPrice"] = str(order_price)
215
+ if instrument is not None:
216
+ payload["instrument"] = instrument
217
+
218
+ res = await self.client.delete(
219
+ f"{self.rest_api}/v1/perpum/positions",
220
+ data=payload,
221
+ )
222
+ data = await res.json()
223
+ return self._ensure_ok("close_position", data)
224
+
189
225
  async def place_order_web(
190
226
  self,
191
227
  instrument: str,
@@ -292,7 +328,7 @@ class Coinw:
292
328
  ws_app = await self._ensure_private_ws()
293
329
  payloads = [
294
330
  {"event": "sub", "params": {"biz": "futures", "type": "order"}},
295
- {"event": "sub", "params": {"biz": "futures", "type": "position"}},
331
+ # {"event": "sub", "params": {"biz": "futures", "type": "position"}},
296
332
  {"event": "sub", "params": {"biz": "futures", "type": "position_change"}},
297
333
  {"event": "sub", "params": {"biz": "futures", "type": "assets"}},
298
334
  ]
@@ -280,16 +280,8 @@ class Orders(DataStore):
280
280
  class Position(DataStore):
281
281
  """CoinW 当前持仓数据存储。"""
282
282
 
283
- _KEYS = ["id"]
283
+ _KEYS = ["openId"]
284
284
 
285
- @staticmethod
286
- def _normalize(entry: dict[str, Any]) -> dict[str, Any] | None:
287
- position_id = entry.get("id")
288
- if position_id is None:
289
- return None
290
- normalized = dict(entry)
291
- normalized["id"] = str(position_id)
292
- return normalized
293
285
 
294
286
  def _onresponse(self, data: Any) -> None:
295
287
  payload = []
@@ -302,9 +294,8 @@ class Position(DataStore):
302
294
  for entry in payload or []:
303
295
  if not isinstance(entry, dict):
304
296
  continue
305
- normalized = self._normalize(entry)
306
- if normalized:
307
- items.append(normalized)
297
+ entry['openId'] = str(entry.get("id"))
298
+ items.append(entry)
308
299
 
309
300
  self._clear()
310
301
  if items:
@@ -312,6 +303,7 @@ class Position(DataStore):
312
303
 
313
304
  def _on_message(self, msg: dict[str, Any]) -> None:
314
305
  data = msg.get("data")
306
+
315
307
  if isinstance(data, dict) and data.get("result") is not None:
316
308
  return
317
309
 
@@ -325,26 +317,28 @@ class Position(DataStore):
325
317
  return
326
318
 
327
319
  to_insert: list[dict[str, Any]] = []
320
+ to_update: list[dict[str, Any]] = []
328
321
  to_delete: list[dict[str, Any]] = []
329
322
 
330
323
  for entry in entries:
331
324
  if not isinstance(entry, dict):
332
325
  continue
333
- normalized = self._normalize(entry)
334
- if not normalized:
335
- continue
326
+ normalized = entry
336
327
 
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"}
340
328
 
341
- query = {"id": normalized["id"]}
342
- to_delete.append(query)
343
- if not remove:
329
+ if normalized.get("status") == 'close':
330
+ to_delete.append(normalized)
331
+ continue
332
+
333
+ if self.find(normalized):
334
+ to_update.append(normalized)
335
+ else:
344
336
  to_insert.append(normalized)
345
337
 
346
338
  if to_delete:
347
339
  self._delete(to_delete)
340
+ if to_update:
341
+ self._update(to_update)
348
342
  if to_insert:
349
343
  self._insert(to_insert)
350
344
 
@@ -449,11 +443,12 @@ class CoinwFuturesDataStore(DataStoreCollection):
449
443
 
450
444
  def onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
451
445
  msg_type = msg.get("type")
446
+ # print(msg)
452
447
  if msg_type == "depth":
453
448
  self.book._on_message(msg)
454
449
  elif msg_type == "order":
455
450
  self.orders._on_message(msg)
456
- elif msg_type == "position":
451
+ elif msg_type == "position" or msg_type == "position_change":
457
452
  self.position._on_message(msg)
458
453
  elif msg_type == "assets":
459
454
  self.balance._on_message(msg)
@@ -470,7 +465,7 @@ class CoinwFuturesDataStore(DataStoreCollection):
470
465
  self.ticker._onresponse(data)
471
466
  elif res.url.path == "/v1/perpum/orders/open":
472
467
  self.orders._onresponse(data)
473
- elif res.url.path == "/v1/perpum/positions":
468
+ elif res.url.path == "/v1/perpum/positions/all":
474
469
  self.position._onresponse(data)
475
470
  elif res.url.path == "/v1/perpum/account/getUserAssets":
476
471
  self.balance._onresponse(data)
@@ -655,17 +650,48 @@ class CoinwFuturesDataStore(DataStoreCollection):
655
650
  - REST: ``GET /v1/perpum/positions``
656
651
  - WebSocket: ``type == "position"``
657
652
 
658
- 数据结构(节选)::
653
+ .. code:: json
659
654
 
660
655
  {
661
- "id": 2435521222631982507,
662
- "instrument": "BTC",
663
- "direction": "short",
664
- "openPrice": 88230.5,
665
- "currentPiece": 1,
666
- "profitUnreal": 0.0086,
667
- "status": "open"
668
- }
656
+ "currentPiece": "0",
657
+ "isProfession": 0,
658
+ "leverage": "10",
659
+ "originalType": "execute",
660
+ "orderId": "33309059291614824",
661
+ "contractType": 1,
662
+ "openId": "2435521222638707873",
663
+ "fee": "0.00020724",
664
+ "openPrice": "0.3456",
665
+ "orderStatus": "finish",
666
+ "instrument": "JUP",
667
+ "quantityUnit": 1,
668
+ "source": "api",
669
+ "updatedDate": 1761192795412,
670
+ "positionModel": 1,
671
+ "feeRate": "0.0006",
672
+ "netProfit": "-0.00040724",
673
+ "baseSize": "1",
674
+ "quote": "usdt",
675
+ "liquidateBy": "manual",
676
+ "totalPiece": "1",
677
+ "orderPrice": "0",
678
+ "id": "23469279597150213",
679
+ "fundingSettle": "0",
680
+ "direction": "long",
681
+ "margin": "0.03435264",
682
+ "takerMaker": 1,
683
+ "indexPrice": "0.3455",
684
+ "quantity": "0.03456",
685
+ "userId": "1757458",
686
+ "closedPiece": "1",
687
+ "createdDate": 1761192793000,
688
+ "hedgeId": "23469279597150214",
689
+ "closePrice": "0.3454",
690
+ "positionMargin": "0.03435264",
691
+ "base": "jup",
692
+ "realPrice": "0.3454",
693
+ "status": "close"
694
+ }
669
695
  """
670
696
 
671
697
  return self._get("position", Position)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.87
3
+ Version: 0.89
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
@@ -6,7 +6,7 @@ hyperquant/logkit.py,sha256=nUo7nx5eONvK39GOhWwS41zNRL756P2J7-5xGzwXnTY,8462
6
6
  hyperquant/notikit.py,sha256=x5yAZ_tAvLQRXcRbcg-VabCaN45LUhvlTZnUqkIqfAA,3596
7
7
  hyperquant/broker/auth.py,sha256=xNZEQP0LRRV9BkT2uXBJ-vFfeahUnRVq1bjIT6YbQu8,10089
8
8
  hyperquant/broker/bitget.py,sha256=X_S0LKZ7FZAEb6oEMr1vdGP1fondzK74BhmNTpRDSEA,9488
9
- hyperquant/broker/coinw.py,sha256=lRbxthAmIncTDcYm0VxZ-753HAj5_d5slwX-8EOHXyY,15854
9
+ hyperquant/broker/coinw.py,sha256=SnJU0vASh77rfcpMGWaIfTblQSjQk3vjlW_4juYdbcs,17214
10
10
  hyperquant/broker/edgex.py,sha256=TqUO2KRPLN_UaxvtLL6HnA9dAQXC1sGxOfqTHd6W5k8,18378
11
11
  hyperquant/broker/hyperliquid.py,sha256=7MxbI9OyIBcImDelPJu-8Nd53WXjxPB5TwE6gsjHbto,23252
12
12
  hyperquant/broker/lbank.py,sha256=98M5wmSoeHwbBYMA3rh25zqLb6fQKVaEmwqALF5nOvY,22181
@@ -17,7 +17,7 @@ hyperquant/broker/lib/hpstore.py,sha256=LnLK2zmnwVvhEbLzYI-jz_SfYpO1Dv2u2cJaRAb8
17
17
  hyperquant/broker/lib/hyper_types.py,sha256=HqjjzjUekldjEeVn6hxiWA8nevAViC2xHADOzDz9qyw,991
18
18
  hyperquant/broker/lib/util.py,sha256=iMU1qF0CHj5zzlIMEQGwjz-qtEVosEe7slXOCuB7Rcw,566
19
19
  hyperquant/broker/models/bitget.py,sha256=0RwDY75KrJb-c-oYoMxbqxWfsILe-n_Npojz4UFUq7c,11389
20
- hyperquant/broker/models/coinw.py,sha256=p86bzwBf-9GsRPMrtY7hWXkJphfSm7kN-_FRwEF9ZQ8,21264
20
+ hyperquant/broker/models/coinw.py,sha256=LvLMVP7i-qkkTK1ubw8eBkMK2RQmFoKPxdKqmC4IToY,22157
21
21
  hyperquant/broker/models/edgex.py,sha256=vPAkceal44cjTYKQ_0BoNAskOpmkno_Yo1KxgMLPc6Y,33954
22
22
  hyperquant/broker/models/hyperliquid.py,sha256=c4r5739ibZfnk69RxPjQl902AVuUOwT8RNvKsMtwXBY,9459
23
23
  hyperquant/broker/models/lbank.py,sha256=vHkNKxIMzpoC_EwcZnEOPOupizF92yGWi9GKxvYYFUQ,19181
@@ -26,6 +26,6 @@ hyperquant/datavison/_util.py,sha256=92qk4vO856RqycO0YqEIHJlEg-W9XKapDVqAMxe6rbw
26
26
  hyperquant/datavison/binance.py,sha256=3yNKTqvt_vUQcxzeX4ocMsI5k6Q6gLZrvgXxAEad6Kc,5001
27
27
  hyperquant/datavison/coinglass.py,sha256=PEjdjISP9QUKD_xzXNzhJ9WFDTlkBrRQlVL-5pxD5mo,10482
28
28
  hyperquant/datavison/okx.py,sha256=yg8WrdQ7wgWHNAInIgsWPM47N3Wkfr253169IPAycAY,6898
29
- hyperquant-0.87.dist-info/METADATA,sha256=kKBv8ig72O_aDeRHobCeo3MJOKIxClr5UQwQOOO1x38,4317
30
- hyperquant-0.87.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
- hyperquant-0.87.dist-info/RECORD,,
29
+ hyperquant-0.89.dist-info/METADATA,sha256=NBPtmJcSeB4mhyzR_K0yISNPcMaiyzLqfjGkA_q6dME,4317
30
+ hyperquant-0.89.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ hyperquant-0.89.dist-info/RECORD,,