xync-client 0.0.155.dev2__tar.gz → 0.0.160__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.155.dev2/xync_client.egg-info → xync_client-0.0.160}/PKG-INFO +2 -1
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/pyproject.toml +1 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/TestEx.py +11 -10
- xync_client-0.0.160/xync_client/Abc/AdLoader.py +5 -0
- xync_client-0.0.160/xync_client/Abc/Agent.py +491 -0
- xync_client-0.0.160/xync_client/Abc/Ex.py +696 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/Order.py +7 -14
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/xtype.py +35 -3
- xync_client-0.0.160/xync_client/Bybit/InAgent.py +36 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/agent.py +509 -412
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/etype/ad.py +47 -34
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/etype/order.py +34 -49
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/ex.py +20 -46
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/order.py +14 -12
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/agent.py +111 -56
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/etype/ad.py +22 -5
- xync_client-0.0.160/xync_client/Htx/etype/order.py +194 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/ex.py +16 -16
- xync_client-0.0.160/xync_client/Mexc/agent.py +268 -0
- xync_client-0.0.160/xync_client/Mexc/api.py +1255 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Mexc/etype/ad.py +52 -1
- xync_client-0.0.160/xync_client/Mexc/etype/order.py +354 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Mexc/ex.py +29 -19
- xync_client-0.0.160/xync_client/Okx/1.py +14 -0
- xync_client-0.0.160/xync_client/Okx/agent.py +39 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Okx/ex.py +8 -8
- xync_client-0.0.160/xync_client/Pms/Payeer/agent.py +396 -0
- xync_client-0.0.160/xync_client/Pms/Payeer/login.py +2 -0
- xync_client-0.0.160/xync_client/Pms/Payeer/trade.py +58 -0
- xync_client-0.0.155.dev2/xync_client/Pms/Volet/__init__.py → xync_client-0.0.160/xync_client/Pms/Volet/agent.py +1 -2
- xync_client-0.0.160/xync_client/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/loader.py +1 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160/xync_client.egg-info}/PKG-INFO +2 -1
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client.egg-info/SOURCES.txt +7 -3
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client.egg-info/requires.txt +1 -0
- xync_client-0.0.155.dev2/xync_client/Abc/AdLoader.py +0 -299
- xync_client-0.0.155.dev2/xync_client/Abc/Agent.py +0 -216
- xync_client-0.0.155.dev2/xync_client/Abc/Ex.py +0 -287
- xync_client-0.0.155.dev2/xync_client/Bybit/InAgent.py +0 -465
- xync_client-0.0.155.dev2/xync_client/Mexc/agent.py +0 -85
- xync_client-0.0.155.dev2/xync_client/Mexc/api.py +0 -636
- xync_client-0.0.155.dev2/xync_client/Mexc/etype/order.py +0 -639
- xync_client-0.0.155.dev2/xync_client/Pms/Payeer/__init__.py +0 -262
- xync_client-0.0.155.dev2/xync_client/Pms/Payeer/api.py +0 -25
- xync_client-0.0.155.dev2/xync_client/Pms/Payeer/login.py +0 -64
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/.env.sample +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/.gitignore +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/README.md +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/makefile +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/setup.cfg +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/TestAgent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/TestAsset.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/TestOrder.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/Auth.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/Exception.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/HasAbotUid.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/InAgent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Abc/PmAgent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.155.dev2/xync_client → xync_client-0.0.160/xync_client/Bybit/etype}/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/etype/cred.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Bybit/ws.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Gmail/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Htx/etype/test.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/.gitignore +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Alfa/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Alfa/state.json +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/MTS/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Ozon/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Payeer/.gitignore +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Sber/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Sber/utils.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Tinkoff/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Volet/api.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Volet/pl.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Xync/__main__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Xync/ed.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/Pms/Yandex/__init__.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/agent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/ex.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/pyd.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/pyro.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/details.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client/pm_unifier.py +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.155.dev2 → xync_client-0.0.160}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: xync-client
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.160
|
|
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
|
|
7
7
|
Requires-Python: >=3.11
|
|
8
8
|
Requires-Dist: asynchuobi
|
|
9
|
+
Requires-Dist: blackboxprotobuf
|
|
9
10
|
Requires-Dist: bs4
|
|
10
11
|
Requires-Dist: bybit-p2p
|
|
11
12
|
Requires-Dist: google-api-python-client
|
|
@@ -4,12 +4,13 @@ import pytest
|
|
|
4
4
|
from pyro_client.client.file import FileClient
|
|
5
5
|
from x_client.aiohttp import Client as HttpClient
|
|
6
6
|
from xync_schema.xtype import BaseAd
|
|
7
|
+
from xync_schema.models import PmEx, ExStat
|
|
7
8
|
|
|
8
9
|
from xync_client.Abc.BaseTest import BaseTest
|
|
9
10
|
from xync_schema.enums import ExStatus, ExType, ExAction
|
|
10
11
|
from xync_schema import models
|
|
11
12
|
from xync_client.Abc.Ex import BaseExClient
|
|
12
|
-
from xync_client.loader import
|
|
13
|
+
from xync_client.loader import NET_TOKEN
|
|
13
14
|
|
|
14
15
|
|
|
15
16
|
@pytest.mark.asyncio(loop_scope="session")
|
|
@@ -18,7 +19,7 @@ class TestEx(BaseTest):
|
|
|
18
19
|
async def clients(self) -> list[HttpClient]:
|
|
19
20
|
exs = await models.Ex.filter(status__gt=ExStatus.plan).prefetch_related("pm_reps")
|
|
20
21
|
[await ex for ex in exs if ex.typ == ExType.tg]
|
|
21
|
-
async with FileClient(
|
|
22
|
+
async with FileClient(NET_TOKEN) as b:
|
|
22
23
|
b: FileClient
|
|
23
24
|
clients: list[BaseExClient] = [ex.client(b) for ex in exs]
|
|
24
25
|
yield clients
|
|
@@ -66,14 +67,14 @@ class TestEx(BaseTest):
|
|
|
66
67
|
# logging.info(f"{client.ex.name}: {ExAction.curs.name} - ok")
|
|
67
68
|
#
|
|
68
69
|
# # 20
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
async def test_pms(self, clients: list[BaseExClient]):
|
|
71
|
+
for client in clients:
|
|
72
|
+
pms: dict[int | str, PmEx] = await client.pms()
|
|
73
|
+
ok = self.is_dict_of_objects(pms, PmEx)
|
|
74
|
+
t, _ = await ExStat.update_or_create({"ok": ok}, ex=client.ex, action=ExAction.pms)
|
|
75
|
+
assert t.ok, "No pms"
|
|
76
|
+
logging.info(f"{client.ex.name}: {ExAction.pms.name} - ok")
|
|
77
|
+
|
|
77
78
|
# # 21
|
|
78
79
|
# async def test_cur_pms_map(self, clients: list[BaseExClient]):
|
|
79
80
|
# for client in clients:
|
|
@@ -0,0 +1,491 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
from abc import abstractmethod
|
|
3
|
+
from asyncio import create_task, sleep
|
|
4
|
+
from collections import defaultdict
|
|
5
|
+
from typing import Literal
|
|
6
|
+
|
|
7
|
+
from pydantic import BaseModel
|
|
8
|
+
from pyro_client.client.file import FileClient
|
|
9
|
+
from x_client import df_hdrs
|
|
10
|
+
from x_client.aiohttp import Client as HttpClient
|
|
11
|
+
from xync_bot import XyncBot
|
|
12
|
+
from xync_client.Abc.PmAgent import PmAgentClient
|
|
13
|
+
|
|
14
|
+
from xync_client.Abc.InAgent import BaseInAgentClient
|
|
15
|
+
|
|
16
|
+
from xync_client.Bybit.etype.order import TakeAdReq
|
|
17
|
+
from xync_schema import models
|
|
18
|
+
from xync_schema.models import OrderStatus, Coin, Cur, Ad, AdStatus, Actor, Agent
|
|
19
|
+
from xync_schema.xtype import BaseAd
|
|
20
|
+
|
|
21
|
+
from xync_client.Abc.Ex import BaseExClient
|
|
22
|
+
from xync_client.Abc.xtype import CredExOut, BaseOrderReq, BaseAdUpdate, AdUpd, GetAds
|
|
23
|
+
from xync_client.Gmail import GmClient
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class BaseAgentClient(HttpClient, BaseInAgentClient):
|
|
27
|
+
actor: Actor
|
|
28
|
+
agent: Agent
|
|
29
|
+
bbot: XyncBot
|
|
30
|
+
fbot: FileClient
|
|
31
|
+
ex_client: BaseExClient
|
|
32
|
+
orders: dict[int, tuple[models.Order, BaseModel]] = {} # pending
|
|
33
|
+
pm_clients: dict[int, PmAgentClient] # {pm_id: PmAgentClient}
|
|
34
|
+
api: HttpClient
|
|
35
|
+
cred_x2e: dict[int, int] = {}
|
|
36
|
+
cred_e2x: dict[int, int] = {}
|
|
37
|
+
|
|
38
|
+
def __init__(
|
|
39
|
+
self,
|
|
40
|
+
agent: Agent, # agent.actor.person.user
|
|
41
|
+
ex_client: BaseExClient,
|
|
42
|
+
fbot: FileClient,
|
|
43
|
+
bbot: XyncBot,
|
|
44
|
+
pm_clients: dict[int, PmAgentClient] = None,
|
|
45
|
+
headers: dict[str, str] = df_hdrs,
|
|
46
|
+
cookies: dict[str, str] = None,
|
|
47
|
+
proxy: models.Proxy = None,
|
|
48
|
+
):
|
|
49
|
+
self.bbot = bbot
|
|
50
|
+
self.fbot = fbot
|
|
51
|
+
self.agent: Agent = agent
|
|
52
|
+
self.actor: Actor = agent.actor
|
|
53
|
+
self.gmail = agent.actor.person.user.gmail and GmClient(agent.actor.person.user)
|
|
54
|
+
self.ex_client: BaseExClient = ex_client
|
|
55
|
+
self.pm_clients: dict[int, PmAgentClient] = defaultdict()
|
|
56
|
+
super().__init__(self.actor.ex.host_p2p, headers, cookies, proxy) # and proxy.str()
|
|
57
|
+
# start
|
|
58
|
+
create_task(self.start())
|
|
59
|
+
|
|
60
|
+
async def x2e_cred(self, cred_id: int) -> int: # cred.exid
|
|
61
|
+
if not self.cred_x2e.get(cred_id):
|
|
62
|
+
self.cred_x2e[cred_id] = (await models.CredEx.get(cred_id=cred_id)).exid
|
|
63
|
+
self.cred_e2x[self.cred_x2e[cred_id]] = cred_id
|
|
64
|
+
return self.cred_x2e[cred_id]
|
|
65
|
+
|
|
66
|
+
async def e2x_cred(self, exid: int) -> int: # cred.id
|
|
67
|
+
if not self.cred_e2x.get(exid):
|
|
68
|
+
self.cred_e2x[exid] = (await models.CredEx.get(exid=exid, ex=self.ex_client.ex)).cred_id
|
|
69
|
+
self.cred_x2e[self.cred_e2x[exid]] = exid
|
|
70
|
+
return self.cred_e2x[exid]
|
|
71
|
+
|
|
72
|
+
async def start(self):
|
|
73
|
+
if self.agent.status & 1: # race
|
|
74
|
+
for race in await models.Race.filter(started=True, road__ad__maker_id=self.agent.actor_id).prefetch_related(
|
|
75
|
+
"road__ad__pair_side__pair__cur", "road__credexs__cred"
|
|
76
|
+
):
|
|
77
|
+
create_task(self.racing(race))
|
|
78
|
+
if self.agent.status & 2: # listen
|
|
79
|
+
await self.start_listen()
|
|
80
|
+
|
|
81
|
+
async def racing(self, race: models.Race):
|
|
82
|
+
pair = race.road.ad.pair_side.pair
|
|
83
|
+
taker_side: int = not race.road.ad.pair_side.is_sell
|
|
84
|
+
# конвертим наши параметры гонки в ex-овые для конкретной биржи текущего агента
|
|
85
|
+
coinex: models.CoinEx = await models.CoinEx.get(coin_id=pair.coin_id, ex=self.actor.ex).prefetch_related("coin")
|
|
86
|
+
curex: models.CurEx = await models.CurEx.get(cur_id=pair.cur_id, ex=self.actor.ex).prefetch_related("cur")
|
|
87
|
+
creds = [c.cred for c in race.road.credexs]
|
|
88
|
+
pm_ids = [pm.id for pm in race.road.ad.pms]
|
|
89
|
+
pmexs: list[models.PmEx] = [pmex for pm in race.road.ad.pms for pmex in pm.pmexs if pmex.ex_id == 4]
|
|
90
|
+
post_pm_ids = {c.cred.ovr_pm_id for c in race.road.credexs if c.cred.ovr_pm_id}
|
|
91
|
+
post_pmexs = set(await models.PmEx.filter(pm_id__in=post_pm_ids, ex=self.actor.ex).prefetch_related("pm"))
|
|
92
|
+
|
|
93
|
+
k = (-1) ** taker_side # on_buy=1, on_sell=-1
|
|
94
|
+
sleep_sec = 3 # 1 if set(pms) & {"volet"} and coinex.coin_id == 1 else 5
|
|
95
|
+
_lstat, volume = None, 0
|
|
96
|
+
|
|
97
|
+
# погнали цикл гонки
|
|
98
|
+
while self.actor.person.user.status > 0: # todo: separate agents, not whole user.activity
|
|
99
|
+
# подгружаем из бд обновления по текущей гонке
|
|
100
|
+
await race.refresh_from_db()
|
|
101
|
+
if not race.started: # пока выключена
|
|
102
|
+
await sleep(5)
|
|
103
|
+
continue
|
|
104
|
+
|
|
105
|
+
# конверт бд int фильтровочной суммы в float конкретной биржи
|
|
106
|
+
amt = race.filter_amount * 10**-curex.cur.scale if race.filter_amount else None
|
|
107
|
+
ceils = await self.get_ceils(coinex, curex, pmexs, 0.003, 0, amt, post_pmexs)
|
|
108
|
+
race.ceil = int(ceils[taker_side] * 10**curex.scale)
|
|
109
|
+
await race.save()
|
|
110
|
+
|
|
111
|
+
last_vol = volume
|
|
112
|
+
if taker_side: # гонка в стакане продажи - мы покупаем монету за ФИАТ
|
|
113
|
+
fiat = max(await models.Fiat.filter(cred_id__in=[c.id for c in creds]), key=lambda x: x.amount)
|
|
114
|
+
volume = (fiat.amount * 10**-curex.cur.scale) / (race.road.ad.price * 10**-curex.scale)
|
|
115
|
+
else: # гонка в стакане покупки - мы продаем МОНЕТУ за фиат
|
|
116
|
+
asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
|
|
117
|
+
volume = asset.free * 10**-coinex.scale
|
|
118
|
+
volume = str(round(volume, coinex.scale))
|
|
119
|
+
get_ads_req = GetAds(
|
|
120
|
+
coin_id=pair.coin_id, cur_id=pair.cur_id, is_sell=bool(taker_side), pm_ids=pm_ids, amount=amt, limit=50
|
|
121
|
+
)
|
|
122
|
+
try:
|
|
123
|
+
ads: list[Ad] = await self.ex_client.ads(get_ads_req)
|
|
124
|
+
except Exception:
|
|
125
|
+
await sleep(1)
|
|
126
|
+
ads: list[Ad] = await self.ads(coinex, curex, taker_side, pmexs, amt, 50, race.vm_filter, post_pmexs)
|
|
127
|
+
|
|
128
|
+
self.overprice_filter(ads, race.ceil * 10**-curex.scale, k) # обрезаем сверху все ads дороже нашего потолка
|
|
129
|
+
|
|
130
|
+
if not ads:
|
|
131
|
+
print(coinex.exid, curex.exid, taker_side, "no ads!")
|
|
132
|
+
await sleep(15)
|
|
133
|
+
continue
|
|
134
|
+
# определяем наше текущее место в уже обрезанном списке ads
|
|
135
|
+
if not (cur_plc := [i for i, ad in enumerate(ads) if int(ad.userId) == self.actor.exid]):
|
|
136
|
+
logging.warning(f"No racing in {pmexs[0].name} {'-' if taker_side else '+'}{coinex.exid}/{curex.exid}")
|
|
137
|
+
await sleep(15)
|
|
138
|
+
continue
|
|
139
|
+
(cur_plc,) = cur_plc # может упасть если в списке > 1 наш ad
|
|
140
|
+
[(await self.ex_client.cond_load(ad, race.road.ad.pair_side, True))[0] for ad in ads[:cur_plc]]
|
|
141
|
+
# rivals = [
|
|
142
|
+
# (await models.RaceStat.update_or_create({"place": plc, "price": ad.price, "premium": ad.premium}, ad=ad))[
|
|
143
|
+
# 0
|
|
144
|
+
# ]
|
|
145
|
+
# for plc, ad in enumerate(rads)
|
|
146
|
+
# ]
|
|
147
|
+
mad: Ad = ads.pop(cur_plc)
|
|
148
|
+
# if (
|
|
149
|
+
# not (lstat := lstat or await race.stats.order_by("-created_at").first())
|
|
150
|
+
# or lstat.place != cur_plc
|
|
151
|
+
# or lstat.price != float(mad.price)
|
|
152
|
+
# or set(rivals) != set(await lstat.rivals)
|
|
153
|
+
# ):
|
|
154
|
+
# lstat = await models.RaceStat.create(race=race, place=cur_plc, price=mad.price, premium=mad.premium)
|
|
155
|
+
# await lstat.rivals.add(*rivals)
|
|
156
|
+
if not ads:
|
|
157
|
+
await sleep(60)
|
|
158
|
+
continue
|
|
159
|
+
if not (cad := self.get_cad(ads, race.ceil * 10**-curex.scale, k, race.target_place, cur_plc)):
|
|
160
|
+
continue
|
|
161
|
+
new_price = round(float(cad.price) - k * step(mad, cad, curex.scale), curex.scale)
|
|
162
|
+
if (
|
|
163
|
+
float(mad.price) == new_price and volume == last_vol
|
|
164
|
+
): # Если место уже нужное или нужная цена и так уже стоит
|
|
165
|
+
print(
|
|
166
|
+
f"{'v' if taker_side else '^'}{mad.price}",
|
|
167
|
+
end=f"[{race.ceil * 10**-curex.scale}+{cur_plc}] ",
|
|
168
|
+
flush=True,
|
|
169
|
+
)
|
|
170
|
+
await sleep(sleep_sec)
|
|
171
|
+
continue
|
|
172
|
+
if cad.priceType: # Если цена конкурента плавающая, то повышаем себе не цену, а %
|
|
173
|
+
new_premium = (float(mad.premium) or float(cad.premium)) - k * step(mad, cad, 2)
|
|
174
|
+
# if float(mad.premium) == new_premium: # Если нужный % и так уже стоит
|
|
175
|
+
# if mad.priceType and cur_plc != race.target_place:
|
|
176
|
+
# new_premium -= k * step(mad, cad, 2)
|
|
177
|
+
# elif volume == last_vol:
|
|
178
|
+
# print(end="v" if taker_side else "^", flush=True)
|
|
179
|
+
# await sleep(sleep_sec)
|
|
180
|
+
# continue
|
|
181
|
+
mad.premium = str(round(new_premium, 2))
|
|
182
|
+
mad.priceType = cad.priceType
|
|
183
|
+
mad.quantity = volume
|
|
184
|
+
mad.maxAmount = str(2_000_000 if curex.cur_id == 1 else 40_000)
|
|
185
|
+
# req = AdUpdateRequest.model_validate(
|
|
186
|
+
# {
|
|
187
|
+
# **mad.model_dump(),
|
|
188
|
+
# "price": str(round(new_price, curex.scale)),
|
|
189
|
+
# "paymentIds": [str(cx.exid) for cx in race.road.credexs],
|
|
190
|
+
# }
|
|
191
|
+
# )
|
|
192
|
+
# try:
|
|
193
|
+
# print(
|
|
194
|
+
# f"c{race.ceil * 10**-curex.scale}+{cur_plc} {coinex.coin.ticker}{'-' if taker_side else '+'}{req.price}{curex.cur.ticker}"
|
|
195
|
+
# f"{[pm.norm for pm in race.road.ad.pms]}{f'({req.premium}%)' if req.premium != '0' else ''} "
|
|
196
|
+
# f"t{race.target_place} ;",
|
|
197
|
+
# flush=True,
|
|
198
|
+
# )
|
|
199
|
+
# _res = self.ad_upd(req)
|
|
200
|
+
# except FailedRequestError as e:
|
|
201
|
+
# if ExcCode(e.status_code) == ExcCode.FixPriceLimit:
|
|
202
|
+
# if limits := re.search(
|
|
203
|
+
# r"The fixed price set is lower than ([0-9]+\.?[0-9]{0,2}) or higher than ([0-9]+\.?[0-9]{0,2})",
|
|
204
|
+
# e.message,
|
|
205
|
+
# ):
|
|
206
|
+
# req.price = limits.group(1 if taker_side else 2)
|
|
207
|
+
# if req.price != mad.price:
|
|
208
|
+
# _res = self.ad_upd(req)
|
|
209
|
+
# else:
|
|
210
|
+
# raise e
|
|
211
|
+
# elif ExcCode(e.status_code) == ExcCode.InsufficientBalance:
|
|
212
|
+
# asset = await models.Asset.get(addr__actor=self.actor, addr__coin_id=coinex.coin_id)
|
|
213
|
+
# req.quantity = str(round(asset.free * 10**-coinex.scale, coinex.scale))
|
|
214
|
+
# _res = self.ad_upd(req)
|
|
215
|
+
# elif ExcCode(e.status_code) == ExcCode.RareLimit:
|
|
216
|
+
# if not (
|
|
217
|
+
# sads := [
|
|
218
|
+
# ma
|
|
219
|
+
# for ma in self.my_ads(False)
|
|
220
|
+
# if (
|
|
221
|
+
# ma.currencyId == curex.exid
|
|
222
|
+
# and ma.tokenId == coinex.exid
|
|
223
|
+
# and taker_side != ma.side
|
|
224
|
+
# and set(ma.payments) == set([pe.exid for pe in pmexs])
|
|
225
|
+
# )
|
|
226
|
+
# ]
|
|
227
|
+
# ):
|
|
228
|
+
# logging.error(f"Need reserve Ad {'sell' if taker_side else 'buy'} {coinex.exid}/{curex.exid}")
|
|
229
|
+
# await sleep(90)
|
|
230
|
+
# continue
|
|
231
|
+
# self.ad_del(ad_id=int(mad.id))
|
|
232
|
+
# req.id = sads[0].id
|
|
233
|
+
# req.actionType = "ACTIVE"
|
|
234
|
+
# self.api.update_ad(**req.model_dump())
|
|
235
|
+
# logging.warning(f"Ad#{mad.id} recreated")
|
|
236
|
+
# # elif ExcCode(e.status_code) == ExcCode.Timestamp:
|
|
237
|
+
# # await sleep(3)
|
|
238
|
+
# else:
|
|
239
|
+
# raise e
|
|
240
|
+
# except (ReadTimeoutError, ConnectionDoesNotExistError):
|
|
241
|
+
# logging.warning("Connection failed. Restarting..")
|
|
242
|
+
await sleep(6)
|
|
243
|
+
|
|
244
|
+
async def get_books(
|
|
245
|
+
self,
|
|
246
|
+
coinex: models.CoinEx,
|
|
247
|
+
curex: models.CurEx,
|
|
248
|
+
pmexs: list[models.PmEx],
|
|
249
|
+
amount: int,
|
|
250
|
+
post_pmexs: list[models.PmEx] = None,
|
|
251
|
+
) -> tuple[list[Ad], list[Ad]]:
|
|
252
|
+
buy: list[Ad] = await self.ads(coinex, curex, False, pmexs, amount, 40, False, post_pmexs)
|
|
253
|
+
sell: list[Ad] = await self.ads(coinex, curex, True, pmexs, amount, 30, False, post_pmexs)
|
|
254
|
+
return buy, sell
|
|
255
|
+
|
|
256
|
+
async def get_spread(
|
|
257
|
+
self, bb: list[Ad], sb: list[Ad], perc: float, place: int = 0
|
|
258
|
+
) -> tuple[tuple[float, float], float, int] | None:
|
|
259
|
+
if len(bb) and len(sb):
|
|
260
|
+
buy_price, sell_price = float(bb[place].price), float(sb[place].price)
|
|
261
|
+
half_spread = (buy_price - sell_price) / (buy_price + sell_price)
|
|
262
|
+
if half_spread * 2 < perc:
|
|
263
|
+
return await self.get_spread(bb, sb, perc, place)
|
|
264
|
+
return (buy_price, sell_price), half_spread, place
|
|
265
|
+
return None
|
|
266
|
+
|
|
267
|
+
async def get_ceils(
|
|
268
|
+
self,
|
|
269
|
+
coinex: models.CoinEx,
|
|
270
|
+
curex: models.CurEx,
|
|
271
|
+
pmexs: list[models.PmEx],
|
|
272
|
+
min_prof=0.02,
|
|
273
|
+
place: int = 0,
|
|
274
|
+
amount: int = None,
|
|
275
|
+
post_pmexs: set[models.PmEx] = None,
|
|
276
|
+
) -> tuple[float, float]: # todo: refact to Pairex
|
|
277
|
+
for pmc_id in {pmx.pm_id for pmx in pmexs} | set(self.pm_clients.keys()):
|
|
278
|
+
if ceils := self.pm_clients[pmc_id].get_ceils():
|
|
279
|
+
return ceils
|
|
280
|
+
bb, sb = await self.get_books(coinex, curex, pmexs, amount, post_pmexs)
|
|
281
|
+
perc = list(post_pmexs or pmexs)[0].pm.fee * 0.0001 + min_prof
|
|
282
|
+
(bf, sf), _hp, _zplace = await self.get_spread(bb, sb, perc, place)
|
|
283
|
+
mdl = (bf + sf) / 2 # middle price
|
|
284
|
+
bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
|
|
285
|
+
return bc, sc
|
|
286
|
+
|
|
287
|
+
async def mad_upd(self, mad: Ad, attrs: dict, cxids: list[str]):
|
|
288
|
+
if not [setattr(mad, k, v) for k, v in attrs.items() if getattr(mad, k) != v]:
|
|
289
|
+
print(end="v" if mad.side else "^", flush=True)
|
|
290
|
+
return await sleep(5)
|
|
291
|
+
# req = AdUpdateRequest.model_validate({**mad.model_dump(), "paymentIds": cxids})
|
|
292
|
+
# try:
|
|
293
|
+
# return self.ad_upd(req)
|
|
294
|
+
# except FailedRequestError as e:
|
|
295
|
+
# if ExcCode(e.status_code) == ExcCode.FixPriceLimit:
|
|
296
|
+
# if limits := re.search(
|
|
297
|
+
# r"The fixed price set is lower than ([0-9]+\.?[0-9]{0,2}) or higher than ([0-9]+\.?[0-9]{0,2})",
|
|
298
|
+
# e.message,
|
|
299
|
+
# ):
|
|
300
|
+
# return await self.mad_upd(mad, {"price": limits.group(1 if mad.side else 2)}, cxids)
|
|
301
|
+
# elif ExcCode(e.status_code) == ExcCode.RareLimit:
|
|
302
|
+
# await sleep(180)
|
|
303
|
+
# else:
|
|
304
|
+
# raise e
|
|
305
|
+
# except (ReadTimeoutError, ConnectionDoesNotExistError):
|
|
306
|
+
# logging.warning("Connection failed. Restarting..")
|
|
307
|
+
# print("-" if mad.side else "+", end=req.price, flush=True)
|
|
308
|
+
await sleep(60)
|
|
309
|
+
|
|
310
|
+
def overprice_filter(self, ads: list[Ad], ceil: float, k: Literal[-1, 1]):
|
|
311
|
+
# вырезаем ads с ценами выше потолка
|
|
312
|
+
if ads and (ceil - float(ads[0].price)) * k > 0:
|
|
313
|
+
if int(ads[0].userId) != self.actor.exid:
|
|
314
|
+
ads.pop(0)
|
|
315
|
+
self.overprice_filter(ads, ceil, k)
|
|
316
|
+
|
|
317
|
+
def get_cad(self, ads: list[Ad], ceil: float, k: Literal[-1, 1], target_place: int, cur_plc: int) -> Ad:
|
|
318
|
+
if not ads:
|
|
319
|
+
return None
|
|
320
|
+
# чью цену будем обгонять, предыдущей или слещующей объявы?
|
|
321
|
+
# cad: Ad = ads[place] if cur_plc > place else ads[cur_plc]
|
|
322
|
+
# переделал пока на жесткую установку целевого места, даже если текущее выше:
|
|
323
|
+
if len(ads) <= target_place:
|
|
324
|
+
logging.error(f"target place {target_place} not found in ads {len(ads)}-lenght list")
|
|
325
|
+
target_place = len(ads) - 1
|
|
326
|
+
cad: Ad = ads[target_place]
|
|
327
|
+
# а цена обгоняемой объявы не выше нашего потолка?
|
|
328
|
+
if (float(cad.price) - ceil) * k <= 0:
|
|
329
|
+
# тогда берем следующую
|
|
330
|
+
ads.pop(target_place)
|
|
331
|
+
cad = self.get_cad(ads, ceil, k, target_place, cur_plc)
|
|
332
|
+
# todo: добавить фильтр по лимитам min-max
|
|
333
|
+
return cad
|
|
334
|
+
|
|
335
|
+
# 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
|
|
336
|
+
@abstractmethod
|
|
337
|
+
async def get_orders(
|
|
338
|
+
self, status: OrderStatus = OrderStatus.created, coin: Coin = None, cur: Cur = None, is_sell: bool = None
|
|
339
|
+
) -> list: ...
|
|
340
|
+
|
|
341
|
+
# 1: [T] Запрос на старт сделки
|
|
342
|
+
@abstractmethod
|
|
343
|
+
async def order_request(self, order_req: BaseOrderReq) -> dict: ...
|
|
344
|
+
|
|
345
|
+
# async def start_order(self, order: Order) -> OrderOutClient:
|
|
346
|
+
# return OrderOutClient(self, order)
|
|
347
|
+
|
|
348
|
+
# 1N: [M] - Запрос мейкеру на сделку
|
|
349
|
+
@abstractmethod
|
|
350
|
+
async def order_request_ask(self) -> dict: ... # , ad: Ad, amount: float, pm: Pm, taker: Agent
|
|
351
|
+
|
|
352
|
+
# 2N: [M] - Уведомление об отмене запроса на сделку
|
|
353
|
+
@abstractmethod
|
|
354
|
+
async def request_canceled_notify(self) -> int: ... # id
|
|
355
|
+
|
|
356
|
+
# # # Cred
|
|
357
|
+
@property
|
|
358
|
+
@abstractmethod
|
|
359
|
+
def fiat_pyd(self) -> BaseModel.__class__: ...
|
|
360
|
+
|
|
361
|
+
@abstractmethod
|
|
362
|
+
def fiat_args2pyd(
|
|
363
|
+
self, exid: int | str, cur: str, detail: str, name: str, fid: int, typ: str, extra=None
|
|
364
|
+
) -> fiat_pyd: ...
|
|
365
|
+
|
|
366
|
+
# 25: Список реквизитов моих платежных методов
|
|
367
|
+
@abstractmethod
|
|
368
|
+
async def creds(self) -> list[CredExOut]: ... # {credex.exid: {cred}}
|
|
369
|
+
|
|
370
|
+
# Создание реквизита на бирже
|
|
371
|
+
async def cred_new(self, cred: models.Cred) -> models.CredEx: ...
|
|
372
|
+
|
|
373
|
+
# await models.Actor.get_or_create({"name": cred.exid}, ex=self.ex_client.ex, exid=self.agent.actor.exid)
|
|
374
|
+
# cred_db: Cred = (await self.cred_pyd2db(cred, self.agent.user_id))[0]
|
|
375
|
+
# if not (credex := models.CredEx.get_or_none(cred=cred_db, ex=self.agent.ex)):
|
|
376
|
+
# credex, _ = models.CredEx.update_or_create({}, cred=cred_db, ex=self.agent.ex)
|
|
377
|
+
# return credex
|
|
378
|
+
|
|
379
|
+
# 27: Редактирование реквизита моего платежного метода
|
|
380
|
+
@abstractmethod
|
|
381
|
+
async def cred_upd(self, cred: models.Cred, exid: int) -> models.CredEx: ...
|
|
382
|
+
|
|
383
|
+
# 28: Удаление реквизита моего платежного метода
|
|
384
|
+
@abstractmethod
|
|
385
|
+
async def cred_del(self, exid: int) -> int: ...
|
|
386
|
+
|
|
387
|
+
# # # Ad
|
|
388
|
+
# 29: Список моих объявлений
|
|
389
|
+
@abstractmethod
|
|
390
|
+
async def my_ads(self, status: AdStatus = None) -> list[BaseAd]: ...
|
|
391
|
+
|
|
392
|
+
@abstractmethod
|
|
393
|
+
async def x2e_req_ad_upd(self, xreq: AdUpd) -> BaseAdUpdate: ...
|
|
394
|
+
|
|
395
|
+
# 30: Создание объявления
|
|
396
|
+
@abstractmethod
|
|
397
|
+
async def ad_new(self, ad: BaseAd) -> Ad: ...
|
|
398
|
+
|
|
399
|
+
async def ad_upd(self, xreq: AdUpd) -> Ad:
|
|
400
|
+
xreq.credexs = await models.CredEx.filter(
|
|
401
|
+
ex_id=self.actor.ex_id,
|
|
402
|
+
cred__pmcur__pm_id__in=xreq.pm_ids,
|
|
403
|
+
cred__pmcur__cur_id=xreq.cur_id,
|
|
404
|
+
cred__person_id=self.actor.person_id,
|
|
405
|
+
).prefetch_related("cred__pmcur")
|
|
406
|
+
# xreq.credexs = credexs
|
|
407
|
+
ereq = await self.x2e_req_ad_upd(xreq)
|
|
408
|
+
return await self._ad_upd(ereq)
|
|
409
|
+
|
|
410
|
+
# 31: Редактирование объявления
|
|
411
|
+
@abstractmethod
|
|
412
|
+
async def _ad_upd(self, ad: BaseAdUpdate) -> Ad: ...
|
|
413
|
+
|
|
414
|
+
# 32: Удаление
|
|
415
|
+
@abstractmethod
|
|
416
|
+
async def ad_del(self, ad_id: int) -> bool: ...
|
|
417
|
+
|
|
418
|
+
# 33: Вкл/выкл объявления
|
|
419
|
+
@abstractmethod
|
|
420
|
+
async def ad_switch(self, offer_id: int, active: bool) -> bool: ...
|
|
421
|
+
|
|
422
|
+
# 34: Вкл/выкл всех объявлений
|
|
423
|
+
@abstractmethod
|
|
424
|
+
async def ads_switch(self, active: bool) -> bool: ...
|
|
425
|
+
|
|
426
|
+
# # # User
|
|
427
|
+
# 35: Получить объект юзера по его ид
|
|
428
|
+
@abstractmethod
|
|
429
|
+
async def get_user(self, user_id) -> dict: ...
|
|
430
|
+
|
|
431
|
+
# 36: Отправка сообщения юзеру с приложенным файлом
|
|
432
|
+
@abstractmethod
|
|
433
|
+
async def send_user_msg(self, msg: str, file=None) -> bool: ...
|
|
434
|
+
|
|
435
|
+
# 37: (Раз)Блокировать юзера
|
|
436
|
+
@abstractmethod
|
|
437
|
+
async def block_user(self, is_blocked: bool = True) -> bool: ...
|
|
438
|
+
|
|
439
|
+
# 38: Поставить отзыв юзеру
|
|
440
|
+
@abstractmethod
|
|
441
|
+
async def rate_user(self, positive: bool) -> bool: ...
|
|
442
|
+
|
|
443
|
+
# 39: Балансы моих монет
|
|
444
|
+
@abstractmethod
|
|
445
|
+
async def my_assets(self) -> dict: ...
|
|
446
|
+
|
|
447
|
+
@abstractmethod
|
|
448
|
+
async def take_ad(self, req: TakeAdReq): ...
|
|
449
|
+
|
|
450
|
+
# Сохранение объявления (с Pm/Cred-ами) в бд
|
|
451
|
+
# async def ad_pydin2db(self, ad_pydin: AdSaleIn | AdBuyIn) -> Ad:
|
|
452
|
+
# ad_db = await self.ex_client.ad_pydin2db(ad_pydin)
|
|
453
|
+
# await ad_db.credexs.add(*getattr(ad_pydin, "credexs_", []))
|
|
454
|
+
# await ad_db.pmexs.add(*getattr(ad_pydin, "pmexs_", []))
|
|
455
|
+
# return ad_db
|
|
456
|
+
|
|
457
|
+
# @staticmethod
|
|
458
|
+
# async def cred_e2db(cred_in: BaseUpd, banks: list[str] = None) -> bool:
|
|
459
|
+
# cred_db, _ = await models.Cred.update_or_create(**cred_in.df_unq())
|
|
460
|
+
# credex_in = models.CredEx.validate({"exid": cred_in.id, "cred_id": cred_db.id})
|
|
461
|
+
# credex_db, _ = await models.CredEx.update_or_create(**credex_in.df_unq())
|
|
462
|
+
# if banks: # only for SBP
|
|
463
|
+
# await cred_db.banks.add(*[await PmExBank.get(exid=b) for b in banks])
|
|
464
|
+
# return True
|
|
465
|
+
|
|
466
|
+
@abstractmethod
|
|
467
|
+
async def _start_listen(self): ...
|
|
468
|
+
|
|
469
|
+
@abstractmethod
|
|
470
|
+
async def load_pending_orders(self): ...
|
|
471
|
+
|
|
472
|
+
async def start_listen(self):
|
|
473
|
+
create_task(self._start_listen())
|
|
474
|
+
await self.load_pending_orders()
|
|
475
|
+
|
|
476
|
+
|
|
477
|
+
def step_is_need(mad, cad) -> bool:
|
|
478
|
+
# todo: пока не решен непонятный кейс, почему то конкурент по всем параметрам слабже, но в списке ранжируется выше.
|
|
479
|
+
# текущая версия: recentExecuteRate округляется до целого, но на бэке байбита его дробная часть больше
|
|
480
|
+
return (
|
|
481
|
+
bool(set(cad.authTag) & {"VA2", "BA"})
|
|
482
|
+
or cad.recentExecuteRate > mad.recentExecuteRate
|
|
483
|
+
or (
|
|
484
|
+
cad.recentExecuteRate
|
|
485
|
+
== mad.recentExecuteRate # and cad.finishNum > mad.finishNum # пока прибавляем для равных
|
|
486
|
+
)
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
|
|
490
|
+
def step(mad, cad, scale: int = 2) -> float:
|
|
491
|
+
return float(int(step_is_need(mad, cad)) * 10**-scale).__round__(scale)
|