Source code for quoine.client

#!/usr/bin/env python
# coding=utf-8

import jwt
import requests
import six
import time

from .exceptions import QuoineAPIException, QuoineRequestException

if six.PY2:
    from urllib import urlencode
elif six.PY3:
    from urllib.parse import urlencode


[docs]class Quoine(object): API_URL = 'https://api.quoine.com' API_VERSION = '2' VENDOR_ID = None LANGUAGE = 'en' SIDE_BUY = 'buy' SIDE_SELL = 'sell' STATUS_FILLED = 'filled' STATUS_LIVE = 'live' STATUS_PARTIAL = 'partially_filled' STATUS_CANCELLED = 'cancelled' ORDER_TYPE_LIMIT = 'limit' ORDER_TYPE_MARKET = 'market' ORDER_TYPE_MARKET_RANGE = 'market_with_range' LEVERAGE_LEVEL_2 = 2 LEVERAGE_LEVEL_4 = 4 LEVERAGE_LEVEL_5 = 5 LEVERAGE_LEVEL_10 = 10 LEVERAGE_LEVEL_25 = 25 MARGIN_ORDER_DIRECTION_ONE = 'one_direction' MARGIN_ORDER_DIRECTION_TWO = 'two_direction' MARGIN_ORDER_DIRECTION_NET = 'netout'
[docs] def __init__(self, api_token_id, api_secret, vendor_id=None, language=None): """Quoine API Client constructor :param api_token_id: Api Token Id :type api_token_id: str. :param api_secret: Api Secret :type api_secret: str. :param vendor_id: Vendor ID optional :type vendor_id: str. :param language: Langague optional :type language: str. """ self.API_TOKEN_ID = api_token_id self.API_SECRET = api_secret if vendor_id: self.VENDOR_ID = vendor_id if language: self.LANGUAGE = language
self.session = self._init_session() def _init_session(self): session = requests.session() headers = {'Accept': 'application/json', 'User-Agent': 'python-quoine', 'X-Quoine-API-Version': self.API_VERSION, 'HTTP_ACCEPT_LANGUAGE': self.LANGUAGE, 'Accept-Language': self.LANGUAGE} if self.VENDOR_ID: headers['X-Quoine-Vendor-ID'] = self.VENDOR_ID session.headers.update(headers) return session def _generate_signature(self, path): auth_payload = { 'path': path, 'nonce': int(time.time() * 1000), 'token_id': self.API_TOKEN_ID } return jwt.encode(auth_payload, self.API_SECRET, 'HS256') def _create_path(self, method, path, data): query_string = '' if method == 'get' and data: query_string = '?{}'.format(urlencode(data)) return '/{}{}'.format(path, query_string) def _create_uri(self, path): return '{}/{}'.format(self.API_URL, path) def _request(self, method, path, signed, **kwargs): kwargs['data'] = kwargs.get('data', {}) kwargs['headers'] = kwargs.get('headers', {}) sig_path = self._create_path(method, path, kwargs['data']) uri = self._create_uri(path) if signed: # generate signature kwargs['headers']['X-Quoine-Auth'] = self._generate_signature(sig_path) if kwargs['data'] and method == 'get': kwargs['params'] = kwargs['data'] del(kwargs['data']) response = getattr(self.session, method)(uri, **kwargs) return self._handle_response(response) def _handle_response(self, response): """Internal helper for handling API responses from the Quoine server. Raises the appropriate exceptions when necessary; otherwise, returns the response. """ if not str(response.status_code).startswith('2'): raise QuoineAPIException(response) try: return response.json() except ValueError: raise QuoineRequestException('Invalid Response: %s' % response.text) def _get(self, path, signed=False, **kwargs): return self._request('get', path, signed, **kwargs) def _post(self, path, signed=False, **kwargs): return self._request('post', path, signed, **kwargs) def _put(self, path, signed=False, **kwargs): return self._request('put', path, signed, **kwargs) def _delete(self, path, signed=False, **kwargs): return self._request('delete', path, signed, **kwargs) # Product Endpoints
[docs] def get_products(self): """Get the list of all available products https://developers.quoine.com/#products .. code:: python products = client.get_products() :returns: list - List of product dictionaries .. code-block:: python [ { "id": 5, "product_type": "CurrencyPair", "code": "CASH", "name": "CASH Trading", "market_ask": "48203.05", "market_bid": "48188.15", "indicator": -1, "currency": "JPY", "currency_pair_code": "BTCJPY", "symbol": "¥", "fiat_minimum_withdraw": "1500.0", "pusher_channel": "product_cash_btcjpy_5", "taker_fee": "0.0", "maker_fee": "0.0", "low_market_bid": "47630.99", "high_market_ask": "48396.71", "volume_24h": "2915.627366519999999998", "last_price_24h": "48217.2", "last_traded_price": "48203.05", "last_traded_quantity": "1.0", "quoted_currency": "JPY", "base_currency": "BTC", "exchange_rate": "0.009398151671149725" }, #... ] :raises: QuoineResponseException, QuoineAPIException """
return self._get('products')
[docs] def get_product(self, product_id): """Get product details https://developers.quoine.com/#get-a-product :param product_id: required :type product_id: int .. code:: python product = client.get_product(1) :returns: list - List of product dictionaries .. code-block:: python { "id": 5, "product_type": "CurrencyPair", "code": "CASH", "name": "CASH Trading", "market_ask": "48203.05", "market_bid": "48188.15", "indicator": -1, "currency": "JPY", "currency_pair_code": "BTCJPY", "symbol": "¥", "fiat_minimum_withdraw": "1500.0", "pusher_channel": "product_cash_btcjpy_5", "taker_fee": "0.0", "maker_fee": "0.0", "low_market_bid": "47630.99", "high_market_ask": "48396.71", "volume_24h": "2915.62736652", "last_price_24h": "48217.2", "last_traded_price": "48203.05", "last_traded_quantity": "1.0", "quoted_currency": "JPY", "base_currency": "BTC", "exchange_rate": "0.009398151671149725" } :raises: QuoineResponseException, QuoineAPIException """
return self._get('products/{}'.format(product_id))
[docs] def get_order_book(self, product_id, full=False): """Get order book for a product https://developers.quoine.com/#get-order-book :param product_id: required :type product_id: int :param full: default False, optional :type full: bool .. code:: python order_book = client.get_order_book(1, full=False) :returns: API response .. code-block:: python { "buy_price_levels": [ [ "416.23000", # price "1.75000" # amount ], #... ], "sell_price_levels": [ [ "416.47000", # price "0.28675" # amount ], #... ] } :raises: QuoineResponseException, QuoineAPIException """ data = {'full': 1 if full else 0}
return self._get('products/{}/price_levels'.format(product_id), data=data) # Excecution Endpoints
[docs] def get_executions(self, product_id, limit=None, page=None): """Get a list of recent executions from a product (Executions are sorted in DESCENDING order - Latest first) https://developers.quoine.com/#executions :param product_id: required :type product_id: int :param limit: How many executions should be returned. Must be <= 1000. Default is 20 :type limit: int :param page: From what page the executions should be returned, e.g if limit=20 and page=2, the response would start from the 21st execution. Default is 1 :type page: int .. code:: python executions = client.get_executions( product_id=1, limit=200) :returns: API response .. code-block:: python { "models": [ { "id": 1011880, "quantity": "6.118954", "price": "409.78", "taker_side": "sell", "created_at": 1457370745 }, { "id": 1011791, "quantity": "1.15", "price": "409.12", "taker_side": "sell", "created_at": 1457365585 } ], "current_page": 2, "total_pages": 1686 } :raises: QuoineResponseException, QuoineAPIException """ data = { 'product_id': product_id } if limit: data['limit'] = limit if page: data['page'] = page
return self._get('executions', data=data)
[docs] def get_executions_since_time(self, product_id, timestamp, limit=None): """Get a list of executions after a particular time (Executions are sorted in ASCENDING order) Note this call has an optional limit parameter but no paging. https://developers.quoine.com/#get-executions-by-timestamp :param product_id: required :type product_id: int :param timestamp: Only show executions at or after this timestamp :type timestamp: int (Unix timestamps in seconds) :param limit: How many executions should be returned. Must be <= 1000. Default is 20 :type limit: int .. code:: python import time since = int(time.time()) executions = client.get_executions_since_time( product_id=1, timestamp=since, limit=50) :returns: API response .. code-block:: python [ { "id": 960598, "quantity": "5.6", "price": "431.89", "taker_side": "buy", "created_at": 1456705487 }, { "id": 960603, "quantity": "0.06", "price": "431.74", "taker_side": "buy", "created_at": 1456705564 } ] :raises: QuoineResponseException, QuoineAPIException """ data = { 'product_id': product_id, 'timestamp': timestamp } if limit: data['limit'] = limit
return self._get('executions', data=data) # Interest Rate Endpoints
[docs] def get_interest_rate_ladder(self, currency): """Get a list of executions after a particular time (Executions are sorted in ASCENDING order) https://developers.quoine.com/#interest-rates :param currency: required (i.e. USD) :type currency: string .. code:: python ladder = client.get_interest_rate_ladder(currency='USD') :returns: API response .. code-block:: python { "bids": [ [ "0.00020", "23617.81698" ], [ "0.00040", "50050.42000" ], [ "0.00050", "100000.00000" ] ], "asks": [ ] } :raises: QuoineResponseException, QuoineAPIException """
return self._get('ir_ladders/{}'.format(currency)) # Orders Endpoints
[docs] def create_order(self, order_type, product_id, side, quantity, price=None, price_range=None): """Create a limit, market or market with range spot order. This function gives full flexibility for spot orders. https://developers.quoine.com/#orders :param order_type: required - limit, market or market_with_range :type order_type: string :param product_id: required :type product_id: int :param side: required - buy or sell :type side: string :param quantity: required quantity to buy or sell :type quantity: string :param price: required price per unit of cryptocurrency :type price: string :param price_range: optional For order_type of market_with_range only, slippage of the order. :type price_range: string .. code:: python order = client.create_order( type=Quoinex.ORDER_TYPE_LIMIT product_id=1, side=Quoinex.SIDE_BUY, quantity='100', price='0.00001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """ data = { 'order': { 'order_type': order_type, 'product_id': product_id, 'side': side, 'quantity': quantity } } if price and order_type == self.ORDER_TYPE_LIMIT: data['order']['price'] = price if price_range and order_type == self.ORDER_TYPE_MARKET_RANGE: data['order']['price_range'] = price_range
return self._post('orders', True, json=data)
[docs] def create_limit_buy(self, product_id, quantity, price): """Create a limit spot buy order https://developers.quoine.com/#orders :param product_id: required :type product_id: int :param quantity: required quantity to buy or sell :type quantity: string :param price: required price per unit of cryptocurrency :type price: string .. code:: python order = client.create_limit_buy( product_id=1, quantity='100', price='0.00001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """
return self.create_order(self.ORDER_TYPE_LIMIT, product_id, self.SIDE_BUY, quantity, price)
[docs] def create_limit_sell(self, product_id, quantity, price): """Create a limit spot sell order https://developers.quoine.com/#orders :param product_id: required :type product_id: int :param quantity: required quantity to buy or sell :type quantity: string :param price: required price per unit of cryptocurrency :type price: string .. code:: python order = client.create_limit_sell( product_id=1, quantity='100', price='0.00001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """
return self.create_order(self.ORDER_TYPE_LIMIT, product_id, 'sell', quantity, price)
[docs] def create_market_buy(self, product_id, quantity, price_range=None): """Create a market spot buy order https://developers.quoine.com/#orders :param product_id: required :type product_id: int :param quantity: required quantity to buy or sell :type quantity: string :param price_range: optional - slippage of the order. :type price_range: string .. code:: python order = client.create_market_buy( product_id=1, quantity='100') # place a market buy with range for slippage order = client.create_market_buy( product_id=1, quantity='100', price_range='0.001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """ order_type = self.ORDER_TYPE_MARKET if price_range: order_type = self.ORDER_TYPE_MARKET_RANGE
return self.create_order(order_type, product_id, self.SIDE_BUY, quantity, price_range=price_range)
[docs] def create_market_sell(self, product_id, quantity, price_range=None): """Create a market spot sell order https://developers.quoine.com/#orders :param product_id: required :type product_id: int :param quantity: required quantity to buy or sell :type quantity: string :param price_range: optional - slippage of the order. :type price_range: string .. code:: python order = client.create_market_sell( product_id=1, quantity='100') # place a market sell with range for slippage order = client.create_market_sell( product_id=1, quantity='100', price_range='0.001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """ order_type = self.ORDER_TYPE_MARKET if price_range: order_type = self.ORDER_TYPE_MARKET_RANGE
return self.create_order(order_type, product_id, self.SIDE_SELL, quantity, price_range=price_range)
[docs] def create_margin_order(self, order_type, product_id, side, quantity, price, leverage_level=2, price_range=None, funding_currency=None, order_direction=None): """Create a leveraged margin order of type limit, market, or market with range Only available on Quoinex To trade at any specific leverage level, you will first need to go to margin trading dashboard, click on that leverage level and then confirm to get authorized. Or you can do it using the update_leverage_level function https://developers.quoine.com/#orders :param order_type: required - limit, market or market_with_range :type order_type: string :param product_id: required :type product_id: int :param side: required - buy or sell :type side: string :param quantity: required quantity to buy or sell :type quantity: string :param price: required price per unit of cryptocurrency :type price: string :param leverage_level: optional - 2, 4, 5, 10 or 25 (default 2) :type leverage_level: int :param price_range: optional - For order_type of market_with_range only, slippage of the order. :type price_range: string :param funding_currency: optional - Currency used to fund the trade with. Default is quoted currency :type funding_currency: string .. code:: python order = client.create_order( type=Quoinex.ORDER_TYPE_LIMIT product_id=1, side=Quoinex.SIDE_BUY, quantity='100', price='0.00001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, } :raises: QuoineResponseException, QuoineAPIException """ data = { 'order': { 'order_type': order_type, 'product_id': product_id, 'side': side, 'quantity': quantity, 'leverage_level': leverage_level } } if price and order_type == self.ORDER_TYPE_LIMIT: data['order']['price'] = price if price_range and order_type == self.ORDER_TYPE_MARKET_RANGE: data['order']['price_range'] = price_range if funding_currency: data['order']['funding_currency'] = funding_currency
return self._post('orders', True, json=data)
[docs] def get_order(self, order_id): """Get an order https://developers.quoine.com/#get-an-order :param order_id: required :type order_id: int .. code:: python order = client.get_order(order_id=2157479) :returns: API response .. code-block:: python { "id": 2157479, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.01", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "filled", "leverage_level": 2, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "unwound_trade_leverage_level": null, "executions": [ { "id": 4566133, "quantity": "0.01", "price": "500.0", "taker_side": "buy", "my_side": "sell", "created_at": 1465396785 } ] } :raises: QuoineResponseException, QuoineAPIException """
return self._get('orders/{}'.format(order_id), True)
[docs] def get_orders(self, funding_currency=None, product_id=None, status=None, with_details=False, limit=None, page=None): """Get a list of orders using filters with pagination https://developers.quoine.com/#get-orders :param funding_currency: optional - filter orders based on funding currency :type funding_currency: string :param product_id: optional - filter orders based on product :type product_id: int :param status: optional - filter orders based on status :type status: string :param with_details: optional - return full order details (attributes between \*) including executions :type with_details: bool :param limit: optional - page limit :type limit: int :param page: optional - page number :type page: int .. code:: python orders = client.get_orders(product_id=1, limit=10) :returns: API response .. code-block:: python { "models": [ { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "live", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD", "unwound_trade_leverage_level": null, "order_fee": "0.0", "margin_used": "0.0", "margin_interest": "0.0", "executions": [] } ], "current_page": 1, "total_pages": 1 } :raises: QuoineResponseException, QuoineAPIException """ data = {} if funding_currency: data['funding_currency'] = funding_currency if product_id: data['product_id'] = product_id if status: data['status'] = status if with_details: data['with_details'] = 1 if limit: data['limit'] = limit if page: data['page'] = page
return self._get('orders', True, data=data)
[docs] def cancel_order(self, order_id): """Cancel an order https://developers.quoine.com/#cancel-an-order :param order_id: required :type order_id: int .. code:: python result = client.cancel_order(order_id=2157479) :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "cancelled", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD" } :raises: QuoineResponseException, QuoineAPIException """
return self._put('orders/{}/cancel'.format(order_id), True)
[docs] def update_live_order(self, order_id, quantity=None, price=None): """Update a live order https://developers.quoine.com/#edit-a-live-order :param order_id: required :type order_id: int :param quantity: optional - one or both of quantity or price should be set :type quantity: string :param price: optional - one or both of quantity or price should be set :type price: string .. code:: python order = client.update_live_order( order_id=2157479, quantity='101', price='0.001') :returns: API response .. code-block:: python { "id": 2157474, "order_type": "limit", "quantity": "0.01", "disc_quantity": "0.0", "iceberg_total_quantity": "0.0", "side": "sell", "filled_quantity": "0.0", "price": "500.0", "created_at": 1462123639, "updated_at": 1462123639, "status": "cancelled", "leverage_level": 1, "source_exchange": "QUOINE", "product_id": 1, "product_code": "CASH", "funding_currency": "USD", "currency_pair_code": "BTCUSD" } :raises: QuoineResponseException, QuoineAPIException """ data = { 'order': {} } if quantity: data['order']['quantity'] = quantity if price: data['order']['price'] = price
return self._put('orders/{}'.format(order_id), True, json=data)
[docs] def get_order_trades(self, order_id): """Get an orders trades https://developers.quoine.com/#get-an-order's-trades :param order_id: required :type order_id: int .. code:: python trades = client.get_order_trades(order_id=2157479) :returns: API response .. code-block:: python [ { "id": 57896, "currency_pair_code": "BTCUSD", "status": "closed", "side": "short", "margin_used": "0.83588", "open_quantity": "0.01", "close_quantity": "0.0", "quantity": "0.01", "leverage_level": 5, "product_code": "CASH", "product_id": 1, "open_price": "417.65", "close_price": "417.0", "trader_id": 3020, "open_pnl": "0.0", "close_pnl": "0.0065", "pnl": "0.0065", "stop_loss": "0.0", "take_profit": "0.0", "funding_currency": "USD", "created_at": 1456250726, "updated_at": 1456251837, "close_fee": "0.0", "total_interest": "0.02", "daily_interest": "0.02" } ] :raises: QuoineResponseException, QuoineAPIException """
return self._get('orders/{}/trades'.format(order_id), True) # Executions Endpoints
[docs] def get_my_executions(self, product_id, limit=None, page=None): """Get list of your executions by product with pagination https://developers.quoine.com/#get-your-executions :param product_id: required :type product_id: int :param limit: Limit execution per request :type limit: int :param page: Page :type page: int .. code:: python executions = client.get_my_executions(product_id=1) :returns: API response .. code-block:: python { "models": [ { "id": 1001232, "quantity": "0.37153179", "price": "390.0", "taker_side": "sell", "my_side": "sell", "created_at": 1457193798 } ], "current_page": 1, "total_pages": 2 } :raises: QuoineResponseException, QuoineAPIException """ data = { 'product_id': product_id } if limit: data['limit'] = limit if page: data['page'] = page
return self._get('executions/me', True, data=data) # Accounts Endpoints
[docs] def get_fiat_accounts(self): """Get list of fiat accounts https://developers.quoine.com/#get-fiat-accounts .. code:: python accounts = client.get_fiat_accounts() :returns: API response .. code-block:: python [ { "id": 4695, "currency": "USD", "currency_symbol": "$", "balance": "10000.1773", "pusher_channel": "user_3020_account_usd", "lowest_offer_interest_rate": "0.00020", "highest_offer_interest_rate": "0.00060", "exchange_rate": "1.0", "currency_type": "fiat", "margin": "0.0", "free_margin": "10000.1773" } ] :raises: QuoineResponseException, QuoineAPIException """
return self._get('fiat_accounts', True)
[docs] def create_fiat_account(self, currency): """Create a fiat account for a currency https://developers.quoine.com/#create-a-fiat-account :param currency: required :type currency: string .. code:: python account = client.create_fiat_accounts(currency='USD') :returns: API response .. code-block:: python { "id": 5595, "currency": "USD", "currency_symbol": "$", "balance": "0.0", "pusher_channel": "user_3122_account_usd", "lowest_offer_interest_rate": "0.00020", "highest_offer_interest_rate": "0.00060", "exchange_rate": "1.0", "currency_type": "fiat", "margin": "0.0", "free_margin": "0.0" } :raises: QuoineResponseException, QuoineAPIException """ data = { 'currency': currency }
return self._post('fiat_accounts', True, json=data)
[docs] def get_crypto_accounts(self): """Get list of crypto accounts https://developers.quoine.com/#get-crypto-accounts .. code:: python accounts = client.get_crypto_accounts() :returns: API response .. code-block:: python [ { "id": 4668, "balance": "4.99", "address": "1F25zWAQ1BAAmppNxLV3KtK6aTNhxNg5Hg", "currency": "BTC", "currency_symbol": "฿", "pusher_channel": "user_3020_account_btc", "minimum_withdraw": 0.02, "lowest_offer_interest_rate": "0.00049", "highest_offer_interest_rate": "0.05000", "currency_type": "crypto" } ] :raises: QuoineResponseException, QuoineAPIException """
return self._get('crypto_accounts', True)
[docs] def get_account_balances(self): """Get all account balances https://developers.quoine.com/#get-all-account-balances .. code:: python account = client.get_account_balances() :returns: API response .. code-block:: python [ { "currency": "BTC", "balance": "0.04925688" }, { "currency": "USD", "balance": "7.17696" }, { "currency": "JPY", "balance": "356.01377" } ] :raises: QuoineResponseException, QuoineAPIException """
return self._get('accounts/balance', True)
[docs] def get_main_asset(self): """Get name of your main asset with balance :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "currency": "JPY", "total_amount": "23050.04" } """
return self._get('accounts/main_asset', True) # Assets Lending Endpoints
[docs] def create_loan_bid(self, rate, quantity, currency): """Create a loan bid https://developers.quoine.com/#create-a-loan-bid :param rate: daily interest rate, e.g 0.0002 (0.02%), must be <= 0.07% :type rate: string :param quantity: amount to lend :type quantity: string :param currency: lending currency (all available in the system except JPY) :type currency: string :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 3580, "bidask_type": "limit", "quantity": "50.0", "currency": "USD", "side": "bid", "filled_quantity": "0.0", "status": "live", "rate": "0.0002", "user_id": 3020 } """ data = { 'loan_bid': { 'rate': rate, 'quantity': quantity, 'currency': currency } }
return self._post('loan_bids', True, json=data)
[docs] def get_loan_bid(self, currency, limit=None, page=None): """Get loan bids https://developers.quoine.com/#get-loan-bids :param currency: lending currency (all available in the system except JPY) :type currency: string :param limit: Limit execution per request :type limit: int :param page: Page :type page: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 3580, "bidask_type": "limit", "quantity": "50.0", "currency": "USD", "side": "bid", "filled_quantity": "0.0", "status": "live", "rate": "0.0002", "user_id": 3020 } """ data = { 'currency': currency } if limit: data['limit'] = limit if page: data['page'] = page
return self._get('loan_bids', True, data=data)
[docs] def close_loan_bid(self, loan_bid_id): """Close loan bid https://developers.quoine.com/#close-loan-bid :param loan_bid_id: load bid Id :type loan_bid_id: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 3580, "bidask_type": "limit", "quantity": "50.0", "currency": "USD", "side": "bid", "filled_quantity": "0.0", "status": "closed", "rate": "0.0007", "user_id": 3020 } """
return self._put('loan_bids/{}/close'.format(loan_bid_id), True)
[docs] def get_loans(self, currency, limit=None, page=None): """Get loans https://developers.quoine.com/#get-loans :param currency: lending currency (all available in the system except JPY) :type currency: string :param limit: Limit execution per request :type limit: int :param page: Page :type page: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "models": [ { "id": 144825, "quantity": "495.1048", "rate": "0.0005", "created_at": 1464168246, "lender_id": 312, "borrower_id": 5712, "status": "open", "currency": "JPY", "fund_reloaned": true } ], "current_page": 1, "total_pages": 1 } """ data = { 'currency': currency } if limit: data['limit'] = limit if page: data['page'] = page
return self._get('loans', True, data=data)
[docs] def update_loan(self, loan_id, fund_reloaned=None): """Update a loan https://developers.quoine.com/#update-a-loan TODO: work out what else we can update :param loan_id: Loan Id :type loan_id: int :param fund_reloaned: optional :type fund_reloaned: bool :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 144825, "quantity": "495.1048", "rate": "0.0005", "created_at": 1464168246, "lender_id": 312, "borrower_id": 5712, "status": "open", "currency": "JPY", "fund_reloaned": false } """ data = { } if fund_reloaned is not None: data['fund_reloaned'] = fund_reloaned
return self._put('loans/{}'.format(loan_id), True, json=data) # Trading Accounts Endpoints
[docs] def get_trading_accounts(self): """Get Trading Accounts https://developers.quoine.com/#get-trading-accounts :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python [ { "id": 1759, "leverage_level": 10, "max_leverage_level": 10, "pnl": "0.0", "equity": "10000.1773", "margin": "4.2302", "free_margin": "9995.9471", "trader_id": 4807, "status": "active", "product_code": "CASH", "currency_pair_code": "BTCUSD", "position": "0.1", "balance": "10000.1773", "created_at": 1421992165, "updated_at": 1457242996, "pusher_channel": "trading_account_1759", "margin_percent": "0.1", "product_id": 1, "funding_currency": "USD", "base_open_price": 0, "long_summary": { "pnl": "0.0", "position": "0.0", "base_open_price": "0.0" }, "short_summary": { "pnl": "0.0", "position": "0.0", "base_open_price": "0.0" } }, #... ] """
return self._get('trading_accounts', True)
[docs] def get_trading_account(self, account_id): """Get a Trading Account https://developers.quoine.com/#get-a-trading-account :param account_id: Trading Account Id :type account_id: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 1759, "leverage_level": 10, "max_leverage_level": 10, "pnl": "0.0", "equity": "10000.1773", "margin": "4.2302", "free_margin": "9995.9471", "trader_id": 4807, "status": "active", "product_code": "CASH", "currency_pair_code": "BTCUSD", "position": "0.1", "balance": "10000.1773", "created_at": 1421992165, "updated_at": 1457242996, "pusher_channel": "trading_account_1759", "margin_percent": "0.1", "product_id": 1, "funding_currency": "USD" } """
return self._get('trading_accounts/{}'.format(account_id), True)
[docs] def update_leverage_level(self, account_id, leverage_level): """Update Trading account leverage level Only available on Quoinex https://developers.quoine.com/#update-leverage-level :param account_id: Trading Account Id :type account_id: int :param leverage_level: New leverage level :type leverage_level: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 1759, "leverage_level": 25, "max_leverage_level": 25, "pnl": "0.0", "equity": "10000.1773", "margin": "4.2302", "free_margin": "9995.9471", "trader_id": 4807, "status": "active", "product_code": "CASH", "currency_pair_code": "BTCUSD", "position": "0.1", "balance": "10000.1773", "created_at": 1421992165, "updated_at": 1457242996, "pusher_channel": "trading_account_1759", "margin_percent": "0.1", "product_id": 1, "funding_currency": "USD" } """ data = { 'trading_account': { 'leverage_level': leverage_level } }
return self._put('trading_accounts/{}'.format(account_id), True, json=data) # Trade Endpoints
[docs] def get_trades(self, funding_currency=None, status=None, limit=None, page=None): """Get Trades https://developers.quoine.com/#get-trades :param funding_currency: optional - get trades of a particular funding currency :type funding_currency: string :param status: optional - open or closed :type status: string :param limit: Limit trades per request :type limit: int :param page: Page :type page: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "models": [ { "id": 57896, "currency_pair_code": "BTCUSD", "status": "open", "side": "short", "margin_used": "0.83588", "open_quantity": "0.01", "close_quantity": "0.0", "quantity": "0.01", "leverage_level": 5, "product_code": "CASH", "product_id": 1, "open_price": "417.65", "close_price": "417.0", "trader_id": 3020, "open_pnl": "0.0", "close_pnl": "0.0", "pnl": "0.0065", "stop_loss": "0.0", "take_profit": "0.0", "funding_currency": "USD", "created_at": 1456250726, "updated_at": 1456251837, "close_fee": "0.0", "total_interest": "0.02", "daily_interest": "0.02" }, #... ], "current_page": 1, "total_pages": 1 } """ data = {} if funding_currency: data['funding_currency'] = funding_currency if status: data['status'] = status if limit: data['limit'] = limit if page: data['page'] = page
return self._get('trades', True, data=data)
[docs] def close_trade(self, trade_id, closed_quantity=None): """Close a trade https://developers.quoine.com/#close-a-trade :param trade_id: Trade Id :type trade_id: int :param closed_quantity: optional - The quantity you want to close :type closed_quantity: string :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 57896, "currency_pair_code": "BTCUSD", "status": "closed", "side": "short", "margin_used": "0.83588", "open_quantity": "0.01", "close_quantity": "0.0", "quantity": "0.01", "leverage_level": 5, "product_code": "CASH", "product_id": 1, "open_price": "417.65", "close_price": "417.0", "trader_id": 3020, "open_pnl": "0.0", "close_pnl": "0.0065", "pnl": "0.0065", "stop_loss": "0.0", "take_profit": "0.0", "funding_currency": "USD", "created_at": 1456250726, "updated_at": 1456251837, "close_fee": "0.0", "total_interest": "0.02", "daily_interest": "0.02" } """ data = {} if closed_quantity: data['closed_quantity'] = closed_quantity
return self._put('trades/{}/close'.format(trade_id), True, json=data)
[docs] def close_all_trades(self, side=None): """Close all trades https://developers.quoine.com/#close-all-trade :param side: optional - Close all trades of this side. Close trades of both side if left blank :type side: string :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python [ { "id": 57896, "currency_pair_code": "BTCUSD", "status": "closed", "side": "short", "margin_used": "0.83588", "open_quantity": "0.01", "close_quantity": "0.0", "quantity": "0.01", "leverage_level": 5, "product_code": "CASH", "product_id": 1, "open_price": "417.65", "close_price": "417.0", "trader_id": 3020, "open_pnl": "0.0", "close_pnl": "0.0065", "pnl": "0.0065", "stop_loss": "0.0", "take_profit": "0.0", "funding_currency": "USD", "created_at": 1456250726, "updated_at": 1456251837, "close_fee": "0.0", "total_interest": "0.02", "daily_interest": "0.02" } ] """ data = {} if side: data['side'] = side
return self._put('trades/close_all', True, json=data)
[docs] def update_trade(self, trade_id, stop_loss, take_profit): """Update a trade https://developers.quoine.com/#update-a-trade :param trade_id: Trade Id :type trade_id: int :param stop_loss: Stop Loss price :type stop_loss: string :param take_profit: Take Profit price :type take_profit: string :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python { "id": 57897, "currency_pair_code": "BTCUSD", "status": "open", "side": "short", "margin_used": "0.83588", "open_quantity": "0.01", "close_quantity": "0.0", "quantity": "0.01", "leverage_level": 5, "product_code": "CASH", "product_id": 1, "open_price": "417.65", "close_price": "0", "trader_id": 3020, "open_pnl": "0.0", "close_pnl": "0.0065", "pnl": "0.0065", "stop_loss": "300.0", "take_profit": "600.0", "funding_currency": "USD", "created_at": 1456250726, "updated_at": 1456251837, "close_fee": "0.0", "total_interest": "0.02", "daily_interest": "0.02" } """ data = { 'trade': { 'stop_loss': stop_loss, 'take_profit': take_profit } }
return self._put('trades/{}'.format(trade_id), True, json=data)
[docs] def get_trade_loans(self, trade_id): """Get a trade's loans https://developers.quoine.com/#get-a-trade's-loans :param trade_id: Trade Id :type trade_id: int :returns: API response :raises: QuoineResponseException, QuoineAPIException .. code-block:: python [ { "id": 103520, "quantity": "42.302", "rate": "0.0002", "created_at": 1461998432, "lender_id": 100, "borrower_id": 3020, "status": "open", "currency": "USD", "fund_reloaned": true } ] """
return self._get('trades/{}/loans'.format(trade_id), True)
[docs]class Quoinex(Quoine):
pass
[docs]class Qryptos(Quoinex):
API_URL = 'https://api.qryptos.com'