xync-client 0.1.3__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.

Potentially problematic release.


This version of xync-client might be problematic. Click here for more details.

@@ -0,0 +1,83 @@
1
+ import hashlib
2
+ import hmac
3
+ from asyncio import run
4
+ from time import time
5
+
6
+ from aiohttp import ClientSession
7
+
8
+ # mixartemev
9
+ client = {
10
+ 'key': 'yvF6tsx2hOsn4kDclN8VlHArWZ9FOeZBHuUpIINKfQxyYPZziQsLPJiGMo1amkE1',
11
+ 'secret': 'oTTnWwbOTR3RcjWOXaQuE8JzxZ7P6v7UnAn08azt79l5ZkbKJUXjF5syc9mRS96C'
12
+ }
13
+ # alena
14
+ # client = Spot(key='dtyLk0I4S4zlWMN6sqO1aFtHKfjDcjstTbG2fuSpfZVEvr2NJLnUnSt0UFyCyHGv', secret='EE3tnb8I2IZGYtWUt72wXZ3NrIaKqUkaGFgMoHxRtkTas2y8EuKK0sQg1jcbGwTI')
15
+
16
+ host = 'https://api.binance.com/'
17
+ ws_host = 'wss://stream.binance.com:9443'
18
+
19
+ earn_lock = '/sapi/v1/simple-earn/locked/list'
20
+ earn_flex = '/sapi/v1/simple-earn/locked/list'
21
+ c2c_hist = 'sapi/v1/c2c/orderMatch/listUserOrderHistory'
22
+ ex_data = 'sapi/v1/convert/exchangeInfo'
23
+
24
+
25
+
26
+ async def get_prv(path: str, params: {} = None, cln: {} = None):
27
+ cln, params = cln or client, params or {}
28
+ def sign(prms: {}) -> {}:
29
+ """Makes a signature and adds it to the params dictionary."""
30
+ data = list(prms.items())
31
+ query: str = '&'.join(["{}={}".format(d[0], d[1]) for d in data])
32
+ m = hmac.new(cln['secret'].encode(), query.encode(), hashlib.sha256)
33
+ prms.update({'signature': m.hexdigest()})
34
+ return prms
35
+
36
+ headers = {'X-MBX-APIKEY': cln['key']}
37
+ params.update({'timestamp': f'{round(time() * 1000)}'})
38
+ params = sign(params)
39
+
40
+ async with ClientSession() as session:
41
+ resp = await session.get(host + path, headers=headers, params=params)
42
+ return await resp.json()
43
+
44
+
45
+ async def spot_prices(*tickers: str):
46
+ symbols = '["' + '","'.join(tickers) + '"]'
47
+ resp = await get_prv('api/v3/ticker/price', {'symbols': symbols} if tickers else None)
48
+ return {r['symbol']: float(r['price']) for r in resp} if type(resp) is list else {}
49
+
50
+
51
+ async def c2c_hst(user: {}, tt: str):
52
+ resp = await get_prv(c2c_hist, user, {'tradeType': tt})
53
+ return resp['data'], resp['total']
54
+
55
+ async def get_earn_locks(page: int = 1, size: int = 100):
56
+ resp = await get_prv(earn_lock, {'current': page, 'size': 100})
57
+ return resp['data'], resp['total']
58
+
59
+
60
+ # # spot assets
61
+ # a = client.user_asset()
62
+ # print(a)
63
+ #
64
+ # # funding assets
65
+ # f = client.funding_wallet()
66
+ # print(f)
67
+ #
68
+ # # transfer
69
+ # # t = client.user_universal_transfer(type='FUNDING_MAIN', asset='BUSD', amount=11)
70
+ # # print(t)
71
+ #
72
+ # n = client.ticker_price('USDTRUB')
73
+ #
74
+ # r = client.enable_fast_withdraw()
75
+ # r = client.withdraw(coin='SHIB', amount=100000, walletType=1, address='0x2469f1a2aa61dba2107d9905d94f1efa9f60eadc', network='BSC', withdrawOrderId=357058112)
76
+ # print(r)
77
+
78
+
79
+ if __name__ == "__main__":
80
+ # res = run(spot_prices())
81
+ # res = run(c2c_hst(client, 'BUY'))
82
+ res = run(get_earn_locks(3))
83
+ print(res)
@@ -0,0 +1,83 @@
1
+ from binance import AsyncClient
2
+
3
+
4
+ class Ebac(AsyncClient): # Earn Binance async client
5
+ HOST = 'https://api-gcp.binance.com/sapi/v1/simple-earn/'
6
+
7
+ async def _req(self, url: str, params: dict = None, is_post: bool = True) -> dict:
8
+ return await self._request('post' if is_post else 'get', self.HOST+url, True, data=params or {})
9
+
10
+ async def _get_pub(self, url: str, params: dict = None) -> dict:
11
+ return await self._request('get', url, False, data=params or {})
12
+
13
+ async def flex_products(self, page: int = 1, asset: str = None) -> []:
14
+ res = await self._req('flexible/list', {'current': page, 'size': 100, 'asset': asset}, False)
15
+ for i in range(res['total'] // 100):
16
+ res['rows'] += (await self._req('flexible/list', {'current': i+2, 'size': 100, 'asset': asset}, False))['rows']
17
+ return res['rows']
18
+
19
+ async def lock_products(self, page: int = 1, asset: str = None) -> []:
20
+ res = await self._req('locked/list', {'current': page, 'size': 100, 'asset': asset}, False)
21
+ for i in range(res['total'] // 100):
22
+ res['rows'] += (await self._req('locked/list', {'current': i+2, 'size': 100, 'asset': asset}, False))['rows']
23
+ return res['rows']
24
+
25
+ async def buy_flex_product(self, product_id: str, amount: float) -> dict:
26
+ return await self._req('flexible/subscribe', {'productId': product_id, 'amount': amount, 'autoSubscribe': True})
27
+
28
+ async def buy_lock_product(self, product_id: str, amount: float) -> dict:
29
+ return await self._req('locked/subscribe', {'productId': product_id, 'amount': amount, 'autoSubscribe': True})
30
+
31
+ async def redeem_lock_product(self, position_id: int) -> dict:
32
+ return await self._req('locked/redeem', {'positionId': position_id})
33
+
34
+ async def redeem_flex_product(self, position_id: int, amount: float = None) -> dict:
35
+ params = {'positionId': position_id, **({'amount': amount} if amount else {'redeemAll': True})}
36
+ return await self._req('flexible/redeem', params)
37
+
38
+ async def flex_position(self, product_id: str = None) -> []:
39
+ res = await self._req('flexible/position', {'productId': product_id, 'size': 100}, False)
40
+ return res['rows']
41
+
42
+ async def lock_position(self, position_id: int = None, project_id: str = None, page: int = 1) -> []:
43
+ res = await self._req('locked/position', {'positionId': position_id, 'projectId': project_id, 'size': 100, 'current': page}, False)
44
+ return res['rows']
45
+
46
+ async def account(self) -> dict:
47
+ return await self._req('account', is_post=False)
48
+
49
+ async def flex_buy_history(self, product_id: str, purchase_id: int = None, asset: str = None) -> []:
50
+ res = await self._req('flexible/history/subscriptionRecord', {
51
+ 'productId': product_id, 'purchaseId': purchase_id, 'asset': asset, 'size': 100
52
+ }, False)
53
+ return res['rows']
54
+
55
+ async def lock_buy_history(self, purchase_id: int = None, asset: str = None) -> []:
56
+ res = await self._req('locked/history/subscriptionRecord', {
57
+ 'purchaseId': purchase_id, 'asset': asset, 'size': 100
58
+ }, False)
59
+ return res['rows']
60
+
61
+ async def flex_redeem_history(self, product_id: str, redeem_id: int = None, asset: str = None) -> []:
62
+ res = await self._req('flexible/history/subscriptionRecord', {
63
+ 'productId': product_id, 'redeemId': redeem_id, 'asset': asset, 'size': 100
64
+ }, False)
65
+ return res['rows']
66
+
67
+ async def lock_redeem_history(self, position_id: int, redeem_id: int = None, asset: str = None) -> []:
68
+ res = await self._req('locked/history/subscriptionRecord', {
69
+ 'positionId': position_id, 'redeemId': redeem_id, 'asset': asset, 'size': 100
70
+ }, False)
71
+ return res['rows']
72
+
73
+ async def flex_quota(self, product_id: str) -> float:
74
+ res = await self._req('locked/personalLeftQuota', {'productId': product_id}, False)
75
+ return float(res['leftPersonalQuota'])
76
+
77
+ async def lock_quota(self, product_id: str) -> float:
78
+ res = await self._req('locked/personalLeftQuota', {'productId': product_id}, False)
79
+ return float(res['leftPersonalQuota'])
80
+
81
+ async def get_beth_rate(self) -> float:
82
+ res = await self._get_pub('https://www.binance.com/bapi/earn/v1/public/pos/cftoken/project/getPurchasableProject')
83
+ return float(res['data']['annualInterestRate'])
@@ -0,0 +1,267 @@
1
+ import hashlib
2
+ import hmac
3
+ from enum import StrEnum
4
+ from time import time
5
+
6
+ from xync_schema import models
7
+ from xync_schema.models import Pm, Coin, Ex, TradeType, Cur, Pair, Ad
8
+ from binance.exceptions import BinanceAPIException, BinanceRequestException
9
+ from asyncio import run
10
+ from aiohttp import ClientResponse
11
+ from http_client import Client
12
+ from more_itertools import batched
13
+ from tortoise_api_model import init_db
14
+
15
+ from cex_clients.loader import BKEY, BSEC, DSN
16
+ from requests import get
17
+
18
+
19
+ class Ep(StrEnum):
20
+ GET_AD = 'ads/getDetailByNo' # 2
21
+ GET_REF_PRICE = 'ads/getReferencePrice' # 3
22
+ GET_MY_ADS = 'ads/listWithPagination' # 4
23
+ POST_AD = 'ads/post' # 5
24
+ GET_PMS = 'paymentMethod/listAll' # 37
25
+ GET_CHAT = 'chat/retrieveChatMessagesWithPagination' # 43
26
+
27
+
28
+ class Sapi(Client):
29
+ base_url = 'https://api-gcp.binance.com'
30
+ middle_url = '/sapi/v1/c2c/'
31
+
32
+ def __init__(self, key: str, secret: str):
33
+ self.key = key
34
+ self.secret = secret
35
+ self.headers = {'X-MBX-APIKEY': key}
36
+ super().__init__()
37
+
38
+ def __sign(self, params: dict):
39
+ ts = get('https://api-gcp.binance.com/api/v3/time').json()['serverTime']
40
+ params = {**(params or {}), 'timestamp': ts}
41
+ """Makes a signature and adds it to the params dictionary."""
42
+ query: str = '&'.join(f'{k}={v}' for k, v in params.items())
43
+ m = hmac.new(self.secret.encode('utf-8'), query.encode('utf-8'), hashlib.sha256)
44
+ return {**params, 'signature': m.hexdigest()}
45
+
46
+ async def _get(self, endpoint: str, params: dict = None):
47
+ res = await self.get(endpoint, self.__sign(params))
48
+ return res.get('data', res)
49
+
50
+ async def _post(self, endpoint: str, data: dict = None, params: dict = None):
51
+ res = await self.post(endpoint, data, self.__sign(params))
52
+ return res
53
+
54
+ """ PUBLIC METHS """
55
+ # 2: Get details of a specific advertisement
56
+ async def get_ad(self, ad_num: int):
57
+ return await self._post(Ep.GET_AD, {'adsNo': ad_num})
58
+
59
+ # 3
60
+ async def get_ref_price(self, assets: [Coin], fiat: Cur, tt: TradeType):
61
+ body = {
62
+ 'assets': [a.ticker for a in assets], # len <= 3
63
+ 'fiatCurrency': fiat.ticker,
64
+ 'fromUserRole': 'USER', # ADVERTISER
65
+ 'payType': 'BANK', # WECHAT
66
+ 'tradeType': tt.name
67
+ }
68
+ return await self._post(Ep.GET_REF_PRICE, body)
69
+
70
+ # 4
71
+ async def get_my_ads(self, page: int = 1, rows: int = 100):
72
+ body = {
73
+ # "advNo": "string",
74
+ # "advStatus": 0,
75
+ # "asset": "string",
76
+ # "classify": "string",
77
+ # "endDate": "2019-08-24T14:15:22Z", "fiatUnit": "string",
78
+ # "inDeal": 0,
79
+ # "order": "string",
80
+ 'page': page,
81
+ 'rows': rows,
82
+ # "sort": "string",
83
+ # "startDate": "2019-08-24T14:15:22Z", "tradeType": "string"
84
+ }
85
+ return await self._post(Ep.GET_MY_ADS, body)
86
+
87
+ # 5
88
+ async def post_ad(self, asset: [Coin], fiat: Cur, tt: TradeType, amount: float, price: float, min_limit: int, max_limit: int, auto_reply: str = ''):
89
+ body = {
90
+ "asset": asset,
91
+ "authType": "GOOGLE",
92
+ "autoReplyMsg": auto_reply,
93
+ "buyerBtcPositionLimit": 0,
94
+ "buyerKycLimit": 0,
95
+ "buyerRegDaysLimit": 0,
96
+ "classify": "mass", # profession, block, f2f
97
+ "code": "string",
98
+ # "emailVerifyCode": "string",
99
+ "fiatUnit": fiat,
100
+ "googleVerifyCode": "string",
101
+ "initAmount": amount,
102
+ "maxSingleTransAmount": min_limit,
103
+ "minSingleTransAmount": max_limit,
104
+ # "mobileVerifyCode": "string",
105
+ # "onlineDelayTime": 0,
106
+ # "onlineNow": True,
107
+ "payTimeLimit": (90, 15)[tt],
108
+ "price": price,
109
+ # "priceFloatingRatio": 0,
110
+ "priceType": 1, # 1: fix, 2: float
111
+ # "rateFloatingRatio": 0,
112
+ "remarks": "string",
113
+ "saveAsTemplate": 0,
114
+ # "templateName": "string",
115
+ "tradeMethods": [
116
+ {
117
+ "identifier": "string",
118
+ "payId": 0,
119
+ "payType": "string"
120
+ }
121
+ ],
122
+ "tradeType": tt.name,
123
+ # "userAllTradeCountMax": 0,
124
+ # "userAllTradeCountMin": 0,
125
+ # "userBuyTradeCountMax": 0,
126
+ # "userBuyTradeCountMin": 0,
127
+ # "userSellTradeCountMax": 0,
128
+ # "userSellTradeCountMin": 0,
129
+ # "userTradeCompleteCountMin": 0,
130
+ # "userTradeCompleteRateFilterTime": 0,
131
+ # "userTradeCompleteRateMin": 0,
132
+ # "userTradeCountFilterTime": 0,
133
+ # "userTradeType": 0,
134
+ # "userTradeVolumeAsset": "string",
135
+ # "userTradeVolumeFilterTime": 0,
136
+ # "userTradeVolumeMax": 0,
137
+ # "userTradeVolumeMin": 0,
138
+ # "yubikeyVerifyCode": "string"
139
+ }
140
+ return await self._post(Ep.GET_MY_ADS, body)
141
+
142
+ # 6. Search Ads
143
+ async def search_ads(self, asset, fiat, trade_type, pms: [str] = None, amount: int = None, page=1, rows=20):
144
+ """
145
+ Search advertisements based on search criteria.
146
+
147
+ Args:
148
+ asset (str): Asset.
149
+ fiat (str): Fiat currency.
150
+ trade_type (str): Trade type ('BUY' or 'SELL').
151
+ pms ([string]): payment types,
152
+ amount (int, optional): payment types,
153
+ page (int, optional): Page number. Defaults to 1.
154
+ rows (int, optional): Number of rows per page. Defaults to 20.
155
+
156
+ Returns:
157
+ dict: List of matching advertisements.
158
+ """
159
+ data = {
160
+ 'page': page,
161
+ 'rows': rows,
162
+ 'asset': asset,
163
+ 'fiat': fiat,
164
+ 'tradeType': trade_type,
165
+ "payTypes": pms,
166
+ # "sort": "asc",
167
+ "transAmount": amount
168
+ }
169
+ return await self._post('ads/search', data)
170
+
171
+ # 7. Update Ad
172
+ async def update_ad(self, adv_no, price):
173
+ """
174
+ Update the price of an advertisement.
175
+
176
+ Args:
177
+ adv_no (str): Advertisement number.
178
+ price (str): New price.
179
+
180
+ Returns:
181
+ dict: Updated advertisement details.
182
+ """
183
+ return await self._post('ads/update', {'advNo': adv_no, 'price': price})
184
+
185
+ # 9. Get coins
186
+ async def get_coins(self):
187
+ return await self._post('digitalCurrency/list')
188
+
189
+ # 10. Get fiats
190
+ async def get_fiats(self):
191
+ return await self._post('fiatCurrency/list')
192
+
193
+ # 22. Get details of a specific order.
194
+ async def get_order_details(self, order_number):
195
+ return await self._post('orderMatch/getUserOrderDetail', {'adOrderNo': order_number})
196
+
197
+ # 24. List orders
198
+ async def get_order_list(self, request_body):
199
+ """
200
+ Get a list of orders.
201
+
202
+ Args:
203
+ request_body (dict): Request body parameters.
204
+
205
+ Returns:
206
+ dict: List of orders.
207
+ """
208
+ return await self._post('orderMatch/listOrders', request_body)
209
+
210
+ # 36. Get My Payment Method info by ID
211
+ async def get_my_pay_meth(self, idd):
212
+ return await self._get('paymentMethod/getPayMethodById', {'id': idd})
213
+
214
+ # 37. Get available Payment Methods List for current user
215
+ async def get_pay_meths(self):
216
+ return await self._post(Ep.GET_PMS)
217
+
218
+ # 38. Get current user info
219
+ async def get_user(self):
220
+ return await self._post('user/baseDetail')
221
+
222
+ # 42. Get wss-url, lister key and token
223
+ async def get_chat_creds(self, client_type='web'):
224
+ return await self._get('chat/retrieveChatCredential', {'clientType': client_type})
225
+
226
+ # 43. Get chat messages related to a specific order
227
+ async def get_chat(self, order_number, page=1, rows=10):
228
+ return await self._get(Ep.GET_CHAT, params={'page': page, 'rows': rows, 'orderNo': order_number})
229
+
230
+
231
+ async def main():
232
+ await init_db(DSN, models) # init db
233
+ sapi = Sapi(BKEY, BSEC)
234
+ # user = await sapi.get_user()
235
+
236
+ coins = await Coin.filter(exs__id__contains=1)
237
+ curs = await Cur.filter(exs__id__contains=1, ticker__in=('RUB', 'PHP', 'TRY', 'USD', 'EUR', 'GEL', 'THB', 'INR'))
238
+ # coin_ids = [coin.ticker for coin in coins]
239
+ # for chunk in batched(coin_ids, 3):
240
+ # for cur in await Cur.filter(exs__id__contains=1):
241
+ # for tt in TradeType:
242
+ # rp = await sapi.get_ref_price(chunk, cur.ticker, tt)
243
+ # print(rp)
244
+
245
+ # pm = await sapi.get_my_pay_meth(31986806)
246
+ # ads = await sapi.get_my_ads()
247
+
248
+ # pms = await sapi.get_pay_meths()
249
+ # [await Pm.update_or_create({'name': pm['name'], 'identifier': pm['identifier'], 'type': pm['typeCode']}, binance_id=pm['id']) for pm in pms]
250
+
251
+ for coin in coins:
252
+ for cur in curs:
253
+ for tt in TradeType:
254
+ rp = await sapi.get_ref_price([coin], cur, tt)
255
+ r = await sapi.search_ads(coin.ticker, cur.ticker, tt.name)
256
+ if r0 := r[0]['data']['adv']:
257
+ pd = {'fee': r0['commissionRate'], 'price': r0['price'], 'total': r[0]['total']}
258
+ pms = [Pm.get(identifier=pm['identifier']) for pm in r0['tradeMethods']]
259
+ ad = {'price': r0['price'], 'id': r0['total']}
260
+ p, _ = await Pair.update_or_create(pd, ex_id=1, cur=cur, coin=coin, sell=tt.value)
261
+ a, _ = await Ad.update_or_create(ad, pair=p, cur=cur, coin=coin, sell=tt.value)
262
+ await a.pms.add(*pms)
263
+
264
+
265
+ if __name__ == "__main__":
266
+ res = run(main())
267
+ print(res)
@@ -0,0 +1,30 @@
1
+ from http_client import Client
2
+
3
+
4
+ class BinanceClient(Client):
5
+ base_url = 'https://p2p.binance.com'
6
+
7
+
8
+ class Public(BinanceClient):
9
+ middle_url = '/bapi/c2c/v2/public/c2c/'
10
+
11
+ async def get_pms_and_country_for_cur(self, cur: str) -> ([str], [str]):
12
+ data = {"fiat": cur, "classifies": ["mass", "profession"]}
13
+ res = await self.post('adv/filter-conditions', data)
14
+ return [(r['identifier'], r['id'], r['tradeMethodName']) for r in res['data']['tradeMethods']], [r['scode'] for r in res['data']['countries'] if r['scode']!='ALL'] # countries,tradeMethods,periods
15
+
16
+
17
+ # class Private(Public): # todo: base class: Public or Client?
18
+ class Private(BinanceClient):
19
+ # auth: dict =
20
+ headers: dict = {
21
+ 'User-Agent': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/103.0.5060.134 Safari/537.36',
22
+ 'Content-Type': 'application/json',
23
+ 'clienttype': 'web',
24
+ }
25
+
26
+ def seq_headers(self):
27
+ return {
28
+ 'csrftoken': self.auth['tok'],
29
+ 'cookie': f'p20t=web.{self.id}.{self.auth["cook"]}',
30
+ }