xync-client 0.0.57.dev10__tar.gz → 0.0.57.dev12__tar.gz

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.
Files changed (112) hide show
  1. {xync_client-0.0.57.dev10/xync_client.egg-info → xync_client-0.0.57.dev12}/PKG-INFO +1 -1
  2. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/Agent.py +3 -2
  3. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/Ex.py +13 -9
  4. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/agent.py +151 -178
  5. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/etype/order.py +4 -4
  6. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/etype/ad.py +1 -1
  7. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/ex.py +7 -7
  8. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12/xync_client.egg-info}/PKG-INFO +1 -1
  9. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/.env.sample +0 -0
  10. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/.gitignore +0 -0
  11. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/.pre-commit-config.yaml +0 -0
  12. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/README.md +0 -0
  13. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/makefile +0 -0
  14. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/pyproject.toml +0 -0
  15. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/setup.cfg +0 -0
  16. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/TestAgent.py +0 -0
  17. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/TestAsset.py +0 -0
  18. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/TestEx.py +0 -0
  19. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/TestOrder.py +0 -0
  20. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Binance/test_binance.py +0 -0
  21. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  22. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  23. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Gate/test_gate.py +0 -0
  24. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
  25. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  26. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  27. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/__init__.py +0 -0
  28. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/tests/_todo_refact/_test_ex.py +0 -0
  29. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/Asset.py +0 -0
  30. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/Auth.py +0 -0
  31. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/BaseTest.py +0 -0
  32. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/InAgent.py +0 -0
  33. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/Order.py +0 -0
  34. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Abc/xtype.py +0 -0
  35. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/__init__.py +0 -0
  36. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/binance_async.py +0 -0
  37. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/earn_api.py +0 -0
  38. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/etype/ad.py +0 -0
  39. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/etype/pm.py +0 -0
  40. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/ex.py +0 -0
  41. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/exceptions.py +0 -0
  42. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/sapi.py +0 -0
  43. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Binance/web_c2c.py +0 -0
  44. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/__init__.py +0 -0
  45. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/agent.py +0 -0
  46. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/base.py +0 -0
  47. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/etype/ad.py +0 -0
  48. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/etype/pm.py +0 -0
  49. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/ex.py +0 -0
  50. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/req.mjs +0 -0
  51. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BingX/sign.js +0 -0
  52. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BitGet/__init__.py +0 -0
  53. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BitGet/agent.py +0 -0
  54. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BitGet/etype/ad.py +0 -0
  55. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BitGet/ex.py +0 -0
  56. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/BitPapa/ex.py +0 -0
  57. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/InAgent.py +0 -0
  58. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/etype/ad.py +0 -0
  59. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/etype/cred.py +0 -0
  60. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/ex.py +0 -0
  61. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/order.py +0 -0
  62. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/web_earn.py +0 -0
  63. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/web_p2p.py +0 -0
  64. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Bybit/ws.py +0 -0
  65. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Gate/etype/ad.py +0 -0
  66. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Gate/ex.py +0 -0
  67. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Gate/premarket.py +0 -0
  68. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Gmail/__init__.py +0 -0
  69. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/agent.py +0 -0
  70. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/earn.py +0 -0
  71. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/etype/__init__.py +0 -0
  72. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/etype/cred.py +0 -0
  73. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/etype/pm.py +0 -0
  74. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Htx/etype/test.py +0 -0
  75. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/KuCoin/etype/ad.py +0 -0
  76. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/KuCoin/etype/pm.py +0 -0
  77. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/KuCoin/ex.py +0 -0
  78. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/KuCoin/web.py +0 -0
  79. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Mexc/etype/ad.py +0 -0
  80. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Mexc/etype/pm.py +0 -0
  81. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Mexc/ex.py +0 -0
  82. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Okx/etype/ad.py +0 -0
  83. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Okx/etype/pm.py +0 -0
  84. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Okx/ex.py +0 -0
  85. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/.gitignore +0 -0
  86. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Alfa/__init__.py +0 -0
  87. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Alfa/state.json +0 -0
  88. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Ozon/__init__.py +0 -0
  89. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Sber/__init__.py +0 -0
  90. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Tinkoff/__init__.py +0 -0
  91. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Tinkoff/state.json +0 -0
  92. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Volet/__init__.py +0 -0
  93. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
  94. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
  95. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Volet/api.py +0 -0
  96. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/Pms/Volet/pl.py +0 -0
  97. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/agent.py +0 -0
  98. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/asset.py +0 -0
  99. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/auth.py +0 -0
  100. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/ex.py +0 -0
  101. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/inAgent.py +0 -0
  102. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/order.py +0 -0
  103. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/pyd.py +0 -0
  104. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/pyro.py +0 -0
  105. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/TgWallet/web.py +0 -0
  106. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/__init__.py +0 -0
  107. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/loader.py +0 -0
  108. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client/pm_unifier.py +0 -0
  109. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client.egg-info/SOURCES.txt +0 -0
  110. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client.egg-info/dependency_links.txt +0 -0
  111. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client.egg-info/requires.txt +0 -0
  112. {xync_client-0.0.57.dev10 → xync_client-0.0.57.dev12}/xync_client.egg-info/top_level.txt +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.57.dev10
3
+ Version: 0.0.57.dev12
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client
@@ -1,6 +1,7 @@
1
1
  from abc import abstractmethod
2
2
 
3
3
  from pydantic import BaseModel
4
+ from pyro_client.client.file import FileClient
4
5
  from x_client.aiohttp import Client as HttpClient
5
6
  from xync_schema import models
6
7
  from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Actor
@@ -11,10 +12,10 @@ from xync_client.Abc.xtype import CredExOut, BaseOrderReq, BaseAdUpdate
11
12
 
12
13
 
13
14
  class BaseAgentClient(HttpClient):
14
- def __init__(self, actor: Actor, headers: dict[str, str] = None, cookies: dict[str, str] = None):
15
+ def __init__(self, actor: Actor, bot: FileClient, headers: dict[str, str] = None, cookies: dict[str, str] = None):
15
16
  self.actor: Actor = actor
16
17
  super().__init__(actor.ex.host_p2p, headers, cookies)
17
- self.ex_client: BaseExClient = self.actor.ex.client(actor)
18
+ self.ex_client: BaseExClient = self.actor.ex.client(bot, actor)
18
19
 
19
20
  # 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
20
21
  @abstractmethod
@@ -234,15 +234,7 @@ class BaseExClient(HttpClient):
234
234
  if not url.startswith("/"):
235
235
  url = "/" + url
236
236
  url = "https://" + self.logo_pre_url + url
237
- if not (file := await models.File.get_or_none(name=url)):
238
- resp = await ss.get(url)
239
- if resp.ok:
240
- byts = await resp.read()
241
- upf, ref = await self.bot.save_doc(byts, resp.content_type)
242
- await sleep(0.34)
243
- typ = FileType[resp.content_type.split("/")[-1]]
244
- file, _ = await models.File.update_or_create({"ref": ref, "size": len(byts), "typ": typ}, name=url)
245
- # fr = await pbot.get_file(file.ref) # check
237
+ return await self.file_upsert(url, ss)
246
238
  return file
247
239
 
248
240
  # Импорт монет (с Coinex-ами) с биржи в бд
@@ -287,6 +279,18 @@ class BaseExClient(HttpClient):
287
279
  await ad_db.pmexs.add(*getattr(ad_pydin, "pmexs_", []))
288
280
  return ad_db
289
281
 
282
+ async def file_upsert(self, url: str, ss: ClientSession = None) -> models.File:
283
+ if not (file := await models.File.get_or_none(name__startswith=url.split("?")[0])):
284
+ ss = ss or self.session
285
+ if (resp := await ss.get(url)).ok:
286
+ byts = await resp.read()
287
+ upf, ref = await self.bot.save_doc(byts, resp.content_type)
288
+ await sleep(0.3)
289
+ typ = FileType[resp.content_type.split("/")[-1]]
290
+ file, _ = await models.File.update_or_create({"ref": ref, "size": len(byts), "typ": typ}, name=url)
291
+ # fr = await pbot.get_file(file.ref) # check
292
+ return file
293
+
290
294
  # async def _proc(self, resp: ClientResponse, data_key: str = None, body: dict | str = None) -> dict | str:
291
295
  # if resp.status in (401, 403):
292
296
  # # proxy = await models.Proxy.filter(valid=True, country__short__not="US").order_by("-updated_at").first()
@@ -11,13 +11,14 @@ import pyotp
11
11
  from asyncpg import ConnectionDoesNotExistError
12
12
  from bybit_p2p import P2P
13
13
  from bybit_p2p._exceptions import FailedRequestError
14
+ from pyro_client.client.file import FileClient
14
15
  from tortoise.expressions import F, Q
15
16
  from urllib3.exceptions import ReadTimeoutError
16
17
  from x_model import init_db
17
18
  from xync_schema import models
18
19
  from xync_schema.enums import OrderStatus
19
20
 
20
- from xync_schema.models import Cur, Actor, Cond, Direction, CondSim, Person
21
+ from xync_schema.models import Cur, Actor, Cond, Direction, CondSim, Person, Pmcur
21
22
 
22
23
  from xync_client.Abc.Agent import BaseAgentClient
23
24
  from xync_client.Abc.xtype import BaseOrderReq, FlatDict
@@ -33,7 +34,7 @@ from xync_client.Bybit.etype.order import (
33
34
  Message,
34
35
  Statuses,
35
36
  )
36
- from xync_client.loader import TORM
37
+ from xync_client.loader import TORM, TOKEN
37
38
 
38
39
 
39
40
  class NoMakerException(Exception):
@@ -81,8 +82,8 @@ class AgentClient(BaseAgentClient): # Bybit client
81
82
  cond_sims: dict[int, tuple[int, int]] = {}
82
83
  sim_conds: dict[int, set[int]] = defaultdict(set) # backward
83
84
 
84
- def __init__(self, actor: Actor, **kwargs):
85
- super().__init__(actor, **kwargs)
85
+ def __init__(self, actor: Actor, bot: FileClient, **kwargs):
86
+ super().__init__(actor, bot, **kwargs)
86
87
  self.api = P2P(testnet=False, api_key=actor.agent.auth["key"], api_secret=actor.agent.auth["sec"])
87
88
 
88
89
  """ Private METHs"""
@@ -381,56 +382,93 @@ class AgentClient(BaseAgentClient): # Bybit client
381
382
  },
382
383
  )
383
384
 
384
- async def get_api_orders(self, begin_time: int, end_time: int, status: int, side: int, token_id: str):
385
- lst = self.api.get_orders(
386
- page=1,
387
- size=1000,
388
- # status=status, # 50 - завершено
389
- # tokenId=token_id,
390
- # beginTime=begin_time,
391
- # endTime=end_time,
392
- # side=side, # 1 - продажа, 0 - покупка
393
- )
394
- ords = {o["id"]: OrderItem.model_validate(o) for o in lst}
385
+ async def get_api_orders(
386
+ self,
387
+ page: int = 1,
388
+ begin_time: int = None,
389
+ end_time: int = None,
390
+ status: int = None,
391
+ side: int = None,
392
+ token_id: str = None,
393
+ ):
394
+ try:
395
+ lst = self.api.get_orders(
396
+ page=page,
397
+ size=30,
398
+ # status=status, # 50 - завершено
399
+ # tokenId=token_id,
400
+ # beginTime=begin_time,
401
+ # endTime=end_time,
402
+ # side=side, # 1 - продажа, 0 - покупка
403
+ )
404
+ except FailedRequestError as e:
405
+ if e.status_code == 10000:
406
+ await sleep(1, await self.get_api_orders(page, begin_time, end_time, status, side, token_id))
407
+ ords = {int(o["id"]): OrderItem.model_validate(o) for o in lst["result"]["items"]}
395
408
  for oid, o in ords.items():
396
- order = OrderFull.model_validate(self.api.get_order_details(orderId=oid))
397
- ad = Ad(**self.api.get_ad_details(itemId=o.itemId))
398
- if not (
399
- ad_db := await models.Ad.get_or_none(
400
- exid=o.itemId, direction__pairex__ex=self.ex_client.ex
401
- ).prefetch_related("pmex")
402
- ):
403
- dr = await Direction.get(
404
- sell=o["side"],
405
- pairex__ex=self.ex_client.ex,
406
- pairex__pair__coin__ticker=o["tokenId"],
407
- pairex__pair__cur__ticker=o["currencyId"],
408
- )
409
- ad_db, cond_isnew = await self.cond_upsert(ad, order["targetUserName"], dr) # todo: fix realname
410
-
411
- models.CredEx.update_or_create({}, exid=order.confirmedPayTerm.paymentType, ex=self.ex_client.ex)
412
- models.Order.update_or_create(
409
+ fo = self.api.get_order_details(orderId=oid)
410
+ order = OrderFull.model_validate(fo["result"])
411
+ ad = Ad(**self.api.get_ad_details(itemId=order.itemId)["result"])
412
+ maker_name = o.buyerRealName, o.sellerRealName # ad.side
413
+ im_maker = order.makerUserId == o.userId
414
+ taker_id = (o.userId, o.targetUserId)[int(im_maker)]
415
+ taker_nick = (self.actor.name, o.targetNickName)[int(im_maker)]
416
+ ad_db, cond_isnew = await self.cond_upsert(ad, maker_name[ad.side], force=True)
417
+ if not ad_db:
418
+ ...
419
+ if (cred := order.confirmedPayTerm).paymentType:
420
+ if not (credex := await models.CredEx.get_or_none(exid=cred.id, ex=self.ex_client.ex)):
421
+ pmcur = await Pmcur.get(pm__pmexs__exid=cred.paymentType, cur__ticker=ad.currencyId)
422
+ if not (
423
+ crd := await models.Cred.get_or_none(
424
+ pmcur=pmcur, person=ad_db.maker.person, detail=cred.accountNo
425
+ )
426
+ ):
427
+ extr = cred.bankName or cred.branchName or cred.qrcode or cred.payMessage or cred.paymentExt1
428
+ crd = await models.Cred.create(
429
+ detail=cred.accountNo,
430
+ pmcur=pmcur,
431
+ person=ad_db.maker.person,
432
+ name=cred.realName,
433
+ extra=extr,
434
+ )
435
+ credex = await models.CredEx.create(exid=cred.id, ex=self.ex_client.ex, cred=crd)
436
+ taker_person, _ = await Person.get_or_create(name=maker_name[::-1][ad.side])
437
+ taker, _ = await Actor.get_or_create(
438
+ {"name": taker_nick}, person=taker_person, ex=self.ex_client.ex, exid=taker_id
439
+ )
440
+ order_db, _ = await models.Order.update_or_create(
413
441
  {
414
442
  "amount": o.amount,
415
443
  "status": OrderStatus[Statuses(o.status).name],
416
- "created_at": o.createDate,
417
- "payed_at": order.transferDate,
418
- "confirmed_at": order.updateDate, # todo: check
419
- "cred": order.confirmedPayTerm,
420
- # "taker": order.updateDate,
444
+ "created_at": int(o.createDate[:-3]),
445
+ "payed_at": order.transferDate != "0" and int(order.transferDate[:-3]),
446
+ "confirmed_at": Statuses(o.status) == Statuses.completed and int(order.updateDate[:-3]),
447
+ "appealed_at": o.status == 30 and int(order.updateDate[:-3]),
448
+ "cred_id": cred.paymentType and credex.cred_id or None,
449
+ "taker": taker,
421
450
  },
422
451
  exid=o.id,
423
452
  ad=ad_db,
424
453
  )
425
- msgs = [Message.model_validate(m) for m in self.api.get_chat_messages(orderId=oid, size=200)]
426
- [
454
+ dmsgs = self.api.get_chat_messages(orderId=oid, size=200)["result"]["result"][::-1]
455
+ if ad.remark != dmsgs.pop(0)["message"]:
456
+ logging.exception(ad.remark)
457
+ msgs = [Message.model_validate(m) for m in dmsgs if m["msgType"] in (1, 2, 7, 8)]
458
+ msgs_db = [
427
459
  models.Msg(
460
+ order=order_db,
428
461
  read=m.isRead,
429
- txt=m.message,
462
+ to_maker=m.userId != order.makerUserId,
463
+ **({"txt": m.message} if m.msgType == 1 else {"file": await self.ex_client.file_upsert(m.message)}),
464
+ sent_at=int(m.createDate[:-3]),
430
465
  )
431
466
  for m in msgs
432
467
  ]
433
- models.Msg.bulk_create([models.Msg])
468
+ _ = await models.Msg.bulk_create(msgs_db, ignore_conflicts=True)
469
+ logging.info(f"orders page#{page} imported ok!")
470
+ if len(ords) == 30:
471
+ await self.get_api_orders(page + 1, begin_time, end_time, status, side, token_id)
434
472
 
435
473
  async def mad_upd(self, mad: Ad, attrs: dict, cxids: list[str]):
436
474
  if not [setattr(mad, k, v) for k, v in attrs.items() if getattr(mad, k) != v]:
@@ -592,10 +630,6 @@ class AgentClient(BaseAgentClient): # Bybit client
592
630
  pairex__pair__cur_id=curex.cur_id,
593
631
  sell=is_sell,
594
632
  )
595
- self.all_conds = {
596
- c.id: (c.raw_txt, {str(a.maker.exid) for a in c.ads})
597
- for c in await Cond.all().prefetch_related("ads__maker")
598
- }
599
633
  while self.actor.person.user.status > 0: # todo: depends on rest asset/fiat
600
634
  ads: list[Ad] = await self.ads(coinex, curex, is_sell, pms and list(creds.keys()))
601
635
 
@@ -632,13 +666,17 @@ class AgentClient(BaseAgentClient): # Bybit client
632
666
  logging.warning("Connection failed. Restarting..")
633
667
  await sleep(6)
634
668
 
635
- async def cond_upsert(self, ad: Ad, rname: str = None, dr: Direction = None) -> tuple[models.Ad, bool]:
636
- sim = None
669
+ async def cond_upsert(
670
+ self, ad: Ad, rname: str = None, dr: Direction = None, force: bool = False
671
+ ) -> tuple[models.Ad, bool]:
672
+ sim, cid = None, None
637
673
  # если точно такое условие уже есть в бд, ниче делать не надо
638
- if not (cleaned := clean(ad.remark)) or cleaned in {oc[0] for oc in self.all_conds.values()}:
674
+ if not (cleaned := clean(ad.remark)) or (cid := {oc[0]: ci for ci, oc in self.all_conds.items()}.get(cleaned)):
675
+ if force:
676
+ return await models.Ad.get_or_none(exid=ad.id) or await self.ad_create(ad, cid, rname, dr), False
639
677
  return None, False
640
678
  # если эта объява уже есть в бд
641
- if ad_db := await models.Ad.get_or_none(exid=ad.id).prefetch_related("cond__ads__maker", "maker"):
679
+ if ad_db := await models.Ad.get_or_none(exid=ad.id).prefetch_related("cond__ads__maker", "maker__person"):
642
680
  # у измененного условия этой объявы есть другие объявы?
643
681
  if rest_ads := set(ad_db.cond.ads) - {ad_db}:
644
682
  # другие объявы этого условия принадлежат другим юзерам
@@ -652,17 +690,15 @@ class AgentClient(BaseAgentClient): # Bybit client
652
690
  return ad_db, True
653
691
  # проверка на всякий что точно нет такого условия
654
692
  if new_cond := await Cond.get_or_none(raw_txt=cleaned):
655
- logging.exception("!!!!!!!!!", rest_uids)
693
+ logging.warning(f"Условие {new_cond.id} появилось в бд из других потоков")
694
+ if rest_ads and rest_uids:
695
+ logging.exception("И оно есть объявах других юезров", rest_ads, rest_uids)
656
696
  # если других объяв со старым условием этой обявы нет, либо они все этого же юзера
657
697
  # обновляем условие (в тч во всех ЕГО объявах)
658
698
  ad_db.cond.last_ver = ad_db.cond.raw_txt
659
699
  ad_db.cond.raw_txt = cleaned
660
- if sim_db := await CondSim.get_or_none(Q(join_type="OR", cond=ad_db.cond, cond_rel=ad_db.cond)):
661
- sim_db.similarity = get_sim(cleaned, ad_db.cond.last_ver)
662
- await sim_db.save()
663
700
  self.all_conds[ad_db.cond_id] = cleaned, {ad_db.maker.exid}
664
701
  await ad_db.cond.save()
665
-
666
702
  await self.sim_upd(ad_db.cond_id, cleaned)
667
703
  return ad_db, False
668
704
 
@@ -687,34 +723,39 @@ class AgentClient(BaseAgentClient): # Bybit client
687
723
 
688
724
  new_cond = await Cond.create(raw_txt=cleaned)
689
725
  self.all_conds[new_cond.id] = new_cond.raw_txt, {ad.userId}
690
- act_df = {"name": ad.nickName}
726
+ ad_db = await self.ad_create(ad, new_cond.id)
727
+
728
+ # если нашелся похожий текст у другого юзера, добавим связь с % похожести
729
+ if sim:
730
+ await self.sim_new(new_cond.id, sim, old_cid)
731
+
732
+ await ad_db.fetch_related("cond", "maker__person")
733
+ return ad_db, True
734
+
735
+ async def ad_create(self, ad: Ad, cid: int, rname: str = None, dr: Direction = None) -> models.Ad:
736
+ act_df = {}
737
+ if int(ad.userId) != self.actor.exid:
738
+ act_df |= {"name": ad.nickName}
691
739
  if rname:
692
- act_df |= {"person": await Person.get_or_create(name=rname)}
740
+ act_df |= {"person": (await Person.get_or_create(name=rname))[0]}
693
741
  actor, _ = await Actor.update_or_create(act_df, exid=ad.userId, ex=self.ex_client.ex)
694
- ad_db = await models.Ad.create(
742
+ return await models.Ad.create(
695
743
  price=ad.price,
696
744
  amount=float(ad.quantity) * float(ad.price),
697
745
  min_fiat=ad.minAmount,
698
746
  max_fiat=ad.maxAmount,
699
- cond=new_cond,
747
+ cond_id=cid,
700
748
  exid=int(ad.id),
701
749
  direction=dr
702
750
  or await Direction.get(
703
751
  sell=ad.side,
704
752
  pairex__ex=self.ex_client.ex,
705
753
  pairex__pair__coin__ticker=ad.tokenId,
706
- pairex__pair__cur__ticker=ad.currency,
754
+ pairex__pair__cur__ticker=ad.currencyId,
707
755
  ),
708
756
  maker=actor,
709
757
  )
710
758
 
711
- # если нашелся похожий текст у другого юзера, добавим связь с % похожести
712
- if sim:
713
- await self.sim_new(new_cond.id, sim, old_cid)
714
-
715
- await ad_db.fetch_related("cond")
716
- return ad_db, True
717
-
718
759
  async def sim_new(self, new_cid: int, sim: int, old_cid: int):
719
760
  if not sim:
720
761
  return None
@@ -727,80 +768,6 @@ class AgentClient(BaseAgentClient): # Bybit client
727
768
  sim_db.similarity = get_sim(new_txt, op_cond.raw_txt)
728
769
  await sim_db.save()
729
770
 
730
- #
731
- # async def cond_upsert(
732
- # self, ad: Ad, rname: str = None, dr: Direction = None, cid: int = 0
733
- # ) -> tuple[models.Ad, bool]:
734
- # sim = None
735
- # dr = dr or await Direction.get(
736
- # sell=ad.side,
737
- # pairex__ex=self.ex_client.ex,
738
- # pairex__pair__coin__ticker=ad.tokenId,
739
- # pairex__pair__cur__ticker=ad.currencyId,
740
- # )
741
- # # если точно такого условия еще нет в бд
742
- # old_conds = self.all_conds.copy() if cid else self.all_conds
743
- # if cid: # если есть то это не текущий проверяемый cond
744
- # old_conds.pop(cid)
745
- # if (cleaned := clean(ad.remark)) and cleaned not in {oc[0] for oc in old_conds.values()}:
746
- # # находим все старые тексты похожие на 90% и более
747
- # if sim_connds := {
748
- # old_cid: (txt, sim)
749
- # for old_cid, (txt, uids) in old_conds.items()
750
- # if len(cleaned) > 15
751
- # and ad.userId not in uids
752
- # and cid not in self.sim_conds.get(old_cid, {})
753
- # and (sim := int((SequenceMatcher(None, cleaned, txt).ratio() - 0.9) * 10_000))
754
- # > self.cond_sims.get(cid, (..., 0))[1]
755
- # }:
756
- # # если есть, берем самый похожий из них
757
- # old_cid, (txt, sim) = max(sim_connds.items(), key=lambda x: x[1])
758
- # old_ads = await models.Ad.filter(cond_id=old_cid, maker__exid=int(ad.userId)).prefetch_related("cond")
759
- # for old_ad in old_ads:
760
- # # и у этого чела есть объява с почти таким же текстом
761
- # if old_ad.exid == int(ad.id): # и он изменил текст как раз в ней
762
- # # заменяем текст без создания нового cond
763
- # await old_ad.cond.update_or_create(raw_txt=cleaned)
764
- # await old_ad.fetch_related("cond")
765
- # return old_ad, False
766
- # # но это не она, значит у него есть другая объява с похожим, но чуть отличающимся текстом
767
- # logging.warning(f"ad#{ad.id}-cond#{old_cid} txt updated:\n{txt}\n|\n|\nV\n{cleaned}")
768
- # if not cid:
769
- # cond, isnew = await Cond.get_or_create(raw_txt=cleaned)
770
- # cid = cond.id
771
- # if isnew:
772
- # self.all_conds[cid] = cond.raw_txt, {ad.userId}
773
- # if sim and sim_connds: # если нашелся похожий текст у другого юзера, добавим связь с % похожести
774
- # await CondSim.update_or_create({"similarity": sim, "cond_rel_id": old_cid}, cond_id=cid)
775
- # self.cond_sims[cid] = old_cid, sim
776
- # self.sim_conds[old_cid].add(cid)
777
- # if not ad.price:
778
- # return
779
- # act_df = {"name": ad.nickName}
780
- # if rname:
781
- # act_df |= {"person": await Person.get_or_create(name=rname)}
782
- # actor, _ = await Actor.update_or_create(act_df, exid=ad.userId, ex=self.ex_client.ex)
783
- # ad_db, _ = await models.Ad.update_or_create(
784
- # {
785
- # "price": ad.price,
786
- # "amount": float(ad.quantity) * float(ad.price),
787
- # "min_fiat": ad.minAmount,
788
- # "max_fiat": ad.maxAmount,
789
- # "cond": cond,
790
- # },
791
- # exid=int(ad.id),
792
- # direction=dr
793
- # or await Direction.get(
794
- # sell=ad.side,
795
- # pairex__ex=self.ex_client.ex,
796
- # pairex__pair__coin__ticker=ad.tokenId,
797
- # pairex__pair__cur__ticker=ad.currency,
798
- # ),
799
- # maker=actor,
800
- # )
801
- # await ad_db.fetch_related("cond")
802
- # return ad_db, isnew
803
-
804
771
  async def actual_cond(self):
805
772
  self.all_conds = {
806
773
  c.id: (c.raw_txt, {str(a.maker.exid) for a in c.ads})
@@ -883,45 +850,51 @@ async def main():
883
850
  actor = (
884
851
  await models.Actor.filter(ex_id=9, agent__isnull=False).prefetch_related("ex", "agent", "person__user").first()
885
852
  )
886
- cl: AgentClient = actor.client()
887
- # await cl.ex_client.set_pmcurexs(cookies=actor.agent.auth["cookies"]) # 617 -> 639
888
- # await cl.set_creds()
889
- usdt = await models.Coinex.get(coin__ticker="USDT", ex=cl.actor.ex).prefetch_related("coin")
890
- btc = await models.Coinex.get(coin__ticker="BTC", ex=cl.actor.ex).prefetch_related("coin")
891
- eth = await models.Coinex.get(coin__ticker="ETH", ex=cl.actor.ex).prefetch_related("coin")
892
- usdc = await models.Coinex.get(coin__ticker="USDC", ex=cl.actor.ex).prefetch_related("coin")
893
- rub = await models.Curex.get(cur__ticker="RUB", ex=cl.actor.ex).prefetch_related("cur")
894
- # await models.Direction.get(
895
- # pairex__ex=cl.actor.ex, pairex__pair__coin__ticker="USDT", pairex__pair__cur__ticker="RUB", sell=True
896
- # )
897
- # await cl.set_creds()
898
- # await cl.actual_cond()
899
- await gather(
900
- cl.battle(usdt, rub, False, ["volet"], 79.97), # гонка в стакане покупки - мы продаем
901
- cl.battle(usdt, rub, True, ["volet"], 79.9), # гонка в стакане продажи - мы покупаем
902
- cl.battle(eth, rub, False, ["volet"], 206_000),
903
- cl.battle(eth, rub, True, ["volet"], 200_000),
904
- cl.battle(btc, rub, False, ["volet"], 8_500_000),
905
- cl.battle(btc, rub, True, ["volet"], 8_400_000),
906
- cl.battle(usdc, rub, False, ["volet"], 80.5),
907
- cl.battle(usdc, rub, True, ["volet"], 79),
908
- cl.take(usdt, rub, False, ceil=80.5, volume=360),
909
- cl.take(usdt, rub, True, ceil=80.5, volume=360),
910
- )
853
+ async with FileClient(TOKEN) as b:
854
+ cl: AgentClient = actor.client(b)
855
+ # await cl.ex_client.set_pmcurexs(cookies=actor.agent.auth["cookies"]) # 617 -> 639
856
+ # await cl.set_creds()
857
+ usdt = await models.Coinex.get(coin__ticker="USDT", ex=cl.actor.ex).prefetch_related("coin")
858
+ btc = await models.Coinex.get(coin__ticker="BTC", ex=cl.actor.ex).prefetch_related("coin")
859
+ eth = await models.Coinex.get(coin__ticker="ETH", ex=cl.actor.ex).prefetch_related("coin")
860
+ usdc = await models.Coinex.get(coin__ticker="USDC", ex=cl.actor.ex).prefetch_related("coin")
861
+ rub = await models.Curex.get(cur__ticker="RUB", ex=cl.actor.ex).prefetch_related("cur")
862
+ # await models.Direction.get(
863
+ # pairex__ex=cl.actor.ex, pairex__pair__coin__ticker="USDT", pairex__pair__cur__ticker="RUB", sell=True
864
+ # )
865
+ cl.all_conds = {
866
+ c.id: (c.raw_txt, {str(a.maker.exid) for a in c.ads})
867
+ for c in await Cond.all().prefetch_related("ads__maker")
868
+ }
869
+ # await cl.set_creds()
870
+ await cl.get_api_orders(2)
871
+ # await cl.actual_cond()
872
+ await gather(
873
+ cl.battle(usdt, rub, False, ["volet"], 79.97), # гонка в стакане покупки - мы продаем
874
+ cl.battle(usdt, rub, True, ["volet"], 79.9), # гонка в стакане продажи - мы покупаем
875
+ cl.battle(eth, rub, False, ["volet"], 206_000),
876
+ cl.battle(eth, rub, True, ["volet"], 200_000),
877
+ cl.battle(btc, rub, False, ["volet"], 8_500_000),
878
+ cl.battle(btc, rub, True, ["volet"], 8_400_000),
879
+ cl.battle(usdc, rub, False, ["volet"], 80.5),
880
+ cl.battle(usdc, rub, True, ["volet"], 79),
881
+ cl.take(usdt, rub, False, ceil=80.5, volume=360),
882
+ cl.take(usdt, rub, True, ceil=80.5, volume=360),
883
+ )
911
884
 
912
- bor = BaseOrderReq(
913
- ad_id="1861440060199632896",
914
- # asset_amount=40,
915
- fiat_amount=3000,
916
- amount_is_fiat=True,
917
- is_sell=False,
918
- cur_exid=rub.exid,
919
- coin_exid=usdt.exid,
920
- coin_scale=usdt.coin.scale,
921
- )
922
- res: OrderResp = await cl.order_request(bor)
923
- await cl.cancel_order(res.orderId)
924
- await cl.close()
885
+ bor = BaseOrderReq(
886
+ ad_id="1861440060199632896",
887
+ # asset_amount=40,
888
+ fiat_amount=3000,
889
+ amount_is_fiat=True,
890
+ is_sell=False,
891
+ cur_exid=rub.exid,
892
+ coin_exid=usdt.exid,
893
+ coin_scale=usdt.coin.scale,
894
+ )
895
+ res: OrderResp = await cl.order_request(bor)
896
+ await cl.cancel_order(res.orderId)
897
+ await cl.close()
925
898
 
926
899
 
927
900
  if __name__ == "__main__":
@@ -105,7 +105,7 @@ class PaymentConfigVo(BaseModel):
105
105
  addTips: str
106
106
  itemTips: str
107
107
  online: int
108
- items: list[str]
108
+ items: list[dict[str, str | bool]]
109
109
 
110
110
 
111
111
  class PaymentTerm(BaseModel):
@@ -236,7 +236,7 @@ class OrderFull(OrderItem):
236
236
  needSellerExamineCancel: bool
237
237
  couponCurrencyAmount: str
238
238
  totalCurrencyAmount: str
239
- usedCoupon: Literal[1, 2] # bool: 1: used, 2: no used
239
+ usedCoupon: bool # bool: 1: used, 2: no used
240
240
  couponTokenId: str
241
241
  couponQuantity: str
242
242
  completedOrderAppealCount: int
@@ -262,12 +262,12 @@ class Message(BaseModel):
262
262
  msgCode: int
263
263
  createDate: str
264
264
  isRead: Literal[0, 1] # int: 1: read, 0: unread
265
- contentType: Literal["text", "pic", "pdf", "video"]
265
+ contentType: Literal["str", "pic", "pdf", "video"]
266
266
  roleType: str
267
267
  userId: str
268
268
  orderId: str
269
269
  msgUuid: str
270
270
  nickName: str
271
- read: str
271
+ read: Literal[0, 1]
272
272
  fileName: str
273
273
  onlyForCustomer: int
@@ -1,7 +1,7 @@
1
1
  from typing import Literal
2
2
 
3
3
  from pydantic import BaseModel
4
- from xync_schema.types import BaseAd
4
+ from xync_schema.xtype import BaseAd
5
5
 
6
6
 
7
7
  class TradeRule(BaseModel):
@@ -4,7 +4,7 @@ from collections import defaultdict
4
4
  from msgspec import convert
5
5
  from pyro_client.client.file import FileClient
6
6
  from x_model import init_db
7
- from xync_schema import models, types
7
+ from xync_schema import models, xtype
8
8
  from xync_schema.models import Ex, Cur
9
9
  from xync_schema.enums import PmType
10
10
 
@@ -51,7 +51,7 @@ class ExClient(BaseExClient):
51
51
 
52
52
  async def ads(
53
53
  self, coin_exid: int, cur_exid: int, is_sell: bool, pm_exids: list[str] = None, amount: int = None
54
- ) -> list[types.BaseAd]:
54
+ ) -> list[xtype.BaseAd]:
55
55
  params = {
56
56
  "coinId": coin_exid,
57
57
  "currency": cur_exid,
@@ -70,7 +70,7 @@ class ExClient(BaseExClient):
70
70
  ads = [ad.Resp(**a) for a in res]
71
71
  return ads
72
72
 
73
- async def ad(self, ad_id: int) -> types.BaseAd:
73
+ async def ad(self, ad_id: int) -> xtype.BaseAd:
74
74
  pass
75
75
 
76
76
  # 20: Get all pms
@@ -99,7 +99,7 @@ class ExClient(BaseExClient):
99
99
  return pmsd
100
100
 
101
101
  # 21: Get all: currency,pay,allCountry,coin
102
- async def curs(self) -> dict[int, types.CurEx]:
102
+ async def curs(self) -> dict[int, xtype.CurEx]:
103
103
  self.session.headers["client-type"] = "web"
104
104
  curs: list[dict] = (await self.data)["currency"]
105
105
  cmap: dict[str, int] = {c["nameShort"]: c["currencyId"] for c in curs}
@@ -108,7 +108,7 @@ class ExClient(BaseExClient):
108
108
  for c in res:
109
109
  for q in c["quoteAsset"]:
110
110
  cursd[q["name"]] = max(cursd.get(q["name"], 0), float(q["minAmount"]))
111
- return {exid: types.CurEx(exid=exid, ticker=tkr, minimum=cursd.get(tkr)) for tkr, exid in cmap.items()}
111
+ return {exid: xtype.CurEx(exid=exid, ticker=tkr, minimum=cursd.get(tkr)) for tkr, exid in cmap.items()}
112
112
 
113
113
  # 22: Список платежных методов по каждой валюте
114
114
  async def cur_pms_map(self) -> dict[int, set[int]]:
@@ -117,13 +117,13 @@ class ExClient(BaseExClient):
117
117
  return {c["currencyId"]: set(c["supportPayments"]) - wrong_pms for c in res["currency"] if c["supportPayments"]}
118
118
 
119
119
  # 23: Список торгуемых монет
120
- async def coins(self) -> dict[int, types.CoinEx]:
120
+ async def coins(self) -> dict[int, xtype.CoinEx]:
121
121
  self.session.headers["client-type"] = "web"
122
122
  coins: list[dict] = (await self.data)["coin"]
123
123
  res = (await self._get("/-/x/otc/v1/trade/fast/config/list?side=buy&tradeMode=c2c_simple"))["data"]
124
124
  coinsl: list[str] = [c["cryptoAsset"]["name"] for c in res]
125
125
  return {
126
- c["coinId"]: types.CoinEx(exid=c["coinId"], ticker=c["coinCode"], scale=c["showPrecision"])
126
+ c["coinId"]: xtype.CoinEx(exid=c["coinId"], ticker=c["coinCode"], scale=c["showPrecision"])
127
127
  for c in coins
128
128
  if c["coinCode"] in coinsl
129
129
  }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.57.dev10
3
+ Version: 0.0.57.dev12
4
4
  Author-email: Mike Artemiev <mixartemev@gmail.com>
5
5
  Project-URL: Homepage, https://gitlab.com/XyncNet/client
6
6
  Project-URL: Repository, https://gitlab.com/XyncNet/client