hyperquant 0.69__tar.gz → 0.71__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.69 → hyperquant-0.71}/PKG-INFO +1 -1
- {hyperquant-0.69 → hyperquant-0.71}/pyproject.toml +1 -1
- hyperquant-0.71/src/hyperquant/broker/bitget.py +107 -0
- hyperquant-0.71/src/hyperquant/broker/lib/util.py +22 -0
- hyperquant-0.71/src/hyperquant/broker/models/bitget.py +283 -0
- hyperquant-0.71/tests/test_bitget.py +59 -0
- {hyperquant-0.69 → hyperquant-0.71}/uv.lock +1 -1
- hyperquant-0.69/src/hyperquant/broker/lib/util.py +0 -9
- {hyperquant-0.69 → hyperquant-0.71}/.gitignore +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/.python-version +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/README.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/apis.json +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/data/alpine_smoke.log +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/data/logs/notikit.log +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/data/logs/test_order_sync.log +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/data/records_swap.csv +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/data/records_swapc.csv +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/doc/edgex_act.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/doc/edgex_debug.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/doc/edgex_order.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/doc/edgex_ws.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/doc/lbank.md +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/pub.sh +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/requirements-dev.lock +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/requirements.lock +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/__init__.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/auth.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/edgex.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/hyperliquid.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/lbank.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/lib/edgex_sign.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/lib/hpstore.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/lib/hyper_types.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/models/edgex.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/models/hyperliquid.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/models/lbank.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/models/ourbit.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/ourbit.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/broker/ws.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/core.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/datavison/_util.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/datavison/binance.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/datavison/coinglass.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/datavison/okx.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/db.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/draw.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/logkit.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/src/hyperquant/notikit.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/tests/test_draw.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/tests/test_edgex.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/tests/test_lbank.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/tests/test_ourbit.py +0 -0
- {hyperquant-0.69 → hyperquant-0.71}/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.71
|
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,107 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import itertools
|
5
|
+
import logging
|
6
|
+
import time
|
7
|
+
from typing import Any, Iterable, Literal
|
8
|
+
|
9
|
+
import pybotters
|
10
|
+
|
11
|
+
from .models.bitget import BitgetDataStore
|
12
|
+
from .lib.util import fmt_value
|
13
|
+
|
14
|
+
logger = logging.getLogger(__name__)
|
15
|
+
|
16
|
+
|
17
|
+
|
18
|
+
class Bitget:
|
19
|
+
"""Bitget public market-data client (REST + WS)."""
|
20
|
+
|
21
|
+
def __init__(
|
22
|
+
self,
|
23
|
+
client: pybotters.Client,
|
24
|
+
*,
|
25
|
+
rest_api: str | None = None,
|
26
|
+
ws_url: str | None = None,
|
27
|
+
) -> None:
|
28
|
+
self.client = client
|
29
|
+
self.store = BitgetDataStore()
|
30
|
+
|
31
|
+
self.rest_api = rest_api or "https://api.bitget.com"
|
32
|
+
self.ws_url = ws_url or "wss://ws.bitget.com/v2/ws/public"
|
33
|
+
self.ws_url_private = ws_url or "wss://ws.bitget.com/v2/ws/private"
|
34
|
+
|
35
|
+
self._ws_app = None
|
36
|
+
|
37
|
+
|
38
|
+
async def __aenter__(self) -> "Bitget":
|
39
|
+
await self.update("detail")
|
40
|
+
return self
|
41
|
+
|
42
|
+
async def __aexit__(self, exc_type, exc, tb) -> None:
|
43
|
+
pass
|
44
|
+
|
45
|
+
async def update(
|
46
|
+
self,
|
47
|
+
update_type: Literal["detail", 'ticker', 'all'] = "all",
|
48
|
+
) -> None:
|
49
|
+
fet = []
|
50
|
+
if update_type in ("detail", "all"):
|
51
|
+
fet.append(
|
52
|
+
self.client.get(
|
53
|
+
f"{self.rest_api}/api/v2/mix/market/contracts?productType=usdt-futures",
|
54
|
+
)
|
55
|
+
)
|
56
|
+
elif update_type in ("ticker", "all"):
|
57
|
+
fet.append(
|
58
|
+
self.client.get(
|
59
|
+
f"{self.rest_api}/api/v2/mix/market/tickers?productType=usdt-futures",
|
60
|
+
)
|
61
|
+
)
|
62
|
+
|
63
|
+
await self.store.initialize(*fet)
|
64
|
+
|
65
|
+
async def place_order(
|
66
|
+
self,
|
67
|
+
symbol: str,
|
68
|
+
*,
|
69
|
+
direction: Literal["buy", "sell", "0", "1"],
|
70
|
+
volume: float,
|
71
|
+
price: float | None = None,
|
72
|
+
order_type: Literal["market", "limit_ioc", "limit_gtc"] = "market",
|
73
|
+
offset_flag: Literal["open", "close", "0", "1"] = "open",
|
74
|
+
exchange_id: str = "Exchange",
|
75
|
+
product_group: str = "SwapU",
|
76
|
+
order_proportion: str = "0.0000",
|
77
|
+
client_order_id: str | None = None,
|
78
|
+
) -> dict[str, Any]:
|
79
|
+
pass
|
80
|
+
|
81
|
+
async def cancel_order(
|
82
|
+
self,
|
83
|
+
order_sys_id: str,
|
84
|
+
*,
|
85
|
+
action_flag: str | int = "1",
|
86
|
+
) -> dict[str, Any]:
|
87
|
+
pass
|
88
|
+
|
89
|
+
|
90
|
+
async def sub_orderbook(self, symbols: list[str], channel: str = 'books1') -> None:
|
91
|
+
"""订阅指定交易对的订单簿(遵循 LBank 协议)。
|
92
|
+
"""
|
93
|
+
|
94
|
+
submsg = {
|
95
|
+
"op": "subscribe",
|
96
|
+
"args": []
|
97
|
+
}
|
98
|
+
for symbol in symbols:
|
99
|
+
submsg["args"].append(
|
100
|
+
{"instType": "SPOT", "channel": channel, "instId": symbol}
|
101
|
+
)
|
102
|
+
|
103
|
+
self.client.ws_connect(
|
104
|
+
self.ws_url,
|
105
|
+
send_json=submsg,
|
106
|
+
hdlr_json=self.store.onmessage
|
107
|
+
)
|
@@ -0,0 +1,22 @@
|
|
1
|
+
from decimal import ROUND_HALF_UP, Decimal
|
2
|
+
|
3
|
+
|
4
|
+
def fmt_value(price: float, tick: float) -> str:
|
5
|
+
tick_dec = Decimal(str(tick))
|
6
|
+
price_dec = Decimal(str(price))
|
7
|
+
return str(
|
8
|
+
(price_dec / tick_dec).quantize(Decimal("1"), rounding=ROUND_HALF_UP) * tick_dec
|
9
|
+
)
|
10
|
+
|
11
|
+
|
12
|
+
def place_to_step(place: int) -> float:
|
13
|
+
"""
|
14
|
+
把 pricePlace / volumePlace 转换成 tick_size / lot_size
|
15
|
+
|
16
|
+
Args:
|
17
|
+
place (int): 小数位数,例如 pricePlace=1, volumePlace=2
|
18
|
+
|
19
|
+
Returns:
|
20
|
+
float: 步长 (step),例如 0.1, 0.01
|
21
|
+
"""
|
22
|
+
return 10 ** (-place)
|
@@ -0,0 +1,283 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
from typing import TYPE_CHECKING, Any, Awaitable
|
5
|
+
from aiohttp import ClientResponse
|
6
|
+
from pybotters import DataStore
|
7
|
+
from pybotters.models.bitget_v2 import BitgetV2DataStore
|
8
|
+
from ..lib.util import place_to_step
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from pybotters.typedefs import Item
|
12
|
+
|
13
|
+
class Detail(DataStore):
|
14
|
+
"""Futures instrument metadata store obtained from the futures instrument endpoint."""
|
15
|
+
|
16
|
+
_KEYS = ["symbol"]
|
17
|
+
|
18
|
+
def _transform(self, entry: dict[str, Any]) -> dict[str, Any] | None:
|
19
|
+
|
20
|
+
step_size = entry.get('volume_place', 1)
|
21
|
+
tick_size = entry.get('price_place', 1)
|
22
|
+
step_size = place_to_step(step_size)
|
23
|
+
tick_size = place_to_step(tick_size)
|
24
|
+
entry['tickSize'] = tick_size
|
25
|
+
entry['stepSize'] = step_size
|
26
|
+
return entry
|
27
|
+
|
28
|
+
def _onresponse(self, data: list[dict[str, Any]] | dict[str, Any] | None) -> None:
|
29
|
+
if not data:
|
30
|
+
self._clear()
|
31
|
+
return
|
32
|
+
entries = data
|
33
|
+
if isinstance(data, dict): # pragma: no cover - defensive guard
|
34
|
+
entries = data.get("data") or []
|
35
|
+
items: list[dict[str, Any]] = []
|
36
|
+
for entry in entries or []:
|
37
|
+
transformed = self._transform(entry)
|
38
|
+
if transformed:
|
39
|
+
items.append(transformed)
|
40
|
+
if not items:
|
41
|
+
self._clear()
|
42
|
+
return
|
43
|
+
self._clear()
|
44
|
+
self._insert(items)
|
45
|
+
|
46
|
+
|
47
|
+
class Book(DataStore):
|
48
|
+
_KEYS = ["t", "s", "S", "p"]
|
49
|
+
|
50
|
+
def _onmessage(self, msg: Item) -> None:
|
51
|
+
action = msg["action"]
|
52
|
+
inst_type = msg["arg"]["instType"]
|
53
|
+
inst_id = msg["arg"]["instId"]
|
54
|
+
|
55
|
+
data_to_insert = []
|
56
|
+
data_to_update = []
|
57
|
+
data_to_delete = []
|
58
|
+
for book in msg["data"]:
|
59
|
+
for side in ("asks", "bids"):
|
60
|
+
for row in book[side]:
|
61
|
+
converted_row = {
|
62
|
+
"t": inst_type,
|
63
|
+
"s": inst_id,
|
64
|
+
"S": side[0],
|
65
|
+
"p": row[0],
|
66
|
+
"q": row[1],
|
67
|
+
}
|
68
|
+
if action == "snapshot":
|
69
|
+
data_to_insert.append(converted_row)
|
70
|
+
elif converted_row["q"] != "0":
|
71
|
+
data_to_update.append(converted_row)
|
72
|
+
else:
|
73
|
+
data_to_delete.append(converted_row)
|
74
|
+
|
75
|
+
# Cleanup on reconnect
|
76
|
+
if action == "snapshot":
|
77
|
+
self._find_and_delete({"t": inst_type, "s": inst_id})
|
78
|
+
|
79
|
+
self._insert(data_to_insert)
|
80
|
+
self._update(data_to_update)
|
81
|
+
self._delete(data_to_delete)
|
82
|
+
|
83
|
+
def sorted(
|
84
|
+
self, query: Item | None = None, limit: int | None = None
|
85
|
+
) -> dict[str, list[Item]]:
|
86
|
+
return self._sorted(
|
87
|
+
item_key="side",
|
88
|
+
item_asc_key="a",
|
89
|
+
item_desc_key="b",
|
90
|
+
sort_key="p",
|
91
|
+
query=query,
|
92
|
+
limit=limit,
|
93
|
+
)
|
94
|
+
|
95
|
+
|
96
|
+
class BitgetDataStore(BitgetV2DataStore):
|
97
|
+
|
98
|
+
def _init(self):
|
99
|
+
super()._init()
|
100
|
+
self._create('detail', datastore_class=Detail)
|
101
|
+
self._create("book", datastore_class=Book)
|
102
|
+
|
103
|
+
async def initialize(self, *aws: Awaitable[ClientResponse]) -> None:
|
104
|
+
for fut in asyncio.as_completed(aws):
|
105
|
+
res = await fut
|
106
|
+
data = await res.json()
|
107
|
+
if res.url.path == '/api/v2/mix/market/contracts':
|
108
|
+
self.detail._onresponse(data)
|
109
|
+
elif res.url.path == '/api/v2/mix/market/tickers':
|
110
|
+
self.ticker._clear()
|
111
|
+
tickers = data.get('data', [])
|
112
|
+
# 为每个ticker添加额外的字段
|
113
|
+
for ticker in tickers:
|
114
|
+
symbol = ticker.get('symbol')
|
115
|
+
ticker['instId'] = symbol
|
116
|
+
ticker['instType'] = 'futures'
|
117
|
+
|
118
|
+
self.ticker._update(tickers)
|
119
|
+
|
120
|
+
@property
|
121
|
+
def detail(self) -> Detail:
|
122
|
+
"""
|
123
|
+
_key: symbol
|
124
|
+
|
125
|
+
Data Structure:
|
126
|
+
|
127
|
+
.. code:: json
|
128
|
+
|
129
|
+
[
|
130
|
+
{
|
131
|
+
"symbol": "BTCUSDT",
|
132
|
+
"baseCoin": "BTC",
|
133
|
+
"quoteCoin": "USDT",
|
134
|
+
"buyLimitPriceRatio": "0.9",
|
135
|
+
"sellLimitPriceRatio": "0.9",
|
136
|
+
"feeRateUpRatio": "0.1",
|
137
|
+
"makerFeeRate": "0.0004",
|
138
|
+
"takerFeeRate": "0.0006",
|
139
|
+
"openCostUpRatio": "0.1",
|
140
|
+
"supportMarginCoins": [
|
141
|
+
"USDT"
|
142
|
+
],
|
143
|
+
"minTradeNum": "0.01",
|
144
|
+
"priceEndStep": "1",
|
145
|
+
"volumePlace": "2",
|
146
|
+
"stepSize": "0.01",
|
147
|
+
"tickSize": "0.1",
|
148
|
+
"pricePlace": "1",
|
149
|
+
"sizeMultiplier": "0.01",
|
150
|
+
"symbolType": "perpetual",
|
151
|
+
"minTradeUSDT": "5",
|
152
|
+
"maxSymbolOrderNum": "999999",
|
153
|
+
"maxProductOrderNum": "999999",
|
154
|
+
"maxPositionNum": "150",
|
155
|
+
"symbolStatus": "normal",
|
156
|
+
"offTime": "-1",
|
157
|
+
"limitOpenTime": "-1",
|
158
|
+
"deliveryTime": "",
|
159
|
+
"deliveryStartTime": "",
|
160
|
+
"launchTime": "",
|
161
|
+
"fundInterval": "8",
|
162
|
+
"minLever": "1",
|
163
|
+
"maxLever": "125",
|
164
|
+
"posLimit": "0.05",
|
165
|
+
"maintainTime": "1680165535278",
|
166
|
+
"maxMarketOrderQty": "220",
|
167
|
+
"maxOrderQty": "1200"
|
168
|
+
}]
|
169
|
+
|
170
|
+
"""
|
171
|
+
return self._get('detail')
|
172
|
+
|
173
|
+
@property
|
174
|
+
def ticker(self) -> DataStore:
|
175
|
+
"""
|
176
|
+
_KEYS = ["instType", "instId"]
|
177
|
+
|
178
|
+
Data Structure:
|
179
|
+
|
180
|
+
.. code:: json
|
181
|
+
|
182
|
+
[
|
183
|
+
{
|
184
|
+
"symbol": "BTCUSDT",
|
185
|
+
"lastPr": "111534.6",
|
186
|
+
"askPr": "111534.6",
|
187
|
+
"bidPr": "111534.5",
|
188
|
+
"bidSz": "23.7924",
|
189
|
+
"askSz": "8.1762",
|
190
|
+
"high24h": "112300",
|
191
|
+
"low24h": "109136.2",
|
192
|
+
"ts": "1759115725508",
|
193
|
+
"change24h": "0.01906",
|
194
|
+
"baseVolume": "35520.11438048",
|
195
|
+
"quoteVolume": "3932280581.066103549",
|
196
|
+
"usdtVolume": "3932280581.066103549",
|
197
|
+
"openUtc": "112100",
|
198
|
+
"changeUtc24h": "-0.00504",
|
199
|
+
"indexPrice": "111587.6090439271505504",
|
200
|
+
"fundingRate": "-0.000002",
|
201
|
+
"holdingAmount": "66775.1917",
|
202
|
+
"deliveryStartTime": null,
|
203
|
+
"deliveryTime": null,
|
204
|
+
"deliveryStatus": "",
|
205
|
+
"open24h": "109448.3",
|
206
|
+
"markPrice": "111537",
|
207
|
+
"instId": "BTCUSDT",
|
208
|
+
"instType": "futures"
|
209
|
+
}
|
210
|
+
]
|
211
|
+
"""
|
212
|
+
return self._get('ticker')
|
213
|
+
|
214
|
+
@property
|
215
|
+
def orders(self) -> DataStore:
|
216
|
+
"""
|
217
|
+
_KEYS = ["instType", "instId", "orderId"]
|
218
|
+
.. code:: json
|
219
|
+
|
220
|
+
[
|
221
|
+
{
|
222
|
+
"instType": "futures",
|
223
|
+
"instId": "BTCUSDT",
|
224
|
+
"orderId": "1",
|
225
|
+
"clientOid": "1",
|
226
|
+
"size": "8.0000",
|
227
|
+
"newSize": "500.0000",
|
228
|
+
"notional": "8.000000",
|
229
|
+
"orderType": "market",
|
230
|
+
"force": "gtc",
|
231
|
+
"side": "buy",
|
232
|
+
"fillPrice": "26256.0",
|
233
|
+
"tradeId": "1",
|
234
|
+
"baseVolume": "0.0003",
|
235
|
+
"fillTime": "1695797773286",
|
236
|
+
"fillFee": "-0.00000018",
|
237
|
+
"fillFeeCoin": "BTC",
|
238
|
+
"tradeScope": "T",
|
239
|
+
"accBaseVolume": "0.0003",
|
240
|
+
"priceAvg": "26256.0",
|
241
|
+
"status": "partially_filled",
|
242
|
+
"cTime": "1695797773257",
|
243
|
+
"uTime": "1695797773326",
|
244
|
+
"stpMode": "cancel_taker",
|
245
|
+
"feeDetail": [
|
246
|
+
{
|
247
|
+
"feeCoin": "BTC",
|
248
|
+
"fee": "-0.00000018"
|
249
|
+
}
|
250
|
+
],
|
251
|
+
"enterPointSource": "WEB"
|
252
|
+
}
|
253
|
+
]
|
254
|
+
"""
|
255
|
+
return self._get('orders')
|
256
|
+
|
257
|
+
@property
|
258
|
+
def book(self) -> DataStore:
|
259
|
+
"""
|
260
|
+
_KEYS = ["t", "s", "S", "p"]
|
261
|
+
|
262
|
+
Data Structure:
|
263
|
+
|
264
|
+
.. code:: json
|
265
|
+
|
266
|
+
[
|
267
|
+
{
|
268
|
+
"t": "futures",
|
269
|
+
"s": "BTCUSDT",
|
270
|
+
"S": "a",
|
271
|
+
"p": "111534.6",
|
272
|
+
"q": "8.1762"
|
273
|
+
},
|
274
|
+
{
|
275
|
+
"t": "futures",
|
276
|
+
"s": "BTCUSDT",
|
277
|
+
"S": "b",
|
278
|
+
"p": "111534.5",
|
279
|
+
"q": "23.7924"
|
280
|
+
}
|
281
|
+
]
|
282
|
+
"""
|
283
|
+
return self._get("book")
|
@@ -0,0 +1,59 @@
|
|
1
|
+
import pybotters
|
2
|
+
from hyperquant.broker.models.bitget import BitgetDataStore
|
3
|
+
|
4
|
+
|
5
|
+
async def test_update():
|
6
|
+
async with pybotters.Client() as client:
|
7
|
+
store = BitgetDataStore()
|
8
|
+
# await store.initialize(
|
9
|
+
# client.get("https://api.bitget.com/api/v2/mix/market/contracts?productType=usdt-futures")
|
10
|
+
# )
|
11
|
+
# print(store.detail.find())
|
12
|
+
await store.initialize(
|
13
|
+
client.get(
|
14
|
+
"https://api.bitget.com/api/v2/mix/market/tickers?productType=usdt-futures"
|
15
|
+
)
|
16
|
+
)
|
17
|
+
print(store.ticker.find({"symbol": "BTCUSDT"}))
|
18
|
+
|
19
|
+
|
20
|
+
async def subscribe_book():
|
21
|
+
|
22
|
+
async with pybotters.Client() as client:
|
23
|
+
store = BitgetDataStore()
|
24
|
+
client.ws_connect(
|
25
|
+
"wss://ws.bitget.com/v2/ws/public",
|
26
|
+
send_json={
|
27
|
+
"op": "subscribe",
|
28
|
+
"args": [
|
29
|
+
{"instType": "SPOT", "channel": "books1", "instId": "BTCUSDT"}
|
30
|
+
]
|
31
|
+
},
|
32
|
+
hdlr_json=store.onmessage
|
33
|
+
)
|
34
|
+
|
35
|
+
while True:
|
36
|
+
await asyncio.sleep(1)
|
37
|
+
print(store.book.find())
|
38
|
+
|
39
|
+
from hyperquant.broker.bitget import Bitget
|
40
|
+
async def test_broker_update():
|
41
|
+
|
42
|
+
async with pybotters.Client() as client:
|
43
|
+
bg = Bitget(client)
|
44
|
+
store = BitgetDataStore()
|
45
|
+
await bg.update('all')
|
46
|
+
print(bg.store.detail.find())
|
47
|
+
|
48
|
+
async def test_broker_sub_orderbook():
|
49
|
+
async with pybotters.Client() as client:
|
50
|
+
bg = Bitget(client)
|
51
|
+
await bg.sub_orderbook(['BTCUSDT', 'ETHUSDT'])
|
52
|
+
while True:
|
53
|
+
await asyncio.sleep(1)
|
54
|
+
print(bg.store.book.find())
|
55
|
+
|
56
|
+
if __name__ == "__main__":
|
57
|
+
import asyncio
|
58
|
+
|
59
|
+
asyncio.run(test_broker_sub_orderbook())
|
@@ -1,9 +0,0 @@
|
|
1
|
-
from decimal import ROUND_HALF_UP, Decimal
|
2
|
-
|
3
|
-
|
4
|
-
def fmt_value(price: float, tick: float) -> str:
|
5
|
-
tick_dec = Decimal(str(tick))
|
6
|
-
price_dec = Decimal(str(price))
|
7
|
-
return str(
|
8
|
-
(price_dec / tick_dec).quantize(Decimal("1"), rounding=ROUND_HALF_UP) * tick_dec
|
9
|
-
)
|
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
|
File without changes
|
File without changes
|