xync-client 0.0.25.dev91__tar.gz → 0.0.25.dev109__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.25.dev91 → xync_client-0.0.25.dev109}/.gitignore +2 -1
- {xync_client-0.0.25.dev91/xync_client.egg-info → xync_client-0.0.25.dev109}/PKG-INFO +3 -2
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/pyproject.toml +2 -2
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/TestEx.py +1 -1
- xync_client-0.0.25.dev109/xync_client/Abc/Agent.py +141 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/AuthTrait.py +3 -2
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/Ex.py +33 -6
- xync_client-0.0.25.dev109/xync_client/Abc/InAgent.py +12 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/types.py +6 -2
- xync_client-0.0.25.dev109/xync_client/Binance/etype/ad.py +125 -0
- xync_client-0.0.25.dev109/xync_client/Binance/etype/pm.py +15 -0
- xync_client-0.0.25.dev109/xync_client/Binance/ex.py +139 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitGet/ex.py +25 -3
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Bybit/ex.py +3 -3
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Gate/ex.py +8 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/etype/ad.py +1 -1
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Mexc/ex.py +1 -1
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Okx/ex.py +8 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/agent.py +148 -138
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/auth.py +3 -1
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/ex.py +1 -1
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/pyd.py +8 -2
- xync_client-0.0.25.dev109/xync_client/TgWallet/pyro.py +156 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/loader.py +3 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109/xync_client.egg-info}/PKG-INFO +3 -2
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client.egg-info/SOURCES.txt +2 -1
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client.egg-info/requires.txt +2 -1
- xync_client-0.0.25.dev91/tests/res.js +0 -26246
- xync_client-0.0.25.dev91/xync_client/Abc/Agent.py +0 -201
- xync_client-0.0.25.dev91/xync_client/Abc/InAgent.py +0 -6
- xync_client-0.0.25.dev91/xync_client/Binance/ex.py +0 -81
- xync_client-0.0.25.dev91/xync_client/TgWallet/pyro.py +0 -52
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/.env.sample +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/README.md +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/makefile +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/setup.cfg +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/TestAgent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/TestAsset.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/TestOrder.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/Base.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitGet/req.mjs +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Bybit/agent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Bybit/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/agent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Htx/ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Mexc/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/__init__.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client/pm_unifier.py +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.25.dev91 → xync_client-0.0.25.dev109}/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.25.
|
|
3
|
+
Version: 0.0.25.dev109
|
|
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
|
|
@@ -12,9 +12,10 @@ Requires-Dist: msgspec
|
|
|
12
12
|
Requires-Dist: python-binance
|
|
13
13
|
Requires-Dist: pybit
|
|
14
14
|
Requires-Dist: pyotp
|
|
15
|
-
Requires-Dist:
|
|
15
|
+
Requires-Dist: kurigram
|
|
16
16
|
Requires-Dist: python-dotenv
|
|
17
17
|
Requires-Dist: python-okx
|
|
18
|
+
Requires-Dist: tgcrypto
|
|
18
19
|
Requires-Dist: xn-client>=0.0.3dev3
|
|
19
20
|
Requires-Dist: xync-schema
|
|
20
21
|
Provides-Extra: dev
|
|
@@ -17,7 +17,7 @@ class TestEx(BaseTest):
|
|
|
17
17
|
@pytest.fixture
|
|
18
18
|
async def clients(self) -> list[BaseClient]:
|
|
19
19
|
exs = await Ex.filter(status__gt=ExStatus.plan)
|
|
20
|
-
[await ex
|
|
20
|
+
[await ex for ex in exs if ex.type_ == ExType.tg]
|
|
21
21
|
clients: list[BaseExClient] = [ex.client() for ex in exs]
|
|
22
22
|
yield clients
|
|
23
23
|
[await cl.close() for cl in clients]
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
from pydantic import BaseModel
|
|
4
|
+
from xync_schema import models
|
|
5
|
+
from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Agent, Cred
|
|
6
|
+
from xync_schema.types import BaseAd, AdSaleIn, AdBuyIn, BaseOrder
|
|
7
|
+
|
|
8
|
+
from xync_client.Abc.Ex import BaseExClient
|
|
9
|
+
from xync_client.Abc.Base import BaseClient
|
|
10
|
+
from xync_client.Abc.types import CredExOut
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class BaseAgentClient(BaseClient):
|
|
14
|
+
def __init__(self, agent: Agent):
|
|
15
|
+
self.agent: Agent = agent
|
|
16
|
+
super().__init__(self.agent.actor.ex) # , "host_p2p"
|
|
17
|
+
self.ex_client: BaseExClient = self.ex.client()
|
|
18
|
+
|
|
19
|
+
# 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
|
|
20
|
+
@abstractmethod
|
|
21
|
+
async def get_orders(
|
|
22
|
+
self, status: OrderStatus = OrderStatus.created, coin: Coin = None, cur: Cur = None, is_sell: bool = None
|
|
23
|
+
) -> list: ...
|
|
24
|
+
|
|
25
|
+
# 1: [T] Запрос на старт сделки
|
|
26
|
+
@abstractmethod
|
|
27
|
+
async def order_request(self, order: BaseOrder) -> dict: ...
|
|
28
|
+
|
|
29
|
+
# async def start_order(self, order: Order) -> OrderOutClient:
|
|
30
|
+
# return OrderOutClient(self, order)
|
|
31
|
+
|
|
32
|
+
# 1N: [M] - Запрос мейкеру на сделку
|
|
33
|
+
@abstractmethod
|
|
34
|
+
async def order_request_ask(self) -> dict: ... # , ad: Ad, amount: float, pm: Pm, taker: Agent
|
|
35
|
+
|
|
36
|
+
# 2N: [M] - Уведомление об отмене запроса на сделку
|
|
37
|
+
@abstractmethod
|
|
38
|
+
async def request_canceled_notify(self) -> int: ... # id
|
|
39
|
+
|
|
40
|
+
# # # Cred
|
|
41
|
+
@property
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def fiat_pyd(self) -> BaseModel.__class__: ...
|
|
44
|
+
|
|
45
|
+
@abstractmethod
|
|
46
|
+
def fiat_args2pyd(
|
|
47
|
+
self, exid: int | str, cur: str, detail: str, name: str, fid: int, typ: str, extra=None
|
|
48
|
+
) -> fiat_pyd: ...
|
|
49
|
+
|
|
50
|
+
# 25: Список реквизитов моих платежных методов
|
|
51
|
+
@abstractmethod
|
|
52
|
+
async def creds(self) -> list: ... # {credex.exid: {cred}}
|
|
53
|
+
|
|
54
|
+
# Создание реквизита на бирже
|
|
55
|
+
async def cred_new(self, cred: models.Cred) -> CredExOut: ...
|
|
56
|
+
|
|
57
|
+
# await models.Actor.get_or_create({"name": cred.exid}, ex=self.ex_client.ex, exid=self.agent.actor.exid)
|
|
58
|
+
# cred_db: Cred = (await self.cred_pyd2db(cred, self.agent.user_id))[0]
|
|
59
|
+
# if not (credex := models.CredEx.get_or_none(cred=cred_db, ex=self.agent.ex)):
|
|
60
|
+
# credex, _ = models.CredEx.update_or_create({}, cred=cred_db, ex=self.agent.ex)
|
|
61
|
+
# return credex
|
|
62
|
+
|
|
63
|
+
# 27: Редактирование реквизита моего платежного метода
|
|
64
|
+
@abstractmethod
|
|
65
|
+
async def cred_upd(self, cred: models.Cred, exid: int) -> CredExOut: ...
|
|
66
|
+
|
|
67
|
+
# 28: Удаление реквизита моего платежного метода
|
|
68
|
+
@abstractmethod
|
|
69
|
+
async def cred_del(self, exid: int) -> int: ...
|
|
70
|
+
|
|
71
|
+
# # # Ad
|
|
72
|
+
# 29: Список моих объявлений
|
|
73
|
+
@abstractmethod
|
|
74
|
+
async def my_ads(self, status: AdStatus = None) -> list[BaseAd]: ...
|
|
75
|
+
|
|
76
|
+
# 30: Создание объявления
|
|
77
|
+
@abstractmethod
|
|
78
|
+
async def ad_new(self, ad: BaseAd) -> Ad: ...
|
|
79
|
+
|
|
80
|
+
# 31: Редактирование объявления
|
|
81
|
+
@abstractmethod
|
|
82
|
+
async def ad_upd(
|
|
83
|
+
self,
|
|
84
|
+
offer_id: int,
|
|
85
|
+
amount: int,
|
|
86
|
+
creds: list[Cred] = None,
|
|
87
|
+
price: float = None,
|
|
88
|
+
is_float: bool = None,
|
|
89
|
+
min_fiat: int = None,
|
|
90
|
+
details: str = None,
|
|
91
|
+
autoreply: str = None,
|
|
92
|
+
status: AdStatus = None,
|
|
93
|
+
) -> Ad: ...
|
|
94
|
+
|
|
95
|
+
# 32: Удаление
|
|
96
|
+
@abstractmethod
|
|
97
|
+
async def ad_del(self, ad_id: int) -> bool: ...
|
|
98
|
+
|
|
99
|
+
# 33: Вкл/выкл объявления
|
|
100
|
+
@abstractmethod
|
|
101
|
+
async def ad_switch(self, offer_id: int, active: bool) -> bool: ...
|
|
102
|
+
|
|
103
|
+
# 34: Вкл/выкл всех объявлений
|
|
104
|
+
@abstractmethod
|
|
105
|
+
async def ads_switch(self, active: bool) -> bool: ...
|
|
106
|
+
|
|
107
|
+
# # # User
|
|
108
|
+
# 35: Получить объект юзера по его ид
|
|
109
|
+
@abstractmethod
|
|
110
|
+
async def get_user(self, user_id) -> dict: ...
|
|
111
|
+
|
|
112
|
+
# 36: Отправка сообщения юзеру с приложенным файлом
|
|
113
|
+
@abstractmethod
|
|
114
|
+
async def send_user_msg(self, msg: str, file=None) -> bool: ...
|
|
115
|
+
|
|
116
|
+
# 37: (Раз)Блокировать юзера
|
|
117
|
+
@abstractmethod
|
|
118
|
+
async def block_user(self, is_blocked: bool = True) -> bool: ...
|
|
119
|
+
|
|
120
|
+
# 38: Поставить отзыв юзеру
|
|
121
|
+
@abstractmethod
|
|
122
|
+
async def rate_user(self, positive: bool) -> bool: ...
|
|
123
|
+
|
|
124
|
+
# 39: Балансы моих монет
|
|
125
|
+
@abstractmethod
|
|
126
|
+
async def my_assets(self) -> dict: ...
|
|
127
|
+
|
|
128
|
+
# Сохранение объявления (с Pm/Cred-ами) в бд
|
|
129
|
+
async def ad_pydin2db(self, ad_pydin: AdSaleIn | AdBuyIn) -> Ad:
|
|
130
|
+
ad_db = await self.ex_client.ad_pydin2db(ad_pydin)
|
|
131
|
+
await ad_db.creds.add(*getattr(ad_pydin, "creds_", []))
|
|
132
|
+
return ad_db
|
|
133
|
+
|
|
134
|
+
# @staticmethod
|
|
135
|
+
# async def cred_e2db(cred_in: BaseUpd, banks: list[str] = None) -> bool:
|
|
136
|
+
# cred_db, _ = await models.Cred.update_or_create(**cred_in.df_unq())
|
|
137
|
+
# credex_in = models.CredEx.validate({"exid": cred_in.id, "cred_id": cred_db.id})
|
|
138
|
+
# credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
|
|
139
|
+
# if banks: # only for SBP
|
|
140
|
+
# await cred_db.banks.add(*[await PmexBank.get(exid=b) for b in banks])
|
|
141
|
+
# return True
|
|
@@ -18,10 +18,11 @@ class BaseAuthTrait(Client):
|
|
|
18
18
|
# noinspection PyUnresolvedReferences
|
|
19
19
|
self.session.headers.update(auth_hdrs)
|
|
20
20
|
|
|
21
|
-
async def _post(self, url: str, data: dict = None, data_key: str = None):
|
|
21
|
+
async def _post(self, url: str, data: dict = None, data_key: str = None, headers: dict = None):
|
|
22
22
|
dt = {"json" if isinstance(data, dict) else "data": data}
|
|
23
23
|
# noinspection PyUnresolvedReferences
|
|
24
|
-
|
|
24
|
+
hdrs = {**self._prehook(data), **(headers or {})}
|
|
25
|
+
resp = await self.session.post(url, **dt, headers=hdrs)
|
|
25
26
|
return await self._proc(resp, data_key, data)
|
|
26
27
|
|
|
27
28
|
async def _proc(self, resp: ClientResponse, data_key: str = None, body: dict | str = None) -> dict | str:
|
|
@@ -8,7 +8,9 @@ from xync_schema import models
|
|
|
8
8
|
from xync_schema.types import CurEx, CoinEx, BaseAd, BaseAdIn
|
|
9
9
|
|
|
10
10
|
from xync_client.Abc.Base import BaseClient, MapOfIdsList
|
|
11
|
-
from xync_client.Abc.types import PmEx
|
|
11
|
+
from xync_client.Abc.types import PmEx
|
|
12
|
+
from xync_client.TgWallet.pyro import PyroClient
|
|
13
|
+
from xync_client.loader import bot
|
|
12
14
|
from xync_client.pm_unifier import PmUnifier, PmUni
|
|
13
15
|
|
|
14
16
|
|
|
@@ -64,6 +66,7 @@ class BaseExClient(BaseClient):
|
|
|
64
66
|
|
|
65
67
|
# Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
|
|
66
68
|
async def set_pmcurexs(self):
|
|
69
|
+
PyroClient(bot)
|
|
67
70
|
# Curs
|
|
68
71
|
cur_pyds: dict[str, CurEx] = await self.curs()
|
|
69
72
|
curs: dict[int | str, models.Cur] = {
|
|
@@ -127,11 +130,15 @@ class BaseExClient(BaseClient):
|
|
|
127
130
|
uni = self.unifier_class(cntrs)
|
|
128
131
|
for k, pm in pms_epyds.items():
|
|
129
132
|
pmu: PmUni = uni(pm.name)
|
|
130
|
-
|
|
133
|
+
country_id = (
|
|
134
|
+
await models.Country.get(name__iexact=cnt).values_list("id", flat=True)
|
|
135
|
+
if (cnt := pmu.country)
|
|
136
|
+
else None
|
|
137
|
+
)
|
|
131
138
|
if prev[2] == pm.name and pmu.country == prev[3]: # оригинальное имя не уникально на этой бирже
|
|
132
139
|
logging.warning(f"Pm: '{pm.name}' duplicated with ids {prev[0]}: {k} on {self.ex.name}")
|
|
133
140
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
134
|
-
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1],
|
|
141
|
+
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
135
142
|
# и добавляем Pmex для него
|
|
136
143
|
await models.Pmex.update_or_create({"name": pm.name}, ex=self.ex, exid=k, pm=pm_)
|
|
137
144
|
elif (
|
|
@@ -142,11 +149,30 @@ class BaseExClient(BaseClient):
|
|
|
142
149
|
)
|
|
143
150
|
# новый Pm не добавляем, только Pmex для него
|
|
144
151
|
# новый Pm не добавляем, а берем старый с этим названием
|
|
145
|
-
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1],
|
|
152
|
+
pm_ = pms.get(prev[0], await models.Pm.get_or_none(norm=prev[1], country_id=country_id))
|
|
146
153
|
# и добавляем.обновляем Pmex для него
|
|
147
154
|
await models.Pmex.update_or_create({"pm": pm_}, ex=self.ex, exid=k, name=pm.name)
|
|
148
155
|
else:
|
|
149
|
-
pmin =
|
|
156
|
+
pmin = models.Pm.validate({**pmu.model_dump(), "country_id": country_id, "typ": pm.typ})
|
|
157
|
+
# # logo
|
|
158
|
+
# if pm.logo and not await models.File.exists(name=pm.logo):
|
|
159
|
+
# if not pm.logo.startswith("https:"):
|
|
160
|
+
# if not pm.logo.startswith("/"):
|
|
161
|
+
# pm.logo = "/" + pm.logo
|
|
162
|
+
# pm.logo = "https://" + pm.logo
|
|
163
|
+
# async with ClientSession() as ss:
|
|
164
|
+
# resp = await ss.get(pm.logo)
|
|
165
|
+
# if resp.ok:
|
|
166
|
+
# byts = await resp.read()
|
|
167
|
+
# upf, ref = await pyro.save_file(byts, resp.content_type)
|
|
168
|
+
# await sleep(1)
|
|
169
|
+
# typ = FileType[resp.content_type.split("/")[-1]]
|
|
170
|
+
# file, _ = await models.File.update_or_create(
|
|
171
|
+
# {"ref": ref, "size": len(byts), "typ": typ}, name=pm.logo
|
|
172
|
+
# )
|
|
173
|
+
# # fil = await pyro.get_file(file.ref) # check
|
|
174
|
+
# pmin.logo_id = file.id
|
|
175
|
+
# # /logo
|
|
150
176
|
try:
|
|
151
177
|
pms[k], _ = await models.Pm.update_or_create(**pmin.df_unq())
|
|
152
178
|
except (MultipleObjectsReturned, IntegrityError) as e:
|
|
@@ -208,7 +234,8 @@ class BaseExClient(BaseClient):
|
|
|
208
234
|
|
|
209
235
|
# Сохранение чужого объявления (с Pm-ами) в бд
|
|
210
236
|
async def ad_pydin2db(self, ad_pydin: BaseAdIn) -> models.Ad:
|
|
211
|
-
|
|
237
|
+
ad_in = models.Ad.validate(ad_pydin.model_dump())
|
|
238
|
+
ad_db, _ = await models.Ad.update_or_create(**ad_in.df_unq())
|
|
212
239
|
if getattr(ad_pydin, "pms_", None): # if it ListItem, not Full One # todo: remove?
|
|
213
240
|
await ad_db.pms.add(*ad_pydin.pms_)
|
|
214
241
|
return ad_db
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from abc import abstractmethod
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class BaseInAgentClient:
|
|
5
|
+
def __init__(self): ...
|
|
6
|
+
|
|
7
|
+
@abstractmethod
|
|
8
|
+
async def start_listen(self) -> bool: ...
|
|
9
|
+
|
|
10
|
+
# 3N: [T] - Уведомление об одобрении запроса на сделку
|
|
11
|
+
@abstractmethod
|
|
12
|
+
async def request_accepted_notify(self) -> int: ... # id
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
from pydantic import BaseModel
|
|
2
|
-
from x_model.types import
|
|
2
|
+
from x_model.types import BaseUpd
|
|
3
3
|
from xync_schema.enums import PmType
|
|
4
4
|
from xync_schema.models import Country, Pm, Ex
|
|
5
5
|
from xync_schema.types import PmexBank
|
|
@@ -18,7 +18,7 @@ class PmEx(BaseModel, PmTrait):
|
|
|
18
18
|
name: str
|
|
19
19
|
|
|
20
20
|
|
|
21
|
-
class PmIn(
|
|
21
|
+
class PmIn(BaseUpd, PmUni, PmTrait):
|
|
22
22
|
_unq = "norm", "country"
|
|
23
23
|
country: Country | None = None
|
|
24
24
|
|
|
@@ -34,3 +34,7 @@ class PmExIn(BaseModel):
|
|
|
34
34
|
|
|
35
35
|
class Config:
|
|
36
36
|
arbitrary_types_allowed = True
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class CredExOut(BaseModel):
|
|
40
|
+
id: int
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
from typing import List, Optional, Dict, Any
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
from xync_schema.types import BaseAd
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class TradeMethod(BaseModel):
|
|
7
|
+
iconUrlColor: Optional[str] = None
|
|
8
|
+
identifier: str
|
|
9
|
+
payAccount: Optional[str] = None
|
|
10
|
+
payBank: Optional[str] = None
|
|
11
|
+
payId: Optional[str] = None
|
|
12
|
+
payMethodId: str
|
|
13
|
+
paySubBank: Optional[str] = None
|
|
14
|
+
payType: str
|
|
15
|
+
tradeMethodBgColor: str
|
|
16
|
+
tradeMethodName: str
|
|
17
|
+
tradeMethodShortName: Optional[str] = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Adv(BaseModel):
|
|
21
|
+
abnormalStatusList: Optional[List[str]] = None
|
|
22
|
+
adAdditionalKycVerifyItems: Optional[List[Any]] = None
|
|
23
|
+
adTradeInstructionTagInfoRets: Optional[List[Any]] = None
|
|
24
|
+
advNo: str
|
|
25
|
+
advStatus: Optional[str] = None
|
|
26
|
+
advUpdateTime: Optional[str] = None
|
|
27
|
+
advVisibleRet: Optional[Dict[str, Any]] = None
|
|
28
|
+
allowTradeMerchant: Optional[bool] = None
|
|
29
|
+
amountAfterEditing: Optional[str] = None
|
|
30
|
+
asset: str
|
|
31
|
+
assetLogo: Optional[str] = None
|
|
32
|
+
assetScale: int
|
|
33
|
+
assetVo: Optional[Dict[str, Any]] = None
|
|
34
|
+
autoReplyMsg: Optional[str] = None
|
|
35
|
+
buyerBtcPositionLimit: Optional[str] = None
|
|
36
|
+
buyerKycLimit: Optional[str] = None
|
|
37
|
+
buyerRegDaysLimit: Optional[str] = None
|
|
38
|
+
classify: str
|
|
39
|
+
closeReason: Optional[str] = None
|
|
40
|
+
commissionRate: str
|
|
41
|
+
createTime: Optional[str] = None
|
|
42
|
+
currencyRate: Optional[str] = None
|
|
43
|
+
dynamicMaxSingleTransAmount: str
|
|
44
|
+
dynamicMaxSingleTransQuantity: str
|
|
45
|
+
fiatScale: int
|
|
46
|
+
fiatSymbol: str
|
|
47
|
+
fiatUnit: str
|
|
48
|
+
fiatVo: Optional[Dict[str, Any]] = None
|
|
49
|
+
initAmount: Optional[str] = None
|
|
50
|
+
inventoryType: Optional[str] = None
|
|
51
|
+
invisibleReason: Optional[str] = None
|
|
52
|
+
invisibleType: Optional[str] = None
|
|
53
|
+
isSafePayment: bool
|
|
54
|
+
isTradable: bool
|
|
55
|
+
launchCountry: Optional[List[str]] = None
|
|
56
|
+
maxSingleTransAmount: str
|
|
57
|
+
maxSingleTransQuantity: str
|
|
58
|
+
minFiatAmountForAdditionalKyc: Optional[str] = None
|
|
59
|
+
minSingleTransAmount: str
|
|
60
|
+
minSingleTransQuantity: str
|
|
61
|
+
minTakerFee: Optional[str] = None
|
|
62
|
+
nonTradableRegions: Optional[List[str]] = None
|
|
63
|
+
offlineReason: Optional[str] = None
|
|
64
|
+
payTimeLimit: int
|
|
65
|
+
price: str
|
|
66
|
+
priceFloatingRatio: Optional[str] = None
|
|
67
|
+
priceScale: int
|
|
68
|
+
priceType: Optional[str] = None
|
|
69
|
+
rateFloatingRatio: Optional[str] = None
|
|
70
|
+
remarks: Optional[str] = None
|
|
71
|
+
storeInformation: Optional[Dict[str, Any]] = None
|
|
72
|
+
surplusAmount: str
|
|
73
|
+
takerAdditionalKycRequired: int
|
|
74
|
+
takerCommissionRate: Optional[str] = None
|
|
75
|
+
tradableQuantity: str
|
|
76
|
+
tradeMethodCommissionRates: Optional[List[Any]] = None
|
|
77
|
+
tradeMethods: List[TradeMethod]
|
|
78
|
+
tradeType: str
|
|
79
|
+
userAllTradeCountMax: Optional[str] = None
|
|
80
|
+
userAllTradeCountMin: Optional[str] = None
|
|
81
|
+
userBuyTradeCountMax: Optional[str] = None
|
|
82
|
+
userBuyTradeCountMin: Optional[str] = None
|
|
83
|
+
userSellTradeCountMax: Optional[str] = None
|
|
84
|
+
userSellTradeCountMin: Optional[str] = None
|
|
85
|
+
userTradeCompleteCountMin: Optional[str] = None
|
|
86
|
+
userTradeCompleteRateFilterTime: Optional[str] = None
|
|
87
|
+
userTradeCompleteRateMin: Optional[str] = None
|
|
88
|
+
userTradeCountFilterTime: Optional[str] = None
|
|
89
|
+
userTradeType: Optional[str] = None
|
|
90
|
+
userTradeVolumeAsset: Optional[str] = None
|
|
91
|
+
userTradeVolumeFilterTime: Optional[str] = None
|
|
92
|
+
userTradeVolumeMax: Optional[str] = None
|
|
93
|
+
userTradeVolumeMin: Optional[str] = None
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
class Advertiser(BaseModel):
|
|
97
|
+
activeTimeInSecond: int
|
|
98
|
+
advConfirmTime: Optional[str] = None
|
|
99
|
+
badges: Optional[List[str]] = None
|
|
100
|
+
email: Optional[str] = None
|
|
101
|
+
isBlocked: bool
|
|
102
|
+
margin: Optional[str] = None
|
|
103
|
+
marginUnit: Optional[str] = None
|
|
104
|
+
mobile: Optional[str] = None
|
|
105
|
+
monthFinishRate: float
|
|
106
|
+
monthOrderCount: int
|
|
107
|
+
nickName: str
|
|
108
|
+
orderCount: Optional[int] = None
|
|
109
|
+
positiveRate: float
|
|
110
|
+
proMerchant: Optional[Dict[str, Any]] = None
|
|
111
|
+
realName: Optional[str] = None
|
|
112
|
+
registrationTime: Optional[str] = None
|
|
113
|
+
tagIconUrls: List[str]
|
|
114
|
+
userGrade: int
|
|
115
|
+
userIdentity: str
|
|
116
|
+
userNo: str
|
|
117
|
+
userType: str
|
|
118
|
+
vipLevel: Optional[int] = None
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
class Ad(BaseAd):
|
|
122
|
+
adv: Adv
|
|
123
|
+
advertiser: Advertiser
|
|
124
|
+
privilegeDesc: Optional[str] = None
|
|
125
|
+
privilegeType: int | None = None
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
from typing import Optional
|
|
2
|
+
from pydantic import BaseModel
|
|
3
|
+
|
|
4
|
+
class PmE(BaseModel):
|
|
5
|
+
id: Optional[int] = None
|
|
6
|
+
payMethodId: str = ""
|
|
7
|
+
payAccount: Optional[str] = None
|
|
8
|
+
payBank: Optional[str] = None
|
|
9
|
+
paySubBank: Optional[str] = None
|
|
10
|
+
payType: Optional[str] = None
|
|
11
|
+
identifier: str
|
|
12
|
+
iconUrlColor: str
|
|
13
|
+
tradeMethodName: str
|
|
14
|
+
tradeMethodShortName: Optional[str] = None
|
|
15
|
+
tradeMethodBgColor: str
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from asyncio import run
|
|
2
|
+
|
|
3
|
+
from x_model import init_db
|
|
4
|
+
|
|
5
|
+
from xync_client.Abc.Ex import BaseExClient
|
|
6
|
+
from xync_client.Binance.etype import pm, ad
|
|
7
|
+
from xync_client.Abc.types import PmEx
|
|
8
|
+
from xync_client.Abc.Base import MapOfIdsList
|
|
9
|
+
from xync_client.loader import PG_DSN
|
|
10
|
+
from xync_client.pm_unifier import PmUnifier
|
|
11
|
+
|
|
12
|
+
from xync_schema.models import Ex
|
|
13
|
+
from xync_schema import types
|
|
14
|
+
from xync_schema import models
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class ExClient(BaseExClient):
|
|
18
|
+
def __init__(self, ex: Ex):
|
|
19
|
+
# self.sapi = Sapi(*bkeys)
|
|
20
|
+
super().__init__(ex)
|
|
21
|
+
|
|
22
|
+
class BinanceUnifier(PmUnifier):
|
|
23
|
+
pm_map = {"Banque de développement local (BDL)": "Banque de développement local (BDL)"}
|
|
24
|
+
|
|
25
|
+
unifier_class = BinanceUnifier
|
|
26
|
+
|
|
27
|
+
async def _pms(self, cur) -> list[pm.PmE]:
|
|
28
|
+
json_data = {
|
|
29
|
+
"fiat": cur,
|
|
30
|
+
"classifies": [
|
|
31
|
+
"mass",
|
|
32
|
+
"profession",
|
|
33
|
+
"fiat_trade",
|
|
34
|
+
],
|
|
35
|
+
}
|
|
36
|
+
pms = await self._post("/bapi/c2c/v2/public/c2c/adv/filter-conditions", data=json_data)
|
|
37
|
+
return [pm.PmE(**_pm) for _pm in pms["data"]["tradeMethods"]]
|
|
38
|
+
|
|
39
|
+
async def curs(self) -> dict[int, types.CurEx]:
|
|
40
|
+
curs = await self._post("/bapi/c2c/v1/friendly/c2c/trade-rule/fiat-list")
|
|
41
|
+
return {c["currencyCode"]: types.CurEx(exid=c["currencyCode"], ticker=c["currencyCode"], scale=c["currencyScale"]) for c in curs["data"]}
|
|
42
|
+
|
|
43
|
+
async def coins(self) -> dict[int, types.CoinEx]:
|
|
44
|
+
for cur in (await self.curs()).keys():
|
|
45
|
+
coins = (await self._post("/bapi/c2c/v2/friendly/c2c/portal/config", {"fiat": cur}))["data"]["areas"][0][
|
|
46
|
+
"tradeSides"
|
|
47
|
+
][0]["assets"]
|
|
48
|
+
return {coin["asset"]: types.CoinEx(exid=coin["asset"], ticker=coin["asset"]) for coin in coins}
|
|
49
|
+
|
|
50
|
+
async def pairs(self) -> MapOfIdsList:
|
|
51
|
+
coins = (await self.coins()).keys()
|
|
52
|
+
curs = (await self.curs()).keys()
|
|
53
|
+
p = {cur: {c for c in coins} for cur in curs}
|
|
54
|
+
return p, p
|
|
55
|
+
|
|
56
|
+
async def pms(self, cur: models.Cur = None) -> dict[int | str, PmEx]:
|
|
57
|
+
all_pms = {}
|
|
58
|
+
for cur in (await self.curs()).values():
|
|
59
|
+
pms = await self._pms(cur.ticker)
|
|
60
|
+
for p in pms:
|
|
61
|
+
all_pms[p.identifier] = PmEx(exid=p.identifier, name=p.tradeMethodName, logo=p.iconUrlColor)
|
|
62
|
+
return all_pms
|
|
63
|
+
|
|
64
|
+
# 22: Cur -> [Pm] rels
|
|
65
|
+
async def cur_pms_map(self) -> MapOfIdsList: # {cur.exid: [pm.exid], [pm.exid]}
|
|
66
|
+
res = await self.curs()
|
|
67
|
+
mp = {c: await self._get_pms_for_cur(c) for c in res.keys()}
|
|
68
|
+
return mp
|
|
69
|
+
|
|
70
|
+
# # 22: Cur -> [Pm] rels
|
|
71
|
+
# async def cur_countries_map(self) -> dict[int, set[int]]: # {cur.exid: [pm.exid]}
|
|
72
|
+
# res = await self._get_pms_and_country_for_cur()
|
|
73
|
+
# wrong_pms = {4, 34, 212, 239, 363, 498, 548, 20009, 20010} # these ids not exist in pms
|
|
74
|
+
# return {c['currencyId']: set(c['supportPayments']) - wrong_pms for c in res['currency'] if c["supportPayments"]}
|
|
75
|
+
|
|
76
|
+
async def ads(self, coin_exid: str, cur_exid: str, is_sell: bool, pm_exids: list[str] = None) -> list[ad.Ad]:
|
|
77
|
+
data = {
|
|
78
|
+
"fiat": cur_exid,
|
|
79
|
+
"page": 1,
|
|
80
|
+
"rows": 10,
|
|
81
|
+
"tradeType": "BUY" if is_sell else "SELL",
|
|
82
|
+
"asset": coin_exid,
|
|
83
|
+
"countries": [],
|
|
84
|
+
"proMerchantAds": False,
|
|
85
|
+
"shieldMerchantAds": False,
|
|
86
|
+
"filterType": "all",
|
|
87
|
+
"periods": [],
|
|
88
|
+
"additionalKycVerifyFilter": 0,
|
|
89
|
+
"publisherType": "merchant",
|
|
90
|
+
"payTypes": pm_exids,
|
|
91
|
+
"classifies": [
|
|
92
|
+
"mass",
|
|
93
|
+
"profession",
|
|
94
|
+
"fiat_trade",
|
|
95
|
+
],
|
|
96
|
+
"tradedWith": False,
|
|
97
|
+
"followed": False,
|
|
98
|
+
}
|
|
99
|
+
ads = await self._post("/bapi/c2c/v2/friendly/c2c/adv/search", data=data)
|
|
100
|
+
return [ad.Ad(id=_ad["adv"]["advNo"], price=_ad["adv"]["price"], **_ad) for _ad in ads["data"]]
|
|
101
|
+
|
|
102
|
+
async def _get_pms_for_cur(self, cur: str) -> ([str], [str]):
|
|
103
|
+
data = {"fiat": cur, "classifies": ["mass", "profession"]}
|
|
104
|
+
res = await self._post("/bapi/c2c/v2/public/c2c/adv/filter-conditions", data)
|
|
105
|
+
return [r["identifier"] for r in res["data"]["tradeMethods"]]
|
|
106
|
+
# , [
|
|
107
|
+
# r["scode"] for r in res["data"]["countries"] if r["scode"] != "ALL"
|
|
108
|
+
# ] # countries,tradeMethods,periods
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
# class Private(Public): # todo: base class: Public or Client?
|
|
112
|
+
# class Private(Client):
|
|
113
|
+
# # auth: dict =
|
|
114
|
+
# headers: dict = {
|
|
115
|
+
# "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36",
|
|
116
|
+
# "Content-Type": "application/json",
|
|
117
|
+
# "clienttype": "web",
|
|
118
|
+
# }
|
|
119
|
+
#
|
|
120
|
+
# def seq_headers(self):
|
|
121
|
+
# return {
|
|
122
|
+
# "csrftoken": self.auth["tok"],
|
|
123
|
+
# "cookie": f'p20t=web.{self.id}.{self.auth["cook"]}',
|
|
124
|
+
# }
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
async def main():
|
|
128
|
+
_ = await init_db(PG_DSN, models)
|
|
129
|
+
ex = await Ex.get(name="Binance")
|
|
130
|
+
cl = ExClient(ex)
|
|
131
|
+
await cl.pairs()
|
|
132
|
+
await cl.pms()
|
|
133
|
+
await cl.ads("ETH", "GEL", False)
|
|
134
|
+
await cl.set_pmcurexs()
|
|
135
|
+
await cl.close()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
if __name__ == "__main__":
|
|
139
|
+
run(main())
|
|
@@ -30,6 +30,15 @@ class ExClient(BaseExClient):
|
|
|
30
30
|
"accept-language": "ru,en;q=0.9",
|
|
31
31
|
"content-type": "application/json;charset=UTF-8",
|
|
32
32
|
"deviceid": "883e1394d8a2278418b6f02804df16c4",
|
|
33
|
+
"devicelanguage": "ru_RU",
|
|
34
|
+
"gaclientid": "2005612572.1744132981",
|
|
35
|
+
"securitynew": "true",
|
|
36
|
+
"terminalcode": "534488ac72b9b87c3ba87725387639ac",
|
|
37
|
+
"terminaltype": "1",
|
|
38
|
+
"timezone": "GMT+03:00",
|
|
39
|
+
"tm": "1744133012568",
|
|
40
|
+
"uhti": "w17441330126555b55e2d8627",
|
|
41
|
+
"usenewpwdversion": "true",
|
|
33
42
|
}
|
|
34
43
|
|
|
35
44
|
async def _coin_cur_pms(self, trying: int = 0) -> dict:
|
|
@@ -52,12 +61,25 @@ class ExClient(BaseExClient):
|
|
|
52
61
|
|
|
53
62
|
async def curs(self) -> dict[str, types.CurEx]:
|
|
54
63
|
curs = (await self._coin_cur_pms())["fiatInfoRespList"]
|
|
55
|
-
return {
|
|
64
|
+
return {
|
|
65
|
+
cur["fiatCode"]: types.CurEx(
|
|
66
|
+
exid=cur["fiatCode"],
|
|
67
|
+
ticker=cur["fiatCode"],
|
|
68
|
+
scale=cur["fiatPrecision"],
|
|
69
|
+
minimum=int(float(cur["orderMinLimit"])),
|
|
70
|
+
)
|
|
71
|
+
for cur in curs
|
|
72
|
+
}
|
|
56
73
|
|
|
57
74
|
async def coins(self) -> dict[str, types.CoinEx]:
|
|
58
75
|
coins: list[dict] = (await self._coin_cur_pms())["coinInfoRespList"]
|
|
59
76
|
return {
|
|
60
|
-
coin["coinCode"]: types.CoinEx(
|
|
77
|
+
coin["coinCode"]: types.CoinEx(
|
|
78
|
+
exid=coin["coinCode"],
|
|
79
|
+
ticker=coin["coinCode"],
|
|
80
|
+
scale=coin["coinPrecision"],
|
|
81
|
+
minimum=int(float(coin["orderMinLimit"])),
|
|
82
|
+
)
|
|
61
83
|
for coin in coins
|
|
62
84
|
}
|
|
63
85
|
|
|
@@ -72,7 +94,7 @@ class ExClient(BaseExClient):
|
|
|
72
94
|
pms: list[dict] = (await self._coin_cur_pms())["fiatInfoRespList"]
|
|
73
95
|
for pm in pms:
|
|
74
96
|
for p in pm["paymethodInfo"]:
|
|
75
|
-
pp[p["paymethodId"]] = PmEx(exid=p["paymethodId"], name=p["paymethodName"])
|
|
97
|
+
pp[p["paymethodId"]] = PmEx(exid=p["paymethodId"], name=p["paymethodName"], logo=p.get("iconUrl"))
|
|
76
98
|
return pp
|
|
77
99
|
|
|
78
100
|
async def ads(
|