xync-client 0.0.25.dev0__tar.gz → 0.0.25.dev3__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.dev0/xync_client.egg-info → xync_client-0.0.25.dev3}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/README.md +7 -1
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/Agent.py +1 -1
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/Ex.py +30 -16
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BitGet/ex.py +2 -2
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/agent.py +10 -25
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/ex.py +52 -27
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/pyd.py +15 -5
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3/xync_client.egg-info}/PKG-INFO +1 -1
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client.egg-info/SOURCES.txt +0 -1
- xync_client-0.0.25.dev0/xync_client/pyd.py +0 -71
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/.env.sample +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/.gitignore +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/makefile +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/pyproject.toml +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/setup.cfg +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/TestAgent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/TestAsset.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/TestEx.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/TestOrder.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Htx/test_htx_p2p.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/AuthTrait.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/Base.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/InAgent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BingX/test/main.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/BitGet/req.mjs +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Bybit/agent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Bybit/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Htx/agent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Htx/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/KuCoin/pub.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/pyro.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/__init__.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client/loader.py +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -136,6 +136,8 @@ classDef red stroke:#f00
|
|
|
136
136
|
- 22: Список торгуемых монет (с ограничениям по валютам, если есть) `coins() => [Coin]`
|
|
137
137
|
- 23: Список пар валюта/монет `pairs() => [Pair]`
|
|
138
138
|
- 24: Список объяв по (buy/sell, cur, coin, pm) `ads(coin: Coin, cur: Cur, is_sell: bool, pms:list[Pm]=None)`
|
|
139
|
+
- 42: Минимальные объемы валют в объявлении `cur_mins() => FlatDict`
|
|
140
|
+
- 43: Минимальные объемы монет в объявлении `coin_mins() => FlatDict`
|
|
139
141
|
|
|
140
142
|
### Fiat
|
|
141
143
|
- 25: Список реквизитов моих платежных методов `my_fiats(cur:Cur=None) => [Fiat]`
|
|
@@ -162,4 +164,8 @@ classDef red stroke:#f00
|
|
|
162
164
|
- 38N: Получение уведомления о полученном отзыве `got_rated => (user_id:int, order_id:int)`
|
|
163
165
|
|
|
164
166
|
### Assets
|
|
165
|
-
-
|
|
167
|
+
- 41: Получить балансы моих монет: `my_assets() => list[Asset]`
|
|
168
|
+
- 40: Получить реквизиты для депозита монеты `deposit(amount: int) => bool`
|
|
169
|
+
- 40N: Получена монета `deposited => amount`
|
|
170
|
+
- 41: Вывести монету `withdraw(amount: int) => bool`
|
|
171
|
+
- 41N: Монета выведена `withdrew => amount`
|
|
@@ -83,7 +83,7 @@ class BaseAgentClient(BaseClient, BaseAuthTrait): # todo: inherit form Base or
|
|
|
83
83
|
|
|
84
84
|
# 25: Список реквизитов моих платежных методов
|
|
85
85
|
@abstractmethod
|
|
86
|
-
async def fiats(self
|
|
86
|
+
async def fiats(self) -> ListOfDicts: ... # {fiat.exid: {fiat}}
|
|
87
87
|
|
|
88
88
|
@staticmethod
|
|
89
89
|
async def fiat_pyd2db(fiat_pyd: FiatNew | FiatUpd, uid: int, fid: int = None) -> tuple[Fiat, bool]:
|
|
@@ -2,7 +2,8 @@ import logging
|
|
|
2
2
|
import re
|
|
3
3
|
from abc import abstractmethod
|
|
4
4
|
|
|
5
|
-
from
|
|
5
|
+
from xync_schema.pydantic import AdPydIn, PmPyd
|
|
6
|
+
|
|
6
7
|
from xync_schema.models import Ex, Coin, Cur, Pm, Pmex, Curex, Pmcur, Pmcurex, Coinex, PmexBank, Ad
|
|
7
8
|
|
|
8
9
|
from xync_client.Abc.Base import BaseClient, DictOfDicts, FlatDict, ListOfDicts, MapOfIdsList
|
|
@@ -33,7 +34,7 @@ class BaseExClient(BaseClient):
|
|
|
33
34
|
|
|
34
35
|
# 20: Список платежных методов
|
|
35
36
|
@abstractmethod
|
|
36
|
-
async def pms(self, cur: Cur = None) -> dict[int | str,
|
|
37
|
+
async def pms(self, cur: Cur = None) -> dict[int | str, PmPyd]: # {pm.exid: pm}
|
|
37
38
|
...
|
|
38
39
|
|
|
39
40
|
# 21: Список платежных методов по каждой валюте
|
|
@@ -117,9 +118,18 @@ class BaseExClient(BaseClient):
|
|
|
117
118
|
s = remove(rm_rgxps, s, True)
|
|
118
119
|
return s.replace(" ", "")
|
|
119
120
|
|
|
121
|
+
# 42: Минимальные объемы валют в объявлении
|
|
122
|
+
@abstractmethod
|
|
123
|
+
async def cur_mins(self) -> FlatDict: ...
|
|
124
|
+
|
|
125
|
+
# 43: Минимальные объемы монет в объявлении
|
|
126
|
+
@abstractmethod
|
|
127
|
+
async def coin_mins(self) -> FlatDict: ...
|
|
128
|
+
|
|
129
|
+
# Импорт Pm-ов (с Pmcur-, Pmex- и Pmcurex-ами) и валют (с Curex-ами) с биржи в бд
|
|
120
130
|
async def set_pmcurexs(self):
|
|
121
131
|
# Pms
|
|
122
|
-
pms_epyds: dict[int | str,
|
|
132
|
+
pms_epyds: dict[int | str, PmPyd] = {
|
|
123
133
|
k: v for k, v in sorted((await self.pms()).items(), key=lambda x: x[1].name)
|
|
124
134
|
} # sort by name
|
|
125
135
|
pms: dict[int | str, Pm] = dict({})
|
|
@@ -129,11 +139,9 @@ class BaseExClient(BaseClient):
|
|
|
129
139
|
if prev[1:] == (norm, pm.name):
|
|
130
140
|
logging.warning(f"Pm: '{pm.name}' duplicated with ids {prev[0]}: {k} on {self.ex.name}")
|
|
131
141
|
pm_ = pms.get(prev[0], (await Pm.get_or_none(name=prev[2])) or await Pm.get_or_none(identifier=prev[1]))
|
|
132
|
-
await Pmex.update_or_create({"pm": pm_}, ex=self.ex, exid=k
|
|
142
|
+
await Pmex.update_or_create({"pm": pm_, "name": pm.name}, ex=self.ex, exid=k)
|
|
133
143
|
elif prev[1] == norm:
|
|
134
|
-
logging.error(
|
|
135
|
-
f"Pm: '{pm.name}' & '{prev[2]}' overnormd as '{norm}' with ids {prev[0]}: {k} on {self.ex.name}"
|
|
136
|
-
)
|
|
144
|
+
logging.error(f"Pm: {pm.name}&{prev[2]} overnormd as {norm} with ids {prev[0]}: {k} on {self.ex.name}")
|
|
137
145
|
await Pmex.update_or_create(
|
|
138
146
|
{"pm": pms.get(prev[0], await Pm.get(name=prev[2]))}, ex=self.ex, exid=k, name=pm.name
|
|
139
147
|
)
|
|
@@ -146,16 +154,17 @@ class BaseExClient(BaseClient):
|
|
|
146
154
|
# Pmex banks
|
|
147
155
|
for k, pm in pms_epyds.items():
|
|
148
156
|
if banks := pm.banks:
|
|
149
|
-
pmex = await Pmex.get(
|
|
157
|
+
pmex = await Pmex.get(ex=self.ex, exid=k) # pm=pms[k],
|
|
150
158
|
for b in banks:
|
|
151
|
-
await PmexBank.update_or_create({"name": b.name}, exid=b.
|
|
159
|
+
await PmexBank.update_or_create({"name": b.name}, exid=b.exid, pmex=pmex)
|
|
152
160
|
|
|
153
161
|
# Curs
|
|
154
162
|
cursd = await self.curs()
|
|
155
163
|
curs: {int: Cur} = {k: (await Cur.update_or_create(ticker=c))[0] for k, c in cursd.items()}
|
|
156
164
|
# Curex
|
|
157
|
-
|
|
158
|
-
|
|
165
|
+
cur_mins = await self.cur_mins()
|
|
166
|
+
curexs = [Curex(cur=c, ex=self.ex, exid=k, minimum=cur_mins[k]) for k, c in curs.items()] # , p2p=True
|
|
167
|
+
await Curex.bulk_create(curexs, update_fields=["minimum"], on_conflict=["cur_id", "ex_id"])
|
|
159
168
|
|
|
160
169
|
cur2pms = await self.cur_pms_map()
|
|
161
170
|
# # Link PayMethods with currencies
|
|
@@ -173,12 +182,17 @@ class BaseExClient(BaseClient):
|
|
|
173
182
|
pmcurexs = [Pmcurex(pmcur=pmcur, ex=self.ex) for pmcur in pmcurs]
|
|
174
183
|
await Pmcurex.bulk_create(pmcurexs)
|
|
175
184
|
|
|
185
|
+
# Импорт монет (с Coinex-ами) с биржи в бд
|
|
176
186
|
async def set_coinexs(self):
|
|
177
187
|
res = await self.coins()
|
|
178
188
|
coins: dict[int, Coin] = {k: (await Coin.update_or_create(ticker=c))[0] for k, c in res.items()}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
189
|
+
coin_mins = await self.coin_mins()
|
|
190
|
+
coinexs: list[Coinex] = [Coinex(coin=c, ex=self.ex, exid=k, minimum=coin_mins[k]) for k, c in coins.items()]
|
|
191
|
+
await Coinex.bulk_create(coinexs, update_fields=["minimum"], on_conflict=["coin_id", "ex_id"])
|
|
192
|
+
|
|
193
|
+
# Сохранение чужого объявления (с Pm-ами) в бд
|
|
194
|
+
@staticmethod
|
|
195
|
+
async def set_ad(ad: AdPydIn) -> Ad:
|
|
196
|
+
ad_db, _ = await Ad.update_or_create(ad.model_dump(exclude_none=True), id=ad.id)
|
|
197
|
+
await ad_db.pms.add(*ad.payMeths)
|
|
184
198
|
return ad_db
|
|
@@ -72,8 +72,8 @@ class ExClient(BaseExClient):
|
|
|
72
72
|
result.append(
|
|
73
73
|
{
|
|
74
74
|
"price": float(slot["priceValue"]),
|
|
75
|
-
"
|
|
76
|
-
"
|
|
75
|
+
"min_fiat": float(slot["minAmount"]),
|
|
76
|
+
"max_fiat": float(min(slot["maxAmount"], slot["amount"])),
|
|
77
77
|
"user": int(slot["userId"]) if slot["userId"] else None,
|
|
78
78
|
"pms": [int(pay_method["paymethodId"]) for pay_method in slot["paymethodInfo"]],
|
|
79
79
|
}
|
|
@@ -2,19 +2,10 @@ from asyncio import run
|
|
|
2
2
|
from enum import StrEnum
|
|
3
3
|
|
|
4
4
|
from x_model import init_db, HTTPException, FailReason
|
|
5
|
+
from xync_client.pyd import FiatXpyd
|
|
5
6
|
from xync_schema import models
|
|
6
7
|
|
|
7
|
-
from xync_client.TgWallet.pyd import
|
|
8
|
-
Banks,
|
|
9
|
-
FiatEpyd,
|
|
10
|
-
Attrs,
|
|
11
|
-
AttrsV2,
|
|
12
|
-
MyAdEPydSale,
|
|
13
|
-
MyAdEPydPurchase,
|
|
14
|
-
AdEpydInPurchase,
|
|
15
|
-
AdEpydInSale,
|
|
16
|
-
AdEPyd,
|
|
17
|
-
)
|
|
8
|
+
from xync_client.TgWallet.pyd import Banks, FiatEpyd, Attrs, AttrsV2, MyAdInPurchaseEpyd, MyAdInSaleEpyd, AdFullEpyd
|
|
18
9
|
from xync_client.loader import PG_DSN
|
|
19
10
|
from xync_schema.enums import AdStatus
|
|
20
11
|
|
|
@@ -25,7 +16,6 @@ from xync_schema.pydantic import FiatNew
|
|
|
25
16
|
|
|
26
17
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
27
18
|
from xync_client.TgWallet.ex import ExClient
|
|
28
|
-
from xync_client.pyd import FiatXn
|
|
29
19
|
|
|
30
20
|
|
|
31
21
|
class Exceptions(StrEnum):
|
|
@@ -50,11 +40,6 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
50
40
|
)
|
|
51
41
|
return order["data"]
|
|
52
42
|
|
|
53
|
-
# 0: Получение ордера по ид
|
|
54
|
-
async def settings(self) -> ListOfDicts:
|
|
55
|
-
settings = await self._post("/p2p/public-api/v2/offer/settings/get")
|
|
56
|
-
return settings["data"]
|
|
57
|
-
|
|
58
43
|
# 0: Получение ордера по ид
|
|
59
44
|
async def order(self, oid) -> ListOfDicts:
|
|
60
45
|
orders = await self._post("/p2p/public-api/v2/offer/order/get", {"orderId": oid})
|
|
@@ -64,8 +49,8 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
64
49
|
async def order_request(self, ad_id: int, amount: float) -> dict | bool:
|
|
65
50
|
await self.agent.fetch_related("ex", "ex__agents")
|
|
66
51
|
ex_client: ExClient = self.agent.ex.client()
|
|
67
|
-
ad:
|
|
68
|
-
fiats = await self.
|
|
52
|
+
ad: AdFullEpyd = await ex_client.ad(ad_id=ad_id)
|
|
53
|
+
fiats = await self.fiats()
|
|
69
54
|
fiats_pms = {fiat["paymentMethod"]["code"]: fiat["id"] for fiat in fiats.values()}
|
|
70
55
|
if not (pms := ad.get("paymentMethods")):
|
|
71
56
|
print(ad)
|
|
@@ -128,18 +113,18 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
128
113
|
}
|
|
129
114
|
|
|
130
115
|
# 25: Список реквизитов моих платежных методов
|
|
131
|
-
async def fiats(self
|
|
116
|
+
async def fiats(self) -> list[FiatEpyd]:
|
|
132
117
|
resp = await self._post("/p2p/public-api/v3/payment-details/get/by-user-id")
|
|
133
118
|
return [FiatEpyd(**fiat) for fiat in resp["data"]]
|
|
134
119
|
|
|
135
|
-
async def fiat_epyd2xpyd(self, fiat: FiatEpyd) ->
|
|
120
|
+
async def fiat_epyd2xpyd(self, fiat: FiatEpyd) -> FiatXpyd:
|
|
136
121
|
if not (pmex := await Pmex.get_or_none(exid=fiat.paymentMethod.code, ex=self.agent.ex)):
|
|
137
122
|
raise HTTPException(FailReason.body, f"No Pmex {fiat.paymentMethod.code} on ex#{self.agent.ex.name}", 404)
|
|
138
123
|
if not (pmcur := await Pmcur.get_or_none(cur__ticker=fiat.currency, pm_id=pmex.pm_id)):
|
|
139
124
|
raise HTTPException(
|
|
140
125
|
FailReason.body, f"No Pmcur with cur#{fiat.currency} and pm#{fiat.paymentMethod.code}", 404
|
|
141
126
|
)
|
|
142
|
-
ftx =
|
|
127
|
+
ftx = FiatXpyd(
|
|
143
128
|
id=fiat.id,
|
|
144
129
|
detail="",
|
|
145
130
|
name=fiat.name,
|
|
@@ -232,7 +217,7 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
232
217
|
)
|
|
233
218
|
return (
|
|
234
219
|
[
|
|
235
|
-
|
|
220
|
+
MyAdEpydSale(**ad) if ad["type"] == "SALE" else MyAdEpydPurchase(**ad)
|
|
236
221
|
for ad in ads["data"]
|
|
237
222
|
if not status or (status and ad["status"] == mapping[status])
|
|
238
223
|
]
|
|
@@ -241,7 +226,7 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
241
226
|
)
|
|
242
227
|
|
|
243
228
|
# 30: Создание объявления
|
|
244
|
-
async def ad_new(self, ad:
|
|
229
|
+
async def ad_new(self, ad: MyAdInPurchaseEpyd | MyAdInSaleEpyd) -> Ad:
|
|
245
230
|
# coin: Coin,
|
|
246
231
|
# cur: str,
|
|
247
232
|
# is_sell: bool,
|
|
@@ -255,7 +240,7 @@ class AgentClient(BaseAgentClient, AuthClient):
|
|
|
255
240
|
# status: AdStatus = AdStatus.active,
|
|
256
241
|
# ) -> Ad.pyd():
|
|
257
242
|
dct = {
|
|
258
|
-
"type":
|
|
243
|
+
"type": ad.type,
|
|
259
244
|
"initVolume": {"currencyCode": coin, "amount": amount},
|
|
260
245
|
"orderRoundingRequired": True,
|
|
261
246
|
"price": {
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
from asyncio import run
|
|
2
|
+
|
|
2
3
|
from x_model import init_db
|
|
3
|
-
from
|
|
4
|
+
from xync_schema.pydantic import AdPydIn, PmPyd, PmexBankPyd
|
|
4
5
|
|
|
5
6
|
from xync_schema import models
|
|
6
|
-
from xync_schema.models import Ex, Agent, Direction, Pair, Coin, Cur
|
|
7
|
+
from xync_schema.models import Ex, Agent, Direction, Pair, Coin, Cur, Pm
|
|
7
8
|
|
|
8
|
-
from xync_client.TgWallet.pyd import AdFullEpyd, AdEpyd
|
|
9
|
+
from xync_client.TgWallet.pyd import AdFullEpyd, AdEpyd, PmEpydRoot
|
|
9
10
|
from xync_client.loader import PG_DSN
|
|
10
11
|
from xync_client.Abc.Ex import BaseExClient
|
|
11
|
-
from xync_client.Abc.Base import FlatDict,
|
|
12
|
+
from xync_client.Abc.Base import FlatDict, MapOfIdsList
|
|
12
13
|
from xync_client.TgWallet.auth import AuthClient
|
|
13
14
|
|
|
14
15
|
|
|
@@ -17,23 +18,42 @@ class ExClient(BaseExClient, AuthClient):
|
|
|
17
18
|
self.agent: Agent = [ag for ag in ex.agents if ag.auth][0] # need for AuthTrait
|
|
18
19
|
super().__init__(ex) # , "host_p2p"
|
|
19
20
|
|
|
21
|
+
# 00: todo: min-max for cur and coin ad amount, order, fee ..
|
|
22
|
+
async def _settings(self) -> dict:
|
|
23
|
+
settings = await self._post("/p2p/public-api/v2/offer/settings/get")
|
|
24
|
+
return settings["data"]
|
|
25
|
+
|
|
26
|
+
async def cur_mins(self) -> FlatDict:
|
|
27
|
+
stg = await self._settings()
|
|
28
|
+
return stg["offerSettings"]["minOrderAmountByCurrencyCode"]
|
|
29
|
+
|
|
30
|
+
async def coin_mins(self) -> FlatDict:
|
|
31
|
+
stg = await self._settings()
|
|
32
|
+
lims = list(stg["offerSettings"]["offerVolumeLimitsPerMarket"].values())
|
|
33
|
+
coins = {k: max(float(v[k]["minInclusive"]) for v in lims) for k, v in lims[0].items()}
|
|
34
|
+
return coins
|
|
35
|
+
|
|
20
36
|
# 19: Список поддерживаемых валют тейкера
|
|
21
37
|
async def curs(self) -> FlatDict:
|
|
22
38
|
coins_curs = await self._post("/p2p/public-api/v2/currency/all-supported")
|
|
23
39
|
return {c["code"]: c["code"] for c in coins_curs["data"]["fiat"]}
|
|
24
40
|
|
|
25
|
-
async def _pms(self, cur: str) -> dict[str,
|
|
41
|
+
async def _pms(self, cur: str) -> dict[str, PmEpydRoot]:
|
|
26
42
|
pms = await self._post("/p2p/public-api/v3/payment-details/get-methods/by-currency-code", {"currencyCode": cur})
|
|
27
|
-
return {pm["code"]:
|
|
43
|
+
return {pm["code"]: PmEpydRoot(**pm) for pm in pms["data"]}
|
|
28
44
|
|
|
29
|
-
# 20: Список платежных
|
|
30
|
-
async def pms(self, cur: str = None) ->
|
|
45
|
+
# 20: Список платежных методов. todo: refact to pmexs?
|
|
46
|
+
async def pms(self, cur: str = None) -> dict[str, PmPyd]:
|
|
47
|
+
pms: dict[str:PmEpydRoot] = {}
|
|
31
48
|
if cur:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
return
|
|
49
|
+
pms = await self._pms(cur)
|
|
50
|
+
else:
|
|
51
|
+
for cur in await self.curs():
|
|
52
|
+
pms |= await self._pms(cur)
|
|
53
|
+
return {
|
|
54
|
+
k: PmPyd(name=pm.nameEng, banks=[PmexBankPyd(exid=b.code, name=b.name) for b in pm.banks or []])
|
|
55
|
+
for k, pm in pms.items()
|
|
56
|
+
}
|
|
37
57
|
|
|
38
58
|
# 21: Список платежных методов по каждой валюте
|
|
39
59
|
async def cur_pms_map(self) -> MapOfIdsList:
|
|
@@ -51,9 +71,9 @@ class ExClient(BaseExClient, AuthClient):
|
|
|
51
71
|
pairs = {cur: set(coins.values()) for cur in curs.values()}
|
|
52
72
|
return pairs
|
|
53
73
|
|
|
54
|
-
async def
|
|
55
|
-
|
|
56
|
-
return AdFullEpyd(**
|
|
74
|
+
async def ad(self, ad_id: int) -> AdFullEpyd:
|
|
75
|
+
ad = await self._post("/p2p/public-api/v2/offer/get", {"offerId": ad_id})
|
|
76
|
+
return AdFullEpyd(**ad["data"])
|
|
57
77
|
|
|
58
78
|
# 24: Список объяв по (buy/sell, cur, coin, pm)
|
|
59
79
|
async def ads(
|
|
@@ -70,39 +90,44 @@ class ExClient(BaseExClient, AuthClient):
|
|
|
70
90
|
ads = await self._post("/p2p/public-api/v2/offer/depth-of-market/", params, "data")
|
|
71
91
|
return [AdEpyd(**ad) for ad in ads]
|
|
72
92
|
|
|
73
|
-
async def ad_epyd2xpyd(self, ad: AdEpyd | AdFullEpyd) ->
|
|
93
|
+
async def ad_epyd2xpyd(self, ad: AdEpyd | AdFullEpyd) -> AdPydIn:
|
|
74
94
|
coin = await Coin.get_or_create_by_name(ad.price.baseCurrencyCode)
|
|
75
95
|
cur = await Cur.get_or_create_by_name(ad.price.quoteCurrencyCode)
|
|
76
96
|
pair, _ = await Pair.get_or_create(coin=coin, cur=cur, ex=self.ex)
|
|
77
97
|
dr, _ = await Direction.get_or_create(pair=pair, sell=ad.is_sell)
|
|
78
98
|
maker, _ = await Agent.get_or_create(exid=ad.user.userId, ex=self.ex)
|
|
79
|
-
|
|
99
|
+
|
|
100
|
+
adx = AdPydIn(
|
|
80
101
|
id=ad.id,
|
|
81
102
|
price=ad.price.value,
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
103
|
+
min_fiat=ad.orderAmountLimits.min,
|
|
104
|
+
max_fiat=ad.orderAmountLimits.max,
|
|
105
|
+
direction=dr,
|
|
106
|
+
agent=maker,
|
|
86
107
|
detail=getattr(ad, "comment", None),
|
|
108
|
+
payMeths=await Pm.filter(pmexs__ex=self.agent.ex, pmexs__exid__in=[p.code for p in ad.paymentMethods]),
|
|
109
|
+
# todo: maybe later adpm_banks
|
|
87
110
|
)
|
|
88
111
|
return adx
|
|
89
112
|
|
|
90
113
|
|
|
91
|
-
async def
|
|
114
|
+
async def _test():
|
|
92
115
|
await init_db(PG_DSN, models, True)
|
|
93
116
|
tgex = await Ex.get(name="TgWallet").prefetch_related("agents", "agents__ex")
|
|
94
117
|
cl: ExClient = tgex.client()
|
|
118
|
+
await cl.pms("RUB")
|
|
95
119
|
await cl.set_pmcurexs()
|
|
96
120
|
await cl.set_coinexs()
|
|
97
121
|
ads: list[AdEpyd] = await cl.ads("USDT", "RUB", False)
|
|
98
|
-
ad: AdFullEpyd = await cl.
|
|
99
|
-
adx:
|
|
122
|
+
ad: AdFullEpyd = await cl.ad(ads[0].id)
|
|
123
|
+
adx: AdPydIn = await cl.ad_epyd2xpyd(ad)
|
|
100
124
|
await cl.set_ad(adx)
|
|
125
|
+
ads: list[AdEpyd] = await cl.ads("USDT", "RUB", True)
|
|
101
126
|
ad: AdEpyd = ads[1]
|
|
102
|
-
adx:
|
|
127
|
+
adx: AdPydIn = await cl.ad_epyd2xpyd(ad)
|
|
103
128
|
await cl.set_ad(adx)
|
|
104
129
|
await cl.close()
|
|
105
130
|
|
|
106
131
|
|
|
107
132
|
if __name__ == "__main__":
|
|
108
|
-
run(
|
|
133
|
+
run(_test())
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
from typing import Literal
|
|
2
2
|
from pydantic import BaseModel
|
|
3
|
-
from xync_client.pyd import PayMeth
|
|
4
3
|
|
|
5
4
|
|
|
6
5
|
class UserStatistics(BaseModel):
|
|
@@ -100,6 +99,17 @@ class AttrsV2(AttrsV2In):
|
|
|
100
99
|
values: list[KeyVal | Banks]
|
|
101
100
|
|
|
102
101
|
|
|
102
|
+
class PmEpyd(BaseModel):
|
|
103
|
+
code: str
|
|
104
|
+
name: str
|
|
105
|
+
originNameLocale: str
|
|
106
|
+
nameEng: str
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class PmEpydRoot(PmEpyd):
|
|
110
|
+
banks: list[PmEpyd] | None = None
|
|
111
|
+
|
|
112
|
+
|
|
103
113
|
class FiatPydIn(BaseModel):
|
|
104
114
|
paymentMethodCode: str
|
|
105
115
|
currencyCode: str
|
|
@@ -110,7 +120,7 @@ class FiatPydIn(BaseModel):
|
|
|
110
120
|
class FiatEpyd(BaseModel):
|
|
111
121
|
id: int
|
|
112
122
|
userId: int
|
|
113
|
-
paymentMethod:
|
|
123
|
+
paymentMethod: PmEpydRoot
|
|
114
124
|
currency: str
|
|
115
125
|
name: str = ""
|
|
116
126
|
attributes: Attrs | AttrsV2
|
|
@@ -122,7 +132,7 @@ class InitVolume(BaseModel):
|
|
|
122
132
|
|
|
123
133
|
|
|
124
134
|
class _PaymentMethodsTrait:
|
|
125
|
-
paymentMethods: list[
|
|
135
|
+
paymentMethods: list[PmEpydRoot]
|
|
126
136
|
|
|
127
137
|
|
|
128
138
|
class __BaseCommonAd(BaseModel):
|
|
@@ -132,7 +142,7 @@ class __BaseCommonAd(BaseModel):
|
|
|
132
142
|
|
|
133
143
|
|
|
134
144
|
class _MyAdEpydIn(__BaseCommonAd):
|
|
135
|
-
|
|
145
|
+
orderConfirmationTimeout: Literal["PT3M", "PT15M"]
|
|
136
146
|
comment: str
|
|
137
147
|
initVolume: InitVolume
|
|
138
148
|
orderRoundingRequired: bool
|
|
@@ -167,7 +177,7 @@ class AdFullEpyd(AdEpyd):
|
|
|
167
177
|
status: Literal["ACTIVE", "INACTIVE", "ACTIVATING"]
|
|
168
178
|
createDateTime: str
|
|
169
179
|
comment: str
|
|
170
|
-
orderConfirmationTimeout: Literal["PT3M"]
|
|
180
|
+
orderConfirmationTimeout: Literal["PT3M", "PT15M"]
|
|
171
181
|
orderAcceptTimeout: Literal["PT10M"]
|
|
172
182
|
|
|
173
183
|
|
|
@@ -19,7 +19,6 @@ tests/_todo_refact/Wallet/test_agent.py
|
|
|
19
19
|
tests/_todo_refact/Wallet/test_ex.py
|
|
20
20
|
xync_client/__init__.py
|
|
21
21
|
xync_client/loader.py
|
|
22
|
-
xync_client/pyd.py
|
|
23
22
|
xync_client.egg-info/PKG-INFO
|
|
24
23
|
xync_client.egg-info/SOURCES.txt
|
|
25
24
|
xync_client.egg-info/dependency_links.txt
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
from pydantic import BaseModel, model_validator
|
|
2
|
-
from xync_schema.enums import AdStatus
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
class PayMeth(BaseModel):
|
|
6
|
-
code: str
|
|
7
|
-
name: str
|
|
8
|
-
originNameLocale: str
|
|
9
|
-
nameEng: str
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
class PmXpyd(BaseModel):
|
|
13
|
-
id: int | None = None
|
|
14
|
-
name: str
|
|
15
|
-
logo: str | None = None
|
|
16
|
-
banks: list[PayMeth] | None = None # todo: refact excess data in banks
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
class PmcurXpyd(BaseModel):
|
|
20
|
-
pm_id: int
|
|
21
|
-
cur_id: int
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
class FiatXpyd(BaseModel):
|
|
25
|
-
# unq
|
|
26
|
-
id: int = None
|
|
27
|
-
user_id: int
|
|
28
|
-
pmcur_id: int | None = None
|
|
29
|
-
pmcur: PmcurXpyd | None = None
|
|
30
|
-
# df
|
|
31
|
-
detail: str
|
|
32
|
-
name: str = ""
|
|
33
|
-
amount: float
|
|
34
|
-
target: float | None = None
|
|
35
|
-
|
|
36
|
-
banks: list[str] = []
|
|
37
|
-
|
|
38
|
-
@classmethod
|
|
39
|
-
@model_validator(mode="before")
|
|
40
|
-
def check_at_least_one_field(cls, values):
|
|
41
|
-
if values.get("pmcur") or values.get("pmcur_id"):
|
|
42
|
-
return values
|
|
43
|
-
raise ValueError("pmcur_id or pmcur is required")
|
|
44
|
-
|
|
45
|
-
def args(self) -> tuple[dict, dict]:
|
|
46
|
-
unq: tuple[str, ...] = "id", "user_id", "pmcur_id", "pmcur"
|
|
47
|
-
df: tuple[str, ...] = "detail", "name", "amount", "target"
|
|
48
|
-
|
|
49
|
-
d = self.model_dump()
|
|
50
|
-
return {k: getattr(self, k) for k in df if d.get(k)}, {k: getattr(self, k) for k in unq if d.get(k)}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
class AdInXpyd(BaseModel):
|
|
54
|
-
# unq
|
|
55
|
-
id: int
|
|
56
|
-
# df
|
|
57
|
-
price: float
|
|
58
|
-
minFiat: float
|
|
59
|
-
maxFiat: float | None = None
|
|
60
|
-
detail: str | None = None
|
|
61
|
-
autoMsg: str | None = None
|
|
62
|
-
status: AdStatus = AdStatus.active
|
|
63
|
-
agent_id: int
|
|
64
|
-
direction_id: int
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
class FiatexXpyd(BaseModel):
|
|
68
|
-
id: int | None = None
|
|
69
|
-
exid: str
|
|
70
|
-
ex_id: int
|
|
71
|
-
fiat_id: int
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Binance/test_binance.py
RENAMED
|
File without changes
|
|
File without changes
|
{xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/tests/_todo_refact/Bybit/test_bybit_p2p.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{xync_client-0.0.25.dev0 → xync_client-0.0.25.dev3}/xync_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|