Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
Pedro Pablo Bustamante Barrera committed Mar 13, 2024
2 parents 402d925 + b86e756 commit 46816b7
Show file tree
Hide file tree
Showing 14 changed files with 317 additions and 78 deletions.
4 changes: 2 additions & 2 deletions cryptomarket/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,10 +201,10 @@ def clean_nones(a_dict: Dict[Any, Optional[Any]]) -> Dict[Any, Any]:

class DictBuilder:
def __init__(self):
self.the_dict = dict()
self.the_dict = {}

def build(self):
orderedDict = dict()
orderedDict = {}
for parameter in sorted(self.the_dict):
orderedDict[parameter] = self.the_dict[parameter]
return orderedDict
Expand Down
123 changes: 121 additions & 2 deletions cryptomarket/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
Price, PriceHistory, SubAccount, Symbol,
Ticker, Trade, Transaction, Fee)
from cryptomarket.dataclasses.aclSettings import ACLSettings
from cryptomarket.dataclasses.convertedCandles import ConvertedCandles
from cryptomarket.dataclasses.convertedCandlesOfSymbol import ConvertedCandlesOfSymbol
from cryptomarket.dataclasses.publicTrade import PublicTrade
from cryptomarket.http_client import HttpClient

Expand All @@ -30,10 +32,11 @@ def __init__(self, api_key: Optional[str] = None, secret_key: Optional[str] = No
self.get_trades_by_symbol = self.get_trades_of_symbol
# aliases of orders
self.create_new_order = self.create_spot_order
self.create_spot_order = self.create_spot_order
self.create_new_spot_order = self.create_spot_order

def close(self):
"""Closes the underlying http connection
"""
self.httpClient.close_session()

def _get(self, endpoint: str, params=None):
Expand Down Expand Up @@ -449,7 +452,7 @@ def get_candles_of_symbol(
:param limit: Optional. Prices per currency pair. Defaul is 100. Min is 1. Max is 1000
:param offset: Optional. Default is 0. Min is 0. Max is 100000
:returns: A list of candles of a symbol
:returns: A class with the target_currency and data with a dict with a list of candles for each symbol of the query. indexed by symbol
"""
params = args.DictBuilder().period(period).sort(sort).since(
since).till(till).limit(limit).offset(offset).build()
Expand All @@ -458,6 +461,92 @@ def get_candles_of_symbol(
return [from_dict(data_class=Candle, data=candle_data)
for candle_data in response]

def get_converted_candles(
self,
target_currency: str,
symbols: Optional[List[str]] = None,
period: Optional[Union[
args.Period, Literal[
'M1', 'M3', 'M15', 'M30', 'H1', 'H4', 'D1', 'D7', '1M'
]
]] = None,
sort: Optional[Union[args.Sort, Literal['ASC', 'DESC']]] = None,
since: str = None,
till: str = None,
limit: int = None
) -> ConvertedCandles:
"""Gets candles regarding the last price converted to the target currency for all symbols or for the specified symbols
Candles are used for OHLC representation
The result contains candles with non-zero volume only (no trades = no candles).
Conversion from the symbol quote currency to the target currency is the mean of "best" bid price and "best" ask price in the order book. If there is no "best" bid of ask price, the last price is returned.
Requires no API key Access Rights.
https://api.exchange.cryptomkt.com/#candles
:param target_currency: Target currency for conversion
:param symbols: Optional. A list of symbol ids. If empty then gets for all symbols
:param period: Optional. A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month). Default is 'M30'
:param sort: Optional. Sort direction. 'ASC' or 'DESC'. Default is 'DESC'
:param from: Optional. Initial value of the queried interval. As DateTime
:param till: Optional. Last value of the queried interval. As DateTime
:param limit: Optional. Prices per currency pair. Defaul is 100. Min is 1. Max is 1000
:returns: A class with the target_currency and data with a list of candles for the symbol of the query.
"""
params = args.DictBuilder().target_currency(target_currency).symbols(symbols).period(period).sort(sort).since(
since).till(till).limit(limit).build()
response = self._get(
endpoint="public/converted/candles", params=params)
return from_dict(ConvertedCandles, response)

def get_converted_candles_of_symbol(
self,
target_currency: str,
symbol: str,
period: Optional[Union[
args.Period, Literal[
'M1', 'M3', 'M15', 'M30', 'H1', 'H4', 'D1', 'D7', '1M'
]
]] = None,
sort: Optional[Union[args.Sort, Literal['ASC', 'DESC']]] = None,
since: str = None,
till: str = None,
limit: int = None,
offset: int = None
) -> ConvertedCandlesOfSymbol:
"""Gets candles regarding the last price converted to the target currency for the specified symbols
Candles are used for OHLC representation
The result contains candles with non-zero volume only (no trades = no candles).
Conversion from the symbol quote currency to the target currency is the mean of "best" bid price and "best" ask price in the order book. If there is no "best" bid of ask price, the last price is returned.
Requires no API key Access Rights.
https://api.exchange.cryptomkt.com/#candles
:param target_currency: Target currency for conversion
:param symbol: A symbol id
:param period: Optional. A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month). Default is 'M30'
:param sort: Optional. Sort direction. 'ASC' or 'DESC'. Default is 'DESC'
:param from: Optional. Initial value of the queried interval. As DateTime
:param till: Optional. Last value of the queried interval. As DateTime
:param limit: Optional. Prices per currency pair. Defaul is 100. Min is 1. Max is 1000
:param offset: Optional. Default is 0. Min is 0. Max is 100000
:returns: A list of candles of a symbol
"""
params = args.DictBuilder().target_currency(target_currency).period(period).sort(sort).since(
since).till(till).limit(limit).offset(offset).build()
response = self._get(
endpoint=f"public/converted/candles/{symbol}", params=params)
return from_dict(ConvertedCandlesOfSymbol, response)

#################
# AUTHENTICATED #
#################
Expand Down Expand Up @@ -1357,3 +1446,33 @@ def get_sub_account_crypto_address(self, sub_account_id: str, currency: str) ->
response = self._get(
endpoint=f'sub-account/crypto/address/{sub_account_id}/{currency}')
return from_dict(data_class=Address, data=response["result"]["address"])

###########
# ALIASES #
###########

# market data
get_ticker_by_symbol = get_ticker
get_ticker_of_symbol = get_ticker
get_ticker_last_price = get_ticker_last_price_of_symbol
get_ticker_last_price_by_symbol = get_ticker_last_price_of_symbol
get_trades_by_symbol = get_trades_of_symbol
get_order_book_by_symbol = get_order_book_of_symbol
get_order_book = get_order_book_of_symbol
get_order_book_volume_by_symbol = get_order_book_volume_of_symbol
get_order_book_volume = get_order_book_volume_of_symbol
get_candles_by_symbol = get_order_book_volume_of_symbol
get_converted_candles_by_symbol = get_converted_candles_of_symbol

# spot trading
get_spot_trading_balance_by_currency = get_spot_trading_balance_of_currency
get_spot_trading_balance = get_spot_trading_balance_of_currency
get_trading_commissions = get_all_trading_commissions
get_trading_commission_by_symbol = get_trading_commission
get_trading_commission_of_symbol = get_trading_commission

# wallet management
get_wallet_balance = get_wallet_balance_of_currency
get_wallet_balance_by_currency = get_wallet_balance_of_currency
get_deposit_crypto_address = get_deposit_crypto_address_of_currency
get_deposit_crypto_address_by_currency = get_deposit_crypto_address_of_currency
9 changes: 9 additions & 0 deletions cryptomarket/dataclasses/convertedCandles.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from dataclasses import dataclass
from typing import Dict, List
from cryptomarket.dataclasses.candle import Candle


@dataclass
class ConvertedCandles:
target_currency: str
data: Dict[str, List[Candle]]
10 changes: 10 additions & 0 deletions cryptomarket/dataclasses/convertedCandlesOfSymbol.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
from dataclasses import dataclass
from typing import List

from cryptomarket.dataclasses.candle import Candle


@dataclass
class ConvertedCandlesOfSymbol:
target_currency: str
data: List[Candle]
2 changes: 1 addition & 1 deletion cryptomarket/websockets/callback_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

class CallbackCache:
def __init__(self):
self.callbacks: Dict[str, ReusableCallback] = dict()
self.callbacks: Dict[str, ReusableCallback] = {}
self._id = 1

def next_id(self):
Expand Down
3 changes: 0 additions & 3 deletions cryptomarket/websockets/interceptors.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,6 @@ def intercept_report(callback):


def intercept_report_(err, response, callback):
print('interceptor')
print('err:', err)
print('response:', response)
if err:
callback(err, None)
return
Expand Down
94 changes: 89 additions & 5 deletions cryptomarket/websockets/market_data_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def subscribe_to_trades(
params = args.DictBuilder().symbols_as_list(symbols).limit(limit).build()

def intercept_feed(feed, feed_type):
result = dict()
result = {}
for key in feed:
result[key] = [from_dict(data_class=WSTrade, data=data)
for data in feed[key]]
Expand All @@ -129,7 +129,7 @@ def subscribe_to_candles(
):
"""subscribe to a feed of candles
subscription is for the specified symbols
subscription is only for the specified symbols
normal subscriptions have one update message per symbol
Expand All @@ -140,12 +140,12 @@ def subscribe_to_candles(
:param callback: callable that recieves a dict of candles, indexed by symbol.
:param symbols: A list of symbol ids to subscribe to
:param period: Optional. A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month). Default is 'M30'
:param period: Optional. A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month).
:param limit: Number of historical entries returned in the first feed. Min is 0. Max is 1000. Default is 0
:param result_callback: A callable of two arguments, takes either a CryptomarketAPIException, or the list of correctly subscribed symbols
"""
def intercept_feed(feed, feed_type):
result = dict()
result = {}
for key in feed:
result[key] = [
from_dict(data_class=WSCandle, data=data) for data in feed[key]]
Expand All @@ -158,6 +158,51 @@ def intercept_feed(feed, feed_type):
result_callback=result_callback,
)

def subscribe_to_converted_candles(
self,
callback: Callable[[Dict[str, List[WSCandle]], Literal['snapshot', 'update']], None],
target_currency: str,
symbols: List[str],
period: Union[args.Period,
Literal['M1', 'M3', 'M15', 'M30', 'H1', 'H4', 'D1', 'D7', '1M']] = None,
limit: Optional[int] = None,
result_callback: Optional[Callable[[
Union[CryptomarketAPIException, None], Union[List[str], None]], None]] = None,
):
"""subscribes to a feed of candles regarding the last price converted to the target currency for the specified symbols
subscription is only for the specified symbols
normal subscriptions have one update message per symbol
Conversion from the symbol quote currency to the target currency is the mean of "best" bid price and "best" ask price in the order book. If there is no "best" bid or ask price, the last price is returned.
Requires no API key Access Rights
https://api.exchange.cryptomkt.com/#subscribe-to-converted-candles
:param callback: callable that recieves a dict of candles, indexed by symbol.
:param symbols: A list of symbol ids to subscribe to
:param period: A valid tick interval. 'M1' (one minute), 'M3', 'M5', 'M15', 'M30', 'H1' (one hour), 'H4', 'D1' (one day), 'D7', '1M' (one month).
:param limit: Limit of returned entries. Min is 0. Max is 1000. Default is 0
:param result_callback: A callable of two arguments, takes either a CryptomarketAPIException, or the list of correctly subscribed symbols
"""
def intercept_feed(feed, feed_type):
result = {}
for key in feed:
result[key] = [
from_dict(data_class=WSCandle, data=data) for data in feed[key]]
callback(result, feed_type)
params = args.DictBuilder().target_currency(
target_currency).symbols_as_list(symbols).limit(limit).build()
self._send_channeled_subscription(
channel=f'converted/candles/{period}',
callback=intercept_feed,
params=params,
result_callback=result_callback,
)

def subscribe_to_mini_ticker(
self,
callback: Callable[[Dict[str, WSMiniTicker]], None],
Expand Down Expand Up @@ -510,7 +555,8 @@ def subscribe_to_price_rates(
"""
if currencies is None:
currencies = ['*']
params = args.DictBuilder().currencies_as_list(currencies).speed(speed).target_currency(target_currency).build()
params = args.DictBuilder().currencies_as_list(currencies).speed(
speed).target_currency(target_currency).build()

def intercept_feed(feed, feed_type):
callback({key: from_dict(data_class=WSPriceRate, data=feed[key])
Expand All @@ -521,3 +567,41 @@ def intercept_feed(feed, feed_type):
params=params,
result_callback=result_callback
)

def subscribe_to_price_rates_in_batches(
self,
callback: Callable[[Dict[str, WSPriceRate]], None],
speed: Union[args.PriceRateSpeed, Literal['1s', '3s']],
target_currency: Optional[str],
currencies: Optional[List[str]] = None,
result_callback: Optional[Callable[[
Union[CryptomarketAPIException, None], Union[List[str], None]], None]] = None,
):
"""subscribe to a feed of price rates
subscription is for all currencies or specified currencies (bases), against a target currency (quote). indexed by currency id (bases)
batch subscriptions have a joined update for all symbols
https://api.exchange.cryptomkt.com/#subscribe-to-price-rates
:param callback: callable that recieves a dict of mini tickers, indexed by symbol.
:param speed: The speed of the feed. '1s' or '3s'
:param target_currency: quote currency for the price rates
:param currencies: Optional. A list of currencies ids (as bases) to subscribe to. If not provided it subscribes to all currencies
:param result_callback: A callable of two arguments, takes either a CryptomarketAPIException, or the list of correctly subscribed currencies
"""
if currencies is None:
currencies = ['*']
params = args.DictBuilder().currencies_as_list(currencies).speed(
speed).target_currency(target_currency).build()

def intercept_feed(feed, feed_type):
callback({key: from_dict(data_class=WSPriceRate, data=feed[key])
for key in feed})
self._send_channeled_subscription(
channel=f'price/rate/{speed}/batch',
callback=intercept_feed,
params=params,
result_callback=result_callback
)
4 changes: 2 additions & 2 deletions cryptomarket/websockets/orderbook_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ class SideOrder(Enum):

class OrderbookCache:
def __init__(self):
self.orderbooks = dict()
self.ob_states = dict()
self.orderbooks = {}
self.ob_states = {}

def update(self, method: str, key:str, new_data: dict):
if method == methodSnapshotOrderbook:
Expand Down
9 changes: 9 additions & 0 deletions cryptomarket/websockets/trading_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -463,3 +463,12 @@ def intercept_result(err, response):
callback(None, result)
params = args.DictBuilder().symbol(symbol).build()
self._send_by_id('spot_fee', callback=intercept_result, params=params)

###########
# ALIASES #
###########

get_spot_trading_balance = get_spot_trading_balance_of_currency
get_spot_trading_balance_by_currency = get_spot_trading_balance_of_currency
get_spot_commision = get_spot_commision_of_symbol
get_spot_commision_by_symbol = get_spot_commision_of_symbol
7 changes: 7 additions & 0 deletions cryptomarket/websockets/wallet_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,3 +243,10 @@ def intercept_response(err, response):
callback=intercept_response,
params=params
)

###########
# ALIASES #
###########

get_wallet_balance_by_currency = get_wallet_balance_of_currency
get_wallet_balance = get_wallet_balance_of_currency
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

setuptools.setup(
name="cryptomarket",
version="3.0.0",
version="3.1.0",
packages=['cryptomarket', 'cryptomarket.websockets'],
include_package_data=True,
description="Cryptomarket API client library",
Expand Down
Loading

0 comments on commit 46816b7

Please sign in to comment.