hyperquant 0.5__py3-none-any.whl → 0.7__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.
@@ -22,19 +22,20 @@ class Book(DataStore):
22
22
  Channel: push.depth.step
23
23
 
24
24
  用于存储和管理订单簿深度数据,包含买卖盘的价格和数量信息
25
- Keys: ["symbol", "side", "px"]
26
- - symbol: 交易对符号
27
- - side: 买卖方向 (A: ask卖出, B: bid买入)
28
- - px: 价格
25
+ Keys: ["s", "S", "p"]
26
+ - s: 交易对符号
27
+ - S: 买卖方向 (A: ask卖出, B: bid买入)
28
+ - p: 价格
29
29
 
30
30
 
31
31
  """
32
32
 
33
- _KEYS = ["symbol", "side", "i"]
33
+ _KEYS = ["s", "S", "p"]
34
34
 
35
35
  def _init(self) -> None:
36
36
  # super().__init__()
37
37
  self._time: int | None = None
38
+ self.limit = 1
38
39
 
39
40
  def _on_message(self, msg: dict[str, Any]) -> None:
40
41
 
@@ -43,29 +44,29 @@ class Book(DataStore):
43
44
  asks = data.get("asks", [])
44
45
  bids = data.get("bids", [])
45
46
  # 提速 默认 5当前
46
- asks = asks[:5]
47
- bids = bids[:5]
47
+ asks = asks[:self.limit]
48
+ bids = bids[:self.limit]
48
49
 
49
50
  timestamp = data.get("ct") # 使用服务器时间
50
51
 
51
52
  data_to_insert: list[Item] = []
52
53
 
53
54
  # 先删除旧的订单簿数据
54
- self._find_and_delete({"symbol": symbol})
55
+ self._find_and_delete({"s": symbol})
55
56
 
56
57
  # 处理买卖盘数据
57
- for side_id, levels in (("B", bids), ("A", asks)):
58
+ for side_id, levels in (("b", bids), ("a", asks)):
58
59
  for i, level in enumerate(levels):
59
60
  # level格式: [price, size, count]
60
61
  if len(level) >= 3:
61
62
  price, size, count = level[0:3]
62
63
  data_to_insert.append(
63
64
  {
64
- "symbol": symbol,
65
- "side": side_id,
66
- "px": str(price),
67
- "sz": str(size),
68
- "count": count,
65
+ "s": symbol,
66
+ "S": side_id,
67
+ "p": str(price),
68
+ "q": str(size),
69
+ "ct": count,
69
70
  "i": i
70
71
  }
71
72
  )
@@ -79,31 +80,17 @@ class Book(DataStore):
79
80
  """返回最后更新时间"""
80
81
  return self._time
81
82
 
82
- @property
83
- def sorted(self) -> dict[str, list[Item]]:
84
- """获取排序后的订单簿数据
85
-
86
- Returns:
87
- 返回按价格排序的买卖盘数据,卖盘升序,买盘降序
88
-
89
- .. code-block:: python
83
+ def sorted(
84
+ self, query: Item | None = None, limit: int | None = None
85
+ ) -> dict[str, list[Item]]:
90
86
 
91
- {
92
- "asks": [
93
- {"symbol": "BTC_USDT", "side": "A", "px": "110152.5", "sz": "53539", "count": 1},
94
- {"symbol": "BTC_USDT", "side": "A", "px": "110152.6", "sz": "95513", "count": 2}
95
- ],
96
- "bids": [
97
- {"symbol": "BTC_USDT", "side": "B", "px": "110152.4", "sz": "76311", "count": 1},
98
- {"symbol": "BTC_USDT", "side": "B", "px": "110152.3", "sz": "104688", "count": 2}
99
- ]
100
- }
101
- """
102
87
  return self._sorted(
103
- item_key="side",
104
- item_asc_key="A", # asks 升序
105
- item_desc_key="B", # bids 降序
106
- sort_key="px",
88
+ item_key="S",
89
+ item_asc_key="a", # asks 升序
90
+ item_desc_key="b", # bids 降序
91
+ sort_key="p",
92
+ query=query,
93
+ limit=limit,
107
94
  )
108
95
 
109
96
 
@@ -146,15 +133,19 @@ class Orders(DataStore):
146
133
  def _fmt(self, order:dict):
147
134
  return {
148
135
  "order_id": order.get("orderId"),
136
+ "position_id": order.get("positionId"),
149
137
  "symbol": order.get("symbol"),
150
- "px": order.get("price"),
138
+ "price": order.get("price"),
151
139
  "vol": order.get("vol"),
152
140
  "lev": order.get("leverage"),
153
141
  "side": "buy" if order.get("side") == 1 else "sell",
154
- "deal_vol": order.get("dealVol"),
155
- "deal_avg_px": order.get("dealAvgPrice"),
142
+ "deal_quantity": order.get("dealVol"),
143
+ "avg_price": order.get("dealAvgPrice"),
156
144
  "create_ts": order.get("createTime"),
157
145
  "update_ts": order.get("updateTime"),
146
+ "fee": order.get("makerFee"),
147
+ "profit": order.get("profit"),
148
+ "used_margin": order.get("usedMargin"),
158
149
  "state": "open"
159
150
  }
160
151
 
@@ -192,6 +183,13 @@ class Orders(DataStore):
192
183
  self._find_and_delete({
193
184
  "order_id": order.get("order_id")
194
185
  })
186
+ else:
187
+ order = self._fmt(data)
188
+ order["state"] = f"unknown_{state}"
189
+ self._update([order])
190
+ self._find_and_delete({
191
+ "order_id": order.get("order_id")
192
+ })
195
193
 
196
194
  class Detail(DataStore):
197
195
  _KEYS = ["symbol"]
@@ -214,7 +212,8 @@ class Detail(DataStore):
214
212
  "io": detail.get("io"),
215
213
  "contract_sz": detail.get("cs"),
216
214
  "minv": detail.get("minV"),
217
- "maxv": detail.get("maxV")
215
+ "maxv": detail.get("maxV"),
216
+ "online_time": detail.get("tcd")
218
217
  }
219
218
  )
220
219
  self._update(data_to_insert)
@@ -225,27 +224,27 @@ class Position(DataStore):
225
224
 
226
225
  def _fmt(self, position:dict):
227
226
  return {
228
- "position_id": position.get("positionId"),
229
- "symbol": position.get("symbol"),
230
- "side": "short" if position.get("positionType") == 2 else "long",
231
- "open_type": position.get("openType"),
232
- "state": position.get("state"),
233
- "hold_vol": position.get("holdVol"),
234
- "frozen_vol": position.get("frozenVol"),
235
- "close_vol": position.get("closeVol"),
236
- "hold_avg_price": position.get("holdAvgPriceFullyScale"),
237
- "open_avg_price": position.get("openAvgPriceFullyScale"),
238
- "close_avg_price": str(position.get("closeAvgPrice")),
239
- "liquidate_price": str(position.get("liquidatePrice")),
240
- "oim": position.get("oim"),
241
- "im": position.get("im"),
242
- "hold_fee": position.get("holdFee"),
243
- "realised": position.get("realised"),
244
- "leverage": position.get("leverage"),
245
- "margin_ratio": position.get("marginRatio"),
246
- "create_ts": position.get("createTime"),
247
- "update_ts": position.get("updateTime"),
248
- }
227
+ "position_id": position.get("positionId"),
228
+ "symbol": position.get("symbol"),
229
+ "side": "short" if position.get("positionType") == 2 else "long",
230
+ "open_type": position.get("openType"),
231
+ "state": position.get("state"),
232
+ "hold_vol": position.get("holdVol"),
233
+ "frozen_vol": position.get("frozenVol"),
234
+ "close_vol": position.get("closeVol"),
235
+ "hold_avg_price": position.get("holdAvgPriceFullyScale"),
236
+ "open_avg_price": position.get("openAvgPriceFullyScale"),
237
+ "close_avg_price": str(position.get("closeAvgPrice")),
238
+ "liquidate_price": str(position.get("liquidatePrice")),
239
+ "oim": position.get("oim"),
240
+ "im": position.get("im"),
241
+ "hold_fee": position.get("holdFee"),
242
+ "realised": position.get("realised"),
243
+ "leverage": position.get("leverage"),
244
+ "margin_ratio": position.get("marginRatio"),
245
+ "create_ts": position.get("createTime"),
246
+ "update_ts": position.get("updateTime"),
247
+ }
249
248
 
250
249
  def _onresponse(self, data: dict[str, Any]):
251
250
  positions = data.get("data", [])
@@ -405,8 +404,8 @@ class OurbitSwapDataStore(DataStoreCollection):
405
404
  "io": ["binance", "mexc"], # 交易所列表
406
405
  "contract_sz": 1,
407
406
  "minv": 1,
408
- "maxv": 10000
409
-
407
+ "maxv": 10000,
408
+ "online_time": 1625247600000 # 上线时间
410
409
  }
411
410
  ]
412
411
  """
@@ -415,32 +414,37 @@ class OurbitSwapDataStore(DataStoreCollection):
415
414
  @property
416
415
  def book(self) -> Book:
417
416
  """订单簿深度数据流
418
-
417
+
418
+ 提供实时订单簿深度数据,包含买卖双方价格和数量信息
419
+
419
420
  Data type: Mutable
420
-
421
- Keys: ("symbol", "side", "px")
421
+
422
+ Keys: ("s", "S", "p")
423
+ - s: 交易对符号,如 "BTC_USDT"
424
+ - S: 买卖方向,"a" 表示卖单(ask),"b" 表示买单(bid)
425
+ - p: 价格
422
426
 
423
427
  Data structure:
424
428
 
425
429
  .. code:: python
426
430
 
427
431
  [
428
- {
429
- "symbol": "BTC_USDT", # 交易对
430
- "side": "A", # 卖出方向
431
- "px": "110152.5", # 价格
432
- "sz": "53539", # 数量
433
- "count": 1 # 订单数量
434
- "i" 0 # 价格档位索引
435
- },
436
- {
437
- "symbol": "BTC_USDT", # 交易对
438
- "side": "B", # 买入方向
439
- "px": "110152.4", # 价格
440
- "sz": "76311", # 数量
441
- "count": 1 # 订单数量
442
- "i" 0 # 价格档位索引
443
- }
432
+ {
433
+ "s": "BTC_USDT", # 交易对符号
434
+ "S": "a", # 卖单方向(ask)
435
+ "p": "110152.5", # 价格
436
+ "q": "53539", # 数量
437
+ "ct": 1, # 该价格的订单数量
438
+ "i": 0 # 价格档位索引(从0开始)
439
+ },
440
+ {
441
+ "s": "BTC_USDT", # 交易对符号
442
+ "S": "b", # 买单方向(bid)
443
+ "p": "110152.4", # 价格
444
+ "q": "76311", # 数量
445
+ "ct": 1, # 该价格的订单数量
446
+ "i": 0 # 价格档位索引(从0开始)
447
+ }
444
448
  ]
445
449
  """
446
450
  return self._get("book", Book)
@@ -605,17 +609,22 @@ class SpotOrders(DataStore):
605
609
 
606
610
 
607
611
  def _fmt(self, order: dict) -> dict:
608
- state = order.get("state")
609
- if state == 1 or state == 2:
610
- state = "open"
611
- elif state == 3:
612
- state = "filled"
613
- elif state == 4:
614
- state = "canceled"
612
+ # 状态映射:1=open, 2=filled(整单成交), 3=partially_filled, 4=canceled
613
+ state_num = order.get("state") or order.get("status")
614
+ if state_num == 1:
615
+ state_txt = "open"
616
+ elif state_num == 2:
617
+ state_txt = "filled" # ✔ 2 才是整单成交
618
+ elif state_num == 3:
619
+ state_txt = "partially_filled"
620
+ elif state_num == 4:
621
+ state_txt = "canceled"
622
+ else:
623
+ state_txt = "unknown"
615
624
 
616
625
  return {
617
- "order_id": order.get("id"),
618
- "symbol": order.get("symbol"),
626
+ "order_id": order.get("id") or order.get("orderId"),
627
+ "symbol": order.get("symbol") or order.get("s"),
619
628
  "currency": order.get("currency"),
620
629
  "market": order.get("market"),
621
630
  "trade_type": order.get("tradeType"),
@@ -626,15 +635,14 @@ class SpotOrders(DataStore):
626
635
  "deal_quantity": order.get("dealQuantity"),
627
636
  "deal_amount": order.get("dealAmount"),
628
637
  "avg_price": order.get("avgPrice"),
629
- "state": order.get("state"),
630
- "source": order.get("source"),
638
+ "state": state_txt,
639
+ "source": order.get("source") or order.get("internal"),
631
640
  "fee": order.get("fee"),
632
641
  "create_ts": order.get("createTime"),
633
642
  "unique_id": order.get("uniqueId"),
634
643
  }
635
644
 
636
645
 
637
-
638
646
  def _onresponse(self, data: dict[str, Any]):
639
647
  orders = (data.get("data") or {}).get("resultList", [])
640
648
  items = [self._fmt(order) for order in orders]
@@ -643,9 +651,9 @@ class SpotOrders(DataStore):
643
651
  self._insert(items)
644
652
 
645
653
  def _on_message(self, msg: dict[str, Any]) -> None:
646
- d:dict = msg.get("d", {})
654
+ d: dict = msg.get("d", {})
647
655
 
648
-
656
+ # 基础字段
649
657
  item = {
650
658
  "order_id": d.get("id"),
651
659
  "symbol": msg.get("s") or d.get("symbol"),
@@ -656,7 +664,6 @@ class SpotOrders(DataStore):
656
664
  "amount": d.get("amount"),
657
665
  "remain_quantity": d.get("remainQ"),
658
666
  "remain_amount": d.get("remainA"),
659
- "state": d.get("status"),
660
667
  "client_order_id": d.get("clientOrderId"),
661
668
  "is_taker": d.get("isTaker"),
662
669
  "create_ts": d.get("createTime"),
@@ -665,32 +672,78 @@ class SpotOrders(DataStore):
665
672
 
666
673
  state = d.get("status")
667
674
 
668
- if state == 1:
669
- item["state"] = "open"
670
- self._insert([item])
671
-
672
- elif state == 3 or state == 2:
673
- if state == 3:
674
- item["state"] = "partially_filled"
675
+
676
+
677
+ # 成交片段(部分/完全)
678
+ if d.get("singleDealPrice"):
679
+ # 单片段信息(可能多次推送;需做增量累计 + 去重)
680
+ single_id = d.get("singleDealId")
681
+ single_px = d.get("singleDealPrice")
682
+ single_qty = d.get("singleDealQuantity")
683
+ try:
684
+ px_i = float(single_px) if single_px is not None else 0.0
685
+ qty_i = float(single_qty) if single_qty is not None else 0.0
686
+ except Exception:
687
+ px_i, qty_i = 0.0, 0.0
688
+
689
+ old = self.get({"order_id": d.get("id")})
690
+ old_qty = float(old.get("deal_quantity") or 0.0) if old else 0.0
691
+ old_avg = float(old.get("avg_price") or 0.0) if old else 0.0
692
+ old_last_single = old.get("last_single_id") if old else None
693
+
694
+ # 去重:若与上一片段 ID 相同,认为是重复推送,直接按状态更新不累计
695
+ if old and single_id and old_last_single == single_id:
696
+ new_qty = old_qty
697
+ new_avg = old_avg
698
+ else:
699
+ # VWAP 累计
700
+ new_qty = old_qty + qty_i
701
+ if new_qty > 0:
702
+ new_avg = (old_avg * old_qty + px_i * qty_i) / new_qty
703
+ else:
704
+ new_avg = px_i
705
+
706
+ # 写回
707
+ item.update({
708
+ "avg_price": str(new_avg) if new_qty > 0 else old.get("avg_price") if old else None,
709
+ "deal_quantity": str(new_qty) if new_qty > 0 else old.get("deal_quantity") if old else None,
710
+ "single_id": single_id,
711
+ "last_single_id": single_id,
712
+ })
713
+
714
+ # 状态文本:2=filled(整单), 3=partially_filled
715
+ # item["state"] = "filled" if state == 2 else "partially_filled"
675
716
  if state == 2:
676
717
  item["state"] = "filled"
677
-
678
- # 如果这三个字段存在追加
679
- if d.get("singleDealId") and d.get("singleDealPrice") and d.get("singleDealQuantity"):
680
- item.update({
681
- "unique_id": d.get("singleDealId"),
682
- "avg_price": d.get("singleDealPrice"),
683
- "deal_quantity": d.get("singleDealQuantity"),
684
- })
718
+ elif state == 3:
719
+ item["state"] = "partially_filled"
720
+ else:
721
+ item["state"] = "unknown_"+str(state)
685
722
 
686
- self._update([item])
687
- self._find_and_delete({ "order_id": d.get("id") })
688
-
689
- elif state == 4:
690
- item["state"] = "canceled"
691
723
  self._update([item])
692
- self._find_and_delete({ "order_id": d.get("id") })
693
724
 
725
+ # 整单成交 或者 部分取消 → 删除
726
+ if state == 2 or 'unknown' in item["state"]:
727
+ self._find_and_delete({"order_id": d.get("id")})
728
+ return
729
+ else:
730
+ # 新建 / 已挂出
731
+ if state == 1:
732
+ item["state"] = "open"
733
+ self._insert([item])
734
+ return
735
+
736
+ elif state == 4:
737
+ item["state"] = "canceled"
738
+ self._update([item])
739
+ self._find_and_delete({"order_id": d.get("id")})
740
+ return
741
+ else:
742
+
743
+ # 未知状态:更新后删除,避免脏数据残留
744
+ item["state"] = "unknown_"+str(state)
745
+ self._update([item])
746
+ self._find_and_delete({"order_id": d.get("id")})
694
747
 
695
748
 
696
749
 
@@ -722,7 +775,7 @@ class SpotBook(DataStore):
722
775
  # items.sort(key=lambda x: x.get("fv", 0)) # 按 fromVersion 排序
723
776
  # self._find_and_delete({"s": symbol})
724
777
 
725
- # 处理缓存
778
+ # 应为我们先连接的ws, 所以可能有缓存需要去处理
726
779
  items = [item for item in self.cache if item.get("s") == symbol]
727
780
  items.sort(key=lambda x: x.get("fv", 0)) # 按 fromVersion 排序
728
781
  self.cache = [item for item in self.cache if item.get("s") != symbol]
@@ -1032,34 +1085,30 @@ class OurbitSpotDataStore(DataStoreCollection):
1032
1085
  @property
1033
1086
  def orders(self) -> SpotOrders:
1034
1087
  """
1035
- 现货订单数据流(SpotOrders)
1036
-
1037
- Keys: ["order_id"]
1038
-
1039
- 说明:
1040
- - 聚合 REST 当前订单与 WS 增量推送(频道: spot@private.orders)
1041
- - 统一状态值:open, partially_filled, filled, canceled
1088
+ 现货订单数据流
1042
1089
 
1043
1090
  Data structure:
1091
+
1044
1092
  .. code:: python
1093
+
1045
1094
  [
1046
1095
  {
1047
1096
  "order_id": "123456", # 订单ID
1048
1097
  "symbol": "BTC_USDT", # 交易对
1049
1098
  "currency": "USDT", # 币种
1050
1099
  "market": "BTC_USDT", # 市场
1051
- "trade_type": "buy", # buy/sell
1052
- "order_type": "limit", # limit/market
1100
+ "trade_type": "buy", # 交易类型
1101
+ "order_type": "limit", # 订单类型
1053
1102
  "price": "11000.0", # 委托价格
1054
1103
  "quantity": "0.01", # 委托数量
1055
1104
  "amount": "110.0", # 委托金额
1056
- "deal_quantity": "0.01", # 已成交数量(累计)
1057
- "deal_amount": "110.0", # 已成交金额(累计)
1058
- "avg_price": "11000.0", # 成交均价(累计)
1059
- "state": "open", # open/partially_filled/filled/canceled
1060
- "fee": "0.01", # 手续费
1105
+ "deal_quantity": "0.01", # 成交数量
1106
+ "deal_amount": "110.0", # 成交金额
1107
+ "avg_price": "11000.0", # 成交均价
1108
+ "state": "open", # 订单状态
1061
1109
  "source": "api", # 来源
1062
- "create_ts": 1625247600000,# 创建时间戳(毫秒)
1110
+ "fee": "0.01", # 手续费
1111
+ "create_ts": 1625247600000,# 创建时间戳
1063
1112
  "unique_id": "abcdefg" # 唯一标识
1064
1113
  }
1065
1114
  ]
@@ -70,11 +70,15 @@ class OurbitSwap:
70
70
 
71
71
  for symbol in symbols:
72
72
  step = self.store.detail.find({"symbol": symbol})[0].get("tick_size")
73
+ step_str = str(Decimal(str(step)).normalize())
73
74
 
74
75
  send_jsons.append(
75
76
  {
76
77
  "method": "sub.depth.step",
77
- "param": {"symbol": symbol, "step": str(step)},
78
+ "param": {
79
+ "symbol": symbol,
80
+ "step": step_str,
81
+ },
78
82
  }
79
83
  )
80
84
 
@@ -83,11 +87,12 @@ class OurbitSwap:
83
87
  )
84
88
 
85
89
  async def sub_personal(self):
86
- self.client.ws_connect(
90
+ wsapp = self.client.ws_connect(
87
91
  self.ws_url,
88
92
  send_json={"method": "sub.personal.user.preference"},
89
93
  hdlr_json=self.store.onmessage,
90
94
  )
95
+ await wsapp._event.wait()
91
96
 
92
97
  def ret_content(self, res: pybotters.FetchResult):
93
98
  match res.data:
@@ -115,6 +120,7 @@ class OurbitSwap:
115
120
  usdt_amount: Optional[float] = None,
116
121
  leverage: Optional[int] = 20,
117
122
  position_id: Optional[int] = None,
123
+ quantity: float = None, # 兼容参数,不使用
118
124
  ):
119
125
  """
120
126
  size为合约张数, openType 1 为逐仓, 2为全仓
@@ -167,12 +173,17 @@ class OurbitSwap:
167
173
  if position_id is None:
168
174
  raise ValueError("position_id is required for closing position")
169
175
  data["positionId"] = position_id
170
- # import time
171
- # print(time.time(), '下单')
176
+
172
177
  res = await self.client.fetch(
173
178
  "POST", f"{self.api_url}/api/v1/private/order/create", data=data
174
179
  )
175
- return self.ret_content(res)
180
+ # 'orderId' =
181
+ # '226474723700166962'
182
+ # 'ts' =
183
+ # 1758034181833
184
+ ret_c = self.ret_content(res)
185
+ # 只返回 orderId
186
+ return ret_c["orderId"]
176
187
 
177
188
  async def place_tpsl(
178
189
  self,
hyperquant/broker/ws.py CHANGED
@@ -1,7 +1,12 @@
1
1
  import asyncio
2
+ import base64
3
+ import time
4
+ from typing import Any
5
+
2
6
  import pybotters
3
7
  from pybotters.ws import ClientWebSocketResponse, logger
4
8
  from pybotters.auth import Hosts
9
+ import urllib
5
10
  import yarl
6
11
 
7
12
 
@@ -17,8 +22,23 @@ class Heartbeat:
17
22
  await ws.send_str('{"method":"ping"}')
18
23
  await asyncio.sleep(10.0)
19
24
 
25
+ @staticmethod
26
+ async def edgex(ws: pybotters.ws.ClientWebSocketResponse):
27
+ while not ws.closed:
28
+ now = str(int(time.time() * 1000))
29
+ await ws.send_json({"type": "ping", "time": now})
30
+ await asyncio.sleep(20.0)
31
+
32
+ @staticmethod
33
+ async def lbank(ws: ClientWebSocketResponse):
34
+ while not ws.closed:
35
+ await ws.send_str('ping')
36
+ await asyncio.sleep(6)
37
+
20
38
  pybotters.ws.HeartbeatHosts.items['futures.ourbit.com'] = Heartbeat.ourbit
21
39
  pybotters.ws.HeartbeatHosts.items['www.ourbit.com'] = Heartbeat.ourbit_spot
40
+ pybotters.ws.HeartbeatHosts.items['quote.edgex.exchange'] = Heartbeat.edgex
41
+ pybotters.ws.HeartbeatHosts.items['uuws.rerrkvifj.com'] = Heartbeat.lbank
22
42
 
23
43
  class WssAuth:
24
44
  @staticmethod
@@ -42,7 +62,5 @@ class WssAuth:
42
62
  break
43
63
  else:
44
64
  logger.warning(f"WebSocket login failed: {data}")
45
-
46
-
47
-
65
+
48
66
  pybotters.ws.AuthHosts.items['futures.ourbit.com'] = pybotters.auth.Item("ourbit", WssAuth.ourbit)
hyperquant/core.py CHANGED
@@ -335,6 +335,9 @@ class Exchange(ExchangeBase):
335
335
  self.account[symbol]['realised_profit'] += profit
336
336
  self.account[symbol]['amount'] -= -direction * cover_amount
337
337
  trade['pos'] = profit # 记录盈亏
338
+
339
+ trade['pos_rate'] = -direction * (price / self.account[symbol]['hold_price'] - 1) if self.account[symbol]['hold_price'] != 0 else 0
340
+
338
341
  self.account[symbol]['hold_price'] = 0 if self.account[symbol]['amount'] == 0 else self.account[symbol]['hold_price']
339
342
 
340
343
  if open_amount > 0:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.5
3
+ Version: 0.7
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
@@ -0,0 +1,29 @@
1
+ hyperquant/__init__.py,sha256=UpjiX4LS5jmrBc2kE8RiLR02eCfD8JDQrR1q8zkLNcQ,161
2
+ hyperquant/core.py,sha256=RzRFbyImqzBiaA-9lQzvxPfxwcOvScdABZviS4y0kqM,20783
3
+ hyperquant/db.py,sha256=i2TjkCbmH4Uxo7UTDvOYBfy973gLcGexdzuT_YcSeIE,6678
4
+ hyperquant/draw.py,sha256=up_lQ3pHeVLoNOyh9vPjgNwjD0M-6_IetSGviQUgjhY,54624
5
+ hyperquant/logkit.py,sha256=nUo7nx5eONvK39GOhWwS41zNRL756P2J7-5xGzwXnTY,8462
6
+ hyperquant/notikit.py,sha256=x5yAZ_tAvLQRXcRbcg-VabCaN45LUhvlTZnUqkIqfAA,3596
7
+ hyperquant/broker/auth.py,sha256=Wst7mTBuUS2BQ5hZd0a8FNNs5Uc01ac9WzJpseTuyAY,7673
8
+ hyperquant/broker/bitget.py,sha256=866OuWUek0xJM8qWa7Bh4GDvcwUe3JVrx5mQMv2WEJE,2616
9
+ hyperquant/broker/edgex.py,sha256=TqUO2KRPLN_UaxvtLL6HnA9dAQXC1sGxOfqTHd6W5k8,18378
10
+ hyperquant/broker/hyperliquid.py,sha256=7MxbI9OyIBcImDelPJu-8Nd53WXjxPB5TwE6gsjHbto,23252
11
+ hyperquant/broker/lbank.py,sha256=dZUbi0a_Vhkp4pJ1V11X6nEM7I4HhQIVRgpSMeGcAMU,11681
12
+ hyperquant/broker/ourbit.py,sha256=NUcDSIttf-HGWzoW1uBTrGLPHlkuemMjYCm91MigTno,18228
13
+ hyperquant/broker/ws.py,sha256=9Zu5JSLj-ylYEVmFmRwvZDDnVYKwb37cLHfZzA0AZGc,2200
14
+ hyperquant/broker/lib/edgex_sign.py,sha256=lLUCmY8HHRLfLKyGrlTJYaBlSHPsIMWg3EZnQJKcmyk,95785
15
+ hyperquant/broker/lib/hpstore.py,sha256=LnLK2zmnwVvhEbLzYI-jz_SfYpO1Dv2u2cJaRAb84D8,8296
16
+ hyperquant/broker/lib/hyper_types.py,sha256=HqjjzjUekldjEeVn6hxiWA8nevAViC2xHADOzDz9qyw,991
17
+ hyperquant/broker/lib/util.py,sha256=iMU1qF0CHj5zzlIMEQGwjz-qtEVosEe7slXOCuB7Rcw,566
18
+ hyperquant/broker/models/bitget.py,sha256=swKYa7-jRoCSQxg0AUTZ7lPEhD1vxYIKm49eaIPwMxU,8961
19
+ hyperquant/broker/models/edgex.py,sha256=vPAkceal44cjTYKQ_0BoNAskOpmkno_Yo1KxgMLPc6Y,33954
20
+ hyperquant/broker/models/hyperliquid.py,sha256=c4r5739ibZfnk69RxPjQl902AVuUOwT8RNvKsMtwXBY,9459
21
+ hyperquant/broker/models/lbank.py,sha256=ZCD1dOUMyWPT8lKDj6C6LcHEof2d0JN384McURzLA-s,18868
22
+ hyperquant/broker/models/ourbit.py,sha256=xMcbuCEXd3XOpPBq0RYF2zpTFNnxPtuNJZCexMZVZ1k,41965
23
+ hyperquant/datavison/_util.py,sha256=92qk4vO856RqycO0YqEIHJlEg-W9XKapDVqAMxe6rbw,533
24
+ hyperquant/datavison/binance.py,sha256=3yNKTqvt_vUQcxzeX4ocMsI5k6Q6gLZrvgXxAEad6Kc,5001
25
+ hyperquant/datavison/coinglass.py,sha256=PEjdjISP9QUKD_xzXNzhJ9WFDTlkBrRQlVL-5pxD5mo,10482
26
+ hyperquant/datavison/okx.py,sha256=yg8WrdQ7wgWHNAInIgsWPM47N3Wkfr253169IPAycAY,6898
27
+ hyperquant-0.7.dist-info/METADATA,sha256=DZvCivcjbSzGsuRtDvwuaAiaG2zw61z_13guzOR2rsQ,4316
28
+ hyperquant-0.7.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
29
+ hyperquant-0.7.dist-info/RECORD,,