xync-client 0.0.235__tar.gz → 0.0.236.dev1__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 (135) hide show
  1. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/PKG-INFO +1 -1
  2. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Agent.py +73 -24
  3. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Ex.py +25 -11
  4. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/xtype.py +6 -0
  5. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/agent.py +45 -45
  6. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/etype/ad.py +11 -3
  7. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/ex.py +64 -2
  8. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/details.py +4 -0
  9. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client.egg-info/PKG-INFO +1 -1
  10. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/.env.sample +0 -0
  11. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/.gitignore +0 -0
  12. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/.pre-commit-config.yaml +0 -0
  13. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/CLAUDE.md +0 -0
  14. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/README.md +0 -0
  15. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/__init__.py +0 -0
  16. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/makefile +0 -0
  17. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/pyproject.toml +0 -0
  18. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/setup.cfg +0 -0
  19. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/TestAgent.py +0 -0
  20. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/TestAsset.py +0 -0
  21. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/TestEx.py +0 -0
  22. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/TestOrder.py +0 -0
  23. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Binance/test_binance.py +0 -0
  24. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  25. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  26. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Gate/test_gate.py +0 -0
  27. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  28. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  29. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/__init__.py +0 -0
  30. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/tests/_todo_refact/_test_ex.py +0 -0
  31. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/AdLoader.py +0 -0
  32. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Asset.py +0 -0
  33. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Auth.py +0 -0
  34. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/BaseTest.py +0 -0
  35. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Exception.py +0 -0
  36. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/HasAbotUid.py +0 -0
  37. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/InAgent.py +0 -0
  38. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/Order.py +0 -0
  39. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Abc/PmAgent.py +0 -0
  40. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/__init__.py +0 -0
  41. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/binance_async.py +0 -0
  42. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/earn_api.py +0 -0
  43. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/etype/ad.py +0 -0
  44. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/etype/pm.py +0 -0
  45. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/ex.py +0 -0
  46. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/exceptions.py +0 -0
  47. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/sapi.py +0 -0
  48. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Binance/web_c2c.py +0 -0
  49. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/__init__.py +0 -0
  50. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/agent.py +0 -0
  51. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/base.py +0 -0
  52. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/etype/ad.py +0 -0
  53. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/etype/pm.py +0 -0
  54. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/ex.py +0 -0
  55. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/req.mjs +0 -0
  56. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BingX/sign.js +0 -0
  57. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BitGet/__init__.py +0 -0
  58. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BitGet/agent.py +0 -0
  59. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BitGet/etype/ad.py +0 -0
  60. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BitGet/ex.py +0 -0
  61. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/BitPapa/ex.py +0 -0
  62. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/etype/__init__.py +0 -0
  63. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/etype/cred.py +0 -0
  64. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/etype/order.py +0 -0
  65. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/etype/pm.py +0 -0
  66. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/inAgent.py +0 -0
  67. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/order.py +0 -0
  68. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/web_earn.py +0 -0
  69. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/web_p2p.py +0 -0
  70. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Bybit/ws.py +0 -0
  71. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Gate/etype/ad.py +0 -0
  72. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Gate/ex.py +0 -0
  73. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Gate/premarket.py +0 -0
  74. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Gmail/__init__.py +0 -0
  75. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/agent.py +0 -0
  76. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/earn.py +0 -0
  77. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/__init__.py +0 -0
  78. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/ad.py +0 -0
  79. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/cred.py +0 -0
  80. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/order.py +0 -0
  81. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/pm.py +0 -0
  82. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/etype/test.py +0 -0
  83. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Htx/ex.py +0 -0
  84. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/KuCoin/etype/ad.py +0 -0
  85. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/KuCoin/etype/pm.py +0 -0
  86. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/KuCoin/ex.py +0 -0
  87. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/KuCoin/web.py +0 -0
  88. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/agent.py +0 -0
  89. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/api.py +0 -0
  90. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/etype/ad.py +0 -0
  91. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/etype/order.py +0 -0
  92. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/etype/pm.py +0 -0
  93. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Mexc/ex.py +0 -0
  94. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Okx/1.py +0 -0
  95. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Okx/agent.py +0 -0
  96. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Okx/etype/ad.py +0 -0
  97. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Okx/etype/pm.py +0 -0
  98. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Okx/ex.py +0 -0
  99. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/.gitignore +0 -0
  100. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Alfa/__init__.py +0 -0
  101. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Alfa/state.json +0 -0
  102. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/MTS/__init__.py +0 -0
  103. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Ozon/__init__.py +0 -0
  104. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Payeer/.gitignore +0 -0
  105. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Payeer/agent.py +0 -0
  106. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Payeer/login.py +0 -0
  107. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Payeer/trade.py +0 -0
  108. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Sber/__init__.py +0 -0
  109. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Sber/utils.py +0 -0
  110. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Tinkoff/__init__.py +0 -0
  111. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
  112. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
  113. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Volet/agent.py +0 -0
  114. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Volet/api.py +0 -0
  115. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Volet/pl.py +0 -0
  116. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Xync/__main__.py +0 -0
  117. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Xync/ed.py +0 -0
  118. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/Yandex/__init__.py +0 -0
  119. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/Pms/airtm/__init__.py +0 -0
  120. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/agent.py +0 -0
  121. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/asset.py +0 -0
  122. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/auth.py +0 -0
  123. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/ex.py +0 -0
  124. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/inAgent.py +0 -0
  125. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/order.py +0 -0
  126. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/pyd.py +0 -0
  127. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/pyro.py +0 -0
  128. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/TgWallet/web.py +0 -0
  129. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/__init__.py +0 -0
  130. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/loader.py +0 -0
  131. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client/pm_unifier.py +0 -0
  132. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client.egg-info/SOURCES.txt +0 -0
  133. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client.egg-info/dependency_links.txt +0 -0
  134. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/xync_client.egg-info/requires.txt +0 -0
  135. {xync_client-0.0.235 → xync_client-0.0.236.dev1}/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.235
3
+ Version: 0.0.236.dev1
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,4 +1,5 @@
1
1
  import logging
2
+ import math
2
3
  from abc import abstractmethod
3
4
  from asyncio import create_task, sleep
4
5
  from collections import defaultdict
@@ -8,7 +9,7 @@ from pydantic import BaseModel
8
9
  from tortoise.exceptions import IntegrityError
9
10
  from x_client import df_hdrs
10
11
  from x_client.aiohttp import Client as HttpClient
11
- from xync_client.details import hot_ad_cond
12
+ from xync_client.details import hot_ad_cond, more1perc
12
13
  from xync_schema.enums import AdStatus, OrderStatus
13
14
 
14
15
  from xync_client.Abc.PmAgent import PmAgentClient
@@ -60,7 +61,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
60
61
  self.pm_clients: dict[int, PmAgentClient] = defaultdict()
61
62
  super().__init__(self.actor.ex.host_p2p, headers, cookies, proxy) # and proxy.str()
62
63
  # start
63
- create_task(self.start())
64
+ # create_task(self.start())
64
65
 
65
66
  async def x2e_cred(self, cred_id: int) -> int: # cred.exid
66
67
  if not self.cred_x2e.get(cred_id):
@@ -113,7 +114,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
113
114
  await self.load_pending_orders()
114
115
  await self.ads_share()
115
116
 
116
- async def load_assets(self, coin_ids: list[int] = None) -> dict:
117
+ async def load_assets(self, coin_ids: list[int] = None):
117
118
  assets = {cid: await self.get_asset(cid) for cid in coin_ids} if coin_ids else await self.my_assets()
118
119
  for cid, amount in assets.items():
119
120
  await self.asset_save(cid, amount)
@@ -523,27 +524,62 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
523
524
  @abstractmethod
524
525
  async def _ad_upd_api(self, ad: MyAdXOut) -> int: ...
525
526
 
526
- async def ad_fresh(self, ads: list[models.Ad], is_sell: bool, bal: float, cur_min, i: int = 0) -> int:
527
+ @staticmethod
528
+ def fee(min_count):
529
+ return 7.5 * math.exp(-0.1 * min_count) + 1.1
530
+
531
+ async def ad_fresh(self, ads: list[models.Ad], is_sell: bool, bal: float, cur_min, rate: float, haq: dict) -> dict:
532
+ if not ads:
533
+ return haq
534
+
527
535
  ad = await ads.pop(0).to_float(ex_id=self.actor.ex_id)
528
- if ad.min_fiat != cur_min and ad.filtered:
529
- logging.error(ad.min_fiat) # need debug
530
- fld = ("amount", "quantity")[int(is_sell)]
531
- if getattr(ad, fld) != bal:
532
- setattr(ad, fld, bal)
533
- setattr(ad, ("amount", "quantity")[int(not is_sell)], None)
534
- xma = MyAdXOut.model_validate(ad, from_attributes=True)
536
+ if (min_count := int(ad.min_fiat / cur_min)) in {1, 10, 60}: # is_full
537
+ i = (list(haq)).index((min_count, int(ad.filtered)))
538
+ elif 5 <= min_count < 10:
539
+ i = 2
540
+ elif 23 <= min_count < 60:
541
+ i = 3
542
+ else:
543
+ logging.error(f"Wrong ad.min_fiat: {ad.exid}:{ad.min_fiat}:{ad.filtered}") # need debug
544
+ return await self.ad_fresh(ads, is_sell, bal, cur_min, rate, haq)
545
+ k, fltrd = list(haq)[i]
546
+ target_min = cur_min * k
547
+ # ad.min_fiat = min(target_min, xbal)
548
+
549
+ fld = ("amount", "quantity")[
550
+ int(is_sell)
551
+ ] # если покупка - отталкиваемся от имеющегося cur баланса, else - coin
552
+ old_bal = getattr(ad, fld)
553
+ setattr(ad, fld, bal)
554
+ setattr(ad, ("amount", "quantity")[int(not is_sell)], None) # а связанный (другой) балланс обнуляем
555
+ xma = MyAdXOut.model_validate(ad, from_attributes=True)
556
+
557
+ if k > 1 and xma.amount < target_min / 2: # хватает ли денег на размещение объявы
558
+ logging.warning(f"Less balance {bal} for {is_sell} ad:{ad.exid}:{ad.min_fiat}:{ad.filtered}")
559
+ return await self.ad_fresh(ads, is_sell, bal, cur_min, rate, haq)
560
+
561
+ xma.min_fiat = min(target_min, xma.amount)
562
+ min_count = xma.min_fiat / cur_min
563
+ pk = self.fee(min_count) if fltrd else 10
564
+ sk = 2 * int(is_sell) - 1
565
+ new_price = round(rate * 0.01 * (1 + sk * pk / 200), 2)
566
+ if xma.price != new_price or more1perc(
567
+ old_bal, bal
568
+ ): # если текущий объем валюты/монеты не совпадает с текущим балансом - обновляем
569
+ xma.price = new_price
535
570
  xma.cond_txt = hot_ad_cond
536
571
  await self._ad_upd_api(xma)
537
- if not ads:
538
- return i
539
- return await self.ad_fresh(ads, is_sell, bal, cur_min, i + 1)
572
+ haq[(k, fltrd)][int(is_sell)] += 1
573
+ else:
574
+ haq[(k, fltrd)][int(is_sell)] -= 1
575
+ return await self.ad_fresh(ads, is_sell, bal, cur_min, rate, haq)
540
576
 
541
- async def ads_fresh(self, cur_id: int = 1, coin_id: int = 1) -> int:
577
+ async def ads_fresh(self, cur_id: int = 1, coin_id: int = 1):
542
578
  """
543
579
  Обновляем/добавляем объявления агента, в зависимости от кол-ва объявлений которое он может размещать
544
580
  одновременно `same_dir_ad` (от 1 до 4), и его текущего coin_balance.
545
581
  """
546
- curex = await models.CurEx.get(cur_id=cur_id, ex_id=self.actor.ex_id)
582
+ curex = await models.CurEx.get(cur_id=cur_id, ex_id=self.actor.ex_id).prefetch_related("cur")
547
583
  usdt_bal = (await self.agent.coins_balance())[coin_id]
548
584
  xbals = await self.actor.person.user.balances()
549
585
  xbal = xbals[cur_id]
@@ -551,10 +587,14 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
551
587
  # то постим 4 объявления:
552
588
  # 1) с минимальным нижним лимитом размера ордера, и без фильтрации контрагентов
553
589
  # 2) с минимальным лимитом, но с фильтрацией контрагентов
554
- # 3) с 10x мин лимитом, и с фильтрацией (если вообще есть баланс от 10x min)
555
- # 4) 50x мин лимит, либо весь баланс если он меньше, с фильтрацией (если есть баланс от 20x min)
556
- if usdt_bal < curex.minimum:
557
- return
590
+ # 3) с 10x мин лимитом, и с фильтрацией (если вообще есть баланс хотя бы от 5x min)
591
+ # 4) 60x мин лимит, либо весь баланс если он меньше, с фильтрацией (если есть баланс от 30x min)
592
+ hot_ads_q = { # item legend: (min_multiplier, is_filtered): [buy_ad_is_posted, sell_ad_is_posted]
593
+ (1, 0): [0, 0],
594
+ (1, 1): [0, 0],
595
+ (10, 1): [0, 0],
596
+ (60, 1): [0, 0],
597
+ }
558
598
  fltr = dict(
559
599
  my_ad__credexs__cred__ovr_pm_id=0,
560
600
  my_ad__credexs__cred__pmcur__cur_id=cur_id,
@@ -563,21 +603,30 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
563
603
  )
564
604
  prftch = "my_ad__credexs", "pair_side__pair__coin", "pair_side__pair__cur"
565
605
 
606
+ if xbal < curex.minimum:
607
+ logging.error(f"Not enough xync balance: {xbal}")
608
+ return
609
+
566
610
  bads = (
567
611
  await models.Ad.filter(**fltr, status=AdStatus.active, pair_side__is_sell=False)
568
612
  .order_by("min_fiat", "filtered")
569
613
  .prefetch_related(*prftch)
570
614
  .limit(self.agent.same_dir_ad)
571
615
  )
572
- await self.ad_fresh(bads, False, xbal, curex.minimum)
616
+ await self.ad_fresh(bads, False, xbal, curex.minimum, curex.cur.rate, hot_ads_q)
617
+
618
+ if usdt_bal * curex.cur.rate * 10**-curex.cur.scale < curex.minimum:
619
+ logging.error(f"Not enough {self.ex_client.ex.name} balance: {usdt_bal}")
620
+ return
573
621
 
574
622
  sads = (
575
- await models.Ad.filter(**fltr, status=AdStatus.active, pair_side__is_sell=False)
576
- .order_by("min_fiat", "filtered")
623
+ await models.Ad.filter(**fltr, status=AdStatus.active, pair_side__is_sell=True)
624
+ .order_by("-min_fiat", "-filtered")
577
625
  .prefetch_related(*prftch)
578
626
  .limit(self.agent.same_dir_ad)
579
627
  )
580
- await self.ad_fresh(sads, True, usdt_bal, curex.minimum)
628
+ await self.ad_fresh(sads, True, usdt_bal, curex.minimum, curex.cur.rate, hot_ads_q)
629
+ return hot_ads_q
581
630
 
582
631
  # 32: Удаление
583
632
  @abstractmethod
@@ -4,7 +4,6 @@ from abc import abstractmethod
4
4
  from asyncio import sleep
5
5
  from collections import defaultdict
6
6
  from difflib import SequenceMatcher
7
- from math import floor
8
7
 
9
8
  from aiohttp import ClientSession, ClientResponse
10
9
  from msgspec import Struct
@@ -187,7 +186,6 @@ class BaseExClient(HttpClient, AdLoader):
187
186
  update=dict(
188
187
  coin_id=(await self.x2e_coin(xreq.coin_id))[0],
189
188
  cur_id=(await self.x2e_cur(xreq.cur_id))[0],
190
- is_sell=str(int(xreq.is_sell)),
191
189
  pm_ids=xreq.pm_ids and [await self.x2e_pm(pid) for pid in xreq.pm_ids],
192
190
  )
193
191
  )
@@ -471,12 +469,12 @@ class BaseExClient(HttpClient, AdLoader):
471
469
  badd = base_ad.model_dump()
472
470
  pms = await models.Pm.filter(pmexs__ex=self.ex, pmexs__exid__in=base_ad.pmex_exids)
473
471
  badd.update(
474
- amount=int((base_ad.amount or base_ad.quantity * base_ad.price) * 10**cur_scale),
475
- max_fiat=int(base_ad.max_fiat),
476
- min_fiat=int(base_ad.min_fiat),
477
- premium=int(base_ad.premium * 100_00),
478
- price=int(base_ad.price * 10**cur_scale),
479
- quantity=int((base_ad.quantity or base_ad.amount / base_ad.price) * 10**coin_scale),
472
+ amount=round((base_ad.amount or base_ad.quantity * base_ad.price) * 10**cur_scale),
473
+ max_fiat=base_ad.max_fiat,
474
+ min_fiat=base_ad.min_fiat,
475
+ premium=round(base_ad.premium * 100_00),
476
+ price=round(base_ad.price * 10**cur_scale),
477
+ quantity=round((base_ad.quantity or base_ad.amount / base_ad.price) * 10**coin_scale),
480
478
  maker_id=(await self.e2x_actor(base_ad.maker)).id,
481
479
  cond_id=cond and cond.id,
482
480
  pair_side_id=await self.e2x_pair(base_ad.coinex_exid, base_ad.curex_exid, bool(base_ad.side.value)),
@@ -721,9 +719,25 @@ class BaseExClient(HttpClient, AdLoader):
721
719
  bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
722
720
  return bc, sc
723
721
 
724
- async def rate(self, cur_id: int, coin_id: int = 1) -> int:
725
- bp, sp = await self.get_books(cur_id, coin_id)
726
- return floor((sum(b.price for b in bp[5:]) + sum(s.price for s in sp[5:])) * 0.1)
722
+ async def rate(self, cur_id: int, coin_id: int = 1) -> float:
723
+ if coin_id == 1:
724
+ ofc = 4 if cur_id in (1, 2, 3) else 1
725
+ else:
726
+ ofc = 1 if cur_id in (1, 2, 3) else 0
727
+
728
+ bp, sp = await self.get_books(coin_id, cur_id)
729
+ if bp and sp:
730
+ return (sum(b.price for b in bp[ofc:]) / len(bp[ofc:]) + sum(s.price for s in sp[ofc:]) / len(bp[ofc:])) / 2
731
+ return 0
732
+
733
+ async def set_rate(self, cur_id: int, coin_id: int = 1):
734
+ cur = await models.Cur[cur_id]
735
+ rate = round(await self.rate(cur_id, coin_id), cur.scale)
736
+ if coin_id == 1:
737
+ cur.rate = rate * 10**cur.scale
738
+ await cur.save(update_fields=["rate"])
739
+ await models.Pair.filter(cur_id=cur_id, coin_id=coin_id).update(rate=rate * 10**cur.scale)
740
+ logging.warning(f"Set rate {coin_id}/{cur.ticker}: {rate}")
727
741
 
728
742
  async def init_seed(self, fbot: FileClient):
729
743
  await self.set_curs()
@@ -216,6 +216,12 @@ class MyAdXOut(AmountQuantityMixin, BaseModel):
216
216
  self.maker = None
217
217
  return self
218
218
 
219
+ @model_validator(mode="after")
220
+ def min_amount(self):
221
+ if self.amount < self.min_fiat:
222
+ self.min_fiat = int(self.amount)
223
+ return self
224
+
219
225
 
220
226
  class BaseCredexsExidsTrait:
221
227
  credex_exids: list[int]
@@ -1,7 +1,7 @@
1
1
  import asyncio
2
2
  import json
3
3
  import logging
4
- from asyncio import sleep, gather
4
+ from asyncio import sleep
5
5
  from datetime import datetime, timedelta, timezone
6
6
  from difflib import SequenceMatcher
7
7
  from hashlib import sha256
@@ -15,7 +15,6 @@ import websockets
15
15
  from aiohttp.http_exceptions import HttpProcessingError, HttpBadRequest
16
16
  from bybit_p2p import P2P
17
17
  from bybit_p2p._exceptions import FailedRequestError
18
- from payeer_api import PayeerAPI
19
18
  from pybit.unified_trading import HTTP
20
19
  from tortoise import Tortoise, get_connection
21
20
  from tortoise.timezone import now
@@ -341,6 +340,7 @@ class AgentClient(BaseAgentClient): # Bybit client
341
340
  data = self.api.update_ad(**upd.model_dump(exclude_none=True))
342
341
  if data["ret_code"]:
343
342
  raise HttpBadRequest(data)
343
+ logging.info(f"Ad:{req.exid} upd: min:{req.min_fiat}, prc:{req.price}, qty:{req.quantity}, flt:{req.filtered}")
344
344
  return not data["ret_code"]
345
345
 
346
346
  def get_security_token_update(self) -> str:
@@ -1001,7 +1001,7 @@ async def main():
1001
1001
  await Tortoise.init(db_url=PG_DSN, modules={"models": ["x_auth.models", "xync_schema.models"]})
1002
1002
 
1003
1003
  agent = (
1004
- await models.Agent.filter(actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, id=3)
1004
+ await models.Agent.filter(actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, id=1)
1005
1005
  .prefetch_related(
1006
1006
  "actor__ex",
1007
1007
  "actor__person__user",
@@ -1033,51 +1033,51 @@ async def main():
1033
1033
  # await bot.start()
1034
1034
  # await cl.ex_client.set_pms(bot)
1035
1035
  # await bot.stop()
1036
- # await cl.load_assets()
1037
- # mads = await cl.load_my_ads()
1038
- # await cl.ads_fresh(False, 1, 1)
1039
- await cl.ads_fresh(True, 1, 1)
1036
+ await cl.load_assets()
1037
+ await cl.load_my_ads()
1038
+ r = await cl.ads_fresh(1, 1)
1039
+ print(r)
1040
1040
  # await cl.asset_save(1, b)
1041
1041
  # await cl.load_creds()
1042
1042
 
1043
- await cl.ads_share()
1044
-
1045
- ms = await models.Agent.filter(
1046
- actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, actor__person__user__id__in=[3]
1047
- ).prefetch_related(
1048
- "actor__ex",
1049
- "actor__person__user__gmail",
1050
- "actor__my_ads__my_ad__race",
1051
- "actor__my_ads__pair_side__pair__cur",
1052
- "actor__my_ads__pms",
1053
- )
1054
- {m.actor.exid: m.client(ecl) for m in ms}
1055
-
1056
- await gather(
1057
- # create_task(cl.start()),
1058
- # create_task(cl.watch_payeer(mcs, abot)),
1059
- )
1060
- # ensure_future(cl.start(True))
1061
- # await cl.boost_acc()
1062
-
1063
- # создание гонок по мои активным объявам:
1064
- # for ma in cl.my_ads():
1065
- # my_ad = await models.MyAd.get(ad__exid=ma.id).prefetch_related('ad__pms', 'ad__pair_side__pair')
1066
- # race, _ = await models.Race.update_or_create(
1067
- # {"started": True, "vm_filter": True, "target_place": 5},
1068
- # road=my_ad
1069
- # )
1070
-
1071
- # for name in names:
1072
- # s, _ = await models.Synonym.update_or_create(typ=SynonymType.name, txt=name)
1073
- # await s.curs.add(rub.cur)
1074
-
1075
- pauth = (await models.PmAgent[1]).auth
1076
- papi = PayeerAPI(pauth["email"], pauth["api_id"], pauth["api_sec"])
1077
- hist: dict = papi.history(count=1000)
1078
- hist |= papi.history(count=1000, append=list(hist.keys())[-1])
1079
- hist |= papi.history(count=1000, append=list(hist.keys())[-1])
1080
- cl.hist = hist
1043
+ # await cl.ads_share()
1044
+ #
1045
+ # ms = await models.Agent.filter(
1046
+ # actor__ex_id=4, auth__isnull=False, status__gt=AgentStatus.off, actor__person__user__id__in=[3]
1047
+ # ).prefetch_related(
1048
+ # "actor__ex",
1049
+ # "actor__person__user__gmail",
1050
+ # "actor__my_ads__my_ad__race",
1051
+ # "actor__my_ads__pair_side__pair__cur",
1052
+ # "actor__my_ads__pms",
1053
+ # )
1054
+ # {m.actor.exid: m.client(ecl) for m in ms}
1055
+ #
1056
+ # await gather(
1057
+ # # create_task(cl.start()),
1058
+ # # create_task(cl.watch_payeer(mcs, abot)),
1059
+ # )
1060
+ # # ensure_future(cl.start(True))
1061
+ # # await cl.boost_acc()
1062
+ #
1063
+ # # создание гонок по мои активным объявам:
1064
+ # # for ma in cl.my_ads():
1065
+ # # my_ad = await models.MyAd.get(ad__exid=ma.id).prefetch_related('ad__pms', 'ad__pair_side__pair')
1066
+ # # race, _ = await models.Race.update_or_create(
1067
+ # # {"started": True, "vm_filter": True, "target_place": 5},
1068
+ # # road=my_ad
1069
+ # # )
1070
+ #
1071
+ # # for name in names:
1072
+ # # s, _ = await models.Synonym.update_or_create(typ=SynonymType.name, txt=name)
1073
+ # # await s.curs.add(rub.cur)
1074
+ #
1075
+ # pauth = (await models.PmAgent[1]).auth
1076
+ # papi = PayeerAPI(pauth["email"], pauth["api_id"], pauth["api_sec"])
1077
+ # hist: dict = papi.history(count=1000)
1078
+ # hist |= papi.history(count=1000, append=list(hist.keys())[-1])
1079
+ # hist |= papi.history(count=1000, append=list(hist.keys())[-1])
1080
+ # cl.hist = hist
1081
1081
 
1082
1082
  # cl.completed_orders = await models.Order.filter(status=OrderStatus.completed, transfer__isnull=False).values_list(
1083
1083
  # "exid", flat=True
@@ -19,13 +19,15 @@ class AdStatusReq(StrEnum):
19
19
 
20
20
  IntStr = Annotated[str, BeforeValidator(str)]
21
21
  Dec2Str = Annotated[str, BeforeValidator(lambda v: f"{round(v, 2):g}")]
22
+ Dec4Str = Annotated[str, BeforeValidator(lambda v: f"{round(v - 0.00049, 4):g}")]
22
23
  NoneStr = Annotated[str, BeforeValidator(lambda v: f"{v or ''}")]
24
+ BoolIntStr = Annotated[Literal["0", "1"], BeforeValidator(lambda v: str(int(v)))]
23
25
 
24
26
 
25
27
  class AdsReq(BaseModel):
26
28
  tokenId: str = Field(validation_alias="coin_id")
27
29
  currencyId: str = Field(validation_alias="cur_id")
28
- side: Literal["0", "1"] = Field(validation_alias="is_sell") # 0 покупка, # 1 продажа
30
+ side: BoolIntStr = Field(validation_alias="is_sell") # 0 покупка, # 1 продажа
29
31
  payment: list[str] = Field([], validation_alias="pm_ids") # int
30
32
  size: str = Field("20", validation_alias="limit", coerce_numbers_to_str=True) # int
31
33
  page: IntStr = "1" # int
@@ -120,7 +122,7 @@ class _MyAdEIn(RemapBase):
120
122
  remark: NoneStr = Field("", validation_alias=AliasChoices("cond_txt", AliasPath("cond", "raw_txt")))
121
123
  tradingPreferenceSet: TradingPreferenceSet = TradingPreferenceSet()
122
124
  paymentIds: list[IntStr]
123
- quantity: Dec2Str # float
125
+ quantity: Dec4Str # float
124
126
  paymentPeriod: int = 15
125
127
 
126
128
  @model_validator(mode="before")
@@ -140,6 +142,7 @@ class _MyAdEIn(RemapBase):
140
142
  orderFinishNumberDay30=5,
141
143
  registerTimeThreshold=15,
142
144
  )
145
+ # out['quantity'] = f"{round(data.quantity-0.5*10**-data._coin_scale, data._coin_scale):g}"
143
146
  return out
144
147
 
145
148
 
@@ -228,7 +231,12 @@ class Ad(BaseAd, RemapBase):
228
231
 
229
232
  @model_validator(mode="after")
230
233
  def set_filtered_flag(self):
231
- self.filtered = bool(self.tradingPreferenceSet.completeRateDay30 or self.tradingPreferenceSet.hasRegisterTime)
234
+ self.filtered = bool(
235
+ self.tradingPreferenceSet
236
+ and self.tradingPreferenceSet.hasCompleteRateDay30
237
+ and self.tradingPreferenceSet.hasRegisterTime
238
+ and self.tradingPreferenceSet.hasOrderFinishNumberDay30
239
+ )
232
240
  return self
233
241
 
234
242
 
@@ -124,6 +124,66 @@ class ExClient(BaseExClient): # Bybit client
124
124
  return ads
125
125
 
126
126
 
127
+ curs = (
128
+ 1,
129
+ 2,
130
+ 3,
131
+ 4,
132
+ 6,
133
+ 8,
134
+ 9,
135
+ 10,
136
+ 11,
137
+ 12,
138
+ 13,
139
+ 14,
140
+ 15,
141
+ 17,
142
+ 18,
143
+ 19,
144
+ 20,
145
+ 21,
146
+ 22,
147
+ 28,
148
+ 29,
149
+ 30,
150
+ 33,
151
+ 36,
152
+ 37,
153
+ 40,
154
+ 41,
155
+ 43,
156
+ 44,
157
+ 47,
158
+ 50,
159
+ 51,
160
+ 52,
161
+ 56,
162
+ 59,
163
+ 65,
164
+ 66,
165
+ 68,
166
+ 69,
167
+ 73,
168
+ 74,
169
+ 77,
170
+ 78,
171
+ 80,
172
+ 81,
173
+ 82,
174
+ 85,
175
+ 88,
176
+ 91,
177
+ 101,
178
+ 103,
179
+ 107,
180
+ 111,
181
+ 112,
182
+ 113,
183
+ 119,
184
+ )
185
+
186
+
127
187
  async def main():
128
188
  _ = await init_db(TORM, True)
129
189
  ex = await Ex.get(name="Bybit")
@@ -131,8 +191,10 @@ async def main():
131
191
  # await bot.start()
132
192
  prx = PRX and "http://" + PRX
133
193
  cl: ExClient = ex.client(proxy=prx)
134
- await cl.set_coins(False)
135
- await cl.rate(1)
194
+ # await cl.set_coins(False)
195
+ for cur in curs:
196
+ for coin in (1, 2, 3, 4):
197
+ await cl.set_rate(cur, coin)
136
198
  # await cl.set_curs()
137
199
  await cl.set_pms(bot)
138
200
  await cl.set_pairs()
@@ -27,6 +27,10 @@ hot_ad_cond = "Банков НЕТ! Только XyncPay: @ex212 \n --- \n К
27
27
  hot_ad_auto_msg = "Банков нет. Только XyncPay. Читайте условия! Отменяйте, если у вас нет XyncPay"
28
28
 
29
29
 
30
+ def more1perc(a: float, b: float):
31
+ return abs(a - b) / a > 0.01
32
+
33
+
30
34
  async def search_messages(phrases_to_find) -> List[Dict[str, str]]:
31
35
  _ = await init_db(TORM, True)
32
36
  msgs = await models.Msg.all().values("txt")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: xync-client
3
- Version: 0.0.235
3
+ Version: 0.0.236.dev1
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