xync-client 0.0.11.dev14__tar.gz → 0.0.11.dev18__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.11.dev14/xync_client.egg-info → xync_client-0.0.11.dev18}/PKG-INFO +1 -1
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/README.md +2 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/pyproject.toml +1 -1
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Abc/BaseTest.py +8 -5
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/TestEx.py +7 -5
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Abc/Agent.py +8 -3
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/base.py +3 -1
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/ex.py +2 -1
- xync_client-0.0.11.dev14/xync_client/Bybit/ex.py → xync_client-0.0.11.dev18/xync_client/Bybit/agent.py +28 -59
- xync_client-0.0.11.dev18/xync_client/Bybit/ex.py +64 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Gate/ex.py +24 -19
- xync_client-0.0.11.dev18/xync_client/Htx/agent.py +115 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Htx/ex.py +3 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/auth.py +2 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18/xync_client.egg-info}/PKG-INFO +1 -1
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client.egg-info/SOURCES.txt +1 -0
- xync_client-0.0.11.dev14/xync_client/Htx/agent.py +0 -18
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/.env.sample +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/.gitignore +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/makefile +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/setup.cfg +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Abc/AgentTest.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Abc/OrderTest.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Binance/test_binance.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Gate/test_gate.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/Htx/test_htx_p2p.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/__init__.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/tests/_test_ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Abc/Auth.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Abc/Base.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Abc/Ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BingX/test/main.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/BitGet/req.mjs +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/KuCoin/pub.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/agent.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/ex.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/pyro.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/__init__.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client/loader.py +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.11.dev14 → xync_client-0.0.11.dev18}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -159,3 +159,5 @@ classDef red stroke:#f00
|
|
|
159
159
|
- 36N: Получение сообщения от юзера `get_user_msg => (msg:str, file=None)`
|
|
160
160
|
- 37N: Получение уведомления о (раз)блокировке юзером `got_blocked => is_blocked:bool`
|
|
161
161
|
- 38N: Получение уведомления о полученном отзыве `got_rated => (user_id:int, order_id:int)`
|
|
162
|
+
|
|
163
|
+
- 39: Получить балансы моих монет: `my_assets() => list[Asset]`
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
|
-
|
|
2
|
+
|
|
3
|
+
# from asyncio import AbstractEventLoop
|
|
3
4
|
from typing import TypeGuard
|
|
4
5
|
|
|
5
6
|
import pytest
|
|
7
|
+
|
|
8
|
+
# import uvloop
|
|
6
9
|
from tortoise.backends.asyncpg import AsyncpgDBClient
|
|
7
10
|
from x_model import init_db
|
|
8
11
|
from xync_client.Abc.Base import BaseClient, DictOfDicts, ListOfDicts, FlatDict, MapOfIdsList
|
|
@@ -12,20 +15,20 @@ from xync_client.loader import PG_DSN
|
|
|
12
15
|
|
|
13
16
|
|
|
14
17
|
class BaseTest:
|
|
15
|
-
loop: AbstractEventLoop
|
|
18
|
+
# loop: AbstractEventLoop
|
|
16
19
|
|
|
17
|
-
# @pytest.fixture(scope="
|
|
20
|
+
# @pytest.fixture(scope="session", autouse=True)
|
|
18
21
|
# def event_loop_policy(self):
|
|
19
22
|
# return uvloop.EventLoopPolicy()
|
|
20
23
|
|
|
21
|
-
@pytest.fixture(scope="
|
|
24
|
+
@pytest.fixture(scope="session", autouse=True)
|
|
22
25
|
async def cn(self) -> AsyncpgDBClient:
|
|
23
26
|
cn: AsyncpgDBClient = await init_db(PG_DSN, models, True)
|
|
24
27
|
yield cn
|
|
25
28
|
await cn.close()
|
|
26
29
|
|
|
27
30
|
@abstractmethod
|
|
28
|
-
@pytest.fixture(scope="
|
|
31
|
+
@pytest.fixture(scope="session")
|
|
29
32
|
async def clients(self) -> list[BaseClient]: ...
|
|
30
33
|
|
|
31
34
|
@staticmethod
|
|
@@ -2,15 +2,16 @@ import logging
|
|
|
2
2
|
|
|
3
3
|
import pytest
|
|
4
4
|
from xync_schema.enums import ExStatus, ExType, ExAction
|
|
5
|
-
from xync_schema.models import Ex, TestEx as
|
|
5
|
+
from xync_schema.models import Ex, TestEx as ExTest
|
|
6
6
|
|
|
7
7
|
from tests.Abc.BaseTest import BaseTest
|
|
8
8
|
from xync_client.Abc.Base import BaseClient, DictOfDicts, FlatDict
|
|
9
9
|
from xync_client.Abc.Ex import BaseExClient
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
@pytest.mark.asyncio(loop_scope="session")
|
|
12
13
|
class TestEx(BaseTest):
|
|
13
|
-
@pytest.fixture
|
|
14
|
+
@pytest.fixture
|
|
14
15
|
async def clients(self) -> list[BaseClient]:
|
|
15
16
|
exs = await Ex.filter(status__gt=ExStatus.plan)
|
|
16
17
|
[await ex.fetch_related("agents") for ex in exs if ex.type_ == ExType.tg]
|
|
@@ -22,7 +23,7 @@ class TestEx(BaseTest):
|
|
|
22
23
|
async def test_pms(self, clients: list[BaseExClient]):
|
|
23
24
|
for client in clients:
|
|
24
25
|
pms: DictOfDicts = await client.pms()
|
|
25
|
-
t, _ = await
|
|
26
|
+
t, _ = await ExTest.update_or_create({"ok": self.is_dict_of_dicts(pms)}, ex=client.ex, action=ExAction.pms)
|
|
26
27
|
assert t.ok, "No pms"
|
|
27
28
|
logging.info(f"{client.ex.name}:{ExAction.pms.name} - ok")
|
|
28
29
|
|
|
@@ -30,7 +31,8 @@ class TestEx(BaseTest):
|
|
|
30
31
|
async def test_curs(self, clients: list[BaseExClient]):
|
|
31
32
|
for client in clients:
|
|
32
33
|
curs: FlatDict = await client.curs()
|
|
33
|
-
|
|
34
|
+
ok = self.is_flat_dict(curs)
|
|
35
|
+
t, _ = await ExTest.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.curs)
|
|
34
36
|
assert t.ok, "No curs"
|
|
35
37
|
logging.info(f"{client.ex.name}:{ExAction.pms.name} - ok")
|
|
36
38
|
|
|
@@ -39,6 +41,6 @@ class TestEx(BaseTest):
|
|
|
39
41
|
for client in clients:
|
|
40
42
|
cur_pms: DictOfDicts = await client.cur_pms_map()
|
|
41
43
|
ok = self.is_dict_of_dicts(cur_pms)
|
|
42
|
-
t, _ = await
|
|
44
|
+
t, _ = await ExTest.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.cur_pms_map)
|
|
43
45
|
assert t.ok, "No pms for cur"
|
|
44
46
|
logging.info(f"{client.ex.name}:{ExAction.pms.name} - ok")
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
|
|
3
|
+
from xync_client.Abc.Base import ListOfDicts
|
|
4
|
+
|
|
3
5
|
from xync_client.Abc.Auth import BaseAuthClient
|
|
4
|
-
from xync_schema.enums import PmType
|
|
5
6
|
from xync_schema.models import OrderStatus, Coin, Cur, Order, Pm, Ad, AdStatus, Fiat
|
|
6
7
|
from xync_schema.pydantic import FiatNew
|
|
7
8
|
|
|
@@ -23,7 +24,7 @@ class BaseAgentClient(BaseAuthClient):
|
|
|
23
24
|
# # # Fiat
|
|
24
25
|
# 25: Список реквизитов моих платежных методов
|
|
25
26
|
@abstractmethod
|
|
26
|
-
async def my_fiats(self, cur: Cur = None) ->
|
|
27
|
+
async def my_fiats(self, cur: Cur = None) -> ListOfDicts: ...
|
|
27
28
|
|
|
28
29
|
# 26: Создание
|
|
29
30
|
@abstractmethod
|
|
@@ -31,7 +32,7 @@ class BaseAgentClient(BaseAuthClient):
|
|
|
31
32
|
|
|
32
33
|
# 27: Редактирование
|
|
33
34
|
@abstractmethod
|
|
34
|
-
async def fiat_upd(self, detail: str
|
|
35
|
+
async def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> bool: ...
|
|
35
36
|
|
|
36
37
|
# 28: Удаление
|
|
37
38
|
@abstractmethod
|
|
@@ -99,3 +100,7 @@ class BaseAgentClient(BaseAuthClient):
|
|
|
99
100
|
# 38: Поставить отзыв юзеру
|
|
100
101
|
@abstractmethod
|
|
101
102
|
async def rate_user(self, positive: bool) -> bool: ...
|
|
103
|
+
|
|
104
|
+
# 39: Балансы моих монет
|
|
105
|
+
@abstractmethod
|
|
106
|
+
async def my_assets(self) -> dict: ...
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import os
|
|
1
2
|
import subprocess
|
|
2
3
|
from datetime import datetime
|
|
3
4
|
from json import dumps
|
|
@@ -11,7 +12,8 @@ class BaseBingXClient(BaseClient):
|
|
|
11
12
|
traceid = str(uuid4()).replace("-", "")
|
|
12
13
|
now = str(int(datetime.now().timestamp() * 1000))
|
|
13
14
|
payload = dumps(_payload, separators=(",", ":"), sort_keys=True) if _payload else "{}"
|
|
14
|
-
|
|
15
|
+
pref = "../xync_client/BingX/" if os.getcwd().split("/")[-1] == "tests" else ""
|
|
16
|
+
p = subprocess.Popen(["node", pref + "req.mjs", now, traceid, payload], stdout=subprocess.PIPE)
|
|
15
17
|
sign = p.stdout.read().decode().strip()
|
|
16
18
|
return {
|
|
17
19
|
"sign": sign,
|
|
@@ -2,8 +2,10 @@ from enum import IntEnum
|
|
|
2
2
|
from time import sleep
|
|
3
3
|
|
|
4
4
|
import pyotp
|
|
5
|
-
from
|
|
5
|
+
from xync_client.Abc.Base import FlatDict
|
|
6
|
+
from xync_schema.models import Cur
|
|
6
7
|
|
|
8
|
+
from xync_client.Abc.Agent import BaseAgentClient
|
|
7
9
|
from xync_client.loader import BYT2FA
|
|
8
10
|
|
|
9
11
|
|
|
@@ -16,10 +18,9 @@ class AdsStatus(IntEnum):
|
|
|
16
18
|
WORKING = 1
|
|
17
19
|
|
|
18
20
|
|
|
19
|
-
class ExClient(
|
|
21
|
+
class ExClient(BaseAgentClient): # Bybit client
|
|
20
22
|
host = "api2.bybit.com"
|
|
21
|
-
|
|
22
|
-
pub_header = {"cookie": ";"} # rewrite token for public methods
|
|
23
|
+
headers = {"cookie": ";"} # rewrite token for public methods
|
|
23
24
|
|
|
24
25
|
last_ad_id: list[str] = []
|
|
25
26
|
create_ad_body = {
|
|
@@ -79,49 +80,15 @@ class ExClient(Client): # Bybit client
|
|
|
79
80
|
"securityRiskToken": "",
|
|
80
81
|
}
|
|
81
82
|
|
|
82
|
-
""" PUBLIC METHS """
|
|
83
|
-
|
|
84
|
-
def get_ads(self, coin: str, cur: str, sell: bool = False, amount: int = None, payment: list[str] = None) -> list:
|
|
85
|
-
data = {
|
|
86
|
-
"userId": "",
|
|
87
|
-
"tokenId": coin,
|
|
88
|
-
"currencyId": cur,
|
|
89
|
-
"payment": payment or [],
|
|
90
|
-
"side": "0" if sell else "1",
|
|
91
|
-
"size": "10",
|
|
92
|
-
"page": "1",
|
|
93
|
-
"amount": str(amount) if amount else "",
|
|
94
|
-
"authMaker": False,
|
|
95
|
-
"canTrade": False,
|
|
96
|
-
}
|
|
97
|
-
ads = self._post("/fiat/otc/item/online/", data, self.pub_header)
|
|
98
|
-
return ads["result"]["items"]
|
|
99
|
-
|
|
100
|
-
async def get_config(self):
|
|
101
|
-
resp = await self._get("/fiat/p2p/config/initial", self.pub_header)
|
|
102
|
-
return resp["result"] # todo: tokens, pairs, ...
|
|
103
|
-
|
|
104
|
-
async def curs(self):
|
|
105
|
-
config = await self.get_config()
|
|
106
|
-
return config["symbols"]
|
|
107
|
-
|
|
108
|
-
def get_coins(self):
|
|
109
|
-
coins = self._get("/spot/api/basic/symbol_list", self.pub_header)
|
|
110
|
-
return coins
|
|
111
|
-
|
|
112
|
-
def get_payment_methods(self):
|
|
113
|
-
pms = self._post("/fiat/otc/configuration/queryAllPaymentList/", headers=self.pub_header)
|
|
114
|
-
return pms
|
|
115
|
-
|
|
116
83
|
""" Private METHs"""
|
|
117
84
|
|
|
118
|
-
def
|
|
85
|
+
def fiat_new(self, payment_type: int, real_name: str, account_number: str) -> FlatDict:
|
|
119
86
|
method1 = self._post(
|
|
120
87
|
"/fiat/otc/user/payment/new_create",
|
|
121
88
|
{"paymentType": payment_type, "realName": real_name, "accountNo": account_number, "securityRiskToken": ""},
|
|
122
89
|
)
|
|
123
90
|
if srt := method1["result"]["securityRiskToken"]:
|
|
124
|
-
self.
|
|
91
|
+
self._check_2fa(srt)
|
|
125
92
|
method2 = self._post(
|
|
126
93
|
"/fiat/otc/user/payment/new_create",
|
|
127
94
|
{
|
|
@@ -142,24 +109,26 @@ class ExClient(Client): # Bybit client
|
|
|
142
109
|
return fiat
|
|
143
110
|
return list_methods[1]
|
|
144
111
|
|
|
145
|
-
|
|
112
|
+
# 27
|
|
113
|
+
def fiat_upd(self, fiat_id: int, detail: str, name: str = None) -> dict:
|
|
146
114
|
fiat = self.get_payment_method(fiat_id)
|
|
147
|
-
fiat["realName"] =
|
|
148
|
-
fiat["accountNo"] =
|
|
149
|
-
result = self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
115
|
+
fiat["realName"] = name
|
|
116
|
+
fiat["accountNo"] = detail
|
|
117
|
+
result = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
150
118
|
srt = result["result"]["securityRiskToken"]
|
|
151
|
-
self.
|
|
119
|
+
self._check_2fa(srt)
|
|
152
120
|
fiat["securityRiskToken"] = srt
|
|
153
|
-
result2 = self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
121
|
+
result2 = await self._post("/fiat/otc/user/payment/new_update", fiat)
|
|
154
122
|
return result2
|
|
155
123
|
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
124
|
+
# 28
|
|
125
|
+
def fiat_del(self, fiat_id: int) -> dict:
|
|
126
|
+
data = {"id": fiat_id, "securityRiskToken": ""}
|
|
127
|
+
method = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
159
128
|
srt = method["result"]["securityRiskToken"]
|
|
160
|
-
self.
|
|
129
|
+
self._check_2fa(srt)
|
|
161
130
|
data["securityRiskToken"] = srt
|
|
162
|
-
delete = self._post("/fiat/otc/user/payment/new_delete", data)
|
|
131
|
+
delete = await self._post("/fiat/otc/user/payment/new_delete", data)
|
|
163
132
|
return delete
|
|
164
133
|
|
|
165
134
|
def switch_ads(self, new_status: AdsStatus) -> dict:
|
|
@@ -176,8 +145,8 @@ class ExClient(Client): # Bybit client
|
|
|
176
145
|
ads = [ad for ad in list_ads if set(ad["payments"]) - {"5", "51"}]
|
|
177
146
|
return float(ads[0]["price"])
|
|
178
147
|
|
|
179
|
-
def
|
|
180
|
-
upm = self._post("/fiat/otc/user/payment/list")
|
|
148
|
+
def my_fiats(self, cur: Cur = None):
|
|
149
|
+
upm = await self._post("/fiat/otc/user/payment/list")
|
|
181
150
|
return upm["result"]
|
|
182
151
|
|
|
183
152
|
def get_user_ads(self, active: bool = True) -> list:
|
|
@@ -191,7 +160,7 @@ class ExClient(Client): # Bybit client
|
|
|
191
160
|
security_risk_token = data["result"]["securityRiskToken"]
|
|
192
161
|
return security_risk_token
|
|
193
162
|
|
|
194
|
-
def
|
|
163
|
+
def _check_2fa(self, risk_token):
|
|
195
164
|
# 2fa code
|
|
196
165
|
bybit_secret = BYT2FA
|
|
197
166
|
totp = pyotp.TOTP(bybit_secret)
|
|
@@ -203,7 +172,7 @@ class ExClient(Client): # Bybit client
|
|
|
203
172
|
if res["ret_msg"] != "success":
|
|
204
173
|
print("Wrong 2fa, wait 5 secs and retry..")
|
|
205
174
|
sleep(5)
|
|
206
|
-
self.
|
|
175
|
+
self._check_2fa(risk_token)
|
|
207
176
|
return res
|
|
208
177
|
|
|
209
178
|
def post_ad(self, risk_token: str):
|
|
@@ -213,8 +182,8 @@ class ExClient(Client): # Bybit client
|
|
|
213
182
|
|
|
214
183
|
# создание объявлений
|
|
215
184
|
def post_create_ad(self, token: str):
|
|
216
|
-
|
|
217
|
-
assert
|
|
185
|
+
result__check_2fa = self._check_2fa(token)
|
|
186
|
+
assert result__check_2fa["ret_msg"] == "success", "2FA code wrong"
|
|
218
187
|
|
|
219
188
|
result_add_ad = self._post_ad(token)
|
|
220
189
|
if result_add_ad["ret_msg"] != "SUCCESS":
|
|
@@ -230,8 +199,8 @@ class ExClient(Client): # Bybit client
|
|
|
230
199
|
return security_risk_token
|
|
231
200
|
|
|
232
201
|
def post_update_ad(self, token):
|
|
233
|
-
|
|
234
|
-
assert
|
|
202
|
+
result__check_2fa = self._check_2fa(token)
|
|
203
|
+
assert result__check_2fa["ret_msg"] == "success", "2FA code wrong"
|
|
235
204
|
|
|
236
205
|
result_update_ad = self.update_ad(token)
|
|
237
206
|
if result_update_ad["ret_msg"] != "SUCCESS":
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import json
|
|
2
|
+
from enum import IntEnum
|
|
3
|
+
|
|
4
|
+
from xync_client.Abc.Base import ListOfDicts, MapOfIdsList, DictOfDicts, FlatDict
|
|
5
|
+
from xync_client.Abc.Ex import BaseExClient
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class AdsStatus(IntEnum):
|
|
9
|
+
REST = 0
|
|
10
|
+
WORKING = 1
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class ExClient(BaseExClient): # Bybit client
|
|
14
|
+
host = "api2.bybit.com"
|
|
15
|
+
headers = {"cookie": ";"} # rewrite token for public methods
|
|
16
|
+
|
|
17
|
+
async def _get_config(self):
|
|
18
|
+
resp = await self._get("/fiat/p2p/config/initial")
|
|
19
|
+
return resp["result"] # todo: tokens, pairs, ...
|
|
20
|
+
|
|
21
|
+
# 20: Список всех платежных методов на бирже
|
|
22
|
+
async def pms(self) -> DictOfDicts:
|
|
23
|
+
pms = await self._post("/fiat/otc/configuration/queryAllPaymentList/")
|
|
24
|
+
pms = pms["result"]["paymentConfigVo"]
|
|
25
|
+
return {
|
|
26
|
+
pm["paymentType"]: {
|
|
27
|
+
"name": pm["paymentName"],
|
|
28
|
+
}
|
|
29
|
+
for pm in pms
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
# 21: Список поддерживаемых валют
|
|
33
|
+
async def curs(self) -> FlatDict:
|
|
34
|
+
config = await self._get_config()
|
|
35
|
+
return {c["id"]: c["currencyId"] for c in config["symbols"]}
|
|
36
|
+
|
|
37
|
+
# 22: Список платежных методов по каждой валюте
|
|
38
|
+
async def cur_pms_map(self) -> MapOfIdsList:
|
|
39
|
+
pms = await self._post("/fiat/otc/configuration/queryAllPaymentList/")
|
|
40
|
+
return json.loads(pms["result"]["currencyPaymentIdMap"])
|
|
41
|
+
|
|
42
|
+
# 23: Список торгуемых монет (с ограничениям по валютам, если есть)
|
|
43
|
+
async def coins(self) -> FlatDict:
|
|
44
|
+
coins = await self._get("/spot/api/basic/symbol_list")
|
|
45
|
+
return coins
|
|
46
|
+
|
|
47
|
+
# 24: Список объяв по (buy/sell, cur, coin, pm)
|
|
48
|
+
async def ads(
|
|
49
|
+
self, coin_exid: str, cur_exid: str, is_sell: bool, pm_exids: list[str | int] = None, amount: int = None
|
|
50
|
+
) -> ListOfDicts:
|
|
51
|
+
data = {
|
|
52
|
+
"userId": "",
|
|
53
|
+
"tokenId": coin_exid,
|
|
54
|
+
"currencyId": cur_exid,
|
|
55
|
+
"payment": pm_exids or [],
|
|
56
|
+
"side": "0" if is_sell else "1",
|
|
57
|
+
"size": "10",
|
|
58
|
+
"page": "1",
|
|
59
|
+
"amount": str(amount) if amount else "",
|
|
60
|
+
"authMaker": False,
|
|
61
|
+
"canTrade": False,
|
|
62
|
+
}
|
|
63
|
+
ads = await self._post("/fiat/otc/item/online/", data)
|
|
64
|
+
return ads["result"]["items"]
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import re
|
|
2
|
-
from asyncio import run
|
|
2
|
+
from asyncio import run, sleep
|
|
3
3
|
from json import JSONDecoder
|
|
4
4
|
|
|
5
5
|
from bs4 import BeautifulSoup, Script
|
|
6
6
|
from x_model import init_db
|
|
7
7
|
from xync_schema import models
|
|
8
|
-
from xync_schema.models import Coin, Cur, Pm, Ad, Ex
|
|
8
|
+
from xync_schema.models import Coin, Cur, Pm, Ad, Ex
|
|
9
9
|
|
|
10
|
-
from xync_client.Abc.Base import MapOfIdsList
|
|
10
|
+
from xync_client.Abc.Base import MapOfIdsList, DictOfDicts, FlatDict
|
|
11
11
|
from xync_client.Abc.Ex import BaseExClient
|
|
12
12
|
from xync_client.loader import PG_DSN
|
|
13
13
|
|
|
@@ -16,19 +16,19 @@ class ExClient(BaseExClient):
|
|
|
16
16
|
async def cur_pms_map(self) -> MapOfIdsList:
|
|
17
17
|
pass
|
|
18
18
|
|
|
19
|
-
async def curs(self) ->
|
|
19
|
+
async def curs(self) -> FlatDict:
|
|
20
20
|
curs = await self._post("/json_svr/buy_crypto_fiat_setting")
|
|
21
|
-
curs = [cur["fiat"] for cur in curs if cur["p2p"]
|
|
22
|
-
curexs = [Curex(cur=c, ex=self.ex) for c in curs]
|
|
23
|
-
await Curex.bulk_create(curexs, ignore_conflicts=True)
|
|
21
|
+
curs = {cur["fiat"]: cur["fiat"] for cur in curs["datas"] if cur["p2p"]}
|
|
24
22
|
return curs
|
|
25
23
|
|
|
26
24
|
async def coins(self, cur: Cur = None) -> list[Coin]: ...
|
|
27
25
|
|
|
28
|
-
async def pms(self, cur: Cur = None) ->
|
|
26
|
+
async def pms(self, cur: Cur = None) -> DictOfDicts:
|
|
27
|
+
await sleep(1)
|
|
29
28
|
doc = await self._get("/p2p")
|
|
29
|
+
await sleep(1)
|
|
30
30
|
soup = BeautifulSoup(doc, "html.parser")
|
|
31
|
-
script: Script = soup.body.find_all("script")[
|
|
31
|
+
script: Script = soup.body.find_all("script")[17] # 17-th not stable
|
|
32
32
|
strng = (
|
|
33
33
|
script.get_text(strip=True)
|
|
34
34
|
.replace("\n", "")
|
|
@@ -43,15 +43,19 @@ class ExClient(BaseExClient):
|
|
|
43
43
|
pattern = r"payment_settings:\s{1}(\{.*?\}),paymentIdMap:"
|
|
44
44
|
match = re.search(pattern, strng.replace(",}", "}").replace(",]", "]"), re.DOTALL)
|
|
45
45
|
res = match.group(1)
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
for
|
|
46
|
+
pms = JSONDecoder(strict=False).decode(res)
|
|
47
|
+
return {
|
|
48
|
+
pm["index"]: {"name": pm["pay_name"], "logo": pm["image"], "identifier": idf, "type_": pm["base_type"]}
|
|
49
|
+
for idf, pm in pms.items()
|
|
50
50
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
# pmcurs = {
|
|
52
|
+
# cur.ticker: (await self._get("/v3/c2c/configs/receipt/templates", {"quoteCurrency": cur.ticker}))["data"]
|
|
53
|
+
# for cur in await self.curs()
|
|
54
|
+
# }
|
|
55
|
+
# pp = {}
|
|
56
|
+
# [[pp.update({p["paymentMethod"]: p["paymentMethodDescription"]}) for p in ps] for ps in pmcurs.values()]
|
|
57
|
+
# pp = {k: v for k, v in sorted(pp.items(), key=lambda x: x[0])}
|
|
58
|
+
# return pp
|
|
55
59
|
|
|
56
60
|
async def ads(self, coin: Coin, cur: Cur, is_sell: bool, pms: list[Pm] = None) -> list[Ad]:
|
|
57
61
|
pass
|
|
@@ -61,9 +65,10 @@ async def main():
|
|
|
61
65
|
_ = await init_db(PG_DSN, models, True)
|
|
62
66
|
bg = await Ex.get(name="Gate")
|
|
63
67
|
cl = ExClient(bg)
|
|
64
|
-
|
|
68
|
+
await cl.curs()
|
|
65
69
|
# await cl.coins()
|
|
66
|
-
await cl.pms()
|
|
70
|
+
pms = await cl.pms()
|
|
71
|
+
print(pms)
|
|
67
72
|
|
|
68
73
|
|
|
69
74
|
if __name__ == "__main__":
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
from x_client.aiohttp import Client
|
|
2
|
+
from xync_schema.enums import AdStatus, PmType, OrderStatus
|
|
3
|
+
from xync_schema.models import Pm, Coin, Cur, Ad, Fiat, Order
|
|
4
|
+
from xync_schema.pydantic import FiatNew
|
|
5
|
+
|
|
6
|
+
from xync_client.Abc.Agent import BaseAgentClient
|
|
7
|
+
|
|
8
|
+
url_ads_req = "https://otc-cf.huobi.com/v1/data/trade-market"
|
|
9
|
+
url_ads_web = "https://www.huobi.com/en-us/fiat-crypto/trade/"
|
|
10
|
+
url_my_ads = "https://otc-api.trygofast.com/v1/data/trade-list?pageSize=50"
|
|
11
|
+
url_my_ad = "https://www.huobi.com/-/x/otc/v1/otc/trade/" # + id
|
|
12
|
+
url_my_bals = "https://www.huobi.com/-/x/otc/v1/capital/balance"
|
|
13
|
+
url_paccs = "https://www.huobi.com/-/x/otc/v1/user/receipt-account"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class Public(Client):
|
|
17
|
+
url_ads_web = "https://www.huobi.com/en-us/fiat-crypto/trade/"
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Private(BaseAgentClient):
|
|
21
|
+
# 0
|
|
22
|
+
async def get_orders(
|
|
23
|
+
self, stauts: OrderStatus = OrderStatus.created, coin: Coin = None, cur: Cur = None, is_sell: bool = None
|
|
24
|
+
) -> list[Order]:
|
|
25
|
+
pass
|
|
26
|
+
|
|
27
|
+
async def order_request(self, ad_id: int, amount: float) -> dict:
|
|
28
|
+
pass
|
|
29
|
+
|
|
30
|
+
async def my_fiats(self, cur: Cur = None) -> list[dict]:
|
|
31
|
+
pass
|
|
32
|
+
|
|
33
|
+
async def fiat_new(self, fiat: FiatNew) -> Fiat.pyd():
|
|
34
|
+
pass
|
|
35
|
+
|
|
36
|
+
async def fiat_upd(self, detail: str = None, type_: PmType = None) -> bool:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
async def fiat_del(self, fiat_id: int) -> bool:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
async def my_ads(self) -> list[dict]:
|
|
43
|
+
res = await self._get(url_my_ads)
|
|
44
|
+
ads: [] = res["data"]
|
|
45
|
+
if (pages := res["totalPage"]) > 1:
|
|
46
|
+
for p in range(2, pages + 1):
|
|
47
|
+
ads += (await self._get(url_my_ads, {"currPage": p})).get("data", False)
|
|
48
|
+
return ads
|
|
49
|
+
|
|
50
|
+
async def ad_new(
|
|
51
|
+
self,
|
|
52
|
+
coin: Coin,
|
|
53
|
+
cur: Cur,
|
|
54
|
+
is_sell: bool,
|
|
55
|
+
pms: list[Pm],
|
|
56
|
+
price: float,
|
|
57
|
+
is_float: bool = True,
|
|
58
|
+
min_fiat: int = None,
|
|
59
|
+
details: str = None,
|
|
60
|
+
autoreply: str = None,
|
|
61
|
+
status: AdStatus = AdStatus.active,
|
|
62
|
+
) -> Ad:
|
|
63
|
+
pass
|
|
64
|
+
|
|
65
|
+
async def ad_upd(
|
|
66
|
+
self,
|
|
67
|
+
pms: [Pm] = None,
|
|
68
|
+
price: float = None,
|
|
69
|
+
is_float: bool = None,
|
|
70
|
+
min_fiat: int = None,
|
|
71
|
+
details: str = None,
|
|
72
|
+
autoreply: str = None,
|
|
73
|
+
status: AdStatus = None,
|
|
74
|
+
) -> bool:
|
|
75
|
+
pass
|
|
76
|
+
|
|
77
|
+
async def ad_del(self) -> bool:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
async def ad_switch(self) -> bool:
|
|
81
|
+
pass
|
|
82
|
+
|
|
83
|
+
async def ads_switch(self) -> bool:
|
|
84
|
+
pass
|
|
85
|
+
|
|
86
|
+
async def get_user(self, user_id) -> dict:
|
|
87
|
+
pass
|
|
88
|
+
|
|
89
|
+
async def send_user_msg(self, msg: str, file=None) -> bool:
|
|
90
|
+
pass
|
|
91
|
+
|
|
92
|
+
async def block_user(self, is_blocked: bool = True) -> bool:
|
|
93
|
+
pass
|
|
94
|
+
|
|
95
|
+
async def rate_user(self, positive: bool) -> bool:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
# 39
|
|
99
|
+
async def my_assets(self) -> dict:
|
|
100
|
+
assets = await self._get(url_my_bals)
|
|
101
|
+
return {c["coinId"]: c["total"] for c in assets["data"] if c["total"]}
|
|
102
|
+
|
|
103
|
+
async def _get_auth_hdrs(self) -> dict[str, str]:
|
|
104
|
+
pass
|
|
105
|
+
|
|
106
|
+
base_url = ""
|
|
107
|
+
middle_url = ""
|
|
108
|
+
|
|
109
|
+
htok: str = "Ev5lFfAvxDU2MA9BJ-Mc4U6zZG3Wb6qsp3Tx2fz6GIoY-uOP2m0-gvjE57ad1qDF"
|
|
110
|
+
|
|
111
|
+
url_ads_req = "https://otc-cf.huobi.com/v1/data/trade-market"
|
|
112
|
+
url_my_ads = "https://otc-api.trygofast.com/v1/data/trade-list?pageSize=50"
|
|
113
|
+
url_my_ad = "https://www.huobi.com/-/x/otc/v1/otc/trade/" # + id
|
|
114
|
+
url_my_bals = "https://www.huobi.com/-/x/otc/v1/capital/balance"
|
|
115
|
+
url_paccs = "https://www.huobi.com/-/x/otc/v1/user/receipt-account"
|
|
@@ -47,10 +47,12 @@ class ExClient(BaseExClient):
|
|
|
47
47
|
wrong_pms = {4, 34, 498, 548, 20009, 20010} # , 212, 239, 363 # these ids not exist in pms
|
|
48
48
|
return {c["currencyId"]: set(c["supportPayments"]) - wrong_pms for c in res["currency"] if c["supportPayments"]}
|
|
49
49
|
|
|
50
|
+
# 23: Список торгуемых монет
|
|
50
51
|
async def coins(self) -> dict[int, str]:
|
|
51
52
|
coins: list[dict] = (await self._coin_curs_pms())["coin"]
|
|
52
53
|
return {c["coinId"]: c["coinCode"] for c in coins if c["coinType"] == 2}
|
|
53
54
|
|
|
55
|
+
# 24: Список объяв
|
|
54
56
|
async def ads(self, coin: Coin, cur: Cur, is_sell: bool, pms: list[Pm] = None) -> list[Ad]:
|
|
55
57
|
res = await self._coin_curs_pms()
|
|
56
58
|
return res["country"]
|
|
@@ -65,6 +67,7 @@ async def main():
|
|
|
65
67
|
_ = await init_db(PG_DSN, models, True)
|
|
66
68
|
ex = await Ex.get(name="Htx")
|
|
67
69
|
cl = ExClient(ex)
|
|
70
|
+
await cl.curs()
|
|
68
71
|
await cl.set_pmcurexs()
|
|
69
72
|
await cl.set_coinexs()
|
|
70
73
|
await cl.close()
|
|
@@ -9,4 +9,6 @@ class AuthClient(BaseAuthClient):
|
|
|
9
9
|
pyro = PyroClient(self.agent)
|
|
10
10
|
init_data = await pyro.get_init_data()
|
|
11
11
|
tokens = HttpClient("walletbot.me")._post("/api/v1/users/auth/", init_data)
|
|
12
|
+
self.agent.exid = tokens["user_id"]
|
|
13
|
+
await self.agent.save()
|
|
12
14
|
return {"Wallet-Authorization": tokens["jwt"], "Authorization": "Bearer " + tokens["value"]}
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
from x_client.aiohttp import Client
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Public(Client):
|
|
5
|
-
url_ads_web = "https://www.huobi.com/en-us/fiat-crypto/trade/"
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
class Private(Client):
|
|
9
|
-
base_url = ""
|
|
10
|
-
middle_url = ""
|
|
11
|
-
|
|
12
|
-
htok: str = "Ev5lFfAvxDU2MA9BJ-Mc4U6zZG3Wb6qsp3Tx2fz6GIoY-uOP2m0-gvjE57ad1qDF"
|
|
13
|
-
|
|
14
|
-
url_ads_req = "https://otc-cf.huobi.com/v1/data/trade-market"
|
|
15
|
-
url_my_ads = "https://otc-api.trygofast.com/v1/data/trade-list?pageSize=50"
|
|
16
|
-
url_my_ad = "https://www.huobi.com/-/x/otc/v1/otc/trade/" # + id
|
|
17
|
-
url_my_bals = "https://www.huobi.com/-/x/otc/v1/capital/balance"
|
|
18
|
-
url_paccs = "https://www.huobi.com/-/x/otc/v1/user/receipt-account"
|
|
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.11.dev14 → xync_client-0.0.11.dev18}/xync_client.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|