xync-client 0.0.160__tar.gz → 0.0.173__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 (137) hide show
  1. {xync_client-0.0.160/xync_client.egg-info → xync_client-0.0.173}/PKG-INFO +1 -1
  2. {xync_client-0.0.160 → xync_client-0.0.173}/README.md +20 -0
  3. {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestAgent.py +10 -10
  4. xync_client-0.0.173/tests/TestOrder.py +24 -0
  5. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Agent.py +154 -22
  6. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Ex.py +107 -127
  7. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Order.py +20 -17
  8. xync_client-0.0.173/xync_client/Abc/xtype.py +236 -0
  9. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/agent.py +1 -1
  10. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/agent.py +1 -3
  11. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/agent.py +80 -327
  12. xync_client-0.0.173/xync_client/Bybit/etype/ad.py +191 -0
  13. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/etype/cred.py +25 -3
  14. xync_client-0.0.173/xync_client/Bybit/etype/order.py +370 -0
  15. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/ex.py +24 -12
  16. xync_client-0.0.160/xync_client/Bybit/InAgent.py → xync_client-0.0.173/xync_client/Bybit/inAgent.py +5 -10
  17. xync_client-0.0.173/xync_client/Bybit/order.py +65 -0
  18. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/agent.py +9 -9
  19. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/ad.py +2 -4
  20. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/test.py +4 -4
  21. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/ex.py +35 -3
  22. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/agent.py +6 -6
  23. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/ex.py +2 -2
  24. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/agent.py +21 -21
  25. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/ex.py +11 -11
  26. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/pyd.py +5 -5
  27. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/pm_unifier.py +3 -2
  28. {xync_client-0.0.160 → xync_client-0.0.173/xync_client.egg-info}/PKG-INFO +1 -1
  29. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/SOURCES.txt +1 -1
  30. xync_client-0.0.160/tests/TestOrder.py +0 -20
  31. xync_client-0.0.160/xync_client/Abc/xtype.py +0 -162
  32. xync_client-0.0.160/xync_client/Bybit/etype/ad.py +0 -170
  33. xync_client-0.0.160/xync_client/Bybit/etype/order.py +0 -318
  34. xync_client-0.0.160/xync_client/Bybit/order.py +0 -43
  35. {xync_client-0.0.160 → xync_client-0.0.173}/.env.sample +0 -0
  36. {xync_client-0.0.160 → xync_client-0.0.173}/.gitignore +0 -0
  37. {xync_client-0.0.160 → xync_client-0.0.173}/.pre-commit-config.yaml +0 -0
  38. {xync_client-0.0.160 → xync_client-0.0.173}/__init__.py +0 -0
  39. {xync_client-0.0.160 → xync_client-0.0.173}/makefile +0 -0
  40. {xync_client-0.0.160 → xync_client-0.0.173}/pyproject.toml +0 -0
  41. {xync_client-0.0.160 → xync_client-0.0.173}/setup.cfg +0 -0
  42. {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestAsset.py +0 -0
  43. {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestEx.py +0 -0
  44. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Binance/test_binance.py +0 -0
  45. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
  46. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
  47. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Gate/test_gate.py +0 -0
  48. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Wallet/test_agent.py +0 -0
  49. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Wallet/test_ex.py +0 -0
  50. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/__init__.py +0 -0
  51. {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/_test_ex.py +0 -0
  52. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/AdLoader.py +0 -0
  53. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Asset.py +0 -0
  54. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Auth.py +0 -0
  55. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/BaseTest.py +0 -0
  56. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Exception.py +0 -0
  57. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/HasAbotUid.py +0 -0
  58. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/InAgent.py +0 -0
  59. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/PmAgent.py +0 -0
  60. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/__init__.py +0 -0
  61. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/binance_async.py +0 -0
  62. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/earn_api.py +0 -0
  63. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/etype/ad.py +0 -0
  64. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/etype/pm.py +0 -0
  65. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/ex.py +0 -0
  66. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/exceptions.py +0 -0
  67. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/sapi.py +0 -0
  68. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/web_c2c.py +0 -0
  69. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/__init__.py +0 -0
  70. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/base.py +0 -0
  71. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/etype/ad.py +0 -0
  72. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/etype/pm.py +0 -0
  73. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/ex.py +0 -0
  74. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/req.mjs +0 -0
  75. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/sign.js +0 -0
  76. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/__init__.py +0 -0
  77. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/etype/ad.py +0 -0
  78. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/ex.py +0 -0
  79. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitPapa/ex.py +0 -0
  80. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/etype/__init__.py +0 -0
  81. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/web_earn.py +0 -0
  82. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/web_p2p.py +0 -0
  83. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/ws.py +0 -0
  84. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/etype/ad.py +0 -0
  85. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/ex.py +0 -0
  86. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/premarket.py +0 -0
  87. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gmail/__init__.py +0 -0
  88. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/earn.py +0 -0
  89. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/__init__.py +0 -0
  90. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/cred.py +0 -0
  91. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/order.py +0 -0
  92. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/pm.py +0 -0
  93. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/etype/ad.py +0 -0
  94. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/etype/pm.py +0 -0
  95. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/ex.py +0 -0
  96. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/web.py +0 -0
  97. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/api.py +0 -0
  98. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/ad.py +0 -0
  99. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/order.py +0 -0
  100. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/pm.py +0 -0
  101. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/1.py +0 -0
  102. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/agent.py +0 -0
  103. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/etype/ad.py +0 -0
  104. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/etype/pm.py +0 -0
  105. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/ex.py +0 -0
  106. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/.gitignore +0 -0
  107. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Alfa/__init__.py +0 -0
  108. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Alfa/state.json +0 -0
  109. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/MTS/__init__.py +0 -0
  110. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Ozon/__init__.py +0 -0
  111. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/.gitignore +0 -0
  112. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/agent.py +0 -0
  113. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/login.py +0 -0
  114. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/trade.py +0 -0
  115. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Sber/__init__.py +0 -0
  116. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Sber/utils.py +0 -0
  117. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Tinkoff/__init__.py +0 -0
  118. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
  119. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
  120. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/agent.py +0 -0
  121. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/api.py +0 -0
  122. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/pl.py +0 -0
  123. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Xync/__main__.py +0 -0
  124. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Xync/ed.py +0 -0
  125. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Yandex/__init__.py +0 -0
  126. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/asset.py +0 -0
  127. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/auth.py +0 -0
  128. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/inAgent.py +0 -0
  129. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/order.py +0 -0
  130. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/pyro.py +0 -0
  131. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/web.py +0 -0
  132. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/__init__.py +0 -0
  133. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/details.py +0 -0
  134. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/loader.py +0 -0
  135. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/dependency_links.txt +0 -0
  136. {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/requires.txt +0 -0
  137. {xync_client-0.0.160 → xync_client-0.0.173}/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.160
3
+ Version: 0.0.173
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,3 +1,23 @@
1
+ ## Структура http-клиентов
2
+ #### Абстрактные классы клиентов:
3
+ **BaseClient** *[host: str]* - базовый http-клиент, с низкоуровнеными методами get, post, put и delete, сессией, и общими
4
+ для всех клиентов свойствами. *[В конструкторе принимает хост строкой]*
5
+
6
+ **BaseExClient**(BaseClient) *[ex: Ex]* - клиент с публичными/анонимными методами конкретной биржи.
7
+ *[В конструкторе принимает зависимость: экземпляр биржи]*
8
+
9
+ **_BaseAuthClient**(BaseClient) *[agent: Agent]* - клиент реализующий логин (получение необходимых заголовков) конкретного
10
+ юзера биржи. *[В конструкторе принимает зависимость: экземпляр агента]*
11
+
12
+ **BaseInAgentTrait** - класс реализующий прием входящих событий от биржи. Если у биржи есть вебсокет канал, то по нему,
13
+ если нет - то через поллинг каждые х секунд.
14
+
15
+ **BaseAgentClient**(BaseAuthClient, BaseInAgentTrait) *[agent: Agent, ex_client: BaseExClient]* - клиент с приватными
16
+ методами биржи от лица конкретного юзера биржи. *[В конструкторе принимает зависимости: экземпляр агента, и клиента биржи]*
17
+
18
+ **BaseOrderClient** *[order: Order, agent_client: BaseExClient]* - методы для обработки конкретного ордера на бирже.
19
+ *[В конструкторе принимает зависимости: экземпляр ордера, и клиента агента]*
20
+
1
21
  ## Order Flow:
2
22
  - 0: Получшение заявок за заданное время, в статусе, по валюте, монете, направлению: `get_orders(stauts=OrderStatus.active, coin='USDT', cur='RUB', is_sell=False) => [order]`
3
23
 
@@ -9,7 +9,7 @@ from xync_schema.xtype import BaseAd
9
9
  from xync_client.Abc.BaseTest import BaseTest
10
10
  from xync_client.Abc.Ex import BaseExClient
11
11
  from xync_client.Abc.Agent import BaseAgentClient
12
- from xync_client.Abc.xtype import CredExOut, BaseOrderReq, ListOfDicts
12
+ from xync_client.Abc.xtype import BaseCredEx, BaseOrderReq, ListOfDicts
13
13
 
14
14
 
15
15
  @pytest.mark.asyncio(loop_scope="session")
@@ -44,8 +44,8 @@ class TestAgent(BaseTest):
44
44
  # 25
45
45
  async def test_my_creds(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
46
46
  for maker, taker in clients:
47
- my_creds: list[CredExOut] = await taker.creds()
48
- ok = self.is_list_of_objects(my_creds, CredExOut)
47
+ my_creds: list[BaseCredEx] = await taker.get_creds()
48
+ ok = self.is_list_of_objects(my_creds, BaseCredEx)
49
49
  t, _ = await ExStat.update_or_create({"ok": ok}, ex=taker.actor.ex, action=ExAction.my_creds)
50
50
  assert t.ok, "No my creds"
51
51
  logging.info(f"{taker.actor.ex.name}:{ExAction.my_creds.name} - ok")
@@ -53,7 +53,7 @@ class TestAgent(BaseTest):
53
53
  # 27
54
54
  async def test_cred_upd(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
55
55
  for maker, taker in clients:
56
- credex = (await taker.creds())[0]
56
+ credex = (await taker.get_creds())[0]
57
57
  credex_db = await CredEx.get(exid=credex.id, ex=taker.actor.ex).prefetch_related("cred")
58
58
  credex_db.cred.name += "+Test!"
59
59
  cred_upd: CredEx = await taker.cred_upd(credex_db.cred, credex.id)
@@ -65,7 +65,7 @@ class TestAgent(BaseTest):
65
65
  # 28
66
66
  async def test_cred_del(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
67
67
  for maker, taker in clients:
68
- credex = (await taker.creds())[0]
68
+ credex = (await taker.get_creds())[0]
69
69
  cred_del: int = await taker.cred_del(credex.id)
70
70
  ok = cred_del == credex.id
71
71
  t, _ = await ExStat.update_or_create({"ok": ok}, ex=taker.actor.ex, action=ExAction.cred_del)
@@ -111,7 +111,7 @@ class TestAgent(BaseTest):
111
111
  req = BaseOrderReq(
112
112
  ad_id=ad.exid,
113
113
  is_sell=ad.direction.sell,
114
- fiat_amount=ad.min_fiat,
114
+ amount=ad.min_fiat,
115
115
  cred_id=mutual_cred.id,
116
116
  )
117
117
  order_request: dict | bool = await taker.order_request(req)
@@ -123,7 +123,7 @@ class TestAgent(BaseTest):
123
123
  # 29
124
124
  async def test_my_ads(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
125
125
  for maker, taker in clients:
126
- my_ads: list[BaseAd] = await maker.my_ads()
126
+ my_ads: list[BaseAd] = await maker.get_my_ads()
127
127
  ok = self.is_list_of_objects(my_ads, BaseAd)
128
128
  t, _ = await ExStat.update_or_create({"ok": ok}, ex=taker.actor.ex, action=ExAction.my_ads)
129
129
  assert t.ok, "Maker should has ads"
@@ -148,7 +148,7 @@ class TestAgent(BaseTest):
148
148
  # 31
149
149
  async def test_ad_upd(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
150
150
  for maker, taker in clients:
151
- my_ads: ListOfDicts = await taker.my_ads()
151
+ my_ads: ListOfDicts = await taker.get_my_ads()
152
152
  ad_upd: Ad.pyd() = await taker.ad_upd(offer_id=my_ads[0]["id"], amount="11")
153
153
  ok = ad_upd["status"] == "SUCCESS"
154
154
  t, _ = await ExStat.update_or_create({"ok": ok}, ex=taker.actor.ex.name, action=ExAction.ad_upd)
@@ -158,7 +158,7 @@ class TestAgent(BaseTest):
158
158
  # 32
159
159
  async def test_ad_del(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
160
160
  for maker, taker in clients:
161
- my_ads: ListOfDicts = await taker.my_ads()
161
+ my_ads: ListOfDicts = await taker.get_my_ads()
162
162
  ad_del: bool = await taker.ad_del(ad_id=my_ads[0]["id"])
163
163
  t, _ = await ExStat.update_or_create({"ok": ad_del}, ex=taker.actor.ex, action=ExAction.ad_del)
164
164
  assert t.ok, "No add new ad"
@@ -167,7 +167,7 @@ class TestAgent(BaseTest):
167
167
  # 33
168
168
  async def test_ad_switch(self, clients: list[tuple[BaseAgentClient, BaseAgentClient]]):
169
169
  for maker, taker in clients:
170
- my_ads: ListOfDicts = await taker.my_ads()
170
+ my_ads: ListOfDicts = await taker.get_my_ads()
171
171
  new_status = not (my_ads[0]["status"] == "ACTIVE")
172
172
  ad_switch: bool = await taker.ad_switch(offer_id=my_ads[0]["id"], active=new_status)
173
173
  t, _ = await ExStat.update_or_create({"ok": ad_switch}, ex=taker.actor.ex, action=ExAction.ad_switch)
@@ -0,0 +1,24 @@
1
+ import pytest
2
+ from xync_client.Abc.Order import BaseOrderClient
3
+ from xync_schema.models import Agent, Ex
4
+
5
+ from xync_client.Abc.Agent import BaseAgentClient
6
+
7
+ from xync_client.Abc.BaseTest import BaseTest
8
+
9
+
10
+ class AgentTest(BaseTest):
11
+ @pytest.fixture(scope="class")
12
+ async def cl(self) -> BaseAgentClient:
13
+ agent = await Agent.filter(auth__not_isnull=True, status__gt=0).prefetch_related("actor__ex").first()
14
+ ex: Ex = agent.actor.ex
15
+ acl: BaseAgentClient = agent.client(ex.client())
16
+ yield acl
17
+ await acl.close()
18
+
19
+ @pytest.fixture(scope="class")
20
+ async def cl1(self) -> BaseOrderClient:
21
+ agent = (await self.exq).agents.filter(auth__not_isnull=True).offset(1).first()
22
+ acl = BaseOrderClient(agent)
23
+ yield acl
24
+ await acl.close()
@@ -6,6 +6,7 @@ from typing import Literal
6
6
 
7
7
  from pydantic import BaseModel
8
8
  from pyro_client.client.file import FileClient
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
12
  from xync_bot import XyncBot
@@ -15,25 +16,36 @@ from xync_client.Abc.InAgent import BaseInAgentClient
15
16
 
16
17
  from xync_client.Bybit.etype.order import TakeAdReq
17
18
  from xync_schema import models
18
- from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Actor, Agent
19
- from xync_schema.xtype import BaseAd
19
+ from xync_schema.models import OrderStatus, Coin, Cur, Ad, Actor, Agent
20
+ from xync_schema import xtype
20
21
 
21
22
  from xync_client.Abc.Ex import BaseExClient
22
- from xync_client.Abc.xtype import CredExOut, BaseOrderReq, BaseAdUpdate, AdUpd, GetAds
23
+ from xync_client.Abc.xtype import (
24
+ BaseCredEx,
25
+ BaseOrderReq,
26
+ BaseAd,
27
+ AdUpdReq,
28
+ GetAdsReq,
29
+ BaseCredexsExidsTrait,
30
+ BaseOrderFull,
31
+ )
23
32
  from xync_client.Gmail import GmClient
24
33
 
25
34
 
26
- class BaseAgentClient(HttpClient, BaseInAgentClient):
35
+ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
27
36
  actor: Actor
28
37
  agent: Agent
29
38
  bbot: XyncBot
30
39
  fbot: FileClient
31
40
  ex_client: BaseExClient
32
- orders: dict[int, tuple[models.Order, BaseModel]] = {} # pending
41
+ orders: dict[int, tuple[models.Order, xtype.BaseOrder]] = {} # pending
33
42
  pm_clients: dict[int, PmAgentClient] # {pm_id: PmAgentClient}
34
43
  api: HttpClient
35
44
  cred_x2e: dict[int, int] = {}
36
- cred_e2x: dict[int, int] = {}
45
+ cred_e2x: dict[int, models.CredEx] = {}
46
+ order_x2e: dict[int, int] = {}
47
+ order_e2x: dict[int, int] = {}
48
+ cdx_cls: type[BaseCredEx]
37
49
 
38
50
  def __init__(
39
51
  self,
@@ -59,15 +71,30 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
59
71
 
60
72
  async def x2e_cred(self, cred_id: int) -> int: # cred.exid
61
73
  if not self.cred_x2e.get(cred_id):
62
- self.cred_x2e[cred_id] = (await models.CredEx.get(cred_id=cred_id)).exid
63
- self.cred_e2x[self.cred_x2e[cred_id]] = cred_id
74
+ credex = await models.CredEx.get(cred_id=cred_id)
75
+ self.cred_x2e[cred_id] = credex.exid
76
+ self.cred_e2x[credex.exid] = credex
64
77
  return self.cred_x2e[cred_id]
65
78
 
66
- async def e2x_cred(self, exid: int) -> int: # cred.id
67
- if not self.cred_e2x.get(exid):
68
- self.cred_e2x[exid] = (await models.CredEx.get(exid=exid, ex=self.ex_client.ex)).cred_id
69
- self.cred_x2e[self.cred_e2x[exid]] = exid
70
- return self.cred_e2x[exid]
79
+ async def e2x_cred(self, base_credex: BaseCredEx) -> models.CredEx: # cred.id
80
+ if not self.cred_e2x.get(base_credex.exid):
81
+ if not (credex := await models.CredEx.get_or_none(exid=base_credex.exid, ex=self.ex_client.ex)):
82
+ credex = await self.credex_save(base_credex)
83
+ self.cred_e2x[base_credex.exid] = credex
84
+ self.cred_x2e[credex.cred_id] = base_credex.exid
85
+ return self.cred_e2x[base_credex.exid]
86
+
87
+ async def x2e_order(self, order_id: int) -> int: # order.exid
88
+ if not self.order_x2e.get(order_id):
89
+ self.order_x2e[order_id] = (await models.Order[order_id]).exid
90
+ self.order_e2x[self.order_x2e[order_id]] = order_id
91
+ return self.order_x2e[order_id]
92
+
93
+ async def e2x_order(self, exid: int) -> int: # order.id
94
+ if not self.order_e2x.get(exid):
95
+ self.order_e2x[exid] = (await models.Order.get(exid=exid, taker__ex=self.ex_client.ex)).id
96
+ self.order_x2e[self.order_e2x[exid]] = exid
97
+ return self.order_e2x[exid]
71
98
 
72
99
  async def start(self):
73
100
  if self.agent.status & 1: # race
@@ -78,6 +105,115 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
78
105
  if self.agent.status & 2: # listen
79
106
  await self.start_listen()
80
107
 
108
+ @abstractmethod
109
+ async def _get_creds(self) -> list[BaseModel]: ...
110
+
111
+ async def get_creds(self) -> list[BaseCredEx]:
112
+ creds: list[BaseModel] = await self._get_creds()
113
+ return [self.cdx_cls.model_validate(cred, from_attributes=True) for cred in creds]
114
+
115
+ async def credex_save(self, cdx: BaseCredEx, pers_id: int = None, cur_id: int = None) -> models.CredEx | None:
116
+ pmex = None
117
+ if cred_old := await models.Cred.get_or_none(
118
+ credexs__exid=cdx.exid, credexs__ex=self.actor.ex
119
+ ).prefetch_related("pmcur"): # is old Cred
120
+ cur_id = cur_id or cred_old.pmcur.cur_id
121
+ elif not cur_id: # is new Cred
122
+ if cdx.curex_exid:
123
+ cur_id = (await models.CurEx.get(exid=cdx.curex_exid, ex=self.actor.ex)).cur_id
124
+ else:
125
+ pmex = await models.PmEx.get_or_none(exid=cdx.pmex_exid, ex=self.ex_client.ex).prefetch_related(
126
+ "pm__curs"
127
+ )
128
+ cur_id = (
129
+ pmex.pm.df_cur_id
130
+ or (await cdx.guess_cur(pmex.pm.curs) if len(pmex.pm.curs) != 1 else pmex.pm.curs[0].cur_id)
131
+ or (pmex.pm.country_id and (await pmex.pm.country).cur_id)
132
+ # or (ecdx.currencyBalance and await models.Cur.get_or_none(ticker=ecdx.currencyBalance[0])) # это че еще за хуйня?
133
+ )
134
+ if not cur_id:
135
+ raise ValueError(f"Set default cur for {pmex.name}")
136
+ pm_id = pmex and pmex.pm_id or await self.ex_client.e2x_pm(cdx.pmex_exid)
137
+ if not (pmcur := await models.PmCur.get_or_none(cur_id=cur_id, pm_id=pm_id)):
138
+ raise ValueError(f"No PmCur with cur#{cur_id} and pm#{cdx.pmex_exid}", 404)
139
+ try:
140
+ pers_id = pers_id or cdx.seller.exid and (await self.ex_client.e2x_actor(cdx.seller)).person_id
141
+ cred_db, _ = await models.Cred.update_or_create(
142
+ {"name": cdx.name, "extra": cdx.extra},
143
+ pmcur=pmcur,
144
+ person_id=pers_id,
145
+ detail=cdx.detail,
146
+ )
147
+ if not cred_db.ovr_pm_id and ("XyncPay" in cred_db.detail or "XyncPay" in cred_db.extra):
148
+ cred_db.ovr_pm_id = 0
149
+ await cred_db.save()
150
+ credex_db, _ = await models.CredEx.update_or_create(exid=cdx.exid, cred=cred_db, ex=self.actor.ex)
151
+ except IntegrityError as e:
152
+ raise e
153
+ return credex_db
154
+
155
+ # 25: Список реквизитов моих платежных методов
156
+ async def load_creds(self) -> list[models.CredEx]:
157
+ credexs_epyd: list[BaseCredEx] = await self.get_creds()
158
+ credexs: list[models.CredEx] = [await self.credex_save(f) for f in credexs_epyd]
159
+ return credexs
160
+
161
+ async def my_ad_save(
162
+ self,
163
+ bmad: BaseAd | BaseCredexsExidsTrait,
164
+ rname: str = None,
165
+ ) -> models.MyAd:
166
+ ad_db = await self.ex_client.ad_save(bmad)
167
+ mad_db, _ = await models.MyAd.update_or_create(ad=ad_db)
168
+ credexs = await models.CredEx.filter(ex_id=self.actor.ex_id, exid__in=bmad.credex_exids)
169
+ await mad_db.credexs.clear()
170
+ await mad_db.credexs.add(*credexs)
171
+ return mad_db
172
+
173
+ async def load_my_ads(self, only_active: bool = None) -> list[models.MyAd]: # upserted)
174
+ ads = await self.get_my_ads(True)
175
+ if not only_active:
176
+ ads += await self.get_my_ads(False)
177
+ return [await self.my_ad_save(ad) for ad in ads]
178
+
179
+ @abstractmethod
180
+ async def _get_order_full(self, order_exid: int) -> BaseOrderFull: ...
181
+
182
+ async def get_order_full(self, order_exid: int) -> xtype.BaseOrder:
183
+ eorder: BaseOrderFull = await self._get_order_full(order_exid)
184
+ _, cur_scale, __ = await self.ex_client.x2e_cur(await self.ex_client.e2x_cur(eorder.curex_exid))
185
+ _, coin_scale = await self.ex_client.x2e_coin(await self.ex_client.e2x_coin(eorder.coinex_exid))
186
+ ad = await self.ex_client.e2x_ad(eorder.ad_id)
187
+ credex = await self.e2x_cred(eorder.credex)
188
+ taker = await self.ex_client.e2x_actor(eorder.taker)
189
+ border = eorder.model_dump()
190
+ border.update(
191
+ ad_id=ad.id,
192
+ cred_id=credex.cred_id,
193
+ taker_id=taker.id,
194
+ amount=int(eorder.amount * 10**cur_scale),
195
+ quantity=int(eorder.quantity * 10**coin_scale),
196
+ )
197
+ return xtype.BaseOrder.model_validate(border)
198
+
199
+ async def load_order(self, order_exid: int, force_refresh: bool = False) -> tuple[models.Order, xtype.BaseOrder]:
200
+ if not self.orders.get(order_exid) or force_refresh:
201
+ order: xtype.BaseOrder = await self.get_order_full(order_exid)
202
+ if not (
203
+ order_db := await models.Order.get_or_none(
204
+ exid=order_exid, ad__maker__ex=self.actor.ex
205
+ ).prefetch_related("ad__pair_side__pair", "cred__pmcur__cur")
206
+ ):
207
+ order_db = await self.order_save(order)
208
+ self.orders[order_exid] = order_db, order
209
+ return self.orders[order_exid]
210
+
211
+ async def order_save(self, order: xtype.BaseOrder) -> models.Order:
212
+ order_in = models.Order.validate(order.model_dump())
213
+ odb, _ = await models.Order.update_or_create(**order_in.df_unq())
214
+ # await odb.fetch_related("ad") # todo: for what?
215
+ return odb
216
+
81
217
  async def racing(self, race: models.Race):
82
218
  pair = race.road.ad.pair_side.pair
83
219
  taker_side: int = not race.road.ad.pair_side.is_sell
@@ -116,7 +252,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
116
252
  asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
117
253
  volume = asset.free * 10**-coinex.scale
118
254
  volume = str(round(volume, coinex.scale))
119
- get_ads_req = GetAds(
255
+ get_ads_req = GetAdsReq(
120
256
  coin_id=pair.coin_id, cur_id=pair.cur_id, is_sell=bool(taker_side), pm_ids=pm_ids, amount=amt, limit=50
121
257
  )
122
258
  try:
@@ -363,10 +499,6 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
363
499
  self, exid: int | str, cur: str, detail: str, name: str, fid: int, typ: str, extra=None
364
500
  ) -> fiat_pyd: ...
365
501
 
366
- # 25: Список реквизитов моих платежных методов
367
- @abstractmethod
368
- async def creds(self) -> list[CredExOut]: ... # {credex.exid: {cred}}
369
-
370
502
  # Создание реквизита на бирже
371
503
  async def cred_new(self, cred: models.Cred) -> models.CredEx: ...
372
504
 
@@ -387,16 +519,16 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
387
519
  # # # Ad
388
520
  # 29: Список моих объявлений
389
521
  @abstractmethod
390
- async def my_ads(self, status: AdStatus = None) -> list[BaseAd]: ...
522
+ async def get_my_ads(self, status: bool = None) -> list[BaseAd | BaseCredexsExidsTrait]: ...
391
523
 
392
524
  @abstractmethod
393
- async def x2e_req_ad_upd(self, xreq: AdUpd) -> BaseAdUpdate: ...
525
+ async def x2e_req_ad_upd(self, xreq: AdUpdReq) -> BaseAd: ...
394
526
 
395
527
  # 30: Создание объявления
396
528
  @abstractmethod
397
529
  async def ad_new(self, ad: BaseAd) -> Ad: ...
398
530
 
399
- async def ad_upd(self, xreq: AdUpd) -> Ad:
531
+ async def ad_upd(self, xreq: AdUpdReq) -> Ad:
400
532
  xreq.credexs = await models.CredEx.filter(
401
533
  ex_id=self.actor.ex_id,
402
534
  cred__pmcur__pm_id__in=xreq.pm_ids,
@@ -409,7 +541,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient):
409
541
 
410
542
  # 31: Редактирование объявления
411
543
  @abstractmethod
412
- async def _ad_upd(self, ad: BaseAdUpdate) -> Ad: ...
544
+ async def _ad_upd(self, ad: BaseAd) -> Ad: ...
413
545
 
414
546
  # 32: Удаление
415
547
  @abstractmethod