xync-client 0.0.141__py3-none-any.whl → 0.0.156.dev18__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 +5 -0
- xync_client/Abc/Agent.py +354 -8
- xync_client/Abc/Ex.py +432 -25
- xync_client/Abc/HasAbotUid.py +10 -0
- xync_client/Abc/InAgent.py +0 -11
- xync_client/Abc/PmAgent.py +34 -26
- xync_client/Abc/xtype.py +57 -3
- xync_client/Bybit/InAgent.py +233 -409
- xync_client/Bybit/agent.py +844 -777
- xync_client/Bybit/etype/__init__.py +0 -0
- xync_client/Bybit/etype/ad.py +54 -86
- xync_client/Bybit/etype/cred.py +29 -9
- xync_client/Bybit/etype/order.py +75 -103
- xync_client/Bybit/ex.py +35 -48
- xync_client/Gmail/__init__.py +119 -98
- xync_client/Htx/agent.py +213 -40
- xync_client/Htx/etype/ad.py +40 -16
- xync_client/Htx/etype/order.py +194 -0
- xync_client/Htx/ex.py +17 -19
- xync_client/Mexc/agent.py +268 -0
- xync_client/Mexc/api.py +1255 -0
- xync_client/Mexc/etype/ad.py +52 -1
- xync_client/Mexc/etype/order.py +354 -0
- xync_client/Mexc/ex.py +34 -22
- 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 -59
- xync_client/Pms/Payeer/trade.py +58 -0
- xync_client/Pms/Volet/__init__.py +82 -63
- xync_client/Pms/Volet/api.py +5 -4
- xync_client/loader.py +2 -0
- xync_client/pm_unifier.py +1 -1
- {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/METADATA +5 -1
- {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/RECORD +38 -29
- xync_client/Pms/Payeer/__init__.py +0 -253
- xync_client/Pms/Payeer/api.py +0 -25
- {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/WHEEL +0 -0
- {xync_client-0.0.141.dist-info → xync_client-0.0.156.dev18.dist-info}/top_level.txt +0 -0
xync_client/Htx/etype/ad.py
CHANGED
|
@@ -1,48 +1,72 @@
|
|
|
1
1
|
from typing import Literal
|
|
2
2
|
|
|
3
|
-
from pydantic import BaseModel
|
|
3
|
+
from pydantic import BaseModel, RootModel
|
|
4
4
|
from xync_schema.xtype import BaseAd
|
|
5
5
|
|
|
6
|
+
from xync_client.Abc.xtype import BaseAdUpdate
|
|
7
|
+
|
|
6
8
|
|
|
7
9
|
class TradeRule(BaseModel):
|
|
8
10
|
title: str
|
|
9
|
-
titleValue: str
|
|
11
|
+
titleValue: str | None = None
|
|
10
12
|
content: str
|
|
11
13
|
inputType: int
|
|
12
14
|
inputValue: str
|
|
13
15
|
hint: str
|
|
14
|
-
contentCode:
|
|
16
|
+
contentCode: Literal["PAY", "MERCHANT"]
|
|
17
|
+
contentType: int | None = None
|
|
15
18
|
sort: int
|
|
16
19
|
|
|
17
20
|
|
|
18
|
-
|
|
21
|
+
TradeRulesV2 = RootModel[list[TradeRule]]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class AdsUpd(BaseAdUpdate):
|
|
19
25
|
tradeType: int
|
|
20
26
|
coinId: int
|
|
21
27
|
currency: int
|
|
22
28
|
minTradeLimit: float
|
|
23
29
|
maxTradeLimit: float
|
|
24
30
|
tradeCount: float
|
|
25
|
-
password: str
|
|
31
|
+
password: str = ""
|
|
26
32
|
payTerm: int
|
|
27
33
|
isFixed: Literal["off", "on"]
|
|
28
|
-
premium:
|
|
34
|
+
premium: float
|
|
29
35
|
isAutoReply: Literal["off", "on"]
|
|
30
36
|
takerAcceptOrder: int
|
|
31
37
|
isPayCode: Literal["off", "on"]
|
|
32
|
-
|
|
33
|
-
receiveAccounts:
|
|
38
|
+
verifyCapitalStatus: str = None # todo: check if int
|
|
39
|
+
receiveAccounts: str
|
|
34
40
|
deviation: int
|
|
35
41
|
isTakerLimit: Literal["off", "on"]
|
|
42
|
+
takerRealLevel: Literal["off", "on"]
|
|
43
|
+
takerIsPhoneBind: Literal["off", "on"]
|
|
44
|
+
takerIsMerchant: Literal["off", "on"]
|
|
45
|
+
takerIsPayment: Literal["off", "on"]
|
|
36
46
|
blockType: int
|
|
37
47
|
session: int
|
|
38
48
|
chargeType: bool
|
|
39
49
|
apiVersion: int
|
|
40
50
|
channel: str
|
|
41
|
-
tradeRulesV2:
|
|
51
|
+
tradeRulesV2: str # TradeRulesV2
|
|
42
52
|
securityToken: str | None = ""
|
|
43
|
-
fixedPrice:
|
|
53
|
+
fixedPrice: float | None = None
|
|
44
54
|
autoReplyContent: str | None = ""
|
|
45
|
-
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
class AdsReq(BaseModel):
|
|
58
|
+
coinId: int
|
|
59
|
+
currency: int
|
|
60
|
+
tradeType: Literal["sell", "buy"]
|
|
61
|
+
payMethod: str
|
|
62
|
+
currPage: int = 1
|
|
63
|
+
acceptOrder: int = 0
|
|
64
|
+
blockType: Literal["general"] = "general"
|
|
65
|
+
online: int = 1
|
|
66
|
+
range: int = 0
|
|
67
|
+
amount: str = "" # float
|
|
68
|
+
onlyTradable: str = "false" # bool
|
|
69
|
+
isFollowed: str = "false" # bool
|
|
46
70
|
|
|
47
71
|
|
|
48
72
|
class PayMethod(BaseModel):
|
|
@@ -69,21 +93,21 @@ class Resp(BaseAd):
|
|
|
69
93
|
isOnline: bool
|
|
70
94
|
isTrade: bool
|
|
71
95
|
isVerifyCapital: bool
|
|
72
|
-
maxTradeLimit:
|
|
96
|
+
maxTradeLimit: float
|
|
73
97
|
merchantLevel: int
|
|
74
|
-
minTradeLimit:
|
|
98
|
+
minTradeLimit: float
|
|
75
99
|
orderCompleteRate: str
|
|
76
100
|
payMethod: str
|
|
77
101
|
payMethods: list[PayMethod]
|
|
78
|
-
payName: str # list[PayName]
|
|
102
|
+
payName: str # list[PayName] # приходит массив объектов внутри строки
|
|
79
103
|
payTerm: int
|
|
80
|
-
price:
|
|
104
|
+
price: float
|
|
81
105
|
takerAcceptAmount: str
|
|
82
106
|
takerAcceptOrder: int
|
|
83
107
|
takerLimit: int
|
|
84
108
|
thumbUp: int
|
|
85
109
|
totalTradeOrderCount: int
|
|
86
|
-
tradeCount:
|
|
110
|
+
tradeCount: float
|
|
87
111
|
tradeMonthTimes: int
|
|
88
112
|
tradeType: int
|
|
89
113
|
uid: int
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
from decimal import Decimal
|
|
2
|
+
from typing import Literal
|
|
3
|
+
|
|
4
|
+
from pydantic import BaseModel, NonNegativeInt, Field, PositiveInt
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class C2COrder(BaseModel):
|
|
8
|
+
cancelCountDown: NonNegativeInt
|
|
9
|
+
consultCancelCountDown: NonNegativeInt
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class OrderItem(BaseModel):
|
|
13
|
+
orderId: int
|
|
14
|
+
counterpartUid: PositiveInt
|
|
15
|
+
counterpartNickName: str
|
|
16
|
+
counterpartIsOnline: bool
|
|
17
|
+
counterpartOrderCount: NonNegativeInt
|
|
18
|
+
counterpartLastTradeTime: NonNegativeInt # timestamp in ms
|
|
19
|
+
counterpartMerchantLevel: NonNegativeInt
|
|
20
|
+
counterpartThumbUp: NonNegativeInt
|
|
21
|
+
counterpartRocketAmount: NonNegativeInt | None
|
|
22
|
+
counterpartPrimeLevel: str = Field(pattern=r"^Prime\d+$")
|
|
23
|
+
counterpartRecentWithdrawTime: PositiveInt | None # timestamp in ms
|
|
24
|
+
side: Literal[0, 1] # 0=buy, 1=sell
|
|
25
|
+
tradeMode: Literal[1, 2] # предполагаемые значения
|
|
26
|
+
runMode: Literal[1, 2] # предполагаемые значения
|
|
27
|
+
quoteAssetName: str = Field(min_length=1, max_length=10)
|
|
28
|
+
cryptoAssetName: str = Field(min_length=1, max_length=10)
|
|
29
|
+
amount: Decimal = Field(gt=0, decimal_places=2)
|
|
30
|
+
quantity: Decimal = Field(gt=0)
|
|
31
|
+
quote: Decimal = Field(gt=0, decimal_places=2)
|
|
32
|
+
orderStatus: NonNegativeInt
|
|
33
|
+
c2cOrder: C2COrder = None
|
|
34
|
+
inNegotiation: bool
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
class ModelField(BaseModel):
|
|
38
|
+
fieldId: str
|
|
39
|
+
name: str
|
|
40
|
+
fieldType: Literal["payee", "pay_account", "bank", "sub_bank", "qr_code"]
|
|
41
|
+
index: PositiveInt
|
|
42
|
+
maxLength: int | None = None
|
|
43
|
+
required: bool | None = None
|
|
44
|
+
copyable: bool
|
|
45
|
+
remindWord: str | None = None
|
|
46
|
+
valueType: str | None = None
|
|
47
|
+
value: str
|
|
48
|
+
nameList: list | None = None
|
|
49
|
+
remindWordList: list | None = None
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
class PaymentMethod(BaseModel):
|
|
53
|
+
id: PositiveInt
|
|
54
|
+
userName: str = Field(min_length=1)
|
|
55
|
+
bankType: PositiveInt
|
|
56
|
+
bankNumber: str
|
|
57
|
+
bankName: str | None = None
|
|
58
|
+
bankAddress: str | None = None
|
|
59
|
+
qrCode: str | None = None
|
|
60
|
+
color: str = Field(pattern=r"^#[0-9A-F]{6}$")
|
|
61
|
+
payMethodName: str = Field(min_length=1)
|
|
62
|
+
paymentStatus: Literal[1]
|
|
63
|
+
modelFieldsList: list[ModelField]
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class OrderInfo(BaseModel):
|
|
67
|
+
orderId: PositiveInt
|
|
68
|
+
orderNo: PositiveInt
|
|
69
|
+
uid: PositiveInt
|
|
70
|
+
nickName: str = Field(min_length=1)
|
|
71
|
+
realName: str | None = None
|
|
72
|
+
roleName: Literal["maker", "taker"]
|
|
73
|
+
side: Literal[0, 1]
|
|
74
|
+
runMode: Literal[1]
|
|
75
|
+
tradeMode: Literal[1]
|
|
76
|
+
liquidDivision: Literal[3]
|
|
77
|
+
sideName: Literal["buy", "sell"]
|
|
78
|
+
quoteAssetId: PositiveInt
|
|
79
|
+
quoteAssetType: Literal[1]
|
|
80
|
+
quoteAssetName: str = Field(min_length=1, max_length=10)
|
|
81
|
+
quoteAssetSymbol: str
|
|
82
|
+
cryptoAssetId: PositiveInt
|
|
83
|
+
cryptoAssetType: Literal[2]
|
|
84
|
+
cryptoAssetName: str = Field(min_length=1, max_length=10)
|
|
85
|
+
cryptoAssetSymbol: str
|
|
86
|
+
amount: Decimal = Field(gt=0, decimal_places=2)
|
|
87
|
+
quantity: Decimal = Field(gt=0)
|
|
88
|
+
quote: Decimal = Field(gt=0, decimal_places=2)
|
|
89
|
+
orderStatus: NonNegativeInt
|
|
90
|
+
gmtCreate: PositiveInt
|
|
91
|
+
gmtModified: PositiveInt
|
|
92
|
+
areaType: Literal[1]
|
|
93
|
+
appealCountDown: NonNegativeInt
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class OtherInfo(BaseModel):
|
|
97
|
+
uid: PositiveInt
|
|
98
|
+
nickName: str = Field(min_length=1)
|
|
99
|
+
realName: str | None = None
|
|
100
|
+
gmtCreate: PositiveInt
|
|
101
|
+
merchantLevel: NonNegativeInt
|
|
102
|
+
realTradeCountBuy: NonNegativeInt
|
|
103
|
+
realTradeCountSell: NonNegativeInt
|
|
104
|
+
registerTime: PositiveInt
|
|
105
|
+
isPhoneBind: bool
|
|
106
|
+
marginAssetId: NonNegativeInt
|
|
107
|
+
marginAssetName: str | None = None
|
|
108
|
+
marginAmount: NonNegativeInt
|
|
109
|
+
appealMonthTimes: NonNegativeInt
|
|
110
|
+
appealMonthWinTimes: NonNegativeInt
|
|
111
|
+
isOnline: bool
|
|
112
|
+
isSeniorAuth: bool
|
|
113
|
+
orderCompleteRate: Decimal = Field(ge=0, le=100, decimal_places=2)
|
|
114
|
+
tradeMonthCount: NonNegativeInt
|
|
115
|
+
tradeCount: NonNegativeInt
|
|
116
|
+
releaseTime: NonNegativeInt
|
|
117
|
+
buyCompleteRate: Decimal = Field(ge=0, le=100, decimal_places=2)
|
|
118
|
+
buyCancelTimeAvg: Decimal = Field(ge=0, decimal_places=2)
|
|
119
|
+
thumbUp: NonNegativeInt
|
|
120
|
+
merchantTags: str | None = None
|
|
121
|
+
totalUserTradeCount: NonNegativeInt
|
|
122
|
+
totalTradeOrderCount: NonNegativeInt
|
|
123
|
+
totalTradeOrderCancelCount: NonNegativeInt
|
|
124
|
+
orderBuyCompleteRate: Decimal = Field(ge=0, le=100, decimal_places=2)
|
|
125
|
+
orderSellCompleteRate: Decimal = Field(ge=0, le=100, decimal_places=2)
|
|
126
|
+
totalOrderCompleteRate: Decimal = Field(ge=0, le=100, decimal_places=2)
|
|
127
|
+
counterpartRocketAmount: int | None = None
|
|
128
|
+
counterpartPrimeLevel: str = Field(pattern=r"^Prime\d+$")
|
|
129
|
+
counterpartRecentWithdrawTime: PositiveInt | None = None
|
|
130
|
+
counterpartOrderCount: NonNegativeInt
|
|
131
|
+
counterpartLastTradeTime: NonNegativeInt
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class Fee(BaseModel):
|
|
135
|
+
feeType: Literal[1]
|
|
136
|
+
feeStatus: Literal[1, 2]
|
|
137
|
+
fee: Decimal = Field(ge=0)
|
|
138
|
+
feeName: str = Field(min_length=1)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
class FeeInfo(BaseModel):
|
|
142
|
+
totalFee: Decimal = Field(ge=0)
|
|
143
|
+
feeList: list[Fee]
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
class OrderTag(BaseModel):
|
|
147
|
+
isSoonLock: Literal[1, 2]
|
|
148
|
+
isPremature: Literal[1, 2]
|
|
149
|
+
isAppeal: Literal[1, 2]
|
|
150
|
+
specialCancelFlag: Literal[1, 2]
|
|
151
|
+
isPhone: Literal[1, 2]
|
|
152
|
+
now: PositiveInt
|
|
153
|
+
isAppealPremature: Literal[1, 2]
|
|
154
|
+
isFollowed: bool
|
|
155
|
+
isShield: bool
|
|
156
|
+
negotiationStatus: int | None = None
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
class C2COrderDetail(BaseModel):
|
|
160
|
+
matchPayId: int | None = None
|
|
161
|
+
payTerm: PositiveInt
|
|
162
|
+
payCode: str | None = None
|
|
163
|
+
quote: Decimal = Field(gt=0, decimal_places=2)
|
|
164
|
+
amount: Decimal = Field(gt=0, decimal_places=2)
|
|
165
|
+
quantity: Decimal = Field(gt=0)
|
|
166
|
+
quoteAssetName: str = Field(min_length=1)
|
|
167
|
+
cryptoAssetName: str = Field(min_length=1)
|
|
168
|
+
buyPayAccount: PositiveInt | None
|
|
169
|
+
gmtPay: PositiveInt | None
|
|
170
|
+
gmtResetCancel: PositiveInt | None = None
|
|
171
|
+
orderStatus: NonNegativeInt
|
|
172
|
+
cancelCountDown: NonNegativeInt
|
|
173
|
+
consultCancelCountDown: NonNegativeInt
|
|
174
|
+
waitCompletedCountDown: NonNegativeInt
|
|
175
|
+
areaType: Literal[1]
|
|
176
|
+
acceptStatus: Literal[0, 1]
|
|
177
|
+
appCountDown: NonNegativeInt
|
|
178
|
+
appMaxCountDown: NonNegativeInt
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
class OrderSnapshot(BaseModel):
|
|
182
|
+
tradeInstructionStatus: Literal["INIT", "COMPLETED"] # добавь другие статусы
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class OrderFull(BaseModel):
|
|
186
|
+
orderInfo: OrderInfo
|
|
187
|
+
otherInfo: OtherInfo
|
|
188
|
+
paymentMethod: list[PaymentMethod]
|
|
189
|
+
feeInfo: FeeInfo
|
|
190
|
+
orderTag: OrderTag
|
|
191
|
+
c2cOrder: C2COrderDetail
|
|
192
|
+
inNegotiation: bool
|
|
193
|
+
takerEvaluateStatus: Literal[0, 1]
|
|
194
|
+
orderSnapshot: OrderSnapshot
|
xync_client/Htx/ex.py
CHANGED
|
@@ -9,7 +9,7 @@ from xync_schema.models import Ex, Cur
|
|
|
9
9
|
from xync_schema.enums import PmType
|
|
10
10
|
|
|
11
11
|
from xync_client.Abc.Ex import BaseExClient
|
|
12
|
-
from xync_client.Abc.xtype import PmEx, MapOfIdsList
|
|
12
|
+
from xync_client.Abc.xtype import PmEx, MapOfIdsList, GetAds
|
|
13
13
|
from xync_client.Htx.etype import pm, Country, ad
|
|
14
14
|
from xync_client.loader import NET_TOKEN
|
|
15
15
|
from xync_client.loader import TORM
|
|
@@ -42,24 +42,22 @@ class ExClient(BaseExClient):
|
|
|
42
42
|
pair[rcurs[cur["name"]]] += [coen]
|
|
43
43
|
return tuple(pairs.values())
|
|
44
44
|
|
|
45
|
-
async def
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
"
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
}
|
|
62
|
-
res = (await self._get("/-/x/otc/v1/data/trade-market", params))["data"]
|
|
45
|
+
async def x2e_req_ads(self, xreq: GetAds) -> ad.AdsReq:
|
|
46
|
+
coin_id, _ = await self.x2e_coin(xreq.coin_id)
|
|
47
|
+
cur_id, _, __ = await self.x2e_cur(xreq.cur_id)
|
|
48
|
+
ereq = ad.AdsReq(
|
|
49
|
+
coinId=int(coin_id),
|
|
50
|
+
currency=int(cur_id),
|
|
51
|
+
tradeType="sell" if xreq.is_sell else "buy",
|
|
52
|
+
payMethod=",".join([await self.x2e_pm(pm_id) for pm_id in xreq.pm_ids]),
|
|
53
|
+
)
|
|
54
|
+
if xreq.amount:
|
|
55
|
+
ereq.amount = str(xreq.amount)
|
|
56
|
+
# todo: all kwargs
|
|
57
|
+
return ereq
|
|
58
|
+
|
|
59
|
+
async def _ads(self, req: ad.AdsReq, lim: int = None, vm_filter: bool = False, **kwargs) -> list[ad.Resp]:
|
|
60
|
+
res = (await self._get("/-/x/otc/v1/data/trade-market", req.model_dump()))["data"]
|
|
63
61
|
ads = [ad.Resp(**a) for a in res]
|
|
64
62
|
return ads
|
|
65
63
|
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import json
|
|
2
|
+
import logging
|
|
3
|
+
from asyncio import run, sleep, create_task
|
|
4
|
+
from hashlib import md5
|
|
5
|
+
from urllib.parse import quote
|
|
6
|
+
from uuid import uuid4
|
|
7
|
+
|
|
8
|
+
import websockets
|
|
9
|
+
from blackboxprotobuf import protobuf_to_json
|
|
10
|
+
from pyro_client.client.file import FileClient
|
|
11
|
+
from xync_bot import XyncBot
|
|
12
|
+
|
|
13
|
+
from xync_client.Mexc.api import MEXCP2PApiClient
|
|
14
|
+
from xync_client.Mexc.etype import ad
|
|
15
|
+
|
|
16
|
+
from xync_client.Abc.xtype import GetAds, AdUpd
|
|
17
|
+
from xync_client.Bybit.etype.order import TakeAdReq
|
|
18
|
+
from xync_client.Mexc.etype.order import OrderDetail
|
|
19
|
+
|
|
20
|
+
from xync_client.loader import PAY_TOKEN, NET_TOKEN
|
|
21
|
+
from xync_schema import models
|
|
22
|
+
from xync_schema.enums import UserStatus, AgentStatus
|
|
23
|
+
|
|
24
|
+
from xync_client.Abc.Agent import BaseAgentClient
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class AgentClient(BaseAgentClient):
|
|
28
|
+
i: int = 5
|
|
29
|
+
headers = {
|
|
30
|
+
# "Accept-Encoding": "gzip, deflate, br, zstd",
|
|
31
|
+
"Accept-Language": "ru,en;q=0.9",
|
|
32
|
+
"Language:": "ru-RU",
|
|
33
|
+
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/142.0.0.0 Safari/537.36",
|
|
34
|
+
}
|
|
35
|
+
api: MEXCP2PApiClient
|
|
36
|
+
|
|
37
|
+
@staticmethod
|
|
38
|
+
async def _heartbeat(ws):
|
|
39
|
+
"""Фоновая задача для PING/PONG"""
|
|
40
|
+
while True:
|
|
41
|
+
await sleep(25)
|
|
42
|
+
await ws.send('{"method":"PING"}')
|
|
43
|
+
|
|
44
|
+
async def _ws_key(self):
|
|
45
|
+
self.i = 13 if self.i > 9999 else self.i + 1
|
|
46
|
+
hdrs = self.agent.auth["headers"] | {
|
|
47
|
+
"trochilus-trace-id": "c7831459-3bb2-4aa7-bf5d-9ff2adef0c08-0062",
|
|
48
|
+
"ucenter-token": self.agent.auth["cookies"]["u_id"],
|
|
49
|
+
}
|
|
50
|
+
# resp = get("https://www.mexc.com/ucenter/api/ws_token", headers=hdrs, cookies=self.agent.auth['cookies'])
|
|
51
|
+
resp = await self._get("/ucenter/api/ws_token", hdrs=hdrs)
|
|
52
|
+
self.wkk = resp["data"]["wsToken"]
|
|
53
|
+
|
|
54
|
+
async def ws_prv(self):
|
|
55
|
+
await self._ws_key()
|
|
56
|
+
url = f"wss://wbs.mexc.com/ws?wsToken={self.wkk}"
|
|
57
|
+
async with websockets.connect(url) as ws:
|
|
58
|
+
create_task(self._heartbeat(ws))
|
|
59
|
+
await ws.send('{"method":"SUBSCRIPTION","params":["otc@private.p2p.orders.pb"],"id":12}')
|
|
60
|
+
await ws.send('{"method":"SUBSCRIPTION","params":["common@private.risk.result.pb"],"id":11}')
|
|
61
|
+
while resp := await ws.recv():
|
|
62
|
+
try:
|
|
63
|
+
data: dict = json.loads(resp)
|
|
64
|
+
except UnicodeDecodeError:
|
|
65
|
+
msg, typedef = protobuf_to_json(resp)
|
|
66
|
+
data = json.loads(msg)
|
|
67
|
+
await self.recv(data)
|
|
68
|
+
if data.get("msg") == "PONG":
|
|
69
|
+
print(end="p")
|
|
70
|
+
else:
|
|
71
|
+
logging.warning(data)
|
|
72
|
+
|
|
73
|
+
async def recv(self, data: dict):
|
|
74
|
+
if data["1"] == "otc@private.p2p.orders.pb":
|
|
75
|
+
o = data["218"]["1"]
|
|
76
|
+
order: OrderDetail = (await self.api.get_order_detail(o["1"])).data
|
|
77
|
+
if order.side == "SELL":
|
|
78
|
+
if order.state == "NOT_PAID":
|
|
79
|
+
...
|
|
80
|
+
elif order.side == "BUY":
|
|
81
|
+
if order.state == "PAID":
|
|
82
|
+
...
|
|
83
|
+
...
|
|
84
|
+
|
|
85
|
+
async def _take_ad(self, req: TakeAdReq):
|
|
86
|
+
self.i = 33 if self.i > 9998 else self.i + 2
|
|
87
|
+
hdrs = self.headers | {"trochilus-trace-id": f"{uuid4()}-{self.i:04d}"}
|
|
88
|
+
auth = {
|
|
89
|
+
"p0": self.actor.agent.auth["p0"],
|
|
90
|
+
"k0": self.actor.agent.auth["k0"],
|
|
91
|
+
"chash": self.actor.agent.auth["chash"],
|
|
92
|
+
"mtoken": self.actor.agent.auth["deviceId"],
|
|
93
|
+
"mhash": md5(self.actor.agent.auth["deviceId"].encode()).hexdigest(),
|
|
94
|
+
}
|
|
95
|
+
data = {
|
|
96
|
+
"scene": "TRADE_BUY",
|
|
97
|
+
"quantity": req.quantity,
|
|
98
|
+
"amount": req.amount,
|
|
99
|
+
"orderId": req.ad_id,
|
|
100
|
+
"authVersion": "v2",
|
|
101
|
+
"deviceId": auth["mtoken"],
|
|
102
|
+
}
|
|
103
|
+
res = await self._post("/api/platform/p2p/api/verify/second_auth/risk/scene", json=data, hdrs=hdrs)
|
|
104
|
+
data = {
|
|
105
|
+
"amount": req.amount,
|
|
106
|
+
"authVersion": "v2",
|
|
107
|
+
"orderId": req.ad_id,
|
|
108
|
+
"price": req.price,
|
|
109
|
+
"ts": int(1761155700.8372989 * 1000),
|
|
110
|
+
"userConfirmPaymentId" if req.is_sell else "userConfirmPayMethodId": req.pm_id,
|
|
111
|
+
}
|
|
112
|
+
self.i = 33 if self.i > 9999 else self.i + 1
|
|
113
|
+
hdrs = self.headers | {"trochilus-trace-id": f"{uuid4()}-{self.i:04d}"}
|
|
114
|
+
res = await self._post("/api/platform/p2p/api/order/deal?mhash=" + auth["mhash"], data=auth | data, hdrs=hdrs)
|
|
115
|
+
return res["data"]
|
|
116
|
+
|
|
117
|
+
async def x2e_req_ad_upd(self, xreq: AdUpd) -> ad.AdUpd:
|
|
118
|
+
coin_id, coin_scale = await self.ex_client.x2e_coin(xreq.coin_id)
|
|
119
|
+
cur_id, cur_scale, minimum = await self.ex_client.x2e_cur(xreq.cur_id)
|
|
120
|
+
ereq = ad.AdUpd(
|
|
121
|
+
id=xreq.id,
|
|
122
|
+
price=round(xreq.price, cur_scale),
|
|
123
|
+
coinId=coin_id,
|
|
124
|
+
currency=cur_id,
|
|
125
|
+
tradeType="SELL" if xreq.is_sell else "BUY",
|
|
126
|
+
deviceId=self.agent.auth["deviceId"],
|
|
127
|
+
payment=",".join([str(cdx.exid) for cdx in xreq.credexs]),
|
|
128
|
+
priceType=0,
|
|
129
|
+
minTradeLimit=minimum,
|
|
130
|
+
maxTradeLimit=round(xreq.max_amount or xreq.amount - 10**-cur_scale, cur_scale),
|
|
131
|
+
quantity=round(xreq.quantity or xreq.amount / xreq.price, coin_scale),
|
|
132
|
+
)
|
|
133
|
+
if xreq.cond:
|
|
134
|
+
ereq.autoResponse = quote(xreq.cond)
|
|
135
|
+
# todo: all kwargs
|
|
136
|
+
return ereq
|
|
137
|
+
|
|
138
|
+
async def _ad_upd(self, req: ad.AdUpd):
|
|
139
|
+
self.i = 33 if self.i > 9999 else self.i + 1
|
|
140
|
+
hdrs = self.headers | {"trochilus-trace-id": f"{uuid4()}-{self.i:04d}"}
|
|
141
|
+
res = await self._put("/api/platform/p2p/api/merchant/order", form_data=req.model_dump(), hdrs=hdrs)
|
|
142
|
+
return res["code"]
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
async def main():
|
|
146
|
+
from x_model import init_db
|
|
147
|
+
from xync_client.loader import TORM
|
|
148
|
+
|
|
149
|
+
cn = await init_db(TORM, True)
|
|
150
|
+
|
|
151
|
+
ex = await models.Ex[12]
|
|
152
|
+
agent = (
|
|
153
|
+
await models.Agent.filter(
|
|
154
|
+
actor__ex=ex,
|
|
155
|
+
status__gte=AgentStatus.race,
|
|
156
|
+
auth__isnull=False,
|
|
157
|
+
actor__person__user__status=UserStatus.ACTIVE,
|
|
158
|
+
actor__person__user__pm_agents__isnull=False,
|
|
159
|
+
)
|
|
160
|
+
.prefetch_related("actor__ex", "actor__person__user__gmail")
|
|
161
|
+
.first()
|
|
162
|
+
)
|
|
163
|
+
bbot = XyncBot(PAY_TOKEN, cn)
|
|
164
|
+
fbot = FileClient(NET_TOKEN)
|
|
165
|
+
ecl = ex.client(fbot)
|
|
166
|
+
cl: AgentClient = agent.client(ecl, fbot, bbot)
|
|
167
|
+
cl.api = MEXCP2PApiClient(agent.auth["key"], agent.auth["sec"])
|
|
168
|
+
create_task(cl.ws_prv())
|
|
169
|
+
|
|
170
|
+
while True:
|
|
171
|
+
bceil = 106
|
|
172
|
+
sceil = 124.98
|
|
173
|
+
breq = GetAds(coin_id=1, cur_id=1, is_sell=False, pm_ids=[366])
|
|
174
|
+
sreq = GetAds(coin_id=1, cur_id=1, is_sell=True, pm_ids=[366])
|
|
175
|
+
breq_upd = AdUpd(
|
|
176
|
+
id="a1574183931501582340", price=87, **{**breq.model_dump(), "amount": 11000.01}, max_amount=4370
|
|
177
|
+
) # + 1 cent
|
|
178
|
+
sreq_upd = AdUpd(id="a1594624084590445568", price=150, **{**sreq.model_dump(), "amount": 30000.01})
|
|
179
|
+
|
|
180
|
+
await sleep(5)
|
|
181
|
+
bads: list[ad.Ad] = await cl.ex_client.ads(breq)
|
|
182
|
+
if bads[0].price >= sceil:
|
|
183
|
+
bad: ad.Ad = bads.pop(0)
|
|
184
|
+
await cl.bbot.send(
|
|
185
|
+
193017646,
|
|
186
|
+
f"price: {bad.price}\nnick: {bad.merchant.nickName}\nmax:{bad.maxPayLimit}"
|
|
187
|
+
f"\nqty: {bad.availableQuantity} [{bad.minTradeLimit}-{bad.maxTradeLimit}]",
|
|
188
|
+
)
|
|
189
|
+
# am = min(bad.maxTradeLimit, max(10000.0, bad.minTradeLimit))
|
|
190
|
+
# req = TakeAdReq(
|
|
191
|
+
# ad_id=bad.exid,
|
|
192
|
+
# amount=am,
|
|
193
|
+
# pm_id=366,
|
|
194
|
+
# is_sell=False,
|
|
195
|
+
# coin_id=1,
|
|
196
|
+
# cur_id=1,
|
|
197
|
+
# )
|
|
198
|
+
# ord_resp: OrderResp = await cl.take_ad(req)
|
|
199
|
+
|
|
200
|
+
bads = [
|
|
201
|
+
a
|
|
202
|
+
for a in bads
|
|
203
|
+
if a.price <= bceil and a.availableQuantity > 20 and (a.maxTradeLimit - a.minTradeLimit > 1000)
|
|
204
|
+
]
|
|
205
|
+
if len(bads) > 1:
|
|
206
|
+
if bads[0].merchant.nickName == cl.actor.name:
|
|
207
|
+
if round(bads[0].price - bads[1].price, 2) > 0.01:
|
|
208
|
+
breq_upd.price = bads[1].price + 0.01
|
|
209
|
+
if _ := await cl.ad_upd(breq_upd):
|
|
210
|
+
await sleep(5, print(_, flush=True))
|
|
211
|
+
print(end="!", flush=True)
|
|
212
|
+
elif bads[0].price != (trgt_price := bads[0].price + 0.01):
|
|
213
|
+
breq_upd.price = trgt_price
|
|
214
|
+
if _ := await cl.ad_upd(breq_upd):
|
|
215
|
+
await sleep(5, print(_, flush=True))
|
|
216
|
+
print(end="!", flush=True)
|
|
217
|
+
|
|
218
|
+
await sleep(5)
|
|
219
|
+
sads: list[ad.Ad] = await cl.ex_client.ads(sreq)
|
|
220
|
+
if sads[0].price <= bceil:
|
|
221
|
+
sad: ad.Ad = sads.pop(0)
|
|
222
|
+
await cl.bbot.send(
|
|
223
|
+
193017646,
|
|
224
|
+
f"price: {sad.price}\nnick: {sad.merchant.nickName}\nmax:{sad.maxPayLimit}"
|
|
225
|
+
f"\nqty: {sad.availableQuantity} [{sad.minTradeLimit}-{sad.maxTradeLimit}]",
|
|
226
|
+
)
|
|
227
|
+
# am = min(sad.maxTradeLimit, max(10000.0, sad.minTradeLimit))
|
|
228
|
+
# req = TakeAdReq(
|
|
229
|
+
# ad_id=sad.exid,
|
|
230
|
+
# amount=am,
|
|
231
|
+
# pm_id=366,
|
|
232
|
+
# is_sell=False,
|
|
233
|
+
# coin_id=1,
|
|
234
|
+
# cur_id=1,
|
|
235
|
+
# )
|
|
236
|
+
# ord_resp: OrderResp = await cl.take_ad(req)
|
|
237
|
+
|
|
238
|
+
sads = [
|
|
239
|
+
a
|
|
240
|
+
for a in sads
|
|
241
|
+
if a.price >= sceil and a.availableQuantity > 20 and (a.maxTradeLimit - a.minTradeLimit > 1000)
|
|
242
|
+
]
|
|
243
|
+
if len(sads) > 1:
|
|
244
|
+
if sads[0].merchant.nickName == cl.actor.name:
|
|
245
|
+
if round(sads[1].price - sads[0].price, 2) > 0.01:
|
|
246
|
+
sreq_upd.price = sads[1].price - 0.01
|
|
247
|
+
if _ := await cl.ad_upd(sreq_upd):
|
|
248
|
+
await sleep(15, print(_, flush=True))
|
|
249
|
+
continue
|
|
250
|
+
print(end="!", flush=True)
|
|
251
|
+
continue
|
|
252
|
+
elif sads[0].price > sceil:
|
|
253
|
+
sreq_upd.price = sads[0].price - 0.01
|
|
254
|
+
if _ := await cl.ad_upd(sreq_upd):
|
|
255
|
+
await sleep(15, print(_, flush=True))
|
|
256
|
+
continue
|
|
257
|
+
print(end="!", flush=True)
|
|
258
|
+
continue
|
|
259
|
+
|
|
260
|
+
print(end=".", flush=True)
|
|
261
|
+
|
|
262
|
+
req = TakeAdReq(ad_id="a1574088909645125632", amount=500, pm_id=366, cur_id=1, price=85.8, is_sell=True)
|
|
263
|
+
res = await cl.take_ad(req)
|
|
264
|
+
print(res)
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
if __name__ == "__main__":
|
|
268
|
+
run(main())
|