xync-client 0.0.147__py3-none-any.whl → 0.0.150__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.
Potentially problematic release.
This version of xync-client might be problematic. Click here for more details.
- xync_client/Abc/AdLoader.py +293 -0
- xync_client/Abc/Agent.py +20 -1
- xync_client/Abc/Ex.py +11 -9
- xync_client/Bybit/agent.py +166 -400
- xync_client/Bybit/etype/ad.py +1 -1
- xync_client/Bybit/etype/cred.py +1 -0
- xync_client/Bybit/etype/order.py +6 -2
- xync_client/Mexc/agent.py +84 -0
- {xync_client-0.0.147.dist-info → xync_client-0.0.150.dist-info}/METADATA +4 -1
- {xync_client-0.0.147.dist-info → xync_client-0.0.150.dist-info}/RECORD +12 -10
- {xync_client-0.0.147.dist-info → xync_client-0.0.150.dist-info}/WHEEL +0 -0
- {xync_client-0.0.147.dist-info → xync_client-0.0.150.dist-info}/top_level.txt +0 -0
xync_client/Bybit/agent.py
CHANGED
|
@@ -2,10 +2,10 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
4
|
from asyncio import sleep, gather
|
|
5
|
-
from collections import defaultdict
|
|
6
5
|
from datetime import datetime, timedelta, timezone
|
|
7
6
|
from difflib import SequenceMatcher
|
|
8
7
|
from enum import IntEnum
|
|
8
|
+
from hashlib import sha256
|
|
9
9
|
from http.client import HTTPException
|
|
10
10
|
from math import floor
|
|
11
11
|
from typing import Literal
|
|
@@ -18,7 +18,7 @@ from payeer_api import PayeerAPI
|
|
|
18
18
|
from pyro_client.client.file import FileClient
|
|
19
19
|
from tortoise import BaseDBAsyncClient
|
|
20
20
|
from tortoise.exceptions import IntegrityError
|
|
21
|
-
from tortoise.expressions import
|
|
21
|
+
from tortoise.expressions import Q
|
|
22
22
|
from tortoise.functions import Count
|
|
23
23
|
from tortoise.signals import post_save
|
|
24
24
|
from urllib3.exceptions import ReadTimeoutError
|
|
@@ -28,7 +28,7 @@ from xync_bot import XyncBot
|
|
|
28
28
|
from xync_schema import models
|
|
29
29
|
from xync_schema.enums import OrderStatus
|
|
30
30
|
|
|
31
|
-
from xync_schema.models import Actor,
|
|
31
|
+
from xync_schema.models import Actor, PmCur, Agent
|
|
32
32
|
|
|
33
33
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
34
34
|
from xync_client.Abc.xtype import FlatDict, BaseOrderReq
|
|
@@ -54,8 +54,11 @@ class NoMakerException(Exception):
|
|
|
54
54
|
|
|
55
55
|
|
|
56
56
|
class AgentClient(BaseAgentClient): # Bybit client
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
headers = {
|
|
58
|
+
# "accept": "application/json",
|
|
59
|
+
"Cookie": ";",
|
|
60
|
+
}
|
|
61
|
+
# rewrite token for public methods
|
|
59
62
|
api: P2P
|
|
60
63
|
last_ad_id: list[str] = []
|
|
61
64
|
update_ad_body = {
|
|
@@ -85,28 +88,24 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
85
88
|
"actionType": "MODIFY",
|
|
86
89
|
"securityRiskToken": "",
|
|
87
90
|
}
|
|
88
|
-
all_conds: dict[int, tuple[str, set[int]]] = {}
|
|
89
|
-
cond_sims: dict[int, int] = defaultdict(set)
|
|
90
|
-
rcond_sims: dict[int, set[int]] = defaultdict(set) # backward
|
|
91
|
-
tree: dict = {}
|
|
92
91
|
|
|
93
92
|
def __init__(self, agent: Agent, fbot: FileClient, bbot: XyncBot, **kwargs):
|
|
94
93
|
super().__init__(agent, fbot, bbot, **kwargs)
|
|
95
94
|
self.api = P2P(testnet=False, api_key=agent.auth["key"], api_secret=agent.auth["sec"])
|
|
96
|
-
self.hist: dict = None
|
|
97
|
-
self.completed_orders: list[int] = None
|
|
95
|
+
self.hist: dict | None = None
|
|
96
|
+
self.completed_orders: list[int] | None = None
|
|
98
97
|
|
|
99
98
|
""" Private METHs"""
|
|
100
99
|
|
|
101
100
|
async def fiat_new(self, payment_type: int, real_name: str, account_number: str) -> FlatDict | None:
|
|
102
101
|
method1 = await self._post(
|
|
103
|
-
"/fiat/otc/user/payment/new_create",
|
|
102
|
+
"/x-api/fiat/otc/user/payment/new_create",
|
|
104
103
|
{"paymentType": payment_type, "realName": real_name, "accountNo": account_number, "securityRiskToken": ""},
|
|
105
104
|
)
|
|
106
105
|
if srt := method1["result"]["securityRiskToken"]:
|
|
107
106
|
await self._check_2fa(srt)
|
|
108
107
|
method2 = await self._post(
|
|
109
|
-
"/fiat/otc/user/payment/new_create",
|
|
108
|
+
"/x-api/fiat/otc/user/payment/new_create",
|
|
110
109
|
{
|
|
111
110
|
"paymentType": payment_type,
|
|
112
111
|
"realName": real_name,
|
|
@@ -118,12 +117,8 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
118
117
|
else:
|
|
119
118
|
return logging.exception(method1)
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
if fiat_id:
|
|
124
|
-
fiat = [m for m in list_methods if m["id"] == fiat_id][0]
|
|
125
|
-
return fiat
|
|
126
|
-
return list_methods[1]
|
|
120
|
+
def get_payment_method(self, fiat_id: int) -> CredEpyd:
|
|
121
|
+
return self.creds()[fiat_id]
|
|
127
122
|
|
|
128
123
|
def creds(self) -> dict[int, CredEpyd]:
|
|
129
124
|
data = self.api.get_user_payment_types()
|
|
@@ -149,8 +144,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
149
144
|
pmex.pm.df_cur_id
|
|
150
145
|
or (pmex.pm.country_id and (await pmex.pm.country).cur_id)
|
|
151
146
|
# or (ecdx.currencyBalance and await models.Cur.get_or_none(ticker=ecdx.currencyBalance[0]))
|
|
152
|
-
or (
|
|
153
|
-
or await self.guess_cur(ecdx)
|
|
147
|
+
or await self.guess_cur(ecdx, len(pmex.pm.curs) > 1 and pmex.pm.curs)
|
|
154
148
|
)
|
|
155
149
|
if not cur_id:
|
|
156
150
|
raise Exception(f"Set default cur for {pmex.name}")
|
|
@@ -169,7 +163,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
169
163
|
credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
|
|
170
164
|
return credex_db
|
|
171
165
|
|
|
172
|
-
async def guess_cur(self, ecdx: CredEpyd):
|
|
166
|
+
async def guess_cur(self, ecdx: CredEpyd, curs: list[models.Cur]):
|
|
173
167
|
mbs = ecdx.bankName.split(", ")
|
|
174
168
|
mbs += ecdx.branchName.split(" / ")
|
|
175
169
|
mbs = {mb.lower(): mb for mb in mbs}
|
|
@@ -181,7 +175,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
181
175
|
.values("pmcurs__cur_id", "names", "ccnt")
|
|
182
176
|
):
|
|
183
177
|
return pms[0]["pmcurs__cur_id"]
|
|
184
|
-
curs = {c.ticker: c.id for c in await models.Cur.all()}
|
|
178
|
+
curs = {c.ticker: c.id for c in curs or await models.Cur.all()}
|
|
185
179
|
for cur, cid in curs.items():
|
|
186
180
|
if re.search(re.compile(rf"\({cur}\)$"), ecdx.bankName):
|
|
187
181
|
return cid
|
|
@@ -191,6 +185,8 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
191
185
|
return cid
|
|
192
186
|
if re.search(re.compile(rf"\({cur}\)$"), ecdx.payMessage):
|
|
193
187
|
return cid
|
|
188
|
+
if re.search(re.compile(rf"\({cur}\)$"), ecdx.paymentExt1):
|
|
189
|
+
return cid
|
|
194
190
|
return None
|
|
195
191
|
|
|
196
192
|
# 25: Список реквизитов моих платежных методов
|
|
@@ -206,28 +202,28 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
206
202
|
# 27
|
|
207
203
|
async def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> dict:
|
|
208
204
|
fiat = self.get_payment_method(fiat_id)
|
|
209
|
-
fiat
|
|
210
|
-
fiat
|
|
211
|
-
result = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
205
|
+
fiat.realName = name
|
|
206
|
+
fiat.accountNo = detail
|
|
207
|
+
result = await self._post("/x-api/fiat/otc/user/payment/new_update", fiat.model_dump(exclude_none=True))
|
|
212
208
|
srt = result["result"]["securityRiskToken"]
|
|
213
209
|
await self._check_2fa(srt)
|
|
214
|
-
fiat
|
|
215
|
-
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
210
|
+
fiat.securityRiskToken = srt
|
|
211
|
+
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat.model_dump(exclude_none=True))
|
|
216
212
|
return result2
|
|
217
213
|
|
|
218
214
|
# 28
|
|
219
215
|
async def fiat_del(self, fiat_id: int) -> dict | str:
|
|
220
216
|
data = {"id": fiat_id, "securityRiskToken": ""}
|
|
221
|
-
method = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
217
|
+
method = await self._post("/x-api/fiat/otc/user/payment/new_delete", data)
|
|
222
218
|
srt = method["result"]["securityRiskToken"]
|
|
223
219
|
await self._check_2fa(srt)
|
|
224
220
|
data["securityRiskToken"] = srt
|
|
225
|
-
delete = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
221
|
+
delete = await self._post("/x-api/fiat/otc/user/payment/new_delete", data)
|
|
226
222
|
return delete
|
|
227
223
|
|
|
228
224
|
async def switch_ads(self, new_status: AdStatus) -> dict:
|
|
229
225
|
data = {"workStatus": new_status.name} # todo: переделать на апи, там status 0 -> 1
|
|
230
|
-
res = await self._post("/fiat/otc/maker/work-config/switch", data)
|
|
226
|
+
res = await self._post("/x-api/fiat/otc/maker/work-config/switch", data)
|
|
231
227
|
return res
|
|
232
228
|
|
|
233
229
|
async def ads(
|
|
@@ -244,10 +240,6 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
244
240
|
cnx.exid, crx.exid, is_sell, [pmex.exid for pmex in pmxs or []], amount, lim, vm_filter
|
|
245
241
|
)
|
|
246
242
|
|
|
247
|
-
def online_ads(self) -> str:
|
|
248
|
-
online = self._get("/fiat/otc/maker/work-config/get")
|
|
249
|
-
return online["result"]["workStatus"]
|
|
250
|
-
|
|
251
243
|
@staticmethod
|
|
252
244
|
def get_rate(list_ads: list) -> float:
|
|
253
245
|
ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
|
|
@@ -264,27 +256,42 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
264
256
|
ads = self.my_ads(True)
|
|
265
257
|
if not active:
|
|
266
258
|
ads += self.my_ads(False)
|
|
267
|
-
res = [await self.
|
|
259
|
+
res = [await self.ex_client.ad_load(ad, maker=self.actor) for ad in ads]
|
|
268
260
|
res = [await models.MyAd.update_or_create(ad=ad) for ad in res]
|
|
269
261
|
return len(res)
|
|
270
262
|
|
|
271
263
|
def get_security_token_create(self):
|
|
272
|
-
data = self._post("/fiat/otc/item/create", self.create_ad_body)
|
|
264
|
+
data = self._post("/x-api/fiat/otc/item/create", self.create_ad_body)
|
|
273
265
|
if data["ret_code"] == 912120019: # Current user can not to create add as maker
|
|
274
266
|
raise NoMakerException(data)
|
|
275
267
|
security_risk_token = data["result"]["securityRiskToken"]
|
|
276
268
|
return security_risk_token
|
|
277
269
|
|
|
278
270
|
async def _check_2fa(self, risk_token) -> int:
|
|
279
|
-
|
|
280
|
-
|
|
271
|
+
res = await self._post(
|
|
272
|
+
"/x-api/user/public/risk/components",
|
|
273
|
+
{"risk_token": risk_token},
|
|
274
|
+
hdrs={
|
|
275
|
+
# "Accept-Language": "ru,en;q=0.9",
|
|
276
|
+
},
|
|
277
|
+
)
|
|
278
|
+
if res["ret_msg"] != "success":
|
|
281
279
|
raise HTTPException("get")
|
|
282
|
-
cres =
|
|
280
|
+
cres = sorted(res["result"]["component_list"], key=lambda c: c["component_id"], reverse=True)
|
|
281
|
+
# cres = [{"component_id": "payment_password_verify"}]
|
|
282
|
+
vdata = {
|
|
283
|
+
"risk_token": risk_token,
|
|
284
|
+
"component_list": {c["component_id"]: await self.__get_2fa(c["component_id"], risk_token) for c in cres},
|
|
285
|
+
}
|
|
283
286
|
res = await self._post(
|
|
284
|
-
"/user/public/risk/verify",
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
"
|
|
287
|
+
"/x-api/user/public/risk/verify",
|
|
288
|
+
vdata,
|
|
289
|
+
hdrs={
|
|
290
|
+
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/125.0.0.0 Safari/537.36",
|
|
291
|
+
"accept-language": "ru,en;q=0.9",
|
|
292
|
+
# "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
|
|
293
|
+
"accept-encoding": "gzip, deflate, br, zstd",
|
|
294
|
+
"accept": "application/json",
|
|
288
295
|
},
|
|
289
296
|
)
|
|
290
297
|
if res["ret_msg"] != "success":
|
|
@@ -293,25 +300,32 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
293
300
|
await self._check_2fa(risk_token)
|
|
294
301
|
return res["ret_code"]
|
|
295
302
|
|
|
296
|
-
async def __get_2fa(
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
303
|
+
async def __get_2fa(
|
|
304
|
+
self, typ: Literal["google2fa", "email_verify", "payment_password_verify", "phone_verify"], rt: str = None
|
|
305
|
+
):
|
|
306
|
+
res = {"ret_msg": "success"}
|
|
307
|
+
if typ != "google2fa":
|
|
308
|
+
# "accept-language": "ru-RU,ru;q=0.9,en-US;q=0.8,en;q=0.7",
|
|
309
|
+
# "accept": "application/json"
|
|
310
|
+
res = await self._post("/x-api/user/public/risk/send/code", {"risk_token": rt, "component_id": typ})
|
|
311
|
+
if res["ret_msg"] == "success":
|
|
312
|
+
if typ == "google2fa":
|
|
313
|
+
bybit_secret = self.agent.auth["2fa"]
|
|
314
|
+
totp = pyotp.TOTP(bybit_secret)
|
|
315
|
+
return totp.now()
|
|
316
|
+
elif typ == "email_verify":
|
|
307
317
|
return self.gmail.bybit_code()
|
|
308
|
-
|
|
309
|
-
|
|
318
|
+
elif typ == "payment_password_verify":
|
|
319
|
+
hp = sha256(self.agent.auth["pass"].encode()).hexdigest()
|
|
320
|
+
return hp
|
|
321
|
+
elif cool_down := int(res["result"]["cool_down"]):
|
|
322
|
+
await sleep(cool_down)
|
|
323
|
+
return self.__get_2fa(typ, rt)
|
|
310
324
|
raise Exception("2fa fail")
|
|
311
325
|
|
|
312
326
|
def _post_ad(self, risk_token: str):
|
|
313
327
|
self.create_ad_body.update({"securityRiskToken": risk_token})
|
|
314
|
-
data = self._post("/fiat/otc/item/create", self.create_ad_body)
|
|
328
|
+
data = self._post("/x-api/fiat/otc/item/create", self.create_ad_body)
|
|
315
329
|
return data
|
|
316
330
|
|
|
317
331
|
# создание объявлений
|
|
@@ -337,7 +351,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
337
351
|
|
|
338
352
|
def get_security_token_update(self) -> str:
|
|
339
353
|
self.update_ad_body["id"] = self.last_ad_id
|
|
340
|
-
data = self._post("/fiat/otc/item/update", self.update_ad_body)
|
|
354
|
+
data = self._post("/x-api/fiat/otc/item/update", self.update_ad_body)
|
|
341
355
|
security_risk_token = data["result"]["securityRiskToken"]
|
|
342
356
|
return security_risk_token
|
|
343
357
|
|
|
@@ -354,7 +368,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
354
368
|
|
|
355
369
|
def update_ad(self, risk_token: str):
|
|
356
370
|
self.update_ad_body.update({"securityRiskToken": risk_token})
|
|
357
|
-
data = self._post("/fiat/otc/item/update", self.update_ad_body)
|
|
371
|
+
data = self._post("/x-api/fiat/otc/item/update", self.update_ad_body)
|
|
358
372
|
return data
|
|
359
373
|
|
|
360
374
|
def ad_del(self, ad_id: int):
|
|
@@ -362,7 +376,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
362
376
|
return data
|
|
363
377
|
|
|
364
378
|
async def __preorder_request(self, ad_id: int) -> PreOrderResp:
|
|
365
|
-
res = await self._post("/fiat/otc/item/simple",
|
|
379
|
+
res = await self._post("/x-api/fiat/otc/item/simple", json={"item_id": str(ad_id)})
|
|
366
380
|
if res["ret_code"] == 0:
|
|
367
381
|
res = res["result"]
|
|
368
382
|
return PreOrderResp.model_validate(res)
|
|
@@ -373,20 +387,18 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
373
387
|
tokenId=br.coin_exid,
|
|
374
388
|
currencyId=br.cur_exid,
|
|
375
389
|
side="1" if br.is_sell else "0",
|
|
376
|
-
amount=
|
|
390
|
+
amount=f"{br.fiat_amount:.2f}".rstrip("0").rstrip("."),
|
|
377
391
|
curPrice=por.curPrice,
|
|
378
392
|
quantity=str(round(br.fiat_amount / float(por.price), br.coin_scale)),
|
|
379
393
|
flag="amount",
|
|
380
|
-
# paymentType="51",
|
|
381
|
-
# paymentId="20399134",
|
|
382
394
|
# online="0"
|
|
383
395
|
)
|
|
384
396
|
if br.is_sell:
|
|
385
397
|
credex = await models.CredEx.get(
|
|
386
398
|
cred__person_id=self.actor.person_id,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
399
|
+
cred__pmcur__pm__pmexs__exid=por.payments[0],
|
|
400
|
+
cred__pmcur__pm__pmexs__ex_id=self.ex_client.ex.id,
|
|
401
|
+
cred__pmcur__cur__ticker=br.cur_exid,
|
|
390
402
|
)
|
|
391
403
|
req = OrderSellRequest(**req.model_dump(), paymentType=por.payments[0], paymentId=str(credex.exid))
|
|
392
404
|
return req
|
|
@@ -398,9 +410,12 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
398
410
|
return await self.__order_create(req, bor)
|
|
399
411
|
|
|
400
412
|
async def __order_create(self, req: OrderRequest | OrderSellRequest, bor: BaseOrderReq) -> OrderResp:
|
|
401
|
-
res: dict = await self._post("/fiat/otc/order/create",
|
|
413
|
+
res: dict = await self._post("/x-api/fiat/otc/order/create", json=req.model_dump())
|
|
402
414
|
if res["ret_code"] == 0:
|
|
403
415
|
resp = OrderResp.model_validate(res["result"])
|
|
416
|
+
elif res["ret_code"] == 10001:
|
|
417
|
+
logging.error(req.model_dump(), "POST", self.session._base_url)
|
|
418
|
+
raise HTTPException()
|
|
404
419
|
elif res["ret_code"] == 912120030 or res["ret_msg"] == "The price has changed, please try again later.":
|
|
405
420
|
resp = await self._order_request(bor)
|
|
406
421
|
if not resp.orderId and resp.needSecurityRisk:
|
|
@@ -414,15 +429,15 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
414
429
|
|
|
415
430
|
async def cancel_order(self, order_id: str) -> bool:
|
|
416
431
|
cr = CancelOrderReq(orderId=order_id)
|
|
417
|
-
res = await self._post("/fiat/otc/order/cancel", cr.model_dump())
|
|
432
|
+
res = await self._post("/x-api/fiat/otc/order/cancel", cr.model_dump())
|
|
418
433
|
return res["ret_code"] == 0
|
|
419
434
|
|
|
420
435
|
def get_order_info(self, order_id: str) -> dict:
|
|
421
|
-
data = self._post("/fiat/otc/order/info", json={"orderId": order_id})
|
|
436
|
+
data = self._post("/x-api/fiat/otc/order/info", json={"orderId": order_id})
|
|
422
437
|
return data["result"]
|
|
423
438
|
|
|
424
439
|
def get_chat_msg(self, order_id):
|
|
425
|
-
data = self._post("/fiat/otc/order/message/listpage", json={"orderId": order_id, "size": 100})
|
|
440
|
+
data = self._post("/x-api/fiat/otc/order/message/listpage", json={"orderId": order_id, "size": 100})
|
|
426
441
|
msgs = [
|
|
427
442
|
{"text": msg["message"], "type": msg["contentType"], "role": msg["roleType"], "user_id": msg["userId"]}
|
|
428
443
|
for msg in data["result"]["result"]
|
|
@@ -431,14 +446,14 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
431
446
|
return msgs
|
|
432
447
|
|
|
433
448
|
def block_user(self, user_id: str):
|
|
434
|
-
return self._post("/fiat/p2p/user/add_block_user", {"blockedUserId": user_id})
|
|
449
|
+
return self._post("/x-api/fiat/p2p/user/add_block_user", {"blockedUserId": user_id})
|
|
435
450
|
|
|
436
451
|
def unblock_user(self, user_id: str):
|
|
437
|
-
return self._post("/fiat/p2p/user/delete_block_user", {"blockedUserId": user_id})
|
|
452
|
+
return self._post("/x-api/fiat/p2p/user/delete_block_user", {"blockedUserId": user_id})
|
|
438
453
|
|
|
439
454
|
def user_review_post(self, order_id: str):
|
|
440
455
|
return self._post(
|
|
441
|
-
"/fiat/otc/order/appraise/modify",
|
|
456
|
+
"/x-api/fiat/otc/order/appraise/modify",
|
|
442
457
|
{
|
|
443
458
|
"orderId": order_id,
|
|
444
459
|
"anonymous": "0",
|
|
@@ -458,7 +473,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
458
473
|
self, side: int = None, status: int = None, begin_time: int = None, end_time: int = None, token_id: str = None
|
|
459
474
|
):
|
|
460
475
|
return await self._post(
|
|
461
|
-
"/fiat/otc/order/pending/simplifyList",
|
|
476
|
+
"/x-api/fiat/otc/order/pending/simplifyList",
|
|
462
477
|
{
|
|
463
478
|
"status": status,
|
|
464
479
|
"tokenId": token_id,
|
|
@@ -472,7 +487,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
472
487
|
|
|
473
488
|
def get_orders_done(self, begin_time: int, end_time: int, status: int, side: int, token_id: str):
|
|
474
489
|
return self._post(
|
|
475
|
-
"/fiat/otc/order/simplifyList",
|
|
490
|
+
"/x-api/fiat/otc/order/simplifyList",
|
|
476
491
|
{
|
|
477
492
|
"status": status, # 50 - завершено
|
|
478
493
|
"tokenId": token_id,
|
|
@@ -494,12 +509,14 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
494
509
|
maker_name = order.buyerRealName, order.sellerRealName
|
|
495
510
|
im_maker = int(order.makerUserId == order.userId)
|
|
496
511
|
taker_id = (order.userId, order.targetUserId)[im_maker]
|
|
497
|
-
taker_person = await self.
|
|
512
|
+
taker_person = await self.ex_client.person_name_update(maker_name[::-1][ad.side], taker_id)
|
|
498
513
|
seller_person = (
|
|
499
|
-
self.actor.person
|
|
514
|
+
self.actor.person
|
|
515
|
+
if order.side
|
|
516
|
+
else await self.ex_client.person_name_update(order.sellerRealName, int(order.targetUserId))
|
|
500
517
|
)
|
|
501
518
|
taker_nick = (self.actor.name, order.targetNickName)[im_maker] # todo: check
|
|
502
|
-
ad_db, cond_isnew = await self.
|
|
519
|
+
ad_db, cond_isnew = await self.ex_client.cond_load(ad, force=True, rname=maker_name[ad.side])
|
|
503
520
|
if not ad_db:
|
|
504
521
|
...
|
|
505
522
|
ecredex: CredEpyd = order.confirmedPayTerm
|
|
@@ -602,7 +619,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
602
619
|
buyer_person = (
|
|
603
620
|
self.actor.person
|
|
604
621
|
if not order.side
|
|
605
|
-
else await self.
|
|
622
|
+
else await self.ex_client.person_name_update(order.buyerRealName, int(order.targetUserId))
|
|
606
623
|
)
|
|
607
624
|
ts = [t for t in tsa if floor(fa := float(order.amount)) <= float(t["creditedAmount"]) <= round(fa)]
|
|
608
625
|
if len(ts) != 1:
|
|
@@ -755,7 +772,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
755
772
|
pmexs: list[models.PmEx] = await models.PmEx.filter(pm_id__in=pm_ids, ex=self.actor.ex).prefetch_related("pm")
|
|
756
773
|
k = (-1) ** int(taker_side) # on_buy=1, on_sell=-1
|
|
757
774
|
sleep_sec = 3 # 1 if set(pms) & {"volet"} and coinex.coin_id == 1 else 5
|
|
758
|
-
creds: list[models.CredEx] = await self.
|
|
775
|
+
creds: list[models.CredEx] = await self.actor.get_credexs_by(pm_ids, curex.cur_id)
|
|
759
776
|
_lstat, volume = None, 0
|
|
760
777
|
|
|
761
778
|
while self.actor.person.user.status > 0:
|
|
@@ -814,7 +831,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
814
831
|
await sleep(15)
|
|
815
832
|
continue
|
|
816
833
|
(cur_plc,) = cur_plc # может упасть если в списке > 1 наш ad
|
|
817
|
-
[(await self.
|
|
834
|
+
[(await self.ex_client.cond_load(ad, race.road.ad.pair_side, True))[0] for ad in ads[:cur_plc]]
|
|
818
835
|
# rivals = [
|
|
819
836
|
# (await models.RaceStat.update_or_create({"place": plc, "price": ad.price, "premium": ad.premium}, ad=ad))[
|
|
820
837
|
# 0
|
|
@@ -955,310 +972,89 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
955
972
|
bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
|
|
956
973
|
return (bc, sc), hp, vmf, zplace
|
|
957
974
|
|
|
958
|
-
async def
|
|
959
|
-
self
|
|
960
|
-
|
|
961
|
-
curex: models.CurEx,
|
|
962
|
-
taker_side: bool,
|
|
963
|
-
pms: list[str] = None,
|
|
964
|
-
ceil: float = None,
|
|
965
|
-
volume: float = 9000,
|
|
966
|
-
min_fiat: int = None,
|
|
967
|
-
max_fiat: int = None,
|
|
968
|
-
):
|
|
969
|
-
k = (-1) ** int(taker_side) # on_buy=1, on_sell=-1
|
|
975
|
+
async def _take_ad(self, req: TakeAdReq):
|
|
976
|
+
res = self.api.get_ad_details(itemId=req.ad_id)["result"]
|
|
977
|
+
ad: Ad = Ad.model_validate(res)
|
|
970
978
|
|
|
971
|
-
if pms:
|
|
972
|
-
creds: dict[models.PmEx, models.CredEx] = await self.get_credexs_by_norms(pms, curex.cur_id)
|
|
973
|
-
[str(p.exid) for p in creds.values()]
|
|
974
|
-
|
|
975
|
-
if taker_side: # гонка в стакане продажи - мы покупаем монету за ФИАТ
|
|
976
|
-
fiats = await models.Fiat.filter(
|
|
977
|
-
cred_id__in=[cx.cred_id for cx in creds.values()], amount__not=F("target")
|
|
978
|
-
)
|
|
979
|
-
volume = min(volume, max(fiats, key=lambda f: f.target - f.amount).amount / ceil)
|
|
980
|
-
else: # гонка в стакане покупки - мы продаем МОНЕТУ за фиат
|
|
981
|
-
asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
|
|
982
|
-
volume = min(volume, asset.free)
|
|
983
|
-
volume = str(round(volume, coinex.coin.scale))
|
|
984
|
-
ps = await PairSide.get(
|
|
985
|
-
is_sell=taker_side,
|
|
986
|
-
pair__coin_id=coinex.coin_id,
|
|
987
|
-
pair__cur_id=curex.cur_id,
|
|
988
|
-
)
|
|
989
|
-
while self.actor.person.user.status > 0: # todo: depends on rest asset/fiat
|
|
990
|
-
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pms and list(creds.keys()))
|
|
991
|
-
|
|
992
|
-
if not ads:
|
|
993
|
-
print(coinex.exid, curex.exid, taker_side, "no ads!")
|
|
994
|
-
await sleep(300)
|
|
995
|
-
continue
|
|
996
|
-
|
|
997
|
-
for i, ad in enumerate(ads):
|
|
998
|
-
if (ceil - float(ad.price)) * k < 0:
|
|
999
|
-
break
|
|
1000
|
-
if int(ad.userId) == self.actor.exid:
|
|
1001
|
-
logging.info(f"My ad {'-' if taker_side else '+'}{coinex.exid}/{curex.exid} on place#{i}")
|
|
1002
|
-
continue
|
|
1003
|
-
ad_db, isnew = await self.cond_upsert(ad, ps=ps)
|
|
1004
|
-
if isnew:
|
|
1005
|
-
s = f"{'-' if taker_side else '+'}{ad.price}[{ad.minAmount}-{ad.maxAmount}]{coinex.exid}/{curex.exid}"
|
|
1006
|
-
print(s, end=" | ", flush=True)
|
|
1007
|
-
try:
|
|
1008
|
-
# take
|
|
1009
|
-
...
|
|
1010
|
-
except FailedRequestError as e:
|
|
1011
|
-
if ExcCode(e.status_code) == ExcCode.RareLimit:
|
|
1012
|
-
await sleep(195)
|
|
1013
|
-
elif ExcCode(e.status_code) == ExcCode.Timestamp:
|
|
1014
|
-
await sleep(2)
|
|
1015
|
-
else:
|
|
1016
|
-
raise e
|
|
1017
|
-
except (ReadTimeoutError, ConnectionDoesNotExistError):
|
|
1018
|
-
logging.warning("Connection failed. Restarting..")
|
|
1019
|
-
await sleep(3)
|
|
1020
|
-
|
|
1021
|
-
async def cond_upsert(
|
|
1022
|
-
self, ad: Ad, rname: str = None, ps: PairSide = None, force: bool = False
|
|
1023
|
-
) -> tuple[models.Ad, bool]:
|
|
1024
|
-
_sim, cid = None, None
|
|
1025
|
-
ad_db = await models.Ad.get_or_none(exid=ad.id, maker__ex=self.ex_client.ex).prefetch_related("cond")
|
|
1026
|
-
# если точно такое условие уже есть в бд
|
|
1027
|
-
if not (cleaned := clean(ad.remark)) or (cid := {oc[0]: ci for ci, oc in self.all_conds.items()}.get(cleaned)):
|
|
1028
|
-
# и объява с таким ид уже есть, но у нее другое условие
|
|
1029
|
-
if ad_db and ad_db.cond_id != cid:
|
|
1030
|
-
# то обновляем ид ее условия
|
|
1031
|
-
ad_db.cond_id = cid
|
|
1032
|
-
await ad_db.save()
|
|
1033
|
-
logging.info(f"{ad.nickName} upd cond#{ad_db.cond_id}->{cid}")
|
|
1034
|
-
# old_cid = ad_db.cond_id # todo: solve race-condition, а пока что очищаем при каждом запуске
|
|
1035
|
-
# if not len((old_cond := await Cond.get(id=old_cid).prefetch_related('ads')).ads):
|
|
1036
|
-
# await old_cond.delete()
|
|
1037
|
-
# logging.warning(f"Cond#{old_cid} deleted!")
|
|
1038
|
-
return (ad_db or force and await self.ad_create(ad, cid, rname, ps)), False
|
|
1039
|
-
# если эта объява в таким ид уже есть в бд, но с другим условием (или без), а текущего условия еще нет в бд
|
|
1040
|
-
if ad_db:
|
|
1041
|
-
await ad_db.fetch_related("cond__ads", "maker")
|
|
1042
|
-
if not ad_db.cond_id or (
|
|
1043
|
-
# у измененного условия этой объявы есть другие объявы?
|
|
1044
|
-
(rest_ads := set(ad_db.cond.ads) - {ad_db})
|
|
1045
|
-
and
|
|
1046
|
-
# другие объявы этого условия принадлежат другим юзерам
|
|
1047
|
-
{ra.maker_id for ra in rest_ads} - {ad_db.maker_id}
|
|
1048
|
-
):
|
|
1049
|
-
# создадим новое условие и присвоим его только текущей объяве
|
|
1050
|
-
cid = await self.cond_new(cleaned, {int(ad.userId)})
|
|
1051
|
-
ad_db.cond_id = cid
|
|
1052
|
-
await ad_db.save()
|
|
1053
|
-
|
|
1054
|
-
return ad_db, True
|
|
1055
|
-
# а если других объяв со старым условием этой обявы нет, либо они все этого же юзера
|
|
1056
|
-
# обновляем условие (в тч во всех ЕГО объявах)
|
|
1057
|
-
ad_db.cond.last_ver = ad_db.cond.raw_txt
|
|
1058
|
-
ad_db.cond.raw_txt = cleaned
|
|
1059
|
-
await ad_db.cond.save()
|
|
1060
|
-
await self.cond_upd(ad_db.cond, {ad_db.maker.exid})
|
|
1061
|
-
# и подправим коэфициенты похожести нового текста
|
|
1062
|
-
await self.fix_rel_sims(ad_db.cond_id, cleaned)
|
|
1063
|
-
return ad_db, False
|
|
1064
|
-
|
|
1065
|
-
cid = await self.cond_new(cleaned, {int(ad.userId)})
|
|
1066
|
-
return await self.ad_create(ad, cid, rname, ps), True
|
|
1067
|
-
|
|
1068
|
-
async def cond_new(self, txt: str, uids: set[int]) -> int:
|
|
1069
|
-
new_cond, _ = await Cond.update_or_create(raw_txt=txt)
|
|
1070
|
-
# и максимально похожую связь для нового условия (если есть >= 60%)
|
|
1071
|
-
await self.cond_upd(new_cond, uids)
|
|
1072
|
-
return new_cond.id
|
|
1073
|
-
|
|
1074
|
-
async def cond_upd(self, cond: Cond, uids: set[int]):
|
|
1075
|
-
self.all_conds[cond.id] = cond.raw_txt, uids
|
|
1076
|
-
# и максимально похожую связь для нового условия (если есть >= 60%)
|
|
1077
|
-
old_cid, sim = await self.cond_get_max_sim(cond.id, cond.raw_txt, uids)
|
|
1078
|
-
await self.actual_sim(cond.id, old_cid, sim)
|
|
1079
|
-
|
|
1080
|
-
def find_in_tree(self, cid: int, old_cid: int) -> bool:
|
|
1081
|
-
if p := self.cond_sims.get(old_cid):
|
|
1082
|
-
if p == cid:
|
|
1083
|
-
return True
|
|
1084
|
-
return self.find_in_tree(cid, p)
|
|
1085
|
-
return False
|
|
1086
|
-
|
|
1087
|
-
async def cond_get_max_sim(self, cid: int, txt: str, uids: set[int]) -> tuple[int | None, int | None]:
|
|
1088
|
-
# находим все старые тексты похожие на 90% и более
|
|
1089
|
-
if len(txt) < 15:
|
|
1090
|
-
return None, None
|
|
1091
|
-
sims: dict[int, int] = {}
|
|
1092
|
-
for old_cid, (old_txt, old_uids) in self.all_conds.items():
|
|
1093
|
-
if len(old_txt) < 15 or uids == old_uids:
|
|
1094
|
-
continue
|
|
1095
|
-
elif not self.can_add_sim(cid, old_cid):
|
|
1096
|
-
continue
|
|
1097
|
-
if sim := get_sim(txt, old_txt):
|
|
1098
|
-
sims[old_cid] = sim
|
|
1099
|
-
# если есть, берем самый похожий из них
|
|
1100
|
-
if sims:
|
|
1101
|
-
old_cid, sim = max(sims.items(), key=lambda x: x[1])
|
|
1102
|
-
await sleep(0.3)
|
|
1103
|
-
return old_cid, sim
|
|
1104
|
-
return None, None
|
|
1105
|
-
|
|
1106
|
-
def can_add_sim(self, cid: int, old_cid: int) -> bool:
|
|
1107
|
-
if cid == old_cid:
|
|
1108
|
-
return False
|
|
1109
|
-
elif self.cond_sims.get(cid) == old_cid:
|
|
1110
|
-
return False
|
|
1111
|
-
elif self.find_in_tree(cid, old_cid):
|
|
1112
|
-
return False
|
|
1113
|
-
elif self.cond_sims.get(old_cid) == cid:
|
|
1114
|
-
return False
|
|
1115
|
-
elif cid in self.rcond_sims.get(old_cid, {}):
|
|
1116
|
-
return False
|
|
1117
|
-
elif old_cid in self.rcond_sims.get(cid, {}):
|
|
1118
|
-
return False
|
|
1119
|
-
return True
|
|
1120
|
-
|
|
1121
|
-
async def person_upsert(self, name: str, exid: int) -> models.Person:
|
|
1122
|
-
if actor := await models.Actor.get_or_none(exid=exid, ex=self.ex_client.ex).prefetch_related("person"):
|
|
1123
|
-
if not actor.person:
|
|
1124
|
-
actor.person = await models.Person.create(name=name)
|
|
1125
|
-
await actor.save()
|
|
1126
|
-
return actor.person
|
|
1127
|
-
return await models.Person.create(name=name)
|
|
1128
|
-
|
|
1129
|
-
async def ad_create(
|
|
1130
|
-
self, ad: Ad, cid: int = None, rname: str = None, ps: PairSide = None, actor: Actor = None
|
|
1131
|
-
) -> models.Ad:
|
|
1132
|
-
act_df = {}
|
|
1133
|
-
if int(ad.userId) != self.actor.exid:
|
|
1134
|
-
act_df |= {"name": ad.nickName}
|
|
1135
|
-
if rname:
|
|
1136
|
-
act_df |= {"person": await self.person_upsert(rname, int(ad.userId))}
|
|
1137
|
-
if not actor:
|
|
1138
|
-
act_df |= {"person": await self.person_upsert(ad.nickName, int(ad.userId))}
|
|
1139
|
-
actor, _ = await Actor.update_or_create(act_df, exid=ad.userId, ex=self.ex_client.ex)
|
|
1140
|
-
ps = ps or await PairSide.get_or_none(
|
|
1141
|
-
is_sell=ad.side,
|
|
1142
|
-
pair__coin__ticker=ad.tokenId,
|
|
1143
|
-
pair__cur__ticker=ad.currencyId,
|
|
1144
|
-
).prefetch_related("pair__cur", "pair__coin")
|
|
1145
|
-
if not ps or not ps.pair:
|
|
1146
|
-
... # THB/USDC
|
|
1147
|
-
ad_upd = models.Ad.validate(ad.model_dump(by_alias=True))
|
|
1148
|
-
cur_scale = 10**ps.pair.cur.scale
|
|
1149
|
-
coinex = await models.CoinEx.get(coin_id=ps.pair.coin_id, ex=self.ex_client.ex)
|
|
1150
|
-
df_unq = ad_upd.df_unq(
|
|
1151
|
-
maker_id=actor.id,
|
|
1152
|
-
pair_side_id=ps.id,
|
|
1153
|
-
amount=int(float(ad.quantity) * float(ad.price) * cur_scale),
|
|
1154
|
-
quantity=int(float(ad.quantity) * 10**coinex.scale),
|
|
1155
|
-
min_fiat=int(float(ad.minAmount) * cur_scale),
|
|
1156
|
-
max_fiat=ad.maxAmount and int(float(ad.maxAmount) * cur_scale),
|
|
1157
|
-
price=int(float(ad.price) * cur_scale),
|
|
1158
|
-
premium=int(float(ad.premium) * cur_scale),
|
|
1159
|
-
)
|
|
1160
|
-
ad_db, _ = await models.Ad.update_or_create(**df_unq)
|
|
1161
|
-
await ad_db.pms.add(*(await models.Pm.filter(pmexs__ex=self.ex_client.ex, pmexs__exid__in=ad.payments)))
|
|
1162
|
-
return ad_db
|
|
1163
|
-
|
|
1164
|
-
async def fix_rel_sims(self, cid: int, new_txt: str):
|
|
1165
|
-
for rel_sim in await CondSim.filter(cond_rel_id=cid).prefetch_related("cond"):
|
|
1166
|
-
if sim := get_sim(new_txt, rel_sim.cond.raw_txt):
|
|
1167
|
-
rel_sim.similarity = sim
|
|
1168
|
-
await rel_sim.save()
|
|
1169
|
-
else:
|
|
1170
|
-
await rel_sim.delete()
|
|
1171
|
-
|
|
1172
|
-
async def actual_cond(self):
|
|
1173
|
-
for curr, old in await CondSim.all().values_list("cond_id", "cond_rel_id"):
|
|
1174
|
-
self.cond_sims[curr] = old
|
|
1175
|
-
self.rcond_sims[old] |= {curr}
|
|
1176
|
-
for cid, (txt, uids) in self.all_conds.items():
|
|
1177
|
-
old_cid, sim = await self.cond_get_max_sim(cid, txt, uids)
|
|
1178
|
-
await self.actual_sim(cid, old_cid, sim)
|
|
1179
|
-
# хз бля чо это ваще
|
|
1180
|
-
# for ad_db in await models.Ad.filter(direction__pairex__ex=self.ex_client.ex).prefetch_related("cond", "maker"):
|
|
1181
|
-
# ad = Ad(id=str(ad_db.exid), userId=str(ad_db.maker.exid), remark=ad_db.cond.raw_txt)
|
|
1182
|
-
# await self.cond_upsert(ad, force=True)
|
|
1183
|
-
|
|
1184
|
-
async def actual_sim(self, cid: int, old_cid: int, sim: int):
|
|
1185
|
-
if not sim:
|
|
1186
|
-
return
|
|
1187
|
-
if old_sim := await CondSim.get_or_none(cond_id=cid):
|
|
1188
|
-
if old_sim.cond_rel_id != old_cid:
|
|
1189
|
-
if sim > old_sim.similarity:
|
|
1190
|
-
logging.warning(f"R {cid}: {old_sim.similarity}->{sim} ({old_sim.cond_rel_id}->{old_cid})")
|
|
1191
|
-
await old_sim.update_from_dict({"similarity": sim, "old_rel_id": old_cid}).save()
|
|
1192
|
-
self._cond_sim_upd(cid, old_cid)
|
|
1193
|
-
elif sim != old_sim.similarity:
|
|
1194
|
-
logging.info(f"{cid}: {old_sim.similarity}->{sim}")
|
|
1195
|
-
await old_sim.update_from_dict({"similarity": sim}).save()
|
|
1196
|
-
else:
|
|
1197
|
-
await CondSim.create(cond_id=cid, cond_rel_id=old_cid, similarity=sim)
|
|
1198
|
-
self._cond_sim_upd(cid, old_cid)
|
|
1199
|
-
|
|
1200
|
-
def _cond_sim_upd(self, cid: int, old_cid: int):
|
|
1201
|
-
if old_old_cid := self.cond_sims.get(cid): # если старый cid уже был в дереве:
|
|
1202
|
-
self.rcond_sims[old_old_cid].remove(cid) # удаляем из обратного
|
|
1203
|
-
self.cond_sims[cid] = old_cid # а в прямом он автоматом переопределится, даже если и был
|
|
1204
|
-
self.rcond_sims[old_cid] |= {cid} # ну и в обратное добавим новый
|
|
1205
|
-
|
|
1206
|
-
async def get_credexs_by_pms(self, pms: list[models.Pm], cur_id: int) -> list[models.CredEx]:
|
|
1207
|
-
return await models.CredEx.filter(
|
|
1208
|
-
ex_id=self.actor.ex_id,
|
|
1209
|
-
cred__pmcur__pm_id__in=[pm.id for pm in pms],
|
|
1210
|
-
cred__person_id=self.actor.person_id,
|
|
1211
|
-
cred__pmcur__cur_id=cur_id,
|
|
1212
|
-
)
|
|
1213
|
-
|
|
1214
|
-
def build_tree(self):
|
|
1215
|
-
set(self.cond_sims.keys()) | set(self.cond_sims.values())
|
|
1216
|
-
tree = defaultdict(dict)
|
|
1217
|
-
# Группируем родителей по детям
|
|
1218
|
-
for child, par in self.cond_sims.items():
|
|
1219
|
-
tree[par] |= {child: {}} # todo: make from self.rcond_sim
|
|
1220
|
-
|
|
1221
|
-
# Строим дерево снизу вверх
|
|
1222
|
-
def subtree(node):
|
|
1223
|
-
if not node:
|
|
1224
|
-
return node
|
|
1225
|
-
for key in node:
|
|
1226
|
-
subnode = tree.pop(key, {})
|
|
1227
|
-
d = subtree(subnode)
|
|
1228
|
-
node[key] |= d # actual tree rebuilding here!
|
|
1229
|
-
return node # todo: refact?
|
|
1230
|
-
|
|
1231
|
-
# Находим корни / без родителей
|
|
1232
|
-
roots = set(self.cond_sims.values()) - set(self.cond_sims.keys())
|
|
1233
|
-
for root in roots:
|
|
1234
|
-
_ = subtree(tree[root])
|
|
1235
|
-
|
|
1236
|
-
self.tree = tree
|
|
1237
|
-
|
|
1238
|
-
async def take_ad(self, req: TakeAdReq):
|
|
1239
|
-
ad: Ad = Ad.model_validate(self.api.get_ad_details(itemId=req.ad_id))
|
|
1240
979
|
bor = BaseOrderReq(
|
|
1241
980
|
ad_id=str(ad.id),
|
|
1242
981
|
fiat_amount=req.amount,
|
|
1243
|
-
is_sell=bool(ad.side),
|
|
982
|
+
is_sell=not bool(ad.side),
|
|
1244
983
|
cur_exid=ad.currencyId,
|
|
1245
984
|
coin_exid=ad.tokenId,
|
|
1246
|
-
coin_scale=ad.token.scale,
|
|
985
|
+
coin_scale=ad.symbolInfo.token.scale,
|
|
1247
986
|
pm_id=req.pm_id,
|
|
1248
987
|
)
|
|
1249
988
|
resp: OrderResp = await self._order_request(bor)
|
|
1250
989
|
return resp
|
|
1251
990
|
|
|
991
|
+
# async def parse_ads(
|
|
992
|
+
# self,
|
|
993
|
+
# coinex: models.CoinEx,
|
|
994
|
+
# curex: models.CurEx,
|
|
995
|
+
# taker_side: bool,
|
|
996
|
+
# pms: list[str] = None,
|
|
997
|
+
# ceil: float = None,
|
|
998
|
+
# volume: float = 9000,
|
|
999
|
+
# min_fiat: int = None,
|
|
1000
|
+
# max_fiat: int = None,
|
|
1001
|
+
# ):
|
|
1002
|
+
# k = (-1) ** int(taker_side) # on_buy=1, on_sell=-1
|
|
1003
|
+
# if pms:
|
|
1004
|
+
# creds: dict[models.PmEx, models.CredEx] = await self.get_credexs_by_norms(pms, curex.cur_id)
|
|
1005
|
+
# [str(p.exid) for p in creds.values()]
|
|
1006
|
+
#
|
|
1007
|
+
# if taker_side: # гонка в стакане продажи - мы покупаем монету за ФИАТ
|
|
1008
|
+
# fiats = await models.Fiat.filter(
|
|
1009
|
+
# cred_id__in=[cx.cred_id for cx in creds.values()], amount__not=F("target")
|
|
1010
|
+
# )
|
|
1011
|
+
# volume = min(volume, max(fiats, key=lambda f: f.target - f.amount).amount / ceil)
|
|
1012
|
+
# else: # гонка в стакане покупки - мы продаем МОНЕТУ за фиат
|
|
1013
|
+
# asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
|
|
1014
|
+
# volume = min(volume, asset.free)
|
|
1015
|
+
# volume = str(round(volume, coinex.coin.scale))
|
|
1016
|
+
# ps = await PairSide.get(
|
|
1017
|
+
# is_sell=taker_side,
|
|
1018
|
+
# pair__coin_id=coinex.coin_id,
|
|
1019
|
+
# pair__cur_id=curex.cur_id,
|
|
1020
|
+
# )
|
|
1021
|
+
# while self.actor.person.user.status > 0: # todo: depends on rest asset/fiat
|
|
1022
|
+
# ads: list[Ad] = await self.ads(coinex, curex, taker_side, pms and list(creds.keys()))
|
|
1023
|
+
#
|
|
1024
|
+
# if not ads:
|
|
1025
|
+
# print(coinex.exid, curex.exid, taker_side, "no ads!")
|
|
1026
|
+
# await sleep(300)
|
|
1027
|
+
# continue
|
|
1028
|
+
#
|
|
1029
|
+
# for i, ad in enumerate(ads):
|
|
1030
|
+
# if (ceil - float(ad.price)) * k < 0:
|
|
1031
|
+
# break
|
|
1032
|
+
# if int(ad.userId) == self.actor.exid:
|
|
1033
|
+
# logging.info(f"My ad {'-' if taker_side else '+'}{coinex.exid}/{curex.exid} on place#{i}")
|
|
1034
|
+
# continue
|
|
1035
|
+
# ad_db, isnew = await self.cond_upsert(ad, ps=ps)
|
|
1036
|
+
# if isnew:
|
|
1037
|
+
# s = f"{'-' if taker_side else '+'}{ad.price}[{ad.minAmount}-{ad.maxAmount}]{coinex.exid}/{curex.exid}"
|
|
1038
|
+
# print(s, end=" | ", flush=True)
|
|
1039
|
+
# try:
|
|
1040
|
+
# # take
|
|
1041
|
+
# ...
|
|
1042
|
+
# except FailedRequestError as e:
|
|
1043
|
+
# if ExcCode(e.status_code) == ExcCode.RareLimit:
|
|
1044
|
+
# await sleep(195)
|
|
1045
|
+
# elif ExcCode(e.status_code) == ExcCode.Timestamp:
|
|
1046
|
+
# await sleep(2)
|
|
1047
|
+
# else:
|
|
1048
|
+
# raise e
|
|
1049
|
+
# except (ReadTimeoutError, ConnectionDoesNotExistError):
|
|
1050
|
+
# logging.warning("Connection failed. Restarting..")
|
|
1051
|
+
# await sleep(3)
|
|
1052
|
+
|
|
1252
1053
|
|
|
1253
1054
|
def ms2utc(msk_ts_str: str):
|
|
1254
1055
|
return datetime.fromtimestamp(int(msk_ts_str) / 1000, timezone(timedelta(hours=3), name="MSK"))
|
|
1255
1056
|
|
|
1256
1057
|
|
|
1257
|
-
def get_sim(s1, s2) -> int:
|
|
1258
|
-
sim = int((SequenceMatcher(None, s1, s2).ratio() - 0.6) * 10_000)
|
|
1259
|
-
return sim if sim > 0 else 0
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
1058
|
def detailed_diff(str1, str2):
|
|
1263
1059
|
matcher = SequenceMatcher(None, str1, str2)
|
|
1264
1060
|
result = []
|
|
@@ -1276,14 +1072,6 @@ def detailed_diff(str1, str2):
|
|
|
1276
1072
|
return "".join(result)
|
|
1277
1073
|
|
|
1278
1074
|
|
|
1279
|
-
def clean(s) -> str:
|
|
1280
|
-
clear = r"[^\w\s.,!?;:()\-]"
|
|
1281
|
-
repeat = r"(.)\1{2,}"
|
|
1282
|
-
s = re.sub(clear, "", s).lower()
|
|
1283
|
-
s = re.sub(repeat, r"\1", s)
|
|
1284
|
-
return s.replace("\n\n", "\n").replace(" ", " ").strip(" \n/.,!?-")
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
1075
|
def step_is_need(mad, cad) -> bool:
|
|
1288
1076
|
# todo: пока не решен непонятный кейс, почему то конкурент по всем параметрам слабже, но в списке ранжируется выше.
|
|
1289
1077
|
# текущая версия: recentExecuteRate округляется до целого, но на бэке байбита его дробная часть больше
|
|
@@ -1353,28 +1141,6 @@ async def main():
|
|
|
1353
1141
|
# s, _ = await models.Synonym.update_or_create(typ=SynonymType.name, txt=name)
|
|
1354
1142
|
# await s.curs.add(rub.cur)
|
|
1355
1143
|
|
|
1356
|
-
# пока порешали рейс-кондишн, очищаем сиротские условия при каждом запуске
|
|
1357
|
-
# [await c.delete() for c in await Cond.filter(ads__isnull=True)]
|
|
1358
|
-
cl.all_conds = {
|
|
1359
|
-
c.id: (c.raw_txt, {a.maker.exid for a in c.ads}) for c in await Cond.all().prefetch_related("ads__maker")
|
|
1360
|
-
}
|
|
1361
|
-
for curr, old in await CondSim.filter().values_list("cond_id", "cond_rel_id"):
|
|
1362
|
-
cl.cond_sims[curr] = old
|
|
1363
|
-
cl.rcond_sims[old] |= {curr}
|
|
1364
|
-
|
|
1365
|
-
cl.build_tree()
|
|
1366
|
-
a = set()
|
|
1367
|
-
|
|
1368
|
-
def check_tree(tre):
|
|
1369
|
-
for p, c in tre.items():
|
|
1370
|
-
a.add(p)
|
|
1371
|
-
check_tree(c)
|
|
1372
|
-
|
|
1373
|
-
for pr, ch in cl.tree.items():
|
|
1374
|
-
check_tree(ch)
|
|
1375
|
-
if ct := set(cl.tree.keys()) & a:
|
|
1376
|
-
logging.exception(f"cycle cids: {ct}")
|
|
1377
|
-
|
|
1378
1144
|
pauth = (await models.PmAgent[1]).auth
|
|
1379
1145
|
papi = PayeerAPI(pauth["email"], pauth["api_id"], pauth["api_sec"])
|
|
1380
1146
|
hist: dict = papi.history(count=1000)
|