xync-client 0.0.155__py3-none-any.whl → 0.0.162__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.
- xync_client/Abc/AdLoader.py +0 -294
- xync_client/Abc/Agent.py +326 -51
- xync_client/Abc/Ex.py +421 -12
- xync_client/Abc/Order.py +7 -14
- xync_client/Abc/xtype.py +35 -3
- xync_client/Bybit/InAgent.py +18 -447
- xync_client/Bybit/agent.py +531 -431
- xync_client/Bybit/etype/__init__.py +0 -0
- xync_client/Bybit/etype/ad.py +47 -34
- xync_client/Bybit/etype/order.py +34 -49
- xync_client/Bybit/ex.py +20 -46
- xync_client/Bybit/order.py +14 -12
- xync_client/Htx/agent.py +82 -40
- xync_client/Htx/etype/ad.py +22 -5
- xync_client/Htx/etype/order.py +194 -0
- xync_client/Htx/ex.py +16 -16
- xync_client/Mexc/agent.py +196 -13
- xync_client/Mexc/api.py +955 -336
- xync_client/Mexc/etype/ad.py +52 -1
- xync_client/Mexc/etype/order.py +131 -416
- xync_client/Mexc/ex.py +29 -19
- xync_client/Okx/1.py +14 -0
- xync_client/Okx/agent.py +39 -0
- xync_client/Okx/ex.py +8 -8
- xync_client/Pms/Payeer/agent.py +396 -0
- xync_client/Pms/Payeer/login.py +1 -63
- xync_client/Pms/Payeer/trade.py +58 -0
- xync_client/Pms/Volet/{__init__.py → agent.py} +1 -2
- xync_client/loader.py +1 -0
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/METADATA +2 -1
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/RECORD +33 -29
- xync_client/Pms/Payeer/__init__.py +0 -262
- xync_client/Pms/Payeer/api.py +0 -25
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/WHEEL +0 -0
- {xync_client-0.0.155.dist-info → xync_client-0.0.162.dist-info}/top_level.txt +0 -0
xync_client/Mexc/etype/order.py
CHANGED
|
@@ -1,59 +1,44 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
"""
|
|
1
|
+
from enum import IntEnum
|
|
2
|
+
from typing import Optional, Literal
|
|
4
3
|
|
|
5
|
-
import hmac
|
|
6
|
-
import hashlib
|
|
7
|
-
import time
|
|
8
|
-
from typing import Optional, List, Literal
|
|
9
|
-
from decimal import Decimal
|
|
10
|
-
|
|
11
|
-
import aiohttp
|
|
12
4
|
from pydantic import BaseModel, Field
|
|
13
5
|
|
|
14
|
-
|
|
15
6
|
# ============ Enums ============
|
|
7
|
+
Side = Literal["BUY", "SELL"]
|
|
16
8
|
|
|
17
9
|
|
|
18
|
-
class
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
10
|
+
class AdvStatus(IntEnum):
|
|
11
|
+
CLOSE = 0
|
|
12
|
+
OPEN = 1
|
|
13
|
+
DELETE = 2
|
|
14
|
+
LOW_STOCK = 3
|
|
22
15
|
|
|
23
|
-
class AdvStatus(str):
|
|
24
|
-
CLOSE = "CLOSE"
|
|
25
|
-
OPEN = "OPEN"
|
|
26
|
-
DELETE = "DELETE"
|
|
27
|
-
LOW_STOCK = "LOW_STOCK"
|
|
28
16
|
|
|
17
|
+
class OrderDealState(IntEnum):
|
|
18
|
+
NOT_PAID = 0
|
|
19
|
+
PAID = 1
|
|
20
|
+
WAIT_PROCESS = 2
|
|
21
|
+
PROCESSING = 3
|
|
22
|
+
DONE = 4
|
|
23
|
+
CANCEL = 5
|
|
24
|
+
INVALID = 6
|
|
25
|
+
REFUSE = 7
|
|
26
|
+
TIMEOUT = 8
|
|
29
27
|
|
|
30
|
-
class OrderDealState(str):
|
|
31
|
-
NOT_PAID = "NOT_PAID"
|
|
32
|
-
PAID = "PAID"
|
|
33
|
-
WAIT_PROCESS = "WAIT_PROCESS"
|
|
34
|
-
PROCESSING = "PROCESSING"
|
|
35
|
-
DONE = "DONE"
|
|
36
|
-
CANCEL = "CANCEL"
|
|
37
|
-
INVALID = "INVALID"
|
|
38
|
-
REFUSE = "REFUSE"
|
|
39
|
-
TIMEOUT = "TIMEOUT"
|
|
40
28
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
GA = "GA"
|
|
29
|
+
class NotifyType(IntEnum):
|
|
30
|
+
SMS = 0
|
|
31
|
+
MAIL = 1
|
|
32
|
+
GA = 2
|
|
46
33
|
|
|
47
34
|
|
|
48
35
|
# ============ Request Models ============
|
|
49
|
-
|
|
50
|
-
|
|
51
36
|
class CreateUpdateAdRequest(BaseModel):
|
|
52
37
|
advNo: Optional[str] = None
|
|
53
38
|
payTimeLimit: int
|
|
54
|
-
initQuantity:
|
|
55
|
-
supplyQuantity: Optional[
|
|
56
|
-
price:
|
|
39
|
+
initQuantity: float
|
|
40
|
+
supplyQuantity: Optional[float] = None
|
|
41
|
+
price: float
|
|
57
42
|
coinId: str
|
|
58
43
|
countryCode: Optional[str] = None
|
|
59
44
|
side: str
|
|
@@ -63,8 +48,8 @@ class CreateUpdateAdRequest(BaseModel):
|
|
|
63
48
|
payMethod: str
|
|
64
49
|
autoReplyMsg: Optional[str] = None
|
|
65
50
|
tradeTerms: Optional[str] = None
|
|
66
|
-
minSingleTransAmount:
|
|
67
|
-
maxSingleTransAmount:
|
|
51
|
+
minSingleTransAmount: float
|
|
52
|
+
maxSingleTransAmount: float
|
|
68
53
|
kycLevel: Optional[str] = None
|
|
69
54
|
requireMobile: Optional[bool] = None
|
|
70
55
|
userAllTradeCountMin: int
|
|
@@ -72,15 +57,15 @@ class CreateUpdateAdRequest(BaseModel):
|
|
|
72
57
|
exchangeCount: Optional[int] = None
|
|
73
58
|
maxPayLimit: Optional[int] = None
|
|
74
59
|
buyerRegDaysLimit: Optional[int] = None
|
|
75
|
-
creditAmount: Optional[
|
|
60
|
+
creditAmount: Optional[float] = None
|
|
76
61
|
blockTrade: Optional[bool] = None
|
|
77
62
|
deviceId: Optional[str] = None
|
|
78
63
|
|
|
79
64
|
|
|
80
65
|
class CreateOrderRequest(BaseModel):
|
|
81
66
|
advNo: str
|
|
82
|
-
amount: Optional[
|
|
83
|
-
tradableQuantity: Optional[
|
|
67
|
+
amount: Optional[float] = None
|
|
68
|
+
tradableQuantity: Optional[float] = None
|
|
84
69
|
userConfirmPaymentId: int
|
|
85
70
|
userConfirmPayMethodId: Optional[int] = None
|
|
86
71
|
deviceId: Optional[str] = None
|
|
@@ -102,8 +87,6 @@ class ServiceSwitchRequest(BaseModel):
|
|
|
102
87
|
|
|
103
88
|
|
|
104
89
|
# ============ Response Models ============
|
|
105
|
-
|
|
106
|
-
|
|
107
90
|
class BaseResponse(BaseModel):
|
|
108
91
|
code: int
|
|
109
92
|
msg: str
|
|
@@ -112,11 +95,11 @@ class BaseResponse(BaseModel):
|
|
|
112
95
|
class PaymentInfo(BaseModel):
|
|
113
96
|
id: int
|
|
114
97
|
payMethod: int
|
|
115
|
-
bankName: str
|
|
116
|
-
account: str
|
|
117
|
-
bankAddress: str
|
|
118
|
-
payee: str
|
|
119
|
-
extend: str
|
|
98
|
+
bankName: str = None
|
|
99
|
+
account: str = None
|
|
100
|
+
bankAddress: str = None
|
|
101
|
+
payee: str = None
|
|
102
|
+
extend: str = None
|
|
120
103
|
|
|
121
104
|
|
|
122
105
|
class MerchantInfo(BaseModel):
|
|
@@ -138,38 +121,41 @@ class MerchantStatistics(BaseModel):
|
|
|
138
121
|
totalBuyCount: int
|
|
139
122
|
totalSellCount: int
|
|
140
123
|
doneLastMonthCount: int
|
|
141
|
-
avgBuyHandleTime:
|
|
142
|
-
avgSellHandleTime:
|
|
124
|
+
avgBuyHandleTime: float
|
|
125
|
+
avgSellHandleTime: float
|
|
143
126
|
lastMonthCompleteRate: str
|
|
144
127
|
completeRate: str
|
|
145
|
-
avgHandleTime:
|
|
128
|
+
avgHandleTime: float
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
2
|
|
146
132
|
|
|
147
133
|
|
|
148
134
|
class Advertisement(BaseModel):
|
|
149
135
|
advNo: str
|
|
150
136
|
payTimeLimit: int
|
|
151
|
-
quantity: int
|
|
152
|
-
price:
|
|
153
|
-
initAmount:
|
|
154
|
-
frozenQuantity:
|
|
155
|
-
availableQuantity:
|
|
156
|
-
coinId: str
|
|
137
|
+
quantity: int = None
|
|
138
|
+
price: float
|
|
139
|
+
initAmount: float = None
|
|
140
|
+
frozenQuantity: float = None
|
|
141
|
+
availableQuantity: float
|
|
142
|
+
coinId: str = None
|
|
157
143
|
coinName: str
|
|
158
144
|
countryCode: str
|
|
159
|
-
commissionRate:
|
|
160
|
-
advStatus: str
|
|
145
|
+
commissionRate: float = None
|
|
146
|
+
advStatus: str = None
|
|
161
147
|
side: str
|
|
162
|
-
createTime: int
|
|
148
|
+
createTime: int = None
|
|
163
149
|
updateTime: int
|
|
164
150
|
fiatUnit: str
|
|
165
|
-
feeType: int
|
|
151
|
+
feeType: int = None
|
|
166
152
|
autoReplyMsg: str
|
|
167
153
|
tradeTerms: str
|
|
168
154
|
payMethod: str
|
|
169
|
-
paymentInfo:
|
|
170
|
-
minSingleTransAmount:
|
|
171
|
-
maxSingleTransAmount:
|
|
172
|
-
kycLevel:
|
|
155
|
+
paymentInfo: list[PaymentInfo]
|
|
156
|
+
minSingleTransAmount: float
|
|
157
|
+
maxSingleTransAmount: float
|
|
158
|
+
kycLevel: Literal["PRIMARY", "ADVANCED"]
|
|
173
159
|
requireMobile: bool
|
|
174
160
|
userAllTradeCountMax: int
|
|
175
161
|
userAllTradeCountMin: int
|
|
@@ -200,30 +186,30 @@ class UserInfo(BaseModel):
|
|
|
200
186
|
class Order(BaseModel):
|
|
201
187
|
advNo: str
|
|
202
188
|
advOrderNo: str
|
|
203
|
-
tradableQuantity:
|
|
204
|
-
price:
|
|
205
|
-
amount:
|
|
189
|
+
tradableQuantity: float
|
|
190
|
+
price: float
|
|
191
|
+
amount: float
|
|
206
192
|
coinName: str
|
|
207
|
-
state:
|
|
193
|
+
state: Literal["DONE", "PAID", "NOT_PAID", "PROCESSING"]
|
|
208
194
|
payTimeLimit: int
|
|
209
|
-
side:
|
|
195
|
+
side: Side
|
|
210
196
|
fiatUnit: str
|
|
211
197
|
createTime: int
|
|
212
198
|
updateTime: int
|
|
213
199
|
userInfo: UserInfo
|
|
214
200
|
complained: bool
|
|
215
|
-
blockUser: bool
|
|
201
|
+
blockUser: bool = None
|
|
216
202
|
unreadCount: int
|
|
217
203
|
complainId: Optional[str] = None
|
|
218
204
|
|
|
219
205
|
|
|
220
206
|
class OrderDetail(Order):
|
|
221
|
-
paymentInfo:
|
|
222
|
-
allowComplainTime: int
|
|
207
|
+
paymentInfo: list[PaymentInfo]
|
|
208
|
+
allowComplainTime: int = None
|
|
223
209
|
confirmPaymentInfo: PaymentInfo
|
|
224
210
|
userInfo: dict
|
|
225
|
-
userFiatStatistics: dict
|
|
226
|
-
spotCount: int
|
|
211
|
+
userFiatStatistics: dict = None
|
|
212
|
+
spotCount: int = None
|
|
227
213
|
|
|
228
214
|
|
|
229
215
|
class CreateAdResponse(BaseResponse):
|
|
@@ -231,12 +217,12 @@ class CreateAdResponse(BaseResponse):
|
|
|
231
217
|
|
|
232
218
|
|
|
233
219
|
class AdListResponse(BaseResponse):
|
|
234
|
-
data:
|
|
220
|
+
data: list[Advertisement]
|
|
235
221
|
page: PageInfo
|
|
236
222
|
|
|
237
223
|
|
|
238
224
|
class MarketAdListResponse(BaseResponse):
|
|
239
|
-
data:
|
|
225
|
+
data: list[MarketAdvertisement]
|
|
240
226
|
page: PageInfo
|
|
241
227
|
|
|
242
228
|
|
|
@@ -245,7 +231,7 @@ class CreateOrderResponse(BaseResponse):
|
|
|
245
231
|
|
|
246
232
|
|
|
247
233
|
class OrderListResponse(BaseResponse):
|
|
248
|
-
data:
|
|
234
|
+
data: list[Order]
|
|
249
235
|
page: PageInfo
|
|
250
236
|
|
|
251
237
|
|
|
@@ -253,7 +239,7 @@ class OrderDetailResponse(BaseResponse):
|
|
|
253
239
|
data: OrderDetail
|
|
254
240
|
|
|
255
241
|
|
|
256
|
-
class ListenKeyResponse(
|
|
242
|
+
class ListenKeyResponse(BaseModel):
|
|
257
243
|
listenKey: str
|
|
258
244
|
|
|
259
245
|
|
|
@@ -284,356 +270,85 @@ class UploadFileResponse(BaseResponse):
|
|
|
284
270
|
data: dict
|
|
285
271
|
|
|
286
272
|
|
|
287
|
-
# ============
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
BASE_URL = "https://api.mexc.com"
|
|
294
|
-
|
|
295
|
-
def __init__(self, api_key: str, api_secret: str):
|
|
296
|
-
self.api_key = api_key
|
|
297
|
-
self.api_secret = api_secret
|
|
298
|
-
self.session: Optional[aiohttp.ClientSession] = None
|
|
299
|
-
|
|
300
|
-
async def __aenter__(self):
|
|
301
|
-
self.session = aiohttp.ClientSession()
|
|
302
|
-
return self
|
|
303
|
-
|
|
304
|
-
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
305
|
-
if self.session:
|
|
306
|
-
await self.session.close()
|
|
307
|
-
|
|
308
|
-
def _generate_signature(self, query_string: str) -> str:
|
|
309
|
-
"""Генерация HMAC SHA256 подписи"""
|
|
310
|
-
return hmac.new(self.api_secret.encode("utf-8"), query_string.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
311
|
-
|
|
312
|
-
def _get_timestamp(self) -> int:
|
|
313
|
-
"""Получение текущего timestamp в миллисекундах"""
|
|
314
|
-
return int(time.time() * 1000)
|
|
315
|
-
|
|
316
|
-
async def _request(
|
|
317
|
-
self, method: str, endpoint: str, params: Optional[dict] = None, data: Optional[BaseModel] = None
|
|
318
|
-
) -> dict:
|
|
319
|
-
"""Базовый метод для HTTP запросов"""
|
|
320
|
-
if not self.session:
|
|
321
|
-
raise RuntimeError("Client not initialized. Use async context manager.")
|
|
322
|
-
|
|
323
|
-
timestamp = self._get_timestamp()
|
|
324
|
-
|
|
325
|
-
# Формирование query string для подписи
|
|
326
|
-
query_params = params.copy() if params else {}
|
|
327
|
-
query_params["timestamp"] = timestamp
|
|
328
|
-
|
|
329
|
-
query_string = "&".join(f"{k}={v}" for k, v in sorted(query_params.items()))
|
|
330
|
-
signature = self._generate_signature(query_string)
|
|
331
|
-
|
|
332
|
-
query_params["signature"] = signature
|
|
333
|
-
|
|
334
|
-
headers = {"X-MEXC-APIKEY": self.api_key, "Content-Type": "application/json"}
|
|
335
|
-
|
|
336
|
-
url = f"{self.BASE_URL}{endpoint}"
|
|
337
|
-
|
|
338
|
-
json_data = data.model_dump(exclude_none=True) if data else None
|
|
339
|
-
|
|
340
|
-
async with self.session.request(method, url, params=query_params, json=json_data, headers=headers) as response:
|
|
341
|
-
return await response.json()
|
|
342
|
-
|
|
343
|
-
# ============ Advertisement Methods ============
|
|
344
|
-
|
|
345
|
-
async def create_or_update_ad(self, request: CreateUpdateAdRequest) -> CreateAdResponse:
|
|
346
|
-
"""Создание или обновление объявления"""
|
|
347
|
-
result = await self._request("POST", "/api/v3/fiat/merchant/ads/save_or_update", data=request)
|
|
348
|
-
return CreateAdResponse(**result)
|
|
349
|
-
|
|
350
|
-
async def get_my_ads(
|
|
351
|
-
self,
|
|
352
|
-
coin_id: Optional[str] = None,
|
|
353
|
-
adv_status: Optional[str] = None,
|
|
354
|
-
merchant_id: Optional[str] = None,
|
|
355
|
-
fiat_unit: Optional[str] = None,
|
|
356
|
-
side: Optional[str] = None,
|
|
357
|
-
kyc_level: Optional[str] = None,
|
|
358
|
-
start_time: Optional[int] = None,
|
|
359
|
-
end_time: Optional[int] = None,
|
|
360
|
-
page: int = 1,
|
|
361
|
-
limit: int = 10,
|
|
362
|
-
) -> AdListResponse:
|
|
363
|
-
"""Получение списка моих объявлений с пагинацией"""
|
|
364
|
-
params = {"page": page, "limit": limit}
|
|
365
|
-
|
|
366
|
-
if coin_id:
|
|
367
|
-
params["coinId"] = coin_id
|
|
368
|
-
if adv_status:
|
|
369
|
-
params["advStatus"] = adv_status
|
|
370
|
-
if merchant_id:
|
|
371
|
-
params["merchantId"] = merchant_id
|
|
372
|
-
if fiat_unit:
|
|
373
|
-
params["fiatUnit"] = fiat_unit
|
|
374
|
-
if side:
|
|
375
|
-
params["side"] = side
|
|
376
|
-
if kyc_level:
|
|
377
|
-
params["kycLevel"] = kyc_level
|
|
378
|
-
if start_time:
|
|
379
|
-
params["startTime"] = start_time
|
|
380
|
-
if end_time:
|
|
381
|
-
params["endTime"] = end_time
|
|
382
|
-
|
|
383
|
-
result = await self._request("GET", "/api/v3/fiat/merchant/ads/pagination", params=params)
|
|
384
|
-
return AdListResponse(**result)
|
|
385
|
-
|
|
386
|
-
async def get_market_ads(
|
|
387
|
-
self,
|
|
388
|
-
fiat_unit: str,
|
|
389
|
-
coin_id: str,
|
|
390
|
-
country_code: Optional[str] = None,
|
|
391
|
-
side: Optional[str] = None,
|
|
392
|
-
amount: Optional[Decimal] = None,
|
|
393
|
-
quantity: Optional[Decimal] = None,
|
|
394
|
-
pay_method: Optional[str] = None,
|
|
395
|
-
block_trade: Optional[bool] = None,
|
|
396
|
-
allow_trade: Optional[bool] = None,
|
|
397
|
-
have_trade: Optional[bool] = None,
|
|
398
|
-
follow: Optional[bool] = None,
|
|
399
|
-
page: int = 1,
|
|
400
|
-
) -> MarketAdListResponse:
|
|
401
|
-
"""Получение рыночных объявлений"""
|
|
402
|
-
params = {"fiatUnit": fiat_unit, "coinId": coin_id, "page": page}
|
|
403
|
-
|
|
404
|
-
if country_code:
|
|
405
|
-
params["countryCode"] = country_code
|
|
406
|
-
if side:
|
|
407
|
-
params["side"] = side
|
|
408
|
-
if amount:
|
|
409
|
-
params["amount"] = str(amount)
|
|
410
|
-
if quantity:
|
|
411
|
-
params["quantity"] = str(quantity)
|
|
412
|
-
if pay_method:
|
|
413
|
-
params["payMethod"] = pay_method
|
|
414
|
-
if block_trade is not None:
|
|
415
|
-
params["blockTrade"] = block_trade
|
|
416
|
-
if allow_trade is not None:
|
|
417
|
-
params["allowTrade"] = allow_trade
|
|
418
|
-
if have_trade is not None:
|
|
419
|
-
params["haveTrade"] = have_trade
|
|
420
|
-
if follow is not None:
|
|
421
|
-
params["follow"] = follow
|
|
422
|
-
|
|
423
|
-
result = await self._request("GET", "/api/v3/fiat/market/ads/pagination", params=params)
|
|
424
|
-
return MarketAdListResponse(**result)
|
|
425
|
-
|
|
426
|
-
# ============ Order Methods ============
|
|
427
|
-
|
|
428
|
-
async def create_order(self, request: CreateOrderRequest) -> CreateOrderResponse:
|
|
429
|
-
"""Создание ордера (захват объявления)"""
|
|
430
|
-
result = await self._request("POST", "/api/v3/fiat/merchant/order/deal", data=request)
|
|
431
|
-
return CreateOrderResponse(**result)
|
|
432
|
-
|
|
433
|
-
async def get_my_orders(
|
|
434
|
-
self,
|
|
435
|
-
start_time: int,
|
|
436
|
-
end_time: int,
|
|
437
|
-
coin_id: Optional[str] = None,
|
|
438
|
-
adv_order_no: Optional[str] = None,
|
|
439
|
-
side: Optional[str] = None,
|
|
440
|
-
order_deal_state: Optional[str] = None,
|
|
441
|
-
page: int = 1,
|
|
442
|
-
limit: int = 10,
|
|
443
|
-
) -> OrderListResponse:
|
|
444
|
-
"""Получение моих ордеров (только как maker)"""
|
|
445
|
-
params = {"startTime": start_time, "endTime": end_time, "page": page, "limit": limit}
|
|
446
|
-
|
|
447
|
-
if coin_id:
|
|
448
|
-
params["coinId"] = coin_id
|
|
449
|
-
if adv_order_no:
|
|
450
|
-
params["advOrderNo"] = adv_order_no
|
|
451
|
-
if side:
|
|
452
|
-
params["side"] = side
|
|
453
|
-
if order_deal_state:
|
|
454
|
-
params["orderDealState"] = order_deal_state
|
|
455
|
-
|
|
456
|
-
result = await self._request("GET", "/api/v3/fiat/merchant/order/pagination", params=params)
|
|
457
|
-
return OrderListResponse(**result)
|
|
458
|
-
|
|
459
|
-
async def get_market_orders(
|
|
460
|
-
self,
|
|
461
|
-
coin_id: Optional[str] = None,
|
|
462
|
-
adv_order_no: Optional[str] = None,
|
|
463
|
-
side: Optional[str] = None,
|
|
464
|
-
order_deal_state: Optional[str] = None,
|
|
465
|
-
start_time: Optional[int] = None,
|
|
466
|
-
end_time: Optional[int] = None,
|
|
467
|
-
page: int = 1,
|
|
468
|
-
limit: int = 10,
|
|
469
|
-
) -> OrderListResponse:
|
|
470
|
-
"""Получение всех ордеров (как maker и taker)"""
|
|
471
|
-
params = {"page": page, "limit": limit}
|
|
472
|
-
|
|
473
|
-
if coin_id:
|
|
474
|
-
params["coinId"] = coin_id
|
|
475
|
-
if adv_order_no:
|
|
476
|
-
params["advOrderNo"] = adv_order_no
|
|
477
|
-
if side:
|
|
478
|
-
params["side"] = side
|
|
479
|
-
if order_deal_state:
|
|
480
|
-
params["orderDealState"] = order_deal_state
|
|
481
|
-
if start_time:
|
|
482
|
-
params["startTime"] = start_time
|
|
483
|
-
if end_time:
|
|
484
|
-
params["endTime"] = end_time
|
|
485
|
-
|
|
486
|
-
result = await self._request("GET", "/api/v3/fiat/market/order/pagination", params=params)
|
|
487
|
-
return OrderListResponse(**result)
|
|
488
|
-
|
|
489
|
-
async def confirm_paid(self, request: ConfirmPaidRequest) -> BaseResponse:
|
|
490
|
-
"""Подтверждение оплаты"""
|
|
491
|
-
result = await self._request("POST", "/api/v3/fiat/confirm_paid", data=request)
|
|
492
|
-
return BaseResponse(**result)
|
|
493
|
-
|
|
494
|
-
async def release_coin(self, request: ReleaseCoinRequest) -> BaseResponse:
|
|
495
|
-
"""Релиз криптовалюты"""
|
|
496
|
-
result = await self._request("POST", "/api/v3/fiat/release_coin", data=request)
|
|
497
|
-
return BaseResponse(**result)
|
|
498
|
-
|
|
499
|
-
async def get_order_detail(self, adv_order_no: str) -> OrderDetailResponse:
|
|
500
|
-
"""Получение деталей ордера"""
|
|
501
|
-
params = {"advOrderNo": adv_order_no}
|
|
502
|
-
|
|
503
|
-
result = await self._request("GET", "/api/v3/fiat/order/detail", params=params)
|
|
504
|
-
return OrderDetailResponse(**result)
|
|
505
|
-
|
|
506
|
-
# ============ Service Methods ============
|
|
507
|
-
|
|
508
|
-
async def switch_service(self, request: ServiceSwitchRequest) -> BaseResponse:
|
|
509
|
-
"""Открытие/закрытие торговли"""
|
|
510
|
-
result = await self._request("POST", "/api/v3/fiat/merchant/service/switch", data=request)
|
|
511
|
-
return BaseResponse(**result)
|
|
512
|
-
|
|
513
|
-
# ============ WebSocket Methods ============
|
|
514
|
-
|
|
515
|
-
async def generate_listen_key(self) -> ListenKeyResponse:
|
|
516
|
-
"""Генерация listenKey для WebSocket"""
|
|
517
|
-
result = await self._request("POST", "/api/v3/userDataStream")
|
|
518
|
-
return ListenKeyResponse(**result)
|
|
519
|
-
|
|
520
|
-
async def get_listen_key(self) -> ListenKeyResponse:
|
|
521
|
-
"""Получение существующего listenKey"""
|
|
522
|
-
result = await self._request("GET", "/api/v3/userDataStream")
|
|
523
|
-
return ListenKeyResponse(**result)
|
|
524
|
-
|
|
525
|
-
# ============ Chat Methods ============
|
|
526
|
-
|
|
527
|
-
async def get_chat_conversation(self, order_no: str) -> ConversationResponse:
|
|
528
|
-
"""Получение ID чат-сессии для ордера"""
|
|
529
|
-
params = {"orderNo": order_no}
|
|
530
|
-
|
|
531
|
-
result = await self._request("GET", "/api/v3/fiat/retrieveChatConversation", params=params)
|
|
532
|
-
return ConversationResponse(**result)
|
|
533
|
-
|
|
534
|
-
async def get_chat_messages(
|
|
535
|
-
self,
|
|
536
|
-
conversation_id: int,
|
|
537
|
-
page: int = 1,
|
|
538
|
-
limit: int = 20,
|
|
539
|
-
chat_message_type: Optional[str] = None,
|
|
540
|
-
message_id: Optional[int] = None,
|
|
541
|
-
sort: Literal["DESC", "ASC"] = "DESC",
|
|
542
|
-
) -> ChatMessagesResponse:
|
|
543
|
-
"""Получение истории чата с пагинацией"""
|
|
544
|
-
params = {"conversationId": conversation_id, "page": page, "limit": limit, "sort": sort}
|
|
545
|
-
|
|
546
|
-
if chat_message_type:
|
|
547
|
-
params["chatMessageType"] = chat_message_type
|
|
548
|
-
if message_id:
|
|
549
|
-
params["id"] = message_id
|
|
550
|
-
|
|
551
|
-
result = await self._request("GET", "/api/v3/fiat/retrieveChatMessageWithPagination", params=params)
|
|
552
|
-
return ChatMessagesResponse(**result)
|
|
553
|
-
|
|
554
|
-
async def upload_file(self, file_data: bytes, filename: str) -> UploadFileResponse:
|
|
555
|
-
"""Загрузка файла"""
|
|
556
|
-
if not self.session:
|
|
557
|
-
raise RuntimeError("Client not initialized.")
|
|
558
|
-
|
|
559
|
-
timestamp = self._get_timestamp()
|
|
560
|
-
query_string = f"timestamp={timestamp}"
|
|
561
|
-
signature = self._generate_signature(query_string)
|
|
562
|
-
|
|
563
|
-
url = f"{self.BASE_URL}/api/v3/fiat/uploadFile"
|
|
564
|
-
params = {"timestamp": timestamp, "signature": signature}
|
|
565
|
-
|
|
566
|
-
headers = {"X-MEXC-APIKEY": self.api_key}
|
|
567
|
-
|
|
568
|
-
form = aiohttp.FormData()
|
|
569
|
-
form.add_field("file", file_data, filename=filename)
|
|
273
|
+
# ============ WebSocket Message Models ============
|
|
274
|
+
class ChatMessageType(IntEnum):
|
|
275
|
+
TEXT = 1
|
|
276
|
+
IMAGE = 2
|
|
277
|
+
VIDEO = 3
|
|
278
|
+
FILE = 4
|
|
570
279
|
|
|
571
|
-
async with self.session.post(url, params=params, data=form, headers=headers) as response:
|
|
572
|
-
result = await response.json()
|
|
573
280
|
|
|
574
|
-
|
|
281
|
+
class WSMethod(str):
|
|
282
|
+
SUBSCRIPTION = "SUBSCRIPTION"
|
|
283
|
+
UNSUBSCRIPTION = "UNSUBSCRIPTION"
|
|
284
|
+
SEND_MESSAGE = "SEND_MESSAGE"
|
|
285
|
+
RECEIVE_MESSAGE = "RECEIVE_MESSAGE"
|
|
286
|
+
PING = "PING"
|
|
575
287
|
|
|
576
|
-
async def download_file(self, file_id: str) -> dict:
|
|
577
|
-
"""Скачивание файла"""
|
|
578
|
-
params = {"fileId": file_id}
|
|
579
288
|
|
|
580
|
-
|
|
581
|
-
|
|
289
|
+
class SendTextMessage(BaseModel):
|
|
290
|
+
"""Отправка текстового сообщения"""
|
|
582
291
|
|
|
292
|
+
content: str
|
|
293
|
+
conversationId: int
|
|
294
|
+
type: int = ChatMessageType.TEXT
|
|
583
295
|
|
|
584
|
-
# ============ Usage Example ============
|
|
585
296
|
|
|
297
|
+
class SendImageMessage(BaseModel):
|
|
298
|
+
"""Отправка изображения"""
|
|
586
299
|
|
|
587
|
-
|
|
588
|
-
|
|
300
|
+
imageUrl: str
|
|
301
|
+
imageThumbUrl: str
|
|
302
|
+
conversationId: int
|
|
303
|
+
type: int = ChatMessageType.IMAGE
|
|
589
304
|
|
|
590
|
-
api_key = "your_api_key"
|
|
591
|
-
api_secret = "your_api_secret"
|
|
592
305
|
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
ad_request = CreateUpdateAdRequest(
|
|
596
|
-
payTimeLimit=15,
|
|
597
|
-
initQuantity=Decimal("100"),
|
|
598
|
-
price=Decimal("70000"),
|
|
599
|
-
coinId="5989b56ba96a43599dbeeca5bb053f43",
|
|
600
|
-
side=Side.BUY,
|
|
601
|
-
fiatUnit="USD",
|
|
602
|
-
payMethod="1",
|
|
603
|
-
minSingleTransAmount=Decimal("10"),
|
|
604
|
-
maxSingleTransAmount=Decimal("1000"),
|
|
605
|
-
userAllTradeCountMin=0,
|
|
606
|
-
userAllTradeCountMax=100,
|
|
607
|
-
)
|
|
306
|
+
class SendVideoMessage(BaseModel):
|
|
307
|
+
"""Отправка видео"""
|
|
608
308
|
|
|
609
|
-
|
|
610
|
-
|
|
309
|
+
videoUrl: str
|
|
310
|
+
imageThumbUrl: str # превью видео
|
|
311
|
+
conversationId: int
|
|
312
|
+
type: int = ChatMessageType.VIDEO
|
|
611
313
|
|
|
612
|
-
# Получение рыночных объявлений
|
|
613
|
-
market_ads = await client.get_market_ads(
|
|
614
|
-
fiat_unit="USD", coin_id="5989b56ba96a43599dbeeca5bb053f43", side=Side.SELL, page=1
|
|
615
|
-
)
|
|
616
314
|
|
|
617
|
-
|
|
315
|
+
class SendFileMessage(BaseModel):
|
|
316
|
+
"""Отправка файла"""
|
|
618
317
|
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
order_request = CreateOrderRequest(advNo=first_ad.advNo, amount=Decimal("100"), userConfirmPaymentId=123)
|
|
318
|
+
fileUrl: str
|
|
319
|
+
conversationId: int
|
|
320
|
+
type: int = ChatMessageType.FILE
|
|
623
321
|
|
|
624
|
-
order_response = await client.create_order(order_request)
|
|
625
|
-
print(f"Created order: {order_response.data}")
|
|
626
322
|
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
print(f"Order state: {order_detail.data.state}")
|
|
323
|
+
class WSRequest(BaseModel):
|
|
324
|
+
"""Базовая структура WebSocket запроса"""
|
|
630
325
|
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
326
|
+
method: str
|
|
327
|
+
params: dict | list[str] | None = None
|
|
328
|
+
id: int = None
|
|
634
329
|
|
|
635
330
|
|
|
636
|
-
|
|
637
|
-
|
|
331
|
+
class WSBaseResponse(BaseModel):
|
|
332
|
+
"""Базовый ответ WebSocket"""
|
|
638
333
|
|
|
639
|
-
|
|
334
|
+
success: bool
|
|
335
|
+
method: str
|
|
336
|
+
msg: str
|
|
337
|
+
data: Optional[str] = None
|
|
338
|
+
|
|
339
|
+
|
|
340
|
+
class ReceivedChatMessage(BaseModel):
|
|
341
|
+
"""Полученное сообщение из чата"""
|
|
342
|
+
|
|
343
|
+
id: int
|
|
344
|
+
content: Optional[str] = None
|
|
345
|
+
conversationId: int
|
|
346
|
+
type: int
|
|
347
|
+
imageUrl: Optional[str] = None
|
|
348
|
+
imageThumbUrl: Optional[str] = None
|
|
349
|
+
videoUrl: Optional[str] = None
|
|
350
|
+
fileUrl: Optional[str] = None
|
|
351
|
+
createTime: str
|
|
352
|
+
self_: bool = Field(alias="self")
|
|
353
|
+
fromUserId: str
|
|
354
|
+
fromNickName: str
|