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.
- hyperquant/broker/auth.py +144 -9
- hyperquant/broker/bitget.py +101 -0
- hyperquant/broker/edgex.py +500 -0
- hyperquant/broker/lbank.py +354 -0
- hyperquant/broker/lib/edgex_sign.py +455 -0
- hyperquant/broker/lib/util.py +22 -0
- hyperquant/broker/models/bitget.py +283 -0
- hyperquant/broker/models/edgex.py +1053 -0
- hyperquant/broker/models/lbank.py +547 -0
- hyperquant/broker/models/ourbit.py +184 -135
- hyperquant/broker/ourbit.py +16 -5
- hyperquant/broker/ws.py +21 -3
- hyperquant/core.py +3 -0
- {hyperquant-0.5.dist-info → hyperquant-0.7.dist-info}/METADATA +1 -1
- hyperquant-0.7.dist-info/RECORD +29 -0
- hyperquant-0.5.dist-info/RECORD +0 -21
- {hyperquant-0.5.dist-info → hyperquant-0.7.dist-info}/WHEEL +0 -0
@@ -22,19 +22,20 @@ class Book(DataStore):
|
|
22
22
|
Channel: push.depth.step
|
23
23
|
|
24
24
|
用于存储和管理订单簿深度数据,包含买卖盘的价格和数量信息
|
25
|
-
Keys: ["
|
26
|
-
-
|
27
|
-
-
|
28
|
-
-
|
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 = ["
|
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[:
|
47
|
-
bids = bids[:
|
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({"
|
55
|
+
self._find_and_delete({"s": symbol})
|
55
56
|
|
56
57
|
# 处理买卖盘数据
|
57
|
-
for side_id, levels in (("
|
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
|
-
"
|
65
|
-
"
|
66
|
-
"
|
67
|
-
"
|
68
|
-
"
|
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
|
-
|
83
|
-
|
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="
|
104
|
-
item_asc_key="
|
105
|
-
item_desc_key="
|
106
|
-
sort_key="
|
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
|
-
"
|
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
|
-
"
|
155
|
-
"
|
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
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
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: ("
|
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
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
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
|
-
|
609
|
-
|
610
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
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":
|
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
|
-
|
669
|
-
|
670
|
-
|
671
|
-
|
672
|
-
|
673
|
-
|
674
|
-
|
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
|
-
|
680
|
-
item
|
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
|
-
|
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", #
|
1052
|
-
"order_type": "limit", #
|
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", #
|
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
|
-
"
|
1110
|
+
"fee": "0.01", # 手续费
|
1111
|
+
"create_ts": 1625247600000,# 创建时间戳
|
1063
1112
|
"unique_id": "abcdefg" # 唯一标识
|
1064
1113
|
}
|
1065
1114
|
]
|
hyperquant/broker/ourbit.py
CHANGED
@@ -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": {
|
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
|
-
|
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
|
-
|
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.
|
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,,
|