hyperquant 1.0__tar.gz → 1.1__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 (64) hide show
  1. {hyperquant-1.0 → hyperquant-1.1}/PKG-INFO +1 -1
  2. {hyperquant-1.0 → hyperquant-1.1}/apis.json +2 -2
  3. {hyperquant-1.0 → hyperquant-1.1}/pyproject.toml +1 -1
  4. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/bitmart.py +4 -4
  5. hyperquant-1.1/test.py +48 -0
  6. hyperquant-1.1/tests/test_bitmart.py +189 -0
  7. {hyperquant-1.0 → hyperquant-1.1}/tests/test_coinup.py +5 -5
  8. {hyperquant-1.0 → hyperquant-1.1}/uv.lock +1 -1
  9. hyperquant-1.0/tests/test_bitmart.py +0 -156
  10. {hyperquant-1.0 → hyperquant-1.1}/.gitignore +0 -0
  11. {hyperquant-1.0 → hyperquant-1.1}/.python-version +0 -0
  12. {hyperquant-1.0 → hyperquant-1.1}/README.md +0 -0
  13. {hyperquant-1.0 → hyperquant-1.1}/data/alpine_smoke.log +0 -0
  14. {hyperquant-1.0 → hyperquant-1.1}/data/logs/notikit.log +0 -0
  15. {hyperquant-1.0 → hyperquant-1.1}/data/logs/test_order_sync.log +0 -0
  16. {hyperquant-1.0 → hyperquant-1.1}/data/records_swap.csv +0 -0
  17. {hyperquant-1.0 → hyperquant-1.1}/data/records_swapc.csv +0 -0
  18. {hyperquant-1.0 → hyperquant-1.1}/doc/bitmart.md +0 -0
  19. {hyperquant-1.0 → hyperquant-1.1}/doc/coinup.md +0 -0
  20. {hyperquant-1.0 → hyperquant-1.1}/doc/lbank.md +0 -0
  21. {hyperquant-1.0 → hyperquant-1.1}/pub.sh +0 -0
  22. {hyperquant-1.0 → hyperquant-1.1}/requirements-dev.lock +0 -0
  23. {hyperquant-1.0 → hyperquant-1.1}/requirements.lock +0 -0
  24. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/__init__.py +0 -0
  25. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/auth.py +0 -0
  26. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/bitget.py +0 -0
  27. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/coinup.py +0 -0
  28. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/coinw.py +0 -0
  29. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/edgex.py +0 -0
  30. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/hyperliquid.py +0 -0
  31. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lbank.py +0 -0
  32. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
  33. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lib/hpstore.py +0 -0
  34. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  35. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lib/util.py +0 -0
  36. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/lighter.py +0 -0
  37. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/bitget.py +0 -0
  38. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/bitmart.py +0 -0
  39. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/coinup.py +0 -0
  40. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/coinw.py +0 -0
  41. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/edgex.py +0 -0
  42. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  43. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/lbank.py +0 -0
  44. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/lighter.py +0 -0
  45. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/models/ourbit.py +0 -0
  46. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/ourbit.py +0 -0
  47. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/broker/ws.py +0 -0
  48. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/core.py +0 -0
  49. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/datavison/_util.py +0 -0
  50. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/datavison/binance.py +0 -0
  51. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/datavison/coinglass.py +0 -0
  52. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/datavison/okx.py +0 -0
  53. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/db.py +0 -0
  54. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/draw.py +0 -0
  55. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/logkit.py +0 -0
  56. {hyperquant-1.0 → hyperquant-1.1}/src/hyperquant/notikit.py +0 -0
  57. {hyperquant-1.0 → hyperquant-1.1}/tests/test_bitget.py +0 -0
  58. {hyperquant-1.0 → hyperquant-1.1}/tests/test_coinw.py +0 -0
  59. {hyperquant-1.0 → hyperquant-1.1}/tests/test_draw.py +0 -0
  60. {hyperquant-1.0 → hyperquant-1.1}/tests/test_edgex.py +0 -0
  61. {hyperquant-1.0 → hyperquant-1.1}/tests/test_lbank.py +0 -0
  62. {hyperquant-1.0 → hyperquant-1.1}/tests/test_lighter.py +0 -0
  63. {hyperquant-1.0 → hyperquant-1.1}/tests/test_ourbit.py +0 -0
  64. {hyperquant-1.0 → hyperquant-1.1}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 1.0
3
+ Version: 1.1
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
@@ -24,8 +24,8 @@
24
24
  "41933ec0f5dace5eee47628ea2e2cb40a491f7fd20f983b385f8bdc5eea3d3ad4a47bd745f70fc2a"
25
25
  ],
26
26
  "bitmart":[
27
- "eyJoZWFkZXIiOnsidHlwIjoiQml0TWFydCIsImFsZyI6IkJNQVBJU0lYIn0sInBheWxvYWQiOnsiamlkIjoiMWRkNDM5ODkzNzU1NGUxOWFlZDY1MjJhZTMwMGZkODYiLCJ2ZXJzaW9uIjoiMjAyNTEwMzEiLCJleHBpcmVzQXQiOjE3NjE5OTE0MzYwNDcsImJtIjoiVXppdFJkZEdpdUNZek5KWSs5Q25xNkFjMlZWNmhiT0hhRzVwemdTSTE5cGRLS0JJN2FpUThGRXNaQkFyTDFVUmR5OGtFZnpCeEJiVnpELzF3Zm16NGRaOUtMU2tJVTVpa0tZaEU0SzJzOC91M1NTQmw5SVYxTjY1MURKL016NHJvdWpicm1hSk8rZU15THJDbnY3TnR1RFFPMnprRkZIcm9zRGZmM1Qvc0hodDZJa2N0UFJTdlU2ZCsrdWp6VG52Y2h1VzRDakhNTVVoQWFYOUhaMGVoTThvSnoxM2NCdHlUOVV2WXREUWd4enI5RjQvdmdYR2hDd1dESEpMNlYwU0lySG9MQkN0TXU4YWxKVy9CMitFLzVXM2JHdWxlZTk1RkhPcTh6YzRKakJXMnFxWHJ2R3RORXRWYnFFeGdJUnF5ak1ueENBNTZ5VjVPajgyQUV3OXVpM2VsaGNFZXYrSGtqUWoyeWpXYTZzR1Q3ZFloc0RRck9WU1g5Q0txelgxIn0sInNpZ25hdHVyZSI6IkRaM2hXREVBNWdXeXZ6RFdNSngzR2xhaUJBWDdiS1pCNk02bkJHaWE3WG0vOE1Vb3N1ZFhsMHp0OCs4TVM5c0szOSt1SG43VW5LalFrNGZPZ0NNU2d3PT0ifQ==",
28
- "vKqWE9vsDKZQmt2su3DMjqorPOpn7eeNS",
27
+ "eyJoZWFkZXIiOnsidHlwIjoiQml0TWFydCIsImFsZyI6IkJNQVBJU0lYIn0sInBheWxvYWQiOnsiamlkIjoiMjk4Mjk1NWMzZTBlNDA5YmFjODYyZGNlOWY0MTFhNDkiLCJ2ZXJzaW9uIjoiMjAyNTExMDEiLCJleHBpcmVzQXQiOjE3NjIwNTE3MzI0NTMsImJtIjoiRVhFbjk2UzV2dGRISmtKZ0hYejlPcTA0a0ZTdFdHTWtRWG5yVHpDZktYdW1OOHFIVTh0WExUeXlTaEMzVFJDMlZHOVhuMWxkcVkzdVdlOHluWlBrTGhqQWNIT0VjK2VoeEhlc3VJVUh3U3ArRVFnMEFtY0JIWW53OVRuelRkb2Fob25jakxBNTdtRDVEK2tPSHNWUXdDdElXRGNsTWdpd1d3V3NlY0d5Y1hNdjJJd1pvUVAwZzRlZUtudTgwNDlpZ1RPdERkN0JLenlFN0tONy85ZWpBL1hHQmg4SzBROW9hTmN6aWwwMmxVUnBGNm9wUUJHVTY1eHhBTkMwR0Zyb2RZMmFNalRtQVN2Si9vdmJMNEQxZGtUcUp6azIxdVlhamllRm9OTmREdlZqMXlzOGdTTGJBc3FWMDlsd2x0M3lTWER2L093a0hyclhJMlAyZVZqU2JuK1hPODhKRTlFYWRpTkcwRU9EOWhLRy9YRFhoU0dVT1N5YnJrNWdLdjNoIn0sInNpZ25hdHVyZSI6InQ3SmRFZ3VhTzNrUU9RSlNBcVRqMDVQRCsrcGR6UjlLVDVZTGhNdmNQRDlvc0tWcjRYMEM0VjkwaStYTm0rMFBxNlhuZGo5SjFSeXFtZVBuVG5QUmRBPT0ifQ==",
28
+ "4OamVUwuSznwyStlmRIfc9o0y5tCYdMOh",
29
29
  "1c0886dd192a1dd0f23f71f7ab577a45"
30
30
  ]
31
31
  }
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "1.00"
3
+ version = "1.01"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -363,7 +363,7 @@ class Bitmart:
363
363
  if detail is None:
364
364
  raise ValueError(f"Market metadata unavailable for symbol: {symbol}")
365
365
 
366
- if qty_contract is None:
366
+ if qty is not None:
367
367
 
368
368
  contract_size_str = detail.get("contract_size") or detail.get("vol_unit") or "1"
369
369
  try:
@@ -380,10 +380,10 @@ class Bitmart:
380
380
  f"Volume too small for contract size ({contract_size_val}): volume={qty}"
381
381
  )
382
382
 
383
- else:
384
- contracts_int = int(qty)
383
+ if qty_contract is not None:
384
+ contracts_int = int(qty_contract)
385
385
  if contracts_int <= 0:
386
- raise ValueError(f"Volume must be positive integer contracts: volume={qty}")
386
+ raise ValueError(f"Volume must be positive integer contracts: volume={qty_contract}")
387
387
 
388
388
  price_unit = detail.get("price_unit") or 1
389
389
  try:
hyperquant-1.1/test.py ADDED
@@ -0,0 +1,48 @@
1
+ import asyncio
2
+ import aiohttp
3
+ import time
4
+ from rnet import Client # rnet 需要 pip install rnet
5
+
6
+ URL = "https://futures.ourbit.com/api/v1/contract/systemSetting"
7
+
8
+ HEADERS = {
9
+ "accept": "*/*",
10
+ "accept-language": "zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6",
11
+ "cache-control": "no-cache",
12
+ "language": "Chinese",
13
+ "pragma": "no-cache",
14
+ "priority": "u=1, i",
15
+ "referer": "https://futures.ourbit.com/zh-CN/exchange/LAYER_USDT",
16
+ "sec-ch-ua": '"Microsoft Edge";v="141", "Not?A_Brand";v="8", "Chromium";v="141"',
17
+ "sec-ch-ua-mobile": "?0",
18
+ "sec-ch-ua-platform": '"macOS"',
19
+ "user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/141.0.0.0 Safari/537.36 Edg/141.0.0.0",
20
+ }
21
+
22
+ async def test_aiohttp(n=10):
23
+ async with aiohttp.ClientSession() as session:
24
+ start = time.perf_counter()
25
+ for _ in range(n):
26
+ async with session.get(URL, headers=HEADERS) as resp:
27
+ await resp.text()
28
+ end = time.perf_counter()
29
+ return (end - start) / n
30
+
31
+ async def test_rnet(n=10):
32
+ client = Client()
33
+ start = time.perf_counter()
34
+ for _ in range(n):
35
+ await client.get(URL, headers=HEADERS)
36
+ end = time.perf_counter()
37
+ return (end - start) / n
38
+
39
+ async def main():
40
+ aio_t = await test_aiohttp()
41
+ rnet_t = await test_rnet()
42
+ print(f"Aiohttp 平均响应时间: {aio_t:.3f}s")
43
+ print(f"Rnet 平均响应时间: {rnet_t:.3f}s")
44
+ faster = "aiohttp" if aio_t < rnet_t else "rnet"
45
+ print(f"🏁 更快的是: {faster}")
46
+
47
+ if __name__ == "__main__":
48
+ asyncio.run(main())
@@ -0,0 +1,189 @@
1
+ import pybotters
2
+
3
+ from hyperquant.broker.lighter import Lighter
4
+ import asyncio
5
+ from logging import Logger
6
+ import time
7
+ from dataclasses import dataclass
8
+ from typing import Any, Awaitable, Literal
9
+ from hyperquant.logkit import get_logger
10
+ from hyperquant.broker.bitmart import Bitmart
11
+
12
+
13
+
14
+ async def test_update():
15
+ async with pybotters.Client(apis='./apis.json') as client:
16
+ async with Bitmart(client=client) as broker:
17
+ # print(broker.store.detail.find()[0])
18
+ # await broker.update('balances')
19
+ # print(broker.store.balances.find())
20
+ # await broker.update('ticker')
21
+ # print(broker.store.ticker.find())
22
+
23
+ # await broker.update('history_orders')
24
+ # print(broker.store.orders.find())
25
+ # print(broker.store.orders.get({'order_id':3000237069605967}))
26
+ await broker.update('positions')
27
+ print(broker.store.positions.find())
28
+
29
+ # print(broker.store.detail.find({'name':'PUMPUSDT'}))
30
+
31
+
32
+ async def test_place():
33
+ async with pybotters.Client(apis='./apis.json') as client:
34
+ async with Bitmart(client=client) as broker:
35
+ # [2025-10-31 17:34:15] 🔵 准备建仓: VIRTUAL_USDT entry=short qty=20.498804 lag_px=1.4635 lead=binance
36
+ # [2025-11-01 01:33:22] 🔵 准备建仓: PUMP_USDT entry=long qty=18872.375560 lag_px=0.004239 lead=binance
37
+ # [2025-11-01 01:33:22] 🔔 Order placement failed: Bitmart submitOrder error: {'errno': 'ORDER_LEVERAGE_INFO_NOT_SYNCHRONIZED', 'message': 'Leverage info not synchronized, please place your order later or re
38
+ for i in range(2):
39
+ start = time.time()
40
+ oid = await broker.place_order(
41
+ symbol='PUMPUSDT',
42
+ side='sell',
43
+ category='limit',
44
+ price=0.004239,
45
+ qty=18872.375560,
46
+ mode='ioc',
47
+ leverage=40
48
+ # qty_contract=1
49
+ )
50
+
51
+ print(f"Placed order ID: {oid}, 下单毫秒数: {(time.time() - start)*1000:.2f} ms")
52
+
53
+ # resp = await broker.cancel_order(
54
+ # symbol='VIRTUALUSDT',
55
+ # order_ids=[oid],
56
+ # )
57
+
58
+ # print(f"Cancel response: {resp}")
59
+
60
+ @dataclass
61
+ class OrderSyncResult:
62
+ position: dict[str, Any]
63
+ order: dict[str, Any]
64
+
65
+
66
+ async def order_sync_polling(
67
+ broker: Bitmart,
68
+ *,
69
+ symbol: str,
70
+ place_task: Any,
71
+ is_ioc: bool = True,
72
+ cancel_retry: int = 3,
73
+ logger: Logger | None = None,
74
+ ) -> OrderSyncResult:
75
+ """Bitmart order sync flow based on doc/bitmart.md.
76
+
77
+ - Awaits the placement task to obtain order id
78
+ - Updates history orders and positions to fetch snapshots
79
+ - If IOC, returns immediately after one sync
80
+ - Otherwise polls and attempts cancel on timeout
81
+ """
82
+ oid = None
83
+ try:
84
+ started = int(time.time() * 1000)
85
+ oid = await place_task
86
+ latency = int(time.time() * 1000) - started
87
+ if logger:
88
+ logger.info(f"Order placed, id={oid}, latency={latency} ms")
89
+ except Exception as e: # pragma: no cover - defensive logging
90
+ if logger:
91
+ logger.warning(f"Order placement failed: {e}")
92
+ return OrderSyncResult(position={}, order={})
93
+
94
+ async def sync() -> OrderSyncResult:
95
+ await broker.update("history_orders")
96
+ await broker.update("positions")
97
+ order = broker.store.orders.get({"order_id": oid}) if oid else None
98
+ position: dict[str, Any] = {}
99
+ if order:
100
+ contract_id = order.get("contract_id")
101
+ if contract_id is not None:
102
+ positions = broker.store.positions.find({"contract_id": contract_id})
103
+ if positions:
104
+ position = positions[0]
105
+ return OrderSyncResult(position=position or {}, order=order or {})
106
+
107
+
108
+ for attempt in range(cancel_retry):
109
+ await asyncio.sleep(1)
110
+ await broker.update("history_orders")
111
+ order = broker.store.orders.get({"order_id": oid}) if oid else None
112
+ # 说明订单已经置入历史委托
113
+ if order:
114
+ return await sync()
115
+ else:
116
+ try:
117
+ # 撤单需要 symbol + order_ids
118
+ await broker.cancel_order(symbol, order_ids=[oid])
119
+ except Exception as e: # pragma: no cover - defensive logging
120
+ if logger:
121
+ logger.warning(
122
+ f"Order cancellation attempt {attempt + 1} failed: {e}"
123
+ )
124
+
125
+ return OrderSyncResult(position={}, order={})
126
+
127
+ async def test_sub_book():
128
+ async with pybotters.Client() as client:
129
+ async with Bitmart(client=client) as broker:
130
+ broker.store.book.limit = 1
131
+ await broker.sub_orderbook(["TRXUSDT", 'XRPUSDT', 'DOTUSDT'])
132
+ while True:
133
+ # await broker.store.book.wait()
134
+ # print(broker.store.book.find())
135
+ asks = broker.store.book.find({"S": "a", 's': 'TRXUSDT'})
136
+ bids = broker.store.book.find({"S": "b", 's': 'TRXUSDT'})
137
+ # 订单薄format化输出
138
+ print("Asks:")
139
+ for ask in asks:
140
+ print(f"Price: {ask['p']}, Quantity: {ask['q']}")
141
+ print("Bids:")
142
+ for bid in bids:
143
+ print(f"Price: {bid['p']}, Quantity: {bid['q']}")
144
+ print("-" * 30)
145
+ await asyncio.sleep(1)
146
+
147
+
148
+ # with broker.store.book.watch() as stream:
149
+ # async for change in stream:
150
+ # print(change)
151
+
152
+ async def test_auto_refresh():
153
+ async with pybotters.Client(apis='./apis.json') as client:
154
+ async with Bitmart(client=client, apis='./apis.json') as broker:
155
+ await broker.auto_refresh(0, test=True)
156
+ await asyncio.sleep(2)
157
+
158
+ async def test_sync_place():
159
+ logger = get_logger("test_sync_place")
160
+ async with pybotters.Client(apis='./apis.json') as client:
161
+ async with Bitmart(client=client) as broker:
162
+ # place_task = broker.place_order(
163
+ # symbol='VIRTUALUSDT',
164
+ # side='sell',
165
+ # category='limit',
166
+ # mode='ioc',
167
+ # price=1.38,
168
+ # qty=0.1,
169
+ # )
170
+
171
+ place_task = broker.place_order( # type: ignore[attr-defined]
172
+ symbol="VELODROMEUSDT",
173
+ side='sell',
174
+ qty_contract=int(round(1.000000)),
175
+ price=0.040645,
176
+ category='market'
177
+ )
178
+ result = await order_sync_polling(
179
+ broker,
180
+ place_task=place_task,
181
+ is_ioc=False,
182
+ cancel_retry=2,
183
+ symbol="VELODROMEUSDT",
184
+ logger=logger,
185
+ )
186
+ logger.info(f"Order Sync Result: {result}")
187
+
188
+ if __name__ == "__main__":
189
+ asyncio.run(test_sync_place())
@@ -16,10 +16,10 @@ async def test_update():
16
16
  async with Coinup(client=client) as broker:
17
17
  # await broker.update("detail")
18
18
  # print(broker.store.detail.get({"symbol": "WLFI-USDT"}))
19
- # await broker.update("position")
20
- # print(broker.store.position.find())
21
- await broker.update("history_orders")
22
- print(broker.store.history_orders.find())
19
+ await broker.update("position")
20
+ print(broker.store.position.find())
21
+ # await broker.update("history_orders")
22
+ # print(broker.store.history_orders.find())
23
23
 
24
24
  # await broker.update('orders')
25
25
  # print(broker.store.orders.find())
@@ -282,4 +282,4 @@ async def test_order_sync_polling():
282
282
  if __name__ == "__main__":
283
283
  import asyncio
284
284
 
285
- asyncio.run(test_sub_book())
285
+ asyncio.run(test_update())
@@ -921,7 +921,7 @@ wheels = [
921
921
 
922
922
  [[package]]
923
923
  name = "hyperquant"
924
- version = "0.99"
924
+ version = "1.0"
925
925
  source = { editable = "." }
926
926
  dependencies = [
927
927
  { name = "aiohttp" },
@@ -1,156 +0,0 @@
1
- import pybotters
2
-
3
- from hyperquant.broker.lighter import Lighter
4
- import asyncio
5
- from logging import Logger
6
- import time
7
- from dataclasses import dataclass
8
- from typing import Any, Awaitable, Literal
9
- from hyperquant.logkit import get_logger
10
- from hyperquant.broker.bitmart import Bitmart
11
-
12
-
13
-
14
- async def test_update():
15
- async with pybotters.Client(apis='./apis.json') as client:
16
- async with Bitmart(client=client) as broker:
17
- # print(broker.store.detail.find()[0])
18
- # await broker.update('balances')
19
- # print(broker.store.balances.find())
20
- # await broker.update('ticker')
21
- # print(broker.store.ticker.find())
22
-
23
- # await broker.update('history_orders')
24
- # print(broker.store.orders.find())
25
- # print(broker.store.orders.get({'order_id':3000237069605967}))
26
- await broker.update('positions')
27
- print(broker.store.positions.find())
28
-
29
-
30
- async def test_place():
31
- async with pybotters.Client(apis='./apis.json') as client:
32
- async with Bitmart(client=client) as broker:
33
- # [2025-10-31 17:34:15] 🔵 准备建仓: VIRTUAL_USDT entry=short qty=20.498804 lag_px=1.4635 lead=binance
34
- oid = await broker.place_order(
35
- symbol='VIRTUALUSDT',
36
- side='sell',
37
- category='limit',
38
- price=1.4635,
39
- qty=20.49880423641954,
40
- )
41
-
42
- print(f"Placed order ID: {oid}")
43
-
44
- # resp = await broker.cancel_order(
45
- # symbol='ONDOUSDT',
46
- # order_ids=[oid],
47
- # )
48
-
49
- # print(f"Cancel response: {resp}")
50
-
51
- @dataclass
52
- class OrderSyncResult:
53
- position: dict[str, Any]
54
- order: dict[str, Any]
55
-
56
- async def order_sync_polling(
57
- broker: Bitmart,
58
- place_task: Awaitable,
59
- is_ioc: bool = True,
60
- cancel_retry: int = 3,
61
- logger: Logger | None = None,
62
- ) -> OrderSyncResult:
63
- try:
64
- oid = await place_task
65
- except Exception as e:
66
- if logger:
67
- logger.warning(f"Order placement failed: {e}")
68
-
69
-
70
- async def sync():
71
- await broker.update('history_orders')
72
- await broker.update('positions')
73
- order = broker.store.orders.get({'order_id': oid})
74
- if order:
75
- contract_id = order.get('contract_id')
76
- positions = broker.store.positions.find({'contract_id': contract_id})
77
- position = positions[0] if positions else {}
78
- return OrderSyncResult(position=position, order=order)
79
-
80
- if is_ioc:
81
- return await sync()
82
- else:
83
- for attempt in range(cancel_retry):
84
- await asyncio.sleep(1)
85
- await broker.update('history_orders')
86
- order = broker.store.orders.get({'order_id': oid})
87
- # 说明订单已经置入历史委托
88
- if order:
89
- return await sync()
90
- else:
91
- try:
92
- await broker.cancel_order(
93
- symbol=order.get('symbol'),
94
- order_ids=[oid],
95
- )
96
- except Exception as e:
97
- if logger:
98
- logger.warning(f"Order cancellation attempt {attempt + 1} failed: {e}")
99
-
100
- return OrderSyncResult(position={}, order={})
101
-
102
-
103
- async def test_sub_book():
104
- async with pybotters.Client() as client:
105
- async with Bitmart(client=client) as broker:
106
- broker.store.book.limit = 1
107
- await broker.sub_orderbook(["TRXUSDT", 'XRPUSDT', 'DOTUSDT'])
108
- while True:
109
- # await broker.store.book.wait()
110
- # print(broker.store.book.find())
111
- asks = broker.store.book.find({"S": "a", 's': 'TRXUSDT'})
112
- bids = broker.store.book.find({"S": "b", 's': 'TRXUSDT'})
113
- # 订单薄format化输出
114
- print("Asks:")
115
- for ask in asks:
116
- print(f"Price: {ask['p']}, Quantity: {ask['q']}")
117
- print("Bids:")
118
- for bid in bids:
119
- print(f"Price: {bid['p']}, Quantity: {bid['q']}")
120
- print("-" * 30)
121
- await asyncio.sleep(1)
122
-
123
-
124
- # with broker.store.book.watch() as stream:
125
- # async for change in stream:
126
- # print(change)
127
-
128
- async def test_auto_refresh():
129
- async with pybotters.Client(apis='./apis.json') as client:
130
- async with Bitmart(client=client, apis='./apis.json') as broker:
131
- await broker.auto_refresh(0, test=True)
132
- await asyncio.sleep(2)
133
-
134
- async def test_sync_place():
135
- logger = get_logger("test_sync_place")
136
- async with pybotters.Client(apis='./apis.json') as client:
137
- async with Bitmart(client=client) as broker:
138
- place_task = broker.place_order(
139
- symbol='ONDOUSDT',
140
- side='sell',
141
- category='market',
142
- mode='ioc',
143
- price=0.71,
144
- qty=0.2,
145
- )
146
- result = await order_sync_polling(
147
- broker,
148
- place_task,
149
- is_ioc=False,
150
- cancel_retry=2,
151
- logger=logger,
152
- )
153
- logger.info(f"Order Sync Result: {result}")
154
-
155
- if __name__ == "__main__":
156
- asyncio.run(test_place())
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
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes