hyperquant 0.25__py3-none-any.whl → 0.31__py3-none-any.whl
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/__init__.py +3 -1
- hyperquant/broker/auth.py +51 -0
- hyperquant/broker/hyperliquid.py +67 -35
- hyperquant/broker/models/hyperliquid.py +284 -0
- hyperquant/broker/models/ourbit.py +502 -0
- hyperquant/broker/ourbit.py +247 -0
- hyperquant/broker/ws.py +12 -0
- hyperquant/core.py +77 -26
- {hyperquant-0.25.dist-info → hyperquant-0.31.dist-info}/METADATA +2 -2
- hyperquant-0.31.dist-info/RECORD +21 -0
- hyperquant-0.25.dist-info/RECORD +0 -16
- {hyperquant-0.25.dist-info → hyperquant-0.31.dist-info}/WHEEL +0 -0
@@ -0,0 +1,502 @@
|
|
1
|
+
from __future__ import annotations
|
2
|
+
|
3
|
+
import asyncio
|
4
|
+
import logging
|
5
|
+
from typing import TYPE_CHECKING, Any, Awaitable
|
6
|
+
|
7
|
+
import aiohttp
|
8
|
+
from pybotters.store import DataStore, DataStoreCollection
|
9
|
+
|
10
|
+
if TYPE_CHECKING:
|
11
|
+
from pybotters.typedefs import Item
|
12
|
+
from pybotters.ws import ClientWebSocketResponse
|
13
|
+
|
14
|
+
|
15
|
+
logger = logging.getLogger(__name__)
|
16
|
+
|
17
|
+
|
18
|
+
class Book(DataStore):
|
19
|
+
"""深度数据存储类,用于处理订单簿深度信息
|
20
|
+
|
21
|
+
Channel: push.depth.step
|
22
|
+
|
23
|
+
用于存储和管理订单簿深度数据,包含买卖盘的价格和数量信息
|
24
|
+
Keys: ["symbol", "side", "px"]
|
25
|
+
- symbol: 交易对符号
|
26
|
+
- side: 买卖方向 (A: ask卖出, B: bid买入)
|
27
|
+
- px: 价格
|
28
|
+
|
29
|
+
|
30
|
+
"""
|
31
|
+
|
32
|
+
_KEYS = ["symbol", "side", "px"]
|
33
|
+
|
34
|
+
def _init(self) -> None:
|
35
|
+
# super().__init__()
|
36
|
+
self._time: int | None = None
|
37
|
+
|
38
|
+
def _on_message(self, msg: dict[str, Any]) -> None:
|
39
|
+
|
40
|
+
symbol = msg.get("symbol")
|
41
|
+
data = msg.get("data", {})
|
42
|
+
asks = data.get("asks", [])
|
43
|
+
bids = data.get("bids", [])
|
44
|
+
timestamp = data.get("ct") # 使用服务器时间
|
45
|
+
|
46
|
+
data_to_insert: list[Item] = []
|
47
|
+
|
48
|
+
# 先删除旧的订单簿数据
|
49
|
+
self._find_and_delete({"symbol": symbol})
|
50
|
+
|
51
|
+
# 处理买卖盘数据
|
52
|
+
for side_id, levels in (("B", bids), ("A", asks)):
|
53
|
+
for level in levels:
|
54
|
+
# level格式: [price, size, count]
|
55
|
+
if len(level) >= 3:
|
56
|
+
price, size, count = level[0:3]
|
57
|
+
data_to_insert.append(
|
58
|
+
{
|
59
|
+
"symbol": symbol,
|
60
|
+
"side": side_id,
|
61
|
+
"px": str(price),
|
62
|
+
"sz": str(size),
|
63
|
+
"count": count,
|
64
|
+
}
|
65
|
+
)
|
66
|
+
|
67
|
+
# 插入新的订单簿数据
|
68
|
+
self._insert(data_to_insert)
|
69
|
+
self._time = timestamp
|
70
|
+
|
71
|
+
@property
|
72
|
+
def time(self) -> int | None:
|
73
|
+
"""返回最后更新时间"""
|
74
|
+
return self._time
|
75
|
+
|
76
|
+
@property
|
77
|
+
def sorted(self) -> dict[str, list[Item]]:
|
78
|
+
"""获取排序后的订单簿数据
|
79
|
+
|
80
|
+
Returns:
|
81
|
+
返回按价格排序的买卖盘数据,卖盘升序,买盘降序
|
82
|
+
|
83
|
+
.. code-block:: python
|
84
|
+
|
85
|
+
{
|
86
|
+
"asks": [
|
87
|
+
{"symbol": "BTC_USDT", "side": "A", "px": "110152.5", "sz": "53539", "count": 1},
|
88
|
+
{"symbol": "BTC_USDT", "side": "A", "px": "110152.6", "sz": "95513", "count": 2}
|
89
|
+
],
|
90
|
+
"bids": [
|
91
|
+
{"symbol": "BTC_USDT", "side": "B", "px": "110152.4", "sz": "76311", "count": 1},
|
92
|
+
{"symbol": "BTC_USDT", "side": "B", "px": "110152.3", "sz": "104688", "count": 2}
|
93
|
+
]
|
94
|
+
}
|
95
|
+
"""
|
96
|
+
return self._sorted(
|
97
|
+
item_key="side",
|
98
|
+
item_asc_key="A", # asks 升序
|
99
|
+
item_desc_key="B", # bids 降序
|
100
|
+
sort_key="px",
|
101
|
+
)
|
102
|
+
|
103
|
+
|
104
|
+
class Ticker(DataStore):
|
105
|
+
_KEYS = ["symbol"]
|
106
|
+
|
107
|
+
def _on_message(self, data: dict[str, Any]):
|
108
|
+
self._onresponse(data)
|
109
|
+
|
110
|
+
def _onresponse(self, data: dict[str, Any]):
|
111
|
+
tickers = data.get("data", [])
|
112
|
+
if tickers:
|
113
|
+
data_to_insert: list[Item] = []
|
114
|
+
for ticker in tickers:
|
115
|
+
ticker: dict[str, Any] = ticker
|
116
|
+
for ticker in tickers:
|
117
|
+
data_to_insert.append(
|
118
|
+
{
|
119
|
+
"amount24": ticker.get("amount24"),
|
120
|
+
"fair_price": ticker.get("fairPrice"),
|
121
|
+
"high24_price": ticker.get("high24Price"),
|
122
|
+
"index_price": ticker.get("indexPrice"),
|
123
|
+
"last_price": ticker.get("lastPrice"),
|
124
|
+
"lower24_price": ticker.get("lower24Price"),
|
125
|
+
"max_bid_price": ticker.get("maxBidPrice"),
|
126
|
+
"min_ask_price": ticker.get("minAskPrice"),
|
127
|
+
"rise_fall_rate": ticker.get("riseFallRate"),
|
128
|
+
"symbol": ticker.get("symbol"),
|
129
|
+
"timestamp": ticker.get("timestamp"),
|
130
|
+
"volume24": ticker.get("volume24"),
|
131
|
+
}
|
132
|
+
)
|
133
|
+
# self._clear()
|
134
|
+
self._insert(data_to_insert)
|
135
|
+
|
136
|
+
|
137
|
+
class Orders(DataStore):
|
138
|
+
_KEYS = ["order_id"]
|
139
|
+
|
140
|
+
# {'success': True, 'code': 0, 'data': [{'orderId': '219108574599630976', 'symbol': 'SOL_USDT', 'positionId': 0, 'price': 190, 'priceStr': '190', 'vol': 1, 'leverage': 20, 'side': 1, 'category': 1, 'orderType': 1, 'dealAvgPrice': 0, 'dealAvgPriceStr': '0', 'dealVol': 0, 'orderMargin': 0.09652, 'takerFee': 0, 'makerFee': 0, 'profit': 0, 'feeCurrency': 'USDT', 'openType': 1, 'state': 2, 'externalOid': '_m_2228b23a75204e1982b301e44d439cbb', 'errorCode': 0, 'usedMargin': 0, 'createTime': 1756277955008, 'updateTime': 1756277955037, 'positionMode': 1, 'version': 1, 'showCancelReason': 0, 'showProfitRateShare': 0, 'voucher': False}]}
|
141
|
+
def _onresponse(self, data: dict[str, Any]):
|
142
|
+
orders = data.get("data", [])
|
143
|
+
if orders:
|
144
|
+
data_to_insert: list[Item] = []
|
145
|
+
for order in orders:
|
146
|
+
order: dict[str, Any] = order
|
147
|
+
|
148
|
+
data_to_insert.append(
|
149
|
+
{
|
150
|
+
"order_id": order.get("orderId"),
|
151
|
+
"symbol": order.get("symbol"),
|
152
|
+
"px": order.get("priceStr"),
|
153
|
+
"vol": order.get("vol"),
|
154
|
+
"lev": order.get("leverage"),
|
155
|
+
"side": "buy" if order.get("side") == 1 else "sell",
|
156
|
+
"deal_vol": order.get("dealVol"),
|
157
|
+
"deal_avg_px": order.get("dealAvgPriceStr"),
|
158
|
+
"create_ts": order.get("createTime"),
|
159
|
+
"update_ts": order.get("updateTime"),
|
160
|
+
}
|
161
|
+
)
|
162
|
+
|
163
|
+
self._clear()
|
164
|
+
self._update(data_to_insert)
|
165
|
+
|
166
|
+
|
167
|
+
class Detail(DataStore):
|
168
|
+
_KEYS = ["symbol"]
|
169
|
+
|
170
|
+
def _on_message(self, data: dict[str, Any]):
|
171
|
+
self._onresponse(data)
|
172
|
+
|
173
|
+
def _onresponse(self, data: dict[str, Any]):
|
174
|
+
details: dict = data.get("data", {})
|
175
|
+
data_to_insert: list[Item] = []
|
176
|
+
if details:
|
177
|
+
for detail in details:
|
178
|
+
data_to_insert.append(
|
179
|
+
{
|
180
|
+
"symbol": detail.get("symbol"),
|
181
|
+
"ft": detail.get("ft"),
|
182
|
+
"max_lev": detail.get("maxL"),
|
183
|
+
"tick_size": detail.get("pu"),
|
184
|
+
"vol_unit": detail.get("vu"),
|
185
|
+
"io": detail.get("io"),
|
186
|
+
"contract_sz": detail.get("cs"),
|
187
|
+
"minv": detail.get("minV"),
|
188
|
+
"maxv": detail.get("maxV")
|
189
|
+
}
|
190
|
+
)
|
191
|
+
self._update(data_to_insert)
|
192
|
+
|
193
|
+
class Position(DataStore):
|
194
|
+
_KEYS = ["position_id"]
|
195
|
+
# {"success":true,"code":0,"data":[{"positionId":5355366,"symbol":"SOL_USDT","positionType":1,"openType":1,"state":1,"holdVol":1,"frozenVol":0,"closeVol":0,"holdAvgPrice":203.44,"holdAvgPriceFullyScale":"203.44","openAvgPrice":203.44,"openAvgPriceFullyScale":"203.44","closeAvgPrice":0,"liquidatePrice":194.07,"oim":0.10253376,"im":0.10253376,"holdFee":0,"realised":-0.0008,"leverage":20,"marginRatio":0.0998,"createTime":1756275984696,"updateTime":1756275984696,"autoAddIm":false,"version":1,"profitRatio":0,"newOpenAvgPrice":203.44,"newCloseAvgPrice":0,"closeProfitLoss":0,"fee":0.00081376}]}
|
196
|
+
def _onresponse(self, data: dict[str, Any]):
|
197
|
+
positions = data.get("data", [])
|
198
|
+
if positions:
|
199
|
+
data_to_insert: list[Item] = []
|
200
|
+
for position in positions:
|
201
|
+
position: dict[str, Any] = position
|
202
|
+
|
203
|
+
data_to_insert.append(
|
204
|
+
{
|
205
|
+
"position_id": position.get("positionId"),
|
206
|
+
"symbol": position.get("symbol"),
|
207
|
+
"side": "short" if position.get("positionType") == 2 else "long",
|
208
|
+
"open_type": position.get("openType"),
|
209
|
+
"state": position.get("state"),
|
210
|
+
"hold_vol": position.get("holdVol"),
|
211
|
+
"frozen_vol": position.get("frozenVol"),
|
212
|
+
"close_vol": position.get("closeVol"),
|
213
|
+
"hold_avg_price": position.get("holdAvgPriceFullyScale"),
|
214
|
+
"open_avg_price": position.get("openAvgPriceFullyScale"),
|
215
|
+
"close_avg_price": str(position.get("closeAvgPrice")),
|
216
|
+
"liquidate_price": str(position.get("liquidatePrice")),
|
217
|
+
"oim": position.get("oim"),
|
218
|
+
"im": position.get("im"),
|
219
|
+
"hold_fee": position.get("holdFee"),
|
220
|
+
"realised": position.get("realised"),
|
221
|
+
"leverage": position.get("leverage"),
|
222
|
+
"margin_ratio": position.get("marginRatio"),
|
223
|
+
"create_ts": position.get("createTime"),
|
224
|
+
"update_ts": position.get("updateTime"),
|
225
|
+
}
|
226
|
+
)
|
227
|
+
|
228
|
+
self._clear()
|
229
|
+
self._insert(data_to_insert)
|
230
|
+
|
231
|
+
class Balance(DataStore):
|
232
|
+
_KEYS = ["currency"]
|
233
|
+
|
234
|
+
def _onresponse(self, data: dict[str, Any]):
|
235
|
+
balances = data.get("data", [])
|
236
|
+
if balances:
|
237
|
+
data_to_insert: list[Item] = []
|
238
|
+
for balance in balances:
|
239
|
+
balance: dict[str, Any] = balance
|
240
|
+
data_to_insert.append({
|
241
|
+
"currency": balance.get("currency"),
|
242
|
+
"position_margin": balance.get("positionMargin"),
|
243
|
+
"available_balance": balance.get("availableBalance"),
|
244
|
+
"cash_balance": balance.get("cashBalance"),
|
245
|
+
"frozen_balance": balance.get("frozenBalance"),
|
246
|
+
"equity": balance.get("equity"),
|
247
|
+
"unrealized": balance.get("unrealized"),
|
248
|
+
"bonus": balance.get("bonus"),
|
249
|
+
"last_bonus": balance.get("lastBonus"),
|
250
|
+
"wallet_balance": balance.get("walletBalance"),
|
251
|
+
"voucher": balance.get("voucher"),
|
252
|
+
"voucher_using": balance.get("voucherUsing"),
|
253
|
+
})
|
254
|
+
self._clear()
|
255
|
+
self._insert(data_to_insert)
|
256
|
+
|
257
|
+
class OurbitSwapDataStore(DataStoreCollection):
|
258
|
+
"""
|
259
|
+
Ourbit DataStoreCollection
|
260
|
+
|
261
|
+
REST API:
|
262
|
+
- 地址: https://futures.ourbit.com
|
263
|
+
- 合约详情
|
264
|
+
GET /api/v1/contract/detailV2?client=web
|
265
|
+
- ticker
|
266
|
+
GET /api/v1/contract/ticker
|
267
|
+
- open_orders
|
268
|
+
GET /api/v1/private/order/list/open_orders?page_size=200
|
269
|
+
- open_positions
|
270
|
+
GET /api/v1/private/position/open_positions
|
271
|
+
|
272
|
+
WebSocket API:
|
273
|
+
- 地址: wss://futures.ourbit.com/edge or /ws
|
274
|
+
- 支持频道:
|
275
|
+
* 深度数据(Book): push.depth.step
|
276
|
+
* 行情数据(Ticker): push.tickers
|
277
|
+
|
278
|
+
示例订阅 JSON:
|
279
|
+
|
280
|
+
.. code:: json
|
281
|
+
|
282
|
+
{
|
283
|
+
"method": "sub.depth.step",
|
284
|
+
"param": {
|
285
|
+
"symbol": "BTC_USDT",
|
286
|
+
"step": "0.1"
|
287
|
+
}
|
288
|
+
}
|
289
|
+
|
290
|
+
.. code:: json
|
291
|
+
|
292
|
+
{
|
293
|
+
"method": "sub.tickers",
|
294
|
+
"param": {
|
295
|
+
"timezone": "UTC+8"
|
296
|
+
}
|
297
|
+
}
|
298
|
+
|
299
|
+
TODO:
|
300
|
+
- 添加 trades、ticker、candle 等其他数据流
|
301
|
+
"""
|
302
|
+
|
303
|
+
def _init(self) -> None:
|
304
|
+
self._create("book", datastore_class=Book)
|
305
|
+
self._create("detail", datastore_class=Detail)
|
306
|
+
self._create("ticker", datastore_class=Ticker)
|
307
|
+
self._create("orders", datastore_class=Orders)
|
308
|
+
self._create("position", datastore_class=Position)
|
309
|
+
self._create("balance", datastore_class=Balance)
|
310
|
+
# TODO: 添加其他数据流,如 trades, ticker, candle 等
|
311
|
+
|
312
|
+
def onmessage(self, msg: Item, ws: ClientWebSocketResponse | None = None) -> None:
|
313
|
+
channel = msg.get("channel")
|
314
|
+
|
315
|
+
if channel == "push.depth.step":
|
316
|
+
self.book._on_message(msg)
|
317
|
+
if channel == "push.tickers":
|
318
|
+
self.ticker._on_message(msg)
|
319
|
+
else:
|
320
|
+
logger.debug(f"未知的channel: {channel}")
|
321
|
+
|
322
|
+
async def initialize(self, *aws: Awaitable[aiohttp.ClientResponse]) -> None:
|
323
|
+
"""Initialize DataStore from HTTP response data."""
|
324
|
+
for f in asyncio.as_completed(aws):
|
325
|
+
res = await f
|
326
|
+
data = await res.json()
|
327
|
+
if res.url.path == "/api/v1/contract/detailV2":
|
328
|
+
self.detail._onresponse(data)
|
329
|
+
if res.url.path == "/api/v1/contract/ticker":
|
330
|
+
self.ticker._onresponse(data)
|
331
|
+
if res.url.path == "/api/v1/private/order/list/open_orders":
|
332
|
+
self.orders._onresponse(data)
|
333
|
+
if res.url.path == "/api/v1/private/position/open_positions":
|
334
|
+
self.position._onresponse(data)
|
335
|
+
if res.url.path == "/api/v1/private/account/assets":
|
336
|
+
self.balance._onresponse(data)
|
337
|
+
|
338
|
+
@property
|
339
|
+
def detail(self) -> Detail:
|
340
|
+
"""合约详情
|
341
|
+
Data structure:
|
342
|
+
.. code:: python
|
343
|
+
[
|
344
|
+
{
|
345
|
+
"symbol": "BTC_USDT", # 交易对
|
346
|
+
"ft": 100, # 合约面值
|
347
|
+
"max_lev": 100, # 最大杠杆
|
348
|
+
"tick_size": 0.1, # 最小变动价位
|
349
|
+
"vol_unit": 1, # 合约单位
|
350
|
+
"io": ["binance", "mexc"], # 交易所列表
|
351
|
+
"contract_sz": 1,
|
352
|
+
"minv": 1,
|
353
|
+
"maxv": 10000
|
354
|
+
|
355
|
+
}
|
356
|
+
]
|
357
|
+
"""
|
358
|
+
return self._get("detail", Detail)
|
359
|
+
|
360
|
+
@property
|
361
|
+
def book(self) -> Book:
|
362
|
+
"""订单簿深度数据流
|
363
|
+
|
364
|
+
Data type: Mutable
|
365
|
+
|
366
|
+
Keys: ("symbol", "side", "px")
|
367
|
+
|
368
|
+
Data structure:
|
369
|
+
|
370
|
+
.. code:: python
|
371
|
+
|
372
|
+
[
|
373
|
+
{
|
374
|
+
"symbol": "BTC_USDT", # 交易对
|
375
|
+
"side": "A", # 卖出方向
|
376
|
+
"px": "110152.5", # 价格
|
377
|
+
"sz": "53539", # 数量
|
378
|
+
"count": 1 # 订单数量
|
379
|
+
},
|
380
|
+
{
|
381
|
+
"symbol": "BTC_USDT", # 交易对
|
382
|
+
"side": "B", # 买入方向
|
383
|
+
"px": "110152.4", # 价格
|
384
|
+
"sz": "76311", # 数量
|
385
|
+
"count": 1 # 订单数量
|
386
|
+
}
|
387
|
+
]
|
388
|
+
"""
|
389
|
+
return self._get("book", Book)
|
390
|
+
|
391
|
+
@property
|
392
|
+
def ticker(self) -> Ticker:
|
393
|
+
"""市场行情数据流
|
394
|
+
|
395
|
+
Data type: Mutable
|
396
|
+
|
397
|
+
Keys: ("symbol",)
|
398
|
+
|
399
|
+
Data structure:
|
400
|
+
|
401
|
+
.. code:: python
|
402
|
+
|
403
|
+
[
|
404
|
+
{
|
405
|
+
"symbol": "BTC_USDT", # 交易对
|
406
|
+
"last_price": "110152.5", # 最新价格
|
407
|
+
"index_price": "110000.0", # 指数价格
|
408
|
+
"fair_price": "110100.0", # 公允价格
|
409
|
+
"high24_price": "115000.0", # 24小时最高价
|
410
|
+
"lower24_price": "105000.0", # 24小时最低价
|
411
|
+
"volume24": "1500", # 24小时交易量
|
412
|
+
"amount24": "165000000", # 24小时交易额
|
413
|
+
"rise_fall_rate": "0.05", # 涨跌幅
|
414
|
+
"max_bid_price": "110150.0", # 买一价
|
415
|
+
"min_ask_price": "110155.0", # 卖一价
|
416
|
+
"timestamp": 1625247600000 # 时间戳
|
417
|
+
}
|
418
|
+
]
|
419
|
+
"""
|
420
|
+
return self._get("ticker", Ticker)
|
421
|
+
|
422
|
+
@property
|
423
|
+
def orders(self) -> Orders:
|
424
|
+
"""
|
425
|
+
订单数据
|
426
|
+
Data structure:
|
427
|
+
|
428
|
+
.. code:: json
|
429
|
+
|
430
|
+
[
|
431
|
+
{
|
432
|
+
"id": "123456",
|
433
|
+
"symbol": "BTC_USDT",
|
434
|
+
"side": "buy",
|
435
|
+
"price": "110152.5",
|
436
|
+
"size": "0.1",
|
437
|
+
"status": "open",
|
438
|
+
"create_ts": 1625247600000,
|
439
|
+
"update_ts": 1625247600000
|
440
|
+
}
|
441
|
+
]
|
442
|
+
"""
|
443
|
+
return self._get("orders", Orders)
|
444
|
+
|
445
|
+
@property
|
446
|
+
def position(self) -> Position:
|
447
|
+
"""
|
448
|
+
持仓数据
|
449
|
+
|
450
|
+
Data structure:
|
451
|
+
.. code:: python
|
452
|
+
[
|
453
|
+
{
|
454
|
+
"position_id": "123456",
|
455
|
+
"symbol": "BTC_USDT",
|
456
|
+
"side": "long",
|
457
|
+
"open_type": "limit",
|
458
|
+
"state": "open",
|
459
|
+
"hold_vol": "0.1",
|
460
|
+
"frozen_vol": "0.0",
|
461
|
+
"close_vol": "0.0",
|
462
|
+
"hold_avg_price": "110152.5",
|
463
|
+
"open_avg_price": "110152.5",
|
464
|
+
"close_avg_price": "0.0",
|
465
|
+
"liquidate_price": "100000.0",
|
466
|
+
"oim": "0.0",
|
467
|
+
"im": "0.0",
|
468
|
+
"hold_fee": "0.0",
|
469
|
+
"realised": "0.0",
|
470
|
+
"leverage": "10",
|
471
|
+
"margin_ratio": "0.1",
|
472
|
+
"create_ts": 1625247600000,
|
473
|
+
"update_ts": 1625247600000
|
474
|
+
}
|
475
|
+
]
|
476
|
+
"""
|
477
|
+
return self._get("position", Position)
|
478
|
+
|
479
|
+
@property
|
480
|
+
def balance(self) -> Balance:
|
481
|
+
"""账户余额数据
|
482
|
+
|
483
|
+
Data structure:
|
484
|
+
.. code:: python
|
485
|
+
[
|
486
|
+
{
|
487
|
+
"currency": "USDT", # 币种
|
488
|
+
"position_margin": 0.3052, # 持仓保证金
|
489
|
+
"available_balance": 19.7284, # 可用余额
|
490
|
+
"cash_balance": 19.7284, # 现金余额
|
491
|
+
"frozen_balance": 0, # 冻结余额
|
492
|
+
"equity": 19.9442, # 权益
|
493
|
+
"unrealized": -0.0895, # 未实现盈亏
|
494
|
+
"bonus": 0, # 奖励
|
495
|
+
"last_bonus": 0, # 最后奖励
|
496
|
+
"wallet_balance": 20.0337, # 钱包余额
|
497
|
+
"voucher": 0, # 代金券
|
498
|
+
"voucher_using": 0 # 使用中的代金券
|
499
|
+
}
|
500
|
+
]
|
501
|
+
"""
|
502
|
+
return self._get("balance", Balance)
|