├── .gitignore ├── LICENSE.txt ├── README.md ├── binance_chain ├── __init__.py ├── consts.py ├── rest_api.py └── websocket.py └── setup.py /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | *.iml 3 | *.pyc 4 | build 5 | dist 6 | tbag.egg-info 7 | MANIFEST 8 | test -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 The Python Packaging Authority (PyPA) 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | ## Binance Chain python SDK 3 | The Binance Chain python SDK is a asynchronous implementation for [Binance Chain API](https://binance-chain.github.io/index.html), 4 | It includes the following modules: 5 | 6 | - BinanceChainRestAPI - The [Binance Chain HTTP API](https://binance-chain.github.io/api-reference/dex-api/paths.html) client, provides access to a Binance Chain node deployment and market data services. 7 | - BinanceChainWsStream - The [DEX websocket](https://binance-chain.github.io/api-reference/dex-api/ws-connection.html) streams data client, provides subscribe and unsubscribe topic from server. 8 | 9 | 10 | ### Requirement 11 | 12 | - python 3.5.3 or above 13 | 14 | - third-part library 15 | - aiohttp>=3.2.1 16 | 17 | 18 | ### Install 19 | use `pip` install 20 | ```text 21 | pip install binance-chain 22 | ``` 23 | 24 | ### Usage 25 | 26 | ##### REST API client 27 | 28 | First, create a rest api client instance. 29 | ```python 30 | from binance_chain.rest_api import BinanceChainRestAPI 31 | 32 | HOST = "https://testnet-dex.binance.org" 33 | 34 | api = BinanceChainRestAPI(HOST) 35 | ``` 36 | 37 | you can get node information, 38 | ```python 39 | import asyncio 40 | 41 | async def test(): 42 | result, err = await api.node_info() 43 | print("err:", err) 44 | print("result:", result) 45 | 46 | asyncio.get_event_loop().run_until_complete(test()) 47 | ``` 48 | 49 | and you can use the fallowing methods like that: 50 | ```python 51 | result, err = await api.get_time() 52 | result, err = await api.node_info() 53 | result, err = await api.validators() 54 | result, err = await api.peers() 55 | result, err = await api.account(ADDRESS) 56 | result, err = await api.tx(TX_HASH) 57 | result, err = await api.tokens() 58 | result, err = await api.markets() 59 | result, err = await api.fees() 60 | result, err = await api.depth("NNB-0AD_BNB", 20) 61 | result, err = await api.klines("NNB-0AD_BNB", "1d") 62 | result, err = await api.orders_closed(ADDRESS, symbol="BNB_BTC.B-918") 63 | result, err = await api.orders_open(ADDRESS) 64 | result, err = await api.order(order_id) 65 | result, err = await api.ticker_24hr("000-0E1_BNB") 66 | result, err = await api.trades(ADDRESS) 67 | result, err = await api.transactions(ADDRESS) 68 | ``` 69 | 70 | 71 | ##### Websocket Stream data client 72 | 73 | Create a websocket stream data client instance, and subscribe topics, or unsubscribe topics. 74 | ```python 75 | import asyncio 76 | 77 | from binance_chain import consts 78 | from binance_chain.websocket import BinanceChainWsStream 79 | 80 | 81 | HOST = "wss://testnet-dex.binance.org" 82 | ADDRESS = "tbnb1efsnn75w7vxaummlhha9lmgcq4kpe38pjks0ee" 83 | 84 | 85 | class Test: 86 | 87 | def __init__(self): 88 | self.ws = BinanceChainWsStream(HOST, connected_callback=self.subscribe_some_topics) 89 | 90 | async def subscribe_some_topics(self): 91 | print("websocket is connected success") 92 | await self.ws.do(consts.METHOD_SUBSCRIBE, consts.TOPIC_ORDER, ADDRESS, callback=self.orders_callback) 93 | await self.ws.do(consts.METHOD_SUBSCRIBE, consts.TOPIC_ORDER, ADDRESS, callback=self.depth_callback) 94 | 95 | async def orders_callback(self, data): 96 | print("order data:", data) 97 | 98 | async def depth_callback(self, data): 99 | print("depth data:", data) 100 | 101 | 102 | Test() 103 | asyncio.get_event_loop().run_forever() 104 | ``` 105 | 106 | - command method 107 | ```python 108 | from binance_chain import consts 109 | 110 | consts.METHOD_SUBSCRIBE # subscribe 111 | consts.METHOD_UNSUBSCRIBE # unsubscribe 112 | ``` 113 | 114 | - topics 115 | ```python 116 | from binance_chain import consts 117 | 118 | consts.TOPIC_ORDER # orders 119 | consts.TOPIC_ACCOUNT # accounts 120 | consts.TOPIC_TRANSFER # transfers 121 | consts.TOPIC_TRADE # "trades 122 | consts.TOPIC_MARKET_DIFF # marketDiff 123 | consts.TOPIC_MARKET_DEPTH # marketDepth 124 | consts.TOPIC_KLINE_1M # kline_1m 125 | consts.TOPIC_KLINE_3M # kline_3m 126 | consts.TOPIC_KLINE_5M # kline_5m 127 | consts.TOPIC_KLINE_15M # kline_15m 128 | consts.TOPIC_KLINE_30M # kline_30m 129 | consts.TOPIC_KLINE_1H # kline_1h 130 | consts.TOPIC_KLINE_2H # kline_2h 131 | consts.TOPIC_KLINE_4H # kline_4h 132 | consts.TOPIC_KLINE_6H # kline_6h 133 | consts.TOPIC_KLINE_8H # kline_8h 134 | consts.TOPIC_KLINE_12H # kline_12h 135 | consts.TOPIC_KLINE_1D # kline_1d 136 | consts.TOPIC_KLINE_3D # kline_3d 137 | consts.TOPIC_KLINE_1W # kline_1w 138 | consts.TOPIC_KLINE_1MON # kline_1M 139 | consts.TOPIC_TICKER # ticker 140 | consts.TOPIC_TICKER_ALL # allTickers 141 | consts.TOPIC_TICKER_MINI # miniTicker 142 | consts.TOPIC_TICKER_MINI_ALL # allMiniTickers 143 | consts.TOPIC_BLOCK_HEIGHT # blockheight 144 | ``` 145 | 146 | 147 | For more API usage documentation, please check the [wiki...](https://binance-chain.github.io/index.html) 148 | -------------------------------------------------------------------------------- /binance_chain/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Demon-Hunter/BinanceChain-py/46c0d4551e885874f0e235278272b0bc258ffb9c/binance_chain/__init__.py -------------------------------------------------------------------------------- /binance_chain/consts.py: -------------------------------------------------------------------------------- 1 | # -*— coding:utf-8 -*- 2 | 3 | """ 4 | const 5 | 6 | Author: HuangTao 7 | Date: 2019/04/03 8 | Email: huangtao@ifclover.com 9 | """ 10 | 11 | 12 | # websocket method 13 | METHOD_SUBSCRIBE = "subscribe" 14 | METHOD_UNSUBSCRIBE = "unsubscribe" 15 | 16 | # websocket topic 17 | TOPIC_ORDER = "orders" 18 | TOPIC_ACCOUNT = "accounts" 19 | TOPIC_TRANSFER = "transfers" 20 | TOPIC_TRADE = "trades" 21 | TOPIC_MARKET_DIFF = "marketDiff" 22 | TOPIC_MARKET_DEPTH = "marketDepth" 23 | TOPIC_KLINE_1M = "kline_1m" 24 | TOPIC_KLINE_3M = "kline_3m" 25 | TOPIC_KLINE_5M = "kline_5m" 26 | TOPIC_KLINE_15M = "kline_15m" 27 | TOPIC_KLINE_30M = "kline_30m" 28 | TOPIC_KLINE_1H = "kline_1h" 29 | TOPIC_KLINE_2H = "kline_2h" 30 | TOPIC_KLINE_4H = "kline_4h" 31 | TOPIC_KLINE_6H = "kline_6h" 32 | TOPIC_KLINE_8H = "kline_8h" 33 | TOPIC_KLINE_12H = "kline_12h" 34 | TOPIC_KLINE_1D = "kline_1d" 35 | TOPIC_KLINE_3D = "kline_3d" 36 | TOPIC_KLINE_1W = "kline_1w" 37 | TOPIC_KLINE_1MON = "kline_1M" 38 | TOPIC_TICKER = "ticker" 39 | TOPIC_TICKER_ALL = "allTickers" 40 | TOPIC_TICKER_MINI = "miniTicker" 41 | TOPIC_TICKER_MINI_ALL = "allMiniTickers" 42 | TOPIC_BLOCK_HEIGHT = "blockheight" 43 | -------------------------------------------------------------------------------- /binance_chain/rest_api.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | """ 4 | Binance chain REST API 5 | https://binance-chain.github.io/api-reference/dex-api/paths.html 6 | 7 | Author: HuangTao 8 | Date: 2019/04/03 9 | Email: huangtao@ifclover.com 10 | """ 11 | 12 | import aiohttp 13 | import asyncio 14 | from urllib.parse import urljoin 15 | 16 | 17 | __all__ = ("BinanceChainRestAPI", ) 18 | 19 | 20 | class BinanceChainRestAPI: 21 | """ Binance chain REST API 22 | """ 23 | 24 | def __init__(self, host=None, timeout=10, proxy=None): 25 | """ 初始化 26 | @param host Binance chain's REST API host, default is the test host: https://testnet-dex.binance.org 27 | @param timeout HTTP request timeout(s), default 10s 28 | @param proxy HTTP proxy 29 | """ 30 | self._host = host or "https://testnet-dex.binance.org" 31 | self._timeout = timeout 32 | self._proxy = proxy 33 | 34 | self._session = aiohttp.ClientSession() 35 | 36 | def __del__(self): 37 | asyncio.get_event_loop().create_task(self._session.close()) 38 | 39 | async def get_time(self): 40 | """ Get the block time. 41 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1time 42 | """ 43 | uri = "/api/v1/time" 44 | result, err = await self.request("GET", uri) 45 | return result, err 46 | 47 | async def node_info(self): 48 | """ Get node information. 49 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1node-info 50 | """ 51 | uri = "/api/v1/node-info" 52 | result, err = await self.request("GET", uri) 53 | return result, err 54 | 55 | async def validators(self): 56 | """ Get validators. 57 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1validators 58 | """ 59 | uri = "/api/v1/validators" 60 | result, err = await self.request("GET", uri) 61 | return result, err 62 | 63 | async def peers(self): 64 | """ Get network peers. 65 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1peers 66 | """ 67 | uri = "/api/v1/peers" 68 | result, err = await self.request("GET", uri) 69 | return result, err 70 | 71 | async def account(self, address): 72 | """ Get an account. 73 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1accountaddress 74 | """ 75 | uri = "/api/v1/account/{address}".format(address=address) 76 | result, err = await self.request("GET", uri) 77 | return result, err 78 | 79 | async def account_sequence(self, address): 80 | """ Get an account sequence. 81 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1accountaddresssequence 82 | """ 83 | uri = "/api/v1/account/{address}/sequence".format(address=address) 84 | result, err = await self.request("GET", uri) 85 | return result, err 86 | 87 | async def tx(self, hash_): 88 | """ Get a transaction. 89 | @param hash_ transaction ID 90 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1txhash 91 | """ 92 | uri = "/api/v1/tx/{hash_}?format=json".format(hash_=hash_) 93 | result, err = await self.request("GET", uri) 94 | return result, err 95 | 96 | async def tokens(self): 97 | """ Get tokens list. 98 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1tokens 99 | """ 100 | uri = "/api/v1/tokens" 101 | result, err = await self.request("GET", uri) 102 | return result, err 103 | 104 | async def markets(self): 105 | """ Get market pairs. 106 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1markets 107 | """ 108 | uri = "/api/v1/markets" 109 | result, err = await self.request("GET", uri) 110 | return result, err 111 | 112 | async def fees(self): 113 | """ Obtain trading fees information. 114 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1fees 115 | """ 116 | uri = "/api/v1/fees" 117 | result, err = await self.request("GET", uri) 118 | return result, err 119 | 120 | async def depth(self, symbol, limit): 121 | """ Get the order book. 122 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 123 | @param limit The limit of results. Allowed limits [5, 10, 20, 50, 100, 500, 1000] 124 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1depth 125 | """ 126 | uri = "/api/v1/depth" 127 | params = { 128 | "symbol": symbol, 129 | "limit": limit 130 | } 131 | result, err = await self.request("GET", uri, params) 132 | return result, err 133 | 134 | async def broadcast(self, body, sync=None): 135 | """ Broadcast a transaction. 136 | @param sync Synchronous broadcast 137 | @param body binary transaction 138 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1broadcast 139 | """ 140 | uri = "/api/v1/broadcast" 141 | if sync: 142 | params = {"sync": sync} 143 | else: 144 | params = {} 145 | headers = { 146 | "content-type": "text/plain" 147 | } 148 | result, err = await self.request("GET", uri, params=params, data=body, headers=headers) 149 | return result, err 150 | 151 | async def klines(self, symbol, interval, limit=300, start=None, end=None): 152 | """ Get candlestick bars. 153 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 154 | @param interval interval. Allowed value [1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 6h, 8h, 12h, 1d, 3d, 1w, 1M] 155 | @param limit The limit of results. default 300; max 1000. 156 | @param start start time in Milliseconds 157 | @param end end time in Milliseconds 158 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1klines 159 | """ 160 | uri = "/api/v1/klines" 161 | params = { 162 | "symbol": symbol, 163 | "interval": interval 164 | } 165 | if limit: 166 | params["limit"] = limit 167 | if start: 168 | params["startTime"] = start 169 | if end: 170 | params["endTime"] = end 171 | result, err = await self.request("GET", uri, params) 172 | return result, err 173 | 174 | async def orders_closed(self, address, offset=0, limit=500, symbol=None, side=None, status=None, start=None, 175 | end=None, total=0): 176 | """ Get closed orders. 177 | @param address the owner address 178 | @param offset start with 0; default 0. 179 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 180 | @param limit The of results. default 500; max 1000. 181 | @param side order side. 1 for buy and 2 for sell. 182 | @param status order status list. Allowed value [Ack, PartialFill, IocNoFill, FullyFill, Canceled, Expired, 183 | FailedBlocking, FailedMatching] 184 | @param start start time in Milliseconds 185 | @param end end time in Milliseconds 186 | @param total total number required, 0 for not required and 1 for required; default not required, 187 | return total=-1 in response 188 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1ordersclosed 189 | """ 190 | uri = "/api/v1/orders/closed" 191 | params = { 192 | "address": address, 193 | "offset": offset, 194 | "limit": limit, 195 | "total": total 196 | } 197 | if symbol: 198 | params["symbol"] = symbol 199 | if side: 200 | params["side"] = side 201 | if status: 202 | params["status"] = status 203 | if start: 204 | params["start"] = start 205 | if end: 206 | params["end"] = end 207 | result, err = await self.request("GET", uri, params) 208 | return result, err 209 | 210 | async def orders_open(self, address, offset=0, limit=500, symbol=None, total=0): 211 | """ Get open orders. 212 | @param address the owner address 213 | @param offset start with 0; default 0. 214 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 215 | @param limit The of results. default 500; max 1000. 216 | @param total total number required, 0 for not required and 1 for required; default not required, 217 | return total=-1 in response 218 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1ordersopen 219 | """ 220 | uri = "/api/v1/orders/open" 221 | params = { 222 | "address": address, 223 | "offset": offset, 224 | "limit": limit, 225 | "total": total 226 | } 227 | if symbol: 228 | params["symbol"] = symbol 229 | result, err = await self.request("GET", uri, params) 230 | return result, err 231 | 232 | async def order(self, order_id): 233 | """ Get an order. 234 | @param order_id order id 235 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1ordersid 236 | """ 237 | uri = "/api/v1/orders/{order_id}".format(order_id=order_id) 238 | result, err = await self.request("GET", uri) 239 | return result, err 240 | 241 | async def ticker_24hr(self, symbol=None): 242 | """ Get a market ticker. 243 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 244 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1ticker24hr 245 | """ 246 | uri = "/api/v1/ticker/24hr" 247 | if symbol: 248 | params = {"symbol": symbol} 249 | else: 250 | params = None 251 | result, err = await self.request("GET", uri, params) 252 | return result, err 253 | 254 | async def trades(self, address=None, symbol=None, buyer_order_id=None, seller_order_id=None, side=None, height=None, 255 | quote_asset=None, offset=0, limit=500, start=None, end=None, total=0): 256 | """ Get market trades. 257 | @param address the owner address 258 | @param symbol Market pair symbol, e.g. NNB-0AD_BNB 259 | @param buyer_order_id buyer order id 260 | @param seller_order_id seller order id 261 | @param side order side. 1 for buy and 2 for sell. 262 | @param height block height 263 | @param quote_asset quote asset 264 | @param offset start with 0; default 0. 265 | @param limit default 500; max 1000. 266 | @param start start time in Milliseconds 267 | @param end end time in Milliseconds 268 | @param total total number required, 0 for not required and 1 for required; default not required, 269 | return total=-1 in response 270 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1trades 271 | """ 272 | uri = "/api/v1/trades" 273 | params = { 274 | "offset": offset, 275 | "limit": limit, 276 | "total": total 277 | } 278 | if address: 279 | params["address"] = address 280 | if symbol: 281 | params["symbol"] = symbol 282 | if buyer_order_id: 283 | params["buyerOrderId"] = buyer_order_id 284 | if seller_order_id: 285 | params["sellerOrderId"] = seller_order_id 286 | if symbol: 287 | params["symbol"] = symbol 288 | if side: 289 | params["side"] = side 290 | if height: 291 | params["height"] = height 292 | if quote_asset: 293 | params["quoteAsset"] = quote_asset 294 | if start: 295 | params["start"] = start 296 | if end: 297 | params["end"] = end 298 | result, err = await self.request("GET", uri, params) 299 | return result, err 300 | 301 | async def transactions(self, address, block_height=None, side=None, offset=None, limit=None, start=None, end=None, 302 | tx_asset=None, tx_type=None): 303 | """ Gets a list of transactions. Multisend transaction is not available in this API. 304 | @param address the owner address 305 | @param block_height blockHeight 306 | @param side transaction side. Allowed value [RECEIVE, SEND] 307 | @param offset offset 308 | @param limit list limit 309 | @param start start time in Milliseconds 310 | @param end end time in Milliseconds 311 | @param tx_asset txAsset 312 | @param tx_type transaction type. Allowed value [NEW_ORDER, ISSUE_TOKEN, BURN_TOKEN, LIST_TOKEN, CANCEL_ORDER, 313 | FREEZE_TOKEN, UN_FREEZE_TOKEN, TRANSFER, PROPOSAL, VOTE,MINT, DEPOSIT] 314 | refer: https://binance-chain.github.io/api-reference/dex-api/paths.html#apiv1transactions 315 | """ 316 | uri = "/api/v1/transactions" 317 | params = { 318 | "address": address 319 | } 320 | if block_height: 321 | params["blockHeight"] = block_height 322 | if side: 323 | params["side"] = side 324 | if offset: 325 | params["offset"] = offset 326 | if limit: 327 | params["limit"] = limit 328 | if start: 329 | params["startTime"] = start 330 | if end: 331 | params["endTime"] = end 332 | if tx_asset: 333 | params["txAsset"] = tx_asset 334 | if tx_type: 335 | params["txType"] = tx_type 336 | result, err = await self.request("GET", uri, params) 337 | return result, err 338 | 339 | async def request(self, method, uri, params=None, body=None, data=None, headers=None): 340 | """ HTTP request 341 | @param method HTTP Method, GET / POST / DELETE / PUT 342 | @param uri HTTP request uri 343 | @param params HTTP request query params 344 | """ 345 | url = urljoin(self._host, uri) 346 | try: 347 | response = await self._session.get(url, params=params, json=body, data=data, headers=headers, 348 | timeout=self._timeout, proxy=self._proxy) 349 | if response.status != 200: 350 | print("method:", method, "url:", url, "response status:", response.status) 351 | text = await response.text() 352 | return None, text 353 | result = await response.json() 354 | except Exception as e: 355 | print(e) 356 | return None, e 357 | return result, None 358 | -------------------------------------------------------------------------------- /binance_chain/websocket.py: -------------------------------------------------------------------------------- 1 | # -*— coding:utf-8 -*- 2 | 3 | """ 4 | Binance chain Websocket Streams 5 | https://binance-chain.github.io/api-reference/dex-api/ws-streams.html 6 | 7 | Author: HuangTao 8 | Date: 2019/04/03 9 | Email: huangtao@ifclover.com 10 | """ 11 | 12 | import json 13 | import aiohttp 14 | import asyncio 15 | from urllib.parse import urljoin 16 | 17 | 18 | class BinanceChainWsStream: 19 | """ Binance chain Websocket Streams 20 | """ 21 | 22 | def __init__(self, wss=None, proxy=None, connected_callback=None): 23 | """ 初始化 24 | @param wss - websocket host, default host is wss://testnet-dex.binance.org 25 | @param proxy - HTTP proxy 26 | @param connected_callback - call this function when websocket connection connected, 27 | notice this function must be asynchronous, and no callback params. 28 | """ 29 | self._wss = wss or "wss://testnet-dex.binance.org" 30 | self._proxy = proxy 31 | self._connected_callback = connected_callback 32 | 33 | self._ws = None # websocket connection object 34 | self._callbacks = {} # websocket message callback, key: topic, value: callback 35 | 36 | asyncio.get_event_loop().create_task(self._connect()) 37 | 38 | def __del__(self): 39 | if self._ws: 40 | asyncio.get_event_loop().create_task(self._ws.close()) 41 | 42 | async def _connect(self): 43 | session = aiohttp.ClientSession() 44 | url = urljoin(self._wss, "/api") 45 | print("wss:", url, "proxy:", self._proxy) 46 | self._ws = await session.ws_connect(url, proxy=self._proxy) 47 | if self._connected_callback: 48 | asyncio.get_event_loop().create_task(self._connected_callback()) 49 | asyncio.get_event_loop().create_task(self._receive()) 50 | 51 | async def _receive(self): 52 | """ 接收消息 53 | """ 54 | async for msg in self.ws: 55 | if msg.type == aiohttp.WSMsgType.TEXT: 56 | try: 57 | data = json.loads(msg.data) 58 | except: 59 | data = msg.data 60 | asyncio.get_event_loop().create_task(self._process(data)) 61 | elif msg.type == aiohttp.WSMsgType.BINARY: 62 | asyncio.get_event_loop().create_task(self._process_binary(msg.data)) 63 | elif msg.type == aiohttp.WSMsgType.CLOSED: 64 | print("receive event CLOSED:", msg) 65 | asyncio.get_event_loop().create_task(self._connect()) 66 | return 67 | elif msg.type == aiohttp.WSMsgType.ERROR: 68 | print("receive event ERROR:", msg) 69 | else: 70 | print("unhandled msg:", msg) 71 | 72 | async def _process(self, msg): 73 | """ process text message that received from server node. 74 | @param msg - received msg 75 | """ 76 | # TODO: heartbeat 77 | print("receive msg:", msg) 78 | topic = msg.get("stream") 79 | data = msg.get("data") 80 | callback = self._callbacks.get(topic) 81 | if callback: 82 | await callback(data) 83 | 84 | async def _process_binary(self, msg): 85 | """ 处理websocket上接收到的消息 binary类型 86 | """ 87 | print("receive binary msg:", msg) 88 | 89 | async def do(self, method, topic, address=None, symbols=None, callback=None): 90 | """ send command to websocket server node. 91 | @param method - websocket command method, subscribe / unsubscribe 92 | @param topic - topic name 93 | @param address - user address 94 | @param symbols - list, symbol pairs 95 | @param callback - call this function when topic message received, notice this function must be asynchronous, 96 | and has a parament `data`. 97 | """ 98 | d = { 99 | "method": method, 100 | "topic": topic 101 | } 102 | if address: 103 | d["address"] = address 104 | if symbols: 105 | d["address"] = address 106 | await self._ws.send_json(d) 107 | self._callbacks[topic] = callback 108 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | # -*- coding:utf-8 -*- 2 | 3 | from distutils.core import setup 4 | 5 | 6 | setup( 7 | name="binance-chain", 8 | version="1.0.0", 9 | packages=["binance_chain", ], 10 | description="Binance chain python SDK", 11 | url="https://github.com/Demon-Hunter/BinanceChain-py", 12 | author="huangtao", 13 | author_email="huangtao@ifclover.com", 14 | license="MIT", 15 | keywords=["binance chain"], 16 | install_requires=[ 17 | "aiohttp>=3.2.1", 18 | ], 19 | ) 20 | --------------------------------------------------------------------------------