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.
- {xync_client-0.0.160/xync_client.egg-info → xync_client-0.0.173}/PKG-INFO +1 -1
- {xync_client-0.0.160 → xync_client-0.0.173}/README.md +20 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestAgent.py +10 -10
- xync_client-0.0.173/tests/TestOrder.py +24 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Agent.py +154 -22
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Ex.py +107 -127
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Order.py +20 -17
- xync_client-0.0.173/xync_client/Abc/xtype.py +236 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/agent.py +1 -1
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/agent.py +1 -3
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/agent.py +80 -327
- xync_client-0.0.173/xync_client/Bybit/etype/ad.py +191 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/etype/cred.py +25 -3
- xync_client-0.0.173/xync_client/Bybit/etype/order.py +370 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/ex.py +24 -12
- xync_client-0.0.160/xync_client/Bybit/InAgent.py → xync_client-0.0.173/xync_client/Bybit/inAgent.py +5 -10
- xync_client-0.0.173/xync_client/Bybit/order.py +65 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/agent.py +9 -9
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/ad.py +2 -4
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/test.py +4 -4
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/ex.py +35 -3
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/agent.py +6 -6
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/ex.py +2 -2
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/agent.py +21 -21
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/ex.py +11 -11
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/pyd.py +5 -5
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/pm_unifier.py +3 -2
- {xync_client-0.0.160 → xync_client-0.0.173/xync_client.egg-info}/PKG-INFO +1 -1
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/SOURCES.txt +1 -1
- xync_client-0.0.160/tests/TestOrder.py +0 -20
- xync_client-0.0.160/xync_client/Abc/xtype.py +0 -162
- xync_client-0.0.160/xync_client/Bybit/etype/ad.py +0 -170
- xync_client-0.0.160/xync_client/Bybit/etype/order.py +0 -318
- xync_client-0.0.160/xync_client/Bybit/order.py +0 -43
- {xync_client-0.0.160 → xync_client-0.0.173}/.env.sample +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/.gitignore +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/makefile +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/pyproject.toml +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/setup.cfg +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestAsset.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/TestEx.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/AdLoader.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Auth.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/Exception.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/HasAbotUid.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/InAgent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Abc/PmAgent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/etype/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Bybit/ws.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Gmail/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/order.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/api.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/order.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/1.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/agent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/.gitignore +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Alfa/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Alfa/state.json +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/MTS/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Ozon/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/.gitignore +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/agent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/login.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Payeer/trade.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Sber/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Sber/utils.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Tinkoff/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/agent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/api.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Volet/pl.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Xync/__main__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Xync/ed.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/Pms/Yandex/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/pyro.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/__init__.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/details.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client/loader.py +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.160 → xync_client-0.0.173}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -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
|
|
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[
|
|
48
|
-
ok = self.is_list_of_objects(my_creds,
|
|
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.
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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,
|
|
19
|
-
from xync_schema
|
|
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
|
|
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,
|
|
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,
|
|
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
|
-
|
|
63
|
-
self.
|
|
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,
|
|
67
|
-
if not self.cred_e2x.get(exid):
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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 =
|
|
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
|
|
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:
|
|
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:
|
|
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:
|
|
544
|
+
async def _ad_upd(self, ad: BaseAd) -> Ad: ...
|
|
413
545
|
|
|
414
546
|
# 32: Удаление
|
|
415
547
|
@abstractmethod
|