xync-client 0.0.233__tar.gz → 0.0.235.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.233 → xync_client-0.0.235.dev3}/PKG-INFO +1 -1
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/README.md +38 -1
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Agent.py +169 -69
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Ex.py +77 -17
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/xtype.py +88 -17
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/agent.py +34 -23
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/etype/ad.py +79 -33
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/ex.py +33 -15
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/agent.py +3 -3
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/agent.py +1 -1
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/details.py +3 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client.egg-info/PKG-INFO +1 -1
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/.env.sample +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/.gitignore +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/.pre-commit-config.yaml +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/CLAUDE.md +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/makefile +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/pyproject.toml +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/setup.cfg +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/TestAgent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/TestAsset.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/TestEx.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/TestOrder.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Binance/test_binance.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Bybit/test_bybit.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Bybit/test_bybit_p2p.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Gate/test_gate.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Wallet/test_agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/Wallet/test_ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/tests/_todo_refact/_test_ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/AdLoader.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Asset.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Auth.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/BaseTest.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Exception.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/HasAbotUid.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/InAgent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/Order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Abc/PmAgent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/binance_async.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/earn_api.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/exceptions.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/sapi.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Binance/web_c2c.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/base.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/req.mjs +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BingX/sign.js +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BitGet/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BitGet/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BitGet/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BitGet/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/BitPapa/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/etype/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/etype/cred.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/etype/order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/inAgent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/web_earn.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/web_p2p.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Bybit/ws.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Gate/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Gate/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Gate/premarket.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Gmail/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/earn.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/cred.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/etype/test.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Htx/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/KuCoin/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/KuCoin/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/KuCoin/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/KuCoin/web.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/api.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/etype/order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Mexc/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Okx/1.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Okx/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Okx/etype/ad.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Okx/etype/pm.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Okx/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/.gitignore +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Alfa/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Alfa/state.json +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/MTS/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Ozon/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Payeer/.gitignore +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Payeer/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Payeer/login.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Payeer/trade.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Sber/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Sber/utils.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Tinkoff/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Volet/_todo_req/req.mjs +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Volet/_todo_req/req.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Volet/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Volet/api.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Volet/pl.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Xync/__main__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Xync/ed.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/Yandex/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/Pms/airtm/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/agent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/asset.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/auth.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/ex.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/inAgent.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/order.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/pyd.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/pyro.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/TgWallet/web.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/__init__.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/loader.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client/pm_unifier.py +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client.egg-info/SOURCES.txt +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client.egg-info/dependency_links.txt +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client.egg-info/requires.txt +0 -0
- {xync_client-0.0.233 → xync_client-0.0.235.dev3}/xync_client.egg-info/top_level.txt +0 -0
|
@@ -188,4 +188,41 @@ classDef red stroke:#f00
|
|
|
188
188
|
- 40: Получить реквизиты для депозита монеты `deposit(amount: int) => bool`
|
|
189
189
|
- 40N: Получена монета `deposited => amount`
|
|
190
190
|
- 41: Вывести монету `withdraw(amount: int) => bool`
|
|
191
|
-
- 41N: Монета выведена `withdrew => amount`
|
|
191
|
+
- 41N: Монета выведена `withdrew => amount`
|
|
192
|
+
|
|
193
|
+
|
|
194
|
+
## Общий флоу для всех сущностей
|
|
195
|
+
|
|
196
|
+
```mermaid
|
|
197
|
+
block-beta
|
|
198
|
+
columns 5
|
|
199
|
+
eOut["eOut"] space xIn["xIn"] space fOut["fOut"]
|
|
200
|
+
space:5
|
|
201
|
+
Exs((("Exs"))) space db[("DataBase")] space Front(("Front"))
|
|
202
|
+
space:5
|
|
203
|
+
eIn["eIn"] space xOut["xOut"] space fIn["fIn"]
|
|
204
|
+
Exs --"A"--> eOut
|
|
205
|
+
eOut --"B"--> xIn
|
|
206
|
+
xIn --"C"--> db
|
|
207
|
+
db --"D"--> xOut
|
|
208
|
+
xOut --"E"--> fIn
|
|
209
|
+
fIn --"F"--> Front
|
|
210
|
+
Front --"G"--> fOut
|
|
211
|
+
fOut --"H"--> xIn
|
|
212
|
+
xOut --"I"--> eIn
|
|
213
|
+
eIn --"J"--> Exs
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
```mermaid
|
|
217
|
+
mindmap
|
|
218
|
+
root(transfer)
|
|
219
|
+
order
|
|
220
|
+
ad
|
|
221
|
+
pair_side
|
|
222
|
+
pair
|
|
223
|
+
coin
|
|
224
|
+
cur
|
|
225
|
+
maker
|
|
226
|
+
person
|
|
227
|
+
user
|
|
228
|
+
```
|
|
@@ -8,14 +8,15 @@ from pydantic import BaseModel
|
|
|
8
8
|
from tortoise.exceptions import IntegrityError
|
|
9
9
|
from x_client import df_hdrs
|
|
10
10
|
from x_client.aiohttp import Client as HttpClient
|
|
11
|
+
from xync_client.details import hot_ad_cond
|
|
12
|
+
from xync_schema.enums import AdStatus, OrderStatus
|
|
13
|
+
|
|
11
14
|
from xync_client.Abc.PmAgent import PmAgentClient
|
|
12
15
|
|
|
13
16
|
from xync_client.Abc.InAgent import BaseInAgentClient
|
|
14
17
|
|
|
15
18
|
from xync_client.Bybit.etype.order import TakeAdReq
|
|
16
19
|
from xync_schema import models
|
|
17
|
-
from xync_schema.models import OrderStatus, Coin, Cur, Ad, Actor, Agent, MyAd
|
|
18
|
-
from xync_schema import xtype
|
|
19
20
|
|
|
20
21
|
from xync_client.Abc.Ex import BaseExClient
|
|
21
22
|
from xync_client.Abc.xtype import (
|
|
@@ -26,14 +27,16 @@ from xync_client.Abc.xtype import (
|
|
|
26
27
|
GetAdsReq,
|
|
27
28
|
BaseCredexsExidsTrait,
|
|
28
29
|
BaseOrderFull,
|
|
30
|
+
BaseOrder,
|
|
31
|
+
MyAdXOut,
|
|
29
32
|
)
|
|
30
33
|
|
|
31
34
|
|
|
32
35
|
class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
33
|
-
actor: Actor
|
|
34
|
-
agent: Agent
|
|
36
|
+
actor: models.Actor
|
|
37
|
+
agent: models.Agent
|
|
35
38
|
ex_client: BaseExClient
|
|
36
|
-
orders: dict[int, tuple[models.Order,
|
|
39
|
+
orders: dict[int, tuple[models.Order, BaseOrder]] = {} # pending
|
|
37
40
|
pm_clients: dict[int, PmAgentClient] # {pm_id: PmAgentClient}
|
|
38
41
|
api: HttpClient
|
|
39
42
|
cred_x2e: dict[int, int] = {}
|
|
@@ -44,15 +47,15 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
44
47
|
|
|
45
48
|
def __init__(
|
|
46
49
|
self,
|
|
47
|
-
agent: Agent, # agent.actor.person.user
|
|
50
|
+
agent: models.Agent, # agent.actor.person.user
|
|
48
51
|
ex_client: BaseExClient,
|
|
49
52
|
pm_clients: dict[int, PmAgentClient] = None,
|
|
50
53
|
headers: dict[str, str] = df_hdrs,
|
|
51
54
|
cookies: dict[str, str] = None,
|
|
52
55
|
proxy: models.Proxy = None,
|
|
53
56
|
):
|
|
54
|
-
self.agent: Agent = agent
|
|
55
|
-
self.actor: Actor = agent.actor
|
|
57
|
+
self.agent: models.Agent = agent
|
|
58
|
+
self.actor: models.Actor = agent.actor
|
|
56
59
|
# self.gmail = agent.actor.person.user.gmail and GmClient(agent.actor.person.user)
|
|
57
60
|
self.ex_client: BaseExClient = ex_client
|
|
58
61
|
self.pm_clients: dict[int, PmAgentClient] = defaultdict()
|
|
@@ -111,6 +114,11 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
111
114
|
await self.load_pending_orders()
|
|
112
115
|
await self.ads_share()
|
|
113
116
|
|
|
117
|
+
async def load_assets(self, coin_ids: list[int] = None) -> dict:
|
|
118
|
+
assets = {cid: await self.get_asset(cid) for cid in coin_ids} if coin_ids else await self.my_assets()
|
|
119
|
+
for cid, amount in assets.items():
|
|
120
|
+
await self.asset_save(cid, amount)
|
|
121
|
+
|
|
114
122
|
@abstractmethod
|
|
115
123
|
async def _get_creds(self) -> list[BaseModel]: ...
|
|
116
124
|
|
|
@@ -180,7 +188,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
180
188
|
@abstractmethod
|
|
181
189
|
async def _get_order_full(self, order_exid: int) -> BaseOrderFull: ...
|
|
182
190
|
|
|
183
|
-
async def get_order_full(self, order_exid: int) ->
|
|
191
|
+
async def get_order_full(self, order_exid: int) -> BaseOrder:
|
|
184
192
|
eorder: BaseOrderFull = await self._get_order_full(order_exid)
|
|
185
193
|
_, cur_scale, __ = await self.ex_client.x2e_cur(await self.ex_client.e2x_cur(eorder.curex_exid))
|
|
186
194
|
_, coin_scale = await self.ex_client.x2e_coin(await self.ex_client.e2x_coin(eorder.coinex_exid))
|
|
@@ -195,11 +203,11 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
195
203
|
amount=int(eorder.amount * 10**cur_scale),
|
|
196
204
|
quantity=int(eorder.quantity * 10**coin_scale),
|
|
197
205
|
)
|
|
198
|
-
return
|
|
206
|
+
return BaseOrder.model_validate(border)
|
|
199
207
|
|
|
200
|
-
async def load_order(self, order_exid: int, force_refresh: bool = False) -> tuple[models.Order,
|
|
208
|
+
async def load_order(self, order_exid: int, force_refresh: bool = False) -> tuple[models.Order, BaseOrder]:
|
|
201
209
|
if not self.orders.get(order_exid) or force_refresh:
|
|
202
|
-
order:
|
|
210
|
+
order: BaseOrder = await self.get_order_full(order_exid)
|
|
203
211
|
if not (
|
|
204
212
|
order_db := await models.Order.get_or_none(
|
|
205
213
|
exid=order_exid, ad__maker__ex=self.actor.ex
|
|
@@ -214,7 +222,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
214
222
|
self.orders[order_exid] = order_db, order
|
|
215
223
|
return self.orders[order_exid]
|
|
216
224
|
|
|
217
|
-
async def order_save(self, order:
|
|
225
|
+
async def order_save(self, order: BaseOrder) -> models.Order:
|
|
218
226
|
order_in = models.Order.validate(order.model_dump())
|
|
219
227
|
odb, _ = await models.Order.update_or_create(**order_in.df_unq())
|
|
220
228
|
|
|
@@ -265,10 +273,12 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
265
273
|
coin_id=pair.coin_id, cur_id=pair.cur_id, is_sell=bool(taker_side), pm_ids=pm_ids, amount=amt, limit=50
|
|
266
274
|
)
|
|
267
275
|
try:
|
|
268
|
-
ads: list[
|
|
276
|
+
ads: list[BaseAd] = await self.ex_client.ads(get_ads_req)
|
|
269
277
|
except Exception:
|
|
270
278
|
await sleep(1)
|
|
271
|
-
ads: list[
|
|
279
|
+
ads: list[BaseAd] = await self.ads(
|
|
280
|
+
coinex, curex, taker_side, pmexs, amt, 50, race.vm_filter, post_pmexs
|
|
281
|
+
)
|
|
272
282
|
|
|
273
283
|
self.overprice_filter(ads, race.ceil * 10**-curex.scale, k) # обрезаем сверху все ads дороже нашего потолка
|
|
274
284
|
|
|
@@ -289,7 +299,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
289
299
|
# ]
|
|
290
300
|
# for plc, ad in enumerate(rads)
|
|
291
301
|
# ]
|
|
292
|
-
mad:
|
|
302
|
+
mad: BaseAd = ads.pop(cur_plc)
|
|
293
303
|
# if (
|
|
294
304
|
# not (lstat := lstat or await race.stats.order_by("-created_at").first())
|
|
295
305
|
# or lstat.place != cur_plc
|
|
@@ -386,50 +396,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
386
396
|
# logging.warning("Connection failed. Restarting..")
|
|
387
397
|
await sleep(6)
|
|
388
398
|
|
|
389
|
-
async def
|
|
390
|
-
self,
|
|
391
|
-
coinex: models.CoinEx,
|
|
392
|
-
curex: models.CurEx,
|
|
393
|
-
pmexs: list[models.PmEx],
|
|
394
|
-
amount: int,
|
|
395
|
-
post_pmexs: list[models.PmEx] = None,
|
|
396
|
-
) -> tuple[list[Ad], list[Ad]]:
|
|
397
|
-
buy: list[Ad] = await self.ads(coinex, curex, False, pmexs, amount, 40, False, post_pmexs)
|
|
398
|
-
sell: list[Ad] = await self.ads(coinex, curex, True, pmexs, amount, 30, False, post_pmexs)
|
|
399
|
-
return buy, sell
|
|
400
|
-
|
|
401
|
-
async def get_spread(
|
|
402
|
-
self, bb: list[Ad], sb: list[Ad], perc: float, place: int = 0
|
|
403
|
-
) -> tuple[tuple[float, float], float, int] | None:
|
|
404
|
-
if len(bb) and len(sb):
|
|
405
|
-
buy_price, sell_price = float(bb[place].price), float(sb[place].price)
|
|
406
|
-
half_spread = (buy_price - sell_price) / (buy_price + sell_price)
|
|
407
|
-
if half_spread * 2 < perc:
|
|
408
|
-
return await self.get_spread(bb, sb, perc, place)
|
|
409
|
-
return (buy_price, sell_price), half_spread, place
|
|
410
|
-
return None
|
|
411
|
-
|
|
412
|
-
async def get_ceils(
|
|
413
|
-
self,
|
|
414
|
-
coinex: models.CoinEx,
|
|
415
|
-
curex: models.CurEx,
|
|
416
|
-
pmexs: list[models.PmEx],
|
|
417
|
-
min_prof=0.02,
|
|
418
|
-
place: int = 0,
|
|
419
|
-
amount: int = None,
|
|
420
|
-
post_pmexs: set[models.PmEx] = None,
|
|
421
|
-
) -> tuple[float, float]: # todo: refact to Pairex
|
|
422
|
-
for pmc_id in {pmx.pm_id for pmx in pmexs} | set(self.pm_clients.keys()):
|
|
423
|
-
if ceils := self.pm_clients[pmc_id].get_ceils():
|
|
424
|
-
return ceils
|
|
425
|
-
bb, sb = await self.get_books(coinex, curex, pmexs, amount, post_pmexs)
|
|
426
|
-
perc = list(post_pmexs or pmexs)[0].pm.fee * 0.0001 + min_prof
|
|
427
|
-
(bf, sf), _hp, _zplace = await self.get_spread(bb, sb, perc, place)
|
|
428
|
-
mdl = (bf + sf) / 2 # middle price
|
|
429
|
-
bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
|
|
430
|
-
return bc, sc
|
|
431
|
-
|
|
432
|
-
async def mad_upd(self, mad: Ad, attrs: dict, cxids: list[str]):
|
|
399
|
+
async def mad_upd(self, mad: BaseAd, attrs: dict, cxids: list[str]):
|
|
433
400
|
if not [setattr(mad, k, v) for k, v in attrs.items() if getattr(mad, k) != v]:
|
|
434
401
|
print(end="v" if mad.side else "^", flush=True)
|
|
435
402
|
return await sleep(5)
|
|
@@ -452,14 +419,14 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
452
419
|
# print("-" if mad.side else "+", end=req.price, flush=True)
|
|
453
420
|
await sleep(60)
|
|
454
421
|
|
|
455
|
-
def overprice_filter(self, ads: list[
|
|
422
|
+
def overprice_filter(self, ads: list[BaseAd], ceil: float, k: Literal[-1, 1]):
|
|
456
423
|
# вырезаем ads с ценами выше потолка
|
|
457
424
|
if ads and (ceil - float(ads[0].price)) * k > 0:
|
|
458
425
|
if int(ads[0].userId) != self.actor.exid:
|
|
459
426
|
ads.pop(0)
|
|
460
427
|
self.overprice_filter(ads, ceil, k)
|
|
461
428
|
|
|
462
|
-
def get_cad(self, ads: list[
|
|
429
|
+
def get_cad(self, ads: list[BaseAd], ceil: float, k: Literal[-1, 1], target_place: int, cur_plc: int) -> BaseAd:
|
|
463
430
|
if not ads:
|
|
464
431
|
return None
|
|
465
432
|
# чью цену будем обгонять, предыдущей или слещующей объявы?
|
|
@@ -468,7 +435,7 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
468
435
|
if len(ads) <= target_place:
|
|
469
436
|
logging.error(f"target place {target_place} not found in ads {len(ads)}-lenght list")
|
|
470
437
|
target_place = len(ads) - 1
|
|
471
|
-
cad:
|
|
438
|
+
cad: BaseAd = ads[target_place]
|
|
472
439
|
# а цена обгоняемой объявы не выше нашего потолка?
|
|
473
440
|
if (float(cad.price) - ceil) * k <= 0:
|
|
474
441
|
# тогда берем следующую
|
|
@@ -480,7 +447,11 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
480
447
|
# 0: Получшение ордеров в статусе status, по монете coin, в валюте coin, в направлении is_sell: bool
|
|
481
448
|
@abstractmethod
|
|
482
449
|
async def get_orders(
|
|
483
|
-
self,
|
|
450
|
+
self,
|
|
451
|
+
status: OrderStatus = OrderStatus.created,
|
|
452
|
+
coin: models.Coin = None,
|
|
453
|
+
cur: models.Cur = None,
|
|
454
|
+
is_sell: bool = None,
|
|
484
455
|
) -> list: ...
|
|
485
456
|
|
|
486
457
|
# 1: [T] Запрос на старт сделки
|
|
@@ -535,9 +506,9 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
535
506
|
|
|
536
507
|
# 30: Создание объявления
|
|
537
508
|
@abstractmethod
|
|
538
|
-
async def ad_new(self, ad: BaseAd) ->
|
|
509
|
+
async def ad_new(self, ad: BaseAd) -> int: ...
|
|
539
510
|
|
|
540
|
-
async def ad_upd(self, xreq
|
|
511
|
+
async def ad_upd(self, xreq) -> int:
|
|
541
512
|
xreq.credexs = await models.CredEx.filter(
|
|
542
513
|
ex_id=self.actor.ex_id,
|
|
543
514
|
cred__pmcur__pm_id__in=xreq.pm_ids,
|
|
@@ -545,14 +516,143 @@ class BaseAgentClient(HttpClient, BaseInAgentClient): # , metaclass=ABCMeta
|
|
|
545
516
|
cred__person_id=self.actor.person_id,
|
|
546
517
|
).prefetch_related("cred__pmcur")
|
|
547
518
|
# xreq.credexs = credexs
|
|
519
|
+
|
|
548
520
|
ereq = await self.x2e_req_ad_upd(xreq)
|
|
549
|
-
return await self.
|
|
521
|
+
return await self._ad_upd_api(ereq)
|
|
550
522
|
|
|
551
523
|
# 31: Редактирование объявления
|
|
552
524
|
@abstractmethod
|
|
553
|
-
async def
|
|
525
|
+
async def _ad_upd_api(self, ad: MyAdXOut) -> int: ...
|
|
526
|
+
|
|
527
|
+
async def ads_fresh(self, cur_id: int = 1, coin_id: int = 1):
|
|
528
|
+
"""
|
|
529
|
+
Обновляем/добавляем объявления агента, в зависимости от кол-ва объявлений которое он может размещать
|
|
530
|
+
одновременно `same_dir_ad` (от 1 до 4), и его текущего coin_balance.
|
|
531
|
+
"""
|
|
532
|
+
curex = await models.CurEx.get(cur_id=cur_id, ex_id=self.actor.ex_id)
|
|
533
|
+
usdt_bal = (await self.agent.coins_balance())[coin_id]
|
|
534
|
+
xbals = await self.actor.person.user.balances()
|
|
535
|
+
xbal = xbals[cur_id]
|
|
536
|
+
# В идеале, если он может размещать сразу 4 объявления, и имеет баланс не менее 50 минимальных размеров ордера,
|
|
537
|
+
# то постим 4 объявления:
|
|
538
|
+
# 1) с минимальным нижним лимитом размера ордера, и без фильтрации контрагентов
|
|
539
|
+
# 2) с минимальным лимитом, но с фильтрацией контрагентов
|
|
540
|
+
# 3) с 10x мин лимитом, и с фильтрацией (если вообще есть баланс от 10x min)
|
|
541
|
+
# 4) 50x мин лимит, либо весь баланс если он меньше, с фильтрацией (если есть баланс от 20x min)
|
|
542
|
+
if usdt_bal < curex.minimum:
|
|
543
|
+
return
|
|
544
|
+
fltr = dict(
|
|
545
|
+
my_ad__credexs__cred__ovr_pm_id=0,
|
|
546
|
+
my_ad__credexs__cred__pmcur__cur_id=cur_id,
|
|
547
|
+
pair_side__pair__coin_id=coin_id,
|
|
548
|
+
maker_id=self.agent.actor_id,
|
|
549
|
+
)
|
|
550
|
+
prftch = "my_ad__credexs", "pair_side__pair__coin", "pair_side__pair__cur"
|
|
554
551
|
|
|
555
|
-
|
|
552
|
+
bads = (
|
|
553
|
+
await models.Ad.filter(**fltr, status=AdStatus.active, pair_side__is_sell=False)
|
|
554
|
+
.order_by("min_fiat", "filtered")
|
|
555
|
+
.prefetch_related(*prftch)
|
|
556
|
+
.limit(self.agent.same_dir_ad)
|
|
557
|
+
)
|
|
558
|
+
if not bads:
|
|
559
|
+
return
|
|
560
|
+
bad = await bads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
561
|
+
if bad.min_fiat != curex.minimum and bad.filtered:
|
|
562
|
+
logging.error(bad.min_fiat) # need debug
|
|
563
|
+
if bad.amount != xbal:
|
|
564
|
+
bad.amount = xbal
|
|
565
|
+
bad.quantity = None
|
|
566
|
+
xma = MyAdXOut.model_validate(bad, from_attributes=True)
|
|
567
|
+
xma.cond_txt = hot_ad_cond
|
|
568
|
+
await self._ad_upd_api(xma)
|
|
569
|
+
|
|
570
|
+
if not bads:
|
|
571
|
+
return
|
|
572
|
+
bad = await bads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
573
|
+
if bad.min_fiat != curex.minimum and not bad.filtered:
|
|
574
|
+
logging.error(bad.min_fiat) # need debug
|
|
575
|
+
if bad.amount != xbal:
|
|
576
|
+
bad.amount = xbal
|
|
577
|
+
bad.quantity = None
|
|
578
|
+
xma = MyAdXOut.model_validate(bad, from_attributes=True)
|
|
579
|
+
xma.cond_txt = hot_ad_cond
|
|
580
|
+
await self._ad_upd_api(xma)
|
|
581
|
+
|
|
582
|
+
if not bads:
|
|
583
|
+
return
|
|
584
|
+
bad = await bads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
585
|
+
if curex.minimum * 2 <= bad.min_fiat < curex.minimum * 10 or bad.amount != xbal:
|
|
586
|
+
bad.min_fiat = min(xbal, curex.minimum * 10)
|
|
587
|
+
bad.amount = xbal
|
|
588
|
+
bad.quantity = None
|
|
589
|
+
xma = MyAdXOut.model_validate(bad, from_attributes=True)
|
|
590
|
+
xma.cond_txt = hot_ad_cond
|
|
591
|
+
await self._ad_upd_api(xma)
|
|
592
|
+
|
|
593
|
+
if not bads:
|
|
594
|
+
return
|
|
595
|
+
bad = await bads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
596
|
+
if curex.minimum * 20 <= bad.min_fiat < curex.minimum * 50 or bad.amount != xbal:
|
|
597
|
+
bad.min_fiat = min(xbal, curex.minimum * 10)
|
|
598
|
+
bad.amount = xbal
|
|
599
|
+
bad.quantity = None
|
|
600
|
+
xma = MyAdXOut.model_validate(bad, from_attributes=True)
|
|
601
|
+
xma.cond_txt = hot_ad_cond
|
|
602
|
+
await self._ad_upd_api(xma)
|
|
603
|
+
|
|
604
|
+
# sell
|
|
605
|
+
sads = (
|
|
606
|
+
await models.Ad.filter(**fltr, status=AdStatus.active, pair_side__is_sell=False)
|
|
607
|
+
.order_by("min_fiat", "filtered")
|
|
608
|
+
.prefetch_related(*prftch)
|
|
609
|
+
.limit(self.agent.same_dir_ad)
|
|
610
|
+
)
|
|
611
|
+
if not sads:
|
|
612
|
+
return
|
|
613
|
+
sad = await sads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
614
|
+
if sad.min_fiat != curex.minimum and sad.filtered:
|
|
615
|
+
logging.error(sad.min_fiat) # need debug
|
|
616
|
+
if sad.quantity != usdt_bal:
|
|
617
|
+
sad.quantity = usdt_bal
|
|
618
|
+
sad.amount = None
|
|
619
|
+
xma = MyAdXOut.model_validate(sad, from_attributes=True)
|
|
620
|
+
xma.cond_txt = hot_ad_cond
|
|
621
|
+
await self._ad_upd_api(xma)
|
|
622
|
+
|
|
623
|
+
if not sads:
|
|
624
|
+
return
|
|
625
|
+
sad = await sads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
626
|
+
if sad.min_fiat != curex.minimum and not sad.filtered:
|
|
627
|
+
logging.error(sad.min_fiat) # need debug
|
|
628
|
+
if sad.quantity != usdt_bal:
|
|
629
|
+
sad.quantity = usdt_bal
|
|
630
|
+
sad.amount = None
|
|
631
|
+
xma = MyAdXOut.model_validate(sad, from_attributes=True)
|
|
632
|
+
xma.cond_txt = hot_ad_cond
|
|
633
|
+
await self._ad_upd_api(xma)
|
|
634
|
+
|
|
635
|
+
if not sads:
|
|
636
|
+
return
|
|
637
|
+
sad = await sads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
638
|
+
if curex.minimum * 2 <= sad.min_fiat < curex.minimum * 10 or sad.quantity != usdt_bal:
|
|
639
|
+
sad.min_fiat = min(usdt_bal, curex.minimum * 10)
|
|
640
|
+
sad.quantity = usdt_bal
|
|
641
|
+
sad.amount = None
|
|
642
|
+
xma = MyAdXOut.model_validate(sad, from_attributes=True)
|
|
643
|
+
xma.cond_txt = hot_ad_cond
|
|
644
|
+
await self._ad_upd_api(xma)
|
|
645
|
+
|
|
646
|
+
if not sads:
|
|
647
|
+
return
|
|
648
|
+
sad = await sads.pop(0).to_float(ex_id=self.actor.ex_id)
|
|
649
|
+
if curex.minimum * 20 <= sad.min_fiat < curex.minimum * 50 or sad.quantity != usdt_bal:
|
|
650
|
+
sad.min_fiat = min(usdt_bal, curex.minimum * 10)
|
|
651
|
+
sad.quantity = usdt_bal
|
|
652
|
+
sad.amount = None
|
|
653
|
+
xma = MyAdXOut.model_validate(sad, from_attributes=True)
|
|
654
|
+
xma.cond_txt = hot_ad_cond
|
|
655
|
+
await self._ad_upd_api(xma)
|
|
556
656
|
|
|
557
657
|
# 32: Удаление
|
|
558
658
|
@abstractmethod
|
|
@@ -4,6 +4,7 @@ from abc import abstractmethod
|
|
|
4
4
|
from asyncio import sleep
|
|
5
5
|
from collections import defaultdict
|
|
6
6
|
from difflib import SequenceMatcher
|
|
7
|
+
from math import floor
|
|
7
8
|
|
|
8
9
|
from aiohttp import ClientSession, ClientResponse
|
|
9
10
|
from msgspec import Struct
|
|
@@ -72,7 +73,7 @@ class BaseExClient(HttpClient, AdLoader):
|
|
|
72
73
|
|
|
73
74
|
# 22: Список торгуемых монет (с ограничением по валютам, если есть)
|
|
74
75
|
@abstractmethod
|
|
75
|
-
async def coins(self) -> dict[str, xtype.CoinEx]: # {coin.ticker: coin}
|
|
76
|
+
async def coins(self, p2p_only: bool = False, cks: dict = None) -> dict[str, xtype.CoinEx]: # {coin.ticker: coin}
|
|
76
77
|
...
|
|
77
78
|
|
|
78
79
|
# 23: Список пар валюта/монет
|
|
@@ -182,16 +183,15 @@ class BaseExClient(HttpClient, AdLoader):
|
|
|
182
183
|
|
|
183
184
|
# 24: Список объяв по (buy/sell, cur, coin, pm)
|
|
184
185
|
async def ads(self, xreq: GetAdsReq, **kwargs) -> list[xtype.BaseAd]:
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
186
|
+
src = xreq.model_copy(
|
|
187
|
+
update=dict(
|
|
188
|
+
coin_id=(await self.x2e_coin(xreq.coin_id))[0],
|
|
189
|
+
cur_id=(await self.x2e_cur(xreq.cur_id))[0],
|
|
190
|
+
is_sell=str(int(xreq.is_sell)),
|
|
191
|
+
pm_ids=xreq.pm_ids and [await self.x2e_pm(pid) for pid in xreq.pm_ids],
|
|
192
|
+
)
|
|
192
193
|
)
|
|
193
|
-
|
|
194
|
-
ereq.amount = str(xreq.amount)
|
|
194
|
+
ereq = AdsReq.model_validate(src.model_dump(exclude_none=True))
|
|
195
195
|
return await self._ads(ereq, **kwargs)
|
|
196
196
|
|
|
197
197
|
@abstractmethod
|
|
@@ -332,25 +332,34 @@ class BaseExClient(HttpClient, AdLoader):
|
|
|
332
332
|
return file
|
|
333
333
|
|
|
334
334
|
# Импорт монет (с CoinEx-ами) с биржи в бд
|
|
335
|
-
async def set_coins(self):
|
|
336
|
-
coinexs: dict[str, xtype.CoinEx] = await self.coins()
|
|
335
|
+
async def set_coins(self, p2p_only: bool = True, cks: dict = None):
|
|
336
|
+
coinexs: dict[str, xtype.CoinEx] = await self.coins(p2p_only, cks)
|
|
337
337
|
coins_db: dict[int, models.Coin] = {
|
|
338
338
|
c.exid: (
|
|
339
|
-
await models.Coin.update_or_create(
|
|
339
|
+
await models.Coin.update_or_create(
|
|
340
|
+
{
|
|
341
|
+
"scale": c.scale if c.scale is not None else self.coin_scales[c.ticker],
|
|
342
|
+
"typ": c.typ,
|
|
343
|
+
},
|
|
344
|
+
ticker=c.ticker,
|
|
345
|
+
)
|
|
340
346
|
)[0]
|
|
341
347
|
for c in coinexs.values()
|
|
342
348
|
}
|
|
343
349
|
coinexs_db: list[models.CoinEx] = [
|
|
344
350
|
models.CoinEx(
|
|
345
|
-
scale=(scl := c.scale
|
|
351
|
+
scale=(scl := c.scale if c.scale is not None else self.coin_scales[c.ticker]),
|
|
346
352
|
coin=coins_db[c.exid],
|
|
347
353
|
ex=self.ex,
|
|
348
354
|
exid=c.exid,
|
|
349
355
|
minimum=c.minimum and c.minimum * 10**scl,
|
|
356
|
+
p2p=c.p2p,
|
|
350
357
|
)
|
|
351
358
|
for c in coinexs.values()
|
|
352
359
|
]
|
|
353
|
-
await models.CoinEx.bulk_create(
|
|
360
|
+
await models.CoinEx.bulk_create(
|
|
361
|
+
coinexs_db, update_fields=["minimum", "scale", "p2p"], on_conflict=["coin_id", "ex_id"]
|
|
362
|
+
)
|
|
354
363
|
return True
|
|
355
364
|
|
|
356
365
|
# Импорт пар биржи в бд
|
|
@@ -463,8 +472,8 @@ class BaseExClient(HttpClient, AdLoader):
|
|
|
463
472
|
pms = await models.Pm.filter(pmexs__ex=self.ex, pmexs__exid__in=base_ad.pmex_exids)
|
|
464
473
|
badd.update(
|
|
465
474
|
amount=int((base_ad.amount or base_ad.quantity * base_ad.price) * 10**cur_scale),
|
|
466
|
-
max_fiat=int(base_ad.max_fiat
|
|
467
|
-
min_fiat=int(base_ad.min_fiat
|
|
475
|
+
max_fiat=int(base_ad.max_fiat),
|
|
476
|
+
min_fiat=int(base_ad.min_fiat),
|
|
468
477
|
premium=int(base_ad.premium * 100_00),
|
|
469
478
|
price=int(base_ad.price * 10**cur_scale),
|
|
470
479
|
quantity=int((base_ad.quantity or base_ad.amount / base_ad.price) * 10**coin_scale),
|
|
@@ -665,6 +674,57 @@ class BaseExClient(HttpClient, AdLoader):
|
|
|
665
674
|
|
|
666
675
|
self.tree = tree
|
|
667
676
|
|
|
677
|
+
async def get_books(
|
|
678
|
+
self,
|
|
679
|
+
coin_id: int,
|
|
680
|
+
cur_id: int,
|
|
681
|
+
pm_ids: list[int] = None,
|
|
682
|
+
amount: int = None,
|
|
683
|
+
post_pms: list[models.Pm] = None,
|
|
684
|
+
) -> tuple[list[BaseAd], list[BaseAd]]:
|
|
685
|
+
sell_req = GetAdsReq(
|
|
686
|
+
coin_id=coin_id, cur_id=cur_id, is_sell=True, pm_ids=pm_ids, amount=amount, vm_only=True, limit=10
|
|
687
|
+
)
|
|
688
|
+
buy_req = GetAdsReq(
|
|
689
|
+
coin_id=coin_id, cur_id=cur_id, is_sell=False, pm_ids=pm_ids, amount=amount, vm_only=True, limit=10
|
|
690
|
+
)
|
|
691
|
+
return await self.ads(sell_req, post_pms=post_pms), await self.ads(buy_req, post_pms=post_pms)
|
|
692
|
+
|
|
693
|
+
async def get_spread(
|
|
694
|
+
self, bb: list[models.Ad], sb: list[models.Ad], perc: float, place: int = 0
|
|
695
|
+
) -> tuple[tuple[float, float], float, int] | None:
|
|
696
|
+
if len(bb) and len(sb):
|
|
697
|
+
buy_price, sell_price = float(bb[place].price), float(sb[place].price)
|
|
698
|
+
half_spread = (buy_price - sell_price) / (buy_price + sell_price)
|
|
699
|
+
if half_spread * 2 < perc:
|
|
700
|
+
return await self.get_spread(bb, sb, perc, place)
|
|
701
|
+
return (buy_price, sell_price), half_spread, place
|
|
702
|
+
return None
|
|
703
|
+
|
|
704
|
+
async def get_ceils(
|
|
705
|
+
self,
|
|
706
|
+
coinex: models.CoinEx,
|
|
707
|
+
curex: models.CurEx,
|
|
708
|
+
pmexs: list[models.PmEx],
|
|
709
|
+
min_prof=0.02,
|
|
710
|
+
place: int = 0,
|
|
711
|
+
amount: int = None,
|
|
712
|
+
post_pms: set[models.PmEx] = None,
|
|
713
|
+
) -> tuple[float, float]: # todo: refact to Pairex
|
|
714
|
+
for pmc_id in {pmx.pm_id for pmx in pmexs} | set(self.pm_clients.keys()):
|
|
715
|
+
if ceils := self.pm_clients[pmc_id].get_ceils():
|
|
716
|
+
return ceils
|
|
717
|
+
bb, sb = await self.get_books(coinex, curex, pmexs, amount, post_pms)
|
|
718
|
+
perc = list(post_pms or pmexs)[0].pm.fee * 0.0001 + min_prof
|
|
719
|
+
(bf, sf), _hp, _zplace = await self.get_spread(bb, sb, perc, place)
|
|
720
|
+
mdl = (bf + sf) / 2 # middle price
|
|
721
|
+
bc, sc = mdl + mdl * (perc / 2), mdl - mdl * (perc / 2)
|
|
722
|
+
return bc, sc
|
|
723
|
+
|
|
724
|
+
async def rate(self, cur_id: int, coin_id: int = 1) -> int:
|
|
725
|
+
bp, sp = await self.get_books(cur_id, coin_id)
|
|
726
|
+
return floor((sum(b.price for b in bp[5:]) + sum(s.price for s in sp[5:])) * 0.1)
|
|
727
|
+
|
|
668
728
|
async def init_seed(self, fbot: FileClient):
|
|
669
729
|
await self.set_curs()
|
|
670
730
|
await self.set_coins()
|