├── .gitignore
├── .travis.yml
├── LICENSE
├── README.rst
├── bigone
├── __init__.py
├── client.py
└── exceptions.py
├── docs
├── Makefile
├── bigone.rst
├── changelog.rst
├── conf.py
├── index.rst
└── overview.rst
├── requirements.txt
├── setup.cfg
├── setup.py
├── test-requirements.txt
├── tests
├── __init__.py
└── test_api_request.py
└── tox.ini
/.gitignore:
--------------------------------------------------------------------------------
1 | lastfailed
2 | python_bigone.egg-info
3 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: python
2 |
3 | python:
4 | - "2.7"
5 | - "3.4"
6 | - "3.5"
7 | - "3.6"
8 |
9 | install:
10 | - pip install -r test-requirements.txt
11 | - pip install -r requirements.txt
12 | - pip install tox-travis
13 |
14 | script:
15 | - tox
16 |
17 | after_success:
18 | - coveralls
19 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 sammchardy
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.
22 |
--------------------------------------------------------------------------------
/README.rst:
--------------------------------------------------------------------------------
1 | ===============================
2 | Welcome to python-bigone v0.1.0
3 | ===============================
4 |
5 | .. image:: https://img.shields.io/pypi/v/python-bigone.svg
6 | :target: https://pypi.python.org/pypi/python-bigone
7 |
8 | .. image:: https://img.shields.io/pypi/l/python-bigone.svg
9 | :target: https://pypi.python.org/pypi/python-bigone
10 |
11 | .. image:: https://img.shields.io/travis/sammchardy/python-bigone.svg
12 | :target: https://travis-ci.org/sammchardy/python-bigone
13 |
14 | .. image:: https://img.shields.io/coveralls/sammchardy/python-bigone.svg
15 | :target: https://coveralls.io/github/sammchardy/python-bigone
16 |
17 | .. image:: https://img.shields.io/pypi/wheel/python-bigone.svg
18 | :target: https://pypi.python.org/pypi/python-bigone
19 |
20 | .. image:: https://img.shields.io/pypi/pyversions/python-bigone.svg
21 | :target: https://pypi.python.org/pypi/python-bigone
22 |
23 | This is an unofficial Python wrapper for the `BigONE exchanges REST API v2 `_. I am in no way affiliated with BigONE, use at your own risk.
24 |
25 | PyPi
26 | https://pypi.python.org/pypi/python-bigone
27 |
28 | Source code
29 | https://github.com/sammchardy/python-bigone
30 |
31 | Documentation
32 | https://python-bigone.readthedocs.io/en/latest/
33 |
34 |
35 | Features
36 | --------
37 |
38 | - Implementation of all REST endpoints
39 | - Simple handling of authentication
40 | - Response exception handling
41 |
42 | Quick Start
43 | -----------
44 |
45 | Register an account with `BigONE `_.
46 |
47 | `Generate an API Key `_ and store it.
48 |
49 | .. code:: bash
50 |
51 | pip install python-bigone
52 |
53 |
54 | .. code:: python
55 |
56 | from bigone.client import Client
57 | client = Client(api_key, api_secret)
58 |
59 | # get markets
60 | markets = client.get_markets()
61 |
62 | # get market order book
63 | depth = client.get_order_book('ETH-BTC')
64 |
65 | # get market trades
66 | trades = client.get_market_trades('ETH-BTC')
67 |
68 | # get your accounts
69 | currencies = client.get_accounts()
70 |
71 | # place a bid order
72 | transaction = client.create_order('KCS-BTC', Client.SIDE_BID, '0.01', '1000')
73 |
74 | # place an ask order
75 | transaction = client.create_order('KCS-BTC', Client.SIDE_ASK, '0.01', '1000')
76 |
77 | # get a list of your orders for a symbol
78 | orders = client.get_orders('ETH-BTC')
79 |
80 | # get a list of your trades for a symbol
81 | orders = client.get_trades('ETH-BTC')
82 |
83 | # get list of all withdrawals
84 | withdrawals = client.get_withdrawals()
85 |
86 | # get list of all deposits
87 | deposits = client.get_deposits()
88 |
89 |
90 | For more `check out the documentation `_.
91 |
92 | Donate
93 | ------
94 |
95 | If this library helped you out feel free to donate.
96 |
97 | - ETH: 0xD7a7fDdCfA687073d7cC93E9E51829a727f9fE70
98 | - NEO: AVJB4ZgN7VgSUtArCt94y7ZYT6d5NDfpBo
99 | - LTC: LPC5vw9ajR1YndE1hYVeo3kJ9LdHjcRCUZ
100 | - BTC: 1Dknp6L6oRZrHDECRedihPzx2sSfmvEBys
101 |
102 | Other Exchanges
103 | ---------------
104 |
105 | If you use `Binance `_ check out my `python-binance `_ library.
106 |
107 | If you use `Kucoin `_ check out my `python-kucoin `_ library.
108 |
109 | If you use `Allcoin `_ check out my `python-allucoin `_ library.
110 |
111 | If you use `Quoinex `_
112 | or `Qryptos `_ check out my `python-quoine `_ library.
113 |
114 | If you use `IDEX `_ check out my `python-idex `_ library.
115 |
116 | .. image:: https://analytics-pixel.appspot.com/UA-111417213-1/github/python-bigone?pixel
117 |
--------------------------------------------------------------------------------
/bigone/__init__.py:
--------------------------------------------------------------------------------
1 | """An unofficial Python wrapper for the Big.One exchange
2 |
3 | .. moduleauthor:: Sam McHardy
4 |
5 | """
6 |
7 | __version__ = '0.1.0'
8 |
--------------------------------------------------------------------------------
/bigone/client.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | import jwt
4 | import requests
5 | import time
6 |
7 | from .exceptions import BigoneAPIException, BigoneRequestException
8 |
9 |
10 | class Client(object):
11 |
12 | API_URL = 'https://big.one/api/v2'
13 |
14 | SIDE_BID = 'BID'
15 | SIDE_ASK = 'ASK'
16 |
17 | def __init__(self, api_key, api_secret):
18 | """Big.One API Client constructor
19 |
20 | https://open.big.one/
21 |
22 | :param api_key: Api Key
23 | :type api_key: str
24 | :param api_key: Api Secret
25 | :type api_key: str
26 |
27 | .. code:: python
28 |
29 | client = Client(api_key, api_secret)
30 |
31 | """
32 |
33 | self.API_KEY = api_key
34 | self.API_SECRET = api_secret
35 | self.session = self._init_session()
36 |
37 | def _init_session(self):
38 |
39 | session = requests.session()
40 | headers = {'Accept': 'application/json',
41 | 'User-Agent': 'python-bigone'}
42 | session.headers.update(headers)
43 | return session
44 |
45 | def _create_uri(self, path):
46 | return '{}/{}'.format(self.API_URL, path)
47 |
48 | def _create_signature(self, ):
49 |
50 | headers = {'typ': 'JWT', 'alg': 'HS256'}
51 | payload = {
52 | 'type': 'OpenAPI',
53 | 'sub': self.API_KEY,
54 | 'nonce': int(time.time() * 1000000000) # convert to nanoseconds
55 | }
56 | sig = jwt.encode(payload, self.API_SECRET, algorithm='HS256', headers=headers)
57 | return sig.decode("utf-8")
58 |
59 | def _request(self, method, path, signed, **kwargs):
60 |
61 | data = kwargs.get('data', None)
62 |
63 | if signed:
64 | kwargs['headers'] = {
65 | 'Authorization': 'Bearer {}'.format(self._create_signature())
66 | }
67 |
68 | uri = self._create_uri(path)
69 |
70 | if method == 'get' and data:
71 | kwargs['params'] = kwargs['data']
72 | del(kwargs['data'])
73 |
74 | if method == 'post' and data:
75 | kwargs['json'] = kwargs['data']
76 | del(kwargs['data'])
77 |
78 | response = getattr(self.session, method)(uri, **kwargs)
79 | return self._handle_response(response)
80 |
81 | def _handle_response(self, response):
82 | """Internal helper for handling API responses from the Quoine server.
83 | Raises the appropriate exceptions when necessary; otherwise, returns the
84 | response.
85 | """
86 |
87 | if not str(response.status_code).startswith('2'):
88 | raise BigoneAPIException(response)
89 | try:
90 | json = response.json()
91 |
92 | if 'msg' in json or 'errors' in json:
93 | raise BigoneAPIException(response)
94 |
95 | # by default return full response
96 | res = json
97 | # if it's a normal response we have a data attribute, return that
98 | if 'data' in json:
99 | res = json['data']
100 | return res
101 | except ValueError:
102 | raise BigoneRequestException('Invalid Response: {}'.format(response.text))
103 |
104 | def _get(self, path, signed=False, **kwargs):
105 | return self._request('get', path, signed, **kwargs)
106 |
107 | def _post(self, path, signed=False, **kwargs):
108 | return self._request('post', path, signed, **kwargs)
109 |
110 | def _put(self, path, signed=False, **kwargs):
111 | return self._request('put', path, signed, **kwargs)
112 |
113 | def _delete(self, path, signed=False, **kwargs):
114 | return self._request('delete', path, signed, **kwargs)
115 |
116 | # Account endpoints
117 |
118 | def get_accounts(self):
119 | """List accounts of current user
120 |
121 | .. code:: python
122 |
123 | accounts = client.get_accounts()
124 |
125 | :return: list of dicts
126 |
127 | .. code:: python
128 |
129 | [
130 | {
131 | "type": "account",
132 | "user_id": "5c1b7700-c903-41f8-9b4c-d78be9b2685d",
133 | "account_id": "7eb4201b-9ae8-450d-819a-1c7dfd272e3d",
134 | "account_type": "BTC",
135 | "account_name": "Bitcoin",
136 | "account_logo_url": "https://storage.googleapis.com/big-one/coins/BTC.svg",
137 | "public_key": "16zy7YGERPEygQitMFaqP4afPJBZeo2WK6",
138 | "system_account": "",
139 | "active_balance": "0.00000000",
140 | "frozen_balance": "0.00000000",
141 | "estimated_btc_price": "1.00000000",
142 | "verification": "EMAIL_VERIFIED",
143 | "has_asset_pin": false
144 | },
145 | {
146 | "type": "account",
147 | "user_id": "5c1b7700-c903-41f8-9b4c-d78be9b2685d",
148 | "account_id": "3d7c2353-add3-4e03-8637-c78e4d2b17cb",
149 | "account_type": "ETH",
150 | "account_name": "Ether",
151 | "account_logo_url": "https://storage.googleapis.com/big-one/coins/ETH.svg",
152 | "public_key": "0xaefde180aae6e0916632dabfdd2f8733c8a03826",
153 | "system_account": "",
154 | "active_balance": "0.00000000",
155 | "frozen_balance": "0.00000000",
156 | "estimated_btc_price": "0.06500000",
157 | "verification": "EMAIL_VERIFIED",
158 | "has_asset_pin": false
159 | }
160 | ]
161 |
162 | :raises: BigoneRequestException, BigoneAPIException
163 |
164 | """
165 |
166 | return self._get('viewer/accounts', True)
167 |
168 | def get_account(self, currency):
169 | """Get account for a currency
170 |
171 | :param currency: Name of currency
172 | :type currency: str
173 |
174 | .. code:: python
175 |
176 | account = client.get_account('BTC')
177 |
178 | :return: dict
179 |
180 | .. code:: python
181 |
182 | {
183 | "type": "account",
184 | "user_id": "5c1b7700-c903-41f8-9b4c-d78be9b2685d",
185 | "account_id": "7eb4201b-9ae8-450d-819a-1c7dfd272e3d",
186 | "account_type": "BTC",
187 | "account_name": "Bitcoin",
188 | "account_logo_url": "https://storage.googleapis.com/big-one/coins/BTC.svg",
189 | "public_key": "16zy7YGERPEygQitMFaqP4afPJBZeo2WK6",
190 | "system_account": "",
191 | "active_balance": "0.00000000",
192 | "frozen_balance": "0.00000000",
193 | "estimated_btc_price": "1.00000000",
194 | "verification": "EMAIL_VERIFIED",
195 | "has_asset_pin": false,
196 | "withdrawal": {
197 | "fee": "0.002",
198 | "fee_type": "BTC"
199 | },
200 | "deposits": [],
201 | "withdrawals": [],
202 | "recipients": []
203 | }
204 |
205 | :raises: BigoneRequestException, BigoneAPIException
206 |
207 | """
208 |
209 | return self._get('accounts/{}'.format(currency), True)
210 |
211 | # Market endpoints
212 |
213 | def get_markets(self):
214 | """List markets
215 |
216 | https://open.big.one/docs/api_market.html#all-markets
217 |
218 | .. code:: python
219 |
220 | markets = client.get_markets()
221 |
222 | :return: list of dicts
223 |
224 | .. code:: python
225 |
226 | [
227 | {
228 | "uuid": "d2185614-50c3-4588-b146-b8afe7534da6",
229 | "quoteScale": 8,
230 | "quoteAsset": {
231 | "uuid": "0df9c3c3-255a-46d7-ab82-dedae169fba9",
232 | "symbol": "BTC",
233 | "name": "Bitcoin"
234 | },
235 | "name": "BTG/BTC",
236 | "baseScale": 4,
237 | "baseAsset": {
238 | "uuid": "5df3b155-80f5-4f5a-87f6-a92950f0d0ff",
239 | "symbol": "BTG",
240 | "name": "Bitcoin Gold"
241 | }
242 | }
243 | ]
244 |
245 | :raises: BigoneRequestException, BigoneAPIException
246 |
247 | """
248 |
249 | return self._get('markets')
250 |
251 | def get_tickers(self):
252 | """List market tickers
253 |
254 | https://open.big.one/docs/api_tickers.html#tickers-of-all-market
255 |
256 | .. code:: python
257 |
258 | markets = client.get_tickers()
259 |
260 | :return: list of dicts
261 |
262 | .. code:: python
263 |
264 | [
265 | {
266 | "volume": null,
267 | "open": "1.0000000000000000",
268 | "market_uuid": "ETH-EOS",
269 | "low": null,
270 | "high": null,
271 | "daily_change_perc": "0",
272 | "daily_change": "0E-16",
273 | "close": "1.0000000000000000",
274 | "bid": {
275 | "price": "1.0000000000000000",
276 | "amount": "106.0000000000000000"
277 | },
278 | "ask": {
279 | "price": "45.0000000000000000",
280 | "amount": "4082.3283464000000000"
281 | }
282 | }
283 | ]
284 |
285 | :raises: BigoneRequestException, BigoneAPIException
286 |
287 | """
288 |
289 | return self._get('tickers')
290 |
291 | def get_ticker(self, symbol):
292 | """Get symbol market details
293 |
294 | https://open.big.one/docs/api_tickers.html#ticker-of-one-market
295 |
296 | :param symbol: Name of symbol
297 | :type symbol: str
298 |
299 | .. code:: python
300 |
301 | # using market ID
302 | market = client.get_ticker('ETH-BTC')
303 |
304 | # using market UUID
305 | market = client.get_ticker('d2185614-50c3-4588-b146-b8afe7534da6')
306 |
307 | :return: dict
308 |
309 | .. code:: python
310 |
311 | {
312 | "volume": null,
313 | "open": "42.0000000000000000",
314 | "market_uuid": "BTC-EOS",
315 | "low": "42.0000000000000000",
316 | "high": null,
317 | "daily_change_perc": "0",
318 | "daily_change": "0E-16",
319 | "close": "42.0000000000000000",
320 | "bid": {
321 | "price": "42.0000000000000000",
322 | "amount": "3.3336371100000000"
323 | },
324 | "ask": {
325 | "price": "45.0000000000000000",
326 | "amount": "4082.3283464000000000"
327 | }
328 | }
329 |
330 | :raises: BigoneRequestException, BigoneAPIException
331 |
332 | """
333 |
334 | return self._get('markets/{}/ticker'.format(symbol))
335 |
336 | def get_order_book(self, symbol):
337 | """Get symbol market details
338 |
339 | :param symbol: Name of symbol
340 | :type symbol: str
341 |
342 | .. code:: python
343 |
344 | # Using market ID
345 | book = client.get_order_book('ETH-BTC')
346 |
347 | # Using market UUID
348 | book = client.get_order_book('d2185614-50c3-4588-b146-b8afe7534da6')
349 |
350 | :return: dict
351 |
352 | .. code:: python
353 |
354 | {
355 | "market_uuid": "BTC-EOS",
356 | "bids": [
357 | {
358 | "price": "42",
359 | "order_count": 4,
360 | "amount": "23.33363711"
361 | }
362 | ],
363 | "asks": [
364 | {
365 | "price": "45",
366 | "order_count": 2,
367 | "amount": "4193.3283464"
368 | }
369 | ]
370 | }
371 |
372 | :raises: BigoneRequestException, BigoneAPIException
373 |
374 | """
375 |
376 | return self._get('markets/{}/depth'.format(symbol))
377 |
378 | def get_market_trades(self, symbol, after=None, before=None, first=None, last=None):
379 | """Get market trades - max 50
380 |
381 | https://open.big.one/docs/api_market_trade.html#trades-of-a-market
382 |
383 | :param symbol: Name of symbol
384 | :type symbol: str
385 | :param after: Return trades after this id
386 | :type after: int
387 | :param before: Return trades before this id
388 | :type before: int
389 | :param first: Slicing count
390 | :type first: int
391 | :param last: Slicing count
392 | :type last: int
393 |
394 | .. code:: python
395 |
396 | trades = client.get_market_trades('ETH-BTC')
397 |
398 | # using after trade ID
399 | trades = client.get_market_trades('ETH-BTC', after=1)
400 |
401 | # using first slice value
402 | trades = client.get_market_trades('ETH-BTC', first=20)
403 |
404 | :return: list of dicts
405 |
406 | .. code:: python
407 |
408 | {
409 | "edges": [
410 | {
411 | "node": {
412 | "taker_side": "BID",
413 | "price": "46.1450000000000000",
414 | "market_uuid": "BTC-EOS",
415 | "id": 1,
416 | "amount": "0.2465480000000000"
417 | },
418 | "cursor": "dGVzdGN1cmVzZQo="
419 | }
420 | ],
421 | "page_info": {
422 | "end_cursor": "dGVzdGN1cmVzZQo=",
423 | "start_cursor": "dGVzdGN1cmVzZQo=",
424 | "has_next_page": true,
425 | "has_previous_page": false
426 | }
427 | }
428 |
429 | :raises: BigoneRequestException, BigoneAPIException
430 |
431 | """
432 | data = {}
433 | if after:
434 | data['after'] = after
435 | if before:
436 | data['before'] = before
437 | if first:
438 | data['first'] = first
439 | if last:
440 | data['last'] = last
441 |
442 | return self._get('markets/{}/trades'.format(symbol), data=data)
443 |
444 | # Order Endpoints
445 |
446 | def create_order(self, symbol, side, price, amount):
447 | """Create a new order
448 |
449 | :param symbol: Name of symbol
450 | :type symbol: str
451 | :param side: side of order (BID or ASK)
452 | :type side: str
453 | :param price: Price as string
454 | :type price: str
455 | :param amount: Amount as string
456 | :type amount: str
457 |
458 | .. code:: python
459 |
460 | order = client.create_order('ETH-BTC', 'BID', '1.0', '1.0')
461 |
462 | :return: dict
463 |
464 | .. code:: python
465 |
466 | {
467 | "id": 10,
468 | "market_uuid": "BTC-EOS",
469 | "price": "10.00",
470 | "amount": "10.00",
471 | "filled_amount": "9.0",
472 | "avg_deal_price": "12.0",
473 | "side": "ASK",
474 | "state": "FILLED"
475 | }
476 |
477 | :raises: BigoneRequestException, BigoneAPIException
478 |
479 | """
480 |
481 | data = {
482 | 'market_id': symbol,
483 | 'side': side,
484 | 'price': price,
485 | 'amount': amount
486 | }
487 |
488 | return self._post('viewer/orders', True, data=data)
489 |
490 | def get_orders(self, symbol, after=None, before=None, first=None, last=None, side=None, state=None):
491 | """Get a list of orders
492 |
493 | :param symbol: Name of symbol
494 | :type symbol: str
495 | :param after: Return trades after this id
496 | :type after: int
497 | :param before: Return trades before this id
498 | :type before: int
499 | :param first: Slicing count
500 | :type first: int
501 | :param last: Slicing count
502 | :type last: int
503 | :param side: Order Side ASK|BID
504 | :type side: str
505 | :param state: Order State CANCELED|FILLED|PENDING
506 | :type state: str
507 |
508 | .. code:: python
509 |
510 | orders = client.get_orders('ETH-BTC')
511 |
512 | :return: dict
513 |
514 | .. code:: python
515 |
516 | {
517 | "edges": [
518 | {
519 | "node": {
520 | "id": 10,
521 | "market_uuid": "d2185614-50c3-4588-b146-b8afe7534da6",
522 | "price": "10.00",
523 | "amount": "10.00",
524 | "filled_amount": "9.0",
525 | "avg_deal_price": "12.0",
526 | "side": "ASK",
527 | "state": "FILLED"
528 | },
529 | "cursor": "dGVzdGN1cmVzZQo="
530 | }
531 | ],
532 | "page_info": {
533 | "end_cursor": "dGVzdGN1cmVzZQo=",
534 | "start_cursor": "dGVzdGN1cmVzZQo=",
535 | "has_next_page": true,
536 | "has_previous_page": false
537 | }
538 | }
539 |
540 | :raises: BigoneRequestException, BigoneAPIException
541 |
542 | """
543 |
544 | data = {
545 | 'market_id': symbol
546 | }
547 | if after:
548 | data['after'] = after
549 | if before:
550 | data['before'] = before
551 | if first:
552 | data['first'] = first
553 | if last:
554 | data['last'] = last
555 | if side:
556 | data['side'] = side
557 | if state:
558 | data['state'] = state
559 |
560 | return self._get('viewer/orders', True, data=data)
561 |
562 | def get_order(self, order_id):
563 | """Get an order
564 |
565 | https://open.big.one/docs/api_orders.html#get-one-order
566 |
567 | :param order_id: Id of order
568 | :type order_id: str
569 |
570 | .. code:: python
571 |
572 | orders = client.get_order('10')
573 |
574 | :return: dict
575 |
576 | .. code:: python
577 |
578 | {
579 | "id": 10,
580 | "market_uuid": "d2185614-50c3-4588-b146-b8afe7534da6",
581 | "price": "10.00",
582 | "amount": "10.00",
583 | "filled_amount": "9.0",
584 | "avg_deal_price": "12.0",
585 | "side": "ASK",
586 | "state": "FILLED"
587 | }
588 |
589 | :raises: BigoneRequestException, BigoneAPIException
590 |
591 | """
592 |
593 | return self._get('viewer/orders/{}'.format(order_id), True)
594 |
595 | def cancel_order(self, order_id):
596 | """Cancel an order
597 |
598 | https://open.big.one/docs/api_orders.html#cancle-order
599 |
600 | :param order_id: Id of order
601 | :type order_id: str
602 |
603 | .. code:: python
604 |
605 | res = client.cancel_order('10')
606 |
607 | :return: dict
608 |
609 | .. code:: python
610 |
611 | {}
612 |
613 | :raises: BigoneRequestException, BigoneAPIException
614 |
615 | """
616 |
617 | return self._post('viewer/orders/{}/cancel'.format(order_id), True)
618 |
619 | def cancel_orders(self):
620 | """Cancel all orders
621 |
622 | https://open.big.one/docs/api_orders.html#cancle-all-orders
623 |
624 |
625 | .. code:: python
626 |
627 | res = client.cancel_orders()
628 |
629 | :return: dict
630 |
631 | .. code:: python
632 |
633 | {}
634 |
635 | :raises: BigoneRequestException, BigoneAPIException
636 |
637 | """
638 |
639 | return self._post('viewer/orders/cancel_all', True)
640 |
641 | # Trade endpoints
642 |
643 | def get_trades(self, symbol=None, after=None, before=None, first=None, last=None):
644 | """Get a list of your trades
645 |
646 | :param symbol: Name of symbol
647 | :type symbol: str
648 | :type after: int
649 | :param before: Return trades before this id
650 | :type before: int
651 | :param first: Slicing count
652 | :type first: int
653 | :param last: Slicing count
654 | :type last: int
655 |
656 | .. code:: python
657 |
658 | trades = client.get_trades('ETH-BTC')
659 |
660 | :return: dict
661 |
662 | .. code:: python
663 |
664 | {
665 | "edges": [
666 | {
667 | "node": {
668 | "viewer_side": "ASK" // ASK, BID, SELF_TRADING
669 | "taker_side": "BID",
670 | "price": "46.1450000000000000",
671 | "market_uuid": "BTC-EOS",
672 | "id": 1,
673 | "amount": "0.2465480000000000"
674 | },
675 | "cursor": "dGVzdGN1cmVzZQo="
676 | }
677 | ],
678 | "page_info": {
679 | "end_cursor": "dGVzdGN1cmVzZQo=",
680 | "start_cursor": "dGVzdGN1cmVzZQo=",
681 | "has_next_page": true,
682 | "has_previous_page": false
683 | }
684 | }
685 |
686 | :raises: BigoneRequestException, BigoneAPIException
687 |
688 | """
689 |
690 | data = {}
691 | if symbol:
692 | data['market_id'] = symbol
693 | if after:
694 | data['after'] = after
695 | if before:
696 | data['before'] = before
697 | if first:
698 | data['first'] = first
699 | if last:
700 | data['last'] = last
701 |
702 | return self._get('viewer/trades', True, data=data)
703 |
704 | # Withdraw endpoints
705 |
706 | def withdrawals(self, first=None, after=None):
707 | """Get a list of withdrawals
708 |
709 | https://open.big.one/docs/api_withdrawal.html#get-withdrawals-of-user
710 |
711 | :param first: Slicing count
712 | :type first: str
713 | :param after: Return withdrawals after this value
714 | :type after: str
715 |
716 | .. code:: python
717 |
718 | withdrawal = client.withdrawals()
719 |
720 | :return: dict
721 |
722 | .. code:: python
723 |
724 | {
725 | "edges": [
726 | {
727 | "node": {
728 | "id": 10,
729 | "customer_id": "ETH",
730 | "asset_uuid": "ETH",
731 | "amount": "5",
732 | "state": "CONFIRMED",
733 | "note": "2018-03-15T16:13:45.610463Z",
734 | "txid": "0x4643bb6b393ac20a6175c713175734a72517c63d6f73a3ca90a15356f2e967da0",
735 | "completed_at": "2018-03-15T16:13:45.610463Z",
736 | "inserted_at": "2018-03-15T16:13:45.610463Z",
737 | "is_internal": true,
738 | "target_address": "0x4643bb6b393ac20a6175c713175734a72517c63d6f7"
739 | },
740 | "cursor": "dGVzdGN1cmVzZQo="
741 | }
742 | ],
743 | "page_info": {
744 | "end_cursor": "dGVzdGN1cmVzZQo=",
745 | "start_cursor": "dGVzdGN1cmVzZQo=",
746 | "has_next_page": true,
747 | "has_previous_page": false
748 | }
749 | }
750 |
751 | :raises: BigoneRequestException, BigoneAPIException
752 |
753 | """
754 |
755 | data = {}
756 | if after:
757 | data['after'] = after
758 | if first:
759 | data['first'] = first
760 |
761 | return self._get('viewer/withdrawals', True, data=data)
762 |
763 | # Deposit endpoints
764 |
765 | def get_deposits(self, first=None, after=None):
766 | """Get a list of deposits
767 |
768 | https://open.big.one/docs/api_deposit.html#deposit-of-user
769 |
770 | :param first: Slicing count
771 | :type first: str
772 | :param after: Return withdrawals after this value
773 | :type after: str
774 |
775 | .. code:: python
776 |
777 | # get all deposits
778 | deposits = client.get_deposits()
779 |
780 | # get BTC deposits
781 | deposits = client.get_deposits('BTC')
782 |
783 | :return: list of dicts
784 |
785 | .. code:: python
786 |
787 | [
788 | {
789 | "type": "deposit",
790 | "deposit_id": "7b76603c-db87-4c4a-b36f-9981058d885e",
791 | "deposit_type": "ETH",
792 | "amount": "1.00000000",
793 | "confirmations": 2231,
794 | "state": "confirmed",
795 | "scanner_url": "https://etherscan.io/tx/0x181a1d616b5b07d5a404636c527ca5432878664d4b85a20976bbd72c07e58abe",
796 | "created_at": "2017-09-06T07:53:41.297047856Z"
797 | }
798 | ]
799 |
800 | :raises: BigoneRequestException, BigoneAPIException
801 |
802 | """
803 |
804 | data = {}
805 | if after:
806 | data['after'] = after
807 | if first:
808 | data['first'] = first
809 |
810 | return self._get('viewer/deposits', True, data=data)
811 |
--------------------------------------------------------------------------------
/bigone/exceptions.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 |
4 | class BigoneAPIException(Exception):
5 | """Exception class to handle general API Exceptions
6 |
7 | `code` values
8 |
9 | `message` format
10 |
11 | """
12 | def __init__(self, response):
13 | self.code = ''
14 | self.message = 'Unknown Error'
15 | try:
16 | json_res = response.json()
17 | except ValueError:
18 | print("Can't parse error response: {}".format(response.text))
19 | self.message = response.text
20 | else:
21 | print("doing something with json_res: {}".format(json_res))
22 | if 'msg' in json_res:
23 | self.message = json_res['msg']
24 | self.code = json_res['code']
25 | elif 'errors' in json_res:
26 | if type(json_res['errors']) == list:
27 | self.message = "\n ".join(["{}: {}".format(el['code'], el['message']) for el in json_res['errors']])
28 | elif 'detail' in json_res['errors']:
29 | self.message = json_res['errors']['detail']
30 |
31 | self.status_code = response.status_code
32 | self.response = response
33 | self.request = getattr(response, 'request', None)
34 |
35 | def __str__(self):
36 | return 'BigoneAPIException {}: {}'.format(self.code, self.message)
37 |
38 |
39 | class BigoneRequestException(Exception):
40 | def __init__(self, message):
41 | self.message = message
42 |
43 | def __str__(self):
44 | return 'BigoneRequestException: {}'.format(self.message)
45 |
--------------------------------------------------------------------------------
/docs/Makefile:
--------------------------------------------------------------------------------
1 | # Minimal makefile for Sphinx documentation
2 | #
3 |
4 | # You can set these variables from the command line.
5 | SPHINXOPTS =
6 | SPHINXBUILD = python -msphinx
7 | SPHINXPROJ = python-bigone
8 | SOURCEDIR = .
9 | BUILDDIR = _build
10 |
11 | # Put it first so that "make" without argument is like "make help".
12 | help:
13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
14 |
15 | .PHONY: help Makefile
16 |
17 | # Catch-all target: route all unknown targets to Sphinx using the new
18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
19 | %: Makefile
20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
21 |
22 | rst:
23 | sphinx-apidoc -f -o ./ ../
24 |
--------------------------------------------------------------------------------
/docs/bigone.rst:
--------------------------------------------------------------------------------
1 | BigONE API
2 | ==========
3 |
4 | client module
5 | ----------------------
6 |
7 | .. automodule:: bigone.client
8 | :members:
9 | :undoc-members:
10 | :show-inheritance:
11 | :member-order: bysource
12 |
13 | exceptions module
14 | --------------------------
15 |
16 | .. automodule:: bigone.exceptions
17 | :members:
18 | :undoc-members:
19 | :show-inheritance:
20 | :member-order: bysource
21 |
--------------------------------------------------------------------------------
/docs/changelog.rst:
--------------------------------------------------------------------------------
1 | Changelog
2 | =========
3 |
4 | v0.1.0 - 2018-06-27
5 | ^^^^^^^^^^^^^^^^^^^
6 |
7 | **Changed**
8 |
9 | - updated to v2 of Bigone API
10 |
11 | v0.0.5 - 2018-01-28
12 | ^^^^^^^^^^^^^^^^^^^
13 |
14 | **Changed**
15 |
16 | - changed `cancel_all_orders` to `cancel_orders` requiring a list of order ids
17 |
18 | v0.0.4 - 2018-01-28
19 | ^^^^^^^^^^^^^^^^^^^
20 |
21 | **Fixed**
22 |
23 | - broken request function
24 |
25 | v0.0.3 - 2018-01-28
26 | ^^^^^^^^^^^^^^^^^^^
27 |
28 | **Fixed**
29 |
30 | - private POST call param format
31 |
32 | v0.0.2 - 2018-01-28
33 | ^^^^^^^^^^^^^^^^^^^
34 |
35 | **Fixed**
36 |
37 | - get_orders endpoint
38 |
39 | v0.0.1 - 2017-01-20
40 | ^^^^^^^^^^^^^^^^^^^
41 |
42 | Initial version
43 |
44 | **Added**
45 |
46 | - General, Market Data and Account endpoints
47 |
--------------------------------------------------------------------------------
/docs/conf.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python3
2 | # -*- coding: utf-8 -*-
3 | #
4 | # python-kucoin documentation build configuration file, created by
5 | # sphinx-quickstart on Thu Sep 21 20:24:54 2017.
6 | #
7 | # This file is execfile()d with the current directory set to its
8 | # containing dir.
9 | #
10 | # Note that not all possible configuration values are present in this
11 | # autogenerated file.
12 | #
13 | # All configuration values have a default; values that are commented out
14 | # serve to show the default.
15 |
16 | # If extensions (or modules to document with autodoc) are in another directory,
17 | # add these directories to sys.path here. If the directory is relative to the
18 | # documentation root, use os.path.abspath to make it absolute, like shown here.
19 | #
20 | import os
21 | import sys
22 | sys.path.insert(0, os.path.abspath('..'))
23 |
24 |
25 | # -- General configuration ------------------------------------------------
26 |
27 | # If your documentation needs a minimal Sphinx version, state it here.
28 | #
29 | # needs_sphinx = '1.0'
30 |
31 | # Add any Sphinx extension module names here, as strings. They can be
32 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
33 | # ones.
34 | extensions = ['sphinx.ext.autodoc',
35 | 'sphinx.ext.imgmath',
36 | 'sphinx.ext.viewcode',
37 | 'sphinx.ext.githubpages']
38 |
39 | # Add any paths that contain templates here, relative to this directory.
40 | templates_path = ['_templates']
41 |
42 | # The suffix(es) of source filenames.
43 | # You can specify multiple suffix as a list of string:
44 | #
45 | # source_suffix = ['.rst', '.md']
46 | source_suffix = '.rst'
47 |
48 | # The master toctree document.
49 | master_doc = 'index'
50 |
51 | # General information about the project.
52 | project = 'python-bigone'
53 | copyright = '2018, Sam McHardy'
54 | author = 'Sam McHardy'
55 |
56 | # The version info for the project you're documenting, acts as replacement for
57 | # |version| and |release|, also used in various other places throughout the
58 | # built documents.
59 | #
60 | # The short X.Y version.
61 | version = '0.2.0'
62 | # The full version, including alpha/beta/rc tags.
63 | release = '0.2.0'
64 |
65 | # The language for content autogenerated by Sphinx. Refer to documentation
66 | # for a list of supported languages.
67 | #
68 | # This is also used if you do content translation via gettext catalogs.
69 | # Usually you set "language" from the command line for these cases.
70 | language = None
71 |
72 | # List of patterns, relative to source directory, that match files and
73 | # directories to ignore when looking for source files.
74 | # This patterns also effect to html_static_path and html_extra_path
75 | exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
76 |
77 | # The name of the Pygments (syntax highlighting) style to use.
78 | pygments_style = 'sphinx'
79 |
80 | # If true, `todo` and `todoList` produce output, else they produce nothing.
81 | todo_include_todos = False
82 |
83 |
84 | # -- Options for HTML output ----------------------------------------------
85 |
86 | # The theme to use for HTML and HTML Help pages. See the documentation for
87 | # a list of builtin themes.
88 | #
89 | #html_theme = 'alabaster'
90 | html_theme = 'sphinx_rtd_theme'
91 |
92 | # Theme options are theme-specific and customize the look and feel of a theme
93 | # further. For a list of options available for each theme, see the
94 | # documentation.
95 | #
96 | # html_theme_options = {}
97 |
98 | # Add any paths that contain custom static files (such as style sheets) here,
99 | # relative to this directory. They are copied after the builtin static files,
100 | # so a file named "default.css" will overwrite the builtin "default.css".
101 | html_static_path = ['_static']
102 |
103 | # Custom sidebar templates, must be a dictionary that maps document names
104 | # to template names.
105 | #
106 | # This is required for the alabaster theme
107 | # refs: http://alabaster.readthedocs.io/en/latest/installation.html#sidebars
108 | html_sidebars = {
109 | '**': [
110 | 'about.html',
111 | 'navigation.html',
112 | 'relations.html', # needs 'show_related': True theme option to display
113 | 'searchbox.html',
114 | 'donate.html',
115 | ]
116 | }
117 |
118 |
119 | # -- Options for HTMLHelp output ------------------------------------------
120 |
121 | # Output file base name for HTML help builder.
122 | htmlhelp_basename = 'python-bigonedoc'
123 |
124 |
125 | # -- Options for LaTeX output ---------------------------------------------
126 |
127 | latex_elements = {
128 | # The paper size ('letterpaper' or 'a4paper').
129 | #
130 | # 'papersize': 'letterpaper',
131 |
132 | # The font size ('10pt', '11pt' or '12pt').
133 | #
134 | # 'pointsize': '10pt',
135 |
136 | # Additional stuff for the LaTeX preamble.
137 | #
138 | # 'preamble': '',
139 |
140 | # Latex figure (float) alignment
141 | #
142 | # 'figure_align': 'htbp',
143 | }
144 |
145 | # Grouping the document tree into LaTeX files. List of tuples
146 | # (source start file, target name, title,
147 | # author, documentclass [howto, manual, or own class]).
148 | latex_documents = [
149 | (master_doc, 'python-bigone.tex', 'python-bigone Documentation',
150 | 'Sam McHardy', 'manual'),
151 | ]
152 |
153 |
154 | # -- Options for manual page output ---------------------------------------
155 |
156 | # One entry per manual page. List of tuples
157 | # (source start file, name, description, authors, manual section).
158 | man_pages = [
159 | (master_doc, 'python-bigone', 'python-bigone Documentation',
160 | [author], 1)
161 | ]
162 |
163 |
164 | # -- Options for Texinfo output -------------------------------------------
165 |
166 | # Grouping the document tree into Texinfo files. List of tuples
167 | # (source start file, target name, title, author,
168 | # dir menu entry, description, category)
169 | texinfo_documents = [
170 | (master_doc, 'python-bigone', 'python-bigone Documentation',
171 | author, 'python-bigone', 'One line description of project.',
172 | 'Miscellaneous'),
173 | ]
174 |
175 |
176 | def skip(app, what, name, obj, skip, options):
177 | # Ensure that the __init__ method gets documented.
178 | if name == "__init__":
179 | return False
180 | return skip
181 |
182 |
183 | def setup(app):
184 | app.connect("autodoc-skip-member", skip)
185 |
186 |
--------------------------------------------------------------------------------
/docs/index.rst:
--------------------------------------------------------------------------------
1 | .. python-bigone documentation master file
2 |
3 | .. include:: ../README.rst
4 |
5 | Contents
6 | ========
7 |
8 | .. toctree::
9 | :maxdepth: 2
10 |
11 | overview
12 |
13 | bigone
14 |
15 | Index
16 | ==================
17 |
18 | * :ref:`genindex`
19 |
--------------------------------------------------------------------------------
/docs/overview.rst:
--------------------------------------------------------------------------------
1 | Getting Started
2 | ===============
3 |
4 | Installation
5 | ------------
6 |
7 | ``python-bigone`` is available on `PYPI `_.
8 | Install with ``pip``:
9 |
10 | .. code:: bash
11 |
12 | pip install python-bigone
13 |
14 |
15 | Register on BigONE
16 | ------------------
17 |
18 | Firstly register an account with `BigONE `_.
19 |
20 | Generate an API Key
21 | -------------------
22 |
23 | To use signed account methods you are required to `create an API Key `_ and store it.
24 |
25 | Initialise the client
26 | ---------------------
27 |
28 | Pass your API Key and Secret
29 |
30 | .. code:: python
31 |
32 | from bigone.client import Client
33 | client = Client(api_key, api_secret)
34 |
35 | API Rate Limit
36 | --------------
37 |
38 | No information
39 |
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | PyJWT==1.6.4
2 | requests==2.19.1
3 |
--------------------------------------------------------------------------------
/setup.cfg:
--------------------------------------------------------------------------------
1 | [bdist_wheel]
2 | universal = 1
3 |
4 | [pep8]
5 | ignore = E501
6 |
--------------------------------------------------------------------------------
/setup.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 |
3 | import codecs
4 | import os
5 | import re
6 |
7 | from setuptools import setup
8 |
9 | here = os.path.abspath(os.path.dirname(__file__))
10 |
11 |
12 | def read(*parts):
13 | with codecs.open(os.path.join(here, *parts), 'r') as fp:
14 | return \
15 | fp.read()
16 |
17 |
18 | def find_version(*file_paths):
19 | version_file = read(*file_paths)
20 | version_match = re.search(r"^__version__ = ['\"]([^'\"]*)['\"]",
21 | version_file, re.M)
22 | if version_match:
23 | return version_match.group(1)
24 | raise RuntimeError("Unable to find version string.")
25 |
26 |
27 | setup(
28 | name='python-bigone',
29 | version=find_version("bigone", "__init__.py"),
30 | packages=['bigone'],
31 | description='BigONE REST API python implementation',
32 | url='https://github.com/sammchardy/python-bigone',
33 | author='Sam McHardy',
34 | license='MIT',
35 | author_email='',
36 | install_requires=['requests', 'pyJWT'],
37 | keywords='bigone exchange rest api bitcoin btc eos qtum bitcny',
38 | classifiers=[
39 | 'Intended Audience :: Developers',
40 | 'License :: OSI Approved :: MIT License',
41 | 'Operating System :: OS Independent',
42 | 'Programming Language :: Python :: 2',
43 | 'Programming Language :: Python :: 2.7',
44 | 'Programming Language :: Python :: 3',
45 | 'Programming Language :: Python :: 3.4',
46 | 'Programming Language :: Python :: 3.5',
47 | 'Programming Language :: Python :: 3.6',
48 | 'Programming Language :: Python',
49 | 'Topic :: Software Development :: Libraries :: Python Modules',
50 | ],
51 | )
52 |
--------------------------------------------------------------------------------
/test-requirements.txt:
--------------------------------------------------------------------------------
1 | coverage
2 | flake8
3 | pytest
4 | pytest-cov
5 | pytest-pep8
6 | python-coveralls
7 | requests-mock
8 | tox
9 | setuptools
10 |
--------------------------------------------------------------------------------
/tests/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/mchardysam/python-bigone/b1f8ef7ab3c25dc4acf1c785f0e374e3815f93c5/tests/__init__.py
--------------------------------------------------------------------------------
/tests/test_api_request.py:
--------------------------------------------------------------------------------
1 | # coding=utf-8
2 |
3 | from bigone.client import Client
4 | from bigone.exceptions import BigoneAPIException, BigoneRequestException
5 | import pytest
6 | import requests_mock
7 |
8 |
9 | client = Client('api_key', 'api_secret')
10 |
11 |
12 | def test_invalid_json():
13 | """Test Invalid response Exception"""
14 |
15 | with pytest.raises(BigoneRequestException):
16 | with requests_mock.mock() as m:
17 | m.get('https://big.one/api/v2/markets', text='')
18 | client.get_markets()
19 |
20 |
21 | def test_api_exception():
22 | """Test API response Exception"""
23 |
24 | with pytest.raises(BigoneAPIException):
25 | with requests_mock.mock() as m:
26 | json_obj = {
27 | 'errors': [{
28 | 'code': 20102,
29 | 'message': 'Unsupported currency ABC'
30 | }]
31 | }
32 | m.get('https://big.one/api/v2/accounts/ABC', json=json_obj, status_code=422)
33 | client.get_account('ABC')
34 |
--------------------------------------------------------------------------------
/tox.ini:
--------------------------------------------------------------------------------
1 | [tox]
2 | envlist = py27, py34, py35, py36
3 |
4 | [testenv]
5 | deps =
6 | -rtest-requirements.txt
7 | -rrequirements.txt
8 | commands = py.test -v tests/ --doctest-modules --cov bigone --cov-report term-missing
9 | passenv =
10 | TRAVIS
11 | TRAVIS_BRANCH
12 | TRAVIS_JOB_ID
13 |
14 | [testenv:flake8]
15 | commands = flake8 bigone/
16 | deps = flake8
17 |
18 | [travis]
19 | python =
20 | 3.6: py36, flake8
21 |
22 | [flake8]
23 | exclude =
24 | .git,
25 | .tox,
26 | build,
27 | dist
28 | ignore = E501
29 |
30 | [pep8]
31 | ignore = E501
32 |
--------------------------------------------------------------------------------