hyperquant 0.74__tar.gz → 0.75__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.
- {hyperquant-0.74 → hyperquant-0.75}/PKG-INFO +1 -1
- {hyperquant-0.74 → hyperquant-0.75}/pyproject.toml +1 -1
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lbank.py +26 -4
- {hyperquant-0.74 → hyperquant-0.75}/tests/test_lbank.py +55 -105
- {hyperquant-0.74 → hyperquant-0.75}/uv.lock +1 -1
- {hyperquant-0.74 → hyperquant-0.75}/.gitignore +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/.python-version +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/README.md +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/apis.json +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/data/alpine_smoke.log +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/data/logs/notikit.log +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/data/logs/test_order_sync.log +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/data/records_swap.csv +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/data/records_swapc.csv +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/doc/lbank.md +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/pub.sh +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/requirements-dev.lock +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/requirements.lock +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/__init__.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/bitget.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/lib/util.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/bitget.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/broker/ws.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/core.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/db.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/draw.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/logkit.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/src/hyperquant/notikit.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/tests/test_bitget.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/tests/test_draw.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/tests/test_edgex.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/tests/test_ourbit.py +0 -0
- {hyperquant-0.74 → hyperquant-0.75}/tests/tmp.py +0 -0
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: hyperquant
|
3
|
-
Version: 0.
|
3
|
+
Version: 0.75
|
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
|
@@ -223,7 +223,31 @@ class Lbank:
|
|
223
223
|
page_index: int = 1,
|
224
224
|
page_size: int = 20,
|
225
225
|
) -> dict[str, Any]:
|
226
|
-
"""
|
226
|
+
"""
|
227
|
+
返回值示例:
|
228
|
+
|
229
|
+
.. code:: json
|
230
|
+
|
231
|
+
{
|
232
|
+
"order_id": "1000632478428573",
|
233
|
+
"instrument_id": "SOLUSDT",
|
234
|
+
"position_id": "1000632478428573",
|
235
|
+
"direction": "0",
|
236
|
+
"offset_flag": "0",
|
237
|
+
"trade_time": 1760123456,
|
238
|
+
"avg_price": 182.5,
|
239
|
+
"volume": 0.03,
|
240
|
+
"turnover": 5.475,
|
241
|
+
"fee": 0.003285,
|
242
|
+
"trade_count": 1
|
243
|
+
}
|
244
|
+
|
245
|
+
如果没有订单成交返回
|
246
|
+
{
|
247
|
+
"order_id": "1000632478428573",
|
248
|
+
"trade_count": 0
|
249
|
+
}
|
250
|
+
"""
|
227
251
|
|
228
252
|
if not order_id:
|
229
253
|
raise ValueError("order_id is required to query order statistics")
|
@@ -440,9 +464,7 @@ class Lbank:
|
|
440
464
|
# logger.warning("Price is ignored for market orders")
|
441
465
|
pass
|
442
466
|
|
443
|
-
|
444
|
-
# payload["LocalID"] = client_order_id
|
445
|
-
print(payload)
|
467
|
+
|
446
468
|
res = await self.client.post(
|
447
469
|
f"{self.front_api}/cfd/cff/v1/SendOrderInsert",
|
448
470
|
json=payload,
|
@@ -148,44 +148,17 @@ async def order_sync_polling(
|
|
148
148
|
volume: float | None = None,
|
149
149
|
window_sec: float = 5.0,
|
150
150
|
grace_sec: float = 5.0,
|
151
|
-
poll_interval: float = 0.5
|
152
|
-
)
|
151
|
+
poll_interval: float = 0.5
|
152
|
+
) :
|
153
|
+
|
153
154
|
"""
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
- 返回值示例:
|
159
|
-
.. code:: json
|
160
|
-
|
161
|
-
{
|
162
|
-
"position_id": "1000633222380983",
|
163
|
-
"bus_id": "1001770970175249",
|
164
|
-
"symbol": "SOLUSDT",
|
165
|
-
"side": "long",
|
166
|
-
"quantity": "0.06",
|
167
|
-
"available": "0.0",
|
168
|
-
"avg_price": "183.62",
|
169
|
-
"entry_price": "183.62",
|
170
|
-
"leverage": "100.0",
|
171
|
-
"liquidation_price": "0",
|
172
|
-
"margin_used": "0.110175",
|
173
|
-
"unrealized_pnl": "0.0",
|
174
|
-
"realized_pnl": "0.0",
|
175
|
-
"update_time": "1760195121",
|
176
|
-
"insert_time": "1758806193"
|
177
|
-
}
|
155
|
+
返回
|
156
|
+
{'order_id': '1000633291976722', 'instrument_id': 'SOLUSDT', 'position_id': '1000633291830781', 'direction': '1', 'offset_flag': '0', 'trade_time': 1760203736, 'avg_price': 183.95000000000002, 'volume': 0.03, 'turnover': 5.5185, 'fee': 0.0033111, 'trade_count': 1}
|
157
|
+
或者
|
158
|
+
{'order_id': '1000633291976722', 'trade_count': 0}
|
178
159
|
"""
|
179
160
|
|
180
161
|
norm_type = order_type.lower()
|
181
|
-
if norm_type not in {"market", "limit_gtc", "limit_ioc"}:
|
182
|
-
raise ValueError(f"unsupported order_type: {order_type}")
|
183
|
-
|
184
|
-
if norm_type != "market" and price is None:
|
185
|
-
raise ValueError("price is required for limit orders")
|
186
|
-
if volume is None:
|
187
|
-
raise ValueError("volume is required for LBank orders")
|
188
|
-
|
189
162
|
started = int(time.time() * 1000)
|
190
163
|
resp = await broker.place_order(
|
191
164
|
symbol,
|
@@ -196,90 +169,66 @@ async def order_sync_polling(
|
|
196
169
|
)
|
197
170
|
|
198
171
|
latency = int(time.time() * 1000) - started
|
199
|
-
print(f"下单延迟 {latency} ms")
|
200
172
|
|
201
|
-
order_id = (
|
202
|
-
|
203
|
-
|
204
|
-
or resp.get("order_id")
|
205
|
-
or resp.get("orderId")
|
206
|
-
)
|
173
|
+
order_id = resp.get("orderSysID")
|
174
|
+
# print(f"下单延迟 {latency} ms, 订单号: {order_id}")
|
175
|
+
|
207
176
|
if not order_id:
|
208
177
|
raise RuntimeError(f"place_order 返回缺少 order_id: {resp}")
|
209
178
|
|
210
|
-
position_id = (
|
211
|
-
resp.get("PositionID")
|
212
|
-
or resp.get("positionID")
|
213
|
-
or resp.get("positionId")
|
214
|
-
)
|
215
179
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
180
|
+
position_id = resp.get("positionID")
|
181
|
+
if not position_id:
|
182
|
+
raise RuntimeError(f"place_order 返回缺少 position_id: {resp}")
|
183
|
+
|
184
|
+
if 'volumeRemain' in resp and float(resp['volumeRemain']) == 0:
|
185
|
+
return {
|
186
|
+
"order_id": order_id,
|
187
|
+
"trade_count": 1,
|
188
|
+
"volume": volume,
|
189
|
+
"avg_price": float(resp.get('openPrice', 0)),
|
190
|
+
"turnover": float(resp.get('turnover', 0)),
|
191
|
+
"fee": float(resp.get('fee', 0)),
|
192
|
+
"position_id": position_id,
|
193
|
+
"direction": direction,
|
194
|
+
"offset_flag": resp.get('offsetFlag', '0'),
|
195
|
+
"trade_time": resp.get('updateTime'),
|
196
|
+
}
|
197
|
+
|
198
|
+
trade_resp = None
|
199
|
+
|
200
|
+
async def _poll_orders(timeout_sec: float) -> dict | None:
|
201
|
+
nonlocal trade_resp
|
237
202
|
async with asyncio.timeout(timeout_sec):
|
238
203
|
while True:
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
continue
|
244
|
-
snapshot = broker.store.orders.get({"order_id": order_id})
|
245
|
-
if snapshot is None:
|
246
|
-
if not order_seen and not allow_symbol_fallback:
|
247
|
-
await asyncio.sleep(poll_interval)
|
248
|
-
continue
|
249
|
-
pos_snapshot = await _refresh_position(allow_symbol_fallback=allow_symbol_fallback)
|
250
|
-
if pos_snapshot is not None:
|
251
|
-
return pos_snapshot
|
252
|
-
await asyncio.sleep(poll_interval)
|
253
|
-
continue
|
254
|
-
order_seen = True
|
255
|
-
position_id = position_id or snapshot.get("position_id")
|
204
|
+
trade_resp = await broker.query_order(order_id)
|
205
|
+
traded_volume = float(trade_resp.get("volume", 0))
|
206
|
+
if traded_volume == volume:
|
207
|
+
return
|
256
208
|
await asyncio.sleep(poll_interval)
|
257
209
|
|
258
210
|
try:
|
259
|
-
|
260
|
-
|
261
|
-
return polled_position
|
211
|
+
await _poll_orders(window_sec)
|
212
|
+
|
262
213
|
except TimeoutError:
|
263
214
|
pass
|
264
215
|
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
break
|
269
|
-
except Exception as e:
|
270
|
-
if '不存在' in str(e):
|
216
|
+
for _attempt in range(3):
|
217
|
+
try:
|
218
|
+
await broker.cancel_order(order_id)
|
271
219
|
break
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
220
|
+
except Exception as e:
|
221
|
+
if '不存在' in str(e):
|
222
|
+
break
|
223
|
+
else:
|
224
|
+
print(f'撤单失败, 重试 {_attempt+1}/3: {e}')
|
225
|
+
|
226
|
+
try:
|
227
|
+
await _poll_orders(window_sec)
|
228
|
+
except TimeoutError:
|
229
|
+
pass
|
280
230
|
|
281
|
-
|
282
|
-
return await _refresh_position(allow_symbol_fallback=True)
|
231
|
+
return trade_resp
|
283
232
|
|
284
233
|
|
285
234
|
async def test_order_sync_polling():
|
@@ -288,7 +237,8 @@ async def test_order_sync_polling():
|
|
288
237
|
await lb.sub_orderbook(["SOLUSDT"], limit=1)
|
289
238
|
await lb.store.book.wait()
|
290
239
|
bid0 = float(lb.store.book.find({"s": "SOLUSDT", 'S': 'b'})[0]['p'])
|
291
|
-
bid0 = bid0 - 0.
|
240
|
+
bid0 = bid0 - 0.01
|
241
|
+
# bid0 = bid0 - 1
|
292
242
|
print(bid0)
|
293
243
|
|
294
244
|
result = await order_sync_polling(
|
@@ -307,7 +257,7 @@ async def test_order_sync_polling():
|
|
307
257
|
async def test_query_order():
|
308
258
|
async with pybotters.Client(apis='./apis.json') as client:
|
309
259
|
async with Lbank(client) as lb:
|
310
|
-
res = await lb.query_order("
|
260
|
+
res = await lb.query_order("1000633284579483")
|
311
261
|
print(res)
|
312
262
|
|
313
263
|
if __name__ == "__main__":
|
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
|
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
|
File without changes
|