hyperquant 0.42__py3-none-any.whl → 0.44__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.
@@ -592,7 +592,11 @@ class SpotBalance(DataStore):
592
592
  def _on_message(self, msg: dict[str, Any]) -> None:
593
593
  data = msg.get("d", {})
594
594
  item = self._fmt_ws(data)
595
- self._update([item])
595
+ av = float(item.get("available", 0))
596
+ if av == 0:
597
+ self._find_and_delete({'currency': item.get("currency")})
598
+ else:
599
+ self._update([item])
596
600
 
597
601
 
598
602
  # SpotOrders: 现货订单数据存储
@@ -929,8 +933,7 @@ class OurbitSpotDataStore(DataStoreCollection):
929
933
  """
930
934
  现货账户余额数据流
931
935
 
932
- Data structure:
933
-
936
+ _KEYS = ["currency"]
934
937
  .. code:: python
935
938
 
936
939
  [
@@ -427,7 +427,7 @@ class OurbitSpot:
427
427
  self,
428
428
  symbol: str,
429
429
  side: Literal["buy", "sell"],
430
- price: float,
430
+ price: float = None,
431
431
  quantity: float = None,
432
432
  order_type: Literal["market", "limit"] = "limit",
433
433
  usdt_amount: float = None
@@ -437,7 +437,7 @@ class OurbitSpot:
437
437
  Args:
438
438
  symbol: 交易对,如 "SOL_USDT"
439
439
  side: 买卖方向 "buy" 或 "sell"
440
- price: 价格
440
+ price: 价格,市价单可为None
441
441
  quantity: 数量
442
442
  order_type: 订单类型 "market" 或 "limit"
443
443
  usdt_amount: USDT金额,如果指定则根据价格计算数量
@@ -445,74 +445,72 @@ class OurbitSpot:
445
445
  Returns:
446
446
  订单响应数据
447
447
  """
448
+ # 参数检查
449
+ if order_type == "limit" and price is None:
450
+ raise ValueError("Limit orders require a price")
451
+ if quantity is None and usdt_amount is None:
452
+ raise ValueError("Either quantity or usdt_amount must be specified")
453
+
448
454
  # 解析交易对
449
- currency, market = symbol.split("_")
450
-
451
- detail = self.store.detail.get({
452
- 'name': currency
453
- })
454
-
455
+ parts = symbol.split("_")
456
+ if len(parts) != 2:
457
+ raise ValueError(f"Invalid symbol format: {symbol}")
458
+
459
+ currency, market = parts
460
+
461
+ # 获取交易对详情
462
+ detail = self.store.detail.get({"name": currency})
455
463
  if not detail:
456
464
  raise ValueError(f"Unknown currency: {currency}")
457
-
458
- price_scale = detail.get('price_scale')
459
- quantity_scale = detail.get('quantity_scale')
460
-
461
- use_quantity = True if quantity is not None else False
462
-
463
- # 如果指定了USDT金额,重新计算数量
464
- if usdt_amount is not None:
465
- if side == "buy":
466
- quantity = usdt_amount / price
467
- else:
468
- # 卖出时usdt_amount表示要卖出的币种价值
469
- quantity = usdt_amount / price
470
-
471
- # 格式化价格和数量
472
- if price_scale is not None:
473
- price = round(price, price_scale)
474
-
475
- if quantity_scale is not None:
476
- quantity = round(quantity, quantity_scale)
465
+
466
+ price_scale = detail.get("price_scale")
467
+ quantity_scale = detail.get("quantity_scale")
477
468
 
478
469
  # 构建请求数据
479
470
  data = {
480
471
  "currency": currency,
481
472
  "market": market,
482
- "tradeType": side.upper(),
483
- "quantity": str(quantity),
473
+ "tradeType": side.upper()
484
474
  }
485
475
 
476
+ # 处理市价单和限价单的不同参数
486
477
  if order_type == "limit":
487
478
  data["orderType"] = "LIMIT_ORDER"
488
- data["price"] = str(price)
479
+ data["price"] = str(round(price, price_scale) if price_scale is not None else price)
480
+
481
+ # 计算并设置数量
482
+ if quantity is None and usdt_amount is not None and price:
483
+ quantity = usdt_amount / price
484
+
485
+ if quantity_scale is not None:
486
+ quantity = round(quantity, quantity_scale)
487
+ data["quantity"] = str(quantity)
488
+
489
489
  elif order_type == "market":
490
490
  data["orderType"] = "MARKET_ORDER"
491
- data["price"] = price
492
- # 删除quantity, 市价只支持amount
493
- if not use_quantity:
494
- del data["quantity"]
491
+
492
+ # 市价单可以使用数量或金额,但不能同时使用
493
+ if usdt_amount is not None:
495
494
  data["amount"] = str(usdt_amount)
496
-
497
- # print(data)
498
- if order_type == 'market':
499
- url = f'{self.api_url}/api/platform/spot/v4/order/place'
500
- elif order_type == 'limit':
501
- url = f'{self.api_url}/api/platform/spot/order/place'
495
+ else:
496
+ if quantity_scale is not None:
497
+ quantity = round(quantity, quantity_scale)
498
+ data["quantity"] = str(quantity)
499
+
500
+ if price:
501
+ data["price"] = str(price)
502
502
 
503
- res = await self.client.fetch(
504
- "POST",
505
- url,
506
- json=data
507
- )
503
+ # 确定API端点
504
+ url = f'{self.api_url}/api/platform/spot/{"v4/order/place" if order_type == "market" else "order/place"}'
505
+
506
+ # 发送请求
507
+ res = await self.client.fetch("POST", url, json=data)
508
508
 
509
509
  # 处理响应
510
- match res.data:
511
- case {"msg": 'success'}:
512
- return res.data["data"]
513
- case _:
514
- raise Exception(f"Failed to place order: {res.data}")
515
-
510
+ if res.data.get("msg") == "success":
511
+ return res.data["data"]
512
+ raise Exception(f"Failed to place order: {res.data}")
513
+
516
514
  async def cancel_orders(self, order_ids: list[str]):
517
515
 
518
516
  for order_id in order_ids:
hyperquant/core.py CHANGED
@@ -269,10 +269,10 @@ class ExchangeBase:
269
269
  )
270
270
 
271
271
  class Exchange(ExchangeBase):
272
- def __init__(self, trade_symbols, fee=0.0002, initial_balance=10000, recorded=False):
272
+ def __init__(self, trade_symbols:list=[], fee=0.0002, initial_balance=10000, recorded=False):
273
273
  super().__init__(initial_balance=initial_balance, recorded=recorded)
274
274
  self.fee = fee
275
- self.trade_symbols = trade_symbols
275
+ self.trade_symbols:list = trade_symbols
276
276
  self.id_gen = 0
277
277
  self.account['USDT'].update({
278
278
  'hold': 0,
@@ -280,8 +280,12 @@ class Exchange(ExchangeBase):
280
280
  'short': 0
281
281
  })
282
282
  for symbol in trade_symbols:
283
- self.account[symbol] = {'amount': 0, 'hold_price': 0, 'value': 0, 'price': 0,
284
- 'realised_profit': 0, 'unrealised_profit': 0, 'fee': 0}
283
+ self.account[symbol] = self._act_template
284
+
285
+ @property
286
+ def _act_template(self):
287
+ return {'amount': 0, 'hold_price': 0, 'value': 0, 'price': 0,
288
+ 'realised_profit': 0, 'unrealised_profit': 0, 'fee': 0}.copy()
285
289
 
286
290
  def Trade(self, symbol, direction, price, amount, **kwargs):
287
291
  if self.recorded and 'time' not in kwargs:
@@ -307,8 +311,7 @@ class Exchange(ExchangeBase):
307
311
 
308
312
  if symbol not in self.trade_symbols:
309
313
  self.trade_symbols.append(symbol)
310
- self.account[symbol] = {'amount': 0, 'hold_price': 0, 'value': 0, 'price': 0,
311
- 'realised_profit': 0, 'unrealised_profit': 0, 'fee': 0}
314
+ self.account[symbol] = self._act_template
312
315
 
313
316
  cover_amount = 0 if direction * self.account[symbol]['amount'] >= 0 else min(abs(self.account[symbol]['amount']), amount)
314
317
  open_amount = amount - cover_amount
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.42
3
+ Version: 0.44
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,21 +1,21 @@
1
1
  hyperquant/__init__.py,sha256=UpjiX4LS5jmrBc2kE8RiLR02eCfD8JDQrR1q8zkLNcQ,161
2
- hyperquant/core.py,sha256=O0NEvv4CcMxP-2Zy7TKeCsHehoxEh8p9NMsTwuUonFo,20658
2
+ hyperquant/core.py,sha256=iEI8qTNpyesB_w67SrKXeGoB9JllovBeJKI0EZFYew4,20631
3
3
  hyperquant/db.py,sha256=i2TjkCbmH4Uxo7UTDvOYBfy973gLcGexdzuT_YcSeIE,6678
4
4
  hyperquant/draw.py,sha256=up_lQ3pHeVLoNOyh9vPjgNwjD0M-6_IetSGviQUgjhY,54624
5
5
  hyperquant/logkit.py,sha256=WALpXpIA3Ywr5DxKKK3k5EKubZ2h-ISGfc5dUReQUBQ,7795
6
6
  hyperquant/notikit.py,sha256=x5yAZ_tAvLQRXcRbcg-VabCaN45LUhvlTZnUqkIqfAA,3596
7
7
  hyperquant/broker/auth.py,sha256=oA9Yw1I59-u0Tnoj2e4wUup5q8V5T2qpga5RKbiAiZI,2614
8
8
  hyperquant/broker/hyperliquid.py,sha256=7MxbI9OyIBcImDelPJu-8Nd53WXjxPB5TwE6gsjHbto,23252
9
- hyperquant/broker/ourbit.py,sha256=aBRXLmUbiiMp1__xlRufTnqMajeknj_V71iCnB87u84,16641
9
+ hyperquant/broker/ourbit.py,sha256=WTzHcBkp_rP0VglVXmaClxBcdOBmdvl6SYQ2VFePC8c,17001
10
10
  hyperquant/broker/ws.py,sha256=umRzxwCaZaRIgIq4YY-AuA0wCXFT0uOBmQbIXFY8CK0,1555
11
11
  hyperquant/broker/lib/hpstore.py,sha256=LnLK2zmnwVvhEbLzYI-jz_SfYpO1Dv2u2cJaRAb84D8,8296
12
12
  hyperquant/broker/lib/hyper_types.py,sha256=HqjjzjUekldjEeVn6hxiWA8nevAViC2xHADOzDz9qyw,991
13
13
  hyperquant/broker/models/hyperliquid.py,sha256=c4r5739ibZfnk69RxPjQl902AVuUOwT8RNvKsMtwXBY,9459
14
- hyperquant/broker/models/ourbit.py,sha256=8XA_VJUl7BkxvsB_Kx3Hr1xCvXIXCV8AVMZ4AX0dwuc,37569
14
+ hyperquant/broker/models/ourbit.py,sha256=v675rOYlZlEYim4sYlhbmuzl9GEg4n6mleGTNMgJKes,37726
15
15
  hyperquant/datavison/_util.py,sha256=92qk4vO856RqycO0YqEIHJlEg-W9XKapDVqAMxe6rbw,533
16
16
  hyperquant/datavison/binance.py,sha256=3yNKTqvt_vUQcxzeX4ocMsI5k6Q6gLZrvgXxAEad6Kc,5001
17
17
  hyperquant/datavison/coinglass.py,sha256=PEjdjISP9QUKD_xzXNzhJ9WFDTlkBrRQlVL-5pxD5mo,10482
18
18
  hyperquant/datavison/okx.py,sha256=yg8WrdQ7wgWHNAInIgsWPM47N3Wkfr253169IPAycAY,6898
19
- hyperquant-0.42.dist-info/METADATA,sha256=yd_IdWhrCMj_VbMpG53xXe7NBPt-JV1R5SR0hkFA3hI,4317
20
- hyperquant-0.42.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
- hyperquant-0.42.dist-info/RECORD,,
19
+ hyperquant-0.44.dist-info/METADATA,sha256=itx7CR0-SMl5xYTlIooqdeoEvaj9qUFL-LndqMWf_o4,4317
20
+ hyperquant-0.44.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
21
+ hyperquant-0.44.dist-info/RECORD,,