Skip to content

Commit 4ae2e59

Browse files
committed
feat: price rate subscription
1 parent e486deb commit 4ae2e59

File tree

8 files changed

+136
-3
lines changed

8 files changed

+136
-3
lines changed

cryptomarket/args.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,11 @@ class TickerSpeed(Checker):
9999
_3_SECONDS = '3s'
100100

101101

102+
class PriceRateSpeed(Checker):
103+
_1_SECOND = '1s'
104+
_3_SECONDS = '3s'
105+
106+
102107
class OrderbookSpeed(Checker):
103108
_100_MILISECONDS = '100ms'
104109
_500_MILISECONDS = '500ms'
@@ -376,6 +381,9 @@ def public_comment(self, val: str):
376381
def symbols_as_list(self, val: List[str]):
377382
return self.add('symbols', val)
378383

384+
def currencies_as_list(self, val: List[str]):
385+
return self.add('currencies', val)
386+
379387
def transaction_type(self, val: List[str]):
380388
return self.add_cheking(TransactionType, 'type', val)
381389

@@ -434,6 +442,9 @@ def sub_account_id(self, val: str):
434442
def subscription_mode(self, val: str):
435443
return self.add_cheking(SubscriptionMode, 'mode', val)
436444

445+
def target_currency(self, val: str):
446+
return self.add('target_currency', val)
447+
437448
def type(self, val: str):
438449
return self.add('type', val)
439450

cryptomarket/dataclasses/__init__.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,13 @@
2323
from .tradeOfOrder import TradeOfOrder
2424
from .transaction import Transaction
2525
from .wsCandle import WSCandle
26-
from .wsminiTicker import WSMiniTicker
26+
from .wsMiniTicker import WSMiniTicker
2727
from .wsOrderBook import WSOrderBook
2828
from .wsOrderBookTop import WSOrderBookTop
2929
from .wsPublicTrade import WSPublicTrade
3030
from .wsTicker import WSTicker
3131
from .wsTrade import WSTrade
32-
32+
from .wsPriceRate import WSPriceRate
3333
__all__ = [
3434
ACLSettings,
3535
Address,
@@ -62,5 +62,6 @@
6262
WSPublicTrade,
6363
WSTicker,
6464
WSTrade,
65+
WSPriceRate,
6566
SubAccount
6667
]
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
from dataclasses import dataclass
2+
3+
4+
@dataclass
5+
class WSPriceRate:
6+
t: int
7+
"""Timestamp in milliseconds"""
8+
r: str
9+
"""rate"""

cryptomarket/websockets/market_data_client.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,10 @@
55

66
import cryptomarket.args as args
77
from cryptomarket.dataclasses.wsCandle import WSCandle
8-
from cryptomarket.dataclasses.wsminiTicker import WSMiniTicker
8+
from cryptomarket.dataclasses.wsMiniTicker import WSMiniTicker
99
from cryptomarket.dataclasses.wsOrderBook import WSOrderBook
1010
from cryptomarket.dataclasses.wsOrderBookTop import WSOrderBookTop
11+
from cryptomarket.dataclasses.wsPriceRate import WSPriceRate
1112
from cryptomarket.dataclasses.wsTicker import WSTicker
1213
from cryptomarket.dataclasses.wsTrade import WSTrade
1314
from cryptomarket.exceptions import CryptomarketAPIException
@@ -485,3 +486,38 @@ def intercept_feed(feed, feed_type):
485486
params=params,
486487
result_callback=result_callback
487488
)
489+
490+
def subscribe_to_price_rates(
491+
self,
492+
callback: Callable[[Dict[str, WSPriceRate]], None],
493+
speed: Union[args.PriceRateSpeed, Literal['1s', '3s']],
494+
target_currency: Optional[str],
495+
currencies: Optional[List[str]] = None,
496+
result_callback: Optional[Callable[[
497+
Union[CryptomarketAPIException, None], Union[List[str], None]], None]] = None,
498+
):
499+
"""subscribe to a feed of price rates
500+
501+
subscription is for all currencies or specified currencies (bases), against a target currency (quote). indexed by currency id (bases)
502+
503+
https://api.exchange.cryptomkt.com/#subscribe-to-price-rates
504+
505+
:param callback: callable that recieves a dict of mini tickers, indexed by symbol.
506+
:param speed: The speed of the feed. '1s' or '3s'
507+
:param target_currency: quote currency for the price rates
508+
:param currencies: Optional. A list of currencies ids (as bases) to subscribe to. If not provided it subscribes to all currencies
509+
:param result_callback: A callable of two arguments, takes either a CryptomarketAPIException, or the list of correctly subscribed currencies
510+
"""
511+
if currencies is None:
512+
currencies = ['*']
513+
params = args.DictBuilder().currencies_as_list(currencies).speed(speed).target_currency(target_currency).build()
514+
515+
def intercept_feed(feed, feed_type):
516+
callback({key: from_dict(data_class=WSPriceRate, data=feed[key])
517+
for key in feed})
518+
self._send_channeled_subscription(
519+
channel=f'price/rate/{speed}',
520+
callback=intercept_feed,
521+
params=params,
522+
result_callback=result_callback
523+
)

tests/rest/test_test.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import json
2+
import time
3+
from typing import Dict, List
4+
from cryptomarket.args import TickerSpeed
5+
from cryptomarket.dataclasses.wsTicker import WSTicker
6+
from cryptomarket.dataclasses.wsTrade import WSTrade
7+
from cryptomarket.websockets.wallet_client import WalletClient
8+
9+
10+
with open('/home/ismael/cryptomarket/keys.json') as fd:
11+
keys = json.load(fd)
12+
13+
14+
def print_report(exception, report):
15+
if exception is not None:
16+
print('exception')
17+
print(exception)
18+
if report is not None:
19+
print('report')
20+
print(report)
21+
22+
23+
if __name__ == '__main__':
24+
from cryptomarket.websockets import TradingClient
25+
26+
client = WalletClient(keys['apiKey'], keys['apiSecret'], window=15_000)
27+
client.connect()
28+
29+
# subscribe to wallet transactions
30+
def callback(transaction):
31+
print(transaction)
32+
client.subscribe_to_transactions(callback)
33+
34+
# unsubscribe from wallet transactions
35+
err = client.unsubscribe_to_transactions()
36+
37+
# get wallet balances
38+
def callback(err, balances):
39+
if err:
40+
print(err)
41+
return
42+
print(balances)
43+
client.get_wallet_balances(callback)
44+
45+
time.sleep(5)
46+
47+
client.close()

tests/websockets/test_helpers.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
WSCandle, WSMiniTicker, WSOrderBook,
77
WSOrderBookTop, WSPublicTrade, WSTicker,
88
WSTrade)
9+
from cryptomarket.dataclasses.wsPriceRate import WSPriceRate
910
from tests.rest.test_helpers import good_list
1011

1112

@@ -124,6 +125,16 @@ def good_orderbook_top(orderbook_top: WSOrderBookTop) -> bool:
124125
)
125126

126127

128+
def good_price_rate(price_rate: WSPriceRate) -> bool:
129+
return good_dict(
130+
asdict(price_rate),
131+
[
132+
"t",
133+
"r",
134+
]
135+
)
136+
137+
127138
def good_candle(candle: WSCandle) -> bool:
128139
return good_dict(
129140
asdict(candle),

tests/websockets/test_market_data_subs.py

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import time
22
import unittest
3+
from cryptomarket.dataclasses.wsPriceRate import WSPriceRate
34

45
from test_helpers import *
56

@@ -167,6 +168,23 @@ def callback(top_of_orderbooks_of_symbol: Dict[str, WSOrderBookTop]):
167168
if Veredict.failed:
168169
self.fail(Veredict.message)
169170

171+
def test_subscribe_to_price_rates(self):
172+
def callback(price_rates: Dict[str, WSPriceRate]):
173+
for currency in price_rates:
174+
price_rate = price_rates[currency]
175+
if not good_price_rate(price_rate):
176+
Veredict.fail("not a good mini ticker")
177+
self.ws.subscribe_to_price_rates(
178+
callback=callback,
179+
speed=args.PriceRateSpeed._1_SECOND,
180+
target_currency="BTC",
181+
currencies=["EOS", "ETH"],
182+
result_callback=result_callback
183+
)
184+
time.sleep(20*SECOND)
185+
if Veredict.failed:
186+
self.fail(Veredict.message)
187+
170188

171189
if __name__ == '__main__':
172190
unittest.main()

0 commit comments

Comments
 (0)