xync-client 0.0.141__py3-none-any.whl → 0.0.155__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 +299 -0
- xync_client/Abc/Agent.py +94 -10
- xync_client/Abc/Ex.py +27 -22
- 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 +24 -2
- xync_client/Bybit/InAgent.py +122 -87
- xync_client/Bybit/agent.py +477 -542
- xync_client/Bybit/etype/ad.py +11 -56
- xync_client/Bybit/etype/cred.py +29 -9
- xync_client/Bybit/etype/order.py +42 -55
- xync_client/Bybit/ex.py +15 -2
- xync_client/Gmail/__init__.py +119 -98
- xync_client/Htx/agent.py +162 -31
- xync_client/Htx/etype/ad.py +18 -11
- xync_client/Htx/ex.py +7 -9
- xync_client/Mexc/agent.py +85 -0
- xync_client/Mexc/api.py +636 -0
- xync_client/Mexc/etype/order.py +639 -0
- xync_client/Mexc/ex.py +10 -8
- xync_client/Pms/Payeer/__init__.py +38 -29
- xync_client/Pms/Payeer/login.py +6 -2
- xync_client/Pms/Volet/__init__.py +82 -63
- xync_client/Pms/Volet/api.py +5 -4
- xync_client/loader.py +1 -0
- xync_client/pm_unifier.py +1 -1
- {xync_client-0.0.141.dist-info → xync_client-0.0.155.dist-info}/METADATA +4 -1
- {xync_client-0.0.141.dist-info → xync_client-0.0.155.dist-info}/RECORD +31 -26
- {xync_client-0.0.141.dist-info → xync_client-0.0.155.dist-info}/WHEEL +0 -0
- {xync_client-0.0.141.dist-info → xync_client-0.0.155.dist-info}/top_level.txt +0 -0
xync_client/Bybit/agent.py
CHANGED
|
@@ -2,15 +2,17 @@ import asyncio
|
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
4
|
from asyncio import sleep, gather
|
|
5
|
-
from
|
|
5
|
+
from asyncio.tasks import create_task
|
|
6
6
|
from datetime import datetime, timedelta, timezone
|
|
7
7
|
from difflib import SequenceMatcher
|
|
8
8
|
from enum import IntEnum
|
|
9
|
+
from hashlib import sha256
|
|
9
10
|
from http.client import HTTPException
|
|
10
11
|
from math import floor
|
|
11
12
|
from typing import Literal
|
|
12
13
|
|
|
13
14
|
import pyotp
|
|
15
|
+
from aiohttp.http_exceptions import HttpProcessingError
|
|
14
16
|
from asyncpg import ConnectionDoesNotExistError
|
|
15
17
|
from bybit_p2p import P2P
|
|
16
18
|
from bybit_p2p._exceptions import FailedRequestError
|
|
@@ -18,20 +20,26 @@ from payeer_api import PayeerAPI
|
|
|
18
20
|
from pyro_client.client.file import FileClient
|
|
19
21
|
from tortoise import BaseDBAsyncClient
|
|
20
22
|
from tortoise.exceptions import IntegrityError
|
|
21
|
-
from tortoise.expressions import
|
|
23
|
+
from tortoise.expressions import Q
|
|
22
24
|
from tortoise.functions import Count
|
|
23
25
|
from tortoise.signals import post_save
|
|
26
|
+
from tortoise.timezone import now
|
|
24
27
|
from urllib3.exceptions import ReadTimeoutError
|
|
28
|
+
from x_client import df_hdrs
|
|
25
29
|
from x_model import init_db
|
|
26
30
|
from x_model.func import ArrayAgg
|
|
31
|
+
from xync_bot import XyncBot
|
|
32
|
+
from xync_client.Bybit.InAgent import InAgentClient
|
|
33
|
+
|
|
34
|
+
from xync_client.Bybit.ex import ExClient
|
|
27
35
|
from xync_schema import models
|
|
28
|
-
from xync_schema.enums import OrderStatus
|
|
36
|
+
from xync_schema.enums import OrderStatus, AgentStatus
|
|
29
37
|
|
|
30
|
-
from xync_schema.models import Actor,
|
|
38
|
+
from xync_schema.models import Actor, PmCur, Agent
|
|
31
39
|
|
|
32
40
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
33
|
-
from xync_client.Abc.xtype import
|
|
34
|
-
from xync_client.Bybit.etype.ad import AdPostRequest, AdUpdateRequest, Ad, AdStatus
|
|
41
|
+
from xync_client.Abc.xtype import FlatDict, BaseOrderReq
|
|
42
|
+
from xync_client.Bybit.etype.ad import AdPostRequest, AdUpdateRequest, Ad, AdStatus, MyAd
|
|
35
43
|
from xync_client.Bybit.etype.cred import CredEpyd
|
|
36
44
|
from xync_client.Bybit.etype.order import (
|
|
37
45
|
OrderRequest,
|
|
@@ -42,17 +50,20 @@ from xync_client.Bybit.etype.order import (
|
|
|
42
50
|
OrderFull,
|
|
43
51
|
Message,
|
|
44
52
|
Status,
|
|
53
|
+
OrderSellRequest,
|
|
54
|
+
TakeAdReq,
|
|
45
55
|
)
|
|
46
|
-
from xync_client.loader import TORM, NET_TOKEN
|
|
56
|
+
from xync_client.loader import TORM, NET_TOKEN, PAY_TOKEN
|
|
47
57
|
|
|
48
58
|
|
|
49
59
|
class NoMakerException(Exception):
|
|
50
60
|
pass
|
|
51
61
|
|
|
52
62
|
|
|
53
|
-
class AgentClient(BaseAgentClient): # Bybit client
|
|
54
|
-
|
|
55
|
-
|
|
63
|
+
class AgentClient(BaseAgentClient, InAgentClient): # Bybit client
|
|
64
|
+
headers = df_hdrs | {"accept-language": "ru-RU"}
|
|
65
|
+
sec_hdrs: dict[str, str]
|
|
66
|
+
# rewrite token for public methods
|
|
56
67
|
api: P2P
|
|
57
68
|
last_ad_id: list[str] = []
|
|
58
69
|
update_ad_body = {
|
|
@@ -82,28 +93,29 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
82
93
|
"actionType": "MODIFY",
|
|
83
94
|
"securityRiskToken": "",
|
|
84
95
|
}
|
|
85
|
-
all_conds: dict[int, tuple[str, set[int]]] = {}
|
|
86
|
-
cond_sims: dict[int, int] = defaultdict(set)
|
|
87
|
-
rcond_sims: dict[int, set[int]] = defaultdict(set) # backward
|
|
88
|
-
tree: dict = {}
|
|
89
96
|
|
|
90
|
-
def __init__(self,
|
|
91
|
-
super().__init__(
|
|
92
|
-
self.
|
|
93
|
-
|
|
94
|
-
|
|
97
|
+
def __init__(self, agent: Agent, ex_client: ExClient, fbot: FileClient, bbot: XyncBot, **kwargs):
|
|
98
|
+
super().__init__(agent, ex_client, fbot, bbot, **kwargs)
|
|
99
|
+
self.sec_hdrs = {
|
|
100
|
+
"accept-language": "ru,en;q=0.9",
|
|
101
|
+
"gdfp": agent.auth["Risktoken"],
|
|
102
|
+
"tx-id": agent.auth["Risktoken"],
|
|
103
|
+
}
|
|
104
|
+
self.api = P2P(testnet=False, api_key=agent.auth["key"], api_secret=agent.auth["sec"])
|
|
105
|
+
self.hist: dict | None = None
|
|
106
|
+
self.completed_orders: list[int] | None = None
|
|
95
107
|
|
|
96
108
|
""" Private METHs"""
|
|
97
109
|
|
|
98
110
|
async def fiat_new(self, payment_type: int, real_name: str, account_number: str) -> FlatDict | None:
|
|
99
111
|
method1 = await self._post(
|
|
100
|
-
"/fiat/otc/user/payment/new_create",
|
|
112
|
+
"/x-api/fiat/otc/user/payment/new_create",
|
|
101
113
|
{"paymentType": payment_type, "realName": real_name, "accountNo": account_number, "securityRiskToken": ""},
|
|
102
114
|
)
|
|
103
115
|
if srt := method1["result"]["securityRiskToken"]:
|
|
104
116
|
await self._check_2fa(srt)
|
|
105
117
|
method2 = await self._post(
|
|
106
|
-
"/fiat/otc/user/payment/new_create",
|
|
118
|
+
"/x-api/fiat/otc/user/payment/new_create",
|
|
107
119
|
{
|
|
108
120
|
"paymentType": payment_type,
|
|
109
121
|
"realName": real_name,
|
|
@@ -115,12 +127,8 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
115
127
|
else:
|
|
116
128
|
return logging.exception(method1)
|
|
117
129
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if fiat_id:
|
|
121
|
-
fiat = [m for m in list_methods if m["id"] == fiat_id][0]
|
|
122
|
-
return fiat
|
|
123
|
-
return list_methods[1]
|
|
130
|
+
def get_payment_method(self, fiat_id: int) -> CredEpyd:
|
|
131
|
+
return self.creds()[fiat_id]
|
|
124
132
|
|
|
125
133
|
def creds(self) -> dict[int, CredEpyd]:
|
|
126
134
|
data = self.api.get_user_payment_types()
|
|
@@ -144,29 +152,37 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
144
152
|
elif not cur_id: # is new Cred
|
|
145
153
|
cur_id = (
|
|
146
154
|
pmex.pm.df_cur_id
|
|
155
|
+
or await self.guess_cur(ecdx, len(pmex.pm.curs) > 1 and pmex.pm.curs)
|
|
147
156
|
or (pmex.pm.country_id and (await pmex.pm.country).cur_id)
|
|
148
|
-
# or (ecdx.currencyBalance and await models.Cur.get_or_none(ticker=ecdx.currencyBalance[0]))
|
|
149
|
-
or (0 < len(pmex.pm.curs) < 30 and pmex.pm.curs[-1].id)
|
|
150
|
-
or await self.guess_cur(ecdx)
|
|
157
|
+
# or (ecdx.currencyBalance and await models.Cur.get_or_none(ticker=ecdx.currencyBalance[0])) # это че еще за хуйня?
|
|
151
158
|
)
|
|
152
159
|
if not cur_id:
|
|
153
160
|
raise Exception(f"Set default cur for {pmex.name}")
|
|
154
161
|
if not (pmcur := await models.PmCur.get_or_none(cur_id=cur_id, pm_id=pmex.pm_id)):
|
|
155
|
-
raise HTTPException(f"No PmCur with cur#{
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
"
|
|
159
|
-
|
|
160
|
-
"
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
162
|
+
raise HTTPException(f"No PmCur with cur#{cur_id} and pm#{ecdx.paymentType}", 404)
|
|
163
|
+
xtr = ecdx.branchName
|
|
164
|
+
if ecdx.bankName:
|
|
165
|
+
xtr += (" | " if xtr else "") + ecdx.bankName
|
|
166
|
+
elif ecdx.payMessage:
|
|
167
|
+
xtr += (" | " if xtr else "") + ecdx.payMessage
|
|
168
|
+
elif ecdx.qrcode:
|
|
169
|
+
xtr += (" | " if xtr else "") + ecdx.qrcode
|
|
170
|
+
elif ecdx.paymentExt1:
|
|
171
|
+
xtr += (" | " if xtr else "") + ecdx.paymentExt1
|
|
172
|
+
cred_db, _ = await models.Cred.update_or_create(
|
|
173
|
+
{
|
|
174
|
+
"name": ecdx.realName,
|
|
175
|
+
"extra": xtr,
|
|
176
|
+
},
|
|
177
|
+
pmcur=pmcur,
|
|
178
|
+
person_id=pers_id or self.actor.person_id,
|
|
179
|
+
detail=ecdx.accountNo or ecdx.payMessage,
|
|
180
|
+
)
|
|
165
181
|
credex_in = models.CredEx.validate({"exid": ecdx.id, "cred_id": cred_db.id, "ex_id": self.actor.ex.id})
|
|
166
182
|
credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
|
|
167
183
|
return credex_db
|
|
168
184
|
|
|
169
|
-
async def guess_cur(self, ecdx: CredEpyd):
|
|
185
|
+
async def guess_cur(self, ecdx: CredEpyd, curs: list[models.Cur]):
|
|
170
186
|
mbs = ecdx.bankName.split(", ")
|
|
171
187
|
mbs += ecdx.branchName.split(" / ")
|
|
172
188
|
mbs = {mb.lower(): mb for mb in mbs}
|
|
@@ -178,7 +194,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
178
194
|
.values("pmcurs__cur_id", "names", "ccnt")
|
|
179
195
|
):
|
|
180
196
|
return pms[0]["pmcurs__cur_id"]
|
|
181
|
-
curs = {c.ticker: c.id for c in await models.Cur.all()}
|
|
197
|
+
curs = {c.ticker: c.id for c in curs or await models.Cur.all()}
|
|
182
198
|
for cur, cid in curs.items():
|
|
183
199
|
if re.search(re.compile(rf"\({cur}\)$"), ecdx.bankName):
|
|
184
200
|
return cid
|
|
@@ -188,6 +204,8 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
188
204
|
return cid
|
|
189
205
|
if re.search(re.compile(rf"\({cur}\)$"), ecdx.payMessage):
|
|
190
206
|
return cid
|
|
207
|
+
if re.search(re.compile(rf"\({cur}\)$"), ecdx.paymentExt1):
|
|
208
|
+
return cid
|
|
191
209
|
return None
|
|
192
210
|
|
|
193
211
|
# 25: Список реквизитов моих платежных методов
|
|
@@ -197,34 +215,34 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
197
215
|
return credexs
|
|
198
216
|
|
|
199
217
|
async def ott(self):
|
|
200
|
-
t = await self._post("/user/private/ott")
|
|
218
|
+
t = await self._post("/x-api/user/private/ott")
|
|
201
219
|
return t
|
|
202
220
|
|
|
203
221
|
# 27
|
|
204
222
|
async def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> dict:
|
|
205
223
|
fiat = self.get_payment_method(fiat_id)
|
|
206
|
-
fiat
|
|
207
|
-
fiat
|
|
208
|
-
result = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
224
|
+
fiat.realName = name
|
|
225
|
+
fiat.accountNo = detail
|
|
226
|
+
result = await self._post("/x-api/fiat/otc/user/payment/new_update", fiat.model_dump(exclude_none=True))
|
|
209
227
|
srt = result["result"]["securityRiskToken"]
|
|
210
228
|
await self._check_2fa(srt)
|
|
211
|
-
fiat
|
|
212
|
-
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
229
|
+
fiat.securityRiskToken = srt
|
|
230
|
+
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat.model_dump(exclude_none=True))
|
|
213
231
|
return result2
|
|
214
232
|
|
|
215
233
|
# 28
|
|
216
234
|
async def fiat_del(self, fiat_id: int) -> dict | str:
|
|
217
235
|
data = {"id": fiat_id, "securityRiskToken": ""}
|
|
218
|
-
method = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
236
|
+
method = await self._post("/x-api/fiat/otc/user/payment/new_delete", data)
|
|
219
237
|
srt = method["result"]["securityRiskToken"]
|
|
220
238
|
await self._check_2fa(srt)
|
|
221
239
|
data["securityRiskToken"] = srt
|
|
222
|
-
delete = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
240
|
+
delete = await self._post("/x-api/fiat/otc/user/payment/new_delete", data)
|
|
223
241
|
return delete
|
|
224
242
|
|
|
225
243
|
async def switch_ads(self, new_status: AdStatus) -> dict:
|
|
226
244
|
data = {"workStatus": new_status.name} # todo: переделать на апи, там status 0 -> 1
|
|
227
|
-
res = await self._post("/fiat/otc/maker/work-config/switch", data)
|
|
245
|
+
res = await self._post("/x-api/fiat/otc/maker/work-config/switch", data)
|
|
228
246
|
return res
|
|
229
247
|
|
|
230
248
|
async def ads(
|
|
@@ -232,27 +250,36 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
232
250
|
cnx: models.CoinEx,
|
|
233
251
|
crx: models.CurEx,
|
|
234
252
|
is_sell: bool,
|
|
235
|
-
|
|
253
|
+
pmexs: list[models.PmEx],
|
|
236
254
|
amount: int = None,
|
|
237
255
|
lim: int = 50,
|
|
238
256
|
vm_filter: bool = False,
|
|
257
|
+
post_pmexs: set[models.PmEx] = None,
|
|
239
258
|
) -> list[Ad]:
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
259
|
+
if post_pmexs:
|
|
260
|
+
pm_exids = None
|
|
261
|
+
lim = min(1000, lim * 25)
|
|
262
|
+
post_pmexids = {p.exid for p in post_pmexs}
|
|
263
|
+
else:
|
|
264
|
+
pm_exids = [px.exid for px in pmexs]
|
|
265
|
+
post_pmexids = set()
|
|
266
|
+
ads: list[Ad] = await self.ex_client.ads(cnx.exid, crx.exid, is_sell, pm_exids, amount, lim, vm_filter)
|
|
267
|
+
if post_pmexs:
|
|
268
|
+
ads = [
|
|
269
|
+
ad
|
|
270
|
+
for ad in ads
|
|
271
|
+
if (set(ad.payments) & post_pmexids or [True for px in post_pmexs if px.pm.norm in ad.remark.lower()])
|
|
272
|
+
]
|
|
273
|
+
return ads
|
|
247
274
|
|
|
248
275
|
@staticmethod
|
|
249
276
|
def get_rate(list_ads: list) -> float:
|
|
250
277
|
ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
|
|
251
278
|
return float(ads[0]["price"])
|
|
252
279
|
|
|
253
|
-
def my_ads(self, active: bool = True, page: int = 1) -> list[
|
|
280
|
+
def my_ads(self, active: bool = True, page: int = 1) -> list[MyAd]:
|
|
254
281
|
resp = self.api.get_ads_list(size="30", page=str(page), status=AdStatus.active if active else AdStatus.sold_out)
|
|
255
|
-
ads = [
|
|
282
|
+
ads = [MyAd.model_validate(ad) for ad in resp["result"]["items"]]
|
|
256
283
|
if resp["result"]["count"] > 30 * page:
|
|
257
284
|
ads.extend(self.my_ads(active, page + 1))
|
|
258
285
|
return ads
|
|
@@ -261,35 +288,63 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
261
288
|
ads = self.my_ads(True)
|
|
262
289
|
if not active:
|
|
263
290
|
ads += self.my_ads(False)
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
291
|
+
for ad in ads:
|
|
292
|
+
ad_db = await self.ex_client.ad_load(ad, maker=self.actor)
|
|
293
|
+
mad_db, _ = await models.MyAd.update_or_create(ad=ad_db)
|
|
294
|
+
exids = [pt.id for pt in ad.paymentTerms]
|
|
295
|
+
credexs = await models.CredEx.filter(ex_id=self.actor.ex_id, exid__in=exids)
|
|
296
|
+
await mad_db.credexs.add(*credexs)
|
|
297
|
+
return len(ads)
|
|
267
298
|
|
|
268
299
|
def get_security_token_create(self):
|
|
269
|
-
data = self._post("/fiat/otc/item/create", self.create_ad_body)
|
|
300
|
+
data = self._post("/x-api/fiat/otc/item/create", self.create_ad_body)
|
|
270
301
|
if data["ret_code"] == 912120019: # Current user can not to create add as maker
|
|
271
302
|
raise NoMakerException(data)
|
|
272
303
|
security_risk_token = data["result"]["securityRiskToken"]
|
|
273
304
|
return security_risk_token
|
|
274
305
|
|
|
275
|
-
def _check_2fa(self, risk_token):
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
totp = pyotp.TOTP(bybit_secret)
|
|
279
|
-
totp_code = totp.now()
|
|
280
|
-
|
|
281
|
-
res = self._post(
|
|
282
|
-
"/user/public/risk/verify", {"risk_token": risk_token, "component_list": {"google2fa": totp_code}}
|
|
283
|
-
)
|
|
306
|
+
async def _check_2fa(self, risk_token) -> int:
|
|
307
|
+
data = {"risk_token": risk_token}
|
|
308
|
+
res = await self._post("/x-api/user/public/risk/components", data, hdrs=self.sec_hdrs)
|
|
284
309
|
if res["ret_msg"] != "success":
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
310
|
+
raise HTTPException("get")
|
|
311
|
+
cres = sorted(res["result"]["component_list"], key=lambda c: c["component_id"], reverse=True)
|
|
312
|
+
vdata = {
|
|
313
|
+
"risk_token": risk_token,
|
|
314
|
+
"component_list": {c["component_id"]: await self.__get_2fa(c["component_id"], risk_token) for c in cres},
|
|
315
|
+
}
|
|
316
|
+
res = await self._post("/x-api/user/public/risk/verify", vdata, hdrs=self.sec_hdrs)
|
|
317
|
+
if er_code := res["ret_code"] or res["result"]["ret_code"]: # если код не 0, значит ошибка
|
|
318
|
+
logging.error("Wrong 2fa, wait 5 secs and retry..")
|
|
319
|
+
await sleep(5)
|
|
320
|
+
return await self._check_2fa(risk_token)
|
|
321
|
+
return er_code
|
|
322
|
+
|
|
323
|
+
async def __get_2fa(
|
|
324
|
+
self, typ: Literal["google2fa", "email_verify", "payment_password_verify", "phone_verify"], rt: str = None
|
|
325
|
+
):
|
|
326
|
+
res = {"ret_msg": "success"}
|
|
327
|
+
if typ != "google2fa":
|
|
328
|
+
data = {"risk_token": rt, "component_id": typ}
|
|
329
|
+
res = await self._post("/x-api/user/public/risk/send/code", data, hdrs=self.sec_hdrs)
|
|
330
|
+
if res["ret_msg"] == "success":
|
|
331
|
+
if typ == "google2fa":
|
|
332
|
+
bybit_secret = self.agent.auth["2fa"]
|
|
333
|
+
totp = pyotp.TOTP(bybit_secret)
|
|
334
|
+
return totp.now()
|
|
335
|
+
elif typ == "email_verify":
|
|
336
|
+
return self.gmail.bybit_code()
|
|
337
|
+
elif typ == "payment_password_verify":
|
|
338
|
+
hp = sha256(self.agent.auth["pass"].encode()).hexdigest()
|
|
339
|
+
return hp
|
|
340
|
+
elif cool_down := int(res["result"]["cool_down"]):
|
|
341
|
+
await sleep(cool_down)
|
|
342
|
+
return self.__get_2fa(typ, rt)
|
|
343
|
+
raise Exception("2fa fail")
|
|
289
344
|
|
|
290
345
|
def _post_ad(self, risk_token: str):
|
|
291
346
|
self.create_ad_body.update({"securityRiskToken": risk_token})
|
|
292
|
-
data = self._post("/fiat/otc/item/create", self.create_ad_body)
|
|
347
|
+
data = self._post("/x-api/fiat/otc/item/create", self.create_ad_body)
|
|
293
348
|
return data
|
|
294
349
|
|
|
295
350
|
# создание объявлений
|
|
@@ -315,7 +370,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
315
370
|
|
|
316
371
|
def get_security_token_update(self) -> str:
|
|
317
372
|
self.update_ad_body["id"] = self.last_ad_id
|
|
318
|
-
data = self._post("/fiat/otc/item/update", self.update_ad_body)
|
|
373
|
+
data = self._post("/x-api/fiat/otc/item/update", self.update_ad_body)
|
|
319
374
|
security_risk_token = data["result"]["securityRiskToken"]
|
|
320
375
|
return security_risk_token
|
|
321
376
|
|
|
@@ -332,46 +387,75 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
332
387
|
|
|
333
388
|
def update_ad(self, risk_token: str):
|
|
334
389
|
self.update_ad_body.update({"securityRiskToken": risk_token})
|
|
335
|
-
data = self._post("/fiat/otc/item/update", self.update_ad_body)
|
|
390
|
+
data = self._post("/x-api/fiat/otc/item/update", self.update_ad_body)
|
|
336
391
|
return data
|
|
337
392
|
|
|
338
393
|
def ad_del(self, ad_id: int):
|
|
339
394
|
data = self.api.remove_ad(itemId=ad_id)
|
|
340
395
|
return data
|
|
341
396
|
|
|
342
|
-
async def
|
|
343
|
-
|
|
344
|
-
if
|
|
345
|
-
|
|
346
|
-
|
|
397
|
+
async def __preorder_request(self, ad_id: int) -> PreOrderResp:
|
|
398
|
+
res = await self._post("/x-api/fiat/otc/item/simple", json={"item_id": str(ad_id)})
|
|
399
|
+
if res["ret_code"] == 0:
|
|
400
|
+
res = res["result"]
|
|
401
|
+
return PreOrderResp.model_validate(res)
|
|
402
|
+
|
|
403
|
+
async def _order_request(self, bor: BaseOrderReq) -> OrderResp:
|
|
404
|
+
por: PreOrderResp = await self.__preorder_request(bor.ad_id)
|
|
347
405
|
req = OrderRequest(
|
|
348
|
-
itemId=
|
|
349
|
-
tokenId=
|
|
350
|
-
currencyId=
|
|
351
|
-
side=
|
|
352
|
-
amount=
|
|
353
|
-
curPrice=
|
|
354
|
-
quantity=str(
|
|
355
|
-
flag="amount"
|
|
406
|
+
itemId=por.id,
|
|
407
|
+
tokenId=bor.coin_exid,
|
|
408
|
+
currencyId=bor.cur_exid,
|
|
409
|
+
side="1" if bor.is_sell else "0",
|
|
410
|
+
amount=f"{bor.fiat_amount:.2f}".rstrip("0").rstrip("."),
|
|
411
|
+
curPrice=por.curPrice,
|
|
412
|
+
quantity=str(round(bor.fiat_amount / float(por.price), bor.coin_scale)),
|
|
413
|
+
flag="amount",
|
|
414
|
+
# online="0"
|
|
356
415
|
)
|
|
416
|
+
if bor.is_sell:
|
|
417
|
+
credex = await models.CredEx.get(
|
|
418
|
+
cred__person_id=self.actor.person_id,
|
|
419
|
+
cred__pmcur__pm__pmexs__exid=[pp for pp in por.payments if pp == bor.pmex_exid][0], # bor.pmex_exid
|
|
420
|
+
cred__pmcur__pm__pmexs__ex_id=self.ex_client.ex.id,
|
|
421
|
+
cred__pmcur__cur__ticker=bor.cur_exid,
|
|
422
|
+
)
|
|
423
|
+
req = OrderSellRequest(**req.model_dump(), paymentType=bor.pmex_exid, paymentId=str(credex.exid))
|
|
357
424
|
# вот непосредственно сам запрос на ордер
|
|
358
|
-
|
|
425
|
+
return await self.__order_create(req, bor)
|
|
426
|
+
|
|
427
|
+
async def __order_create(self, req: OrderRequest | OrderSellRequest, bor: BaseOrderReq) -> OrderResp:
|
|
428
|
+
hdrs = {"Risktoken": self.sec_hdrs["gdfp"]}
|
|
429
|
+
res: dict = await self._post("/x-api/fiat/otc/order/create", json=req.model_dump(), hdrs=hdrs)
|
|
359
430
|
if res["ret_code"] == 0:
|
|
360
|
-
|
|
431
|
+
resp = OrderResp.model_validate(res["result"])
|
|
432
|
+
elif res["ret_code"] == 10001:
|
|
433
|
+
logging.error(req.model_dump(), "POST", self.session._base_url)
|
|
434
|
+
raise HTTPException()
|
|
361
435
|
elif res["ret_code"] == 912120030 or res["ret_msg"] == "The price has changed, please try again later.":
|
|
362
|
-
|
|
436
|
+
resp = await self._order_request(bor)
|
|
437
|
+
else:
|
|
438
|
+
logging.exception(res)
|
|
439
|
+
if not resp.orderId and resp.needSecurityRisk:
|
|
440
|
+
if rc := await self._check_2fa(resp.securityRiskToken):
|
|
441
|
+
await self.bbot.send(self.actor.person.user.username_id, f"Bybit 2fa: {rc}")
|
|
442
|
+
raise Exception(f"Bybit 2fa: {rc}")
|
|
443
|
+
# еще раз уже с токеном
|
|
444
|
+
req.securityRiskToken = resp.securityRiskToken
|
|
445
|
+
resp = await self.__order_create(req, bor)
|
|
446
|
+
return resp
|
|
363
447
|
|
|
364
448
|
async def cancel_order(self, order_id: str) -> bool:
|
|
365
449
|
cr = CancelOrderReq(orderId=order_id)
|
|
366
|
-
res = await self._post("/fiat/otc/order/cancel", cr.model_dump())
|
|
450
|
+
res = await self._post("/x-api/fiat/otc/order/cancel", cr.model_dump())
|
|
367
451
|
return res["ret_code"] == 0
|
|
368
452
|
|
|
369
|
-
def get_order_info(self, order_id: str) ->
|
|
370
|
-
data = self._post("/fiat/otc/order/info", json={"orderId": order_id})
|
|
371
|
-
return data["result"]
|
|
453
|
+
async def get_order_info(self, order_id: str) -> OrderFull:
|
|
454
|
+
data = await self._post("/x-api/fiat/otc/order/info", json={"orderId": order_id})
|
|
455
|
+
return OrderFull.model_validate(data["result"])
|
|
372
456
|
|
|
373
457
|
def get_chat_msg(self, order_id):
|
|
374
|
-
data = self._post("/fiat/otc/order/message/listpage", json={"orderId": order_id, "size": 100})
|
|
458
|
+
data = self._post("/x-api/fiat/otc/order/message/listpage", json={"orderId": order_id, "size": 100})
|
|
375
459
|
msgs = [
|
|
376
460
|
{"text": msg["message"], "type": msg["contentType"], "role": msg["roleType"], "user_id": msg["userId"]}
|
|
377
461
|
for msg in data["result"]["result"]
|
|
@@ -380,14 +464,14 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
380
464
|
return msgs
|
|
381
465
|
|
|
382
466
|
def block_user(self, user_id: str):
|
|
383
|
-
return self._post("/fiat/p2p/user/add_block_user", {"blockedUserId": user_id})
|
|
467
|
+
return self._post("/x-api/fiat/p2p/user/add_block_user", {"blockedUserId": user_id})
|
|
384
468
|
|
|
385
469
|
def unblock_user(self, user_id: str):
|
|
386
|
-
return self._post("/fiat/p2p/user/delete_block_user", {"blockedUserId": user_id})
|
|
470
|
+
return self._post("/x-api/fiat/p2p/user/delete_block_user", {"blockedUserId": user_id})
|
|
387
471
|
|
|
388
472
|
def user_review_post(self, order_id: str):
|
|
389
473
|
return self._post(
|
|
390
|
-
"/fiat/otc/order/appraise/modify",
|
|
474
|
+
"/x-api/fiat/otc/order/appraise/modify",
|
|
391
475
|
{
|
|
392
476
|
"orderId": order_id,
|
|
393
477
|
"anonymous": "0",
|
|
@@ -407,7 +491,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
407
491
|
self, side: int = None, status: int = None, begin_time: int = None, end_time: int = None, token_id: str = None
|
|
408
492
|
):
|
|
409
493
|
return await self._post(
|
|
410
|
-
"/fiat/otc/order/pending/simplifyList",
|
|
494
|
+
"/x-api/fiat/otc/order/pending/simplifyList",
|
|
411
495
|
{
|
|
412
496
|
"status": status,
|
|
413
497
|
"tokenId": token_id,
|
|
@@ -421,7 +505,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
421
505
|
|
|
422
506
|
def get_orders_done(self, begin_time: int, end_time: int, status: int, side: int, token_id: str):
|
|
423
507
|
return self._post(
|
|
424
|
-
"/fiat/otc/order/simplifyList",
|
|
508
|
+
"/x-api/fiat/otc/order/simplifyList",
|
|
425
509
|
{
|
|
426
510
|
"status": status, # 50 - завершено
|
|
427
511
|
"tokenId": token_id,
|
|
@@ -434,21 +518,24 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
434
518
|
)
|
|
435
519
|
|
|
436
520
|
async def create_order(self, order: OrderFull) -> models.Order:
|
|
437
|
-
ad = Ad(**self.api.get_ad_details(itemId=order.itemId)["result"])
|
|
521
|
+
# ad = Ad(**self.api.get_ad_details(itemId=order.itemId)["result"])
|
|
438
522
|
await sleep(1)
|
|
439
523
|
curex = await models.CurEx.get_or_none(ex=self.ex_client.ex, exid=order.currencyId).prefetch_related("cur")
|
|
440
524
|
cur_scale = (curex.scale if curex.scale is not None else curex.cur.scale) if curex else 2
|
|
441
525
|
coinex = await models.CoinEx.get(ex=self.ex_client.ex, exid=order.tokenId).prefetch_related("coin")
|
|
442
526
|
coin_scale = coinex.scale if coinex.scale is not None else coinex.cur.scale
|
|
443
|
-
maker_name = order.
|
|
527
|
+
maker_name = order.sellerRealName, order.buyerRealName
|
|
444
528
|
im_maker = int(order.makerUserId == order.userId)
|
|
445
529
|
taker_id = (order.userId, order.targetUserId)[im_maker]
|
|
446
|
-
taker_person = await self.
|
|
530
|
+
taker_person = await self.ex_client.person_name_update(maker_name[::-1][order.side], taker_id)
|
|
447
531
|
seller_person = (
|
|
448
|
-
self.actor.person
|
|
532
|
+
self.actor.person
|
|
533
|
+
if order.side
|
|
534
|
+
else await self.ex_client.person_name_update(order.sellerRealName, int(order.targetUserId))
|
|
449
535
|
)
|
|
450
536
|
taker_nick = (self.actor.name, order.targetNickName)[im_maker] # todo: check
|
|
451
|
-
ad_db, cond_isnew = await self.
|
|
537
|
+
# ad_db, cond_isnew = await self.ex_client.cond_load(ad, force=True, rname=maker_name[order.side])
|
|
538
|
+
ad_db = await models.Ad.get(exid=order.itemId)
|
|
452
539
|
if not ad_db:
|
|
453
540
|
...
|
|
454
541
|
ecredex: CredEpyd = order.confirmedPayTerm
|
|
@@ -458,22 +545,22 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
458
545
|
if ecredex.paymentType:
|
|
459
546
|
if ecredex.paymentType == 51:
|
|
460
547
|
ecredex.accountNo = ecredex.accountNo.replace("p", "P").replace("р", "P").replace("Р", "P")
|
|
461
|
-
if not re.match(r"^([Pp])\d{7,10}$", ecredex.accountNo):
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
548
|
+
# if not re.match(r"^([Pp])\d{7,10}$", ecredex.accountNo):
|
|
549
|
+
# msgs = self.api.get_chat_messages(orderId=order.id, size=100)["result"]["result"]
|
|
550
|
+
# msgs = [m["message"] for m in msgs if m["roleType"] == "user" and m["userId"] == order.targetUserId]
|
|
551
|
+
# msgs = [g.group() for m in msgs if (g := re.match(r"([PpРр])\d{7,10}\b", m))]
|
|
552
|
+
# crd = await models.Cred.get_or_none(
|
|
553
|
+
# detail=ecredex.accountNo, credexs__exid=ecredex.id, credexs__ex=self.ex_client.ex
|
|
554
|
+
# )
|
|
555
|
+
# if not msgs and re.match(r"^\d{7,10}$", ecredex.accountNo):
|
|
556
|
+
# ecredex.accountNo = "P" + ecredex.accountNo
|
|
557
|
+
# elif msgs:
|
|
558
|
+
# ecredex.accountNo = msgs[-1]
|
|
559
|
+
# else:
|
|
560
|
+
# ...
|
|
561
|
+
# if crd:
|
|
562
|
+
# crd.detail = ecredex.accountNo
|
|
563
|
+
# await crd.save(update_fields=["detail"])
|
|
477
564
|
if not (credex := await models.CredEx.get_or_none(exid=ecredex.id, ex=self.ex_client.ex)):
|
|
478
565
|
# cur_id = await Cur.get(ticker=ad.currencyId).values_list('id', flat=True)
|
|
479
566
|
# await self.cred_epyd2db(ecredex, ad_db.maker.person_id, cur_id)
|
|
@@ -481,7 +568,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
481
568
|
await PmCur.filter(
|
|
482
569
|
pm__pmexs__ex=self.ex_client.ex,
|
|
483
570
|
pm__pmexs__exid=ecredex.paymentType,
|
|
484
|
-
cur__ticker=
|
|
571
|
+
cur__ticker=order.currencyId,
|
|
485
572
|
).count()
|
|
486
573
|
!= 1
|
|
487
574
|
):
|
|
@@ -490,7 +577,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
490
577
|
pmcur := await PmCur.get_or_none(
|
|
491
578
|
pm__pmexs__ex=self.ex_client.ex,
|
|
492
579
|
pm__pmexs__exid=ecredex.paymentType,
|
|
493
|
-
cur__ticker=
|
|
580
|
+
cur__ticker=order.currencyId,
|
|
494
581
|
)
|
|
495
582
|
):
|
|
496
583
|
...
|
|
@@ -545,13 +632,13 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
545
632
|
to = ((odb.payed_at or odb.created_at) + timedelta(minutes=180 + 30)).isoformat(sep=" ").split("+")[0]
|
|
546
633
|
tsa = [
|
|
547
634
|
t
|
|
548
|
-
for tid, t in self.hist.items()
|
|
635
|
+
for tid, t in (self.hist.items() if self.hist else [])
|
|
549
636
|
if (ecredex.accountNo == t["to"] and t["from"] != "@merchant" and frm < t["date"] < to)
|
|
550
637
|
]
|
|
551
638
|
buyer_person = (
|
|
552
639
|
self.actor.person
|
|
553
640
|
if not order.side
|
|
554
|
-
else await self.
|
|
641
|
+
else await self.ex_client.person_name_update(order.buyerRealName, int(order.targetUserId))
|
|
555
642
|
)
|
|
556
643
|
ts = [t for t in tsa if floor(fa := float(order.amount)) <= float(t["creditedAmount"]) <= round(fa)]
|
|
557
644
|
if len(ts) != 1:
|
|
@@ -670,7 +757,8 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
670
757
|
# cad: Ad = ads[place] if cur_plc > place else ads[cur_plc]
|
|
671
758
|
# переделал пока на жесткую установку целевого места, даже если текущее выше:
|
|
672
759
|
if len(ads) <= target_place:
|
|
673
|
-
logging.error(f"target place {target_place} not found in ads
|
|
760
|
+
logging.error(f"target place {target_place} not found in ads {len(ads)}-lenght list")
|
|
761
|
+
target_place = len(ads) - 1
|
|
674
762
|
cad: Ad = ads[target_place]
|
|
675
763
|
# а цена обгоняемой объявы не выше нашего потолка?
|
|
676
764
|
if (float(cad.price) - ceil) * k <= 0:
|
|
@@ -689,10 +777,14 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
689
777
|
# if round(cpc * new_premium / cpm, 2) == m
|
|
690
778
|
# mad.premium = new_premium.to_eng_string()
|
|
691
779
|
|
|
692
|
-
async def
|
|
693
|
-
self
|
|
694
|
-
|
|
695
|
-
|
|
780
|
+
async def start_race(self):
|
|
781
|
+
races = await models.Race.filter(started=True, road__ad__maker_id=self.actor.id).prefetch_related(
|
|
782
|
+
"road__ad__pair_side__pair__cur", "road__credexs__cred", "road__ad__pms__pmexs__pm"
|
|
783
|
+
)
|
|
784
|
+
tasks = [create_task(self.racing(race), name=f"Rc{race.id}") for race in races]
|
|
785
|
+
return await gather(*tasks)
|
|
786
|
+
|
|
787
|
+
async def racing(self, race: models.Race):
|
|
696
788
|
coinex: models.CoinEx = await models.CoinEx.get(
|
|
697
789
|
coin_id=race.road.ad.pair_side.pair.coin_id, ex=self.actor.ex
|
|
698
790
|
).prefetch_related("coin")
|
|
@@ -700,11 +792,13 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
700
792
|
cur_id=race.road.ad.pair_side.pair.cur_id, ex=self.actor.ex
|
|
701
793
|
).prefetch_related("cur")
|
|
702
794
|
taker_side: bool = not race.road.ad.pair_side.is_sell
|
|
703
|
-
|
|
704
|
-
pmexs: list[models.PmEx] =
|
|
795
|
+
creds = [c.cred for c in race.road.credexs]
|
|
796
|
+
pmexs: list[models.PmEx] = [pmex for pm in race.road.ad.pms for pmex in pm.pmexs if pmex.ex_id == 4]
|
|
797
|
+
post_pm_ids = {c.cred.ovr_pm_id for c in race.road.credexs if c.cred.ovr_pm_id}
|
|
798
|
+
post_pmexs = set(await models.PmEx.filter(pm_id__in=post_pm_ids, ex=self.actor.ex).prefetch_related("pm"))
|
|
799
|
+
|
|
705
800
|
k = (-1) ** int(taker_side) # on_buy=1, on_sell=-1
|
|
706
801
|
sleep_sec = 3 # 1 if set(pms) & {"volet"} and coinex.coin_id == 1 else 5
|
|
707
|
-
creds: list[models.CredEx] = await self.get_credexs_by_pms(race.road.ad.pms, curex.cur_id)
|
|
708
802
|
_lstat, volume = None, 0
|
|
709
803
|
|
|
710
804
|
while self.actor.person.user.status > 0:
|
|
@@ -715,8 +809,9 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
715
809
|
continue
|
|
716
810
|
# если гонка дольше Х минут не обновлялась, обновляем ее (и ее пары) потолок
|
|
717
811
|
expiration = datetime.now(timezone.utc) - timedelta(minutes=15)
|
|
812
|
+
amt = race.filter_amount * 10**-curex.cur.scale if race.filter_amount else None
|
|
718
813
|
if race.updated_at < expiration:
|
|
719
|
-
ceils, hp, vmf, zplace = await self.get_ceils(coinex, curex, pmexs, 0.
|
|
814
|
+
ceils, hp, vmf, zplace = await self.get_ceils(coinex, curex, pmexs, 0.003, False, 0, amt, post_pmexs)
|
|
720
815
|
race.ceil = int(ceils[int(taker_side)] * 10**curex.scale)
|
|
721
816
|
await race.save()
|
|
722
817
|
# upd pair race
|
|
@@ -725,34 +820,28 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
725
820
|
road__ad__pair_side__is_sell=taker_side,
|
|
726
821
|
road__ad__maker=self.actor,
|
|
727
822
|
updated_at__lt=expiration,
|
|
728
|
-
|
|
729
|
-
pms_count=len(
|
|
823
|
+
road__credexs__id__in=[c.id for c in race.road.credexs],
|
|
824
|
+
pms_count=len(pmexs),
|
|
730
825
|
):
|
|
731
826
|
prace.ceil = int(ceils[int(not taker_side)] * 10**curex.scale)
|
|
732
827
|
await prace.save()
|
|
733
828
|
|
|
734
829
|
last_vol = volume
|
|
735
830
|
if taker_side: # гонка в стакане продажи - мы покупаем монету за ФИАТ
|
|
736
|
-
fiat = max(await models.Fiat.filter(cred_id__in=[c.
|
|
737
|
-
volume = fiat.amount / race.road.ad.price
|
|
831
|
+
fiat = max(await models.Fiat.filter(cred_id__in=[c.id for c in creds]), key=lambda x: x.amount)
|
|
832
|
+
volume = (fiat.amount * 10**-curex.cur.scale) / (race.road.ad.price * 10**-curex.scale)
|
|
738
833
|
else: # гонка в стакане покупки - мы продаем МОНЕТУ за фиат
|
|
739
834
|
asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
|
|
740
835
|
volume = asset.free * 10**-coinex.scale
|
|
741
836
|
volume = str(round(volume, coinex.scale))
|
|
742
|
-
|
|
743
837
|
try:
|
|
744
|
-
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pmexs)
|
|
838
|
+
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pmexs, amt, 50, race.vm_filter, post_pmexs)
|
|
745
839
|
except Exception:
|
|
746
840
|
await sleep(1)
|
|
747
|
-
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pmexs)
|
|
841
|
+
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pmexs, amt, 50, race.vm_filter, post_pmexs)
|
|
748
842
|
|
|
749
|
-
if race.vm_filter:
|
|
750
|
-
ads = [ad for ad in ads if "VA" in ad.authTag]
|
|
751
843
|
self.overprice_filter(ads, race.ceil * 10**-curex.scale, k) # обрезаем сверху все ads дороже нашего потолка
|
|
752
844
|
|
|
753
|
-
if 571 in pm_ids and coinex.coin.ticker == "USDT" and not taker_side:
|
|
754
|
-
...
|
|
755
|
-
|
|
756
845
|
if not ads:
|
|
757
846
|
print(coinex.exid, curex.exid, taker_side, "no ads!")
|
|
758
847
|
await sleep(15)
|
|
@@ -763,7 +852,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
763
852
|
await sleep(15)
|
|
764
853
|
continue
|
|
765
854
|
(cur_plc,) = cur_plc # может упасть если в списке > 1 наш ad
|
|
766
|
-
[(await self.
|
|
855
|
+
[(await self.ex_client.cond_load(ad, race.road.ad.pair_side, True))[0] for ad in ads[:cur_plc]]
|
|
767
856
|
# rivals = [
|
|
768
857
|
# (await models.RaceStat.update_or_create({"place": plc, "price": ad.price, "premium": ad.premium}, ad=ad))[
|
|
769
858
|
# 0
|
|
@@ -784,7 +873,7 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
784
873
|
continue
|
|
785
874
|
if not (cad := self.get_cad(ads, race.ceil * 10**-curex.scale, k, race.target_place, cur_plc)):
|
|
786
875
|
continue
|
|
787
|
-
new_price = round(float(cad.price) - k * step(mad, cad, curex.
|
|
876
|
+
new_price = round(float(cad.price) - k * step(mad, cad, curex.scale), curex.scale)
|
|
788
877
|
if (
|
|
789
878
|
float(mad.price) == new_price and volume == last_vol
|
|
790
879
|
): # Если место уже нужное или нужная цена и так уже стоит
|
|
@@ -796,23 +885,23 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
796
885
|
await sleep(sleep_sec)
|
|
797
886
|
continue
|
|
798
887
|
if cad.priceType: # Если цена конкурента плавающая, то повышаем себе не цену, а %
|
|
799
|
-
new_premium = float(cad.premium) - k * step(mad, cad, 2)
|
|
800
|
-
if float(mad.premium) == new_premium: # Если нужный % и так уже стоит
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
888
|
+
new_premium = (float(mad.premium) or float(cad.premium)) - k * step(mad, cad, 2)
|
|
889
|
+
# if float(mad.premium) == new_premium: # Если нужный % и так уже стоит
|
|
890
|
+
# if mad.priceType and cur_plc != race.target_place:
|
|
891
|
+
# new_premium -= k * step(mad, cad, 2)
|
|
892
|
+
# elif volume == last_vol:
|
|
893
|
+
# print(end="v" if taker_side else "^", flush=True)
|
|
894
|
+
# await sleep(sleep_sec)
|
|
895
|
+
# continue
|
|
807
896
|
mad.premium = str(round(new_premium, 2))
|
|
808
897
|
mad.priceType = cad.priceType
|
|
809
898
|
mad.quantity = volume
|
|
810
|
-
mad.maxAmount = str(2_000_000)
|
|
899
|
+
mad.maxAmount = str(2_000_000 if curex.cur_id == 1 else 40_000)
|
|
811
900
|
req = AdUpdateRequest.model_validate(
|
|
812
901
|
{
|
|
813
902
|
**mad.model_dump(),
|
|
814
903
|
"price": str(round(new_price, curex.scale)),
|
|
815
|
-
"paymentIds": [str(
|
|
904
|
+
"paymentIds": [str(cx.exid) for cx in race.road.credexs],
|
|
816
905
|
}
|
|
817
906
|
)
|
|
818
907
|
try:
|
|
@@ -839,18 +928,23 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
839
928
|
req.quantity = str(round(asset.free * 10**-coinex.scale, coinex.scale))
|
|
840
929
|
_res = self.ad_upd(req)
|
|
841
930
|
elif ExcCode(e.status_code) == ExcCode.RareLimit:
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
931
|
+
if not (
|
|
932
|
+
sads := [
|
|
933
|
+
ma
|
|
934
|
+
for ma in self.my_ads(False)
|
|
935
|
+
if (
|
|
936
|
+
ma.currencyId == curex.exid
|
|
937
|
+
and ma.tokenId == coinex.exid
|
|
938
|
+
and taker_side != ma.side
|
|
939
|
+
and set(ma.payments) == set([pe.exid for pe in pmexs])
|
|
940
|
+
)
|
|
941
|
+
]
|
|
942
|
+
):
|
|
943
|
+
logging.error(f"Need reserve Ad {'sell' if taker_side else 'buy'} {coinex.exid}/{curex.exid}")
|
|
944
|
+
await sleep(90)
|
|
945
|
+
continue
|
|
852
946
|
self.ad_del(ad_id=int(mad.id))
|
|
853
|
-
req.id =
|
|
947
|
+
req.id = sads[0].id
|
|
854
948
|
req.actionType = "ACTIVE"
|
|
855
949
|
self.api.update_ad(**req.model_dump())
|
|
856
950
|
logging.warning(f"Ad#{mad.id} recreated")
|
|
@@ -863,10 +957,15 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
863
957
|
await sleep(6)
|
|
864
958
|
|
|
865
959
|
async def get_books(
|
|
866
|
-
self,
|
|
960
|
+
self,
|
|
961
|
+
coinex: models.CoinEx,
|
|
962
|
+
curex: models.CurEx,
|
|
963
|
+
pmexs: list[models.PmEx],
|
|
964
|
+
amount: int,
|
|
965
|
+
post_pmexs: list[models.PmEx] = None,
|
|
867
966
|
) -> tuple[list[Ad], list[Ad]]:
|
|
868
|
-
buy: list[Ad] = await self.ads(coinex, curex, False, pmexs,
|
|
869
|
-
sell: list[Ad] = await self.ads(coinex, curex, True, pmexs,
|
|
967
|
+
buy: list[Ad] = await self.ads(coinex, curex, False, pmexs, amount, 40, False, post_pmexs)
|
|
968
|
+
sell: list[Ad] = await self.ads(coinex, curex, True, pmexs, amount, 30, False, post_pmexs)
|
|
870
969
|
return buy, sell
|
|
871
970
|
|
|
872
971
|
async def get_spread(
|
|
@@ -876,12 +975,12 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
876
975
|
...
|
|
877
976
|
buy_price, sell_price = float(bb[place].price), float(sb[place].price)
|
|
878
977
|
half_spread = (buy_price - sell_price) / (buy_price + sell_price)
|
|
879
|
-
if half_spread * 2 < perc:
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
978
|
+
# if half_spread * 2 < perc: # todo: aA???
|
|
979
|
+
# if not exact:
|
|
980
|
+
# if vmf is None: # сначала фильтруем только VA
|
|
981
|
+
# return await self.get_spread(bb, sb, perc, True, place)
|
|
982
|
+
# # если даже по VA не хватает спреда - увеличиваем место
|
|
983
|
+
# return await self.get_spread(bb, sb, perc, vmf, place + 1)
|
|
885
984
|
|
|
886
985
|
return (buy_price, sell_price), half_spread, vmf, place
|
|
887
986
|
|
|
@@ -893,307 +992,161 @@ class AgentClient(BaseAgentClient): # Bybit client
|
|
|
893
992
|
min_prof=0.02,
|
|
894
993
|
vmf: bool = False,
|
|
895
994
|
place: int = 0,
|
|
995
|
+
amount: int = None,
|
|
996
|
+
post_pmexs: set[models.PmEx] = None,
|
|
896
997
|
) -> tuple[tuple[float, float], float, bool, int]: # todo: refact to Pairex
|
|
897
|
-
bb, sb = await self.get_books(coinex, curex, pmexs)
|
|
998
|
+
bb, sb = await self.get_books(coinex, curex, pmexs, amount, post_pmexs)
|
|
898
999
|
if vmf:
|
|
1000
|
+
# ориентируемся на цены объявлений только проверенных мерчантов
|
|
899
1001
|
bb = [b for b in bb if "VA" in b.authTag]
|
|
900
1002
|
sb = [s for s in sb if "VA" in s.authTag]
|
|
901
|
-
perc = pmexs[0].pm.fee * 0.0001 + min_prof
|
|
1003
|
+
perc = list(post_pmexs or pmexs)[0].pm.fee * 0.0001 + min_prof
|
|
902
1004
|
(bf, sf), hp, vmf, zplace = await self.get_spread(bb, sb, perc, vmf, place)
|
|
903
1005
|
mdl = (bf + sf) / 2
|
|
904
1006
|
bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
|
|
905
1007
|
return (bc, sc), hp, vmf, zplace
|
|
906
1008
|
|
|
907
|
-
async def
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
1009
|
+
async def take_ad(self, req: TakeAdReq):
|
|
1010
|
+
if req.price and req.is_sell and req.cur_:
|
|
1011
|
+
... # todo call the get_ad_details() only if lack of data
|
|
1012
|
+
# res = self.api.get_ad_details(itemId=req.ad_id)["result"]
|
|
1013
|
+
# ad: Ad = Ad.model_validate(res)
|
|
1014
|
+
# pmexs = await models.PmEx.filter(ex_id=self.actor.ex_id, pm_id=req.pm_id)
|
|
1015
|
+
# if len(pmexs) > 1:
|
|
1016
|
+
# pmexs = [p for p in pmexs if p.exid in ad.payments]
|
|
1017
|
+
#
|
|
1018
|
+
# # todo: map pm->cred_pattern
|
|
1019
|
+
# pmexid = exids.pop() if (exids := set(ad.payments) & set(px.exid for px in pmexs)) else "40"
|
|
1020
|
+
pmexid = str(req.pm_id)
|
|
1021
|
+
coinex = await models.CoinEx.get(coin_id=req.coin_id, ex=self.ex_client.ex)
|
|
1022
|
+
curex = await models.CurEx.get(cur_id=req.cur_id, ex=self.ex_client.ex)
|
|
1023
|
+
|
|
1024
|
+
# if ad.side: # продажа, я (тейкер) покупатель
|
|
1025
|
+
# pmexs = await models.PmEx.filter(ex_id=self.actor.ex_id, pm_id=req.pm_id)
|
|
1026
|
+
# if len(pmexs) > 1:
|
|
1027
|
+
# pmexs = [p for p in pmexs if p.name.endswith(f" ({ad.currencyId})")]
|
|
1028
|
+
# else:
|
|
1029
|
+
# pmexs = await models.CredEx.filter(
|
|
1030
|
+
# ex_id=self.actor.ex_id, cred__person_id=self.actor.person_id,
|
|
1031
|
+
# cred__pmcur__pm_id=req.pm_id, cred__pmcur__cur__ticker=ad.currencyId
|
|
1032
|
+
# )
|
|
1033
|
+
# req.pm_id = pmexs[0].exid
|
|
1034
|
+
# req.quantity = round(req.amount / float(ad.price) - 0.00005, 4) # todo: to get the scale from coinEx
|
|
1035
|
+
|
|
1036
|
+
bor = BaseOrderReq(
|
|
1037
|
+
ad_id=str(req.ad_id),
|
|
1038
|
+
fiat_amount=req.amount,
|
|
1039
|
+
is_sell=req.is_sell,
|
|
1040
|
+
cur_exid=curex.exid,
|
|
1041
|
+
coin_exid=coinex.exid,
|
|
1042
|
+
coin_scale=coinex.scale,
|
|
1043
|
+
pmex_exid=pmexid,
|
|
937
1044
|
)
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
if int(
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
await ad_db.save()
|
|
982
|
-
logging.info(f"{ad.nickName} upd cond#{ad_db.cond_id}->{cid}")
|
|
983
|
-
# old_cid = ad_db.cond_id # todo: solve race-condition, а пока что очищаем при каждом запуске
|
|
984
|
-
# if not len((old_cond := await Cond.get(id=old_cid).prefetch_related('ads')).ads):
|
|
985
|
-
# await old_cond.delete()
|
|
986
|
-
# logging.warning(f"Cond#{old_cid} deleted!")
|
|
987
|
-
return (ad_db or force and await self.ad_create(ad, cid, rname, ps)), False
|
|
988
|
-
# если эта объява в таким ид уже есть в бд, но с другим условием (или без), а текущего условия еще нет в бд
|
|
989
|
-
if ad_db:
|
|
990
|
-
await ad_db.fetch_related("cond__ads", "maker")
|
|
991
|
-
if not ad_db.cond_id or (
|
|
992
|
-
# у измененного условия этой объявы есть другие объявы?
|
|
993
|
-
(rest_ads := set(ad_db.cond.ads) - {ad_db})
|
|
994
|
-
and
|
|
995
|
-
# другие объявы этого условия принадлежат другим юзерам
|
|
996
|
-
{ra.maker_id for ra in rest_ads} - {ad_db.maker_id}
|
|
997
|
-
):
|
|
998
|
-
# создадим новое условие и присвоим его только текущей объяве
|
|
999
|
-
cid = await self.cond_new(cleaned, {int(ad.userId)})
|
|
1000
|
-
ad_db.cond_id = cid
|
|
1001
|
-
await ad_db.save()
|
|
1002
|
-
|
|
1003
|
-
return ad_db, True
|
|
1004
|
-
# а если других объяв со старым условием этой обявы нет, либо они все этого же юзера
|
|
1005
|
-
# обновляем условие (в тч во всех ЕГО объявах)
|
|
1006
|
-
ad_db.cond.last_ver = ad_db.cond.raw_txt
|
|
1007
|
-
ad_db.cond.raw_txt = cleaned
|
|
1008
|
-
await ad_db.cond.save()
|
|
1009
|
-
await self.cond_upd(ad_db.cond, {ad_db.maker.exid})
|
|
1010
|
-
# и подправим коэфициенты похожести нового текста
|
|
1011
|
-
await self.fix_rel_sims(ad_db.cond_id, cleaned)
|
|
1012
|
-
return ad_db, False
|
|
1013
|
-
|
|
1014
|
-
cid = await self.cond_new(cleaned, {int(ad.userId)})
|
|
1015
|
-
return await self.ad_create(ad, cid, rname, ps), True
|
|
1016
|
-
|
|
1017
|
-
async def cond_new(self, txt: str, uids: set[int]) -> int:
|
|
1018
|
-
new_cond, _ = await Cond.update_or_create(raw_txt=txt)
|
|
1019
|
-
# и максимально похожую связь для нового условия (если есть >= 60%)
|
|
1020
|
-
await self.cond_upd(new_cond, uids)
|
|
1021
|
-
return new_cond.id
|
|
1022
|
-
|
|
1023
|
-
async def cond_upd(self, cond: Cond, uids: set[int]):
|
|
1024
|
-
self.all_conds[cond.id] = cond.raw_txt, uids
|
|
1025
|
-
# и максимально похожую связь для нового условия (если есть >= 60%)
|
|
1026
|
-
old_cid, sim = await self.cond_get_max_sim(cond.id, cond.raw_txt, uids)
|
|
1027
|
-
await self.actual_sim(cond.id, old_cid, sim)
|
|
1028
|
-
|
|
1029
|
-
def find_in_tree(self, cid: int, old_cid: int) -> bool:
|
|
1030
|
-
if p := self.cond_sims.get(old_cid):
|
|
1031
|
-
if p == cid:
|
|
1032
|
-
return True
|
|
1033
|
-
return self.find_in_tree(cid, p)
|
|
1034
|
-
return False
|
|
1035
|
-
|
|
1036
|
-
async def cond_get_max_sim(self, cid: int, txt: str, uids: set[int]) -> tuple[int | None, int | None]:
|
|
1037
|
-
# находим все старые тексты похожие на 90% и более
|
|
1038
|
-
if len(txt) < 15:
|
|
1039
|
-
return None, None
|
|
1040
|
-
sims: dict[int, int] = {}
|
|
1041
|
-
for old_cid, (old_txt, old_uids) in self.all_conds.items():
|
|
1042
|
-
if len(old_txt) < 15 or uids == old_uids:
|
|
1043
|
-
continue
|
|
1044
|
-
elif not self.can_add_sim(cid, old_cid):
|
|
1045
|
-
continue
|
|
1046
|
-
if sim := get_sim(txt, old_txt):
|
|
1047
|
-
sims[old_cid] = sim
|
|
1048
|
-
# если есть, берем самый похожий из них
|
|
1049
|
-
if sims:
|
|
1050
|
-
old_cid, sim = max(sims.items(), key=lambda x: x[1])
|
|
1051
|
-
await sleep(0.3)
|
|
1052
|
-
return old_cid, sim
|
|
1053
|
-
return None, None
|
|
1054
|
-
|
|
1055
|
-
def can_add_sim(self, cid: int, old_cid: int) -> bool:
|
|
1056
|
-
if cid == old_cid:
|
|
1057
|
-
return False
|
|
1058
|
-
elif self.cond_sims.get(cid) == old_cid:
|
|
1059
|
-
return False
|
|
1060
|
-
elif self.find_in_tree(cid, old_cid):
|
|
1061
|
-
return False
|
|
1062
|
-
elif self.cond_sims.get(old_cid) == cid:
|
|
1063
|
-
return False
|
|
1064
|
-
elif cid in self.rcond_sims.get(old_cid, {}):
|
|
1065
|
-
return False
|
|
1066
|
-
elif old_cid in self.rcond_sims.get(cid, {}):
|
|
1067
|
-
return False
|
|
1068
|
-
return True
|
|
1069
|
-
|
|
1070
|
-
async def person_upsert(self, name: str, exid: int) -> models.Person:
|
|
1071
|
-
if actor := await models.Actor.get_or_none(exid=exid, ex=self.ex_client.ex).prefetch_related("person"):
|
|
1072
|
-
if not actor.person:
|
|
1073
|
-
actor.person = await models.Person.create(name=name)
|
|
1074
|
-
await actor.save()
|
|
1075
|
-
return actor.person
|
|
1076
|
-
return await models.Person.create(name=name)
|
|
1077
|
-
|
|
1078
|
-
async def ad_create(
|
|
1079
|
-
self, ad: Ad, cid: int = None, rname: str = None, ps: PairSide = None, actor: Actor = None
|
|
1080
|
-
) -> models.Ad:
|
|
1081
|
-
act_df = {}
|
|
1082
|
-
if int(ad.userId) != self.actor.exid:
|
|
1083
|
-
act_df |= {"name": ad.nickName}
|
|
1084
|
-
if rname:
|
|
1085
|
-
act_df |= {"person": await self.person_upsert(rname, int(ad.userId))}
|
|
1086
|
-
if not actor:
|
|
1087
|
-
act_df |= {"person": await self.person_upsert(ad.nickName, int(ad.userId))}
|
|
1088
|
-
actor, _ = await Actor.update_or_create(act_df, exid=ad.userId, ex=self.ex_client.ex)
|
|
1089
|
-
ps = ps or await PairSide.get_or_none(
|
|
1090
|
-
is_sell=ad.side,
|
|
1091
|
-
pair__coin__ticker=ad.tokenId,
|
|
1092
|
-
pair__cur__ticker=ad.currencyId,
|
|
1093
|
-
).prefetch_related("pair__cur", "pair__coin")
|
|
1094
|
-
if not ps or not ps.pair:
|
|
1095
|
-
... # THB/USDC
|
|
1096
|
-
ad_upd = models.Ad.validate(ad.model_dump(by_alias=True))
|
|
1097
|
-
cur_scale = 10**ps.pair.cur.scale
|
|
1098
|
-
coinex = await models.CoinEx.get(coin_id=ps.pair.coin_id, ex=self.ex_client.ex)
|
|
1099
|
-
df_unq = ad_upd.df_unq(
|
|
1100
|
-
maker_id=actor.id,
|
|
1101
|
-
pair_side_id=ps.id,
|
|
1102
|
-
amount=int(float(ad.quantity) * float(ad.price) * cur_scale),
|
|
1103
|
-
quantity=int(float(ad.quantity) * 10**coinex.scale),
|
|
1104
|
-
min_fiat=int(float(ad.minAmount) * cur_scale),
|
|
1105
|
-
max_fiat=ad.maxAmount and int(float(ad.maxAmount) * cur_scale),
|
|
1106
|
-
price=int(float(ad.price) * cur_scale),
|
|
1107
|
-
premium=int(float(ad.premium) * cur_scale),
|
|
1108
|
-
)
|
|
1109
|
-
ad_db, _ = await models.Ad.update_or_create(**df_unq)
|
|
1110
|
-
await ad_db.pms.add(*(await models.Pm.filter(pmexs__ex=self.ex_client.ex, pmexs__exid__in=ad.payments)))
|
|
1111
|
-
return ad_db
|
|
1112
|
-
|
|
1113
|
-
async def fix_rel_sims(self, cid: int, new_txt: str):
|
|
1114
|
-
for rel_sim in await CondSim.filter(cond_rel_id=cid).prefetch_related("cond"):
|
|
1115
|
-
if sim := get_sim(new_txt, rel_sim.cond.raw_txt):
|
|
1116
|
-
rel_sim.similarity = sim
|
|
1117
|
-
await rel_sim.save()
|
|
1118
|
-
else:
|
|
1119
|
-
await rel_sim.delete()
|
|
1120
|
-
|
|
1121
|
-
async def actual_cond(self):
|
|
1122
|
-
for curr, old in await CondSim.all().values_list("cond_id", "cond_rel_id"):
|
|
1123
|
-
self.cond_sims[curr] = old
|
|
1124
|
-
self.rcond_sims[old] |= {curr}
|
|
1125
|
-
for cid, (txt, uids) in self.all_conds.items():
|
|
1126
|
-
old_cid, sim = await self.cond_get_max_sim(cid, txt, uids)
|
|
1127
|
-
await self.actual_sim(cid, old_cid, sim)
|
|
1128
|
-
# хз бля чо это ваще
|
|
1129
|
-
# for ad_db in await models.Ad.filter(direction__pairex__ex=self.ex_client.ex).prefetch_related("cond", "maker"):
|
|
1130
|
-
# ad = Ad(id=str(ad_db.exid), userId=str(ad_db.maker.exid), remark=ad_db.cond.raw_txt)
|
|
1131
|
-
# await self.cond_upsert(ad, force=True)
|
|
1132
|
-
|
|
1133
|
-
async def actual_sim(self, cid: int, old_cid: int, sim: int):
|
|
1134
|
-
if not sim:
|
|
1135
|
-
return
|
|
1136
|
-
if old_sim := await CondSim.get_or_none(cond_id=cid):
|
|
1137
|
-
if old_sim.cond_rel_id != old_cid:
|
|
1138
|
-
if sim > old_sim.similarity:
|
|
1139
|
-
logging.warning(f"R {cid}: {old_sim.similarity}->{sim} ({old_sim.cond_rel_id}->{old_cid})")
|
|
1140
|
-
await old_sim.update_from_dict({"similarity": sim, "old_rel_id": old_cid}).save()
|
|
1141
|
-
self._cond_sim_upd(cid, old_cid)
|
|
1142
|
-
elif sim != old_sim.similarity:
|
|
1143
|
-
logging.info(f"{cid}: {old_sim.similarity}->{sim}")
|
|
1144
|
-
await old_sim.update_from_dict({"similarity": sim}).save()
|
|
1145
|
-
else:
|
|
1146
|
-
await CondSim.create(cond_id=cid, cond_rel_id=old_cid, similarity=sim)
|
|
1147
|
-
self._cond_sim_upd(cid, old_cid)
|
|
1148
|
-
|
|
1149
|
-
def _cond_sim_upd(self, cid: int, old_cid: int):
|
|
1150
|
-
if old_old_cid := self.cond_sims.get(cid): # если старый cid уже был в дереве:
|
|
1151
|
-
self.rcond_sims[old_old_cid].remove(cid) # удаляем из обратного
|
|
1152
|
-
self.cond_sims[cid] = old_cid # а в прямом он автоматом переопределится, даже если и был
|
|
1153
|
-
self.rcond_sims[old_cid] |= {cid} # ну и в обратное добавим новый
|
|
1154
|
-
|
|
1155
|
-
async def get_credexs_by_pms(self, pms: list[models.Pm], cur_id: int) -> list[models.CredEx]:
|
|
1156
|
-
return await models.CredEx.filter(
|
|
1157
|
-
ex_id=self.actor.ex_id,
|
|
1158
|
-
cred__pmcur__pm_id__in=[pm.id for pm in pms],
|
|
1159
|
-
cred__person_id=self.actor.person_id,
|
|
1160
|
-
cred__pmcur__cur_id=cur_id,
|
|
1161
|
-
)
|
|
1162
|
-
|
|
1163
|
-
def build_tree(self):
|
|
1164
|
-
set(self.cond_sims.keys()) | set(self.cond_sims.values())
|
|
1165
|
-
tree = defaultdict(dict)
|
|
1166
|
-
# Группируем родителей по детям
|
|
1167
|
-
for child, par in self.cond_sims.items():
|
|
1168
|
-
tree[par] |= {child: {}} # todo: make from self.rcond_sim
|
|
1169
|
-
|
|
1170
|
-
# Строим дерево снизу вверх
|
|
1171
|
-
def subtree(node):
|
|
1172
|
-
if not node:
|
|
1173
|
-
return node
|
|
1174
|
-
for key in node:
|
|
1175
|
-
subnode = tree.pop(key, {})
|
|
1176
|
-
d = subtree(subnode)
|
|
1177
|
-
node[key] |= d # actual tree rebuilding here!
|
|
1178
|
-
return node # todo: refact?
|
|
1179
|
-
|
|
1180
|
-
# Находим корни / без родителей
|
|
1181
|
-
roots = set(self.cond_sims.values()) - set(self.cond_sims.keys())
|
|
1182
|
-
for root in roots:
|
|
1183
|
-
_ = subtree(tree[root])
|
|
1045
|
+
resp: OrderResp = await self._order_request(bor)
|
|
1046
|
+
return resp
|
|
1047
|
+
|
|
1048
|
+
async def watch_payeer(self, mcs: dict[int, "AgentClient"]):
|
|
1049
|
+
coinex: models.CoinEx = await models.CoinEx.get(coin_id=1, ex=self.actor.ex).prefetch_related("coin")
|
|
1050
|
+
curex: models.CurEx = await models.CurEx.get(cur_id=1, ex=self.actor.ex).prefetch_related("cur")
|
|
1051
|
+
post_pmexs = set(await models.PmEx.filter(pm_id=366, ex=self.actor.ex).prefetch_related("pm"))
|
|
1052
|
+
i = 0
|
|
1053
|
+
while True:
|
|
1054
|
+
try:
|
|
1055
|
+
ss = await self.ads(coinex, curex, True, None, None, 1000, False, post_pmexs)
|
|
1056
|
+
ss = [s for s in ss if float(s.price) > 90.42 or int(s.userId) in mcs.keys()]
|
|
1057
|
+
if ss:
|
|
1058
|
+
ad: Ad = ss[0]
|
|
1059
|
+
await self.bbot.send(
|
|
1060
|
+
193017646,
|
|
1061
|
+
f"price: {ad.price}\nnick: {ad.nickName}\nprice: {ad.price}"
|
|
1062
|
+
f"\nqty: {ad.quantity} [{ad.minAmount}-{ad.maxAmount}]",
|
|
1063
|
+
)
|
|
1064
|
+
am = min(float(ad.maxAmount), max(1000 + i, float(ad.minAmount)))
|
|
1065
|
+
req = TakeAdReq(
|
|
1066
|
+
ad_id=ad.id,
|
|
1067
|
+
amount=am,
|
|
1068
|
+
pm_id=14,
|
|
1069
|
+
is_sell=True,
|
|
1070
|
+
coin_id=1,
|
|
1071
|
+
cur_id=1,
|
|
1072
|
+
)
|
|
1073
|
+
ord_resp: OrderResp = await self.take_ad(req)
|
|
1074
|
+
# order: OrderFull = OrderFull(**self.api.get_order_details(orderId=ord_resp.orderId)["result"])
|
|
1075
|
+
order: OrderFull = await self.get_order_info(ord_resp.orderId)
|
|
1076
|
+
odb = await self.create_order(order)
|
|
1077
|
+
# t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
|
|
1078
|
+
# await t.fetch_related("order__cred__pmcur__cur")
|
|
1079
|
+
# res = await self.pm_clients[366].check_in(t)
|
|
1080
|
+
if int(ad.userId) in mcs:
|
|
1081
|
+
mcs[int(ad.userId)].api.mark_as_paid(
|
|
1082
|
+
orderId=str(odb.exid),
|
|
1083
|
+
paymentType=ad.payments[0], # pmex.exid
|
|
1084
|
+
paymentId=order.paymentTermList[0].id, # credex.exid
|
|
1085
|
+
)
|
|
1086
|
+
self.api.release_assets(orderId=order.id)
|
|
1087
|
+
...
|
|
1184
1088
|
|
|
1185
|
-
|
|
1089
|
+
bs = await self.ads(coinex, curex, False, None, None, 1000, False, post_pmexs)
|
|
1090
|
+
bs = [b for b in bs if float(b.price) < 89.56 or int(b.userId) in mcs.keys()]
|
|
1091
|
+
if bs:
|
|
1092
|
+
ad: Ad = bs[0]
|
|
1093
|
+
await self.bbot.send(
|
|
1094
|
+
193017646,
|
|
1095
|
+
f"price: {ad.price}\nnick: {ad.nickName}\nprice: {ad.price}"
|
|
1096
|
+
f"\nqty: {ad.quantity} [{ad.minAmount}-{ad.maxAmount}]",
|
|
1097
|
+
)
|
|
1098
|
+
am = min(float(ad.maxAmount), max(600 + i, float(ad.minAmount)))
|
|
1099
|
+
req = TakeAdReq(
|
|
1100
|
+
ad_id=ad.id,
|
|
1101
|
+
amount=am,
|
|
1102
|
+
pm_id=14,
|
|
1103
|
+
is_sell=False,
|
|
1104
|
+
coin_id=1,
|
|
1105
|
+
cur_id=1,
|
|
1106
|
+
)
|
|
1107
|
+
ord_resp: OrderResp = await self.take_ad(req)
|
|
1108
|
+
# order: OrderFull = OrderFull(**self.api.get_order_details(orderId=ord_resp.orderId)["result"])
|
|
1109
|
+
order: OrderFull = await self.get_order_info(ord_resp.orderId)
|
|
1110
|
+
odb = await self.create_order(order)
|
|
1111
|
+
t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
|
|
1112
|
+
await t.fetch_related("order__cred__pmcur__cur")
|
|
1113
|
+
# res = await self.pm_clients[366].send(t)
|
|
1114
|
+
self.api.mark_as_paid(
|
|
1115
|
+
orderId=str(odb.exid),
|
|
1116
|
+
paymentType=ad.payments[0], # pmex.exid
|
|
1117
|
+
paymentId=order.paymentTermList[0].id, # credex.exid
|
|
1118
|
+
)
|
|
1119
|
+
if int(ad.userId) in mcs:
|
|
1120
|
+
mcs[int(ad.userId)].api.release_assets(orderId=order.id)
|
|
1121
|
+
await sleep(1)
|
|
1122
|
+
...
|
|
1123
|
+
except Exception as e:
|
|
1124
|
+
logging.exception(e)
|
|
1125
|
+
await sleep(90)
|
|
1126
|
+
except HttpProcessingError as e:
|
|
1127
|
+
logging.error(e)
|
|
1128
|
+
print(end=".", flush=True)
|
|
1129
|
+
i += 1
|
|
1130
|
+
await sleep(5)
|
|
1131
|
+
|
|
1132
|
+
async def boost_acc(self):
|
|
1133
|
+
await sleep(45)
|
|
1134
|
+
for i in range(10):
|
|
1135
|
+
am = 500 + i
|
|
1136
|
+
req = TakeAdReq(ad_id="1856989782009487360", amount=am, pm_id=366)
|
|
1137
|
+
ord_resp: OrderResp = await self.take_ad(req)
|
|
1138
|
+
order: OrderFull = OrderFull(**self.api.get_order_details(orderId=ord_resp.orderId)["result"])
|
|
1139
|
+
odb = await self.create_order(order)
|
|
1140
|
+
t = await models.Transfer(order=odb, amount=odb.amount, updated_at=now())
|
|
1141
|
+
await t.fetch_related("order__cred__pmcur__cur")
|
|
1142
|
+
await self.pm_clients[366].send(t)
|
|
1143
|
+
...
|
|
1186
1144
|
|
|
1187
1145
|
|
|
1188
1146
|
def ms2utc(msk_ts_str: str):
|
|
1189
1147
|
return datetime.fromtimestamp(int(msk_ts_str) / 1000, timezone(timedelta(hours=3), name="MSK"))
|
|
1190
1148
|
|
|
1191
1149
|
|
|
1192
|
-
def get_sim(s1, s2) -> int:
|
|
1193
|
-
sim = int((SequenceMatcher(None, s1, s2).ratio() - 0.6) * 10_000)
|
|
1194
|
-
return sim if sim > 0 else 0
|
|
1195
|
-
|
|
1196
|
-
|
|
1197
1150
|
def detailed_diff(str1, str2):
|
|
1198
1151
|
matcher = SequenceMatcher(None, str1, str2)
|
|
1199
1152
|
result = []
|
|
@@ -1211,14 +1164,6 @@ def detailed_diff(str1, str2):
|
|
|
1211
1164
|
return "".join(result)
|
|
1212
1165
|
|
|
1213
1166
|
|
|
1214
|
-
def clean(s) -> str:
|
|
1215
|
-
clear = r"[^\w\s.,!?;:()\-]"
|
|
1216
|
-
repeat = r"(.)\1{2,}"
|
|
1217
|
-
s = re.sub(clear, "", s).lower()
|
|
1218
|
-
s = re.sub(repeat, r"\1", s)
|
|
1219
|
-
return s.replace("\n\n", "\n").replace(" ", " ").strip(" \n/.,!?-")
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
1167
|
def step_is_need(mad, cad) -> bool:
|
|
1223
1168
|
# todo: пока не решен непонятный кейс, почему то конкурент по всем параметрам слабже, но в списке ранжируется выше.
|
|
1224
1169
|
# текущая версия: recentExecuteRate округляется до целого, но на бэке байбита его дробная часть больше
|
|
@@ -1243,37 +1188,75 @@ class ExcCode(IntEnum):
|
|
|
1243
1188
|
Timestamp = 10002
|
|
1244
1189
|
IP = 10010
|
|
1245
1190
|
Quantity = 912300019
|
|
1191
|
+
PayMethod = 912300013
|
|
1246
1192
|
Unknown = 912300014
|
|
1247
1193
|
|
|
1248
1194
|
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1195
|
+
@post_save(models.Race)
|
|
1196
|
+
async def race_upserted(
|
|
1197
|
+
_cls: type[models.Race], race: models.Race, created: bool, _db: BaseDBAsyncClient, _updated: list[str]
|
|
1198
|
+
):
|
|
1199
|
+
logging.warning(f"Race {race.id} is now upserted")
|
|
1200
|
+
asyncio.all_tasks()
|
|
1201
|
+
if created:
|
|
1202
|
+
...
|
|
1203
|
+
else: # параметры гонки изменены
|
|
1204
|
+
...
|
|
1252
1205
|
|
|
1253
|
-
@post_save(models.Race)
|
|
1254
|
-
async def race_upserted(
|
|
1255
|
-
_cls: type[models.Race], race: models.Race, created: bool, _db: BaseDBAsyncClient, _updated: list[str]
|
|
1256
|
-
):
|
|
1257
|
-
logging.warning(f"Race {race.id} is now upserted")
|
|
1258
|
-
asyncio.all_tasks()
|
|
1259
|
-
if created:
|
|
1260
|
-
...
|
|
1261
|
-
else: # параметры гонки изменены
|
|
1262
|
-
...
|
|
1263
1206
|
|
|
1264
|
-
|
|
1265
|
-
|
|
1207
|
+
async def main():
|
|
1208
|
+
logging.basicConfig(level=logging.INFO)
|
|
1209
|
+
cn = await init_db(TORM)
|
|
1210
|
+
|
|
1211
|
+
agent = (
|
|
1212
|
+
await models.Agent.filter(actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, id=8)
|
|
1213
|
+
.prefetch_related(
|
|
1214
|
+
"actor__ex",
|
|
1215
|
+
"actor__person__user__gmail",
|
|
1216
|
+
"actor__my_ads__my_ad__race",
|
|
1217
|
+
"actor__my_ads__pair_side__pair__cur",
|
|
1218
|
+
"actor__my_ads__pms",
|
|
1219
|
+
)
|
|
1220
|
+
.first()
|
|
1266
1221
|
)
|
|
1267
1222
|
filebot = FileClient(NET_TOKEN)
|
|
1268
|
-
await filebot.start()
|
|
1223
|
+
# await filebot.start()
|
|
1269
1224
|
# b.add_handler(MessageHandler(cond_start_handler, command("cond")))
|
|
1270
|
-
|
|
1225
|
+
ex = await models.Ex.get(name="Bybit")
|
|
1226
|
+
ecl: ExClient = ex.client(filebot)
|
|
1227
|
+
abot = XyncBot(PAY_TOKEN, cn)
|
|
1228
|
+
cl: AgentClient = agent.client(ecl, filebot, abot)
|
|
1229
|
+
|
|
1230
|
+
# req = TakeAdReq(ad_id=1955696985964089344, amount=504, pm_id=128)
|
|
1231
|
+
# await cl.take_ad(req)
|
|
1232
|
+
|
|
1233
|
+
# await cl.actual_cond()
|
|
1234
|
+
# cl.get_api_orders(), # 10, 1738357200000, 1742504399999
|
|
1271
1235
|
|
|
1272
1236
|
# await cl.ex_client.set_pairs()
|
|
1273
1237
|
# await cl.ex_client.set_pms()
|
|
1238
|
+
|
|
1274
1239
|
# await cl.set_creds()
|
|
1275
1240
|
# await cl.export_my_ads()
|
|
1276
1241
|
|
|
1242
|
+
ms = await models.Agent.filter(
|
|
1243
|
+
actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, actor__person__user__id__in=[2]
|
|
1244
|
+
).prefetch_related(
|
|
1245
|
+
"actor__ex",
|
|
1246
|
+
"actor__person__user__gmail",
|
|
1247
|
+
"actor__my_ads__my_ad__race",
|
|
1248
|
+
"actor__my_ads__pair_side__pair__cur",
|
|
1249
|
+
"actor__my_ads__pms",
|
|
1250
|
+
)
|
|
1251
|
+
mcs = {m.actor.exid: m.client(ecl, filebot, abot) for m in ms}
|
|
1252
|
+
|
|
1253
|
+
await gather(
|
|
1254
|
+
create_task(cl.start(True)),
|
|
1255
|
+
create_task(cl.watch_payeer(mcs)),
|
|
1256
|
+
)
|
|
1257
|
+
# ensure_future(cl.start(True))
|
|
1258
|
+
# await cl.boost_acc()
|
|
1259
|
+
|
|
1277
1260
|
# создание гонок по мои активным объявам:
|
|
1278
1261
|
# for ma in cl.my_ads():
|
|
1279
1262
|
# my_ad = await models.MyAd.get(ad__exid=ma.id).prefetch_related('ad__pms', 'ad__pair_side__pair')
|
|
@@ -1286,28 +1269,6 @@ async def main():
|
|
|
1286
1269
|
# s, _ = await models.Synonym.update_or_create(typ=SynonymType.name, txt=name)
|
|
1287
1270
|
# await s.curs.add(rub.cur)
|
|
1288
1271
|
|
|
1289
|
-
# пока порешали рейс-кондишн, очищаем сиротские условия при каждом запуске
|
|
1290
|
-
# [await c.delete() for c in await Cond.filter(ads__isnull=True)]
|
|
1291
|
-
cl.all_conds = {
|
|
1292
|
-
c.id: (c.raw_txt, {a.maker.exid for a in c.ads}) for c in await Cond.all().prefetch_related("ads__maker")
|
|
1293
|
-
}
|
|
1294
|
-
for curr, old in await CondSim.filter().values_list("cond_id", "cond_rel_id"):
|
|
1295
|
-
cl.cond_sims[curr] = old
|
|
1296
|
-
cl.rcond_sims[old] |= {curr}
|
|
1297
|
-
|
|
1298
|
-
cl.build_tree()
|
|
1299
|
-
a = set()
|
|
1300
|
-
|
|
1301
|
-
def check_tree(tre):
|
|
1302
|
-
for p, c in tre.items():
|
|
1303
|
-
a.add(p)
|
|
1304
|
-
check_tree(c)
|
|
1305
|
-
|
|
1306
|
-
for pr, ch in cl.tree.items():
|
|
1307
|
-
check_tree(ch)
|
|
1308
|
-
if ct := set(cl.tree.keys()) & a:
|
|
1309
|
-
logging.exception(f"cycle cids: {ct}")
|
|
1310
|
-
|
|
1311
1272
|
pauth = (await models.PmAgent[1]).auth
|
|
1312
1273
|
papi = PayeerAPI(pauth["email"], pauth["api_id"], pauth["api_sec"])
|
|
1313
1274
|
hist: dict = papi.history(count=1000)
|
|
@@ -1320,32 +1281,6 @@ async def main():
|
|
|
1320
1281
|
# )
|
|
1321
1282
|
# await cl.get_api_orders() # 43, 1741294800000, 1749157199999)
|
|
1322
1283
|
|
|
1323
|
-
races = await models.Race.filter(started=True).prefetch_related(
|
|
1324
|
-
"road__ad__pair_side__pair__cur",
|
|
1325
|
-
"road__ad__pms",
|
|
1326
|
-
)
|
|
1327
|
-
tasks = [asyncio.create_task(cl.racing(race), name=f"Rc{race.id}") for race in races]
|
|
1328
|
-
# await cl.actual_cond()
|
|
1329
|
-
try:
|
|
1330
|
-
await gather(
|
|
1331
|
-
*tasks
|
|
1332
|
-
# cl.get_api_orders(), # 10, 1738357200000, 1742504399999
|
|
1333
|
-
)
|
|
1334
|
-
except Exception as e:
|
|
1335
|
-
await filebot.send("🤬Bybit agent CRASHED!!!🤬", actor.person.user.username_id)
|
|
1336
|
-
await filebot.send(e.__repr__(), actor.person.user.username_id)
|
|
1337
|
-
raise e
|
|
1338
|
-
# bor = BaseOrderReq(
|
|
1339
|
-
# ad_id="1861440060199632896",
|
|
1340
|
-
# # asset_amount=40,
|
|
1341
|
-
# fiat_amount=3000,
|
|
1342
|
-
# amount_is_fiat=True,
|
|
1343
|
-
# is_sell=False,
|
|
1344
|
-
# cur_exid=rub.exid,
|
|
1345
|
-
# coin_exid=usdt.exid,
|
|
1346
|
-
# coin_scale=usdt.coin.scale,
|
|
1347
|
-
# )
|
|
1348
|
-
# res: OrderResp = await cl.order_request(bor)
|
|
1349
1284
|
# await cl.cancel_order(res.orderId)
|
|
1350
1285
|
await filebot.stop()
|
|
1351
1286
|
await cl.close()
|