trio-binance 0.3.0__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.
trio_binance/enums.py ADDED
@@ -0,0 +1,70 @@
1
+ from enum import Enum
2
+
3
+ SYMBOL_TYPE_SPOT = "SPOT"
4
+
5
+ ORDER_STATUS_NEW = "NEW"
6
+ ORDER_STATUS_PARTIALLY_FILLED = "PARTIALLY_FILLED"
7
+ ORDER_STATUS_FILLED = "FILLED"
8
+ ORDER_STATUS_CANCELED = "CANCELED"
9
+ ORDER_STATUS_PENDING_CANCEL = "PENDING_CANCEL"
10
+ ORDER_STATUS_REJECTED = "REJECTED"
11
+ ORDER_STATUS_EXPIRED = "EXPIRED"
12
+
13
+ KLINE_INTERVAL_1MINUTE = "1m"
14
+ KLINE_INTERVAL_3MINUTE = "3m"
15
+ KLINE_INTERVAL_5MINUTE = "5m"
16
+ KLINE_INTERVAL_15MINUTE = "15m"
17
+ KLINE_INTERVAL_30MINUTE = "30m"
18
+ KLINE_INTERVAL_1HOUR = "1h"
19
+ KLINE_INTERVAL_2HOUR = "2h"
20
+ KLINE_INTERVAL_4HOUR = "4h"
21
+ KLINE_INTERVAL_6HOUR = "6h"
22
+ KLINE_INTERVAL_8HOUR = "8h"
23
+ KLINE_INTERVAL_12HOUR = "12h"
24
+ KLINE_INTERVAL_1DAY = "1d"
25
+ KLINE_INTERVAL_3DAY = "3d"
26
+ KLINE_INTERVAL_1WEEK = "1w"
27
+ KLINE_INTERVAL_1MONTH = "1M"
28
+
29
+ SIDE_BUY = "BUY"
30
+ SIDE_SELL = "SELL"
31
+
32
+ ORDER_TYPE_LIMIT = "LIMIT"
33
+ ORDER_TYPE_MARKET = "MARKET"
34
+ ORDER_TYPE_STOP_LOSS = "STOP_LOSS"
35
+ ORDER_TYPE_STOP_LOSS_LIMIT = "STOP_LOSS_LIMIT"
36
+ ORDER_TYPE_TAKE_PROFIT = "TAKE_PROFIT"
37
+ ORDER_TYPE_TAKE_PROFIT_LIMIT = "TAKE_PROFIT_LIMIT"
38
+ ORDER_TYPE_LIMIT_MAKER = "LIMIT_MAKER"
39
+
40
+ FUTURE_ORDER_TYPE_LIMIT = "LIMIT"
41
+ FUTURE_ORDER_TYPE_MARKET = "MARKET"
42
+ FUTURE_ORDER_TYPE_STOP = "STOP"
43
+ FUTURE_ORDER_TYPE_STOP_MARKET = "STOP_MARKET"
44
+ FUTURE_ORDER_TYPE_TAKE_PROFIT = "TAKE_PROFIT"
45
+ FUTURE_ORDER_TYPE_TAKE_PROFIT_MARKET = "TAKE_PROFIT_MARKET"
46
+ FUTURE_ORDER_TYPE_LIMIT_MAKER = "LIMIT_MAKER"
47
+
48
+ TIME_IN_FORCE_GTC = "GTC" # Good till cancelled
49
+ TIME_IN_FORCE_IOC = "IOC" # Immediate or cancel
50
+ TIME_IN_FORCE_FOK = "FOK" # Fill or kill
51
+ TIME_IN_FORCE_GTX = "GTX" # Post only order
52
+
53
+ ORDER_RESP_TYPE_ACK = "ACK"
54
+ ORDER_RESP_TYPE_RESULT = "RESULT"
55
+ ORDER_RESP_TYPE_FULL = "FULL"
56
+
57
+ WEBSOCKET_DEPTH_5 = "5"
58
+ WEBSOCKET_DEPTH_10 = "10"
59
+ WEBSOCKET_DEPTH_20 = "20"
60
+
61
+
62
+ class FuturesType(Enum):
63
+ USD_M = 1
64
+ COIN_M = 2
65
+
66
+
67
+ class ContractType(Enum):
68
+ PERPETUAL = "perpetual"
69
+ CURRENT_QUARTER = "current_quarter"
70
+ NEXT_QUARTER = "next_quarter"
@@ -0,0 +1,76 @@
1
+ import orjson
2
+
3
+
4
+ class BinanceAPIException(Exception):
5
+ def __init__(self, response, status_code, text):
6
+ self.code = 0
7
+ try:
8
+ json_res = orjson.loads(text)
9
+ except ValueError:
10
+ self.message = "Invalid JSON error message from Binance: {}".format(response.text)
11
+ else:
12
+ self.code = json_res["code"]
13
+ self.message = json_res["msg"]
14
+ self.status_code = status_code
15
+ self.response = response
16
+ self.request = getattr(response, "request", None)
17
+
18
+ def __str__(self): # pragma: no cover
19
+ return "APIError(code=%s): %s" % (self.code, self.message)
20
+
21
+
22
+ class BinanceRequestException(Exception):
23
+ def __init__(self, message):
24
+ self.message = message
25
+
26
+ def __str__(self):
27
+ return "BinanceRequestException: %s" % self.message
28
+
29
+
30
+ class BinanceOrderException(Exception):
31
+ def __init__(self, code, message):
32
+ self.code = code
33
+ self.message = message
34
+
35
+ def __str__(self):
36
+ return "BinanceOrderException(code=%s): %s" % (self.code, self.message)
37
+
38
+
39
+ class BinanceOrderMinAmountException(BinanceOrderException):
40
+ def __init__(self, value):
41
+ message = "Amount must be a multiple of %s" % value
42
+ super().__init__(-1013, message)
43
+
44
+
45
+ class BinanceOrderMinPriceException(BinanceOrderException):
46
+ def __init__(self, value):
47
+ message = "Price must be at least %s" % value
48
+ super().__init__(-1013, message)
49
+
50
+
51
+ class BinanceOrderMinTotalException(BinanceOrderException):
52
+ def __init__(self, value):
53
+ message = "Total must be at least %s" % value
54
+ super().__init__(-1013, message)
55
+
56
+
57
+ class BinanceOrderUnknownSymbolException(BinanceOrderException):
58
+ def __init__(self, value):
59
+ message = "Unknown symbol %s" % value
60
+ super().__init__(-1013, message)
61
+
62
+
63
+ class BinanceOrderInactiveSymbolException(BinanceOrderException):
64
+ def __init__(self, value):
65
+ message = "Attempting to trade an inactive symbol %s" % value
66
+ super().__init__(-1013, message)
67
+
68
+
69
+ class BinanceWebsocketUnableToConnect(Exception):
70
+ pass
71
+
72
+
73
+ class NotImplementedException(Exception):
74
+ def __init__(self, value):
75
+ message = f"Not implemented: {value}"
76
+ super().__init__(message)
@@ -0,0 +1,49 @@
1
+ from decimal import Decimal
2
+ from typing import Union, Optional, Dict
3
+
4
+ import dateparser
5
+ import math
6
+ import pytz
7
+
8
+ from datetime import datetime
9
+
10
+
11
+ def date_to_milliseconds(date_str: str) -> int:
12
+ """Convert UTC date to milliseconds
13
+
14
+ If using offset strings add "UTC" to date string e.g. "now UTC", "11 hours ago UTC"
15
+
16
+ See dateparse docs for formats http://dateparser.readthedocs.io/en/latest/
17
+
18
+ :param date_str: date in readable format, i.e. "January 01, 2018", "11 hours ago UTC", "now UTC"
19
+ """
20
+ # get epoch value in UTC
21
+ epoch: datetime = datetime.utcfromtimestamp(0).replace(tzinfo=pytz.utc)
22
+ # parse our date string
23
+ d: Optional[datetime] = dateparser.parse(date_str, settings={"TIMEZONE": "UTC"})
24
+ # if the date is not timezone aware apply UTC timezone
25
+ if d.tzinfo is None or d.tzinfo.utcoffset(d) is None:
26
+ d = d.replace(tzinfo=pytz.utc)
27
+
28
+ # return the difference in time
29
+ return int((d - epoch).total_seconds() * 1000.0)
30
+
31
+
32
+ def round_step_size(quantity: Union[float, Decimal], step_size: Union[float, Decimal]) -> float:
33
+ """Rounds a given quantity to a specific step size
34
+
35
+ :param quantity: required
36
+ :param step_size: required
37
+
38
+ :return: decimal
39
+ """
40
+ precision: int = int(round(-math.log(step_size, 10), 0))
41
+ return float(round(quantity, precision))
42
+
43
+
44
+ def convert_ts_str(ts_str):
45
+ if ts_str is None:
46
+ return ts_str
47
+ if type(ts_str) == int:
48
+ return ts_str
49
+ return date_to_milliseconds(ts_str)
@@ -0,0 +1,101 @@
1
+ from contextlib import asynccontextmanager
2
+ from random import randint
3
+
4
+ import trio
5
+ import trio_websocket
6
+ import orjson
7
+ from trio_websocket import open_websocket_url
8
+
9
+ from trio_binance import AsyncClient
10
+
11
+
12
+ class BinanceSocketManager:
13
+ URLS = {
14
+ "main": {
15
+ "spot": "wss://stream.binance.com:9443",
16
+ "linear": "wss://fstream.binance.com",
17
+ "inverse": "wss://dstream.binance.com",
18
+ "portfolio": "wss://fstream.binance.com/pm",
19
+ },
20
+ "test": {},
21
+ }
22
+
23
+ def __init__(
24
+ self,
25
+ client: AsyncClient,
26
+ endpoint: str = "spot",
27
+ alternative_net: str = "",
28
+ private=False,
29
+ ):
30
+ self.ws: trio_websocket.WebSocketConnection | None = None
31
+ self.endpoint: str = endpoint
32
+ self.alternative_net: str = alternative_net if alternative_net else "main"
33
+ self.client: AsyncClient = client
34
+ self.listen_key: str = ""
35
+ self.user_data_stream = private
36
+
37
+ @classmethod
38
+ async def create(
39
+ cls,
40
+ client: AsyncClient,
41
+ endpoint: str = "spot",
42
+ alternative_net: str = "",
43
+ private=False,
44
+ ):
45
+ self = cls(client, endpoint, alternative_net, private)
46
+ if self.endpoint == "spot":
47
+ self.listen_key = await self.client.stream_get_listen_key()
48
+ elif self.endpoint == "linear":
49
+ self.listen_key = await self.client.futures_stream_get_listen_key()
50
+ elif self.endpoint == "inverse":
51
+ self.listen_key = await self.client.futures_coin_stream_get_listen_key()
52
+ elif self.endpoint == "portfolio":
53
+ self.listen_key = await self.client.portfolio_margin_stream_get_listen_key()
54
+ return self
55
+
56
+ @asynccontextmanager
57
+ async def connect(self):
58
+ try:
59
+ base_url = self.URLS[self.alternative_net][self.endpoint]
60
+ if self.user_data_stream:
61
+ url = f"{base_url}/ws/{self.listen_key}"
62
+ else:
63
+ url = f"{base_url}/stream"
64
+ except KeyError:
65
+ raise ValueError(f"endpoint {self.endpoint} with net {self.alternative_net} not supported")
66
+ async with open_websocket_url(url) as ws:
67
+ self.ws = ws
68
+ async with trio.open_nursery() as nursery:
69
+ nursery.start_soon(self.keepalive)
70
+ yield self.ws
71
+ nursery.cancel_scope.cancel()
72
+
73
+ async def keepalive(self):
74
+ while True:
75
+ await trio.sleep(59 * 60)
76
+ with trio.fail_after(5):
77
+ if self.endpoint == "spot":
78
+ await self.client.stream_keepalive()
79
+ elif self.endpoint == "linear":
80
+ await self.client.futures_stream_keepalive()
81
+ elif self.endpoint == "inverse":
82
+ await self.client.futures_coin_stream_keepalive()
83
+ elif self.endpoint == "portfolio":
84
+ await self.client.portfolio_margin_stream_keepalive()
85
+
86
+ async def subscribe(self, params: list[str], sub_id: int | None = None):
87
+ if sub_id is None:
88
+ sub_id = randint(1, 2147483647)
89
+ await self.ws.send_message(orjson.dumps({"method": "SUBSCRIBE", "params": params, "id": sub_id}))
90
+
91
+ async def list_subscribe(self, sub_id: int | None = None):
92
+ await self.ws.send_message(orjson.dumps({"method": "LIST_SUBSCRIPTIONS", "id": sub_id}))
93
+
94
+ async def unsubscribe(self, params: list[str], sub_id: int | None = None):
95
+ await self.ws.send_message(orjson.dumps({"method": "UNSUBSCRIBE", "params": params, "id": sub_id}))
96
+
97
+ async def get_next_message(self):
98
+ while True:
99
+ raw_message = await self.ws.get_message()
100
+ message = orjson.loads(raw_message)
101
+ yield message
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2017 Shu Wang
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,62 @@
1
+ Metadata-Version: 2.1
2
+ Name: trio-binance
3
+ Version: 0.3.0
4
+ Summary: trio based asynchronous binance SDK
5
+ Home-page: https://github.com/halfelf/trio-binance
6
+ License: MIT
7
+ Keywords: binance,python-trio
8
+ Author: Shu Wang
9
+ Author-email: halfelf.ronin@gmail.com
10
+ Requires-Python: >=3.11,<4.0
11
+ Classifier: Framework :: Trio
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: Intended Audience :: Financial and Insurance Industry
14
+ Classifier: License :: OSI Approved :: MIT License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.11
17
+ Classifier: Programming Language :: Python :: 3.12
18
+ Requires-Dist: dateparser (>=1.1.0,<2.0.0)
19
+ Requires-Dist: h2 (>=4.1.0,<5.0.0)
20
+ Requires-Dist: httpx (>0.20.0)
21
+ Requires-Dist: orjson (>=3.6.0,<4.0.0)
22
+ Requires-Dist: pytz (>=2024.1,<2025.0)
23
+ Requires-Dist: trio (>=0.25.0)
24
+ Requires-Dist: trio-websocket (>=0.11.1,<0.12.0)
25
+ Project-URL: Repository, https://github.com/halfelf/trio-binance
26
+ Description-Content-Type: text/x-rst
27
+
28
+ =================================
29
+ Welcome to trio-binance
30
+ =================================
31
+
32
+ This is an unofficial Python wrapper for the `Binance exchange REST API v3 <https://binance-docs.github.io/apidocs/spot/en>`_. I am in no way affiliated with Binance, use at your own risk.
33
+
34
+ And this repository is forked from `python-binance <https://github.com/sammchardy/python-binance>`_, but has only async client, and works **only** with `trio <https://trio.readthedocs.io/en/stable/index.html>`_ or `trio-compatible <https://trio.readthedocs.io/en/stable/awesome-trio-libraries.html#trio-asyncio-interoperability>`_ asynchronous frameworks.
35
+
36
+ Source code
37
+ https://github.com/halfelf/trio-binance
38
+
39
+ Quick Start
40
+ -----------
41
+
42
+ `Register an account with Binance <https://accounts.binance.com/en/register?ref=10099792>`_.
43
+
44
+ `Generate an API Key <https://www.binance.com/en/my/settings/api-management>`_ and assign relevant permissions.
45
+
46
+ .. code:: bash
47
+
48
+ pip install trio-binance
49
+
50
+
51
+ Example
52
+ -------------
53
+
54
+ Check pytest file under ``tests``.
55
+
56
+ Donate
57
+ ------
58
+
59
+ If this library helps, feel free to donate.
60
+
61
+ - ETH: 0xf560e5F7F234307A20670ed8A5778F350a8366d1
62
+
@@ -0,0 +1,11 @@
1
+ LICENSE,sha256=h6dW5yRP__7ICaHJi7ZbKAO5Eln9wBs9Yd84flq0VB0,1065
2
+ trio_binance/__init__.py,sha256=8s8wr4KTwy9DmgUNbowHLksHnFLjdshF6bU1Q5neFYw,67
3
+ trio_binance/client.py,sha256=pPqWWsAa6hdLSKMBWDT5UrPsGxFubOLMlZr0hA_FrvE,77725
4
+ trio_binance/enums.py,sha256=YS2NARvK7nMfok_YUqip_Z85ju9eR0FKrHhyMMsk4hY,1891
5
+ trio_binance/exceptions.py,sha256=EVEDajSR3MP-Oa_9O1OW5qe7SLKPv75RI30wH7KH9sg,2260
6
+ trio_binance/helpers.py,sha256=7y6hcFACJnrP4x2Y0yfxBJmks6piy6qWwWHa3Vxop8U,1493
7
+ trio_binance/streams.py,sha256=2xo2SW47lLtPL1mZmA4ZLqxTzLIueg1_mEluXhrWrLs,3780
8
+ trio_binance-0.3.0.dist-info/LICENSE,sha256=h6dW5yRP__7ICaHJi7ZbKAO5Eln9wBs9Yd84flq0VB0,1065
9
+ trio_binance-0.3.0.dist-info/METADATA,sha256=fiAsFBRQIj3JreU-crvlDLnMBM0LGu5OqfFr-7TDSHI,2134
10
+ trio_binance-0.3.0.dist-info/WHEEL,sha256=FMvqSimYX_P7y0a7UY-_Mc83r5zkBZsCYPm7Lr0Bsq4,88
11
+ trio_binance-0.3.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.8.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any