hyperquant 0.54__tar.gz → 0.56__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 (43) hide show
  1. {hyperquant-0.54 → hyperquant-0.56}/PKG-INFO +1 -1
  2. hyperquant-0.56/apis.json +5 -0
  3. {hyperquant-0.54 → hyperquant-0.56}/pyproject.toml +1 -1
  4. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/models/ourbit.py +2 -1
  5. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/ourbit.py +12 -4
  6. hyperquant-0.56/tests/test_ourbit.py +183 -0
  7. {hyperquant-0.54 → hyperquant-0.56}/uv.lock +1 -1
  8. hyperquant-0.54/apis.json +0 -5
  9. hyperquant-0.54/tests/test_order_sync.py +0 -107
  10. hyperquant-0.54/tests/test_ourbit.py +0 -78
  11. {hyperquant-0.54 → hyperquant-0.56}/.gitignore +0 -0
  12. {hyperquant-0.54 → hyperquant-0.56}/.python-version +0 -0
  13. {hyperquant-0.54 → hyperquant-0.56}/README.md +0 -0
  14. {hyperquant-0.54 → hyperquant-0.56}/backtest_tmp.py +0 -0
  15. {hyperquant-0.54 → hyperquant-0.56}/data/alpine_smoke.log +0 -0
  16. {hyperquant-0.54 → hyperquant-0.56}/data/logs/notikit.log +0 -0
  17. {hyperquant-0.54 → hyperquant-0.56}/data/logs/test_order_sync.log +0 -0
  18. {hyperquant-0.54 → hyperquant-0.56}/deals.json +0 -0
  19. {hyperquant-0.54 → hyperquant-0.56}/pnl_chart.html +0 -0
  20. {hyperquant-0.54 → hyperquant-0.56}/pub.sh +0 -0
  21. {hyperquant-0.54 → hyperquant-0.56}/requirements-dev.lock +0 -0
  22. {hyperquant-0.54 → hyperquant-0.56}/requirements.lock +0 -0
  23. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/__init__.py +0 -0
  24. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/auth.py +0 -0
  25. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/hyperliquid.py +0 -0
  26. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/lib/hpstore.py +0 -0
  27. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  28. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  29. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/broker/ws.py +0 -0
  30. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/core.py +0 -0
  31. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/datavison/_util.py +0 -0
  32. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/datavison/binance.py +0 -0
  33. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/datavison/coinglass.py +0 -0
  34. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/datavison/okx.py +0 -0
  35. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/db.py +0 -0
  36. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/draw.py +0 -0
  37. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/logkit.py +0 -0
  38. {hyperquant-0.54 → hyperquant-0.56}/src/hyperquant/notikit.py +0 -0
  39. {hyperquant-0.54 → hyperquant-0.56}/tests/test.py +0 -0
  40. {hyperquant-0.54 → hyperquant-0.56}/tests/test_draw.py +0 -0
  41. {hyperquant-0.54 → hyperquant-0.56}/tests/test_lbank.py +0 -0
  42. {hyperquant-0.54 → hyperquant-0.56}/tests/test_store.py +0 -0
  43. {hyperquant-0.54 → hyperquant-0.56}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.54
3
+ Version: 0.56
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,5 @@
1
+ {
2
+ "ourbit": [
3
+ "WEBa07743126a6cc69a896a501404ae8357e4116059ebc5bde75020881dc53a24ba"
4
+ ]
5
+ }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "0.54"
3
+ version = "0.56"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -134,6 +134,7 @@ class Orders(DataStore):
134
134
  def _fmt(self, order:dict):
135
135
  return {
136
136
  "order_id": order.get("orderId"),
137
+ "position_id": order.get("positionId"),
137
138
  "symbol": order.get("symbol"),
138
139
  "price": order.get("price"),
139
140
  "vol": order.get("vol"),
@@ -185,7 +186,7 @@ class Orders(DataStore):
185
186
  })
186
187
  else:
187
188
  order = self._fmt(data)
188
- order["state"] = "unknown"
189
+ order["state"] = f"unknown_{state}"
189
190
  self._update([order])
190
191
  self._find_and_delete({
191
192
  "order_id": order.get("order_id")
@@ -83,11 +83,12 @@ class OurbitSwap:
83
83
  )
84
84
 
85
85
  async def sub_personal(self):
86
- self.client.ws_connect(
86
+ wsapp = self.client.ws_connect(
87
87
  self.ws_url,
88
88
  send_json={"method": "sub.personal.user.preference"},
89
89
  hdlr_json=self.store.onmessage,
90
90
  )
91
+ await wsapp._event.wait()
91
92
 
92
93
  def ret_content(self, res: pybotters.FetchResult):
93
94
  match res.data:
@@ -115,6 +116,7 @@ class OurbitSwap:
115
116
  usdt_amount: Optional[float] = None,
116
117
  leverage: Optional[int] = 20,
117
118
  position_id: Optional[int] = None,
119
+ quantity: float = None, # 兼容参数,不使用
118
120
  ):
119
121
  """
120
122
  size为合约张数, openType 1 为逐仓, 2为全仓
@@ -167,12 +169,18 @@ class OurbitSwap:
167
169
  if position_id is None:
168
170
  raise ValueError("position_id is required for closing position")
169
171
  data["positionId"] = position_id
170
- # import time
171
- # print(time.time(), '下单')
172
+
172
173
  res = await self.client.fetch(
173
174
  "POST", f"{self.api_url}/api/v1/private/order/create", data=data
174
175
  )
175
- return self.ret_content(res)
176
+ # 'orderId' =
177
+ # '226474723700166962'
178
+ # 'ts' =
179
+ # 1758034181833
180
+ print(res.data)
181
+ ret_c = self.ret_content(res)
182
+ # 只返回 orderId
183
+ return ret_c["orderId"]
176
184
 
177
185
  async def place_tpsl(
178
186
  self,
@@ -0,0 +1,183 @@
1
+ import pybotters
2
+
3
+ from hyperquant.broker.ourbit import OurbitSpot
4
+ from hyperquant.broker.ourbit import OurbitSwap
5
+
6
+ async def download_orders():
7
+ async with pybotters.Client(
8
+ apis={
9
+ "ourbit": [
10
+ "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
11
+ ]
12
+ }
13
+ ) as client:
14
+ # 时间区间 (毫秒)
15
+ start_time = 1757254540000 # 起始
16
+ end_time = 1757433599999 # 结束
17
+
18
+ page_size = 100 # 接口最大 100
19
+ page_num = 1
20
+ all_results = []
21
+
22
+ while True:
23
+ url = (
24
+ "https://www.ourbit.com/api/platform/spot/deal/deals"
25
+ f"?endTime={end_time}&pageNum={page_num}&pageSize={page_size}&startTime={start_time}"
26
+ )
27
+ res = await client.fetch("GET", url)
28
+ result_list = res.data["data"]["resultList"]
29
+ got = len(result_list)
30
+ print(f"page {page_num} -> {got} items")
31
+ all_results.extend(result_list)
32
+
33
+ if got < page_size: # 最后一页
34
+ break
35
+ page_num += 1
36
+
37
+ print(f"total collected: {len(all_results)}")
38
+
39
+ # 写入汇总数据
40
+ import json
41
+ with open("deals.json", "w") as f:
42
+ json.dump(
43
+ {
44
+ "data": {
45
+ "resultList": all_results,
46
+ "total": len(all_results),
47
+ "pageSize": page_size,
48
+ "pagesFetched": page_num
49
+ }
50
+ },
51
+ f,
52
+ indent=2
53
+ )
54
+ print("Saved to deals.json")
55
+
56
+ async def test_detail():
57
+ async with pybotters.Client() as client:
58
+ ob = OurbitSpot(client)
59
+ await ob.__aenter__()
60
+ print(ob.store.detail.get({
61
+ 'name': 'OPEN'
62
+ }))
63
+
64
+ async def test_ourbit_wrap():
65
+ async with pybotters.Client(
66
+ apis={
67
+ "ourbit": [
68
+ "WEBa07743126a6cc69a896a501404ae8357e4116059ebc5bde75020881dc53a24ba"
69
+ ]
70
+ }
71
+ ) as client:
72
+ ob = OurbitSpot(client)
73
+ await ob.__aenter__()
74
+ await ob.update('balance')
75
+ print(ob.store.balance.find())
76
+
77
+
78
+ import asyncio
79
+ import time
80
+ from hyperquant.broker.ourbit import OurbitSpot
81
+ import pybotters
82
+ from hyperquant.logkit import get_logger
83
+
84
+ logger = get_logger('test_order_sync', './data/logs/test_order_sync.log', show_time=True)
85
+
86
+
87
+ # 等待指定 oid 的最终 delete,超时抛 TimeoutError
88
+ async def wait_delete(stream: pybotters.StoreStream, oid: str, seconds: float):
89
+ async with asyncio.timeout(seconds):
90
+ while True:
91
+ change = await stream.__anext__()
92
+ # print(change.operation, change.data)
93
+ if change.operation == "delete" and change.data.get("order_id") == oid:
94
+ return change.data # 内含 state / avg_price / deal_quantity 等累计字段
95
+
96
+
97
+ async def order_sync(
98
+ ob: OurbitSpot| OurbitSwap,
99
+ symbol: str = "SOL_USDT",
100
+ side: str = "buy",
101
+ order_type: str = "market", # "market" / "limit"
102
+ usdt_amount: float | None = None, # 市价可填
103
+ quantity: float | None = None, # 市价可填
104
+ price: float | None = None, # 限价必填
105
+ window_sec: float = 2.0, # 主等待窗口(限价可设为 5.0)
106
+ grace_sec: float = 2, # 撤单后宽限
107
+ ):
108
+ with ob.store.orders.watch() as stream:
109
+ # 下单(只保留最简两种入参形态)
110
+ try:
111
+ if isinstance(ob, OurbitSwap):
112
+ oid = await ob.place_order(
113
+ symbol,
114
+ side,
115
+ order_type=order_type,
116
+ usdt_amount=usdt_amount,
117
+ quantity=quantity,
118
+ price=price
119
+ )
120
+ except Exception as e:
121
+ return {"symbol": symbol, "state": "error", "error": str(e)}
122
+
123
+ # 步骤1:主窗口内等待这单的最终 delete
124
+ try:
125
+ return await wait_delete(stream, oid, window_sec)
126
+ except TimeoutError:
127
+ # 步骤2:到点撤单(市价通常用不到;限价才有意义)
128
+ for i in range(3):
129
+ try:
130
+ await ob.cancel_order(oid)
131
+ break
132
+ except Exception:
133
+ pass
134
+ await asyncio.sleep(0.1)
135
+ # 固定宽限内再等“迟到”的最终 delete
136
+ try:
137
+ return await wait_delete(stream, oid, grace_sec)
138
+ except TimeoutError:
139
+ return {"order_id": oid, "symbol": symbol, "state": "timeout"}
140
+
141
+
142
+ async def test_order_sync_spot():
143
+ async with pybotters.Client(
144
+ apis={
145
+ "ourbit": [
146
+ "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
147
+ ]
148
+ }
149
+ ) as client:
150
+ ob = OurbitSpot(client)
151
+ await ob.__aenter__()
152
+ await ob.sub_personal() # 私有频道
153
+ ob.store.book.limit = 3
154
+ await ob.sub_orderbook(["SOL_USDT"]) # 订单簿频道
155
+ # # 示例:市价
156
+ # now= time.time()
157
+ result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="market", usdt_amount=8, price=200, window_sec=2)
158
+ print(result)
159
+
160
+
161
+ async def test_order_sync_swap():
162
+ async with pybotters.Client(
163
+ apis={
164
+ "ourbit": [
165
+ "WEBb401428e69af1815808e470be0a4f4e8a70a5c5cc0b0df0a33220f689167c629"
166
+ ]
167
+ }
168
+ ) as client:
169
+ ob = OurbitSwap(client)
170
+ await ob.__aenter__()
171
+ await ob.sub_personal() # 私有频道
172
+
173
+ # await ob.sub_orderbook(["SOL_USDT"]) # 订单簿频道
174
+ # # 示例:市价
175
+ # now= time.time()
176
+ result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="market", usdt_amount=8, price=200, window_sec=3)
177
+ print(result)
178
+
179
+
180
+
181
+ if __name__ == "__main__":
182
+ import asyncio
183
+ asyncio.run(test_order_sync_swap())
@@ -530,7 +530,7 @@ wheels = [
530
530
 
531
531
  [[package]]
532
532
  name = "hyperquant"
533
- version = "0.53"
533
+ version = "0.55"
534
534
  source = { editable = "." }
535
535
  dependencies = [
536
536
  { name = "aiohttp" },
hyperquant-0.54/apis.json DELETED
@@ -1,5 +0,0 @@
1
- {
2
- "ourbit": [
3
- "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
4
- ]
5
- }
@@ -1,107 +0,0 @@
1
- import asyncio
2
- import time
3
- from hyperquant.broker.ourbit import OurbitSpot
4
- import pybotters
5
- from hyperquant.logkit import get_logger
6
-
7
- logger = get_logger('test_order_sync', './data/logs/test_order_sync.log', show_time=True)
8
-
9
-
10
- # 等待指定 oid 的最终 delete,超时抛 TimeoutError
11
- async def wait_delete(stream: pybotters.StoreStream, oid: str, seconds: float):
12
- async with asyncio.timeout(seconds):
13
- while True:
14
- change = await stream.__anext__()
15
- if change.operation == "delete" and change.data.get("order_id") == oid:
16
- return change.data # 内含 state / avg_price / deal_quantity 等累计字段
17
-
18
-
19
- async def order_sync(
20
- ob: OurbitSpot,
21
- symbol: str = "SOL_USDT",
22
- side: str = "buy",
23
- order_type: str = "market", # "market" / "limit"
24
- usdt_amount: float | None = None, # 市价可填
25
- quantity: float | None = None, # 市价可填
26
- price: float | None = None, # 限价必填
27
- window_sec: float = 2.0, # 主等待窗口(限价可设为 5.0)
28
- grace_sec: float = 2, # 撤单后宽限
29
- ):
30
- with ob.store.orders.watch() as stream:
31
- # 下单(只保留最简两种入参形态)
32
- try:
33
- oid = await ob.place_order(
34
- symbol,
35
- side,
36
- order_type=order_type,
37
- usdt_amount=usdt_amount,
38
- quantity=quantity,
39
- price=price,
40
- )
41
- except Exception as e:
42
- return {"symbol": symbol, "state": "error", "error": str(e)}
43
-
44
- # 步骤1:主窗口内等待这单的最终 delete
45
- try:
46
- return await wait_delete(stream, oid, window_sec)
47
- except TimeoutError:
48
- # 步骤2:到点撤单(市价通常用不到;限价才有意义)
49
- for i in range(3):
50
- try:
51
- await ob.cancel_order(oid)
52
- break
53
- except Exception:
54
- pass
55
- await asyncio.sleep(0.1)
56
- # 固定宽限内再等“迟到”的最终 delete
57
- try:
58
- return await wait_delete(stream, oid, grace_sec)
59
- except TimeoutError:
60
- return {"order_id": oid, "symbol": symbol, "state": "timeout"}
61
-
62
-
63
- async def main():
64
- async with pybotters.Client(
65
- apis={
66
- "ourbit": [
67
- "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
68
- ]
69
- }
70
- ) as client:
71
- ob = OurbitSpot(client)
72
- await ob.__aenter__()
73
- await ob.sub_personal() # 私有频道
74
- ob.store.book.limit = 3
75
- await ob.sub_orderbook(["SOL_USDT"]) # 订单簿频道
76
- # # 示例:市价
77
- # now= time.time()
78
- result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="market", usdt_amount=8, price=200, window_sec=2)
79
- print(result)
80
-
81
-
82
- # while True:
83
- # asks = ob.store.book.find({'s': 'SOL_USDT', 'S': 'a'})
84
- # bids = ob.store.book.find({'s': 'SOL_USDT', 'S': 'b'})
85
- # if asks and bids:
86
- # best_ask = float(asks[0]['p'])
87
- # best_bid = float(bids[0]['p'])
88
-
89
- # result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="limit", quantity=0.04, price=best_bid, window_sec=1)
90
- # logger.info(result)
91
-
92
- # if result['state'] == 'filled':
93
- # logger.ok(f"买入成功: {result}")
94
- # elif result['state'] == 'canceled':
95
- # if result.get('avg_price'):
96
- # logger.ok(f"部分成交,已撤单: {result}")
97
- # else:
98
- # logger.error(f"买入失败: {result}")
99
-
100
- # await asyncio.sleep(1)
101
-
102
-
103
-
104
-
105
- if __name__ == "__main__":
106
- asyncio.run(main())
107
-
@@ -1,78 +0,0 @@
1
- import pybotters
2
-
3
- from hyperquant.broker.ourbit import OurbitSpot
4
- from hyperquant.broker.ourbit import OurbitSwap
5
-
6
- async def download_orders():
7
- async with pybotters.Client(
8
- apis={
9
- "ourbit": [
10
- "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
11
- ]
12
- }
13
- ) as client:
14
- # 时间区间 (毫秒)
15
- start_time = 1757254540000 # 起始
16
- end_time = 1757433599999 # 结束
17
-
18
- page_size = 100 # 接口最大 100
19
- page_num = 1
20
- all_results = []
21
-
22
- while True:
23
- url = (
24
- "https://www.ourbit.com/api/platform/spot/deal/deals"
25
- f"?endTime={end_time}&pageNum={page_num}&pageSize={page_size}&startTime={start_time}"
26
- )
27
- res = await client.fetch("GET", url)
28
- result_list = res.data["data"]["resultList"]
29
- got = len(result_list)
30
- print(f"page {page_num} -> {got} items")
31
- all_results.extend(result_list)
32
-
33
- if got < page_size: # 最后一页
34
- break
35
- page_num += 1
36
-
37
- print(f"total collected: {len(all_results)}")
38
-
39
- # 写入汇总数据
40
- import json
41
- with open("deals.json", "w") as f:
42
- json.dump(
43
- {
44
- "data": {
45
- "resultList": all_results,
46
- "total": len(all_results),
47
- "pageSize": page_size,
48
- "pagesFetched": page_num
49
- }
50
- },
51
- f,
52
- indent=2
53
- )
54
- print("Saved to deals.json")
55
-
56
- async def test_detail():
57
- async with pybotters.Client() as client:
58
- ob = OurbitSpot(client)
59
- await ob.__aenter__()
60
- print(ob.store.detail.get({
61
- 'name': 'OPEN'
62
- }))
63
-
64
- async def test_ourbit_wrap():
65
- async with pybotters.Client(
66
- apis={
67
- "ourbit": [
68
- "WEB3bf088f8b2f2fae07592fe1a6240e2d798100a9cb2a91f8fda1056b6865ab3ee"
69
- ]
70
- }
71
- ) as client:
72
- ob = OurbitSwap(client)
73
- await ob.__aenter__()
74
- print(ob.store.detail.find())
75
-
76
- if __name__ == "__main__":
77
- import asyncio
78
- asyncio.run(test_detail())
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
File without changes
File without changes
File without changes