xync-client 0.0.162__py3-none-any.whl → 0.0.172__py3-none-any.whl
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/Abc/Agent.py +154 -22
- xync_client/Abc/Ex.py +107 -127
- xync_client/Abc/Order.py +16 -17
- xync_client/Abc/xtype.py +139 -65
- xync_client/BingX/agent.py +1 -1
- xync_client/BitGet/agent.py +1 -3
- xync_client/Bybit/agent.py +80 -331
- xync_client/Bybit/etype/ad.py +79 -58
- xync_client/Bybit/etype/cred.py +25 -3
- xync_client/Bybit/etype/order.py +150 -95
- xync_client/Bybit/ex.py +24 -12
- xync_client/Bybit/{InAgent.py → inAgent.py} +5 -10
- xync_client/Bybit/order.py +33 -16
- xync_client/Htx/agent.py +9 -9
- xync_client/Htx/etype/ad.py +2 -4
- xync_client/Htx/etype/test.py +4 -4
- xync_client/Htx/ex.py +35 -3
- xync_client/Mexc/agent.py +6 -6
- xync_client/Mexc/ex.py +2 -2
- xync_client/TgWallet/agent.py +21 -21
- xync_client/TgWallet/ex.py +11 -11
- xync_client/TgWallet/pyd.py +5 -5
- xync_client/pm_unifier.py +3 -2
- {xync_client-0.0.162.dist-info → xync_client-0.0.172.dist-info}/METADATA +1 -1
- {xync_client-0.0.162.dist-info → xync_client-0.0.172.dist-info}/RECORD +27 -27
- {xync_client-0.0.162.dist-info → xync_client-0.0.172.dist-info}/WHEEL +0 -0
- {xync_client-0.0.162.dist-info → xync_client-0.0.172.dist-info}/top_level.txt +0 -0
xync_client/Abc/Order.py
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
from abc import abstractmethod
|
|
2
2
|
|
|
3
|
-
from
|
|
4
|
-
|
|
5
|
-
from xync_client.Bybit.agent import AgentClient
|
|
3
|
+
from xync_client.Abc.Agent import BaseAgentClient
|
|
4
|
+
from xync_schema.models import Order, PmEx, CredEx
|
|
6
5
|
|
|
7
6
|
|
|
8
7
|
class BaseOrderClient:
|
|
@@ -10,32 +9,32 @@ class BaseOrderClient:
|
|
|
10
9
|
im_maker: bool
|
|
11
10
|
im_seller: bool
|
|
12
11
|
|
|
13
|
-
def __init__(self, order: Order, agent_client:
|
|
12
|
+
def __init__(self, order: Order, agent_client: BaseAgentClient):
|
|
14
13
|
self.order = order
|
|
15
14
|
self.im_maker = order.taker_id != agent_client.actor.id # or order.ad.agent_id == agent.id
|
|
16
15
|
self.im_seller = order.ad.pair_side.is_sell and self.im_maker
|
|
17
16
|
self.agent_client = agent_client
|
|
18
17
|
|
|
19
|
-
# 2: [T] Отмена запроса на сделку
|
|
20
|
-
@abstractmethod
|
|
21
|
-
async def cancel_request(self) -> Order: ...
|
|
22
|
-
|
|
23
|
-
# 3: [M] Одобрить запрос на сделку
|
|
24
|
-
@abstractmethod
|
|
25
|
-
async def accept_request(self) -> bool: ...
|
|
26
|
-
|
|
27
|
-
# 4: [M] Отклонить запрос на сделку
|
|
28
|
-
@abstractmethod
|
|
29
|
-
async def reject_request(self) -> bool: ...
|
|
30
|
-
|
|
31
18
|
# 5: [B] Перевод сделки в состояние "оплачено", c отправкой чека
|
|
19
|
+
async def mark_payed(self, cred_id: int = None, receipt: bytes = None):
|
|
20
|
+
cred_id = cred_id or self.order.cred_id
|
|
21
|
+
pmex = await PmEx.get(pm__pmcurs__id=self.order.cred.pmcur_id, ex=self.agent_client.ex_client.ex)
|
|
22
|
+
credex = await CredEx.get(cred_id=cred_id, ex=self.agent_client.ex_client.ex)
|
|
23
|
+
await self._mark_payed(credex.exid, pmex.exid, receipt)
|
|
24
|
+
|
|
32
25
|
@abstractmethod
|
|
33
|
-
async def
|
|
26
|
+
async def _mark_payed(self, credex_exid: int = None, pmex_exid: int | str = None, receipt: bytes = None): ...
|
|
34
27
|
|
|
35
28
|
# 6: [B] Отмена сделки
|
|
36
29
|
@abstractmethod
|
|
37
30
|
async def cancel_order(self) -> bool: ...
|
|
38
31
|
|
|
32
|
+
# 6: Запрос отмены (оплаченная контрагентом продажа)
|
|
33
|
+
async def cancel_request(self) -> bool: ...
|
|
34
|
+
|
|
35
|
+
# 6: Одобрение запроса на отмену (оплаченная мной покупка)
|
|
36
|
+
async def cancel_accept(self): ...
|
|
37
|
+
|
|
39
38
|
# 7: [S] Подтвердить получение оплаты
|
|
40
39
|
@abstractmethod
|
|
41
40
|
async def confirm(self) -> bool: ...
|
xync_client/Abc/xtype.py
CHANGED
|
@@ -1,9 +1,14 @@
|
|
|
1
|
+
import re
|
|
1
2
|
from typing import Literal, ClassVar
|
|
2
3
|
|
|
3
|
-
from pydantic import BaseModel, model_validator, model_serializer
|
|
4
|
+
from pydantic import BaseModel, model_validator, model_serializer, Field
|
|
5
|
+
from pydantic_core.core_schema import SerializationInfo
|
|
6
|
+
from tortoise.expressions import Q
|
|
7
|
+
from tortoise.functions import Count
|
|
8
|
+
from x_model.func import ArrayAgg
|
|
4
9
|
from x_model.types import BaseUpd
|
|
5
|
-
from xync_schema.enums import PmType
|
|
6
|
-
from xync_schema.models import Country, Pm, Ex, CredEx
|
|
10
|
+
from xync_schema.enums import PmType, Side, AdStatus, OrderStatus
|
|
11
|
+
from xync_schema.models import Country, Pm, Ex, CredEx, Cur
|
|
7
12
|
from xync_schema.xtype import PmExBank
|
|
8
13
|
|
|
9
14
|
from xync_client.pm_unifier import PmUni
|
|
@@ -27,12 +32,13 @@ class RemapBase(BaseModel):
|
|
|
27
32
|
return data
|
|
28
33
|
|
|
29
34
|
@model_serializer
|
|
30
|
-
def _map_out(self):
|
|
31
|
-
data = self
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
35
|
+
def _map_out(self, srlz_info: SerializationInfo):
|
|
36
|
+
data = dict(self)
|
|
37
|
+
if srlz_info.by_alias:
|
|
38
|
+
for field, mapping in self._remap.items():
|
|
39
|
+
reverse = {v: k for k, v in mapping.items()}
|
|
40
|
+
if field in data:
|
|
41
|
+
data[field] = reverse.get(data[field], data[field])
|
|
36
42
|
return data
|
|
37
43
|
|
|
38
44
|
|
|
@@ -65,74 +71,80 @@ class PmExIn(BaseModel):
|
|
|
65
71
|
arbitrary_types_allowed = True
|
|
66
72
|
|
|
67
73
|
|
|
68
|
-
class
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
class BaseOrderReq(BaseModel):
|
|
73
|
-
ad_id: int | str
|
|
74
|
-
|
|
75
|
-
asset_amount: float | None = None
|
|
76
|
-
fiat_amount: float | None = None
|
|
77
|
-
|
|
78
|
-
pmex_exid: str = None # int
|
|
79
|
-
|
|
80
|
-
# todo: mv from base to special ex class
|
|
81
|
-
amount_is_fiat: bool = True
|
|
82
|
-
is_sell: bool = None
|
|
83
|
-
cur_exid: int | str = None
|
|
84
|
-
coin_exid: int | str = None
|
|
85
|
-
coin_scale: int = None
|
|
74
|
+
class BaseActor(BaseModel):
|
|
75
|
+
exid: int | str
|
|
76
|
+
nick: str | None = None
|
|
86
77
|
|
|
87
|
-
@model_validator(mode="after")
|
|
88
|
-
def check_a_or_b(self):
|
|
89
|
-
if self.amount_is_fiat and not self.fiat_amount:
|
|
90
|
-
raise ValueError("fiat_amount is required if amount_is_fiat")
|
|
91
|
-
if not self.amount_is_fiat and not self.asset_amount:
|
|
92
|
-
raise ValueError("asset_amount is required if not amount_is_fiat")
|
|
93
|
-
if not self.asset_amount and not self.fiat_amount:
|
|
94
|
-
raise ValueError("either fiat_amount or asset_amount is required")
|
|
95
|
-
return self
|
|
96
78
|
|
|
79
|
+
class BaseCounteragent(BaseActor):
|
|
80
|
+
name: str
|
|
97
81
|
|
|
98
|
-
class BaseOrderPaidReq(BaseModel):
|
|
99
|
-
ad_id: int | str
|
|
100
82
|
|
|
101
|
-
|
|
102
|
-
|
|
83
|
+
class BaseCredEx(BaseModel):
|
|
84
|
+
detail: str
|
|
85
|
+
exid: int | str = Field(alias="id")
|
|
86
|
+
extra: str | None = None
|
|
87
|
+
name: str
|
|
88
|
+
pmex_exid: int | str
|
|
89
|
+
curex_exid: int | str = None # fills on outer BaseOrderFull validation hook
|
|
90
|
+
seller: BaseCounteragent = None # fills on outer BaseOrderFull validation hook
|
|
91
|
+
|
|
92
|
+
async def guess_cur(self, curs: list[Cur] = None):
|
|
93
|
+
curs = {c.ticker: c.id for c in curs or await Cur.all()}
|
|
94
|
+
for cur, cid in curs.items():
|
|
95
|
+
if re.search(re.compile(rf"\({cur}\)"), self.extra + self.detail):
|
|
96
|
+
return cid
|
|
97
|
+
lower_extras = [mb.lower() for mb in self.extra.split(" | ")]
|
|
98
|
+
if (
|
|
99
|
+
pms := await Pm.filter(Q(join_type="OR", pmexs__name__in=lower_extras, norm__in=self.extra.split(" | ")))
|
|
100
|
+
.group_by("pmcurs__cur_id", "pmcurs__cur__ticker")
|
|
101
|
+
.annotate(ccnt=Count("id"), names=ArrayAgg("norm"))
|
|
102
|
+
.order_by("-ccnt", "pmcurs__cur__ticker")
|
|
103
|
+
.values("pmcurs__cur_id", "names", "ccnt")
|
|
104
|
+
):
|
|
105
|
+
return pms[0]["pmcurs__cur_id"]
|
|
106
|
+
return None
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
class BaseAd(BaseModel):
|
|
110
|
+
amount: float | None = None
|
|
111
|
+
auto_msg: str | None = None
|
|
112
|
+
cond_txt: str
|
|
113
|
+
created_at: int # utc(0) seconds
|
|
114
|
+
coinex_exid: int | str
|
|
115
|
+
curex_exid: int | str
|
|
116
|
+
exid: int | str = Field(alias="id")
|
|
117
|
+
maker_exid: int | str
|
|
118
|
+
maker_name: str
|
|
119
|
+
maker: BaseActor = None
|
|
120
|
+
max_fiat: int
|
|
121
|
+
min_fiat: int
|
|
122
|
+
# paymentPeriod: int
|
|
123
|
+
pmex_exids: list[int | str]
|
|
124
|
+
premium: float
|
|
125
|
+
price: float
|
|
126
|
+
quantity: float | None = None
|
|
127
|
+
# recentOrderNum: int
|
|
128
|
+
side: Literal[Side.BUY, Side.SALE]
|
|
129
|
+
status: Literal[AdStatus.active, AdStatus.defActive, AdStatus.soldOut] # 10: online; 20: offline; 30: completed
|
|
103
130
|
|
|
104
131
|
@model_validator(mode="after")
|
|
105
|
-
def
|
|
106
|
-
if not self.
|
|
107
|
-
raise ValueError("either
|
|
132
|
+
def amount_or_quantity_required(self):
|
|
133
|
+
if not self.amount and not self.quantity:
|
|
134
|
+
raise ValueError("either amount or quantity is required")
|
|
135
|
+
self.maker = BaseActor(exid=self.maker_exid, nick=self.maker_name and self.maker_name)
|
|
108
136
|
return self
|
|
109
137
|
|
|
110
138
|
|
|
111
|
-
class
|
|
112
|
-
|
|
139
|
+
class BaseCredexsExidsTrait:
|
|
140
|
+
credex_exids: list[int]
|
|
113
141
|
|
|
114
142
|
|
|
115
|
-
class
|
|
116
|
-
|
|
117
|
-
createDate: str
|
|
118
|
-
currencyId: str
|
|
119
|
-
maxAmount: str
|
|
120
|
-
minAmount: str
|
|
121
|
-
nickName: str
|
|
122
|
-
paymentPeriod: int
|
|
123
|
-
payments: list[str]
|
|
124
|
-
premium: str
|
|
125
|
-
price: str
|
|
126
|
-
priceType: Literal[0, 1] # 0 - fix rate, 1 - floating
|
|
127
|
-
quantity: str
|
|
128
|
-
recentOrderNum: int
|
|
129
|
-
remark: str
|
|
130
|
-
side: Literal[0, 1] # 0 - покупка, 1 - продажа
|
|
131
|
-
tokenId: str
|
|
132
|
-
userId: str
|
|
143
|
+
class BaseCredexsTrait:
|
|
144
|
+
credex_exids: list[BaseCredEx]
|
|
133
145
|
|
|
134
146
|
|
|
135
|
-
class
|
|
147
|
+
class GetAdsReq(BaseModel):
|
|
136
148
|
coin_id: int | str
|
|
137
149
|
cur_id: int | str
|
|
138
150
|
is_sell: bool
|
|
@@ -148,7 +160,7 @@ class GetAds(BaseModel):
|
|
|
148
160
|
kwargs: dict = {}
|
|
149
161
|
|
|
150
162
|
|
|
151
|
-
class
|
|
163
|
+
class AdUpdReq(BaseAd, GetAdsReq):
|
|
152
164
|
price: float
|
|
153
165
|
pm_ids: list[int | str]
|
|
154
166
|
amount: float
|
|
@@ -160,3 +172,65 @@ class AdUpd(BaseAdUpdate, GetAds):
|
|
|
160
172
|
|
|
161
173
|
class Config:
|
|
162
174
|
arbitrary_types_allowed = True
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
class BaseOrder(BaseModel):
|
|
178
|
+
ad__pair_side__is_sell: bool # int: 0 покупка, 1 продажа (именно для меня - апи агента, и пох мейкер я или тейкер)
|
|
179
|
+
created_at: int
|
|
180
|
+
exid: int = Field(alias="id")
|
|
181
|
+
my_exid: int | None = None # апи агент юзер
|
|
182
|
+
status: OrderStatus
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
class BaseOrderItem(BaseOrder):
|
|
186
|
+
amount: float | None = None
|
|
187
|
+
pmex_exid: int | str = None # int
|
|
188
|
+
quantity: float | None = None
|
|
189
|
+
ctr_exid: int | None = None # контрагент
|
|
190
|
+
ctr_nick: str | None = None
|
|
191
|
+
taker_exid: int | None = None # в байбите нету
|
|
192
|
+
curex_exid: int | str = None
|
|
193
|
+
coinex_exid: int | str = None
|
|
194
|
+
seller_name: str
|
|
195
|
+
buyer_name: str
|
|
196
|
+
|
|
197
|
+
@model_validator(mode="after")
|
|
198
|
+
def amount_or_quantity_required(self):
|
|
199
|
+
if not self.amount and not self.quantity:
|
|
200
|
+
raise ValueError("either amount or quantity is required")
|
|
201
|
+
return self
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
class BaseOrderFull(BaseOrderItem):
|
|
205
|
+
ad_id: int | str
|
|
206
|
+
ad__maker_exid: int | None = None
|
|
207
|
+
credex: BaseCredEx
|
|
208
|
+
my_nick: str = Field(alias="nickName")
|
|
209
|
+
taker: BaseCounteragent = None # fills on validation hook
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
class BaseOrderReq(BaseModel):
|
|
213
|
+
ad_id: int | str
|
|
214
|
+
|
|
215
|
+
quantity: float | None = None
|
|
216
|
+
amount: float | None = None
|
|
217
|
+
|
|
218
|
+
pmex_exid: str = None # int
|
|
219
|
+
|
|
220
|
+
is_sell: bool = None
|
|
221
|
+
cur_exid: int | str = None
|
|
222
|
+
coin_exid: int | str = None
|
|
223
|
+
coin_scale: int = None
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
class BaseOrderPaidReq(BaseModel):
|
|
227
|
+
ad_id: int | str
|
|
228
|
+
|
|
229
|
+
cred_id: int | None = None
|
|
230
|
+
pm_id: int | None = None # or pmcur_id?
|
|
231
|
+
|
|
232
|
+
@model_validator(mode="after")
|
|
233
|
+
def check_a_or_b(self):
|
|
234
|
+
if not self.cred_id and not self.pm_id:
|
|
235
|
+
raise ValueError("either cred_id or pm_id is required")
|
|
236
|
+
return self
|
xync_client/BingX/agent.py
CHANGED
xync_client/BitGet/agent.py
CHANGED
|
@@ -2,13 +2,11 @@ import json
|
|
|
2
2
|
import subprocess
|
|
3
3
|
from asyncio import run
|
|
4
4
|
from x_model import init_db
|
|
5
|
-
from xync_schema import models
|
|
6
5
|
from xync_schema.enums import AdStatus, PmType, OrderStatus
|
|
7
6
|
from xync_schema.models import User, Pm, Coin, Cur, Ad, Fiat, Order, Agent
|
|
8
7
|
from xync_schema.pydantic import FiatNew
|
|
9
8
|
|
|
10
9
|
from xync_client.Abc.Agent import BaseAgentClient
|
|
11
|
-
from xync_client.loader import PG_DSN
|
|
12
10
|
|
|
13
11
|
|
|
14
12
|
class Client(BaseAgentClient):
|
|
@@ -50,7 +48,7 @@ class Client(BaseAgentClient):
|
|
|
50
48
|
async def fiat_del(self, fiat_id: int) -> bool:
|
|
51
49
|
pass
|
|
52
50
|
|
|
53
|
-
async def
|
|
51
|
+
async def get_my_ads(self) -> list[Ad]:
|
|
54
52
|
pass
|
|
55
53
|
|
|
56
54
|
async def ad_new(
|