hyperquant 0.56__tar.gz → 0.58__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 (40) hide show
  1. {hyperquant-0.56 → hyperquant-0.58}/PKG-INFO +1 -1
  2. {hyperquant-0.56 → hyperquant-0.58}/pyproject.toml +1 -1
  3. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/models/ourbit.py +4 -3
  4. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/ourbit.py +0 -1
  5. {hyperquant-0.56 → hyperquant-0.58}/tests/test_ourbit.py +28 -1
  6. {hyperquant-0.56 → hyperquant-0.58}/uv.lock +1 -1
  7. hyperquant-0.56/tests/test.py +0 -183
  8. hyperquant-0.56/tests/test_store.py +0 -16
  9. {hyperquant-0.56 → hyperquant-0.58}/.gitignore +0 -0
  10. {hyperquant-0.56 → hyperquant-0.58}/.python-version +0 -0
  11. {hyperquant-0.56 → hyperquant-0.58}/README.md +0 -0
  12. {hyperquant-0.56 → hyperquant-0.58}/apis.json +0 -0
  13. {hyperquant-0.56 → hyperquant-0.58}/backtest_tmp.py +0 -0
  14. {hyperquant-0.56 → hyperquant-0.58}/data/alpine_smoke.log +0 -0
  15. {hyperquant-0.56 → hyperquant-0.58}/data/logs/notikit.log +0 -0
  16. {hyperquant-0.56 → hyperquant-0.58}/data/logs/test_order_sync.log +0 -0
  17. {hyperquant-0.56 → hyperquant-0.58}/deals.json +0 -0
  18. {hyperquant-0.56 → hyperquant-0.58}/pnl_chart.html +0 -0
  19. {hyperquant-0.56 → hyperquant-0.58}/pub.sh +0 -0
  20. {hyperquant-0.56 → hyperquant-0.58}/requirements-dev.lock +0 -0
  21. {hyperquant-0.56 → hyperquant-0.58}/requirements.lock +0 -0
  22. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/__init__.py +0 -0
  23. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/auth.py +0 -0
  24. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/hyperliquid.py +0 -0
  25. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/lib/hpstore.py +0 -0
  26. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/lib/hyper_types.py +0 -0
  27. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/models/hyperliquid.py +0 -0
  28. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/broker/ws.py +0 -0
  29. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/core.py +0 -0
  30. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/datavison/_util.py +0 -0
  31. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/datavison/binance.py +0 -0
  32. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/datavison/coinglass.py +0 -0
  33. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/datavison/okx.py +0 -0
  34. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/db.py +0 -0
  35. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/draw.py +0 -0
  36. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/logkit.py +0 -0
  37. {hyperquant-0.56 → hyperquant-0.58}/src/hyperquant/notikit.py +0 -0
  38. {hyperquant-0.56 → hyperquant-0.58}/tests/test_draw.py +0 -0
  39. {hyperquant-0.56 → hyperquant-0.58}/tests/test_lbank.py +0 -0
  40. {hyperquant-0.56 → hyperquant-0.58}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperquant
3
- Version: 0.56
3
+ Version: 0.58
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,6 +1,6 @@
1
1
  [project]
2
2
  name = "hyperquant"
3
- version = "0.56"
3
+ version = "0.58"
4
4
  description = "A minimal yet hyper-efficient backtesting framework for quantitative trading"
5
5
  authors = [
6
6
  { name = "MissinA", email = "1421329142@qq.com" }
@@ -213,7 +213,8 @@ class Detail(DataStore):
213
213
  "io": detail.get("io"),
214
214
  "contract_sz": detail.get("cs"),
215
215
  "minv": detail.get("minV"),
216
- "maxv": detail.get("maxV")
216
+ "maxv": detail.get("maxV"),
217
+ "online_time": detail.get("tcd")
217
218
  }
218
219
  )
219
220
  self._update(data_to_insert)
@@ -404,8 +405,8 @@ class OurbitSwapDataStore(DataStoreCollection):
404
405
  "io": ["binance", "mexc"], # 交易所列表
405
406
  "contract_sz": 1,
406
407
  "minv": 1,
407
- "maxv": 10000
408
-
408
+ "maxv": 10000,
409
+ "online_time": 1625247600000 # 上线时间
409
410
  }
410
411
  ]
411
412
  """
@@ -177,7 +177,6 @@ class OurbitSwap:
177
177
  # '226474723700166962'
178
178
  # 'ts' =
179
179
  # 1758034181833
180
- print(res.data)
181
180
  ret_c = self.ret_content(res)
182
181
  # 只返回 orderId
183
182
  return ret_c["orderId"]
@@ -175,9 +175,36 @@ async def test_order_sync_swap():
175
175
  # now= time.time()
176
176
  result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="market", usdt_amount=8, price=200, window_sec=3)
177
177
  print(result)
178
+
179
+
180
+ async def test_order_close_swap():
181
+ async with pybotters.Client(
182
+ apis={
183
+ "ourbit": [
184
+ "WEBb401428e69af1815808e470be0a4f4e8a70a5c5cc0b0df0a33220f689167c629"
185
+ ]
186
+ }
187
+ ) as client:
188
+ ob = OurbitSwap(client)
189
+ await ob.__aenter__()
190
+ # await ob.sub_personal() # 私有频道
191
+ # result = await order_sync( ob, symbol="SOL_USDT", side="buy", order_type="market", usdt_amount=8, price=200, window_sec=3)
192
+ # print(result)
193
+ # oid = await ob.place_order(
194
+ # "SOL_USDT",
195
+ # "buy",
196
+ # order_type="market",
197
+ # size=1
198
+ # )
199
+
200
+ # print(oid)
201
+ # await ob.update('position')
202
+ # print(ob.store.position.find())
203
+
204
+ await ob.place_order('SOL_USDT', 'close_sell', 1, position_id=6062178)
178
205
 
179
206
 
180
207
 
181
208
  if __name__ == "__main__":
182
209
  import asyncio
183
- asyncio.run(test_order_sync_swap())
210
+ asyncio.run(test_order_close_swap())
@@ -530,7 +530,7 @@ wheels = [
530
530
 
531
531
  [[package]]
532
532
  name = "hyperquant"
533
- version = "0.55"
533
+ version = "0.57"
534
534
  source = { editable = "." }
535
535
  dependencies = [
536
536
  { name = "aiohttp" },
@@ -1,183 +0,0 @@
1
- import asyncio
2
- import time
3
- from typing import Optional, TypedDict, Literal
4
-
5
- import pybotters
6
- from hyperquant.broker.ourbit import OurbitSpot
7
- from hyperquant.logkit import get_logger
8
-
9
- logger = get_logger("alpine_test", "./data/alpine_smoke.log", True)
10
-
11
-
12
- class Hold(TypedDict, total=False):
13
- symbol: str
14
- status: Literal["pending", "filled", "closing"]
15
- oid: str
16
- ts: float
17
- p: float
18
- q: float
19
- filled_ts: float
20
-
21
-
22
- class AlpineSmokeTest:
23
- """
24
- 仅针对 ALPINE_USDT:市价开仓 -> 持有 5 秒 -> 市价平仓。
25
- - 目的:测试 WS 事件链路与下单路径稳定性(不依赖价差/策略信号)。
26
- - 仅订阅 Ourbit 订单簿(可选) 和私有频道,验证参数与心跳。
27
- """
28
-
29
- SYMBOL = "SOL_USDT"
30
-
31
- def __init__(self, hold_seconds: float = 5.0, open_timeout_ms: int = 2000, close_timeout_ms: int = 3000):
32
- self.hold_seconds = hold_seconds
33
- self.open_timeout_ms = open_timeout_ms
34
- self.close_timeout_ms = close_timeout_ms
35
- self.client: Optional[pybotters.Client] = None
36
- self.ourbit: Optional[OurbitSpot] = None
37
- self.ob_store = None
38
-
39
- def _msg_debug(self,msg: dict, ws):
40
-
41
- if 'spot@private.orders' in msg.get("c", ""):
42
- logger.info(f"orders消息: {msg}")
43
-
44
- async def _msg_debug2(self):
45
- with self.ob_store.orders.watch() as stream:
46
- async for change in stream:
47
- print(change)
48
-
49
- async def __aenter__(self):
50
- self.client = pybotters.Client(apis="./apis.json")
51
- await self.client.__aenter__()
52
-
53
- self.ourbit = OurbitSpot(self.client)
54
- await self.ourbit.__aenter__()
55
- self.ob_store = self.ourbit.store
56
-
57
- # 仅订阅 ALPINE 订单簿与私有频道(用于测试 WS 参数与心跳)
58
- await self.ourbit.sub_orderbook([self.SYMBOL])
59
- await self.ourbit.sub_personal()
60
- logger.info("已就绪:仅订阅 Ourbit ALPINE 订单簿/私有频道")
61
- asyncio.create_task(self._msg_debug2())
62
- return self
63
-
64
- async def __aexit__(self, et, ev, tb):
65
- if self.client:
66
- await self.client.__aexit__(et, ev, tb)
67
-
68
- # ============ helpers ============
69
- async def _open_market_and_wait(self, symbol: str, usdt_amount: float, timeout_ms: int) -> Optional[Hold]:
70
- """以市价开仓并在本地流中等待终态。成功返回 Hold;失败/超时返回 None。"""
71
- start = time.time() * 1000
72
- with self.ob_store.orders.watch() as stream:
73
- try:
74
- oid = await self.ourbit.place_order(symbol, "buy", order_type="market", usdt_amount=usdt_amount)
75
- logger.info(f"准备开仓: {symbol} oid={oid}")
76
- except Exception as e:
77
- logger.error(f"开仓下单失败 {symbol}: {e}")
78
- return None
79
-
80
- while True:
81
- remain = timeout_ms - (time.time() * 1000 - start)
82
- if remain <= 0:
83
- logger.warning(f"开仓超时: {symbol} oid={oid}")
84
- return None
85
- try:
86
- change = await asyncio.wait_for(stream.__anext__(), timeout=remain / 1000)
87
- except asyncio.TimeoutError:
88
- logger.warning(f"开仓超时: {symbol} oid={oid}")
89
- return None
90
-
91
- if change.operation != "delete":
92
- continue
93
- data = change.data
94
- if data.get("order_id") != oid:
95
- continue
96
-
97
- state = data.get("state")
98
- if state == "filled":
99
- p = float(data["avg_price"]) ; q = float(data["deal_quantity"]) ; ts = time.time() * 1000
100
- logger.ok(f"建仓成交: {symbol} p={p} q={q}")
101
- return {"symbol": symbol, "status": "filled", "oid": oid, "p": p, "q": q, "filled_ts": ts}
102
- if state in ("canceled", "expired", "rejected", "failed"):
103
- logger.warning(f"开仓失败: {symbol} state={state}")
104
- return None
105
-
106
- async def _close_market_and_wait(self, symbol: str, qty: float, timeout_ms: int) -> bool:
107
- """以市价平仓并等待终态。成功返回 True。"""
108
- start = time.time() * 1000
109
- with self.ob_store.orders.watch() as stream:
110
- try:
111
- oid = await self.ourbit.place_order(symbol, "sell", order_type="market", quantity=qty)
112
- logger.info(f"触发平仓: {symbol} qty={qty} oid={oid}")
113
- except Exception as e:
114
- logger.error(f"平仓下单失败 {symbol}: {e}")
115
- return False
116
-
117
-
118
- while True:
119
- remain = timeout_ms - (time.time() * 1000 - start)
120
- if remain <= 0:
121
- logger.error(f"平仓超时: {symbol} oid={oid}")
122
- return False
123
- try:
124
- change = await asyncio.wait_for(stream.__anext__(), timeout=remain / 1000)
125
- except asyncio.TimeoutError:
126
- logger.error(f"平仓超时: {symbol} oid={oid}")
127
- return False
128
-
129
- if change.operation != "delete":
130
- continue
131
- data = change.data
132
- if data.get("order_id") != oid:
133
- continue
134
-
135
- state = data.get("state")
136
- if state == "filled":
137
- logger.ok(f"平仓完成: {symbol} close_p={data.get('avg_price')}")
138
- return True
139
- if state in ("canceled", "expired", "rejected", "failed"):
140
- logger.error(f"平仓失败: {symbol} state={state}")
141
- return False
142
-
143
- # ============ one-shot test flow ============
144
- async def run_once(self, usdt_amount: float = 10.0):
145
- """一次性流程:开仓 -> 持有 N 秒 -> 平仓。"""
146
- # 1) 开仓
147
- hold = await self._open_market_and_wait(self.SYMBOL, usdt_amount, timeout_ms=self.open_timeout_ms)
148
- if not hold:
149
- logger.warning("开仓未成功,终止本次测试")
150
- return
151
-
152
- # 2) 持有 N 秒
153
- logger.info(f"开始持有 {self.hold_seconds}s: {self.SYMBOL} q={hold['q']} p={hold['p']}")
154
- await asyncio.sleep(self.hold_seconds)
155
-
156
- # 3) 平仓
157
- ok = await self._close_market_and_wait(self.SYMBOL, float(hold["q"]), timeout_ms=self.close_timeout_ms)
158
- if ok:
159
- logger.info("本次测试完成 ✅")
160
- else:
161
- logger.error("本次测试失败 ❌")
162
-
163
- async def run_loop(self, usdt_amount: float = 10.0, interval_seconds: float = 60.0):
164
- """循环执行 run_once,间隔 N 秒。"""
165
- while True:
166
- await self.run_once(usdt_amount)
167
- logger.info(f"等待 {interval_seconds}s 后进行下一轮测试")
168
- await asyncio.sleep(interval_seconds)
169
-
170
-
171
- async def main():
172
- async with AlpineSmokeTest(hold_seconds=5.0) as test:
173
- # await test.run_once(usdt_amount=10.0)
174
- await test.run_loop(usdt_amount=10.0, interval_seconds=5)
175
-
176
-
177
- if __name__ == "__main__":
178
- try:
179
- asyncio.run(main())
180
- except KeyboardInterrupt:
181
- print("\n👋 程序已退出")
182
- except Exception as e:
183
- print(f"❌ 程序异常: {e}")
@@ -1,16 +0,0 @@
1
- import asyncio
2
- import pybotters
3
-
4
-
5
- async def main():
6
- ds = pybotters.store.DataStore(keys=["id"])
7
- loop = asyncio.get_running_loop()
8
-
9
- wait_task = loop.create_task(ds.wait())
10
- loop.call_soon(
11
- ds._insert, [{"id": 1, "val": 1}, {"id": 2, "val": 2}, {"id": 3, "val": 3}]
12
- )
13
- await asyncio.wait_for(wait_task, timeout=5.0)
14
-
15
- ds._insert, [{"id": 1, "val": 1}, {"id": 2, "val": 2}, {"id": 3, "val": 3}]
16
-
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